001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     * 
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     * 
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    import java.io.File;
019    import java.io.FileInputStream;
020    import java.io.FileNotFoundException;
021    import java.lang.reflect.Method;
022    import java.net.MalformedURLException;
023    import java.net.URL;
024    import java.net.URLClassLoader;
025    import java.net.URLDecoder;
026    import java.util.ArrayList;
027    import java.util.Properties;
028    import java.util.StringTokenizer;
029    
030    /**
031     * This class is used as a wrapper for loading the
032     * org.apache.commons.launcher.Launcher class and invoking its
033     * <code>main(String[])</code> method. This particular
034     * class is primary used by the Windows 95, 98, ME, and 2000 platforms to
035     * overcome the difficulty of putting a jar file directly into the JVM's
036     * classpath when using batch scripts on these platforms.
037     * <p>
038     * Specifically, the problem on thse platforms is when Windows uses the PATH
039     * environment variable to find and run a batch script, %0 will resolve
040     * incorrectly in that batch script.
041     * <p>
042     * The way to work around this Windows limitation is to do the following:
043     * <ol>
044     * <li>Put this class' class file - LauncherBootstrap.class - in the same
045     * directory as the batch script. Do not put this class file in a jar file.
046     * <li>Put the jar file containing the launcher's classes in the same
047     * directory as the batch script and this class' class file. Be sure that
048     * that the jar file is named "commons-launcher.jar".
049     * <li>Make the Java command in the batch script invoke Java use the following
050     * classpath arguments. Be sure to include the quotes to ensure that paths
051     * containing spaces are handled properly:
052     * <code>-classpath %0\..;"%PATH%"</code>
053     * </ol>
054     *
055     * @author Patrick Luby
056     */
057    public class LauncherBootstrap {
058    
059        //---------------------------------------------------------- Static Fields
060    
061        /**
062         * Ant classpath property name
063         */
064        public final static String ANT_CLASSPATH_PROP_NAME = "ant.class.path";
065    
066        /**
067         * Jar file name
068         */
069        public final static String LAUNCHER_JAR_FILE_NAME = "commons-launcher.jar";
070    
071        /**
072         * Properties file name
073         */
074        public final static String LAUNCHER_PROPS_FILE_NAME = "launcher.properties";
075    
076        /**
077         * Class name to load
078         */
079        public final static String LAUNCHER_MAIN_CLASS_NAME = "org.apache.commons.launcher.Launcher";
080    
081        /**
082         * Cached Laucher class.
083         */
084        private static Class launcherClass = null;
085    
086        //---------------------------------------------------------- Static Methods
087    
088        /**
089         * The main method.
090         *
091         * @param args command line arguments
092         */
093        public static void main(String[] args) {
094    
095            try {
096    
097                // Try to find the LAUNCHER_JAR_FILE_NAME file in the class
098                // loader's and JVM's classpath.
099                URL coreURL = LauncherBootstrap.class.getResource("/" + LauncherBootstrap.LAUNCHER_JAR_FILE_NAME);
100                if (coreURL == null)
101                    throw new FileNotFoundException(LauncherBootstrap.LAUNCHER_JAR_FILE_NAME);
102    
103                // Coerce the coreURL's directory into a file
104                File coreDir = new File(URLDecoder.decode(coreURL.getFile())).getCanonicalFile().getParentFile();
105    
106                // Try to find the LAUNCHER_PROPS_FILE_NAME file in the same
107                // directory as this class
108                File propsFile = new File(coreDir, LauncherBootstrap.LAUNCHER_PROPS_FILE_NAME);
109                if (!propsFile.canRead())
110                    throw new FileNotFoundException(propsFile.getPath());
111    
112                // Load the properties in the LAUNCHER_PROPS_FILE_NAME 
113                Properties props = new Properties();
114                FileInputStream fis = new FileInputStream(propsFile);
115                props.load(fis);
116                fis.close();
117    
118                // Create a class loader that contains the Launcher, Ant, and
119                // JAXP classes.
120                URL[] antURLs = LauncherBootstrap.fileListToURLs((String)props.get(LauncherBootstrap.ANT_CLASSPATH_PROP_NAME));
121                URL[] urls = new URL[1 + antURLs.length];
122                urls[0] = coreURL;
123                for (int i = 0; i < antURLs.length; i++)
124                    urls[i + 1] = antURLs[i];
125                ClassLoader parentLoader = Thread.currentThread().getContextClassLoader();
126                URLClassLoader loader = null;
127                if (parentLoader != null)
128                    loader = new URLClassLoader(urls, parentLoader);
129                else
130                    loader = new URLClassLoader(urls);
131    
132                // Load the LAUNCHER_MAIN_CLASS_NAME class
133                launcherClass = loader.loadClass(LAUNCHER_MAIN_CLASS_NAME);
134    
135                // Get the LAUNCHER_MAIN_CLASS_NAME class' getLocalizedString()
136                // method as we need it for printing the usage statement
137                Method getLocalizedStringMethod = launcherClass.getDeclaredMethod("getLocalizedString", new Class[]{ String.class });
138    
139                // Invoke the LAUNCHER_MAIN_CLASS_NAME class' start() method.
140                // If the ant.class.path property is not set correctly in the 
141                // LAUNCHER_PROPS_FILE_NAME, this will throw an exception.
142                Method startMethod = launcherClass.getDeclaredMethod("start", new Class[]{ String[].class });
143                int returnValue = ((Integer)startMethod.invoke(null, new Object[]{ args })).intValue();
144                // Always exit cleanly after invoking the start() method
145                System.exit(returnValue);
146    
147           } catch (Throwable t) {
148    
149               t.printStackTrace();
150               System.exit(1);
151    
152            }
153    
154        }
155    
156        /**
157         * Convert a ":" separated list of URL file fragments into an array of URL
158         * objects. Note that any all URL file fragments must conform to the format
159         * required by the "file" parameter in the
160         * {@link URL(String, String, String)} constructor.
161         *
162         * @param fileList the ":" delimited list of URL file fragments to be
163         *  converted
164         * @return an array of URL objects
165         * @throws MalformedURLException if the fileList parameter contains any
166         *  malformed URLs
167         */
168        private static URL[] fileListToURLs(String fileList)
169            throws MalformedURLException
170        {
171    
172            if (fileList == null || "".equals(fileList))
173                return new URL[0];
174    
175            // Parse the path string
176            ArrayList list = new ArrayList();
177            StringTokenizer tokenizer = new StringTokenizer(fileList, ":");
178            URL bootstrapURL = LauncherBootstrap.class.getResource("/" + LauncherBootstrap.class.getName() + ".class");
179            while (tokenizer.hasMoreTokens())
180                list.add(new URL(bootstrapURL, tokenizer.nextToken()));
181    
182            return (URL[])list.toArray(new URL[list.size()]);
183    
184        }
185    
186    }