Статьи |
Повышение эффективности x:transform и не только
Автор: Алексей Валиков, 11 ноября 2002
Страницы: 1![]() ![]() |
Для XSLT-преобразований в JSP мы используем тэг x:transform из JSTL. Беда в том, что "стандартная" реализация этого безобразия не очень эффективная. При загрузке преобразования через <c:import ... /> и последующим <x:transform ... /> фактически выполняется загрузка и разбор строки и создание нового трансформера и т.д. Никакого кеширования в стандартной реализации нет. Сегодня потратил немного времени на реализацию кеширования, может кому пригодится.
Переписывать x:transform было очень неохота, поэтому я решил написать кэширующую TransformerFactory. [1] Идея состоит в том, что для StreamSourcesystemId проверяется - если он указывает на файл, то проходит через кеш, если нет - то загружается "как обычно". Написанная фабрика унаследована от Saxonовской реализации. Остается лишь добиться импортирования трансформеров, как StreamSource. Для этого немного дописал тэг c:import, чтобы при наличии атрибута varSource в указанную переменную пихался соответствующий StreamSource (по аналогии с varReader). [2]
TLD не привожу, ибо тривиально.
Комментарии/пожелания/критика как всегда пожалуйста. Простите, что без Javadoc, оформлять красиво времени пока нет.
[1]
package de.fzi.dbs.xml.transform;
import java.io.File;
import java.io.FileNotFoundException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import javax.xml.transform.Source;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.stream.StreamSource;
import net.sf.saxon.TransformerFactoryImpl;
public class CachingTransformerFactory
extends TransformerFactoryImpl {
private static Map templatesCache = new HashMap();
public Transformer newTransformer(Source source)
throws TransformerConfigurationException {
if (source instanceof StreamSource)
try {
final URI uri = new URI(source.getSystemId());
if ("file".equals(uri.getScheme()))
return newTransformer(new File(uri));
} catch (URISyntaxException urise) {
throw new TransformerConfigurationException(urise);
}
return super.newTransformer(source);
}
public synchronized Transformer newTransformer(File file)
throws TransformerConfigurationException {
Transformer transformer = null;
// Search the cache for the templates entry
TemplatesCacheEntry templatesCacheEntry =
(TemplatesCacheEntry) templatesCache.get(
file.getAbsolutePath());
// If entry found
if (templatesCacheEntry != null) {
// Check timestamp of modification
if (templatesCacheEntry.lastModified
< templatesCacheEntry.templatesFile.lastModified())
templatesCacheEntry = null;
}
// If no templatesEntry is found or this entry was obsolete
if (templatesCacheEntry == null) {
// If this file does not exists, throw the exception
if (!file.exists()) {
throw new TransformerConfigurationException(
"Requested transformation ["
+ file.getAbsolutePath()
+ "] does not exist.");
}
// Create new cache entry
templatesCacheEntry =
new TemplatesCacheEntry(newTemplates(
new StreamSource(file)), file);
// Save this entry to the cache
templatesCache.put(file.getAbsolutePath(),
templatesCacheEntry);
}
return templatesCacheEntry.templates.newTransformer();
}
public static synchronized void clear() {
// Clear templates cache
templatesCache.clear();
}
private class TemplatesCacheEntry {
private long lastModified;
private Templates templates;
private File templatesFile;
private TemplatesCacheEntry(Templates templates,
File templatesFile) {
this.templates = templates;
this.templatesFile = templatesFile;
this.lastModified = templatesFile.lastModified();
}
}
}[2]
package de.fzi.dbs.MT.Taglib;
import java.io.File;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
public class ImportTag
extends org.apache.taglibs.standard.tag.el.core.ImportTag {
private String varSource;
private Source source;
public ImportTag() {
super();
init();
}
private void init() {
varSource = null;
source = null;
}
public void release() {
super.release();
init();
}
public void setVarSource(String varSource) {
this.varSource = varSource;
}
public int doStartTag() throws JspException {
int superResult = super.doStartTag();
if (varSource != null) {
try {
source = acquireSource();
pageContext.setAttribute(varSource, source);
} catch (IOException ioex) {
throw new JspException(ioex);
}
}
return superResult;
}
public int doEndTag() throws JspException {
if (varSource == null)
return super.doEndTag();
return EVAL_PAGE;
}
private Source acquireSource() throws IOException {
if (isAbsoluteUrl(url)) {
return new StreamSource(url);
} else {
final File file =
new File(pageContext.getServletContext().getRealPath(url));
return new StreamSource(file.toURI().toString());
}
}
}



