Author: jboynes
Date: Sat Nov 29 16:06:54 2014
New Revision: 1642442

URL: http://svn.apache.org/r1642442
Log:
Refactor and consolidate XML processing

Added:
    
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/XmlUtil.java
   (with props)
    
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/util/UnclosableWriter.java
   (with props)
    
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/util/UrlUtil.java
   (with props)
Modified:
    
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/ImportSupport.java
    
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/RedirectSupport.java
    
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/UrlSupport.java
    
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/ParseSupport.java
    
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/TransformSupport.java
    
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/XalanUtil.java
    
tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/ExprSupportTest.java
    
tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/ForEachTagTest.java
    
tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/JSTLVariableStackTest.java

Modified: 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/ImportSupport.java
URL: 
http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/ImportSupport.java?rev=1642442&r1=1642441&r2=1642442&view=diff
==============================================================================
--- 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/ImportSupport.java
 (original)
+++ 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/ImportSupport.java
 Sat Nov 29 16:06:54 2014
@@ -47,6 +47,7 @@ import javax.servlet.jsp.tagext.BodyTagS
 import javax.servlet.jsp.tagext.TryCatchFinally;
 
 import org.apache.taglibs.standard.resources.Resources;
+import org.apache.taglibs.standard.util.UrlUtil;
 
 /**
  * <p>Support for tag handlers for &lt;import&gt;, the general-purpose
@@ -63,23 +64,6 @@ public abstract class ImportSupport exte
     // Public constants
 
     /**
-     * <p>Valid characters in a scheme.</p>
-     * <p>RFC 1738 says the following:</p>
-     * <blockquote>
-     * Scheme names consist of a sequence of characters. The lower
-     * case letters "a"--"z", digits, and the characters plus ("+"),
-     * period ("."), and hyphen ("-") are allowed. For resiliency,
-     * programs interpreting URLs should treat upper case letters as
-     * equivalent to lower case in scheme names (e.g., allow "HTTP" as
-     * well as "http").
-     * </blockquote>
-     * <p>We treat as absolute any URL that begins with such a scheme name,
-     * followed by a colon.</p>
-     */
-    public static final String VALID_SCHEME_CHARS =
-            
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+.-";
-
-    /**
      * Default character encoding for response.
      */
     public static final String DEFAULT_ENCODING = "ISO-8859-1";
@@ -141,7 +125,7 @@ public abstract class ImportSupport exte
         }
 
         // Record whether our URL is absolute or relative
-        isAbsoluteUrl = isAbsoluteUrl();
+        isAbsoluteUrl = UrlUtil.isAbsoluteUrl(url);
 
         try {
             // If we need to expose a Reader, we've got to do it right away
@@ -579,47 +563,11 @@ public abstract class ImportSupport exte
         return urlWithParams;
     }
 
-    /**
-     * Returns <tt>true</tt> if our current URL is absolute,
-     * <tt>false</tt> otherwise.
-     */
-    private boolean isAbsoluteUrl() throws JspTagException {
-        return isAbsoluteUrl(url);
-    }
-
 
     //*********************************************************************
     // Public utility methods
 
     /**
-     * Returns <tt>true</tt> if our current URL is absolute,
-     * <tt>false</tt> otherwise.
-     */
-    public static boolean isAbsoluteUrl(String url) {
-        // a null URL is not absolute, by our definition
-        if (url == null) {
-            return false;
-        }
-
-        // do a fast, simple check first
-        int colonPos;
-        if ((colonPos = url.indexOf(":")) == -1) {
-            return false;
-        }
-
-        // if we DO have a colon, make sure that every character
-        // leading up to it is a valid scheme character
-        for (int i = 0; i < colonPos; i++) {
-            if (VALID_SCHEME_CHARS.indexOf(url.charAt(i)) == -1) {
-                return false;
-            }
-        }
-
-        // if so, we've got an absolute url
-        return true;
-    }
-
-    /**
      * Strips a servlet session ID from <tt>url</tt>.  The session ID
      * is encoded as a URL "path parameter" beginning with "jsessionid=".
      * We thus remove anything we find between ";jsessionid=" (inclusive)

Modified: 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/RedirectSupport.java
URL: 
http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/RedirectSupport.java?rev=1642442&r1=1642441&r2=1642442&view=diff
==============================================================================
--- 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/RedirectSupport.java
 (original)
+++ 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/RedirectSupport.java
 Sat Nov 29 16:06:54 2014
@@ -23,6 +23,8 @@ import javax.servlet.jsp.JspTagException
 import javax.servlet.jsp.PageContext;
 import javax.servlet.jsp.tagext.BodyTagSupport;
 
+import org.apache.taglibs.standard.util.UrlUtil;
+
 /**
  * <p>Support for tag handlers for &lt;redirect&gt;, JSTL 1.0's tag
  * for redirecting to a new URL (with optional query parameters).</p>
@@ -108,7 +110,7 @@ public abstract class RedirectSupport ex
         // if the URL is relative, rewrite it with 'redirect' encoding rules
         HttpServletResponse response =
                 ((HttpServletResponse) pageContext.getResponse());
-        if (!ImportSupport.isAbsoluteUrl(result)) {
+        if (!UrlUtil.isAbsoluteUrl(result)) {
             result = response.encodeRedirectURL(result);
         }
 

Modified: 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/UrlSupport.java
URL: 
http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/UrlSupport.java?rev=1642442&r1=1642441&r2=1642442&view=diff
==============================================================================
--- 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/UrlSupport.java
 (original)
+++ 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/UrlSupport.java
 Sat Nov 29 16:06:54 2014
@@ -25,6 +25,7 @@ import javax.servlet.jsp.PageContext;
 import javax.servlet.jsp.tagext.BodyTagSupport;
 
 import org.apache.taglibs.standard.resources.Resources;
+import org.apache.taglibs.standard.util.UrlUtil;
 
 /**
  * <p>Support for tag handlers for &lt;url&gt;, the URL creation
@@ -110,7 +111,7 @@ public abstract class UrlSupport extends
         result = params.aggregateParams(baseUrl);
 
         // if the URL is relative, rewrite it
-        if (!ImportSupport.isAbsoluteUrl(result)) {
+        if (!UrlUtil.isAbsoluteUrl(result)) {
             HttpServletResponse response =
                     ((HttpServletResponse) pageContext.getResponse());
             result = response.encodeURL(result);
@@ -144,7 +145,7 @@ public abstract class UrlSupport extends
             String url, String context, PageContext pageContext)
             throws JspException {
         // don't touch absolute URLs
-        if (ImportSupport.isAbsoluteUrl(url)) {
+        if (UrlUtil.isAbsoluteUrl(url)) {
             return url;
         }
 

Modified: 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/ParseSupport.java
URL: 
http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/ParseSupport.java?rev=1642442&r1=1642441&r2=1642442&view=diff
==============================================================================
--- 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/ParseSupport.java
 (original)
+++ 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/ParseSupport.java
 Sat Nov 29 16:06:54 2014
@@ -17,36 +17,26 @@
 
 package org.apache.taglibs.standard.tag.common.xml;
 
-import java.io.FileNotFoundException;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.Reader;
 import java.io.StringReader;
 
-import javax.servlet.http.HttpServletRequest;
 import javax.servlet.jsp.JspException;
 import javax.servlet.jsp.JspTagException;
 import javax.servlet.jsp.PageContext;
 import javax.servlet.jsp.tagext.BodyTagSupport;
 import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.transform.TransformerConfigurationException;
-import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.dom.DOMResult;
-import javax.xml.transform.sax.SAXTransformerFactory;
 import javax.xml.transform.sax.TransformerHandler;
 
 import org.apache.taglibs.standard.resources.Resources;
-import org.apache.taglibs.standard.tag.common.core.ImportSupport;
 import org.apache.taglibs.standard.tag.common.core.Util;
 import org.w3c.dom.Document;
-import org.xml.sax.EntityResolver;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
 import org.xml.sax.XMLFilter;
 import org.xml.sax.XMLReader;
-import org.xml.sax.helpers.XMLReaderFactory;
 
 /**
  * <p>Support for tag handlers for &lt;parse&gt;, the XML parsing tag.</p>
@@ -69,12 +59,7 @@ public abstract class ParseSupport exten
     private String varDom;               // 'varDom' attribute
     private int scope;                   // processed 'scope' attr
     private int scopeDom;               // processed 'scopeDom' attr
-
-    // state in support of XML parsing...
-    private DocumentBuilderFactory dbf;
-    private DocumentBuilder db;
-    private TransformerFactory tf;
-    private TransformerHandler th;
+    private XmlUtil.JstlEntityResolver entityResolver;
 
 
     //*********************************************************************
@@ -90,15 +75,10 @@ public abstract class ParseSupport exten
         xml = null;
         systemId = null;
         filter = null;
-        dbf = null;
-        db = null;
-        tf = null;
-        th = null;
         scope = PageContext.PAGE_SCOPE;
         scopeDom = PageContext.PAGE_SCOPE;
     }
 
-
     //*********************************************************************
     // Tag logic
 
@@ -106,68 +86,41 @@ public abstract class ParseSupport exten
 
     @Override
     public int doEndTag() throws JspException {
-        try {
-
-            // set up our DocumentBuilder
-            if (dbf == null) {
-                dbf = DocumentBuilderFactory.newInstance();
-                dbf.setNamespaceAware(true);
-                dbf.setValidating(false);
-            }
-            db = dbf.newDocumentBuilder();
-
-            // if we've gotten a filter, set up a transformer to support it
-            if (filter != null) {
-                if (tf == null) {
-                    tf = TransformerFactory.newInstance();
-                }
-                if (!tf.getFeature(SAXTransformerFactory.FEATURE)) {
-                    throw new JspTagException(
-                            Resources.getMessage("PARSE_NO_SAXTRANSFORMER"));
-                }
-                SAXTransformerFactory stf = (SAXTransformerFactory) tf;
-                th = stf.newTransformerHandler();
-            }
-
-            // produce a Document by parsing whatever the attributes tell us 
to use
-            Document d;
-            Object xmlText = this.xml;
-            if (xmlText == null) {
-                // if the attribute was specified, use the body as 'xml'
-                if (bodyContent != null && bodyContent.getString() != null) {
-                    xmlText = bodyContent.getString().trim();
-                } else {
-                    xmlText = "";
-                }
-            }
-            if (xmlText instanceof String) {
-                d = parseStringWithFilter((String) xmlText, filter);
-            } else if (xmlText instanceof Reader) {
-                d = parseReaderWithFilter((Reader) xmlText, filter);
+        // produce a Document by parsing whatever the attributes tell us to use
+        Object xmlText = this.xml;
+        if (xmlText == null) {
+            // if the attribute was specified, use the body as 'xml'
+            if (bodyContent != null && bodyContent.getString() != null) {
+                xmlText = bodyContent.getString().trim();
             } else {
-                throw new JspTagException(
-                        Resources.getMessage("PARSE_INVALID_SOURCE"));
+                xmlText = "";
             }
+        }
+        if (xmlText instanceof String) {
+            xmlText = new StringReader((String) xmlText);
+        }
+        if (!(xmlText instanceof Reader)) {
+            throw new 
JspTagException(Resources.getMessage("PARSE_INVALID_SOURCE"));
+        }
+        InputSource source = XmlUtil.newInputSource(((Reader) xmlText), 
systemId);
 
-            // we've got a Document object; store it out as appropriate
-            // (let any exclusivity or other constraints be enforced by 
TEI/TLV)
-            if (var != null) {
-                pageContext.setAttribute(var, d, scope);
-            }
-            if (varDom != null) {
-                pageContext.setAttribute(varDom, d, scopeDom);
-            }
+        Document d;
+        if (filter != null) {
+            d = parseInputSourceWithFilter(source, filter);
+        } else {
+            d = parseInputSource(source);
+        }
 
-            return EVAL_PAGE;
-        } catch (SAXException ex) {
-            throw new JspException(ex);
-        } catch (IOException ex) {
-            throw new JspException(ex);
-        } catch (ParserConfigurationException ex) {
-            throw new JspException(ex);
-        } catch (TransformerConfigurationException ex) {
-            throw new JspException(ex);
+        // we've got a Document object; store it out as appropriate
+        // (let any exclusivity or other constraints be enforced by TEI/TLV)
+        if (var != null) {
+            pageContext.setAttribute(var, d, scope);
         }
+        if (varDom != null) {
+            pageContext.setAttribute(varDom, d, scopeDom);
+        }
+
+        return EVAL_PAGE;
     }
 
     // Releases any resources we may have (or inherit)
@@ -184,151 +137,50 @@ public abstract class ParseSupport exten
     /**
      * Parses the given InputSource after, applying the given XMLFilter.
      */
-    private Document parseInputSourceWithFilter(InputSource s, XMLFilter f)
-            throws SAXException, IOException {
-        if (f != null) {
-            // prepare an output Document
-            Document o = db.newDocument();
-
-            // use TrAX to adapt SAX events to a Document object
-            th.setResult(new DOMResult(o));
-            XMLReader xr = XMLReaderFactory.createXMLReader();
-            xr.setEntityResolver(new JstlEntityResolver(pageContext));
+    private Document parseInputSourceWithFilter(InputSource s, XMLFilter f) 
throws JspException {
+        try {
+            XMLReader xr = XmlUtil.newXMLReader(entityResolver);
             //   (note that we overwrite the filter's parent.  this seems
             //    to be expected usage.  we could cache and reset the old
             //    parent, but you can't setParent(null), so this wouldn't
             //    be perfect.)
             f.setParent(xr);
+
+            TransformerHandler th = XmlUtil.newTransformerHandler();
+            Document o = XmlUtil.newEmptyDocument();
+            th.setResult(new DOMResult(o));
             f.setContentHandler(th);
+
             f.parse(s);
             return o;
-        } else {
-            return parseInputSource(s);
+        } catch (IOException e) {
+            throw new JspException(e);
+        } catch (SAXException e) {
+            throw new JspException(e);
+        } catch (TransformerConfigurationException e) {
+            throw new JspException(e);
         }
     }
 
     /**
-     * Parses the given Reader after applying the given XMLFilter.
-     */
-    private Document parseReaderWithFilter(Reader r, XMLFilter f)
-            throws SAXException, IOException {
-        return parseInputSourceWithFilter(new InputSource(r), f);
-    }
-
-    /**
-     * Parses the given String after applying the given XMLFilter.
-     */
-    private Document parseStringWithFilter(String s, XMLFilter f)
-            throws SAXException, IOException {
-        StringReader r = new StringReader(s);
-        return parseReaderWithFilter(r, f);
-    }
-
-    /**
-     * Parses the given Reader after applying the given XMLFilter.
-     */
-    private Document parseURLWithFilter(String url, XMLFilter f)
-            throws SAXException, IOException {
-        return parseInputSourceWithFilter(new InputSource(url), f);
-    }
-
-    /**
      * Parses the given InputSource into a Document.
      */
-    private Document parseInputSource(InputSource s)
-            throws SAXException, IOException {
-        db.setEntityResolver(new JstlEntityResolver(pageContext));
-
-        // normalize URIs so they can be processed consistently by resolver
-        if (systemId == null) {
-            s.setSystemId("jstl:");
-        } else if (ImportSupport.isAbsoluteUrl(systemId)) {
-            s.setSystemId(systemId);
-        } else {
-            s.setSystemId("jstl:" + systemId);
+    private Document parseInputSource(InputSource s) throws JspException {
+        try {
+            DocumentBuilder db = XmlUtil.newDocumentBuilder();
+            db.setEntityResolver(entityResolver);
+            return db.parse(s);
+        } catch (SAXException e) {
+            throw new JspException(e);
+        } catch (IOException e) {
+            throw new JspException(e);
         }
-        return db.parse(s);
     }
 
-    /**
-     * Parses the given Reader into a Document.
-     */
-    private Document parseReader(Reader r) throws SAXException, IOException {
-        return parseInputSource(new InputSource(r));
-    }
-
-    /**
-     * Parses the given String into a Document.
-     */
-    private Document parseString(String s) throws SAXException, IOException {
-        StringReader r = new StringReader(s);
-        return parseReader(r);
-    }
-
-    /**
-     * Parses the URL (passed as a String) into a Document.
-     */
-    private Document parseURL(String url) throws SAXException, IOException {
-        return parseInputSource(new InputSource(url));
-    }
-
-    //*********************************************************************
-    // JSTL-specific EntityResolver class
-
-    /**
-     * Lets us resolve relative external entities.
-     */
-    public static class JstlEntityResolver implements EntityResolver {
-        private final PageContext ctx;
-
-        public JstlEntityResolver(PageContext ctx) {
-            this.ctx = ctx;
-        }
-
-        public InputSource resolveEntity(String publicId, String systemId)
-                throws FileNotFoundException {
-
-            // pass if we don't have a systemId
-            if (systemId == null) {
-                return null;
-            }
-
-            // strip leading "jstl:" off URL if applicable
-            if (systemId.startsWith("jstl:")) {
-                systemId = systemId.substring(5);
-            }
-
-            // we're only concerned with relative URLs
-            if (ImportSupport.isAbsoluteUrl(systemId)) {
-                return null;
-            }
-
-            // for relative URLs, load and wrap the resource.
-            // don't bother checking for 'null' since we specifically want
-            // the parser to fail if the resource doesn't exist
-            InputStream s;
-            if (systemId.startsWith("/")) {
-                s = ctx.getServletContext().getResourceAsStream(systemId);
-                if (s == null) {
-                    throw new FileNotFoundException(
-                            Resources.getMessage("UNABLE_TO_RESOLVE_ENTITY",
-                                    systemId));
-                }
-            } else {
-                String pagePath =
-                        ((HttpServletRequest) 
ctx.getRequest()).getServletPath();
-                String basePath =
-                        pagePath.substring(0, pagePath.lastIndexOf("/"));
-                s = ctx.getServletContext().getResourceAsStream(
-                        basePath + "/" + systemId);
-                if (s == null) {
-                    throw new FileNotFoundException(
-                            Resources.getMessage("UNABLE_TO_RESOLVE_ENTITY",
-                                    systemId));
-                }
-            }
-            return new InputSource(s);
-        }
+    @Override
+    public void setPageContext(PageContext pageContext) {
+        super.setPageContext(pageContext);
+        entityResolver = pageContext == null ? null: new 
XmlUtil.JstlEntityResolver(pageContext);
     }
 
     //*********************************************************************

Modified: 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/TransformSupport.java
URL: 
http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/TransformSupport.java?rev=1642442&r1=1642441&r2=1642442&view=diff
==============================================================================
--- 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/TransformSupport.java
 (original)
+++ 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/TransformSupport.java
 Sat Nov 29 16:06:54 2014
@@ -17,43 +17,29 @@
 
 package org.apache.taglibs.standard.tag.common.xml;
 
-import java.io.IOException;
-import java.io.InputStream;
 import java.io.Reader;
 import java.io.StringReader;
-import java.io.Writer;
 import java.util.List;
 
-import javax.servlet.http.HttpServletRequest;
 import javax.servlet.jsp.JspException;
 import javax.servlet.jsp.JspTagException;
 import javax.servlet.jsp.PageContext;
 import javax.servlet.jsp.tagext.BodyTagSupport;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.transform.Result;
 import javax.xml.transform.Source;
 import javax.xml.transform.Transformer;
 import javax.xml.transform.TransformerConfigurationException;
 import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.URIResolver;
 import javax.xml.transform.dom.DOMResult;
 import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.sax.SAXSource;
 import javax.xml.transform.stream.StreamResult;
-import javax.xml.transform.stream.StreamSource;
 
 import org.apache.taglibs.standard.resources.Resources;
-import org.apache.taglibs.standard.tag.common.core.ImportSupport;
 import org.apache.taglibs.standard.tag.common.core.Util;
+import org.apache.taglibs.standard.util.UnclosableWriter;
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
-import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
-import org.xml.sax.helpers.XMLReaderFactory;
 
 /**
  * <p>Support for tag handlers for &lt;transform&gt;, the XML transformation
@@ -79,24 +65,14 @@ public abstract class TransformSupport e
     private String var;                 // 'var' attribute
     private int scope;                  // processed 'scope' attr
     private Transformer t;              // actual Transformer
-    private TransformerFactory tf;      // reusable factory
-    private DocumentBuilder db;         // reusable factory
+    private XmlUtil.JstlEntityResolver entityResolver;
+    private XmlUtil.JstlUriResolver uriResolver;
 
 
     //*********************************************************************
     // Constructor and initialization
 
     public TransformSupport() {
-        try {
-            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
-            dbf.setNamespaceAware(true);
-            dbf.setValidating(false);
-            db = dbf.newDocumentBuilder();
-            tf = TransformerFactory.newInstance();
-        } catch (ParserConfigurationException e) {
-            throw (AssertionError) new AssertionError("Unable to create 
DocumentBuilder").initCause(e);
-        }
-
         init();
     }
 
@@ -106,7 +82,6 @@ public abstract class TransformSupport e
         xmlSystemId = xsltSystemId = null;
         var = null;
         result = null;
-        tf.setURIResolver(null);
         scope = PageContext.PAGE_SCOPE;
     }
 
@@ -117,36 +92,69 @@ public abstract class TransformSupport e
     @Override
     public int doStartTag() throws JspException {
         // set up transformer in the start tag so that nested <param> tags can 
set parameters directly
-        t = getTransformer(xslt, xsltSystemId);
+        if (xslt == null) {
+            throw new 
JspTagException(Resources.getMessage("TRANSFORM_XSLT_IS_NULL"));
+        }
+
+        Source source;
+        try {
+            if (xslt instanceof Source) {
+                source = (Source) xslt;
+            } else if (xslt instanceof String) {
+                String s = (String) xslt;
+                s = s.trim();
+                if (s.length() == 0) {
+                    throw new 
JspTagException(Resources.getMessage("TRANSFORM_XSLT_IS_EMPTY"));
+                }
+                source = XmlUtil.newSAXSource(new StringReader(s), 
xsltSystemId, entityResolver);
+            } else if (xslt instanceof Reader) {
+                source = XmlUtil.newSAXSource((Reader) xslt, xsltSystemId, 
entityResolver);
+            } else {
+                throw new 
JspTagException(Resources.getMessage("TRANSFORM_XSLT_UNSUPPORTED_TYPE", 
xslt.getClass()));
+            }
+        } catch (SAXException e) {
+            throw new JspException(e);
+        }
+
+        try {
+            t = XmlUtil.newTransformer(source);
+            t.setURIResolver(uriResolver);
+        } catch (TransformerConfigurationException e) {
+            throw new JspTagException(e);
+        } catch (RuntimeException e) {
+            throw e;
+        }
         return EVAL_BODY_BUFFERED;
     }
 
     @Override
     public int doEndTag() throws JspException {
-        Source source = xmlSpecified ? getSourceFromXmlAttribute() : 
getDocumentFromBodyContent();
 
         try {
-            //************************************
-            // Conduct the transformation
+            Source source = xmlSpecified ? getSourceFromXmlAttribute() : 
getSourceFromBodyContent();
 
-            // we can assume at most one of 'var' or 'result' is specified
-            if (result != null)
-            // we can write directly to the Result
-            {
-                t.transform(source, result);
-            } else if (var != null) {
-                // we need a Document
-                Document d = db.newDocument();
+            // Conduct the transformation
+            if (var != null) {
+                // Save the result to var.
+                Document d = XmlUtil.newEmptyDocument();
                 Result doc = new DOMResult(d);
                 t.transform(source, doc);
                 pageContext.setAttribute(var, d, scope);
             } else {
-                Result page = new StreamResult(new 
SafeWriter(pageContext.getOut()));
-                t.transform(source, page);
+                // Write to out if result is not specified.
+                Result out = result;
+                if (out == null) {
+                    out = new StreamResult(new 
UnclosableWriter(pageContext.getOut()));
+                }
+                t.transform(source, out);
             }
             return EVAL_PAGE;
         } catch (TransformerException ex) {
             throw new JspException(ex);
+        } catch (SAXException e) {
+            throw new JspException(e);
+        } finally {
+            t = null;
         }
     }
 
@@ -161,7 +169,8 @@ public abstract class TransformSupport e
     @Override
     public void setPageContext(PageContext pageContext) {
         super.setPageContext(pageContext);
-        tf.setURIResolver(pageContext == null ? null : new 
JstlUriResolver(pageContext));
+        uriResolver = pageContext == null ? null : new 
XmlUtil.JstlUriResolver(pageContext);
+        entityResolver = pageContext == null ? null : new 
XmlUtil.JstlEntityResolver(pageContext);
     }
 
 
@@ -180,64 +189,12 @@ public abstract class TransformSupport e
     // Utility methods
 
     /**
-     * Wraps systemId with a "jstl:" prefix to prevent the parser from
-     * thinking that the URI is truly relative and resolving it against
-     * the current directory in the filesystem.
-     */
-    private static String wrapSystemId(String systemId) {
-        if (systemId == null) {
-            return "jstl:";
-        } else if (ImportSupport.isAbsoluteUrl(systemId)) {
-            return systemId;
-        } else {
-            return ("jstl:" + systemId);
-        }
-    }
-
-    /**
-     * Create a Transformer from the xslt attribute.
-     *
-     * @param xslt     the xslt attribute
-     * @param systemId the systemId for the transform
-     * @return an XSLT transformer
-     * @throws JspException if there was a problem creating the transformer
-     */
-    Transformer getTransformer(Object xslt, String systemId) throws 
JspException {
-        if (xslt == null) {
-            throw new 
JspTagException(Resources.getMessage("TRANSFORM_XSLT_IS_NULL"));
-        }
-        Source source;
-        if (xslt instanceof Source) {
-            source = (Source) xslt;
-        } else {
-            if (xslt instanceof String) {
-                String s = (String) xslt;
-                s = s.trim();
-                if (s.length() == 0) {
-                    throw new 
JspTagException(Resources.getMessage("TRANSFORM_XSLT_IS_EMPTY"));
-                }
-                xslt = new StringReader(s);
-            }
-            if (xslt instanceof Reader) {
-                source = getSource((Reader) xslt, systemId);
-            } else {
-                throw new 
JspTagException(Resources.getMessage("TRANSFORM_XSLT_UNSUPPORTED_TYPE", 
xslt.getClass()));
-            }
-        }
-        try {
-            return tf.newTransformer(source);
-        } catch (TransformerConfigurationException e) {
-            throw new JspTagException(e);
-        }
-    }
-
-    /**
      * Return the Source for a document specified in the "doc" or "xml" 
attribute.
      *
      * @return the document Source
      * @throws JspTagException if there is a problem with the attribute
      */
-    Source getSourceFromXmlAttribute() throws JspTagException {
+    Source getSourceFromXmlAttribute() throws JspTagException, SAXException {
         Object xml = this.xml;
         if (xml == null) {
             throw new 
JspTagException(Resources.getMessage("TRANSFORM_XML_IS_NULL"));
@@ -261,10 +218,10 @@ public abstract class TransformSupport e
             if (s.length() == 0) {
                 throw new 
JspTagException(Resources.getMessage("TRANSFORM_XML_IS_EMPTY"));
             }
-            return getSource(new StringReader(s), xmlSystemId);
+            return XmlUtil.newSAXSource(new StringReader(s), xmlSystemId, 
entityResolver);
         }
         if (xml instanceof Reader) {
-            return getSource((Reader) xml, xmlSystemId);
+            return XmlUtil.newSAXSource((Reader) xml, xmlSystemId, 
entityResolver);
         }
         if (xml instanceof Node) {
             return new DOMSource((Node) xml, xmlSystemId);
@@ -278,7 +235,7 @@ public abstract class TransformSupport e
      * @return the document Source
      * @throws JspTagException if there is a problem with the body content
      */
-    Source getDocumentFromBodyContent() throws JspTagException {
+    Source getSourceFromBodyContent() throws JspTagException, SAXException {
         if (bodyContent == null) {
             throw new 
JspTagException(Resources.getMessage("TRANSFORM_BODY_IS_NULL"));
         }
@@ -290,31 +247,7 @@ public abstract class TransformSupport e
         if (s.length() == 0) {
             throw new 
JspTagException(Resources.getMessage("TRANSFORM_BODY_IS_EMPTY"));
         }
-        return getSource(new StringReader(s), xmlSystemId);
-    }
-
-    /**
-     * Create a Source from a Reader
-     *
-     * @param reader   the Reader to read
-     * @param systemId the systemId for the document
-     * @return a SAX Source
-     * @throws JspTagException if there is a problem creating the Source
-     */
-    Source getSource(Reader reader, String systemId) throws JspTagException {
-        try {
-            // explicitly go through SAX to maintain control
-            // over how relative external entities resolve
-            XMLReader xr = XMLReaderFactory.createXMLReader();
-            xr.setEntityResolver(new 
ParseSupport.JstlEntityResolver(pageContext));
-            InputSource s = new InputSource(reader);
-            s.setSystemId(wrapSystemId(systemId));
-            Source source = new SAXSource(xr, s);
-            source.setSystemId(wrapSystemId(systemId));
-            return source;
-        } catch (SAXException e) {
-            throw new JspTagException(e);
-        }
+        return XmlUtil.newSAXSource(new StringReader(s), xmlSystemId, 
entityResolver);
     }
 
 
@@ -328,109 +261,4 @@ public abstract class TransformSupport e
     public void setScope(String scope) {
         this.scope = Util.getScope(scope);
     }
-
-
-    //*********************************************************************
-    // Private utility classes
-
-    /**
-     * A Writer based on a wrapped Writer but ignoring requests to
-     * close() and flush() it.  (Someone must have wrapped the
-     * toilet in my office similarly...)
-     */
-    private static class SafeWriter extends Writer {
-        // TODO: shouldn't we be delegating all methods?
-        private Writer w;
-
-        public SafeWriter(Writer w) {
-            this.w = w;
-        }
-
-        @Override
-        public void close() {
-        }
-
-        @Override
-        public void flush() {
-        }
-
-        @Override
-        public void write(char[] cbuf, int off, int len) throws IOException {
-            w.write(cbuf, off, len);
-        }
-    }
-
-    //*********************************************************************
-    // JSTL-specific URIResolver class
-
-    /**
-     * Lets us resolve relative external entities.
-     */
-    private static class JstlUriResolver implements URIResolver {
-        private final PageContext ctx;
-
-        public JstlUriResolver(PageContext ctx) {
-            this.ctx = ctx;
-        }
-
-        public Source resolve(String href, String base)
-                throws TransformerException {
-
-            // pass if we don't have a systemId
-            if (href == null) {
-                return null;
-            }
-
-            // remove "jstl" marker from 'base'
-            // NOTE: how 'base' is determined varies among different Xalan
-            // xsltc implementations
-            int index;
-            if (base != null && (index = base.indexOf("jstl:")) != -1) {
-                base = base.substring(index + 5);
-            }
-
-            // we're only concerned with relative URLs
-            if (ImportSupport.isAbsoluteUrl(href)
-                    || (base != null && ImportSupport.isAbsoluteUrl(base))) {
-                return null;
-            }
-
-            // base is relative; remove everything after trailing '/'
-            if (base == null || base.lastIndexOf("/") == -1) {
-                base = "";
-            } else {
-                base = base.substring(0, base.lastIndexOf("/") + 1);
-            }
-
-            // concatenate to produce the real URL we're interested in
-            String target = base + href;
-
-            // for relative URLs, load and wrap the resource.
-            // don't bother checking for 'null' since we specifically want
-            // the parser to fail if the resource doesn't exist
-            InputStream s;
-            if (target.startsWith("/")) {
-                s = ctx.getServletContext().getResourceAsStream(target);
-                if (s == null) {
-                    throw new TransformerException(
-                            Resources.getMessage("UNABLE_TO_RESOLVE_ENTITY",
-                                    href));
-                }
-            } else {
-                String pagePath =
-                        ((HttpServletRequest) 
ctx.getRequest()).getServletPath();
-                String basePath =
-                        pagePath.substring(0, pagePath.lastIndexOf("/"));
-                s = ctx.getServletContext().getResourceAsStream(
-                        basePath + "/" + target);
-                if (s == null) {
-                    throw new TransformerException(
-                            Resources.getMessage("UNABLE_TO_RESOLVE_ENTITY",
-                                    href));
-                }
-            }
-            return new StreamSource(s);
-        }
-    }
-
 }

Modified: 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/XalanUtil.java
URL: 
http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/XalanUtil.java?rev=1642442&r1=1642441&r2=1642442&view=diff
==============================================================================
--- 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/XalanUtil.java
 (original)
+++ 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/XalanUtil.java
 Sat Nov 29 16:06:54 2014
@@ -19,9 +19,6 @@ package org.apache.taglibs.standard.tag.
 import javax.servlet.jsp.PageContext;
 import javax.servlet.jsp.tagext.Tag;
 import javax.servlet.jsp.tagext.TagSupport;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.transform.TransformerException;
 
 import org.apache.xpath.VariableStack;
@@ -31,21 +28,11 @@ import org.apache.xpath.objects.XNodeSet
 import org.apache.xpath.objects.XNumber;
 import org.apache.xpath.objects.XObject;
 import org.apache.xpath.objects.XString;
-import org.w3c.dom.Document;
 import org.w3c.dom.NodeList;
 
 /**
  */
 public class XalanUtil {
-    private static final DocumentBuilderFactory dbf;
-
-    static {
-        // from Java5 on DocumentBuilderFactory is thread safe and hence can 
be cached
-        dbf = DocumentBuilderFactory.newInstance();
-        dbf.setNamespaceAware(true);
-        dbf.setValidating(false);
-    }
-
     /**
      * Return the XPathContext to be used for evaluating expressions.
      *
@@ -67,29 +54,12 @@ public class XalanUtil {
         XPathContext context = new XPathContext(false);
         VariableStack variableStack = new JSTLVariableStack(pageContext);
         context.setVarStack(variableStack);
-        int dtm = context.getDTMHandleFromNode(newEmptyDocument());
+        int dtm = context.getDTMHandleFromNode(XmlUtil.newEmptyDocument());
         context.pushCurrentNodeAndExpression(dtm, dtm);
         return context;
     }
 
     /**
-     * Create a new empty document.
-     *
-     * This method always allocates a new document as its root node might be
-     * exposed to other tags and potentially be mutated.
-     *
-     * @return a new empty document
-     */
-    private static Document newEmptyDocument() {
-        try {
-            DocumentBuilder db = dbf.newDocumentBuilder();
-            return db.newDocument();
-        } catch (ParserConfigurationException e) {
-            throw new AssertionError();
-        }
-    }
-
-    /**
      * Return the Java value corresponding to an XPath result.
      *
      * @param xo the XPath type

Added: 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/XmlUtil.java
URL: 
http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/XmlUtil.java?rev=1642442&view=auto
==============================================================================
--- 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/XmlUtil.java
 (added)
+++ 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/XmlUtil.java
 Sat Nov 29 16:06:54 2014
@@ -0,0 +1,279 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.taglibs.standard.tag.common.xml;
+
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.Reader;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.jsp.PageContext;
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.sax.TransformerHandler;
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.taglibs.standard.resources.Resources;
+import org.apache.taglibs.standard.util.UrlUtil;
+import org.w3c.dom.Document;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+/**
+ * Utilities for working with JAXP and SAX.
+ */
+public class XmlUtil {
+    private static final DocumentBuilderFactory dbf;
+    private static final SAXTransformerFactory stf;
+
+    static {
+        // from Java5 on DocumentBuilderFactory is thread safe and hence can 
be cached
+        dbf = DocumentBuilderFactory.newInstance();
+        dbf.setNamespaceAware(true);
+        dbf.setValidating(false);
+        try {
+            dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+        } catch (ParserConfigurationException e) {
+            throw new AssertionError("Parser does not support secure 
processing");
+        }
+
+        TransformerFactory tf = TransformerFactory.newInstance();
+        if (!(tf instanceof SAXTransformerFactory)) {
+            throw new AssertionError("TransformerFactory does not support 
SAX");
+        }
+        try {
+            tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+        } catch (TransformerConfigurationException e) {
+            throw new AssertionError("TransformerFactory does not support 
secure processing");
+        }
+        stf = (SAXTransformerFactory) tf;
+    }
+
+
+    /**
+     * Create a new empty document.
+     *
+     * This method always allocates a new document as its root node might be
+     * exposed to other tags and potentially be mutated.
+     *
+     * @return a new empty document
+     */
+    static Document newEmptyDocument() {
+        return newDocumentBuilder().newDocument();
+    }
+
+    /**
+     * Create a new DocumentBuilder configured for namespaces but not 
validating.
+     *
+     * @return a new, configured DocumentBuilder
+     */
+    static DocumentBuilder newDocumentBuilder() {
+        try {
+            return dbf.newDocumentBuilder();
+        } catch (ParserConfigurationException e) {
+            throw new AssertionError();
+        }
+    }
+
+    /**
+     * Create a new TransformerHandler.
+     * @return a new TransformerHandler
+     */
+    static TransformerHandler newTransformerHandler() throws 
TransformerConfigurationException {
+        return stf.newTransformerHandler();
+    }
+
+    static Transformer newTransformer(Source source) throws 
TransformerConfigurationException {
+        Transformer transformer = stf.newTransformer(source);
+        if (transformer == null) {
+            throw new TransformerConfigurationException("newTransformer 
returned null");
+        }
+        return transformer;
+    }
+
+    /**
+     * Create an InputSource from a Reader.
+     *
+     * The systemId will be wrapped for use with JSTL's EntityResolver and 
UriResolver.
+     *
+     * @param reader the source of the XML
+     * @param systemId the system id
+     * @return a configured InputSource
+     */
+    static InputSource newInputSource(Reader reader, String systemId) {
+        InputSource source = new InputSource(reader);
+        source.setSystemId(wrapSystemId(systemId));
+        return source;
+    }
+
+    /**
+     * Create an XMLReader that resolves entities using JSTL semantics.
+     * @param entityResolver for resolving using JSTL semamtics
+     * @return a new XMLReader
+     * @throws SAXException if there was a problem creating the reader
+     */
+    static XMLReader newXMLReader(JstlEntityResolver entityResolver) throws 
SAXException {
+        XMLReader xmlReader = XMLReaderFactory.createXMLReader();
+        xmlReader.setEntityResolver(entityResolver);
+        return xmlReader;
+    }
+
+    /**
+     * Create a SAXSource from a Reader. Any entities will be resolved using 
JSTL semantics.
+     *
+     * @param reader the source of the XML
+     * @param systemId the system id
+     * @param entityResolver for resolving using JSTL semamtics
+     * @return a new SAXSource
+     * @throws SAXException if there was a problem creating the source
+     */
+    static SAXSource newSAXSource(Reader reader, String systemId, 
JstlEntityResolver entityResolver)  throws SAXException {
+        SAXSource source = new SAXSource(newXMLReader(entityResolver), new 
InputSource(reader));
+        source.setSystemId(wrapSystemId(systemId));
+        return source;
+    }
+
+    /**
+     * Wraps systemId with a "jstl:" prefix to prevent the parser from
+     * thinking that the URI is truly relative and resolving it against
+     * the current directory in the filesystem.
+     */
+    private static String wrapSystemId(String systemId) {
+        if (systemId == null) {
+            return "jstl:";
+        } else if (UrlUtil.isAbsoluteUrl(systemId)) {
+            return systemId;
+        } else {
+            return ("jstl:" + systemId);
+        }
+    }
+
+    /**
+     * JSTL-specific implementation of EntityResolver.
+     */
+    static class JstlEntityResolver implements EntityResolver {
+        private final PageContext ctx;
+
+        public JstlEntityResolver(PageContext ctx) {
+            this.ctx = ctx;
+        }
+
+        public InputSource resolveEntity(String publicId, String systemId) 
throws FileNotFoundException {
+
+            // pass if we don't have a systemId
+            if (systemId == null) {
+                return null;
+            }
+
+            // strip leading "jstl:" off URL if applicable
+            if (systemId.startsWith("jstl:")) {
+                systemId = systemId.substring(5);
+            }
+
+            // we're only concerned with relative URLs
+            if (UrlUtil.isAbsoluteUrl(systemId)) {
+                return null;
+            }
+
+            // for relative URLs, load and wrap the resource.
+            // don't bother checking for 'null' since we specifically want
+            // the parser to fail if the resource doesn't exist
+            String path = systemId;
+            if (!path.startsWith("/")) {
+                String pagePath = ((HttpServletRequest) 
ctx.getRequest()).getServletPath();
+                String basePath = pagePath.substring(0, 
pagePath.lastIndexOf("/"));
+                path =  basePath + "/" + systemId;
+            }
+
+            InputStream s = ctx.getServletContext().getResourceAsStream(path);
+            if (s == null) {
+                throw new 
FileNotFoundException(Resources.getMessage("UNABLE_TO_RESOLVE_ENTITY", 
systemId));
+            }
+            return new InputSource(s);
+        }
+    }
+
+    /**
+     * JSTL-specific implementation of URIResolver.
+     */
+    static class JstlUriResolver implements URIResolver {
+        private final PageContext ctx;
+
+        public JstlUriResolver(PageContext ctx) {
+            this.ctx = ctx;
+        }
+
+        public Source resolve(String href, String base) throws 
TransformerException {
+
+            // pass if we don't have a systemId
+            if (href == null) {
+                return null;
+            }
+
+            // remove "jstl" marker from 'base'
+            // NOTE: how 'base' is determined varies among different Xalan
+            // xsltc implementations
+            int index;
+            if (base != null && (index = base.indexOf("jstl:")) != -1) {
+                base = base.substring(index + 5);
+            }
+
+            // we're only concerned with relative URLs
+            if (UrlUtil.isAbsoluteUrl(href)
+                    || (base != null && UrlUtil.isAbsoluteUrl(base))) {
+                return null;
+            }
+
+            // base is relative; remove everything after trailing '/'
+            if (base == null || base.lastIndexOf("/") == -1) {
+                base = "";
+            } else {
+                base = base.substring(0, base.lastIndexOf("/") + 1);
+            }
+
+            // concatenate to produce the real URL we're interested in
+            String target = base + href;
+
+            // for relative URLs, load and wrap the resource.
+            // don't bother checking for 'null' since we specifically want
+            // the parser to fail if the resource doesn't exist
+            if (!target.startsWith("/")) {
+                String pagePath = ((HttpServletRequest) 
ctx.getRequest()).getServletPath();
+                String basePath = pagePath.substring(0, 
pagePath.lastIndexOf("/"));
+                target = basePath + "/" + target;
+            }
+            InputStream s = 
ctx.getServletContext().getResourceAsStream(target);
+            if (s == null) {
+                throw new 
TransformerException(Resources.getMessage("UNABLE_TO_RESOLVE_ENTITY", href));
+            }
+            return new StreamSource(s);
+        }
+    }
+}

Propchange: 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/XmlUtil.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/util/UnclosableWriter.java
URL: 
http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/util/UnclosableWriter.java?rev=1642442&view=auto
==============================================================================
--- 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/util/UnclosableWriter.java
 (added)
+++ 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/util/UnclosableWriter.java
 Sat Nov 29 16:06:54 2014
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.taglibs.standard.util;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * A Writer based on a wrapped Writer but ignoring requests to
+ * close() and flush() it.  (Someone must have wrapped the
+ * toilet in my office similarly...)
+ */
+public class UnclosableWriter extends Writer {
+    // TODO: shouldn't we be delegating all methods?
+    private Writer w;
+
+    public UnclosableWriter(Writer w) {
+        this.w = w;
+    }
+
+    @Override
+    public void close() {
+    }
+
+    @Override
+    public void flush() {
+    }
+
+    @Override
+    public void write(char[] cbuf, int off, int len) throws IOException {
+        w.write(cbuf, off, len);
+    }
+}

Propchange: 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/util/UnclosableWriter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/util/UrlUtil.java
URL: 
http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/util/UrlUtil.java?rev=1642442&view=auto
==============================================================================
--- 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/util/UrlUtil.java
 (added)
+++ 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/util/UrlUtil.java
 Sat Nov 29 16:06:54 2014
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.taglibs.standard.util;
+
+import java.util.BitSet;
+
+/**
+ * Utilities for working with URLs.
+ */
+public class UrlUtil {
+    /**
+     * <p>Valid characters in a scheme.</p>
+     * <p>RFC 1738 says the following:</p>
+     * <blockquote>
+     * Scheme names consist of a sequence of characters. The lower
+     * case letters "a"--"z", digits, and the characters plus ("+"),
+     * period ("."), and hyphen ("-") are allowed. For resiliency,
+     * programs interpreting URLs should treat upper case letters as
+     * equivalent to lower case in scheme names (e.g., allow "HTTP" as
+     * well as "http").
+     * </blockquote>
+     * <p>We treat as absolute any URL that begins with such a scheme name,
+     * followed by a colon.</p>
+     */
+/*
+    private static final String VALID_SCHEME_CHARS =
+            
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+.-";
+*/
+    private static final BitSet VALID_SCHEME_CHARS;
+    static {
+        VALID_SCHEME_CHARS = new BitSet(128);
+        VALID_SCHEME_CHARS.set('A', 'Z' + 1);
+        VALID_SCHEME_CHARS.set('a', 'z' + 1);
+        VALID_SCHEME_CHARS.set('0', '9' + 1);
+        VALID_SCHEME_CHARS.set('+');
+        VALID_SCHEME_CHARS.set('.');
+        VALID_SCHEME_CHARS.set('-');
+    }
+
+    /**
+     * Determine if a URL is absolute by JSTL's definition.
+     */
+    public static boolean isAbsoluteUrl(String url) {
+        // a null URL is not absolute, by our definition
+        if (url == null) {
+            return false;
+        }
+
+        // do a fast, simple check first
+        int colonPos = url.indexOf(":");
+        if (colonPos == -1) {
+            return false;
+        }
+
+        // if we DO have a colon, make sure that every character
+        // leading up to it is a valid scheme character
+        for (int i = 0; i < colonPos; i++) {
+            if (!VALID_SCHEME_CHARS.get(url.charAt(i))) {
+                return false;
+            }
+        }
+
+        // if so, we've got an absolute url
+        return true;
+    }
+}

Propchange: 
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/util/UrlUtil.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/ExprSupportTest.java
URL: 
http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/ExprSupportTest.java?rev=1642442&r1=1642441&r2=1642442&view=diff
==============================================================================
--- 
tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/ExprSupportTest.java
 (original)
+++ 
tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/ExprSupportTest.java
 Sat Nov 29 16:06:54 2014
@@ -21,7 +21,6 @@ import java.io.InputStream;
 import javax.servlet.jsp.JspWriter;
 import javax.servlet.jsp.PageContext;
 import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
 
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -45,10 +44,7 @@ public class ExprSupportTest {
 
     @BeforeClass
     public static void loadXml() throws Exception {
-        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
-        dbf.setNamespaceAware(true);
-        dbf.setValidating(false);
-        DocumentBuilder db = dbf.newDocumentBuilder();
+        DocumentBuilder db = XmlUtil.newDocumentBuilder();
         InputStream is = ExprSupportTest.class.getResourceAsStream("test.xml");
         try {
             test = db.parse(is);

Modified: 
tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/ForEachTagTest.java
URL: 
http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/ForEachTagTest.java?rev=1642442&r1=1642441&r2=1642442&view=diff
==============================================================================
--- 
tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/ForEachTagTest.java
 (original)
+++ 
tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/ForEachTagTest.java
 Sat Nov 29 16:06:54 2014
@@ -20,41 +20,33 @@ import java.io.InputStream;
 
 import javax.servlet.jsp.PageContext;
 import javax.servlet.jsp.tagext.IterationTag;
-import javax.servlet.jsp.tagext.Tag;
 import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.xpath.XPathConstants;
 
-import org.apache.xpath.XPath;
-import org.apache.xpath.XPathContext;
-import org.apache.xpath.objects.XObject;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Ignore;
 import org.junit.Test;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import sun.security.krb5.internal.TGSRep;
 
+import org.apache.xpath.XPath;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.objects.XObject;
 import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.verify;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
 
 /**
  */
 public class ForEachTagTest {
     private static Document test;
-    private static DocumentBuilderFactory dbf;
 
     @BeforeClass
     public static void loadXml() throws Exception {
-        dbf = DocumentBuilderFactory.newInstance();
-        dbf.setNamespaceAware(true);
-        dbf.setValidating(false);
-        DocumentBuilder db = dbf.newDocumentBuilder();
+        DocumentBuilder db = XmlUtil.newDocumentBuilder();
         InputStream is = ExprSupportTest.class.getResourceAsStream("test.xml");
         try {
             test = db.parse(is);
@@ -126,8 +118,7 @@ public class ForEachTagTest {
     public void testIterationPerformance() throws Exception {
         // create a large document
         final int SIZE = 200000;
-        DocumentBuilder db = dbf.newDocumentBuilder();
-        test = db.newDocument();
+        test = XmlUtil.newEmptyDocument();
         Element root = test.createElement("root");
         test.appendChild(root);
         for (int i = 0; i < SIZE; i++) {

Modified: 
tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/JSTLVariableStackTest.java
URL: 
http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/JSTLVariableStackTest.java?rev=1642442&r1=1642441&r2=1642442&view=diff
==============================================================================
--- 
tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/JSTLVariableStackTest.java
 (original)
+++ 
tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/JSTLVariableStackTest.java
 Sat Nov 29 16:06:54 2014
@@ -20,11 +20,13 @@ import javax.servlet.ServletContext;
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.jsp.PageContext;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.transform.TransformerException;
 
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
 import org.apache.xml.utils.QName;
 import org.apache.xpath.XPathContext;
 import org.apache.xpath.objects.XBoolean;
@@ -32,16 +34,12 @@ import org.apache.xpath.objects.XNodeSet
 import org.apache.xpath.objects.XNumber;
 import org.apache.xpath.objects.XObjectFactory;
 import org.apache.xpath.objects.XString;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
 import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.verify;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
 
 /**
  */
@@ -156,11 +154,7 @@ public class JSTLVariableStackTest {
         Assert.assertTrue(XObjectFactory.create(1234, xpathContext) instanceof 
XNumber);
         Assert.assertTrue(XObjectFactory.create("Hello", xpathContext) 
instanceof XString);
 
-        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
-        dbf.setNamespaceAware(true);
-        dbf.setValidating(false);
-        DocumentBuilder db = dbf.newDocumentBuilder();
-        Document d = db.newDocument();
+        Document d = XmlUtil.newEmptyDocument();
         Element root = d.createElement("root");
         XNodeSetForDOM xo = (XNodeSetForDOM) XObjectFactory.create(root, 
xpathContext);
         Assert.assertEquals(root, xo.object());



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to