You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by cr...@locus.apache.org on 2000/09/29 22:44:08 UTC

cvs commit: jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/startup Bootstrap.java Catalina.java

craigmcc    00/09/29 13:44:08

  Modified:    catalina/src/share/org/apache/catalina/loader
                        StandardClassLoader.java
               catalina/src/share/org/apache/catalina/startup
                        Bootstrap.java Catalina.java
  Added:       catalina/src/share/org/apache/catalina/loader Extension.java
  Log:
  Implement the first stage of support for the new Servlet 2.3 requirments
  related to recognizing dependencies on shared "optional packages"
  (formerly called "standard extensions") that might be made available to
  all web applications via a special class loader that becomes the parent to
  the web app class loader.
  
  NOTE:  The shared extensions class loader is currently being created (by
  the Bootstrap class) and propogated to the Catalina object, but not yet
  propogated down to the containers.  That will be part of the next set of
  commits, which will include enhancements to enforce the new rules.
  
  Revision  Changes    Path
  1.3       +138 -6    jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/loader/StandardClassLoader.java
  
  Index: StandardClassLoader.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/loader/StandardClassLoader.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- StandardClassLoader.java	2000/09/23 22:41:12	1.2
  +++ StandardClassLoader.java	2000/09/29 20:44:07	1.3
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/loader/StandardClassLoader.java,v 1.2 2000/09/23 22:41:12 craigmcc Exp $
  - * $Revision: 1.2 $
  - * $Date: 2000/09/23 22:41:12 $
  + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/loader/StandardClassLoader.java,v 1.3 2000/09/29 20:44:07 craigmcc Exp $
  + * $Revision: 1.3 $
  + * $Date: 2000/09/29 20:44:07 $
    *
    * ====================================================================
    *
  @@ -67,11 +67,16 @@
   import java.io.File;
   import java.io.InputStream;
   import java.io.IOException;
  +import java.net.JarURLConnection;
   import java.net.MalformedURLException;
   import java.net.URL;
   import java.net.URLClassLoader;
  +import java.util.ArrayList;
   import java.util.Enumeration;
   import java.util.HashMap;
  +import java.util.Iterator;
  +import java.util.jar.JarFile;
  +import java.util.jar.Manifest;
   
   
   /**
  @@ -94,7 +99,7 @@
    * independently.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.2 $ $Date: 2000/09/23 22:41:12 $
  + * @version $Revision: 1.3 $ $Date: 2000/09/29 20:44:07 $
    */
   
   public class StandardClassLoader
  @@ -194,6 +199,15 @@
   
   
       /**
  +     * The set of optional packages (formerly standard extensions) that
  +     * are available in the repositories associated with this class loader.
  +     * Each object in this list is of type
  +     * <code>org.apache.catalina.loader.Extension</code>.
  +     */
  +    protected ArrayList available = new ArrayList();
  +
  +
  +    /**
        * The cache of ClassCacheEntries for classes we have loaded locally,
        * keyed by class name.
        */
  @@ -225,6 +239,15 @@
   
   
       /**
  +     * The set of optional packages (formerly standard extensions) that
  +     * are required in the repositories associated with this class loader.
  +     * Each object in this list is of type
  +     * <code>org.apache.catalina.loader.Extension</code>.
  +     */
  +    protected ArrayList required = new ArrayList();
  +
  +
  +    /**
        * The set of class name prefixes to which access should be restricted.
        * A request for a class or resource that starts with this prefix will
        * fail with an appropriate exception or <code>null</code> return value,
  @@ -337,8 +360,6 @@
           // Add this repository to our internal list
           addRepositoryInternal(repository);
   
  -        ;       // FIXME: addRepository()
  -
       }
   
   
  @@ -402,6 +423,41 @@
   
   
       /**
  +     * Return a list of "optional packages" (formerly "standard extensions")
  +     * that have been declared to be available in the repositories associated
  +     * with this class loader, plus any parent class loader implemented with
  +     * the same class.
  +     */
  +    public Extension[] findAvailable() {
  +
  +        // Initialize the results with our local available extensions
  +        ArrayList results = new ArrayList();
  +        Iterator available = this.available.iterator();
  +        while (available.hasNext())
  +            results.add(available.next());
  +
  +        // Trace our parentage tree and add declared extensions when possible
  +        ClassLoader loader = this;
  +        while (true) {
  +            loader = loader.getParent();
  +            if (loader == null)
  +                break;
  +            if (!(loader instanceof StandardClassLoader))
  +                continue;
  +            Extension extensions[] =
  +                ((StandardClassLoader) loader).findAvailable();
  +            for (int i = 0; i < extensions.length; i++)
  +                results.add(extensions[i]);
  +        }
  +
  +        // Return the results as an array
  +        Extension extensions[] = new Extension[results.size()];
  +        return ((Extension[]) results.toArray(extensions));
  +
  +    }
  +
  +
  +    /**
        * Return a String array of the current repositories for this class
        * loader.  If there are no repositories, a zero-length array is
        * returned.
  @@ -414,6 +470,41 @@
   
   
       /**
  +     * Return a list of "optional packages" (formerly "standard extensions")
  +     * that have been declared to be required in the repositories associated
  +     * with this class loader, plus any parent class loader implemented with
  +     * the same class.
  +     */
  +    public Extension[] findRequired() {
  +
  +        // Initialize the results with our local required extensions
  +        ArrayList results = new ArrayList();
  +        Iterator required = this.required.iterator();
  +        while (required.hasNext())
  +            results.add(required.next());
  +
  +        // Trace our parentage tree and add declared extensions when possible
  +        ClassLoader loader = this;
  +        while (true) {
  +            loader = loader.getParent();
  +            if (loader == null)
  +                break;
  +            if (!(loader instanceof StandardClassLoader))
  +                continue;
  +            Extension extensions[] =
  +                ((StandardClassLoader) loader).findRequired();
  +            for (int i = 0; i < extensions.length; i++)
  +                results.add(extensions[i]);
  +        }
  +
  +        // Return the results as an array
  +        Extension extensions[] = new Extension[results.size()];
  +        return ((Extension[]) results.toArray(extensions));
  +
  +    }
  +
  +
  +    /**
        * Return a String array of the restricted class or resource name prefixes
        * for this class loader.  If there are none, a zero-length array
        * is returned.
  @@ -885,9 +976,50 @@
        * Add a repository to our internal array only.
        *
        * @param repository The new repository
  +     *
  +     * @exception IllegalArgumentException if the manifest of a JAR file
  +     *  cannot be processed correctly
        */
       protected void addRepositoryInternal(String repository) {
   
  +        // Validate the manifest of a JAR file repository
  +        if (!repository.endsWith("/")) {
  +            try {
  +                JarFile jarFile = null;
  +                if (repository.startsWith("jar:")) {
  +                    URL url = new URL(repository);
  +                    JarURLConnection conn =
  +                        (JarURLConnection) url.openConnection();
  +                    conn.setAllowUserInteraction(false);
  +                    conn.setDoInput(true);
  +                    conn.setDoOutput(false);
  +                    conn.connect();
  +                    jarFile = conn.getJarFile();
  +                } else if (repository.startsWith("file://")) {
  +                    jarFile = new JarFile(repository.substring(7));
  +                } else if (repository.startsWith("file:")) {
  +                    jarFile = new JarFile(repository.substring(5));
  +                } else {
  +                    throw new IllegalArgumentException
  +                        ("addRepositoryInternal:  Invalid URL '" +
  +                         repository + "'");
  +                }
  +                Manifest manifest = jarFile.getManifest();
  +                Iterator extensions =
  +                    Extension.getAvailable(manifest).iterator();
  +                while (extensions.hasNext())
  +                    available.add(extensions.next());
  +                extensions =
  +                    Extension.getRequired(manifest).iterator();
  +                while (extensions.hasNext())
  +                    required.add(extensions.next());
  +                jarFile.close();
  +            } catch (Throwable t) {
  +                throw new IllegalArgumentException("addRepositoryInternal: " + t);
  +            }
  +        }
  +
  +        // Add this repository to our internal list
   	synchronized (repositories) {
   	    String results[] = new String[repositories.length + 1];
               System.arraycopy(repositories, 0, results, 0, repositories.length);
  
  
  
  1.1                  jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/loader/Extension.java
  
  Index: Extension.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/loader/Extension.java,v 1.1 2000/09/29 20:44:07 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2000/09/29 20:44:07 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */ 
  
  
  package org.apache.catalina.loader;
  
  
  import java.util.ArrayList;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
  import java.util.StringTokenizer;
  import java.util.jar.Attributes;
  import java.util.jar.Manifest;
  
  
  /**
   * Utility class that represents either an available "Optional Package"
   * (formerly known as "Standard Extension") as described in the manifest
   * of a JAR file, or the requirement for such an optional package.  It is
   * used to support the requirements of the Servlet Specification, version
   * 2.3, related to providing shared extensions to all webapps.
   * <p>
   * In addition, static utility methods are available to scan a manifest
   * and return an array of either available or required optional modules
   * documented in that manifest.
   * <p>
   * For more information about optional packages, see the document
   * <em>Optional Package Versioning</em> in the documentation bundle for your
   * Java2 Standard Edition package, in file
   * <code>guide/extensions/versioning.html</code>.
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2000/09/29 20:44:07 $
   */
  
  public final class Extension {
  
  
      // ------------------------------------------------------------- Properties
  
  
      /**
       * The name of the optional package being made available, or required.
       */
      private String extensionName = null;
  
      public String getExtensionName() {
          return (this.extensionName);
      }
  
      public void setExtensionName(String extensionName) {
          this.extensionName = extensionName;
      }
  
  
      /**
       * The URL from which the most recent version of this optional package
       * can be obtained if it is not already installed.
       */
      private String implementationURL = null;
  
      public String getImplementationURL() {
          return (this.implementationURL);
      }
  
      public void setImplementationURL(String implementationURL) {
          this.implementationURL = implementationURL;
      }
  
  
      /**
       * The name of the company or organization that produced this
       * implementation of this optional package.
       */
      private String implementationVendor = null;
  
      public String getImplementationVendor() {
          return (this.implementationVendor);
      }
  
      public void setImplementationVendor(String implementationVendor) {
          this.implementationVendor = implementationVendor;
      }
  
  
      /**
       * The unique identifier of the company that produced the optional
       * package contained in this JAR file.
       */
      private String implementationVendorId = null;
  
      public String getImplementationVendorId() {
          return (this.implementationVendorId);
      }
  
      public void setImplementationVendorId(String implementationVendorId) {
          this.implementationVendorId = implementationVendorId;
      }
  
  
      /**
       * The version number (dotted decimal notation) for this implementation
       * of the optional package.
       */
      private String implementationVersion = null;
  
      public String getImplementationVersion() {
          return (this.implementationVersion);
      }
  
      public void setImplementationVersion(String implementationVersion) {
          this.implementationVersion = implementationVersion;
      }
  
  
      /**
       * The name of the company or organization that originated the
       * specification to which this optional package conforms.
       */
      private String specificationVendor = null;
  
      public String getSpecificationVendor() {
          return (this.specificationVendor);
      }
  
      public void setSpecificationVendor(String specificationVendor) {
          this.specificationVendor = specificationVendor;
      }
  
  
      /**
       * The version number (dotted decimal notation) of the specification
       * to which this optional package conforms.
       */
      private String specificationVersion = null;
  
      public String getSpecificationVersion() {
          return (this.specificationVersion);
      }
  
      public void setSpecificationVersion(String specificationVersion) {
          this.specificationVersion = specificationVersion;
      }
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Return <code>true</code> if the specified <code>Extension</code>
       * (which represents an optional package required by this application)
       * is satisfied by this <code>Extension</code> (which represents an
       * optional package that is already installed.  Otherwise, return
       * <code>false</code>.
       *
       * @param required Description of the required optional package
       */
      public boolean isCompatibleWith(Extension required) {
  
          // Extension Name must match
          if (extensionName == null)
              return (false);
          if (!extensionName.equals(required.getExtensionName()))
              return (false);
  
          // Available specification version must be >= required
          if (!isNewer(specificationVersion, required.getSpecificationVersion()))
              return (false);
  
          // Implementation Vendor ID must match
          if (implementationVendorId == null)
              return (false);
          if (!implementationVendorId.equals(required.getImplementationVendorId()))
              return (false);
  
          // Implementation version must be >= required
          if (!isNewer(implementationVersion, required.getImplementationVersion()))
              return (false);
  
          // This available optional package satisfies the requirements
          return (true);
  
      }
  
  
      /**
       * Return a String representation of this object.
       */
      public String toString() {
  
          StringBuffer sb = new StringBuffer("Extension[");
          sb.append(extensionName);
          if (implementationURL != null) {
              sb.append(", implementationURL=");
              sb.append(implementationURL);
          }
          if (implementationVendor != null) {
              sb.append(", implementationVendor=");
              sb.append(implementationVendor);
          }
          if (implementationVendorId != null) {
              sb.append(", implementationVendorId=");
              sb.append(implementationVendorId);
          }
          if (implementationVersion != null) {
              sb.append(", implementationVersion=");
              sb.append(implementationVersion);
          }
          if (specificationVendor != null) {
              sb.append(", specificationVendor=");
              sb.append(specificationVendor);
          }
          if (specificationVersion != null) {
              sb.append(", specificationVersion=");
              sb.append(specificationVersion);
          }
          sb.append("]");
          return (sb.toString());
  
      }
  
  
      // --------------------------------------------------------- Static Methods
  
  
      /**
       * Return the set of <code>Extension</code> objects representing optional
       * packages that are available in the JAR file associated with the
       * specified <code>Manifest</code>.  If there are no such optional
       * packages, a zero-length list is returned.
       *
       * @param manifest Manifest to be parsed
       */
      public static List getAvailable(Manifest manifest) {
  
          ArrayList results = new ArrayList();
          Extension extension = null;
  
          Attributes attributes = manifest.getMainAttributes();
          if (attributes != null) {
              extension = getAvailable(attributes);
              if (extension != null)
                  results.add(extension);
          }
  
          Map entries = manifest.getEntries();
          Iterator keys = entries.keySet().iterator();
          while (keys.hasNext()) {
              String key = (String) keys.next();
              attributes = (Attributes) entries.get(key);
              extension = getAvailable(attributes);
              if (extension != null)
                  results.add(extension);
          }
  
          return (results);
  
      }
  
  
      /**
       * Return the set of <code>Extension</code> objects representing optional
       * packages that are required by the application contained in the JAR
       * file associated with the specified <code>Manifest</code>.  If there
       * are no such optional packages, a zero-length list is returned.
       *
       * @param manifest Manifest to be parsed
       */
      public static List getRequired(Manifest manifest) {
  
          ArrayList results = new ArrayList();
  
          Attributes attributes = manifest.getMainAttributes();
          if (attributes != null) {
              Iterator required = getRequired(attributes).iterator();
              while (required.hasNext())
                  results.add(required.next());
          }
  
          Map entries = manifest.getEntries();
          Iterator keys = entries.keySet().iterator();
          while (keys.hasNext()) {
              String key = (String) keys.next();
              attributes = (Attributes) entries.get(key);
              Iterator required = getRequired(attributes).iterator();
              while (required.hasNext())
                  results.add(required.next());
          }
  
          return (results);
  
      }
  
  
      // -------------------------------------------------------- Private Methods
  
  
      /**
       * If the specified manifest attributes entry represents an available
       * optional package, construct and return an <code>Extension</code>
       * instance representing this package; otherwise return <code>null</code>.
       *
       * @param attributes Manifest attributes to be parsed
       */
      private static Extension getAvailable(Attributes attributes) {
  
          String name = attributes.getValue("Extension-Name");
          if (name == null)
              return (null);
          Extension extension = new Extension();
          extension.setExtensionName(name);
  
          extension.setImplementationVendor
              (attributes.getValue("Implementation-Vendor"));
          extension.setImplementationVendorId
              (attributes.getValue("Implementation-Vendor-Id"));
          extension.setImplementationVersion
              (attributes.getValue("Implementation-Version"));
          extension.setSpecificationVendor
              (attributes.getValue("Specification-Vendor"));
          extension.setSpecificationVersion
              (attributes.getValue("Specification-Version"));
  
          return (extension);
  
      }
  
  
      /**
       * Return the set of required optional packages defined in the specified
       * attributes entry, if any.  If no such optional packages are found,
       * a zero-length list is returned.
       *
       * @param attributes Attributes to be parsed
       */
      private static List getRequired(Attributes attributes) {
  
          ArrayList results = new ArrayList();
          String names = attributes.getValue("Extension-List");
          if (names == null)
              return (results);
          names += " ";
  
          while (true) {
  
              int space = names.indexOf(" ");
              if (space < 0)
                  break;
              String name = names.substring(0, space).trim();
              names = names.substring(space + 1);
  
              String value =
                  attributes.getValue(name + "-Extension-Name");
              if (value == null)
                  continue;
              Extension extension = new Extension();
              extension.setExtensionName(value);
  
              extension.setImplementationURL
                  (attributes.getValue(name + "-Implementation-URL"));
              extension.setImplementationVendorId
                  (attributes.getValue(name + "-Implementation-Vendor-Id"));
              extension.setImplementationVersion
                  (attributes.getValue(name + "-Implementation-Version"));
              extension.setSpecificationVersion
                  (attributes.getValue(name + "-Specification-Version"));
  
              results.add(extension);
  
          }
  
          return (results);
  
      }
  
  
      /**
       * Return <code>true</code> if the first version number is greater than
       * or equal to the second; otherwise return <code>false</code>.
       *
       * @param first First version number (dotted decimal)
       * @param second Second version number (dotted decimal)
       *
       * @exception NumberFormatException on a malformed version number
       */
      private boolean isNewer(String first, String second)
          throws NumberFormatException {
  
          if ((first == null) || (second == null))
              return (false);
          if (first.equals(second))
              return (true);
  
          StringTokenizer fTok = new StringTokenizer(first, ".", true);
          StringTokenizer sTok = new StringTokenizer(second, ".", true);
          int fVersion = 0;
          int sVersion = 0;
          while (fTok.hasMoreTokens() || sTok.hasMoreTokens()) {
              if (fTok.hasMoreTokens())
                  fVersion = Integer.parseInt(fTok.nextToken());
              else
                  fVersion = 0;
              if (sTok.hasMoreTokens())
                  sVersion = Integer.parseInt(sTok.nextToken());
              else
                  sVersion = 0;
              if (fVersion < sVersion)
                  return (false);
              else if (fVersion > sVersion)
                  return (true);
              if (fTok.hasMoreTokens())   // Swallow the periods
                  fTok.nextToken();
              if (sTok.hasMoreTokens())
                  sTok.nextToken();
          }
  
          return (true);  // Exact match
  
      }
  
  
  }
  
  
  
  1.4       +130 -40   jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/startup/Bootstrap.java
  
  Index: Bootstrap.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/startup/Bootstrap.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- Bootstrap.java	2000/09/22 23:52:52	1.3
  +++ Bootstrap.java	2000/09/29 20:44:07	1.4
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/startup/Bootstrap.java,v 1.3 2000/09/22 23:52:52 craigmcc Exp $
  - * $Revision: 1.3 $
  - * $Date: 2000/09/22 23:52:52 $
  + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/startup/Bootstrap.java,v 1.4 2000/09/29 20:44:07 craigmcc Exp $
  + * $Revision: 1.4 $
  + * $Date: 2000/09/29 20:44:07 $
    *
    * ====================================================================
    *
  @@ -70,6 +70,7 @@
   import java.net.MalformedURLException;
   import java.net.URL;
   import java.util.ArrayList;
  +import org.apache.catalina.loader.Extension;
   import org.apache.catalina.loader.StandardClassLoader;
   
   
  @@ -83,7 +84,7 @@
    * class path and therefore not visible to application level classes.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.3 $ $Date: 2000/09/22 23:52:52 $
  + * @version $Revision: 1.4 $ $Date: 2000/09/29 20:44:07 $
    */
   
   public final class Bootstrap {
  @@ -99,31 +100,86 @@
        */
       public static void main(String args[]) {
   
  -        // Construct the "class path" for a new class loader
  -        ArrayList list = new ArrayList();
  +        // Construct the class loaders we will need
  +        ClassLoader catalinaLoader = createCatalinaLoader();
  +        ClassLoader sharedLoader = createSharedLoader();
   
  -	// Add the "classes" subdirectory underneath "catalina.home"
  -	File classes = new File(System.getProperty("catalina.home"),
  -				"classes");
  -	if (classes.exists() && classes.canRead() &&
  -	    classes.isDirectory()) {
  -	    list.add(classes.getAbsolutePath() + "/");
  -	}
  +	// Load our startup class and call its process() method
  +	try {
  +
  +	    Class startupClass =
  +		catalinaLoader.loadClass
  +                ("org.apache.catalina.startup.Catalina");
  +	    Object startupInstance = startupClass.newInstance();
  +
  +            // Set the shared extensions class loader
  +            String methodName = "setSharedLoader";
  +            Class paramTypes[] = new Class[1];
  +            paramTypes[0] = Class.forName("java.lang.ClassLoader");
  +            Object paramValues[] = new Object[1];
  +            paramValues[0] = sharedLoader;
  +            Method method =
  +                startupInstance.getClass().getMethod(methodName, paramTypes);
  +            method.invoke(startupInstance, paramValues);
  +
  +            // Call the process() method
  +	    methodName = "process";
  +	    paramTypes = new Class[1];
  +	    paramTypes[0] = args.getClass();
  +	    paramValues = new Object[1];
  +	    paramValues[0] = args;
  +	    method =
  +		startupInstance.getClass().getMethod(methodName, paramTypes);
  +	    method.invoke(startupInstance, paramValues);
   
  -	// Add the JAR files in the "server" subdirectory as well
  -	File directory = new File(System.getProperty("catalina.home"),
  -				  "server");
  -	if (!directory.exists() || !directory.canRead() ||
  -	    !directory.isDirectory()) {
  -	    System.out.println("No 'server' directory to be processed");
  -	    System.exit(1);
  +	} catch (Exception e) {
  +	    System.out.println("Exception during startup processing");
  +	    e.printStackTrace(System.out);
  +	    System.exit(2);
   	}
  +
  +	System.exit(0);
  +
  +    }
  +
  +
  +    /**
  +     * Construct and return the class loader to be used for loading
  +     * Catalina internal classes.
  +     */
  +    private static ClassLoader createCatalinaLoader() {
  +
  +        // Construct the "class path" for this class loader
  +        ArrayList list = new ArrayList();
  +
  +        File classes = new File(System.getProperty("catalina.home"),
  +                                "classes");
  +        if (classes.exists() && classes.canRead() &&
  +            classes.isDirectory()) {
  +            try {
  +                URL url = new URL("file", null,
  +                                  classes.getAbsolutePath() + "/");
  +                list.add(url.toString());
  +            } catch (MalformedURLException e) {
  +                System.out.println("Cannot create URL for " +
  +                                   classes.getAbsolutePath());
  +                System.exit(1);
  +            }
  +        }
  +
  +        File directory = new File(System.getProperty("catalina.home"),
  +                                  "server");
  +        if (!directory.exists() || !directory.canRead() ||
  +            !directory.isDirectory()) {
  +            System.out.println("Directory " + directory.getAbsolutePath()
  +                               + " does not exist");
  +            System.exit(1);
  +        }
   	String filenames[] = directory.list();
   	for (int i = 0; i < filenames.length; i++) {
   	    if (!filenames[i].toLowerCase().endsWith(".jar"))
   		continue;
               File file = new File(directory, filenames[i]);
  -            //	    loader.addRepository(file.getAbsolutePath());
               try {
                   URL url = new URL("file", null, file.getAbsolutePath());
                   list.add(url.toString());
  @@ -136,28 +192,62 @@
   
           // Construct the class loader itself
           String array[] = (String[]) list.toArray(new String[list.size()]);
  -	StandardClassLoader loader = new StandardClassLoader(array);
  +        StandardClassLoader loader = new StandardClassLoader(array);
   
  -	// Load our startup class and call its process() method
  -	try {
  -	    Class startupClass =
  -		loader.loadClass("org.apache.catalina.startup.Catalina");
  -	    Object startupInstance = startupClass.newInstance();
  -	    String methodName = "process";
  -	    Class paramTypes[] = new Class[1];
  -	    paramTypes[0] = args.getClass();
  -	    Object paramValues[] = new Object[1];
  -	    paramValues[0] = args;
  -	    Method method =
  -		startupInstance.getClass().getMethod(methodName, paramTypes);
  -	    method.invoke(startupInstance, paramValues);
  -	} catch (Exception e) {
  -	    System.out.println("Exception during startup processing");
  -	    e.printStackTrace(System.out);
  -	    System.exit(2);
  +        return (loader);
  +
  +    }
  +
  +
  +    /**
  +     * Construct and return the class loader to be used for shared
  +     * extensions by web applications loaded with Catalina.
  +     */
  +    private static ClassLoader createSharedLoader() {
  +
  +        // Construct the "class path" for this class loader
  +        ArrayList list = new ArrayList();
  +
  +        File directory = new File(System.getProperty("catalina.home"),
  +                                  "lib");
  +        if (!directory.exists() || !directory.canRead() ||
  +            !directory.isDirectory()) {
  +            System.out.println("Directory " + directory.getAbsolutePath()
  +                               + " does not exist");
  +            System.exit(1);
  +        }
  +	String filenames[] = directory.list();
  +	for (int i = 0; i < filenames.length; i++) {
  +	    if (!filenames[i].toLowerCase().endsWith(".jar"))
  +		continue;
  +            File file = new File(directory, filenames[i]);
  +            try {
  +                URL url = new URL("file", null, file.getAbsolutePath());
  +                list.add(url.toString());
  +            } catch (MalformedURLException e) {
  +                System.out.println("Cannot create URL for " +
  +                                   filenames[i]);
  +                System.exit(1);
  +            }
   	}
   
  -	System.exit(0);
  +        // Construct the class loader itself
  +        String array[] = (String[]) list.toArray(new String[list.size()]);
  +        StandardClassLoader loader = new StandardClassLoader(array);
  +
  +        /*
  +        System.out.println("AVAILABLE OPTIONAL PACKAGES:");
  +        Extension available[] = loader.findAvailable();
  +        for (int i = 0; i < available.length; i++)
  +            System.out.println(available[i].toString());
  +        System.out.println("REQUIRED OPTIONAL PACKAGES:");
  +        Extension required[] = loader.findRequired();
  +        for (int i = 0; i < required.length; i++)
  +            System.out.println(required[i].toString());
  +        System.out.println("===========================");
  +        */
  +
  +        return (loader);
   
       }
   
  
  
  
  1.5       +22 -4     jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/startup/Catalina.java
  
  Index: Catalina.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/startup/Catalina.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- Catalina.java	2000/09/24 02:53:00	1.4
  +++ Catalina.java	2000/09/29 20:44:07	1.5
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/startup/Catalina.java,v 1.4 2000/09/24 02:53:00 craigmcc Exp $
  - * $Revision: 1.4 $
  - * $Date: 2000/09/24 02:53:00 $
  + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/startup/Catalina.java,v 1.5 2000/09/29 20:44:07 craigmcc Exp $
  + * $Revision: 1.5 $
  + * $Date: 2000/09/29 20:44:07 $
    *
    * ====================================================================
    *
  @@ -94,7 +94,7 @@
    * </u>
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.4 $ $Date: 2000/09/24 02:53:00 $
  + * @version $Revision: 1.5 $ $Date: 2000/09/29 20:44:07 $
    */
   
   public class Catalina {
  @@ -122,6 +122,12 @@
   
   
       /**
  +     * The shared extensions class loader for this server.
  +     */
  +    protected ClassLoader sharedLoader = ClassLoader.getSystemClassLoader();
  +
  +
  +    /**
        * Are we starting a new server?
        */
       protected boolean starting = false;
  @@ -176,6 +182,18 @@
       public void setServer(Server server) {
   
           this.server = server;
  +
  +    }
  +
  +
  +    /**
  +     * Set the shared extensions class loader.
  +     *
  +     * @param sharedLoader The shared extensions class loader.
  +     */
  +    public void setSharedLoader(ClassLoader sharedLoader) {
  +
  +        this.sharedLoader = sharedLoader;
   
       }