Extend the virtual loader a bit further, allowing developers to specify a class-path...
authorfhanik <fhanik@13f79535-47bb-0310-9956-ffa450edef68>
Tue, 21 Aug 2007 19:00:23 +0000 (19:00 +0000)
committerfhanik <fhanik@13f79535-47bb-0310-9956-ffa450edef68>
Tue, 21 Aug 2007 19:00:23 +0000 (19:00 +0000)
git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@568233 13f79535-47bb-0310-9956-ffa450edef68

java/org/apache/catalina/loader/VirtualWebappLoader.java

index 6cb131c..0733016 100755 (executable)
 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 @@ import org.apache.juli.logging.LogFactory;
  * 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>
  * &lt;Context docBase="\webapps\mydocbase">
  *   &lt;Loader className="org.apache.catalina.loader.VirtualWebappLoader"
  *              virtualClasspath="\dir\classes:\somedir\somejar.jar"
  *              makeLocalCopy="true"
- *              separator=":"/>
+ *              separator=":"
+ *              separateJars="true"
+ *              readManifestCP="true"/>
  * &lt;/Context>
  * </code>
  *
@@ -73,7 +82,7 @@ public class VirtualWebappLoader extends WebappLoader {
     /**
      * 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 @@ public class VirtualWebappLoader extends WebappLoader {
      * 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 @@ public class VirtualWebappLoader extends WebappLoader {
         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 @@ public class VirtualWebappLoader extends WebappLoader {
             }
             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 @@ public class VirtualWebappLoader extends WebappLoader {
                     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
@@ -205,4 +272,16 @@ public class VirtualWebappLoader extends WebappLoader {
     public String getSeparator() {
         return separator;
     }
+
+    public boolean getSeparateJars() {
+        return separateJars;
+    }
+
+    public boolean getReadManifestCP() {
+        return readManifestCP;
+    }
+
+    public String getVirtualClasspath() {
+        return virtualClasspath;
+    }
 }