FileDocCategorySizeDatePackage
TldLocationsCache.javaAPI DocGlassfish v2 API24315Fri May 04 22:32:52 BST 2007org.apache.jasper.compiler

TldLocationsCache

public class TldLocationsCache extends Object
A container for all tag libraries that are defined "globally" for the web application. Tag Libraries can be defined globally in one of two ways: 1. Via elements in web.xml: the uri and location of the tag-library are specified in the element. 2. Via packaged jar files that contain .tld files within the META-INF directory, or some subdirectory of it. The taglib is 'global' if it has the element defined. A mapping between the taglib URI and its associated TaglibraryInfoImpl is maintained in this container. Actually, that's what we'd like to do. However, because of the way the classes TagLibraryInfo and TagInfo have been defined, it is not currently possible to share an instance of TagLibraryInfo across page invocations. A bug has been submitted to the spec lead. In the mean time, all we do is save the 'location' where the TLD associated with a taglib URI can be found. When a JSP page has a taglib directive, the mappings in this container are first searched (see method getLocation()). If a mapping is found, then the location of the TLD is returned. If no mapping is found, then the uri specified in the taglib directive is to be interpreted as the location for the TLD of this tag library.
author
Pierre Delisle
author
Jan Luehe

Fields Summary
private static com.sun.org.apache.commons.logging.Log
log
public static final int
ABS_URI
The types of URI one may specify for a tag library
public static final int
ROOT_REL_URI
public static final int
NOROOT_REL_URI
private static final String
WEB_XML
private static final String
FILE_PROTOCOL
private static final String
JAR_FILE_SUFFIX
private static HashSet
noTldJars
private static HashSet
systemUris
private static HashSet
systemUrisJsf
private HashMap
mappings
The mapping of the 'global' tag library URI to the location (resource path) of the TLD associated with that tag library. The location is returned as a String array: [0] The location [1] If the location is a jar file, this is the location of the tld.
private boolean
initialized
private ServletContext
ctxt
private boolean
redeployMode
private org.apache.jasper.Options
options
private boolean
localTldsProcessed
private boolean
useMyFaces
Constructors Summary
public TldLocationsCache(ServletContext ctxt, org.apache.jasper.Options options)



    //*********************************************************************
    // Constructor and Initilizations
    
    /*
     * Initializes the set of JARs that are known not to contain any TLDs
     */
     
        systemUrisJsf.add("http://java.sun.com/jsf/core");
        systemUrisJsf.add("http://java.sun.com/jsf/html");
        systemUris.add("http://java.sun.com/jsp/jstl/core");
    
    // END SJSAS 6384538
        /* SJSAS 6384538
        this(ctxt, true);
        */
        // START SJSAS 6384538
        this(ctxt, options, true);
        // END SJSAS 6384538
    
public TldLocationsCache(ServletContext ctxt, org.apache.jasper.Options options, boolean redeployMode)
Constructor.

param
ctxt the servlet context of the web application in which Jasper is running
param
redeployMode if true, then the compiler will allow redeploying a tag library from the same jar, at the expense of slowing down the server a bit. Note that this may only work on JDK 1.3.1_01a and later, because of JDK bug 4211817 fixed in this release. If redeployMode is false, a faster but less capable mode will be used.

    // END SJSAS 6384538
        this.ctxt = ctxt;
        // START SJSAS 6384538
        this.options = options;
        // END SJSAS 6384538
        this.redeployMode = redeployMode;
        /* GlassFish 747
        mappings = new Hashtable();
        */

        Boolean b = (Boolean) ctxt.getAttribute("com.sun.faces.useMyFaces");
        if (b != null) {
            useMyFaces = b.booleanValue();
        }
        initialized = false;
    
Methods Summary
public java.lang.String[]getLocation(java.lang.String uri)
Gets the 'location' of the TLD associated with the given taglib 'uri'. Returns null if the uri is not associated with any tag library 'exposed' in the web application. A tag library is 'exposed' either explicitly in web.xml or implicitly via the uri tag in the TLD of a taglib deployed in a jar file (WEB-INF/lib).

param
uri The taglib uri
return
An array of two Strings: The first element denotes the real path to the TLD. If the path to the TLD points to a jar file, then the second element denotes the name of the TLD entry in the jar file. Returns null if the uri is not associated with any tag library 'exposed' in the web application.

        if (!initialized) {
            init();
        }
        return (String[]) mappings.get(uri);
    
private java.lang.StringgetUriFromTld(java.lang.String resourcePath, java.io.InputStream in)

        // Parse the tag library descriptor at the specified resource path
        /* SJSAS 6384538
        TreeNode tld = new ParserUtils().parseXMLDocument(resourcePath, in);
        */
        // START SJSAS 6384538
        TreeNode tld = new ParserUtils().parseXMLDocument(
            resourcePath, in, options.isValidationEnabled());
        // END SJSAS 6384538
        TreeNode uri = tld.findChild("uri");
        if (uri != null) {
            String body = uri.getBody();
            if (body != null)
                return body;
        }

        return null;
    
private voidinit()

        if (initialized) return;

        // START GlassFish 747
        HashMap tldUriToLocationMap = (HashMap) ctxt.getAttribute(
            Constants.JSP_TLD_URI_TO_LOCATION_MAP);
        if (tldUriToLocationMap != null) {
            localTldsProcessed = true;
            mappings = tldUriToLocationMap;
        } else {
            mappings = new HashMap();
        }
        // END GlassFish 747
        try {
            /* GlassFish 747
            processWebDotXml();
            */
            // START Glassfish 747
            if (!localTldsProcessed) {
                processWebDotXml();
            }
            // END Glassfish 747
            scanJars();
            /* GlassFish 747
            processTldsInFileSystem("/WEB-INF/");
            */
            // START GlassFish 747
            if (!localTldsProcessed) {
                processTldsInFileSystem("/WEB-INF/");
            }
            // END Glassfish 747
            initialized = true;
        } catch (Exception ex) {
            throw new JasperException(
                Localizer.getMessage("jsp.error.internal.tldinit"),
                ex);
        }
    
private booleanneedScanJar(java.lang.String jarPath, boolean isLocal)


        if (isLocal) {
            return true;
        }

        String jarName = jarPath;
        int slash = jarPath.lastIndexOf('/");
        if (slash >= 0) {
            jarName = jarPath.substring(slash + 1);
        }
        return ((noTldJars == null) || !noTldJars.contains(jarName));
    
private voidprocessTldsInFileSystem(java.lang.String startPath)


        Set dirList = ctxt.getResourcePaths(startPath);
        if (dirList != null) {
            Iterator it = dirList.iterator();
            while (it.hasNext()) {
                String path = (String) it.next();
                if (path.endsWith("/")) {
                    processTldsInFileSystem(path);
                }
                if (!path.endsWith(".tld")) {
                    continue;
                }
                if (path.startsWith("/WEB-INF/tags/")
                        && !path.endsWith("implicit.tld")) {
                    throw new JasperException(
                        Localizer.getMessage(
                                "jsp.error.tldinit.tldInWebInfTags",
                                path));
                }
                InputStream stream = ctxt.getResourceAsStream(path);
                String uri = null;
                try {
                    uri = getUriFromTld(path, stream);
                } finally {
                    if (stream != null) {
                        try {
                            stream.close();
                        } catch (Throwable t) {
                            // do nothing
                        }
                    }
                }
                // Add implicit map entry only if its uri is not already
                // present in the map
                if (uri != null
                         && mappings.get(uri) == null
                         && !systemUris.contains(uri)
                         && (!systemUrisJsf.contains(uri)
                             || useMyFaces)) {
                    mappings.put(uri, new String[] { path, null });
                }
            }
        }
    
private voidprocessWebDotXml()


        InputStream is = null;

        try {
            // Acquire input stream to web application deployment descriptor
            String altDDName = (String)ctxt.getAttribute(
                                                    Constants.ALT_DD_ATTR);
            if (altDDName != null) {
                try {
                    is = new FileInputStream(altDDName);
                } catch (FileNotFoundException e) {
                    if (log.isWarnEnabled()) {
                        log.warn(Localizer.getMessage(
                                            "jsp.error.internal.filenotfound",
                                            altDDName));
                    }
                }
            } else {
                is = ctxt.getResourceAsStream(WEB_XML);
                /* SJSAS 6396582
                if (is == null && log.isWarnEnabled()) {
                    log.warn(Localizer.getMessage(
                                            "jsp.error.internal.filenotfound",
                                            WEB_XML));
                }
                */
            }

            if (is == null) {
                return;
            }

            // Parse the web application deployment descriptor
            TreeNode webtld = null;
            // altDDName is the absolute path of the DD
            if (altDDName != null) {
                webtld = new ParserUtils().parseXMLDocument(altDDName, is);
            } else {
                webtld = new ParserUtils().parseXMLDocument(WEB_XML, is);
            }

            // Allow taglib to be an element of the root or jsp-config (JSP2.0)
            TreeNode jspConfig = webtld.findChild("jsp-config");
            if (jspConfig != null) {
                webtld = jspConfig;
            }
            Iterator taglibs = webtld.findChildren("taglib");
            while (taglibs.hasNext()) {

                // Parse the next <taglib> element
                TreeNode taglib = (TreeNode) taglibs.next();
                String tagUri = null;
                String tagLoc = null;
                TreeNode child = taglib.findChild("taglib-uri");
                if (child != null)
                    tagUri = child.getBody();
                // Ignore system tlds in web.xml, for backward compatibility
                if (systemUris.contains(tagUri)
                        || (!useMyFaces && systemUrisJsf.contains(tagUri))) {
                    continue;
                }
                child = taglib.findChild("taglib-location");
                if (child != null)
                    tagLoc = child.getBody();

                // Save this location if appropriate
                if (tagLoc == null)
                    continue;
                if (uriType(tagLoc) == NOROOT_REL_URI)
                    tagLoc = "/WEB-INF/" + tagLoc;
                String tagLoc2 = null;
                if (tagLoc.endsWith(JAR_FILE_SUFFIX)) {
                    tagLoc = ctxt.getResource(tagLoc).toString();
                    tagLoc2 = "META-INF/taglib.tld";
                }
                mappings.put(tagUri, new String[] { tagLoc, tagLoc2 });
            }
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (Throwable t) {}
            }
        }
    
private voidscanJar(java.net.JarURLConnection conn, boolean ignore)
Scans the given JarURLConnection for TLD files located in META-INF (or a subdirectory of it), adding an implicit map entry to the taglib map for any TLD that has a element.

param
conn The JarURLConnection to the JAR file to scan
param
ignore true if any exceptions raised when processing the given JAR should be ignored, false otherwise


        JarFile jarFile = null;
        String resourcePath = conn.getJarFileURL().toString();
        try {
            if (redeployMode) {
                conn.setUseCaches(false);
            }
            jarFile = conn.getJarFile();
            Enumeration entries = jarFile.entries();
            while (entries.hasMoreElements()) {
                JarEntry entry = (JarEntry) entries.nextElement();
                String name = entry.getName();
                if (!name.startsWith("META-INF/")) continue;
                if (!name.endsWith(".tld")) continue;
                InputStream stream = jarFile.getInputStream(entry);
                try {
                    String uri = getUriFromTld(resourcePath, stream);
                    // Add map entry.
                    // Override existing entries as we move higher
                    // up in the classloader delegation chain.
                    if (uri != null
                            && (mappings.get(uri) == null
                                || systemUris.contains(uri)
                                || (systemUrisJsf.contains(uri)
                                    && !useMyFaces))) {
                        mappings.put(uri, new String[]{ resourcePath, name });
                    }
                } finally {
                    if (stream != null) {
                        try {
                            stream.close();
                        } catch (Throwable t) {
                            // do nothing
                        }
                    }
                }
            }
        } catch (Exception ex) {
            if (!redeployMode) {
                // if not in redeploy mode, close the jar in case of an error
                if (jarFile != null) {
                    try {
                        jarFile.close();
                    } catch (Throwable t) {
                        // ignore
                    }
                }
            }
            if (!ignore) {
                throw new JasperException(ex);
            }
        } finally {
            if (redeployMode) {
                // if in redeploy mode, always close the jar
                if (jarFile != null) {
                    try {
                        jarFile.close();
                    } catch (Throwable t) {
                        // ignore
                    }
                }
            }
        }
    
private voidscanJars()


        ClassLoader webappLoader
            = Thread.currentThread().getContextClassLoader();
        ClassLoader loader = webappLoader;

        // START Glassfish 747
        if (localTldsProcessed) {
            if (loader != null) {
                loader = loader.getParent();
            }
        }
        // END GlassFish 747

        while (loader != null) {
            if (loader instanceof URLClassLoader) {
                boolean isLocal = (loader == webappLoader);
                URL[] urls = ((URLClassLoader) loader).getURLs();
                for (int i=0; i<urls.length; i++) {
                    URLConnection conn = urls[i].openConnection();
                    if (conn instanceof JarURLConnection) {
                        if (needScanJar(
                                ((JarURLConnection) conn).getJarFile().getName(),
                                isLocal)) {
                            scanJar((JarURLConnection) conn, true);
                        }
                    } else {
                        String urlStr = urls[i].toString();
                        if (urlStr.startsWith(FILE_PROTOCOL)
                                && urlStr.endsWith(JAR_FILE_SUFFIX)
                                && needScanJar(urlStr, isLocal)) {
                            URL jarURL = new URL("jar:" + urlStr + "!/");
                            scanJar((JarURLConnection) jarURL.openConnection(),
                                    true);
                        }
                    }
                }
            }

            loader = loader.getParent();
        }
    
public static voidsetNoTldJars(java.lang.String jarNames)
Sets the list of JAR files that are known not to contain any TLDs. Only shared JAR files (that is, those loaded by a delegation parent of the webapp's classloader) will be checked against this list.

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

        if (jarNames != null) {
            if (noTldJars == null) {
                noTldJars = new HashSet<String>();
            } else {
                noTldJars.clear();
            }
            StringTokenizer tokenizer = new StringTokenizer(jarNames, ",");
            while (tokenizer.hasMoreElements()) {
                noTldJars.add(tokenizer.nextToken());
            }
        }
    
public static voidsetNoTldJars(java.util.HashSet set)
Sets the list of JAR files that are known not to contain any TLDs. Only shared JAR files (that is, those loaded by a delegation parent of the webapp's classloader) will be checked against this list.

param
set HashSet containing the names of JAR files known not to contain any TLDs

        noTldJars = set;
    
public static inturiType(java.lang.String uri)
Returns the type of a URI: ABS_URI ROOT_REL_URI NOROOT_REL_URI

        if (uri.indexOf(':") != -1) {
            return ABS_URI;
        } else if (uri.startsWith("/")) {
            return ROOT_REL_URI;
        } else {
            return NOROOT_REL_URI;
        }