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

[email protected]
Newsgroups gmane.text.xml.cocoon.cvs
Message-ID <[email protected]>
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"));
+    }
 }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.