package oms3.compiler; import java.io.File; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.tools.DiagnosticCollector; import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; import javax.tools.ToolProvider; /** * */ public final class Compiler { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); MemoryOutputJavaFileManager fileManager; ClassLoader loader; Map<String, Class<?>> cache = new HashMap<String, Class<?>>(); List<String> compilerOptions = new ArrayList<String>(); // private static Compiler instance; public static synchronized Compiler singleton(URLClassLoader parent) { if (instance == null) { instance = new Compiler(parent); } return instance; } private Compiler(URLClassLoader parent) { //If not running on JDK, compiler will be null if (compiler == null) { throw new Error("Compiler not available. This may happen if " + "running on JRE instead of JDK. Please use a full JDK 1.6." + "javax.tools.ToolProvider.getSystemJavaCompiler() returned null."); } fileManager = new MemoryOutputJavaFileManager(compiler.getStandardFileManager(null, null, null)); loader = new JavaFileManagerClassLoader(fileManager, parent); // create a classpath for the compiler StringBuilder b = new StringBuilder(); URL[] cp = parent.getURLs(); for (int i = 0; i < cp.length; i++) { b.append(File.pathSeparatorChar); b.append(cp[i].getFile()); } // set compiler's classpath to be same as the runtime's compilerOptions.addAll(Arrays.asList("-cp", System.getProperty("java.class.path") + b.toString())); } /** * Compiles a single source file and loads the class with a * default class loader. The default class loader is the one used * to load the test case class. * * @param name the name of the class to compile. * @param code the source code of the class. * * @return the compiled class. */ public synchronized Class<?> compileSource(String name, String code) throws Exception { Class<?> c = cache.get(name); if (c == null) { c = compileSource0(name, code); cache.put(name, c); } return c; } public synchronized Class<?> getCompiledClass(String name) { try { return Class.forName(name); } catch (ClassNotFoundException e) { try { return loader.loadClass(name); } catch (ClassNotFoundException ex) { return cache.get(name); } } } /** * Compiles multiple sources file and loads the classes. * * @param sourceFiles the source files to compile. * @param parentLoader the parent class loader to use when loading classes. * * @return a map of compiled classes. This maps class names to * Class objects. * @throws Exception * */ private Class<?> compileSource0(String className, String sourceCode) throws Exception { List<MemorySourceJavaFileObject> compUnits = new ArrayList<MemorySourceJavaFileObject>(1); compUnits.add(new MemorySourceJavaFileObject(className + ".java", sourceCode)); DiagnosticCollector<JavaFileObject> diag = new DiagnosticCollector<JavaFileObject>(); Boolean result = compiler.getTask(null, fileManager, diag, compilerOptions, null, compUnits).call(); if (result.equals(Boolean.FALSE)) { throw new RuntimeException(diag.getDiagnostics().toString()); } try { String classDotName = className.replace('/', '.'); return Class.forName(classDotName, true, loader); } catch (ClassNotFoundException e) { throw e; } } }