Author: fhanik Date: Tue Aug 21 12:00:23 2007 New Revision: 568233 URL: http://svn.apache.org/viewvc?rev=568233&view=rev Log: Extend the virtual loader a bit further, allowing developers to specify a class-path using the MANIFEST.MF file in the WAR file. I can't see that it would break the spec, and Websphere does it.
Modified: tomcat/trunk/java/org/apache/catalina/loader/VirtualWebappLoader.java Modified: tomcat/trunk/java/org/apache/catalina/loader/VirtualWebappLoader.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/loader/VirtualWebappLoader.java?rev=568233&r1=568232&r2=568233&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/loader/VirtualWebappLoader.java (original) +++ tomcat/trunk/java/org/apache/catalina/loader/VirtualWebappLoader.java Tue Aug 21 12:00:23 2007 @@ -17,14 +17,20 @@ package org.apache.catalina.loader; import java.io.File; +import java.io.IOException; import java.util.ArrayList; import java.util.StringTokenizer; +import java.util.jar.Attributes; import java.util.jar.JarFile; +import java.util.jar.Manifest; +import javax.naming.NamingException; +import javax.naming.directory.DirContext; import org.apache.catalina.LifecycleException; import org.apache.catalina.startup.ExpandWar; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; +import org.apache.naming.resources.Resource; /** * Simple webapp classloader that allows a customized classpath to be added @@ -41,13 +47,16 @@ * but be kept separate during runtime. * * The separator for the virtualClasspath defaulted to ; but can be configured using the separator attribute - * + * + * IF the attribute readManifestCP is set to true, the Class-Path from the WAR files META-INF/MANIFEST.MF file is also read. * <code> * <Context docBase="\webapps\mydocbase"> * <Loader className="org.apache.catalina.loader.VirtualWebappLoader" * virtualClasspath="\dir\classes:\somedir\somejar.jar" * makeLocalCopy="true" - * separator=":"/> + * separator=":" + * separateJars="true" + * readManifestCP="true"/> * </Context> * </code> * @@ -73,7 +82,7 @@ /** * Should we make a copy of the libraries upon startup */ - protected boolean makeLocalCopy = false; + protected boolean makeLocalCopy = true; /** * The location of the libraries. @@ -84,6 +93,17 @@ * The path seperator */ protected String separator = ";"; + + /** + * Separate Jars, means that Jars will be loaded + * into the classloaded, in a non locking way. + */ + protected boolean separateJars = true; + + /** + * Read the manifest class-path + */ + protected boolean readManifestCP = true; /** * Construct a new WebappLoader with no defined parent class loader (so that * the actual parent will be the system class loader). @@ -120,6 +140,14 @@ this.separator = separator; } + public void setReadManifestCP(boolean readManifestCP) { + this.readManifestCP = readManifestCP; + } + + public void setSeparateJars(boolean separateJars) { + this.separateJars = separateJars; + } + @Override public void start() throws LifecycleException { if (log.isInfoEnabled()) log.info("Starting VirtualWebappLoader for:"+getContainer().getName()); @@ -141,35 +169,16 @@ } tempDir.mkdirs(); } - StringTokenizer tkn = new StringTokenizer(virtualClasspath, separator); - while (tkn!=null && tkn.hasMoreTokens()) { - String ftkn = tkn.nextToken(); - if (ftkn==null) continue; - File file = new File(ftkn); - if (!file.exists()) { - continue; - } - File tmpFile = file; - if (makeLocalCopy) { - tmpFile = new File(tempDir, file.getName()); - if (log.isDebugEnabled()) log.debug("Creating local copy:"+tmpFile.getAbsolutePath()); - if (!ExpandWar.copy(file, tmpFile)) throw new LifecycleException("Unable to copy resources:"+file.getAbsolutePath()); - } - if (tmpFile.isDirectory()) { - if (log.isDebugEnabled()) log.debug("Adding directory to virtual repo:"+tmpFile.getAbsolutePath()); - addRepository("file:/" + tmpFile.getAbsolutePath() + "/"); - } else if (tmpFile.getAbsolutePath().endsWith(".jar")) { - //addRepository("file:/" + tmpFile.getAbsolutePath()); - jarFiles.add(tmpFile.getAbsolutePath()); - } else { - if (log.isDebugEnabled()) log.debug("Adding file to virtual repo:"+tmpFile.getAbsolutePath()); - addRepository("file:/" + tmpFile.getAbsolutePath()); - } - } + processClassPath(virtualClasspath,jarFiles,separator); + + processManifest(jarFiles); + if (log.isDebugEnabled()) log.debug("Starting parent WebappLoader"); super.start(); + //jars were added as a regular repository above + if (!separateJars) return; //add JarFiles to the classloader, we can't do that before we start //since there is no classloader during that time @@ -185,9 +194,67 @@ wloader.addJar(filename,jfile,file); }catch ( Exception iox) { if (log.isDebugEnabled()) log.debug("",iox); + }//catch + }//for + }//end if + } + + protected void processManifest(ArrayList<String> jarFiles) throws LifecycleException { + //process the meta inf directory + DirContext resources = getContainer().getResources(); + // Setting up the class repository (/WEB-INF/classes), if it exists + String metainfPath = "/META-INF"; + DirContext metainf = null; + try { + Object object = resources.lookup(metainfPath); + if (object instanceof DirContext) { + metainf = (DirContext) object; + Object o = metainf.lookup("MANIFEST.MF"); + if (o!=null && o instanceof Resource) { + Manifest mf = new Manifest(((Resource)o).streamContent()); + Attributes attr = mf.getMainAttributes(); + String classpath = (String)attr.getValue("Class-Path"); + if ( classpath != null ) processClassPath(classpath,jarFiles," "); } } - } + } catch(IOException e) { + //unable to read manifest + log.debug("Unable to read manifest.",e); + } catch(NamingException e) { + // Silent catch: it's valid that no /META-INF collection exists + } + } + + private void processClassPath(String classpath, ArrayList<String> jarFiles, String sep) throws LifecycleException { + StringTokenizer tkn = new StringTokenizer(classpath, sep); + while (tkn!=null && tkn.hasMoreTokens()) { + String ftkn = tkn.nextToken(); + if (ftkn==null) continue; + File file = new File(ftkn); + addRepository(jarFiles, file); + } + } + + protected void addRepository(ArrayList<String> jarFiles, File file) throws LifecycleException { + if (!file.exists()) { + return; + } + File tmpFile = file; + if (makeLocalCopy) { + tmpFile = new File(tempDir, file.getName()); + if (log.isDebugEnabled()) log.debug("Creating local copy:"+tmpFile.getAbsolutePath()); + if (!ExpandWar.copy(file, tmpFile)) throw new LifecycleException("Unable to copy resources:"+file.getAbsolutePath()); + } + if (tmpFile.isDirectory()) { + if (log.isDebugEnabled()) log.debug("Adding directory to virtual repo:"+tmpFile.getAbsolutePath()); + addRepository("file:/" + tmpFile.getAbsolutePath() + "/"); + } else if (tmpFile.getAbsolutePath().endsWith(".jar") && separateJars) { + //addRepository("file:/" + tmpFile.getAbsolutePath()); + jarFiles.add(tmpFile.getAbsolutePath()); + } else { + if (log.isDebugEnabled()) log.debug("Adding file to virtual repo:"+tmpFile.getAbsolutePath()); + addRepository("file:/" + tmpFile.getAbsolutePath()); + } } @Override @@ -204,5 +271,17 @@ public String getSeparator() { return separator; + } + + public boolean getSeparateJars() { + return separateJars; + } + + public boolean getReadManifestCP() { + return readManifestCP; + } + + public String getVirtualClasspath() { + return virtualClasspath; } } --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]