You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by lu...@apache.org on 2003/03/26 21:40:37 UTC

cvs commit: jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/startup TldConfig.java

luehe       2003/03/26 12:40:37

  Modified:    catalina/src/share/org/apache/catalina/startup
                        TldConfig.java
  Log:
  Fixed Bugzilla 15875 ("Support global sharing of tag libraries")
  
  Revision  Changes    Path
  1.3       +186 -66   jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/startup/TldConfig.java
  
  Index: TldConfig.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/startup/TldConfig.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- TldConfig.java	16 Feb 2003 19:40:21 -0000	1.2
  +++ TldConfig.java	26 Mar 2003 20:40:37 -0000	1.3
  @@ -69,6 +69,8 @@
   import java.io.InputStream;
   import java.io.ObjectInputStream;
   import java.io.ObjectOutputStream;
  +import java.net.URLConnection;
  +import java.net.URLClassLoader;
   import java.net.JarURLConnection;
   import java.net.URL;
   import java.util.ArrayList;
  @@ -106,6 +108,9 @@
       private static org.apache.commons.logging.Log log=
           org.apache.commons.logging.LogFactory.getLog( TldConfig.class );
   
  +    private static final String FILE_URL_PREFIX = "file:";
  +    private static final int FILE_URL_PREFIX_LEN = FILE_URL_PREFIX.length();
  +
       // ----------------------------------------------------- Instance Variables
   
       /**
  @@ -199,32 +204,23 @@
               }
           }
   
  -        // Acquire this list of TLD resource paths to be processed
  +        /*
  +	 * Acquire the list of TLD resource paths, possibly embedded in JAR
  +	 * files, to be processed
  +	 */
           Set resourcePaths = tldScanResourcePaths();
  +	Set globalJarPaths = getGlobalJarPaths();
   
  -        if( tldCache!= null && tldCache.exists()) {
  -            // Find last modified
  -            Iterator paths = resourcePaths.iterator();
  -            long lastModified=0;
  -            while (paths.hasNext()) {
  -                String path = (String) paths.next();
  -                URL url = context.getServletContext().getResource(path);
  -                if( url==null ) {
  -                    log.info( "Null url "+ path );
  -                    break;
  -                }
  -                long lastM=url.openConnection().getLastModified();
  -                if( lastM > lastModified ) lastModified=lastM;
  -                if( log.isDebugEnabled() )
  -                    log.debug( "Last modified " + path + " " + lastM);
  -            }
  -
  -            if( lastModified < tldCache.lastModified()) {
  +	// Check to see if we can use cached listeners
  +        if (tldCache != null && tldCache.exists()) {
  +            long lastModified = getLastModified(resourcePaths, globalJarPaths);
  +            if (lastModified < tldCache.lastModified()) {
                   processCache(tldCache);
                   return;
               }
           }
  -        // Scan each accumulated resource paths for TLDs to be processed
  +
  +        // Scan each accumulated resource path for TLDs to be processed
           Iterator paths = resourcePaths.iterator();
           while (paths.hasNext()) {
               String path = (String) paths.next();
  @@ -234,7 +230,12 @@
                   tldScanTld(path);
               }
           }
  -        String list[]=getTldListeners();
  +        paths = globalJarPaths.iterator();
  +        while (paths.hasNext()) {
  +            tldScanJar((JarURLConnection) paths.next());
  +        }
  +
  +        String list[] = getTldListeners();
   
           if( tldCache!= null ) {
               log.info( "Saving tld cache: " + tldCache + " " + list.length);
  @@ -263,6 +264,48 @@
   
       // -------------------------------------------------------- Private Methods
   
  +    /*
  +     * Returns the last modification date of the given sets of resources.
  +     *
  +     * @param resourcePaths
  +     * @param globalJarPaths
  +     *
  +     * @return Last modification date
  +     */
  +    private long getLastModified(Set resourcePaths, Set globalJarPaths)
  +            throws Exception {
  +
  +	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.info( "Null url "+ path );
  +		break;
  +	    }
  +	    long lastM = url.openConnection().getLastModified();
  +	    if (lastM > lastModified) lastModified = lastM;
  +	    if (log.isDebugEnabled()) {
  +		log.debug( "Last modified " + path + " " + lastM);
  +	    }
  +	}
  +
  +	paths = globalJarPaths.iterator();
  +	while (paths.hasNext()) {
  +	    JarURLConnection conn = (JarURLConnection) paths.next();
  +	    long lastM = conn.getLastModified();
  +	    if (lastM > lastModified) lastModified = lastM;
  +	    if (log.isDebugEnabled()) {
  +		log.debug("Last modified " + conn.getJarFileURL().toString()
  +			  + " " + lastM);
  +	    }
  +	}
  +
  +	return lastModified;
  +    }
  +
       private void processCache(File tldCache ) throws IOException {
           // read the cache and return;
           try {
  @@ -394,21 +437,33 @@
               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));
  +	}
  +	url = new URL("jar:" + url.toString() + "!/");
  +	tldScanJar((JarURLConnection) url.openConnection());
  +    }
  +
  +    /*
  +     * Scans all TLD entries in the given JAR for application listeners.
  +     *
  +     * @param conn URLConnection to the JAR file whose TLD entries are
  +     * scanned for application listeners
  +     */
  +    private void tldScanJar(JarURLConnection conn) throws Exception {
  +
           JarFile jarFile = null;
           String name = null;
           InputStream inputStream = null;
  -        try {
  -            URL url = context.getServletContext().getResource(resourcePath);
  -            if (url == null) {
  -                throw new IllegalArgumentException
  -                    (sm.getString("contextConfig.tldResourcePath",
  -                                  resourcePath));
  -            }
  -            url = new URL("jar:" + url.toString() + "!/");
  -            JarURLConnection conn =
  -                (JarURLConnection) url.openConnection();
  -            conn.setUseCaches(false);
  -            jarFile = conn.getJarFile();
  +
  +	String jarPath = conn.getJarFileURL().toString();
  +
  +	try {
  +	    conn.setUseCaches(false);
  +	    jarFile = conn.getJarFile();
               Enumeration entries = jarFile.entries();
               while (entries.hasMoreElements()) {
                   JarEntry entry = (JarEntry) entries.nextElement();
  @@ -434,10 +489,13 @@
               // XXX Why do we wrap it ? The signature is 'throws Exception'
               if (name == null) {
                       log.error(sm.getString("contextConfig.tldJarException",
  -                                  resourcePath, context.getPath()), e);
  +					   jarPath, context.getPath()),
  +			      e);
               } else {
                       log.error(sm.getString("contextConfig.tldEntryException",
  -                                  name, resourcePath, context.getPath()), e);
  +					   name, jarPath,
  +					   context.getPath()),
  +			      e);
               }
           } finally {
               if (inputStream != null) {
  @@ -461,7 +519,6 @@
   
       }
   
  -
       /**
        * Scan the TLD contents in the specified input stream, and register
        * any application event listeners found there.  <b>NOTE</b> - It is
  @@ -487,7 +544,6 @@
   
       }
   
  -
       /**
        * Scan the TLD contents at the specified resource path, and register
        * any application event listeners found there.
  @@ -531,7 +587,6 @@
   
       }
   
  -
       /**
        * Accumulate and return a Set of resource paths to be analyzed for
        * tag library descriptors.  Each element of the returned set will be
  @@ -568,38 +623,66 @@
               resourcePaths.add(resourcePath);
           }
   
  -        // Scan TLDs in the /WEB-INF subdirectory of the web application
  +        DirContext resources = context.getResources();
  +	if (resources != null) {
  +	    tldScanResourcePathsWebInf(resources, resourcePaths);
  +	    tldScanResourcePathsWebInfLibJars(resources, resourcePaths);
  +	}
  +
  +        // Return the completed set
  +        return (resourcePaths);
  +
  +    }
  +
  +    /*
  +     * Scans TLDs in the /WEB-INF subdirectory of the web application.
  +     *
  +     * @param resources The web application's resources
  +     * @param resourcePaths The set of resource paths to add to
  +     */
  +    private void tldScanResourcePathsWebInf(DirContext resources,
  +					    Set resourcePaths) 
  +            throws IOException {
  +
           if (log.isTraceEnabled()) {
               log.trace("  Scanning TLDs in /WEB-INF subdirectory");
           }
  -        DirContext resources = context.getResources();
  -        if( resources!=null ) {
  -            try {
  -                NamingEnumeration items = resources.list("/WEB-INF");
  -                while (items.hasMoreElements()) {
  -                    NameClassPair item = (NameClassPair) items.nextElement();
  -                    String resourcePath = "/WEB-INF/" + item.getName();
  -                    // FIXME - JSP 2.0 is not explicit about whether we should
  -                    // scan subdirectories of /WEB-INF for TLDs also
  -                    if (!resourcePath.endsWith(".tld")) {
  -                        continue;
  -                    }
  -                    if (log.isTraceEnabled()) {
  -                        log.trace("   Adding path '" + resourcePath + "'");
  -                    }
  -                    resourcePaths.add(resourcePath);
  -                }
  -            } catch (NamingException e) {
  -                ; // Silent catch: it's valid that no /WEB-INF directory exists
  -            }
  -        } else {
  -            log.info("No resource " + context + " " + context.getClass());
  -        }
   
  -        // Scan JARs in the /WEB-INF/lib subdirectory of the web application
  +	try {
  +	    NamingEnumeration items = resources.list("/WEB-INF");
  +	    while (items.hasMoreElements()) {
  +		NameClassPair item = (NameClassPair) items.nextElement();
  +		String resourcePath = "/WEB-INF/" + item.getName();
  +		// FIXME - JSP 2.0 is not explicit about whether we should
  +		// scan subdirectories of /WEB-INF for TLDs also
  +		if (!resourcePath.endsWith(".tld")) {
  +		    continue;
  +		}
  +		if (log.isTraceEnabled()) {
  +		    log.trace("   Adding path '" + resourcePath + "'");
  +		}
  +		resourcePaths.add(resourcePath);
  +	    }
  +	} catch (NamingException e) {
  +	    ; // Silent catch: it's valid that no /WEB-INF directory exists
  +	}
  +    }
  +
  +    /*
  +     * Adds any JARs in the /WEB-INF/lib subdirectory of the web application
  +     * to the given set of resource paths.
  +     *
  +     * @param resources The web application's resources
  +     * @param resourcePaths The set of resource paths to add to
  +     */
  +    private void tldScanResourcePathsWebInfLibJars(DirContext resources,
  +						   Set resourcePaths)
  +            throws IOException {
  +
           if (log.isTraceEnabled()) {
               log.trace("  Scanning JARs in /WEB-INF/lib subdirectory");
           }
  +
           try {
               NamingEnumeration items = resources.list("/WEB-INF/lib");
               while (items.hasMoreElements()) {
  @@ -616,10 +699,47 @@
           } catch (NamingException e) {
               ; // Silent catch: it's valid that no /WEB-INF/lib directory exists
           }
  +    }
   
  -        // Return the completed set
  -        return (resourcePaths);
  +    /*
  +     * Returns the paths to all JAR files accessible to all parent
  +     * classloaders of the web application class loader.
  +     *
  +     * This is a Tomcat-specific extension to the TLD search order defined in
  +     * the JSP spec, which will allow 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.,
  +     * <CATALINA_HOME>/common/lib).
  +     *
  +     * @return Set of paths to all JAR files accessible to all parent class
  +     * loaders of the web application class loader
  +     */
  +    private Set getGlobalJarPaths() throws IOException {
   
  -    }
  +        Set globalJarPaths = new HashSet();
  +
  +	ClassLoader loader = Thread.currentThread().getContextClassLoader();
  +	while (loader != null) {
  +	    if (loader instanceof URLClassLoader) {
  +		URL[] urls = ((URLClassLoader) loader).getURLs();
  +		for (int i=0; i<urls.length; i++) {
  +		    URLConnection conn = urls[i].openConnection();
  +		    if (conn instanceof JarURLConnection) {
  +			globalJarPaths.add((JarURLConnection) conn);
  +		    } else {
  +			String urlStr = urls[i].toString();
  +			if (urlStr.startsWith("file:")
  +			        && urlStr.endsWith(".jar")) {
  +			    URL jarURL = new URL("jar:" + urlStr + "!/");
  +			    globalJarPaths.add((JarURLConnection)
  +					       jarURL.openConnection());
  +			}
  +		    }
  +		}
  +	    }
  +	    loader = loader.getParent();
  +	}
   
  +	return globalJarPaths;
  +    }
   }
  
  
  

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