/*
* Copyright 2010, Mysema Ltd
*
* 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 com.mysema.codegen;
import java.io.*;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.jar.Manifest;
import javax.lang.model.SourceVersion;
import javax.tools.*;
import com.google.common.base.Joiner;
/**
* SimpleCompiler provides a convenience wrapper of the JavaCompiler interface
* with automatic classpath generation
*
* @author tiwe
*
*/
public class SimpleCompiler implements JavaCompiler {
private static final Joiner pathJoiner = Joiner.on(File.pathSeparator);
protected static boolean isSureFireBooter(URLClassLoader cl) {
for (URL url : cl.getURLs()) {
if (url.getPath().contains("surefirebooter")) {
return true;
}
}
return false;
}
public static String getClassPath(URLClassLoader cl) {
try {
List<String> paths = new ArrayList<String>();
if (isSureFireBooter(cl)) {
// extract MANIFEST.MF Class-Path entry, since the Java Compiler doesn't handle
// manifest only jars in the classpath correctly
URL url = cl.findResource("META-INF/MANIFEST.MF");
Manifest manifest = new Manifest(url.openStream());
String classpath = manifest.getMainAttributes().getValue("Class-Path");
for (String entry : classpath.split(" ")) {
URL entryUrl = new URL(entry);
String decodedPath = URLDecoder.decode(entryUrl.getPath(), "UTF-8");
paths.add(new File(decodedPath).getAbsolutePath());
}
} else {
ClassLoader c = cl;
while (c instanceof URLClassLoader) {
for (URL url : ((URLClassLoader)c).getURLs()) {
String decodedPath = URLDecoder.decode(url.getPath(), "UTF-8");
paths.add(new File(decodedPath).getAbsolutePath());
}
c = c.getParent();
}
}
return pathJoiner.join(paths);
} catch (UnsupportedEncodingException e) {
throw new CodegenException(e);
} catch (IOException e) {
throw new CodegenException(e);
}
}
private final ClassLoader classLoader;
private String classPath;
private final JavaCompiler compiler;
public SimpleCompiler() {
this(ToolProvider.getSystemJavaCompiler(), Thread.currentThread().getContextClassLoader());
}
public SimpleCompiler(JavaCompiler compiler, ClassLoader classLoader) {
this.compiler = compiler;
this.classLoader = classLoader;
}
private String getClasspath() {
if (classPath == null) {
if (classLoader instanceof URLClassLoader) {
classPath = getClassPath((URLClassLoader) classLoader);
} else {
throw new IllegalArgumentException("Unsupported ClassLoader " + classLoader);
}
}
return classPath;
}
@Override
public Set<SourceVersion> getSourceVersions() {
return compiler.getSourceVersions();
}
@Override
public StandardJavaFileManager getStandardFileManager(
DiagnosticListener<? super JavaFileObject> diagnosticListener, Locale locale,
Charset charset) {
return compiler.getStandardFileManager(diagnosticListener, locale, charset);
}
@Override
public CompilationTask getTask(Writer out, JavaFileManager fileManager,
DiagnosticListener<? super JavaFileObject> diagnosticListener,
Iterable<String> options, Iterable<String> classes,
Iterable<? extends JavaFileObject> compilationUnits) {
return compiler.getTask(out, fileManager, diagnosticListener, options, classes,
compilationUnits);
}
@Override
public int isSupportedOption(String option) {
return compiler.isSupportedOption(option);
}
@Override
public int run(InputStream in, OutputStream out, OutputStream err, String... arguments) {
for (String a : arguments) {
if (a.equals("-classpath")) {
return compiler.run(in, out, err, arguments);
}
}
// no classpath given
List<String> args = new ArrayList<String>(arguments.length + 2);
args.add("-classpath");
args.add(getClasspath());
for (String arg : arguments) {
args.add(arg);
}
return compiler.run(in, out, err, args.toArray(new String[args.size()]));
}
}