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.harmony.tools.javac;
019:
020: import java.io.File;
021: import java.io.PrintWriter;
022: import java.lang.reflect.Constructor;
023: import java.lang.reflect.InvocationTargetException;
024: import java.lang.reflect.Method;
025: import java.net.MalformedURLException;
026: import java.net.URL;
027: import java.net.URLClassLoader;
028: import org.apache.harmony.tools.toolutils.Util;
029:
030: /**
031: * A proxy to the Java source code compiler itself.
032: */
033: class Compiler {
034:
035: /* FIXME: Hard-coded for now, the name of the ECJ JAR file */
036: static final String ECJ_JAR_FILE = "ecj_3.3.jar"; //$NON-NLS-1$
037:
038: static final String TOOLS_JAR_FILE = "tools.jar"; //$NON-NLS-1$
039:
040: /* The name of the ECJ compiler class */
041: static final String MAIN_CLASS_NAME = "org.eclipse.jdt.internal.compiler.batch.Main"; //$NON-NLS-1$
042:
043: /*
044: * Invokes the compiler with the given command-line arguments. The supported
045: * arguments can be determined form the usage message.
046: *
047: * Answers the result of the compilation from ECJ; i.e. true if the compile
048: * succeeded, and false otherwise.
049: */
050: public static boolean main(String[] args) {
051: return main(args, Util.getDefaultWriter(System.out), Util
052: .getDefaultWriter(System.err));
053: }
054:
055: public static boolean main(String[] args, PrintWriter out,
056: PrintWriter err) {
057: Compiler myself = new Compiler(out, err);
058:
059: // If there is a problem invoking the method, simply dump the trace for
060: // now
061: try {
062: Object result = myself.staticCompileMth.invoke(
063: myself.mainInst, new Object[] { args });
064: return (Boolean) result;
065: } catch (IllegalArgumentException e) {
066: e.printStackTrace();
067: } catch (IllegalAccessException e) {
068: e.printStackTrace();
069: } catch (InvocationTargetException e) {
070: e.printStackTrace();
071: }
072: return false;
073: }
074:
075: // Reference to ECJ 'Main' compiler class.
076: Class<?> ecjCompilerClass;
077:
078: // An instance of the ECJ compiler
079: Object mainInst;
080:
081: // The Main#printUsage() method.
082: Method printUsageMth;
083:
084: // The static Main#compile(string[]) method on the ECJ compiler
085: Method staticCompileMth;
086:
087: /**
088: * Default constructor. Returns a new initialized instance of the Java
089: * compiler.
090: */
091: public Compiler(PrintWriter out, PrintWriter err) {
092: super ();
093: initialize(out, err);
094: }
095:
096: /*
097: * Initialize our local variables. Called during type construction.
098: */
099: protected void initialize(PrintWriter out, PrintWriter err) {
100: try {
101: initializeMainClass();
102: initializeInstance(out, err);
103: initializeMethods();
104: } catch (Exception e) {
105: // If there is a problem we log it to the console
106: e.printStackTrace();
107: }
108: }
109:
110: /*
111: * Defines the local instance of the ECJ compiler
112: */
113: protected void initializeInstance(PrintWriter out, PrintWriter err)
114: throws SecurityException, NoSuchMethodException,
115: IllegalArgumentException, InstantiationException,
116: IllegalAccessException, InvocationTargetException {
117:
118: // Create a new instance of the compiler
119: Constructor<?> ctor = ecjCompilerClass
120: .getConstructor(new Class[] { PrintWriter.class,
121: PrintWriter.class, Boolean.TYPE });
122:
123: mainInst = ctor.newInstance(new Object[] { out, err,
124: Boolean.FALSE });
125: }
126:
127: /*
128: * Defines the compiler class from the ECJ jar file
129: */
130: protected void initializeMainClass() throws ClassNotFoundException,
131: SecurityException, NoSuchMethodException,
132: MalformedURLException, IllegalArgumentException,
133: InstantiationException, IllegalAccessException,
134: InvocationTargetException {
135:
136: // Find the ECJ JAR file, prefer those found near loaders
137: URL ecjURL = searchLoaders();
138: if (ecjURL == null) {
139: ecjURL = searchPaths();
140: }
141: if (ecjURL == null) {
142: throw new RuntimeException("Cannot find file "
143: + ECJ_JAR_FILE);
144: }
145:
146: // Load the ECJ main class
147: URLClassLoader loader = new URLClassLoader(new URL[] { ecjURL });
148: ecjCompilerClass = loader.loadClass(MAIN_CLASS_NAME);
149: }
150:
151: /*
152: * Looks for the ECJ JAR file in the current working directory, and in the
153: * jdk/lib of the current runtime. Answers with a URL of the JAR file if
154: * found, or null if not found.
155: */
156: private URL searchPaths() throws MalformedURLException {
157: // Search in current working directory
158: File cwdFile = new File(ECJ_JAR_FILE);
159: if (cwdFile.exists()) {
160: return cwdFile.toURL();
161: }
162:
163: // Look for it via the java.home
164: File javaHomeFile = new File(System.getProperty("java.home")); //$NON-NLS-1$
165: String pathFromJDK = "lib" + File.separator + ECJ_JAR_FILE; //$NON-NLS-1$
166:
167: // Is java.home pointing at a JDK?
168: File jdkBasedFile = new File(javaHomeFile, pathFromJDK);
169: if (jdkBasedFile.exists()) {
170: return jdkBasedFile.toURL();
171: }
172: // Maybe it is pointing at a JRE.
173: File jdkHomeFile = javaHomeFile.getParentFile();
174: if (jdkHomeFile == null) {
175: return null;
176: }
177: File jreBasedFile = new File(jdkHomeFile, pathFromJDK);
178: if (jreBasedFile.exists()) {
179: return jreBasedFile.toURL();
180: }
181:
182: // We didn't find it
183: return null;
184: }
185:
186: /*
187: * Find the ECJ jar by searching for the tools.jar location and figuring
188: * that it is alongside that.
189: */
190: private URL searchLoaders() throws MalformedURLException {
191: URLClassLoader bogusLoader = new URLClassLoader(new URL[] {});
192: ClassLoader parentLoader = bogusLoader.getParent();
193: while (parentLoader instanceof URLClassLoader) {
194: URLClassLoader parentURLLoader = (URLClassLoader) parentLoader;
195: URL[] uls = parentURLLoader.getURLs();
196: for (int i = 0; i < uls.length; i++) {
197: URL l = uls[i];
198: String filename = new File(l.getFile()).getName();
199: if (filename.equals(TOOLS_JAR_FILE)) {
200: return new URL(l, ECJ_JAR_FILE);
201: }
202: }
203: // Not found here, move up a level
204: parentLoader = parentLoader.getParent();
205: }
206: // We didn't find it
207: return null;
208: }
209:
210: /*
211: * Initialize our local references to compiler methods we may wish to
212: * invoke.
213: */
214: protected void initializeMethods() throws SecurityException,
215: NoSuchMethodException {
216: staticCompileMth = ecjCompilerClass.getMethod("compile", //$NON-NLS-1$
217: new Class[] { String[].class });
218: printUsageMth = ecjCompilerClass.getMethod(
219: "printUsage", (Class[]) null); //$NON-NLS-1$
220: }
221:
222: /**
223: * Prints the compiler usage message out on the console.
224: */
225: public void printUsage() {
226: // If there is a problem invoking the method, simply dump the trace for
227: // now
228: try {
229: printUsageMth.invoke(mainInst);
230: } catch (IllegalArgumentException e) {
231: e.printStackTrace();
232: } catch (IllegalAccessException e) {
233: e.printStackTrace();
234: } catch (InvocationTargetException e) {
235: e.printStackTrace();
236: }
237: }
238: }
|