FileDocCategorySizeDatePackage
TldConfig.javaAPI DocApache Tomcat 6.0.1425795Fri Jul 20 04:20:34 BST 2007org.apache.catalina.startup

TldConfig

public final class TldConfig extends Object
Startup event listener for a Context that configures the properties of that Context, and the associated defined servlets.
author
Craig R. McClanahan
author
Jean-Francois Arcand
author
Costin Manolache

Fields Summary
private static HashSet
noTldJars
private static org.apache.juli.logging.Log
log
private org.apache.catalina.Context
context
The Context we are associated with.
private static final org.apache.catalina.util.StringManager
sm
The string resources for this package.
private static org.apache.tomcat.util.digester.Digester
tldDigester
The Digester we will use to process tag library descriptor files.
private static boolean
tldValidation
Attribute value used to turn on/off TLD validation
private static boolean
tldNamespaceAware
Attribute value used to turn on/off TLD namespace awarenes.
private boolean
rescan
private ArrayList
listeners
Constructors Summary
Methods Summary
public voidaddApplicationListener(java.lang.String s)

        //if(log.isDebugEnabled())
            log.debug( "Add tld listener " + s);
        listeners.add(s);
    
private static org.apache.tomcat.util.digester.DigestercreateTldDigester()
Create (if necessary) and return a Digester configured to process a tag library descriptor, looking for additional listener classes to be registered.


        return DigesterFactory.newDigester(tldValidation, 
                                           tldNamespaceAware, 
                                           new TldRuleSet());

    
public voidexecute()
Scan for and configure all tag library descriptors found in this web application.

exception
Exception if a fatal input/output or parsing error occurs

        long t1=System.currentTimeMillis();

        File tldCache=null;

        if (context instanceof StandardContext) {
            File workDir= (File)
                ((StandardContext)context).getServletContext().getAttribute(Globals.WORK_DIR_ATTR);
            //tldCache=new File( workDir, "tldCache.ser");
        }

        // Option to not rescan
        if( ! rescan ) {
            // find the cache
            if( tldCache!= null && tldCache.exists()) {
                // just read it...
                processCache(tldCache);
                return;
            }
        }

        /*
         * Acquire the list of TLD resource paths, possibly embedded in JAR
         * files, to be processed
         */
        Set resourcePaths = tldScanResourcePaths();
        Map jarPaths = getJarPaths();

        // Check to see if we can use cached listeners
        if (tldCache != null && tldCache.exists()) {
            long lastModified = getLastModified(resourcePaths, jarPaths);
            if (lastModified < tldCache.lastModified()) {
                processCache(tldCache);
                return;
            }
        }

        // Scan each accumulated resource path for TLDs to be processed
        Iterator paths = resourcePaths.iterator();
        while (paths.hasNext()) {
            String path = (String) paths.next();
            if (path.endsWith(".jar")) {
                tldScanJar(path);
            } else {
                tldScanTld(path);
            }
        }
        if (jarPaths != null) {
            paths = jarPaths.values().iterator();
            while (paths.hasNext()) {
                tldScanJar((File) paths.next());
            }
        }

        String list[] = getTldListeners();

        if( tldCache!= null ) {
            log.debug( "Saving tld cache: " + tldCache + " " + list.length);
            try {
                FileOutputStream out=new FileOutputStream(tldCache);
                ObjectOutputStream oos=new ObjectOutputStream( out );
                oos.writeObject( list );
                oos.close();
            } catch( IOException ex ) {
                ex.printStackTrace();
            }
        }

        if( log.isDebugEnabled() )
            log.debug( "Adding tld listeners:" + list.length);
        for( int i=0; list!=null && i<list.length; i++ ) {
            context.addApplicationListener(list[i]);
        }

        long t2=System.currentTimeMillis();
        if( context instanceof StandardContext ) {
            ((StandardContext)context).setTldScanTime(t2-t1);
        }

    
public org.apache.catalina.ContextgetContext()

        return context;
    
private java.util.MapgetJarPaths()
Returns a map of the paths to all JAR files that are accessible to the webapp and will be scanned for TLDs. The map always includes all the JARs under WEB-INF/lib, as well as shared JARs in the classloader delegation chain of the webapp's classloader. The latter constitutes a Tomcat-specific extension to the TLD search order defined in the JSP spec. It allows tag libraries packaged as JAR files to be shared by web applications by simply dropping them in a location that all web applications have access to (e.g., /common/lib). The set of shared JARs to be scanned for TLDs is narrowed down by the noTldJars class variable, which contains the names of JARs that are known not to contain any TLDs.

return
Map of JAR file paths


        HashMap jarPathMap = null;

        ClassLoader webappLoader = Thread.currentThread().getContextClassLoader();
        ClassLoader loader = webappLoader;
        while (loader != null) {
            if (loader instanceof URLClassLoader) {
                URL[] urls = ((URLClassLoader) loader).getURLs();
                for (int i=0; i<urls.length; i++) {
                    // Expect file URLs, these are %xx encoded or not depending on
                    // the class loader
                    // This is definitely not as clean as using JAR URLs either
                    // over file or the custom jndi handler, but a lot less
                    // buggy overall
                    File file = null;
                    try {
                        file = new File(urls[i].toURI());
                    } catch (URISyntaxException e) {
                        // Ignore, probably an unencoded char
                        file = new File(urls[i].getFile());
                    }
                    try {
                        file = file.getCanonicalFile();
                    } catch (IOException e) {
                        // Ignore
                    }
                    if (!file.exists()) {
                        continue;
                    }
                    String path = file.getAbsolutePath();
                    if (!path.endsWith(".jar")) {
                        continue;
                    }
                    /*
                     * Scan all JARs from WEB-INF/lib, plus any shared JARs
                     * that are not known not to contain any TLDs
                     */
                    if (loader == webappLoader
                            || noTldJars == null
                            || !noTldJars.contains(file.getName())) {
                        if (jarPathMap == null) {
                            jarPathMap = new HashMap();
                            jarPathMap.put(path, file);
                        } else if (!jarPathMap.containsKey(path)) {
                            jarPathMap.put(path, file);
                        }
                    }
                }
            }
            loader = loader.getParent();
        }

        return jarPathMap;
    
private longgetLastModified(java.util.Set resourcePaths, java.util.Map jarPaths)


        long lastModified = 0;

        Iterator paths = resourcePaths.iterator();
        while (paths.hasNext()) {
            String path = (String) paths.next();
            URL url = context.getServletContext().getResource(path);
            if (url == null) {
                log.debug( "Null url "+ path );
                break;
            }
            long lastM = url.openConnection().getLastModified();
            if (lastM > lastModified) lastModified = lastM;
            if (log.isDebugEnabled()) {
                log.debug( "Last modified " + path + " " + lastM);
            }
        }

        if (jarPaths != null) {
            paths = jarPaths.values().iterator();
            while (paths.hasNext()) {
                File jarFile = (File) paths.next();
                long lastM = jarFile.lastModified();
                if (lastM > lastModified) lastModified = lastM;
                if (log.isDebugEnabled()) {
                    log.debug("Last modified " + jarFile.getAbsolutePath()
                              + " " + lastM);
                }
            }
        }

        return lastModified;
    
public java.lang.String[]getTldListeners()

        String result[]=new String[listeners.size()];
        listeners.toArray(result);
        return result;
    
public booleangetTldNamespaceAware()
Get the server.xml attribute's xmlNamespaceAware.

return
true if namespace awarenes is enabled.

        return tldNamespaceAware;
    
public booleangetTldValidation()
Get the server.xml attribute's xmlValidation.

return
true if validation is enabled.

        return tldValidation;
    
public booleanisRescan()

        return rescan;
    
private voidprocessCache(java.io.File tldCache)

        // read the cache and return;
        try {
            FileInputStream in=new FileInputStream(tldCache);
            ObjectInputStream ois=new ObjectInputStream( in );
            String list[]=(String [])ois.readObject();
            if( log.isDebugEnabled() )
                log.debug("Reusing tldCache " + tldCache + " " + list.length);
            for( int i=0; list!=null && i<list.length; i++ ) {
                context.addApplicationListener(list[i]);
            }
            ois.close();
        } catch( ClassNotFoundException ex ) {
            ex.printStackTrace();
        }
    
public voidsetContext(org.apache.catalina.Context context)

        this.context = context;
    
public static voidsetNoTldJars(java.lang.String jarNames)
Sets the list of JARs that are known not to contain any TLDs.

param
jarNames List of comma-separated names of JAR files that are known not to contain any TLDs


    // --------------------------------------------------------- Public Methods

                                         
         
        if (jarNames != null) {
            noTldJars.clear();
            StringTokenizer tokenizer = new StringTokenizer(jarNames, ",");
            while (tokenizer.hasMoreElements()) {
                noTldJars.add(tokenizer.nextToken());
            }
        }
    
public voidsetRescan(boolean rescan)

        this.rescan = rescan;
    
public voidsetTldNamespaceAware(boolean tldNamespaceAware)
Set the namespace aware feature of the XML parser used when parsing xml instances.

param
tldNamespaceAware true to enable namespace awareness

        TldConfig.tldNamespaceAware = tldNamespaceAware;
    
public voidsetTldValidation(boolean tldValidation)
Set the validation feature of the XML parser used when parsing xml instances.

param
tldValidation true to enable xml instance validation

        TldConfig.tldValidation = tldValidation;
    
private voidtldScanJar(java.lang.String resourcePath)
Scan the JAR file at the specified resource path for TLDs in the META-INF subdirectory, and scan each TLD for application event listeners that need to be registered.

param
resourcePath Resource path of the JAR file to scan
exception
Exception if an exception occurs while scanning this JAR


        if (log.isDebugEnabled()) {
            log.debug(" Scanning JAR at resource path '" + resourcePath + "'");
        }

        URL url = context.getServletContext().getResource(resourcePath);
        if (url == null) {
            throw new IllegalArgumentException
                                (sm.getString("contextConfig.tldResourcePath",
                                              resourcePath));
        }

        File file = null;
        try {
            file = new File(url.toURI());
        } catch (URISyntaxException e) {
            // Ignore, probably an unencoded char
            file = new File(url.getFile());
        }
        try {
            file = file.getCanonicalFile();
        } catch (IOException e) {
            // Ignore
        }
        tldScanJar(file);

    
private voidtldScanJar(java.io.File file)
Scans all TLD entries in the given JAR for application listeners.

param
file JAR file whose TLD entries are scanned for application listeners


        JarFile jarFile = null;
        String name = null;

        String jarPath = file.getAbsolutePath();

        try {
            jarFile = new JarFile(file);
            Enumeration entries = jarFile.entries();
            while (entries.hasMoreElements()) {
                JarEntry entry = (JarEntry) entries.nextElement();
                name = entry.getName();
                if (!name.startsWith("META-INF/")) {
                    continue;
                }
                if (!name.endsWith(".tld")) {
                    continue;
                }
                if (log.isTraceEnabled()) {
                    log.trace("  Processing TLD at '" + name + "'");
                }
                try {
                    tldScanStream(new InputSource(jarFile.getInputStream(entry)));
                } catch (Exception e) {
                    log.error(sm.getString("contextConfig.tldEntryException",
                                           name, jarPath, context.getPath()),
                              e);
                }
            }
        } catch (Exception e) {
            log.error(sm.getString("contextConfig.tldJarException",
                                   jarPath, context.getPath()),
                      e);
        } finally {
            if (jarFile != null) {
                try {
                    jarFile.close();
                } catch (Throwable t) {
                    // Ignore
                }
            }
        }
    
private java.util.SettldScanResourcePaths()
Accumulate and return a Set of resource paths to be analyzed for tag library descriptors. Each element of the returned set will be the context-relative path to either a tag library descriptor file, or to a JAR file that may contain tag library descriptors in its META-INF subdirectory.

exception
IOException if an input/output error occurs while accumulating the list of resource paths

        if (log.isDebugEnabled()) {
            log.debug(" Accumulating TLD resource paths");
        }
        Set resourcePaths = new HashSet();

        // Accumulate resource paths explicitly listed in the web application
        // deployment descriptor
        if (log.isTraceEnabled()) {
            log.trace("  Scanning <taglib> elements in web.xml");
        }
        String taglibs[] = context.findTaglibs();
        for (int i = 0; i < taglibs.length; i++) {
            String resourcePath = context.findTaglib(taglibs[i]);
            // FIXME - Servlet 2.4 DTD implies that the location MUST be
            // a context-relative path starting with '/'?
            if (!resourcePath.startsWith("/")) {
                resourcePath = "/WEB-INF/" + resourcePath;
            }
            if (log.isTraceEnabled()) {
                log.trace("   Adding path '" + resourcePath +
                    "' for URI '" + taglibs[i] + "'");
            }
            resourcePaths.add(resourcePath);
        }

        DirContext resources = context.getResources();
        if (resources != null) {
            tldScanResourcePathsWebInf(resources, "/WEB-INF", resourcePaths);
        }

        // Return the completed set
        return (resourcePaths);

    
private voidtldScanResourcePathsWebInf(javax.naming.directory.DirContext resources, java.lang.String rootPath, java.util.Set tldPaths)


        if (log.isTraceEnabled()) {
            log.trace("  Scanning TLDs in " + rootPath + " subdirectory");
        }

        try {
            NamingEnumeration items = resources.list(rootPath);
            while (items.hasMoreElements()) {
                NameClassPair item = (NameClassPair) items.nextElement();
                String resourcePath = rootPath + "/" + item.getName();
                if (!resourcePath.endsWith(".tld")
                        && (resourcePath.startsWith("/WEB-INF/classes")
                            || resourcePath.startsWith("/WEB-INF/lib"))) {
                    continue;
                }
                if (resourcePath.endsWith(".tld")) {
                    if (log.isTraceEnabled()) {
                        log.trace("   Adding path '" + resourcePath + "'");
                    }
                    tldPaths.add(resourcePath);
                } else {
                    tldScanResourcePathsWebInf(resources, resourcePath,
                                               tldPaths);
                }
            }
        } catch (NamingException e) {
            ; // Silent catch: it's valid that no /WEB-INF directory exists
        }
    
private voidtldScanStream(org.xml.sax.InputSource resourceStream)
Scan the TLD contents in the specified input stream, and register any application event listeners found there. NOTE - It is the responsibility of the caller to close the InputStream after this method returns.

param
resourceStream InputStream containing a tag library descriptor
exception
Exception if an exception occurs while scanning this TLD


        if (tldDigester == null){
            tldDigester = createTldDigester();
        }
        
        synchronized (tldDigester) {
            try {
                tldDigester.push(this);
                tldDigester.parse(resourceStream);
            } finally {
                tldDigester.reset();
            }
        }

    
private voidtldScanTld(java.lang.String resourcePath)
Scan the TLD contents at the specified resource path, and register any application event listeners found there.

param
resourcePath Resource path being scanned
exception
Exception if an exception occurs while scanning this TLD


        if (log.isDebugEnabled()) {
            log.debug(" Scanning TLD at resource path '" + resourcePath + "'");
        }

        InputSource inputSource = null;
        try {
            InputStream stream =
                context.getServletContext().getResourceAsStream(resourcePath);
            if (stream == null) {
                throw new IllegalArgumentException
                (sm.getString("contextConfig.tldResourcePath",
                        resourcePath));
            }
            inputSource = new InputSource(stream);
            if (inputSource == null) {
                throw new IllegalArgumentException
                    (sm.getString("contextConfig.tldResourcePath",
                                  resourcePath));
            }
            tldScanStream(inputSource);
        } catch (Exception e) {
             throw new ServletException
                 (sm.getString("contextConfig.tldFileException", resourcePath,
                               context.getPath()),
                  e);
        }