/*
* Copyright 2006 Ralf Jaochim
*
* 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.castor.xmlctf.compiler;
import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import org.castor.xmlctf.XMLTestCase;
import org.castor.xmlctf.util.FileServices;
/**
* Compiles a directory tree, recursively. This class is built to use the Sun
* Javac compiler contained in tools.jar. A IllegalStateException will be thrown
* if tools.jar is not on the classpath at construction of the class and
* execution of the compileDirectory() method.
*
* @author <a href="mailto:ralf DOT joachim AT syscon DOT eu">Ralf Joachim</a>
* @version $Revision: 5951 $ $Date: 2006-04-25 16:09:10 -0600 (Tue, 25 Apr 2006) $
* @since 1.0.5
*/
public class SunJavaCompiler implements Compiler {
private static final int COMPILATION_SUCCESS = 0;
private static final int COMPILATION_ERROR = 1;
private static final int COMPILATION_CMDERR = 2;
private static final int COMPILATION_SYSERR = 3;
private static final int COMPILATION_ABNORMAL = 4;
private static final String COMPILE_CLASSNAME = "com.sun.tools.javac.Main";
private static final String COMPILE_METHODNAME = "compile";
private static final Class[] COMPILE_PARAMTYPE = new Class[] {String[].class};
private static final HashSet IGNORE_DIRS = new HashSet();
private static Method _compileMethod = null;
private static boolean _initialized = false;
/** Java version of the JVM we are running in. */
private static final float JAVA_VERSION = Float.parseFloat(System.getProperty("java.specification.version"));
private String _javaVersion = null;
private final File _baseDirectory;
private final File _outputDirectory;
/**
* Creates a compiler for a given directory.
* @param baseDirectory The directory that holds the files to be compiled.
*/
public SunJavaCompiler(final File baseDirectory) {
if (baseDirectory == null) {
throw new IllegalArgumentException("'baseDirectory' must not be null.");
}
_baseDirectory = baseDirectory;
_outputDirectory = baseDirectory;
if (!_initialized) { initialize(); }
}
/**
* Sets the Java source version the current test will be using.
* @param javaSourceVersion The Java Source version to be used.
*/
public void setJavaSourceVersion(final float javaSourceVersion) {
float srcVersion = javaSourceVersion;
if (javaSourceVersion >= 5F && javaSourceVersion < 10F) {
srcVersion = 1.0F + (javaSourceVersion / 10F);
}
_javaVersion = "" + srcVersion;
}
/**
* Initialize.
*/
private void initialize() {
IGNORE_DIRS.add(FileServices.CVS);
IGNORE_DIRS.add(FileServices.SVN);
try {
ClassLoader loader = this.getClass().getClassLoader();
Class cls = loader.loadClass(COMPILE_CLASSNAME);
_compileMethod = cls.getMethod(COMPILE_METHODNAME, COMPILE_PARAMTYPE);
} catch (Exception ex) {
IllegalStateException ise = new IllegalStateException("Failed to find compile method.");
ise.initCause(ex);
throw ise;
}
_initialized = true;
}
/**
* Compiles the content of a directory. Throws a <code>CompilationException</code>
* if the build fails.
*/
public void compileDirectory() {
List filesList = findSourceFiles(_baseDirectory);
if (filesList.size() > 0) {
filesList.addAll(0, getCompileArguments(_baseDirectory, _outputDirectory));
String[] args = new String[filesList.size()];
args = (String[]) filesList.toArray(args);
int status;
try {
Object result = _compileMethod.invoke(null, new Object[] {args});
status = ((Integer) result).intValue();
} catch (Exception ex) {
throw new IllegalStateException("Failed to call compile method.");
}
switch (status) {
case COMPILATION_SUCCESS: break;
case COMPILATION_ERROR: throw new CompilationException("Compile status: ERROR");
case COMPILATION_CMDERR: throw new CompilationException("Compile status: CMDERR");
case COMPILATION_SYSERR: throw new CompilationException("Compile status: SYSERR");
case COMPILATION_ABNORMAL: throw new CompilationException("Compile status: ABNORMAL");
default: throw new CompilationException("Compile status: Unknown");
}
} else {
throw new CompilationException("No files to compile: " + _baseDirectory);
}
}
/**
* Returns a list of arguments for the compiler.
* @param srcDir The source directory for compilation
* @param destDir The destination directory for compilation
* @return a list of arguments for the compiler.
*/
private List getCompileArguments(final File srcDir, final File destDir) {
List args = new ArrayList();
args.add("-g");
if (JAVA_VERSION == 1.5F) {
args.add("-Xlint:unchecked");
}
if (XMLTestCase._verbose) {
args.add("-verbose");
} else {
args.add("-nowarn");
args.add("-Xmaxwarns");
args.add("0");
args.add("-Xmaxerrs");
args.add("5");
}
if (_javaVersion != null) {
args.add("-source");
args.add(_javaVersion);
}
args.add("-classpath");
String classPathOverriden = System.getProperty("xmlctf.classpath.override");
if (classPathOverriden != null) {
args.add(classPathOverriden + ";" + destDir.getAbsolutePath());
} else {
args.add(System.getProperty("java.class.path") + ";" + destDir.getAbsolutePath());
}
args.add("-d");
args.add(destDir.getAbsolutePath());
args.add("-sourcepath");
args.add(srcDir.getAbsolutePath());
return args;
}
/**
* Recursively searches the provided directory, returning a list of all Java files found.
* @param srcDir A directory to search for Java files.
* @return a List of all Java files found in the provided directory
*/
private List findSourceFiles(final File srcDir) {
List files = new ArrayList();
File[] entries = srcDir.listFiles();
for (int i = 0; i < entries.length; i++) {
File entry = entries[i];
if (entry.getName().endsWith(".java")) {
files.add(entry.getAbsolutePath());
} else if (entry.isDirectory() && !IGNORE_DIRS.contains(entry.getName())) {
files.addAll(findSourceFiles(entry));
}
}
return files;
}
}