You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by il...@apache.org on 2013/02/25 14:56:09 UTC
svn commit: r1449709 - in /cocoon/cocoon3/trunk/cocoon-sax/src:
main/java/org/apache/cocoon/sax/component/XSLTTransformer.java
test/java/org/apache/cocoon/sax/component/XSLTTransformerTest.java
Author: ilgrosso
Date: Mon Feb 25 13:56:08 2013
New Revision: 1449709
URL: http://svn.apache.org/r1449709
Log:
[COCOON3-72] #resolve
Modified:
cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/XSLTTransformer.java
cocoon/cocoon3/trunk/cocoon-sax/src/test/java/org/apache/cocoon/sax/component/XSLTTransformerTest.java
Modified: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/XSLTTransformer.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/XSLTTransformer.java?rev=1449709&r1=1449708&r2=1449709&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/XSLTTransformer.java (original)
+++ cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/XSLTTransformer.java Mon Feb 25 13:56:08 2013
@@ -19,8 +19,8 @@ package org.apache.cocoon.sax.component;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
-import java.util.Map.Entry;
import java.util.regex.Pattern;
+import javax.xml.transform.Source;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
@@ -33,6 +33,7 @@ import org.apache.cocoon.pipeline.SetupE
import org.apache.cocoon.pipeline.caching.CacheKey;
import org.apache.cocoon.pipeline.caching.CompoundCacheKey;
import org.apache.cocoon.pipeline.caching.ParameterCacheKey;
+import org.apache.cocoon.pipeline.caching.TimestampSourceCacheKey;
import org.apache.cocoon.pipeline.caching.TimestampURLCacheKey;
import org.apache.cocoon.pipeline.component.CachingPipelineComponent;
import org.apache.cocoon.pipeline.util.StringRepresentation;
@@ -67,20 +68,26 @@ public class XSLTTransformer extends Abs
*/
private static final Logger LOG = LoggerFactory.getLogger(XSLTTransformer.class);
+ private static final String SOURCE = "source";
+
/**
* The XSLT parameters reference.
*/
private Map<String, Object> parameters;
/**
- * The XSLT URL source.
+ * The XSLT Template reference.
*/
- private URL source;
+ private Templates templates;
/**
- * The XSLT Template reference.
+ * The XSLT URL source.
*/
- private Templates templates;
+ private URL url;
+
+ private long lastModified;
+
+ private Source source;
/**
* Empty constructor, used in sitemap.
@@ -92,10 +99,10 @@ public class XSLTTransformer extends Abs
/**
* Creates a new transformer reading the XSLT from the URL source.
*
- * @param source the XSLT URL source
+ * @param url the XSLT URL source
*/
- public XSLTTransformer(final URL source) {
- this(source, null);
+ public XSLTTransformer(final URL url) {
+ this(url, null);
}
/**
@@ -104,12 +111,37 @@ public class XSLTTransformer extends Abs
* This constructor is useful when users want to perform XSLT transformation using <a
* href="http://xml.apache.org/xalan-j/xsltc_usage.html">xsltc</a>.
*
+ * @param url the XSLT URL source
+ * @param attributes the Transformer Factory attributes
+ */
+ public XSLTTransformer(final URL url, final Map<String, Object> attributes) {
+ super();
+ this.load(url, attributes);
+ }
+
+ /**
+ * Creates a new transformer reading the XSLT from the source.
+ *
* @param source the XSLT URL source
+ * @param lastModified timestamp
+ */
+ public XSLTTransformer(final Source source, final long lastModified) {
+ this(source, lastModified, null);
+ }
+
+ /**
+ * Creates a new transformer reading the XSLT from the Source source and setting the TransformerFactory attributes.
+ *
+ * This constructor is useful when users want to perform XSLT transformation using <a
+ * href="http://xml.apache.org/xalan-j/xsltc_usage.html">xsltc</a>.
+ *
+ * @param source the XSLT source
+ * @param lastModified timestamp
* @param attributes the Transformer Factory attributes
*/
- public XSLTTransformer(final URL source, final Map<String, Object> attributes) {
+ public XSLTTransformer(final Source source, final long lastModified, final Map<String, Object> attributes) {
super();
- this.loadXSLT(source, attributes);
+ this.load(source, lastModified, attributes);
}
/**
@@ -119,54 +151,78 @@ public class XSLTTransformer extends Abs
* This method is useful when users want to perform XSLT transformation using <a
* href="http://xml.apache.org/xalan-j/xsltc_usage.html">xsltc</a>.
*
- * @param source the XSLT URL source
+ * @param url the XSLT URL source
* @param attributes the Transformer Factory attributes
*/
- private void loadXSLT(final URL source, final Map<String, Object> attributes) {
+ private void load(final URL url, final Map<String, Object> attributes) {
+ if (url == null) {
+ throw new IllegalArgumentException("The parameter 'source' mustn't be null.");
+ }
+
+ this.url = url;
+ this.lastModified = URLConnectionUtils.getLastModified(this.url);
+
+ this.load(new StreamSource(this.url.toExternalForm()), this.url.toExternalForm(), attributes);
+ }
+
+ /**
+ * Method useful to create a new transformer reading the XSLT from the URL source and setting the Transformer
+ * Factory attributes.
+ *
+ * This method is useful when users want to perform XSLT transformation using <a
+ * href="http://xml.apache.org/xalan-j/xsltc_usage.html">xsltc</a>.
+ *
+ * @param source the XSLT source
+ * @param lastModified timestamp
+ * @param attributes the Transformer Factory attributes
+ */
+ private void load(final Source source, final long lastModified, final Map<String, Object> attributes) {
if (source == null) {
throw new IllegalArgumentException("The parameter 'source' mustn't be null.");
}
this.source = source;
+ this.lastModified = lastModified;
- Long lastModified = URLConnectionUtils.getLastModified(this.source);
+ this.load(this.source, this.source.toString(), attributes);
+ }
- this.templates = null;
+ private void load(final Source source, final String localCacheKey, final Map<String, Object> attributes) {
// check the XSLT is in the cache first
- if (XSLT_CACHE.containsKey(this.source.toExternalForm())) {
+ if (XSLT_CACHE.containsKey(localCacheKey)) {
// get the XSLT directly from the cache
- ValidityValue<Templates> cacheEntry = XSLT_CACHE.get(this.source.toExternalForm());
- if (lastModified == null || cacheEntry.getLastModified() >= lastModified) {
- LOG.debug("{} local cache hit: {}", getClass().getSimpleName(), this.source.toExternalForm());
+ final ValidityValue<Templates> cacheEntry = XSLT_CACHE.get(localCacheKey);
+ if (cacheEntry.getLastModified() >= lastModified) {
+ LOG.debug("{} local cache hit: {}", getClass().getSimpleName(), localCacheKey);
this.templates = cacheEntry.getValue();
}
}
if (this.templates == null) {
- LOG.debug("{} local cache miss: {}", getClass().getSimpleName(), this.source.toExternalForm());
+ LOG.debug("{} local cache miss: {}", getClass().getSimpleName(), localCacheKey);
// XSLT has to be parsed
- SAXTransformerFactory transformerFactory;
- if (attributes != null && !attributes.isEmpty()) {
+ final SAXTransformerFactory transformerFactory;
+ if (attributes == null || attributes.isEmpty()) {
+ transformerFactory = TRAX_FACTORY;
+ } else {
transformerFactory = createNewSAXTransformerFactory();
- for (Entry<String, Object> attribute : attributes.entrySet()) {
+ for (Map.Entry<String, Object> attribute : attributes.entrySet()) {
transformerFactory.setAttribute(attribute.getKey(), attribute.getValue());
}
- } else {
- transformerFactory = TRAX_FACTORY;
}
try {
- this.templates = transformerFactory.newTemplates(new StreamSource(this.source.toExternalForm()));
+ this.templates = transformerFactory.newTemplates(source);
// store the XSLT into the cache for future reuse
- LOG.debug("{} local cache put: {}", getClass().getSimpleName(), this.source.toExternalForm());
+ LOG.debug("{} local cache put: {}", getClass().getSimpleName(), localCacheKey);
- ValidityValue<Templates> cacheEntry = new ValidityValue<Templates>(this.templates, lastModified);
- XSLT_CACHE.put(this.source.toExternalForm(), cacheEntry);
+ final ValidityValue<Templates> cacheEntry =
+ new ValidityValue<Templates>(this.templates, this.lastModified);
+ XSLT_CACHE.put(localCacheKey, cacheEntry);
} catch (TransformerConfigurationException e) {
- throw new SetupException("Impossible to read XSLT from '" + this.source.toExternalForm()
- + "', see nested exception", e);
+ throw new SetupException("Impossible to read XSLT from '" + source + "', see nested exception", e);
}
}
}
@@ -177,10 +233,10 @@ public class XSLTTransformer extends Abs
* @param parameters the XSLT parameters to be applied to XSLT stylesheet
*/
public void setParameters(final Map<String, ? extends Object> parameters) {
- if (parameters != null) {
- this.parameters = new HashMap<String, Object>(parameters);
- } else {
+ if (parameters == null) {
this.parameters = null;
+ } else {
+ this.parameters = new HashMap<String, Object>(parameters);
}
}
@@ -190,23 +246,23 @@ public class XSLTTransformer extends Abs
@Override
public void setConfiguration(final Map<String, ? extends Object> configuration) {
try {
- this.source = (URL) configuration.get("source");
+ this.url = (URL) configuration.get(SOURCE);
} catch (ClassCastException cce) {
- throw new SetupException("The configuration value of 'source' can't be cast to java.net.URL.", cce);
+ throw new SetupException(
+ "The configuration value of '" + SOURCE + "' can't be cast to " + URL.class.getName(), cce);
}
- if (this.source != null) {
- Object attributesObj = configuration.get("attributes");
- if (attributesObj != null && attributesObj instanceof Map) {
+ if (this.url == null) {
+ LOG.debug("Impossible to load XSLT parameters from null source");
+ } else {
+ final Object attributesObj = configuration.get("attributes");
+ if (attributesObj instanceof Map) {
@SuppressWarnings("unchecked")
- Map<String, Object> attributesMap = (Map<String, Object>) attributesObj;
- this.loadXSLT(this.source, attributesMap);
+ final Map<String, Object> attributesMap = (Map<String, Object>) attributesObj;
+ this.load(this.url, attributesMap);
} else {
- this.loadXSLT(this.source, null);
+ this.load(this.url, null);
}
- } else {
- LOG.debug("Impossible to load XSLT parameters from '{}' source, "
- + "make sure it is NOT null and is a valid URL", this.source.toExternalForm());
}
this.setParameters(configuration);
@@ -227,8 +283,8 @@ public class XSLTTransformer extends Abs
if (this.parameters != null) {
final Transformer transformer = transformerHandler.getTransformer();
- for (Entry<String, Object> entry : this.parameters.entrySet()) {
- String name = entry.getKey();
+ for (Map.Entry<String, Object> entry : this.parameters.entrySet()) {
+ final String name = entry.getKey();
// is valid XSLT parameter name
if (XSLT_PARAMETER_NAME_PATTERN.matcher(name).matches()) {
@@ -243,10 +299,11 @@ public class XSLTTransformer extends Abs
result.setLexicalHandler(consumer);
transformerHandler.setResult(result);
- TraxErrorListener traxErrorListener = new TraxErrorListener(LOG, this.source.toExternalForm());
+ final TraxErrorListener traxErrorListener = new TraxErrorListener(LOG,
+ this.url == null ? this.source.toString() : this.url.toExternalForm());
transformerHandler.getTransformer().setErrorListener(traxErrorListener);
- SAXConsumerAdapter saxConsumerAdapter = new SAXConsumerAdapter();
+ final SAXConsumerAdapter saxConsumerAdapter = new SAXConsumerAdapter();
saxConsumerAdapter.setContentHandler(transformerHandler);
super.setSAXConsumer(saxConsumerAdapter);
}
@@ -258,12 +315,14 @@ public class XSLTTransformer extends Abs
*/
@Override
public CacheKey constructCacheKey() {
- if (this.source == null) {
+ if (this.url == null && this.source == null) {
throw new SetupException(this.getClass().getSimpleName() + " has no source.");
}
final CompoundCacheKey cacheKey = new CompoundCacheKey();
- cacheKey.addCacheKey(new TimestampURLCacheKey(this.source, URLConnectionUtils.getLastModified(this.source)));
+ cacheKey.addCacheKey(this.url == null
+ ? new TimestampSourceCacheKey(this.source, this.lastModified)
+ : new TimestampURLCacheKey(this.url, this.lastModified));
cacheKey.addCacheKey(ParameterCacheKey.getSitemapSafeInstance(this.parameters));
return cacheKey;
@@ -280,6 +339,8 @@ public class XSLTTransformer extends Abs
@Override
public String toString() {
- return StringRepresentation.buildString(this, "src=" + this.source);
+ return StringRepresentation.buildString(this, "src=" + (this.url == null
+ ? "<" + this.source + "," + this.lastModified + ">"
+ : this.url.toExternalForm()));
}
}
Modified: cocoon/cocoon3/trunk/cocoon-sax/src/test/java/org/apache/cocoon/sax/component/XSLTTransformerTest.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sax/src/test/java/org/apache/cocoon/sax/component/XSLTTransformerTest.java?rev=1449709&r1=1449708&r2=1449709&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sax/src/test/java/org/apache/cocoon/sax/component/XSLTTransformerTest.java (original)
+++ cocoon/cocoon3/trunk/cocoon-sax/src/test/java/org/apache/cocoon/sax/component/XSLTTransformerTest.java Mon Feb 25 13:56:08 2013
@@ -16,25 +16,38 @@
*/
package org.apache.cocoon.sax.component;
-import static junit.framework.Assert.*;
+import static org.junit.Assert.assertFalse;
import java.io.ByteArrayOutputStream;
import java.util.Collections;
+import javax.xml.transform.stream.StreamSource;
import org.apache.cocoon.pipeline.CachingPipeline;
import org.apache.cocoon.pipeline.caching.Cache;
import org.apache.cocoon.pipeline.caching.SimpleCache;
+import org.apache.cocoon.pipeline.util.URLConnectionUtils;
import org.apache.cocoon.sax.SAXPipelineComponent;
import org.junit.Test;
public class XSLTTransformerTest {
- private CachingPipeline<SAXPipelineComponent> makePipeline(final Cache cache, final String paramValue) {
- CachingPipeline<SAXPipelineComponent> pipeline = new CachingPipeline<SAXPipelineComponent>();
+ private CachingPipeline<SAXPipelineComponent> makeURLPipeline(final Cache cache, final String paramValue) {
+ return makePipelineInternal(cache, paramValue, new XSLTTransformer(getClass().getResource("/test.xslt")));
+ }
+
+ private CachingPipeline<SAXPipelineComponent> makeSourcePipeline(final Cache cache, final String paramValue) {
+ return makePipelineInternal(cache, paramValue, new XSLTTransformer(
+ new StreamSource(getClass().getResourceAsStream("/test.xslt")),
+ URLConnectionUtils.getLastModified(getClass().getResource("/test.xslt"))));
+ }
+
+ private CachingPipeline<SAXPipelineComponent> makePipelineInternal(final Cache cache, final String paramValue,
+ final XSLTTransformer xslt) {
+
+ final CachingPipeline<SAXPipelineComponent> pipeline = new CachingPipeline<SAXPipelineComponent>();
pipeline.setCache(cache);
pipeline.addComponent(new XMLGenerator(getClass().getResource("/test.xml")));
- XSLTTransformer xslt = new XSLTTransformer(getClass().getResource("/test.xslt"));
xslt.setParameters(Collections.singletonMap("myParam", paramValue));
pipeline.addComponent(xslt);
@@ -43,22 +56,28 @@ public class XSLTTransformerTest {
return pipeline;
}
- @Test
- public void cache() throws Exception {
- Cache cache = new SimpleCache();
+ private void cacheInternal(final CachingPipeline<SAXPipelineComponent> pipeline1,
+ final CachingPipeline<SAXPipelineComponent> pipeline2) throws Exception {
- CachingPipeline<SAXPipelineComponent> pipeline1 = makePipeline(cache, "value1");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
pipeline1.setup(baos);
pipeline1.execute();
- String result1 = new String(baos.toByteArray(), "UTF-8");
+ final String result1 = new String(baos.toByteArray(), "UTF-8");
- CachingPipeline<SAXPipelineComponent> pipeline2 = makePipeline(cache, "value2");
baos = new ByteArrayOutputStream();
pipeline2.setup(baos);
pipeline2.execute();
- String result2 = new String(baos.toByteArray(), "UTF-8");
+ final String result2 = new String(baos.toByteArray(), "UTF-8");
assertFalse("Pipeline caching is not working as expected", result1.equals(result2));
}
+
+ @Test
+ public void cache() throws Exception {
+ Cache cache = new SimpleCache();
+ cacheInternal(makeURLPipeline(cache, "value1"), makeURLPipeline(cache, "value2"));
+
+ cache = new SimpleCache();
+ cacheInternal(makeSourcePipeline(cache, "value1"), makeSourcePipeline(cache, "value2"));
+ }
}