blob: 582fbd6e7415d264ca92d3e848e97bc76966ab0f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.harmony.tools.javac;
import java.io.File;
import java.io.PrintWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import org.apache.harmony.tools.toolutils.Util;
/**
* A proxy to the Java source code compiler itself.
*/
class Compiler {
/* FIXME: Hard-coded for now, the name of the ECJ JAR file */
static final String ECJ_JAR_FILE = "ecj-3.4.2.jar"; //$NON-NLS-1$
static final String TOOLS_JAR_FILE = "tools.jar"; //$NON-NLS-1$
/* The name of the ECJ compiler class */
static final String MAIN_CLASS_NAME = "org.eclipse.jdt.internal.compiler.batch.Main"; //$NON-NLS-1$
/*
* Invokes the compiler with the given command-line arguments. The supported
* arguments can be determined form the usage message.
*
* Answers the result of the compilation from ECJ; i.e. true if the compile
* succeeded, and false otherwise.
*/
public static boolean main(String[] args) {
return main(args, Util.getDefaultWriter(System.out), Util.getDefaultWriter(System.err));
}
public static boolean main(String[] args, PrintWriter out, PrintWriter err) {
Compiler myself = new Compiler(out, err);
// If there is a problem invoking the method, simply dump the trace for
// now
try {
Object result = myself.staticCompileMth.invoke(myself.mainInst,
new Object[] { args });
return (Boolean) result;
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return false;
}
// Reference to ECJ 'Main' compiler class.
Class<?> ecjCompilerClass;
// An instance of the ECJ compiler
Object mainInst;
// The Main#printUsage() method.
Method printUsageMth;
// The static Main#compile(string[]) method on the ECJ compiler
Method staticCompileMth;
/**
* Default constructor. Returns a new initialized instance of the Java
* compiler.
*/
public Compiler(PrintWriter out, PrintWriter err) {
super();
initialize(out, err);
}
/*
* Initialize our local variables. Called during type construction.
*/
protected void initialize(PrintWriter out, PrintWriter err) {
try {
initializeMainClass();
initializeInstance(out, err);
initializeMethods();
} catch (Exception e) {
// If there is a problem we log it to the console
e.printStackTrace();
}
}
/*
* Defines the local instance of the ECJ compiler
*/
protected void initializeInstance(PrintWriter out, PrintWriter err) throws SecurityException,
NoSuchMethodException, IllegalArgumentException,
InstantiationException, IllegalAccessException,
InvocationTargetException {
// Create a new instance of the compiler
Constructor<?> ctor = ecjCompilerClass.getConstructor(new Class[] {
PrintWriter.class, PrintWriter.class, Boolean.TYPE });
mainInst = ctor.newInstance(new Object[] { out, err,
Boolean.FALSE });
}
/*
* Defines the compiler class from the ECJ jar file
*/
protected void initializeMainClass() throws ClassNotFoundException,
SecurityException, NoSuchMethodException, MalformedURLException,
IllegalArgumentException, InstantiationException,
IllegalAccessException, InvocationTargetException {
// Find the ECJ JAR file, prefer those found near loaders
URL ecjURL = searchLoaders();
if (ecjURL == null) {
ecjURL = searchPaths();
}
if (ecjURL == null) {
throw new RuntimeException("Cannot find file " + ECJ_JAR_FILE);
}
// Load the ECJ main class
URLClassLoader loader = new URLClassLoader(new URL[] { ecjURL });
ecjCompilerClass = loader.loadClass(MAIN_CLASS_NAME);
}
/*
* Looks for the ECJ JAR file in the current working directory, and in the
* jdk/lib of the current runtime. Answers with a URL of the JAR file if
* found, or null if not found.
*/
private URL searchPaths() throws MalformedURLException {
// Search in current working directory
File cwdFile = new File(ECJ_JAR_FILE);
if (cwdFile.exists()) {
return cwdFile.toURL();
}
// Look for it via the java.home
File javaHomeFile = new File(System.getProperty("java.home")); //$NON-NLS-1$
String pathFromJDK = "lib" + File.separator + ECJ_JAR_FILE; //$NON-NLS-1$
// Is java.home pointing at a JDK?
File jdkBasedFile = new File(javaHomeFile, pathFromJDK);
if (jdkBasedFile.exists()) {
return jdkBasedFile.toURL();
}
// Maybe it is pointing at a JRE.
File jdkHomeFile = javaHomeFile.getParentFile();
if (jdkHomeFile == null) {
return null;
}
File jreBasedFile = new File(jdkHomeFile, pathFromJDK);
if (jreBasedFile.exists()) {
return jreBasedFile.toURL();
}
// We didn't find it
return null;
}
/*
* Find the ECJ jar by searching for the tools.jar location and figuring
* that it is alongside that.
*/
private URL searchLoaders() throws MalformedURLException {
URLClassLoader bogusLoader = new URLClassLoader(new URL[] {});
ClassLoader parentLoader = bogusLoader.getParent();
while (parentLoader instanceof URLClassLoader) {
URLClassLoader parentURLLoader = (URLClassLoader) parentLoader;
URL[] uls = parentURLLoader.getURLs();
for (int i = 0; i < uls.length; i++) {
URL l = uls[i];
String filename = new File(l.getFile()).getName();
if (filename.equals(TOOLS_JAR_FILE)) {
return new URL(l, ECJ_JAR_FILE);
}
}
// Not found here, move up a level
parentLoader = parentLoader.getParent();
}
// We didn't find it
return null;
}
/*
* Initialize our local references to compiler methods we may wish to
* invoke.
*/
protected void initializeMethods() throws SecurityException,
NoSuchMethodException {
staticCompileMth = ecjCompilerClass.getMethod("compile", //$NON-NLS-1$
new Class[] { String[].class });
printUsageMth = ecjCompilerClass
.getMethod("printUsage", (Class[]) null); //$NON-NLS-1$
}
/**
* Prints the compiler usage message out on the console.
*/
public void printUsage() {
// If there is a problem invoking the method, simply dump the trace for
// now
try {
printUsageMth.invoke(mainInst);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}