- Improve the algorithm used when constructing classloaders, in particular to respect...
authorremm <remm@13f79535-47bb-0310-9956-ffa450edef68>
Wed, 12 Apr 2006 10:54:41 +0000 (10:54 +0000)
committerremm <remm@13f79535-47bb-0310-9956-ffa450edef68>
Wed, 12 Apr 2006 10:54:41 +0000 (10:54 +0000)
- Submitted by Rainer Jung.

git-svn-id: https://svn.apache.org/repos/asf/tomcat/tc6.0.x/trunk@393433 13f79535-47bb-0310-9956-ffa450edef68

java/org/apache/catalina/startup/Bootstrap.java
java/org/apache/catalina/startup/ClassLoaderFactory.java

index e1272a1..fa7f817 100644 (file)
-/*\r
- * Copyright 1999,2004 The Apache Software Foundation.\r
- * \r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- * \r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-\r
-package org.apache.catalina.startup;\r
-\r
-\r
-import java.io.File;\r
-import java.lang.reflect.Method;\r
-import java.net.MalformedURLException;\r
-import java.net.URL;\r
-import java.util.ArrayList;\r
-import java.util.StringTokenizer;\r
-\r
-import javax.management.MBeanServer;\r
-import javax.management.MBeanServerFactory;\r
-import javax.management.ObjectName;\r
-\r
-import org.apache.catalina.security.SecurityClassLoad;\r
-import org.apache.commons.logging.Log;\r
-import org.apache.commons.logging.LogFactory;\r
-\r
-\r
-/**\r
- * Boostrap loader for Catalina.  This application constructs a class loader\r
- * for use in loading the Catalina internal classes (by accumulating all of the\r
- * JAR files found in the "server" directory under "catalina.home"), and\r
- * starts the regular execution of the container.  The purpose of this\r
- * roundabout approach is to keep the Catalina internal classes (and any\r
- * other classes they depend on, such as an XML parser) out of the system\r
- * class path and therefore not visible to application level classes.\r
- *\r
- * @author Craig R. McClanahan\r
- * @author Remy Maucherat\r
- * @version $Revision: 304108 $ $Date: 2005-09-29 07:55:15 +0200 (jeu., 29 sept. 2005) $\r
- */\r
-\r
-public final class Bootstrap {\r
-\r
-    private static Log log = LogFactory.getLog(Bootstrap.class);\r
-    \r
-    // -------------------------------------------------------------- Constants\r
-\r
-\r
-    protected static final String CATALINA_HOME_TOKEN = "${catalina.home}";\r
-    protected static final String CATALINA_BASE_TOKEN = "${catalina.base}";\r
-\r
-\r
-    // ------------------------------------------------------- Static Variables\r
-\r
-\r
-    private static final String JMX_ERROR_MESSAGE =\r
-        "This release of Apache Tomcat was packaged to run on J2SE 5.0 \n"\r
-        + "or later. It can be run on earlier JVMs by downloading and \n"\r
-        + "installing a compatibility package from the Apache Tomcat \n"\r
-        + "binary download page.";\r
-\r
-\r
-    /**\r
-     * Daemon object used by main.\r
-     */\r
-    private static Bootstrap daemon = null;\r
-\r
-\r
-    // -------------------------------------------------------------- Variables\r
-\r
-\r
-    /**\r
-     * Daemon reference.\r
-     */\r
-    private Object catalinaDaemon = null;\r
-\r
-\r
-    protected ClassLoader commonLoader = null;\r
-    protected ClassLoader catalinaLoader = null;\r
-    protected ClassLoader sharedLoader = null;\r
-\r
-\r
-    // -------------------------------------------------------- Private Methods\r
-\r
-\r
-    private void initClassLoaders() {\r
-        try {\r
-            commonLoader = createClassLoader("common", null);\r
-            if( commonLoader == null ) {\r
-                // no config file, default to this loader - we might be in a 'single' env.\r
-                commonLoader=this.getClass().getClassLoader();\r
-            }\r
-            catalinaLoader = createClassLoader("server", commonLoader);\r
-            sharedLoader = createClassLoader("shared", commonLoader);\r
-        } catch (Throwable t) {\r
-            log.error("Class loader creation threw exception", t);\r
-            System.exit(1);\r
-        }\r
-    }\r
-\r
-\r
-    private ClassLoader createClassLoader(String name, ClassLoader parent)\r
-        throws Exception {\r
-\r
-        String value = CatalinaProperties.getProperty(name + ".loader");\r
-        if ((value == null) || (value.equals("")))\r
-            return parent;\r
-\r
-        ArrayList unpackedList = new ArrayList();\r
-        ArrayList packedList = new ArrayList();\r
-        ArrayList urlList = new ArrayList();\r
-\r
-        StringTokenizer tokenizer = new StringTokenizer(value, ",");\r
-        while (tokenizer.hasMoreElements()) {\r
-            String repository = tokenizer.nextToken();\r
-\r
-            // Local repository\r
-            boolean packed = false;\r
-            if (repository.startsWith(CATALINA_HOME_TOKEN)) {\r
-                repository = getCatalinaHome()\r
-                    + repository.substring(CATALINA_HOME_TOKEN.length());\r
-            } else if (repository.startsWith(CATALINA_BASE_TOKEN)) {\r
-                repository = getCatalinaBase()\r
-                    + repository.substring(CATALINA_BASE_TOKEN.length());\r
-            }\r
-\r
-            // Check for a JAR URL repository\r
-            try {\r
-                urlList.add(new URL(repository));\r
-                continue;\r
-            } catch (MalformedURLException e) {\r
-                // Ignore\r
-            }\r
-\r
-            if (repository.endsWith("*.jar")) {\r
-                packed = true;\r
-                repository = repository.substring\r
-                    (0, repository.length() - "*.jar".length());\r
-            }\r
-            if (packed) {\r
-                packedList.add(new File(repository));\r
-            } else {\r
-                unpackedList.add(new File(repository));\r
-            }\r
-        }\r
-\r
-        File[] unpacked = (File[]) unpackedList.toArray(new File[0]);\r
-        File[] packed = (File[]) packedList.toArray(new File[0]);\r
-        URL[] urls = (URL[]) urlList.toArray(new URL[0]);\r
-\r
-        ClassLoader classLoader = ClassLoaderFactory.createClassLoader\r
-            (unpacked, packed, urls, parent);\r
-\r
-        // Retrieving MBean server\r
-        MBeanServer mBeanServer = null;\r
-        if (MBeanServerFactory.findMBeanServer(null).size() > 0) {\r
-            mBeanServer =\r
-                (MBeanServer) MBeanServerFactory.findMBeanServer(null).get(0);\r
-        } else {\r
-            mBeanServer = MBeanServerFactory.createMBeanServer();\r
-        }\r
-\r
-        // Register the server classloader\r
-        ObjectName objectName =\r
-            new ObjectName("Catalina:type=ServerClassLoader,name=" + name);\r
-        mBeanServer.registerMBean(classLoader, objectName);\r
-\r
-        return classLoader;\r
-\r
-    }\r
-\r
-\r
-    /**\r
-     * Initialize daemon.\r
-     */\r
-    public void init()\r
-        throws Exception\r
-    {\r
-\r
-        // Set Catalina path\r
-        setCatalinaHome();\r
-        setCatalinaBase();\r
-\r
-        initClassLoaders();\r
-\r
-        Thread.currentThread().setContextClassLoader(catalinaLoader);\r
-\r
-        SecurityClassLoad.securityClassLoad(catalinaLoader);\r
-\r
-        // Load our startup class and call its process() method\r
-        if (log.isDebugEnabled())\r
-            log.debug("Loading startup class");\r
-        Class startupClass =\r
-            catalinaLoader.loadClass\r
-            ("org.apache.catalina.startup.Catalina");\r
-        Object startupInstance = startupClass.newInstance();\r
-\r
-        // Set the shared extensions class loader\r
-        if (log.isDebugEnabled())\r
-            log.debug("Setting startup class properties");\r
-        String methodName = "setParentClassLoader";\r
-        Class paramTypes[] = new Class[1];\r
-        paramTypes[0] = Class.forName("java.lang.ClassLoader");\r
-        Object paramValues[] = new Object[1];\r
-        paramValues[0] = sharedLoader;\r
-        Method method =\r
-            startupInstance.getClass().getMethod(methodName, paramTypes);\r
-        method.invoke(startupInstance, paramValues);\r
-\r
-        catalinaDaemon = startupInstance;\r
-\r
-    }\r
-\r
-\r
-    /**\r
-     * Load daemon.\r
-     */\r
-    private void load(String[] arguments)\r
-        throws Exception {\r
-\r
-        // Call the load() method\r
-        String methodName = "load";\r
-        Object param[];\r
-        Class paramTypes[];\r
-        if (arguments==null || arguments.length==0) {\r
-            paramTypes = null;\r
-            param = null;\r
-        } else {\r
-            paramTypes = new Class[1];\r
-            paramTypes[0] = arguments.getClass();\r
-            param = new Object[1];\r
-            param[0] = arguments;\r
-        }\r
-        Method method = \r
-            catalinaDaemon.getClass().getMethod(methodName, paramTypes);\r
-        if (log.isDebugEnabled())\r
-            log.debug("Calling startup class " + method);\r
-        method.invoke(catalinaDaemon, param);\r
-\r
-    }\r
-\r
-\r
-    // ----------------------------------------------------------- Main Program\r
-\r
-\r
-    /**\r
-     * Load the Catalina daemon.\r
-     */\r
-    public void init(String[] arguments)\r
-        throws Exception {\r
-\r
-        init();\r
-        load(arguments);\r
-\r
-    }\r
-\r
-\r
-    /**\r
-     * Start the Catalina daemon.\r
-     */\r
-    public void start()\r
-        throws Exception {\r
-        if( catalinaDaemon==null ) init();\r
-\r
-        Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);\r
-        method.invoke(catalinaDaemon, (Object [])null);\r
-\r
-    }\r
-\r
-\r
-    /**\r
-     * Stop the Catalina Daemon.\r
-     */\r
-    public void stop()\r
-        throws Exception {\r
-\r
-        Method method = catalinaDaemon.getClass().getMethod("stop", (Class [] ) null);\r
-        method.invoke(catalinaDaemon, (Object [] ) null);\r
-\r
-    }\r
-\r
-\r
-    /**\r
-     * Stop the standlone server.\r
-     */\r
-    public void stopServer()\r
-        throws Exception {\r
-\r
-        Method method = \r
-            catalinaDaemon.getClass().getMethod("stopServer", (Class []) null);\r
-        method.invoke(catalinaDaemon, (Object []) null);\r
-\r
-    }\r
-\r
-\r
-   /**\r
-     * Stop the standlone server.\r
-     */\r
-    public void stopServer(String[] arguments)\r
-        throws Exception {\r
-\r
-        Object param[];\r
-        Class paramTypes[];\r
-        if (arguments==null || arguments.length==0) {\r
-            paramTypes = null;\r
-            param = null;\r
-        } else {\r
-            paramTypes = new Class[1];\r
-            paramTypes[0] = arguments.getClass();\r
-            param = new Object[1];\r
-            param[0] = arguments;\r
-        }\r
-        Method method = \r
-            catalinaDaemon.getClass().getMethod("stopServer", paramTypes);\r
-        method.invoke(catalinaDaemon, param);\r
-\r
-    }\r
-\r
-\r
-    /**\r
-     * Set flag.\r
-     */\r
-    public void setAwait(boolean await)\r
-        throws Exception {\r
-\r
-        Class paramTypes[] = new Class[1];\r
-        paramTypes[0] = Boolean.TYPE;\r
-        Object paramValues[] = new Object[1];\r
-        paramValues[0] = new Boolean(await);\r
-        Method method = \r
-            catalinaDaemon.getClass().getMethod("setAwait", paramTypes);\r
-        method.invoke(catalinaDaemon, paramValues);\r
-\r
-    }\r
-\r
-    public boolean getAwait()\r
-        throws Exception\r
-    {\r
-        Class paramTypes[] = new Class[0];\r
-        Object paramValues[] = new Object[0];\r
-        Method method =\r
-            catalinaDaemon.getClass().getMethod("getAwait", paramTypes);\r
-        Boolean b=(Boolean)method.invoke(catalinaDaemon, paramValues);\r
-        return b.booleanValue();\r
-    }\r
-\r
-\r
-    /**\r
-     * Destroy the Catalina Daemon.\r
-     */\r
-    public void destroy() {\r
-\r
-        // FIXME\r
-\r
-    }\r
-\r
-\r
-    /**\r
-     * Main method, used for testing only.\r
-     *\r
-     * @param args Command line arguments to be processed\r
-     */\r
-    public static void main(String args[]) {\r
-\r
-        try {\r
-            // Attempt to load JMX class\r
-            new ObjectName("test:foo=bar");\r
-        } catch (Throwable t) {\r
-            System.out.println(JMX_ERROR_MESSAGE);\r
-            try {\r
-                // Give users some time to read the message before exiting\r
-                Thread.sleep(5000);\r
-            } catch (Exception ex) {\r
-            }\r
-            return;\r
-        }\r
-\r
-        if (daemon == null) {\r
-            daemon = new Bootstrap();\r
-            try {\r
-                daemon.init();\r
-            } catch (Throwable t) {\r
-                t.printStackTrace();\r
-                return;\r
-            }\r
-        }\r
-\r
-        try {\r
-            String command = "start";\r
-            if (args.length > 0) {\r
-                command = args[args.length - 1];\r
-            }\r
-\r
-            if (command.equals("startd")) {\r
-                args[0] = "start";\r
-                daemon.load(args);\r
-                daemon.start();\r
-            } else if (command.equals("stopd")) {\r
-                args[0] = "stop";\r
-                daemon.stop();\r
-            } else if (command.equals("start")) {\r
-                daemon.setAwait(true);\r
-                daemon.load(args);\r
-                daemon.start();\r
-            } else if (command.equals("stop")) {\r
-                daemon.stopServer(args);\r
-            } else {\r
-                log.warn("Bootsrap: command \"" + command + "\" does not exist.");\r
-            }\r
-        } catch (Throwable t) {\r
-            t.printStackTrace();\r
-        }\r
-\r
-    }\r
-\r
-    public void setCatalinaHome(String s) {\r
-        System.setProperty( "catalina.home", s );\r
-    }\r
-\r
-    public void setCatalinaBase(String s) {\r
-        System.setProperty( "catalina.base", s );\r
-    }\r
-\r
-\r
-    /**\r
-     * Set the <code>catalina.base</code> System property to the current\r
-     * working directory if it has not been set.\r
-     */\r
-    private void setCatalinaBase() {\r
-\r
-        if (System.getProperty("catalina.base") != null)\r
-            return;\r
-        if (System.getProperty("catalina.home") != null)\r
-            System.setProperty("catalina.base",\r
-                               System.getProperty("catalina.home"));\r
-        else\r
-            System.setProperty("catalina.base",\r
-                               System.getProperty("user.dir"));\r
-\r
-    }\r
-\r
-\r
-    /**\r
-     * Set the <code>catalina.home</code> System property to the current\r
-     * working directory if it has not been set.\r
-     */\r
-    private void setCatalinaHome() {\r
-\r
-        if (System.getProperty("catalina.home") != null)\r
-            return;\r
-        File bootstrapJar = \r
-            new File(System.getProperty("user.dir"), "bootstrap.jar");\r
-        if (bootstrapJar.exists()) {\r
-            try {\r
-                System.setProperty\r
-                    ("catalina.home", \r
-                     (new File(System.getProperty("user.dir"), ".."))\r
-                     .getCanonicalPath());\r
-            } catch (Exception e) {\r
-                // Ignore\r
-                System.setProperty("catalina.home",\r
-                                   System.getProperty("user.dir"));\r
-            }\r
-        } else {\r
-            System.setProperty("catalina.home",\r
-                               System.getProperty("user.dir"));\r
-        }\r
-\r
-    }\r
-\r
-\r
-    /**\r
-     * Get the value of the catalina.home environment variable.\r
-     */\r
-    public static String getCatalinaHome() {\r
-        return System.getProperty("catalina.home",\r
-                                  System.getProperty("user.dir"));\r
-    }\r
-\r
-\r
-    /**\r
-     * Get the value of the catalina.base environment variable.\r
-     */\r
-    public static String getCatalinaBase() {\r
-        return System.getProperty("catalina.base", getCatalinaHome());\r
-    }\r
-\r
-\r
-}\r
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.catalina.startup;
+
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.ObjectName;
+
+import org.apache.catalina.security.SecurityClassLoad;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * Boostrap loader for Catalina.  This application constructs a class loader
+ * for use in loading the Catalina internal classes (by accumulating all of the
+ * JAR files found in the "server" directory under "catalina.home"), and
+ * starts the regular execution of the container.  The purpose of this
+ * roundabout approach is to keep the Catalina internal classes (and any
+ * other classes they depend on, such as an XML parser) out of the system
+ * class path and therefore not visible to application level classes.
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @version $Revision: 304108 $ $Date: 2005-09-29 07:55:15 +0200 (jeu., 29 sept. 2005) $
+ */
+
+public final class Bootstrap {
+
+    private static Log log = LogFactory.getLog(Bootstrap.class);
+    
+    // -------------------------------------------------------------- Constants
+
+
+    protected static final String CATALINA_HOME_TOKEN = "${catalina.home}";
+    protected static final String CATALINA_BASE_TOKEN = "${catalina.base}";
+
+
+    // ------------------------------------------------------- Static Variables
+
+
+    private static final String JMX_ERROR_MESSAGE =
+        "This release of Apache Tomcat was packaged to run on J2SE 5.0 \n"
+        + "or later. It can be run on earlier JVMs by downloading and \n"
+        + "installing a compatibility package from the Apache Tomcat \n"
+        + "binary download page.";
+
+
+    /**
+     * Daemon object used by main.
+     */
+    private static Bootstrap daemon = null;
+
+
+    // -------------------------------------------------------------- Variables
+
+
+    /**
+     * Daemon reference.
+     */
+    private Object catalinaDaemon = null;
+
+
+    protected ClassLoader commonLoader = null;
+    protected ClassLoader catalinaLoader = null;
+    protected ClassLoader sharedLoader = null;
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    private void initClassLoaders() {
+        try {
+            commonLoader = createClassLoader("common", null);
+            if( commonLoader == null ) {
+                // no config file, default to this loader - we might be in a 'single' env.
+                commonLoader=this.getClass().getClassLoader();
+            }
+            catalinaLoader = createClassLoader("server", commonLoader);
+            sharedLoader = createClassLoader("shared", commonLoader);
+        } catch (Throwable t) {
+            log.error("Class loader creation threw exception", t);
+            System.exit(1);
+        }
+    }
+
+
+    private ClassLoader createClassLoader(String name, ClassLoader parent)
+        throws Exception {
+
+        String value = CatalinaProperties.getProperty(name + ".loader");
+        if ((value == null) || (value.equals("")))
+            return parent;
+
+        ArrayList repositoryLocations = new ArrayList();
+        ArrayList repositoryTypes = new ArrayList();
+        int i;
+        StringTokenizer tokenizer = new StringTokenizer(value, ",");
+        while (tokenizer.hasMoreElements()) {
+            String repository = tokenizer.nextToken();
+
+            // Local repository
+            boolean replace = false;
+            String before = repository;
+            while ((i=repository.indexOf(CATALINA_HOME_TOKEN))>=0) {
+                replace=true;
+                if (i>0) {
+                repository = repository.substring(0,i) + getCatalinaHome() 
+                    + repository.substring(i+CATALINA_HOME_TOKEN.length());
+                } else {
+                    repository = getCatalinaHome() 
+                        + repository.substring(CATALINA_HOME_TOKEN.length());
+                }
+            }
+            while ((i=repository.indexOf(CATALINA_BASE_TOKEN))>=0) {
+                replace=true;
+                if (i>0) {
+                repository = repository.substring(0,i) + getCatalinaBase() 
+                    + repository.substring(i+CATALINA_BASE_TOKEN.length());
+                } else {
+                    repository = getCatalinaBase() 
+                        + repository.substring(CATALINA_BASE_TOKEN.length());
+                }
+            }
+            if (replace && log.isDebugEnabled())
+                log.debug("Expanded " + before + " to " + replace);
+
+            // Check for a JAR URL repository
+            try {
+                URL url=new URL(repository);
+                repositoryLocations.add(repository);
+                repositoryTypes.add(ClassLoaderFactory.IS_URL);
+                continue;
+            } catch (MalformedURLException e) {
+                // Ignore
+            }
+
+            if (repository.endsWith("*.jar")) {
+                repository = repository.substring
+                    (0, repository.length() - "*.jar".length());
+                repositoryLocations.add(repository);
+                repositoryTypes.add(ClassLoaderFactory.IS_GLOB);
+            } else if (repository.endsWith(".jar")) {
+                repositoryLocations.add(repository);
+                repositoryTypes.add(ClassLoaderFactory.IS_JAR);
+            } else {
+                repositoryLocations.add(repository);
+                repositoryTypes.add(ClassLoaderFactory.IS_DIR);
+            }
+        }
+
+        String[] locations = (String[]) repositoryLocations.toArray(new String[0]);
+        Integer[] types = (Integer[]) repositoryTypes.toArray(new Integer[0]);
+        ClassLoader classLoader = ClassLoaderFactory.createClassLoader
+            (locations, types, parent);
+
+        // Retrieving MBean server
+        MBeanServer mBeanServer = null;
+        if (MBeanServerFactory.findMBeanServer(null).size() > 0) {
+            mBeanServer =
+                (MBeanServer) MBeanServerFactory.findMBeanServer(null).get(0);
+        } else {
+            mBeanServer = MBeanServerFactory.createMBeanServer();
+        }
+
+        // Register the server classloader
+        ObjectName objectName =
+            new ObjectName("Catalina:type=ServerClassLoader,name=" + name);
+        mBeanServer.registerMBean(classLoader, objectName);
+
+        return classLoader;
+
+    }
+
+
+    /**
+     * Initialize daemon.
+     */
+    public void init()
+        throws Exception
+    {
+
+        // Set Catalina path
+        setCatalinaHome();
+        setCatalinaBase();
+
+        initClassLoaders();
+
+        Thread.currentThread().setContextClassLoader(catalinaLoader);
+
+        SecurityClassLoad.securityClassLoad(catalinaLoader);
+
+        // Load our startup class and call its process() method
+        if (log.isDebugEnabled())
+            log.debug("Loading startup class");
+        Class startupClass =
+            catalinaLoader.loadClass
+            ("org.apache.catalina.startup.Catalina");
+        Object startupInstance = startupClass.newInstance();
+
+        // Set the shared extensions class loader
+        if (log.isDebugEnabled())
+            log.debug("Setting startup class properties");
+        String methodName = "setParentClassLoader";
+        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);
+
+        catalinaDaemon = startupInstance;
+
+    }
+
+
+    /**
+     * Load daemon.
+     */
+    private void load(String[] arguments)
+        throws Exception {
+
+        // Call the load() method
+        String methodName = "load";
+        Object param[];
+        Class paramTypes[];
+        if (arguments==null || arguments.length==0) {
+            paramTypes = null;
+            param = null;
+        } else {
+            paramTypes = new Class[1];
+            paramTypes[0] = arguments.getClass();
+            param = new Object[1];
+            param[0] = arguments;
+        }
+        Method method = 
+            catalinaDaemon.getClass().getMethod(methodName, paramTypes);
+        if (log.isDebugEnabled())
+            log.debug("Calling startup class " + method);
+        method.invoke(catalinaDaemon, param);
+
+    }
+
+
+    // ----------------------------------------------------------- Main Program
+
+
+    /**
+     * Load the Catalina daemon.
+     */
+    public void init(String[] arguments)
+        throws Exception {
+
+        init();
+        load(arguments);
+
+    }
+
+
+    /**
+     * Start the Catalina daemon.
+     */
+    public void start()
+        throws Exception {
+        if( catalinaDaemon==null ) init();
+
+        Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
+        method.invoke(catalinaDaemon, (Object [])null);
+
+    }
+
+
+    /**
+     * Stop the Catalina Daemon.
+     */
+    public void stop()
+        throws Exception {
+
+        Method method = catalinaDaemon.getClass().getMethod("stop", (Class [] ) null);
+        method.invoke(catalinaDaemon, (Object [] ) null);
+
+    }
+
+
+    /**
+     * Stop the standlone server.
+     */
+    public void stopServer()
+        throws Exception {
+
+        Method method = 
+            catalinaDaemon.getClass().getMethod("stopServer", (Class []) null);
+        method.invoke(catalinaDaemon, (Object []) null);
+
+    }
+
+
+   /**
+     * Stop the standlone server.
+     */
+    public void stopServer(String[] arguments)
+        throws Exception {
+
+        Object param[];
+        Class paramTypes[];
+        if (arguments==null || arguments.length==0) {
+            paramTypes = null;
+            param = null;
+        } else {
+            paramTypes = new Class[1];
+            paramTypes[0] = arguments.getClass();
+            param = new Object[1];
+            param[0] = arguments;
+        }
+        Method method = 
+            catalinaDaemon.getClass().getMethod("stopServer", paramTypes);
+        method.invoke(catalinaDaemon, param);
+
+    }
+
+
+    /**
+     * Set flag.
+     */
+    public void setAwait(boolean await)
+        throws Exception {
+
+        Class paramTypes[] = new Class[1];
+        paramTypes[0] = Boolean.TYPE;
+        Object paramValues[] = new Object[1];
+        paramValues[0] = new Boolean(await);
+        Method method = 
+            catalinaDaemon.getClass().getMethod("setAwait", paramTypes);
+        method.invoke(catalinaDaemon, paramValues);
+
+    }
+
+    public boolean getAwait()
+        throws Exception
+    {
+        Class paramTypes[] = new Class[0];
+        Object paramValues[] = new Object[0];
+        Method method =
+            catalinaDaemon.getClass().getMethod("getAwait", paramTypes);
+        Boolean b=(Boolean)method.invoke(catalinaDaemon, paramValues);
+        return b.booleanValue();
+    }
+
+
+    /**
+     * Destroy the Catalina Daemon.
+     */
+    public void destroy() {
+
+        // FIXME
+
+    }
+
+
+    /**
+     * Main method, used for testing only.
+     *
+     * @param args Command line arguments to be processed
+     */
+    public static void main(String args[]) {
+
+        try {
+            // Attempt to load JMX class
+            new ObjectName("test:foo=bar");
+        } catch (Throwable t) {
+            System.out.println(JMX_ERROR_MESSAGE);
+            try {
+                // Give users some time to read the message before exiting
+                Thread.sleep(5000);
+            } catch (Exception ex) {
+            }
+            return;
+        }
+
+        if (daemon == null) {
+            daemon = new Bootstrap();
+            try {
+                daemon.init();
+            } catch (Throwable t) {
+                t.printStackTrace();
+                return;
+            }
+        }
+
+        try {
+            String command = "start";
+            if (args.length > 0) {
+                command = args[args.length - 1];
+            }
+
+            if (command.equals("startd")) {
+                args[0] = "start";
+                daemon.load(args);
+                daemon.start();
+            } else if (command.equals("stopd")) {
+                args[0] = "stop";
+                daemon.stop();
+            } else if (command.equals("start")) {
+                daemon.setAwait(true);
+                daemon.load(args);
+                daemon.start();
+            } else if (command.equals("stop")) {
+                daemon.stopServer(args);
+            } else {
+                log.warn("Bootstrap: command \"" + command + "\" does not exist.");
+            }
+        } catch (Throwable t) {
+            t.printStackTrace();
+        }
+
+    }
+
+    public void setCatalinaHome(String s) {
+        System.setProperty( "catalina.home", s );
+    }
+
+    public void setCatalinaBase(String s) {
+        System.setProperty( "catalina.base", s );
+    }
+
+
+    /**
+     * Set the <code>catalina.base</code> System property to the current
+     * working directory if it has not been set.
+     */
+    private void setCatalinaBase() {
+
+        if (System.getProperty("catalina.base") != null)
+            return;
+        if (System.getProperty("catalina.home") != null)
+            System.setProperty("catalina.base",
+                               System.getProperty("catalina.home"));
+        else
+            System.setProperty("catalina.base",
+                               System.getProperty("user.dir"));
+
+    }
+
+
+    /**
+     * Set the <code>catalina.home</code> System property to the current
+     * working directory if it has not been set.
+     */
+    private void setCatalinaHome() {
+
+        if (System.getProperty("catalina.home") != null)
+            return;
+        File bootstrapJar = 
+            new File(System.getProperty("user.dir"), "bootstrap.jar");
+        if (bootstrapJar.exists()) {
+            try {
+                System.setProperty
+                    ("catalina.home", 
+                     (new File(System.getProperty("user.dir"), ".."))
+                     .getCanonicalPath());
+            } catch (Exception e) {
+                // Ignore
+                System.setProperty("catalina.home",
+                                   System.getProperty("user.dir"));
+            }
+        } else {
+            System.setProperty("catalina.home",
+                               System.getProperty("user.dir"));
+        }
+
+    }
+
+
+    /**
+     * Get the value of the catalina.home environment variable.
+     */
+    public static String getCatalinaHome() {
+        return System.getProperty("catalina.home",
+                                  System.getProperty("user.dir"));
+    }
+
+
+    /**
+     * Get the value of the catalina.base environment variable.
+     */
+    public static String getCatalinaBase() {
+        return System.getProperty("catalina.base", getCatalinaHome());
+    }
+
+
+}
index 3ca120f..1d7a297 100644 (file)
-/*\r
- * Copyright 1999,2004 The Apache Software Foundation.\r
- * \r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- * \r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-\r
-package org.apache.catalina.startup;\r
-\r
-\r
-import java.io.File;\r
-import java.net.URL;\r
-import java.util.ArrayList;\r
-\r
-import org.apache.catalina.loader.StandardClassLoader;\r
-import org.apache.commons.logging.Log;\r
-import org.apache.commons.logging.LogFactory;\r
-\r
-\r
-/**\r
- * <p>Utility class for building class loaders for Catalina.  The factory\r
- * method requires the following parameters in order to build a new class\r
- * loader (with suitable defaults in all cases):</p>\r
- * <ul>\r
- * <li>A set of directories containing unpacked classes (and resources)\r
- *     that should be included in the class loader's\r
- *     repositories.</li>\r
- * <li>A set of directories containing classes and resources in JAR files.\r
- *     Each readable JAR file discovered in these directories will be\r
- *     added to the class loader's repositories.</li>\r
- * <li><code>ClassLoader</code> instance that should become the parent of\r
- *     the new class loader.</li>\r
- * </ul>\r
- *\r
- * @author Craig R. McClanahan\r
- * @version $Revision: 303210 $ $Date: 2004-09-08 01:13:01 +0200 (mer., 08 sept. 2004) $\r
- */\r
-\r
-public final class ClassLoaderFactory {\r
-\r
-\r
-    private static Log log = LogFactory.getLog(ClassLoaderFactory.class);\r
-\r
-    // --------------------------------------------------------- Public Methods\r
-\r
-\r
-    /**\r
-     * Create and return a new class loader, based on the configuration\r
-     * defaults and the specified directory paths:\r
-     *\r
-     * @param unpacked Array of pathnames to unpacked directories that should\r
-     *  be added to the repositories of the class loader, or <code>null</code> \r
-     * for no unpacked directories to be considered\r
-     * @param packed Array of pathnames to directories containing JAR files\r
-     *  that should be added to the repositories of the class loader, \r
-     * or <code>null</code> for no directories of JAR files to be considered\r
-     * @param parent Parent class loader for the new class loader, or\r
-     *  <code>null</code> for the system class loader.\r
-     *\r
-     * @exception Exception if an error occurs constructing the class loader\r
-     */\r
-    public static ClassLoader createClassLoader(File unpacked[],\r
-                                                File packed[],\r
-                                                ClassLoader parent)\r
-        throws Exception {\r
-        return createClassLoader(unpacked, packed, null, parent);\r
-    }\r
-\r
-\r
-    /**\r
-     * Create and return a new class loader, based on the configuration\r
-     * defaults and the specified directory paths:\r
-     *\r
-     * @param unpacked Array of pathnames to unpacked directories that should\r
-     *  be added to the repositories of the class loader, or <code>null</code> \r
-     * for no unpacked directories to be considered\r
-     * @param packed Array of pathnames to directories containing JAR files\r
-     *  that should be added to the repositories of the class loader, \r
-     * or <code>null</code> for no directories of JAR files to be considered\r
-     * @param urls Array of URLs to remote repositories, designing either JAR \r
-     *  resources or uncompressed directories that should be added to \r
-     *  the repositories of the class loader, or <code>null</code> for no \r
-     *  directories of JAR files to be considered\r
-     * @param parent Parent class loader for the new class loader, or\r
-     *  <code>null</code> for the system class loader.\r
-     *\r
-     * @exception Exception if an error occurs constructing the class loader\r
-     */\r
-    public static ClassLoader createClassLoader(File unpacked[],\r
-                                                File packed[],\r
-                                                URL urls[],\r
-                                                ClassLoader parent)\r
-        throws Exception {\r
-\r
-        if (log.isDebugEnabled())\r
-            log.debug("Creating new class loader");\r
-\r
-        // Construct the "class path" for this class loader\r
-        ArrayList list = new ArrayList();\r
-\r
-        // Add unpacked directories\r
-        if (unpacked != null) {\r
-            for (int i = 0; i < unpacked.length; i++)  {\r
-                File file = unpacked[i];\r
-                if (!file.exists() || !file.canRead())\r
-                    continue;\r
-                file = new File(file.getCanonicalPath() + File.separator);\r
-                URL url = file.toURL();\r
-                if (log.isDebugEnabled())\r
-                    log.debug("  Including directory " + url);\r
-                list.add(url);\r
-            }\r
-        }\r
-\r
-        // Add packed directory JAR files\r
-        if (packed != null) {\r
-            for (int i = 0; i < packed.length; i++) {\r
-                File directory = packed[i];\r
-                if (!directory.isDirectory() || !directory.exists() ||\r
-                    !directory.canRead())\r
-                    continue;\r
-                String filenames[] = directory.list();\r
-                for (int j = 0; j < filenames.length; j++) {\r
-                    String filename = filenames[j].toLowerCase();\r
-                    if (!filename.endsWith(".jar"))\r
-                        continue;\r
-                    File file = new File(directory, filenames[j]);\r
-                    if (log.isDebugEnabled())\r
-                        log.debug("  Including jar file " + file.getAbsolutePath());\r
-                    URL url = file.toURL();\r
-                    list.add(url);\r
-                }\r
-            }\r
-        }\r
-\r
-        // Add URLs\r
-        if (urls != null) {\r
-            for (int i = 0; i < urls.length; i++) {\r
-                if (log.isDebugEnabled())\r
-                    log.debug("  Including URL " + urls[i]);\r
-                list.add(urls[i]);\r
-            }\r
-        }\r
-\r
-        // Construct the class loader itself\r
-        URL[] array = (URL[]) list.toArray(new URL[list.size()]);\r
-        StandardClassLoader classLoader = null;\r
-        if (parent == null)\r
-            classLoader = new StandardClassLoader(array);\r
-        else\r
-            classLoader = new StandardClassLoader(array, parent);\r
-        return (classLoader);\r
-\r
-    }\r
-\r
-\r
-}\r
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.catalina.startup;
+
+
+import java.io.File;
+import java.net.URL;
+import java.util.ArrayList;
+
+import org.apache.catalina.loader.StandardClassLoader;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * <p>Utility class for building class loaders for Catalina.  The factory
+ * method requires the following parameters in order to build a new class
+ * loader (with suitable defaults in all cases):</p>
+ * <ul>
+ * <li>A set of directories containing unpacked classes (and resources)
+ *     that should be included in the class loader's
+ *     repositories.</li>
+ * <li>A set of directories containing classes and resources in JAR files.
+ *     Each readable JAR file discovered in these directories will be
+ *     added to the class loader's repositories.</li>
+ * <li><code>ClassLoader</code> instance that should become the parent of
+ *     the new class loader.</li>
+ * </ul>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303210 $ $Date: 2004-09-08 01:13:01 +0200 (mer., 08 sept. 2004) $
+ */
+
+public final class ClassLoaderFactory {
+
+
+    private static Log log = LogFactory.getLog(ClassLoaderFactory.class);
+
+    protected static final Integer IS_DIR = new Integer(0);
+    protected static final Integer IS_JAR = new Integer(1);
+    protected static final Integer IS_GLOB = new Integer(2);
+    protected static final Integer IS_URL = new Integer(3);
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Create and return a new class loader, based on the configuration
+     * defaults and the specified directory paths:
+     *
+     * @param unpacked Array of pathnames to unpacked directories that should
+     *  be added to the repositories of the class loader, or <code>null</code> 
+     * for no unpacked directories to be considered
+     * @param packed Array of pathnames to directories containing JAR files
+     *  that should be added to the repositories of the class loader, 
+     * or <code>null</code> for no directories of JAR files to be considered
+     * @param parent Parent class loader for the new class loader, or
+     *  <code>null</code> for the system class loader.
+     *
+     * @exception Exception if an error occurs constructing the class loader
+     */
+    public static ClassLoader createClassLoader(File unpacked[],
+                                                File packed[],
+                                                ClassLoader parent)
+        throws Exception {
+        return createClassLoader(unpacked, packed, null, parent);
+    }
+
+
+    /**
+     * Create and return a new class loader, based on the configuration
+     * defaults and the specified directory paths:
+     *
+     * @param unpacked Array of pathnames to unpacked directories that should
+     *  be added to the repositories of the class loader, or <code>null</code> 
+     * for no unpacked directories to be considered
+     * @param packed Array of pathnames to directories containing JAR files
+     *  that should be added to the repositories of the class loader, 
+     * or <code>null</code> for no directories of JAR files to be considered
+     * @param urls Array of URLs to remote repositories, designing either JAR 
+     *  resources or uncompressed directories that should be added to 
+     *  the repositories of the class loader, or <code>null</code> for no 
+     *  directories of JAR files to be considered
+     * @param parent Parent class loader for the new class loader, or
+     *  <code>null</code> for the system class loader.
+     *
+     * @exception Exception if an error occurs constructing the class loader
+     */
+    public static ClassLoader createClassLoader(File unpacked[],
+                                                File packed[],
+                                                URL urls[],
+                                                ClassLoader parent)
+        throws Exception {
+
+        if (log.isDebugEnabled())
+            log.debug("Creating new class loader");
+
+        // Construct the "class path" for this class loader
+        ArrayList list = new ArrayList();
+
+        // Add unpacked directories
+        if (unpacked != null) {
+            for (int i = 0; i < unpacked.length; i++)  {
+                File file = unpacked[i];
+                if (!file.exists() || !file.canRead())
+                    continue;
+                file = new File(file.getCanonicalPath() + File.separator);
+                URL url = file.toURL();
+                if (log.isDebugEnabled())
+                    log.debug("  Including directory " + url);
+                list.add(url);
+            }
+        }
+
+        // Add packed directory JAR files
+        if (packed != null) {
+            for (int i = 0; i < packed.length; i++) {
+                File directory = packed[i];
+                if (!directory.isDirectory() || !directory.exists() ||
+                    !directory.canRead())
+                    continue;
+                String filenames[] = directory.list();
+                for (int j = 0; j < filenames.length; j++) {
+                    String filename = filenames[j].toLowerCase();
+                    if (!filename.endsWith(".jar"))
+                        continue;
+                    File file = new File(directory, filenames[j]);
+                    if (log.isDebugEnabled())
+                        log.debug("  Including jar file " + file.getAbsolutePath());
+                    URL url = file.toURL();
+                    list.add(url);
+                }
+            }
+        }
+
+        // Construct the class loader itself
+        URL[] array = (URL[]) list.toArray(new URL[list.size()]);
+        StandardClassLoader classLoader = null;
+        if (parent == null)
+            classLoader = new StandardClassLoader(array);
+        else
+            classLoader = new StandardClassLoader(array, parent);
+        return (classLoader);
+
+    }
+
+
+    /**
+     * Create and return a new class loader, based on the configuration
+     * defaults and the specified directory paths:
+     *
+     * @param locations Array of strings containing class directories, jar files,
+     *  jar directories or URLS that should be added to the repositories of
+     *  the class loader. The type is given by the member of param types.
+     * @param types Array of types for the members of param locations.
+     *  Possible values are IS_DIR (class directory), IS_JAR (single jar file),
+     *  IS_GLOB (directory of jar files) and IS_URL (URL).
+     * @param parent Parent class loader for the new class loader, or
+     *  <code>null</code> for the system class loader.
+     *
+     * @exception Exception if an error occurs constructing the class loader
+     */
+    public static ClassLoader createClassLoader(String locations[],
+                                                Integer types[],
+                                                ClassLoader parent)
+        throws Exception {
+
+        if (log.isDebugEnabled())
+            log.debug("Creating new class loader");
+
+        // Construct the "class path" for this class loader
+        ArrayList list = new ArrayList();
+
+        if (locations != null && types != null && locations.length == types.length) {
+            for (int i = 0; i < locations.length; i++)  {
+                String location = locations[i];
+                if ( types[i] == IS_URL ) {
+                    URL url = new URL(location);
+                    if (log.isDebugEnabled())
+                        log.debug("  Including URL " + url);
+                    list.add(url);
+                } else if ( types[i] == IS_DIR ) {
+                    File directory = new File(location);
+                    directory = new File(directory.getCanonicalPath());
+                    if (!directory.exists() || !directory.isDirectory() ||
+                        !directory.canRead())
+                         continue;
+                    URL url = directory.toURL();
+                    if (log.isDebugEnabled())
+                        log.debug("  Including directory " + url);
+                    list.add(url);
+                } else if ( types[i] == IS_JAR ) {
+                    File file=new File(location);
+                    file = new File(file.getCanonicalPath());
+                    if (!file.exists() || !file.canRead())
+                        continue;
+                    URL url = file.toURL();
+                    if (log.isDebugEnabled())
+                        log.debug("  Including jar file " + url);
+                    list.add(url);
+                } else if ( types[i] == IS_GLOB ) {
+                    File directory=new File(location);
+                    if (!directory.exists() || !directory.isDirectory() ||
+                        !directory.canRead())
+                        continue;
+                    if (log.isDebugEnabled())
+                        log.debug("  Including directory glob "
+                            + directory.getAbsolutePath());
+                    String filenames[] = directory.list();
+                    for (int j = 0; j < filenames.length; j++) {
+                        String filename = filenames[j].toLowerCase();
+                        if (!filename.endsWith(".jar"))
+                            continue;
+                        File file = new File(directory, filenames[j]);
+                        file = new File(file.getCanonicalPath());
+                        if (!file.exists() || !file.canRead())
+                            continue;
+                        if (log.isDebugEnabled())
+                            log.debug("    Including glob jar file "
+                                + file.getAbsolutePath());
+                        URL url = file.toURL();
+                        list.add(url);
+                    }
+                }
+            }
+        }
+
+        // Construct the class loader itself
+        URL[] array = (URL[]) list.toArray(new URL[list.size()]);
+        if (log.isDebugEnabled())
+            for (int i = 0; i < array.length; i++) {
+                log.debug("  location " + i + " is " + array[i]);
+            }
+        StandardClassLoader classLoader = null;
+        if (parent == null)
+            classLoader = new StandardClassLoader(array);
+        else
+            classLoader = new StandardClassLoader(array, parent);
+        return (classLoader);
+
+    }
+
+
+}