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: package org.apache.tools.ant.launch;
019:
020: import java.net.URL;
021: import java.net.URLClassLoader;
022: import java.net.MalformedURLException;
023: import java.io.File;
024: import java.util.StringTokenizer;
025: import java.util.List;
026: import java.util.ArrayList;
027: import java.util.Iterator;
028:
029: /**
030: * This is a launcher for Ant.
031: *
032: * @since Ant 1.6
033: */
034: public class Launcher {
035:
036: /**
037: * The Ant Home (installation) Directory property.
038: * {@value}
039: */
040: public static final String ANTHOME_PROPERTY = "ant.home";
041:
042: /**
043: * The Ant Library Directory property.
044: * {@value}
045: */
046: public static final String ANTLIBDIR_PROPERTY = "ant.library.dir";
047:
048: /**
049: * The directory name of the per-user ant directory.
050: * {@value}
051: */
052: public static final String ANT_PRIVATEDIR = ".ant";
053:
054: /**
055: * The name of a per-user library directory.
056: * {@value}
057: */
058: public static final String ANT_PRIVATELIB = "lib";
059:
060: /**
061: * The location of a per-user library directory.
062: * <p>
063: * It's value is the concatenation of {@link #ANT_PRIVATEDIR}
064: * with {@link #ANT_PRIVATELIB}, with an appropriate file separator
065: * in between. For example, on Unix, it's <code>.ant/lib</code>.
066: */
067: public static final String USER_LIBDIR = ANT_PRIVATEDIR
068: + File.separatorChar + ANT_PRIVATELIB;
069:
070: /**
071: * The startup class that is to be run.
072: * {@value}
073: */
074: public static final String MAIN_CLASS = "org.apache.tools.ant.Main";
075:
076: /**
077: * System property with user home directory.
078: * {@value}
079: */
080: public static final String USER_HOMEDIR = "user.home";
081:
082: /**
083: * System property with application classpath.
084: * {@value}
085: */
086: private static final String JAVA_CLASS_PATH = "java.class.path";
087:
088: /**
089: * Exit code on trouble
090: */
091: protected static final int EXIT_CODE_ERROR = 2;
092:
093: /**
094: * Entry point for starting command line Ant.
095: *
096: * @param args commandline arguments
097: */
098: public static void main(String[] args) {
099: int exitCode;
100: try {
101: Launcher launcher = new Launcher();
102: exitCode = launcher.run(args);
103: } catch (LaunchException e) {
104: exitCode = EXIT_CODE_ERROR;
105: System.err.println(e.getMessage());
106: } catch (Throwable t) {
107: exitCode = EXIT_CODE_ERROR;
108: t.printStackTrace(System.err);
109: }
110: if (exitCode != 0) {
111: System.exit(exitCode);
112: }
113: }
114:
115: /**
116: * Add a CLASSPATH or -lib to lib path urls.
117: *
118: * @param path the classpath or lib path to add to the libPathULRLs
119: * @param getJars if true and a path is a directory, add the jars in
120: * the directory to the path urls
121: * @param libPathURLs the list of paths to add to
122: */
123: private void addPath(String path, boolean getJars, List libPathURLs)
124: throws MalformedURLException {
125: StringTokenizer tokenizer = new StringTokenizer(path,
126: File.pathSeparator);
127: while (tokenizer.hasMoreElements()) {
128: String elementName = tokenizer.nextToken();
129: File element = new File(elementName);
130: if (elementName.indexOf("%") != -1 && !element.exists()) {
131: continue;
132: }
133: if (getJars && element.isDirectory()) {
134: // add any jars in the directory
135: URL[] dirURLs = Locator.getLocationURLs(element);
136: for (int j = 0; j < dirURLs.length; ++j) {
137: libPathURLs.add(dirURLs[j]);
138: }
139: }
140:
141: libPathURLs.add(Locator.fileToURL(element));
142: }
143: }
144:
145: /**
146: * Run the launcher to launch Ant.
147: *
148: * @param args the command line arguments
149: * @return an exit code. As the normal ant main calls exit when it ends,
150: * this is for handling failures at bind-time
151: * @exception MalformedURLException if the URLs required for the classloader
152: * cannot be created.
153: */
154: private int run(String[] args) throws LaunchException,
155: MalformedURLException {
156: String antHomeProperty = System.getProperty(ANTHOME_PROPERTY);
157: File antHome = null;
158:
159: File sourceJar = Locator.getClassSource(getClass());
160: File jarDir = sourceJar.getParentFile();
161: String mainClassname = MAIN_CLASS;
162:
163: if (antHomeProperty != null) {
164: antHome = new File(antHomeProperty);
165: }
166:
167: if (antHome == null || !antHome.exists()) {
168: antHome = jarDir.getParentFile();
169: System.setProperty(ANTHOME_PROPERTY, antHome
170: .getAbsolutePath());
171: }
172:
173: if (!antHome.exists()) {
174: throw new LaunchException("Ant home is set incorrectly or "
175: + "ant could not be located");
176: }
177:
178: List libPaths = new ArrayList();
179: String cpString = null;
180: List argList = new ArrayList();
181: String[] newArgs;
182: boolean noUserLib = false;
183: boolean noClassPath = false;
184:
185: for (int i = 0; i < args.length; ++i) {
186: if (args[i].equals("-lib")) {
187: if (i == args.length - 1) {
188: throw new LaunchException("The -lib argument must "
189: + "be followed by a library location");
190: }
191: libPaths.add(args[++i]);
192: } else if (args[i].equals("-cp")) {
193: if (i == args.length - 1) {
194: throw new LaunchException("The -cp argument must "
195: + "be followed by a classpath expression");
196: }
197: if (cpString != null) {
198: throw new LaunchException("The -cp argument must "
199: + "not be repeated");
200: }
201: cpString = args[++i];
202: } else if (args[i].equals("--nouserlib")
203: || args[i].equals("-nouserlib")) {
204: noUserLib = true;
205: } else if (args[i].equals("--noclasspath")
206: || args[i].equals("-noclasspath")) {
207: noClassPath = true;
208: } else if (args[i].equals("-main")) {
209: if (i == args.length - 1) {
210: throw new LaunchException(
211: "The -main argument must "
212: + "be followed by a library location");
213: }
214: mainClassname = args[++i];
215: } else {
216: argList.add(args[i]);
217: }
218: }
219:
220: //decide whether to copy the existing arg set, or
221: //build a new one from the list of all args excluding the special
222: //operations that only we handle
223: if (argList.size() == args.length) {
224: newArgs = args;
225: } else {
226: newArgs = (String[]) argList.toArray(new String[argList
227: .size()]);
228: }
229:
230: URL[] libURLs = getLibPathURLs(noClassPath ? null : cpString,
231: libPaths);
232: URL[] systemURLs = getSystemURLs(jarDir);
233: URL[] userURLs = noUserLib ? new URL[0] : getUserURLs();
234:
235: URL[] jars = getJarArray(libURLs, userURLs, systemURLs, Locator
236: .getToolsJar());
237:
238: // now update the class.path property
239: StringBuffer baseClassPath = new StringBuffer(System
240: .getProperty(JAVA_CLASS_PATH));
241: if (baseClassPath.charAt(baseClassPath.length() - 1) == File.pathSeparatorChar) {
242: baseClassPath.setLength(baseClassPath.length() - 1);
243: }
244:
245: for (int i = 0; i < jars.length; ++i) {
246: baseClassPath.append(File.pathSeparatorChar);
247: baseClassPath.append(Locator.fromURI(jars[i].toString()));
248: }
249:
250: System.setProperty(JAVA_CLASS_PATH, baseClassPath.toString());
251:
252: URLClassLoader loader = new URLClassLoader(jars);
253: Thread.currentThread().setContextClassLoader(loader);
254: Class mainClass = null;
255: int exitCode = 0;
256: try {
257: mainClass = loader.loadClass(mainClassname);
258: AntMain main = (AntMain) mainClass.newInstance();
259: main.startAnt(newArgs, null, null);
260: } catch (InstantiationException ex) {
261: System.err.println("Incompatible version of "
262: + mainClassname + " detected");
263: File mainJar = Locator.getClassSource(mainClass);
264: System.err.println("Location of this class " + mainJar);
265: exitCode = EXIT_CODE_ERROR;
266: } catch (Throwable t) {
267: t.printStackTrace(System.err);
268: exitCode = EXIT_CODE_ERROR;
269: }
270: return exitCode;
271: }
272:
273: /**
274: * Get the list of -lib enties and -cp entry into
275: * a URL array.
276: * @param cpString the classpath string
277: * @param libPaths the list of -lib entries.
278: * @return an array of URLs.
279: */
280: private URL[] getLibPathURLs(String cpString, List libPaths)
281: throws MalformedURLException {
282: List libPathURLs = new ArrayList();
283:
284: if (cpString != null) {
285: addPath(cpString, false, libPathURLs);
286: }
287:
288: for (Iterator i = libPaths.iterator(); i.hasNext();) {
289: String libPath = (String) i.next();
290: addPath(libPath, true, libPathURLs);
291: }
292:
293: return (URL[]) libPathURLs.toArray(new URL[libPathURLs.size()]);
294: }
295:
296: /**
297: * Get the jar files in ANT_HOME/lib.
298: * determine ant library directory for system jars: use property
299: * or default using location of ant-launcher.jar
300: */
301: private URL[] getSystemURLs(File antLauncherDir)
302: throws MalformedURLException {
303: File antLibDir = null;
304: String antLibDirProperty = System
305: .getProperty(ANTLIBDIR_PROPERTY);
306: if (antLibDirProperty != null) {
307: antLibDir = new File(antLibDirProperty);
308: }
309: if ((antLibDir == null) || !antLibDir.exists()) {
310: antLibDir = antLauncherDir;
311: System.setProperty(ANTLIBDIR_PROPERTY, antLibDir
312: .getAbsolutePath());
313: }
314: return Locator.getLocationURLs(antLibDir);
315: }
316:
317: /**
318: * Get the jar files in user.home/.ant/lib
319: */
320: private URL[] getUserURLs() throws MalformedURLException {
321: File userLibDir = new File(System.getProperty(USER_HOMEDIR),
322: USER_LIBDIR);
323:
324: return Locator.getLocationURLs(userLibDir);
325: }
326:
327: /**
328: * Combine the various jar sources into a single array of jars.
329: * @param libJars the jars specified in -lib command line options
330: * @param userJars the jars in ~/.ant/lib
331: * @param systemJars the jars in $ANT_HOME/lib
332: * @param toolsJar the tools.jar file
333: * @return a combined array
334: * @throws MalformedURLException if there is a problem.
335: */
336: private URL[] getJarArray(URL[] libJars, URL[] userJars,
337: URL[] systemJars, File toolsJar)
338: throws MalformedURLException {
339: int numJars = libJars.length + userJars.length
340: + systemJars.length;
341: if (toolsJar != null) {
342: numJars++;
343: }
344: URL[] jars = new URL[numJars];
345: System.arraycopy(libJars, 0, jars, 0, libJars.length);
346: System.arraycopy(userJars, 0, jars, libJars.length,
347: userJars.length);
348: System.arraycopy(systemJars, 0, jars, userJars.length
349: + libJars.length, systemJars.length);
350:
351: if (toolsJar != null) {
352: jars[jars.length - 1] = Locator.fileToURL(toolsJar);
353: }
354: return jars;
355: }
356: }
|