You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by jb...@apache.org on 2013/08/10 23:53:43 UTC

svn commit: r1512826 - in /tomcat/trunk: java/org/apache/catalina/ java/org/apache/catalina/core/ java/org/apache/catalina/startup/ java/org/apache/catalina/storeconfig/ java/org/apache/jasper/resources/ java/org/apache/jasper/servlet/ test/org/apache/...

Author: jboynes
Date: Sat Aug 10 21:53:43 2013
New Revision: 1512826

URL: http://svn.apache.org/r1512826
Log:
Refactor Catalina's TLD processing into Jasper's ServletContainerInitializer.
Replaces the TldConfig lifecycle listener with code the SCI to scan for TLDs and register listeners dynamically.
Removes the "processTld" property from StandardContext and deprecates other TLD related properties on Context
Does not yet address refactoring Jasper's own TLD processing into the SCI.

Added:
    tomcat/trunk/java/org/apache/jasper/servlet/TldScanner.java   (with props)
    tomcat/trunk/test/org/apache/jasper/servlet/TestTldScanner.java   (with props)
Removed:
    tomcat/trunk/java/org/apache/catalina/startup/TldConfig.java
    tomcat/trunk/java/org/apache/catalina/startup/TldRuleSet.java
Modified:
    tomcat/trunk/java/org/apache/catalina/Context.java
    tomcat/trunk/java/org/apache/catalina/core/StandardContext.java
    tomcat/trunk/java/org/apache/catalina/storeconfig/server-registry.xml
    tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties
    tomcat/trunk/java/org/apache/jasper/servlet/JasperInitializer.java
    tomcat/trunk/test/org/apache/catalina/core/TestStandardContext.java

Modified: tomcat/trunk/java/org/apache/catalina/Context.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/Context.java?rev=1512826&r1=1512825&r2=1512826&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/Context.java (original)
+++ tomcat/trunk/java/org/apache/catalina/Context.java Sat Aug 10 21:53:43 2013
@@ -621,6 +621,7 @@ public interface Context extends Contain
      * parsing tlds files.
      * @param tldValidation true to enable xml instance validation
      */
+    @Deprecated
     public void setTldValidation(boolean tldValidation);
 
 
@@ -629,6 +630,7 @@ public interface Context extends Contain
      * @return true if validation is enabled.
      *
      */
+    @Deprecated
     public boolean getTldValidation();
 
 
@@ -636,6 +638,7 @@ public interface Context extends Contain
      * Get the server.xml <host> attribute's xmlNamespaceAware.
      * @return true if namespace awareness is enabled.
      */
+    @Deprecated
     public boolean getTldNamespaceAware();
 
 
@@ -644,6 +647,7 @@ public interface Context extends Contain
      * parsing xml instances.
      * @param tldNamespaceAware true to enable namespace awareness
      */
+    @Deprecated
     public void setTldNamespaceAware(boolean tldNamespaceAware);
 
     /**

Modified: tomcat/trunk/java/org/apache/catalina/core/StandardContext.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/StandardContext.java?rev=1512826&r1=1512825&r2=1512826&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/core/StandardContext.java (original)
+++ tomcat/trunk/java/org/apache/catalina/core/StandardContext.java Sat Aug 10 21:53:43 2013
@@ -99,7 +99,6 @@ import org.apache.catalina.Wrapper;
 import org.apache.catalina.deploy.NamingResourcesImpl;
 import org.apache.catalina.loader.WebappLoader;
 import org.apache.catalina.session.StandardManager;
-import org.apache.catalina.startup.TldConfig;
 import org.apache.catalina.util.CharsetMapper;
 import org.apache.catalina.util.ContextName;
 import org.apache.catalina.util.ExtensionValidator;
@@ -707,11 +706,6 @@ public class StandardContext extends Con
     private boolean webXmlNamespaceAware = Globals.STRICT_SERVLET_COMPLIANCE;
 
     /**
-     * Attribute value used to turn on/off TLD processing
-     */
-    private boolean processTlds = true;
-
-    /**
      * Attribute value used to turn on/off XML validation
      */
     private boolean tldValidation = Globals.STRICT_SERVLET_COMPLIANCE;
@@ -6338,10 +6332,6 @@ public class StandardContext extends Con
     protected void initInternal() throws LifecycleException {
         super.initInternal();
 
-        if (processTlds) {
-            this.addLifecycleListener(new TldConfig());
-        }
-
         // Register the naming resources
         if (namingResources != null) {
             namingResources.init();
@@ -6518,22 +6508,6 @@ public class StandardContext extends Con
     }
 
     /**
-     * Sets the process TLDs attribute.
-     *
-     * @param newProcessTlds The new value
-     */
-    public void setProcessTlds(boolean newProcessTlds) {
-        processTlds = newProcessTlds;
-    }
-
-    /**
-     * Returns the processTlds attribute value.
-     */
-    public boolean getProcessTlds() {
-        return processTlds;
-    }
-
-    /**
      * Get the server.xml <host> attribute's xmlNamespaceAware.
      * @return true if namespace awarenes is enabled.
      */

Modified: tomcat/trunk/java/org/apache/catalina/storeconfig/server-registry.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/storeconfig/server-registry.xml?rev=1512826&r1=1512825&r2=1512826&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/storeconfig/server-registry.xml (original)
+++ tomcat/trunk/java/org/apache/catalina/storeconfig/server-registry.xml Sat Aug 10 21:53:43 2013
@@ -189,7 +189,6 @@
        <TransientChild>org.apache.catalina.startup.ContextConfig</TransientChild>
        <TransientChild>org.apache.catalina.startup.EngineConfig</TransientChild>
        <TransientChild>org.apache.catalina.startup.HostConfig</TransientChild>
-       <TransientChild>org.apache.catalina.startup.TldConfig</TransientChild>
        <TransientChild>org.apache.catalina.core.StandardHost$MemoryLeakTrackingListener</TransientChild>
        <TransientChild>org.apache.catalina.mapper.MapperListener</TransientChild>
        <TransientChild>org.apache.catalina.core.ThreadLocalLeakPreventionListener</TransientChild>

Modified: tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties?rev=1512826&r1=1512825&r2=1512826&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties (original)
+++ tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties Sat Aug 10 21:53:43 2013
@@ -398,3 +398,5 @@ jsp.tldCache.noTldSummary=At least one J
 jsp.error.el_interpreter_class.instantiation=Failed to load or instantiate ELInterpreter class [{0}]
 
 org.apache.jasper.servlet.JasperInitializer.onStartup=Initializing Jasper for context [{0}]
+org.apache.jasper.servlet.TldScanner.webxmlSkip=Skipping load of TLD for URI {1} from resource path {0} as it has already been defined in <jsp-config>
+org.apache.jasper.servlet.TldScanner.webxmlAdd=Loading TLD for URI {1} from resource path {0}

Modified: tomcat/trunk/java/org/apache/jasper/servlet/JasperInitializer.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/servlet/JasperInitializer.java?rev=1512826&r1=1512825&r2=1512826&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/jasper/servlet/JasperInitializer.java (original)
+++ tomcat/trunk/java/org/apache/jasper/servlet/JasperInitializer.java Sat Aug 10 21:53:43 2013
@@ -16,6 +16,7 @@
  */
 package org.apache.jasper.servlet;
 
+import java.io.IOException;
 import java.util.Set;
 
 import javax.servlet.ServletContainerInitializer;
@@ -25,11 +26,17 @@ import javax.servlet.ServletException;
 import org.apache.jasper.compiler.Localizer;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
+import org.xml.sax.SAXException;
 
 /**
  * Initializer for the Jasper JSP Engine.
  */
 public class JasperInitializer implements ServletContainerInitializer {
+    /**
+     * Name of ServletContext initParam that determines if descriptor XML
+     * should be validated.
+     */
+    public static final String VALIDATE = "org.apache.jasper.validateDescriptors";
     private static final String MSG = "org.apache.jasper.servlet.JasperInitializer";
     private static final Log LOG = LogFactory.getLog(JasperInitializer.class);
 
@@ -38,5 +45,20 @@ public class JasperInitializer implement
         if (LOG.isDebugEnabled()) {
             LOG.debug(Localizer.getMessage(MSG + ".onStartup", context.getServletContextName()));
         }
+
+        boolean validate = Boolean.valueOf(context.getInitParameter(VALIDATE));
+
+        // scan the application for TLDs
+        TldScanner scanner = new TldScanner(context, true, validate);
+        try {
+            scanner.scan();
+        } catch (IOException | SAXException e) {
+            throw new ServletException(e);
+        }
+
+        // add any listeners defined in TLDs
+        for (String listener : scanner.getListeners()) {
+            context.addListener(listener);
+        }
     }
 }

Added: tomcat/trunk/java/org/apache/jasper/servlet/TldScanner.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/servlet/TldScanner.java?rev=1512826&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/jasper/servlet/TldScanner.java (added)
+++ tomcat/trunk/java/org/apache/jasper/servlet/TldScanner.java Sat Aug 10 21:53:43 2013
@@ -0,0 +1,305 @@
+/*
+ * 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.jasper.servlet;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.JarURLConnection;
+import java.net.URL;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.ServletContext;
+import javax.servlet.descriptor.JspConfigDescriptor;
+import javax.servlet.descriptor.TaglibDescriptor;
+
+import org.apache.jasper.compiler.JarScannerFactory;
+import org.apache.jasper.compiler.Localizer;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.JarScanType;
+import org.apache.tomcat.JarScanner;
+import org.apache.tomcat.JarScannerCallback;
+import org.apache.tomcat.util.descriptor.tld.TaglibXml;
+import org.apache.tomcat.util.descriptor.tld.TldParser;
+import org.apache.tomcat.util.scan.Jar;
+import org.apache.tomcat.util.scan.JarFactory;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * Scans for and loads Tag Library Descriptors contained in a web application.
+ */
+public class TldScanner {
+    private static final Log log = LogFactory.getLog(TldScanner.class);
+    private static final String MSG = "org.apache.jasper.servlet.TldScanner";
+    private static final String TLD_EXT = ".tld";
+    private static final String WEB_INF = "/WEB-INF/";
+    private final ServletContext context;
+    private final TldParser tldParser;
+    private final Map<String, TaglibXml> taglibMap = new HashMap<>();
+    private final List<String> listeners = new ArrayList<>();
+
+    /**
+     * Initialize with the application's ServletContext.
+     *
+     * @param context the application's servletContext
+     */
+    public TldScanner(ServletContext context,
+                      boolean namespaceAware,
+                      boolean validation) {
+        this.context = context;
+        this.tldParser = new TldParser(namespaceAware, validation);
+    }
+
+    /**
+     * Scan for TLDs in all places defined by the specification:
+     * <ol>
+     * <li>Tag libraries defined by the platform</li>
+     * <li>Entries from &lt;jsp-config&gt; in web.xml</li>
+     * <li>A resources under /WEB-INF</li>
+     * <li>In jar files from /WEB-INF/lib</li>
+     * <li>Additional entries from the container</li>
+     * </ol>
+     *
+     * @return the taglib map build by this scan
+     * @throws IOException  if there was a problem scanning for or loading a TLD
+     * @throws SAXException if there was a problem parsing a TLD
+     */
+    public Map<String, TaglibXml> scan() throws IOException, SAXException {
+        scanPlatform();
+        scanJspConfig();
+        scanResourcePaths(WEB_INF);
+        scanJars();
+        return taglibMap;
+    }
+
+    /**
+     * Returns the taglib map built by this scanner.
+     *
+     * @return the taglib map
+     */
+    public Map<String, TaglibXml> getTaglibMap() {
+        return taglibMap;
+    }
+
+    /**
+     * Returns a list of all listeners declared by scanned TLDs.
+     *
+     * @return a list of listener class names
+     */
+    public List<String> getListeners() {
+        return listeners;
+    }
+
+    /**
+     * Scan for TLDs required by the platform specification.
+     */
+    protected void scanPlatform() {
+    }
+
+    /**
+     * Scan for TLDs defined in &lt;jsp-config&gt;.
+     */
+    protected void scanJspConfig() throws IOException, SAXException {
+        JspConfigDescriptor jspConfigDescriptor = context.getJspConfigDescriptor();
+        if (jspConfigDescriptor == null) {
+            return;
+        }
+
+        Collection<TaglibDescriptor> descriptors = jspConfigDescriptor.getTaglibs();
+        for (TaglibDescriptor descriptor : descriptors) {
+            String taglibURI = descriptor.getTaglibURI();
+            String resourcePath = descriptor.getTaglibLocation();
+            // Note: Whilst the Servlet 2.4 DTD implies that the location must
+            // be a context-relative path starting with '/', JSP.7.3.6.1 states
+            // explicitly how paths that do not start with '/' should be
+            // handled.
+            if (!resourcePath.startsWith("/")) {
+                resourcePath = WEB_INF + resourcePath;
+            }
+            if (taglibMap.containsKey(taglibURI)) {
+                log.warn(Localizer.getMessage(MSG + ".webxmlSkip",
+                        resourcePath,
+                        taglibURI));
+                continue;
+            }
+
+            if (log.isTraceEnabled()) {
+                log.trace(Localizer.getMessage(MSG + ".webxmlAdd",
+                        resourcePath,
+                        taglibURI));
+            }
+
+            URL url = context.getResource(resourcePath);
+            if (resourcePath.endsWith(".jar")) {
+                // if the path points to a jar file, the TLD is presumed to be
+                // inside at META-INF/taglib.tld
+                url = new URL ("jar:" +
+                        url.toExternalForm() +
+                        "!/META-INF/taglib.tld");
+            }
+
+            TaglibXml tld = tldParser.parse(url);
+            taglibMap.put(taglibURI, tld);
+        }
+    }
+
+    /**
+     * Scan web application resources for TLDs, recursively.
+     *
+     * @param startPath the directory resource to scan
+     * @throws IOException  if there was a problem scanning for or loading a TLD
+     * @throws SAXException if there was a problem parsing a TLD
+     */
+    protected void scanResourcePaths(String startPath)
+            throws IOException, SAXException {
+
+        Set<String> dirList = context.getResourcePaths(startPath);
+        if (dirList != null) {
+            for (String path : dirList) {
+                if (path.endsWith("/")) {
+                    scanResourcePaths(path);
+                } else if (path.startsWith("/WEB-INF/tags/")) {
+                    // JSP 7.3.1: in /WEB-INF/tags only consider implicit.tld
+                    if (path.endsWith("/implicit.tld")) {
+                        parseTld(path);
+                    }
+                } else if (path.endsWith(TLD_EXT)) {
+                    parseTld(path);
+                }
+            }
+        }
+    }
+
+    /**
+     * Scan for TLDs in JARs in /WEB-INF/lib.
+     */
+    public void scanJars() {
+        JarScanner scanner = JarScannerFactory.getJarScanner(context);
+        TldScannerCallback callback = new TldScannerCallback();
+        scanner.scan(JarScanType.TLD, context, callback);
+        if (!callback.tldFound) {
+            log.info(Localizer.getMessage("jsp.tldCache.noTldSummary"));
+        }
+    }
+
+    private void parseTld(String resourcePath) throws IOException, SAXException {
+        parseTld(context.getResource(resourcePath));
+    }
+
+    private void parseTld(URL url) throws IOException, SAXException {
+        TaglibXml tld = tldParser.parse(url);
+        registerTld(tld);
+    }
+
+    private void registerTld(TaglibXml tld) {
+        String uri = tld.getUri();
+        if (uri != null) {
+            if (!taglibMap.containsKey(uri)) {
+                taglibMap.put(uri, tld);
+            }
+        }
+        if (tld.getListeners() != null) {
+            listeners.addAll(tld.getListeners());
+        }
+    }
+
+    private class TldScannerCallback implements JarScannerCallback {
+        private boolean tldFound = false;
+
+        @Override
+        public void scan(JarURLConnection urlConn, boolean isWebapp) throws IOException {
+            boolean found = false;
+            Jar jar = JarFactory.newInstance(urlConn.getURL());
+            StringBuilder base = new StringBuilder(256);
+            base.append("jar:").append(urlConn.getURL()).append("!/");
+            int baseLength = base.length();
+            try {
+                jar.nextEntry();
+                for (String entryName = jar.getEntryName();
+                     entryName != null;
+                     jar.nextEntry(), entryName = jar.getEntryName()) {
+                    if (!(entryName.startsWith("META-INF/") &&
+                            entryName.endsWith(TLD_EXT))) {
+                        continue;
+                    }
+                    found = true;
+                    String location = base.append(entryName).toString();
+                    base.setLength(baseLength);
+                    try (InputStream is = jar.getEntryInputStream()) {
+                        InputSource source = new InputSource(is);
+                        source.setSystemId(location);
+                        TaglibXml tld = tldParser.parse(source);
+                        registerTld(tld);
+                    } catch (SAXException e) {
+                        throw new IOException(e);
+                    }
+                }
+            } finally {
+                jar.close();
+            }
+            if (found) {
+                tldFound = true;
+            } else {
+                if (log.isDebugEnabled()) {
+                    log.debug(Localizer.getMessage("jsp.tldCache.noTldInJar",
+                            urlConn.getJarFileURL().toString()));
+                }
+            }
+        }
+
+        @Override
+        public void scan(File file, boolean isWebapp) throws IOException {
+            File metaInf = new File(file, "META-INF");
+            if (!metaInf.isDirectory()) {
+                return;
+            }
+            Files.walkFileTree(metaInf.toPath(), new SimpleFileVisitor<Path>() {
+                @Override
+                public FileVisitResult visitFile(Path file,
+                                                 BasicFileAttributes attrs)
+                        throws IOException {
+                    if (file.endsWith(TLD_EXT)) {
+                        try {
+                            parseTld(file.toUri().toURL());
+                            tldFound = true;
+                        } catch (SAXException e) {
+                            throw new IOException(e);
+                        }
+                    }
+                    return FileVisitResult.CONTINUE;
+                }
+            });
+        }
+
+        @Override
+        public void scanWebInfClasses() throws IOException {
+            // this is now handled when WEB-INF is scanned for resources
+        }
+    }
+}

Propchange: tomcat/trunk/java/org/apache/jasper/servlet/TldScanner.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomcat/trunk/test/org/apache/catalina/core/TestStandardContext.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/core/TestStandardContext.java?rev=1512826&r1=1512825&r2=1512826&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/catalina/core/TestStandardContext.java (original)
+++ tomcat/trunk/test/org/apache/catalina/core/TestStandardContext.java Sat Aug 10 21:53:43 2013
@@ -64,6 +64,7 @@ import org.apache.catalina.startup.Teste
 import org.apache.catalina.startup.TesterServlet;
 import org.apache.catalina.startup.Tomcat;
 import org.apache.catalina.startup.TomcatBaseTest;
+import org.apache.jasper.servlet.JasperInitializer;
 import org.apache.tomcat.util.buf.ByteChunk;
 import org.apache.tomcat.util.descriptor.web.FilterDef;
 import org.apache.tomcat.util.descriptor.web.FilterMap;
@@ -865,6 +866,7 @@ public class TestStandardContext extends
 
         File docBase = new File("test/webapp-3.0");
         Context ctx = tomcat.addContext("", docBase.getAbsolutePath());
+        ctx.addServletContainerInitializer(new JasperInitializer(), null);
 
         // Start the context
         tomcat.start();

Added: tomcat/trunk/test/org/apache/jasper/servlet/TestTldScanner.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/jasper/servlet/TestTldScanner.java?rev=1512826&view=auto
==============================================================================
--- tomcat/trunk/test/org/apache/jasper/servlet/TestTldScanner.java (added)
+++ tomcat/trunk/test/org/apache/jasper/servlet/TestTldScanner.java Sat Aug 10 21:53:43 2013
@@ -0,0 +1,42 @@
+/*
+ * 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.jasper.servlet;
+
+import java.io.File;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.startup.Tomcat;
+import org.apache.catalina.startup.TomcatBaseTest;
+
+public class TestTldScanner extends TomcatBaseTest {
+
+    @Test
+    public void testWithWebapp() throws Exception {
+        Tomcat tomcat = getTomcatInstance();
+        File appDir = new File("test/webapp-3.0");
+        Context context = tomcat.addWebapp(null, "/test", appDir.getAbsolutePath());
+        tomcat.start();
+
+        TldScanner scanner = new TldScanner(context.getServletContext(), true, true);
+        scanner.scan();
+        Assert.assertEquals(5, scanner.getTaglibMap().size());
+        Assert.assertEquals(1, scanner.getListeners().size());
+    }
+}

Propchange: tomcat/trunk/test/org/apache/jasper/servlet/TestTldScanner.java
------------------------------------------------------------------------------
    svn:eol-style = native



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