/**
*
*/
package it.xsemantics.dsl.tests;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.emf.common.util.WrappedException;
import org.eclipse.jdt.core.compiler.CompilationProgress;
import org.eclipse.jdt.internal.compiler.batch.FileSystem;
import org.eclipse.jdt.internal.compiler.batch.Main;
import org.eclipse.xtext.util.Files;
import org.eclipse.xtext.xbase.compiler.OnTheFlyJavaCompiler;
import com.google.inject.Inject;
/**
* @author Lorenzo Bettini
*
*/
public class XsemanticsOnTheFlyJavaCompiler extends OnTheFlyJavaCompiler {
static class DelegateOutStream extends OutputStream {
private OutputStream delegate;
@Override
public void close() throws IOException {
delegate.close();
}
@Override
public boolean equals(Object obj) {
return delegate.equals(obj);
}
@Override
public void flush() throws IOException {
delegate.flush();
}
@Override
public int hashCode() {
return delegate.hashCode();
}
public void setDelegate(OutputStream delegate) {
this.delegate = delegate;
}
@Override
public String toString() {
return delegate.toString();
}
@Override
public void write(byte[] b) throws IOException {
delegate.write(b);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
delegate.write(b, off, len);
}
@Override
public void write(int b) throws IOException {
delegate.write(b);
}
}
/**
* HACK - reuse the classpath, since it is super expensive to reopen and
* scan the zips.
*
* @author Sven Efftinge - Initial contribution and API
*/
static class PatchedMain extends Main {
@SuppressWarnings("rawtypes")
public PatchedMain(PrintWriter outWriter, PrintWriter errWriter,
boolean systemExitWhenFinished, Map customDefaultOptions,
CompilationProgress compilationProgress) {
super(outWriter, errWriter, systemExitWhenFinished,
customDefaultOptions, compilationProgress);
}
@Override
public FileSystem getLibraryAccess() {
if (fileSystem == null) {
fileSystem = new PatchedFileSystem(super.getLibraryAccess());
}
return fileSystem;
}
}
private static PatchedFileSystem fileSystem;
private DelegateOutStream errorStream = new DelegateOutStream();
@Inject
private ClassLoader parentClassLoader;
@Override
public String getClasspathArgs() {
final String classpathArgs = super.getClasspathArgs();
return classpathArgs
+ (classpathArgs.isEmpty() ? "" : File.pathSeparator
+ createTempDir().getAbsolutePath()
+ File.separator);
}
@Override
protected Main getMain() {
return new PatchedMain(new PrintWriter(new OutputStreamWriter(
System.out)), new PrintWriter(new OutputStreamWriter(
errorStream)), false /* systemExit */, null /* options */, null);
}
// /**
// * Copied from {@link OnTheFlyJavaCompiler}
// * we don't need this anymore since it's accessible now
// *
// * @return
// */
// @Override
// protected File createTempDir() {
// File rootTempDir = null;
// String defTmpPath = System.getProperty("java.io.tmpdir");
// if (defTmpPath != null) {
// rootTempDir = new File(defTmpPath);
// } else {
// // use current directory, should be writable
// rootTempDir = new File("./");
// }
// // VM unique temp dir
// File tempDir = new File(rootTempDir, "otfjc"
// + OnTheFlyJavaCompiler.class.hashCode());
// return tempDir;
// }
@Override
public Class<?> compileToClass(String classname, String code) {
File tempDir = createTempDir();
final String classNameAsPath = classname.replace('.',
File.separatorChar);
final File srcFile = new File(tempDir, classNameAsPath + ".java");
createFolderStructure(srcFile.getParentFile());
final File targetFile = new File(tempDir, classNameAsPath + ".class");
if (targetFile.exists())
targetFile.delete();
try {
srcFile.createNewFile();
Files.writeStringIntoFile(srcFile.getCanonicalPath(), code);
errorStream.setDelegate(new ByteArrayOutputStream());
StringBuilder sb = new StringBuilder(getComplianceLevelArg());
sb.append(" ");
sb.append(getClasspathArgs());
sb.append(" ");
sb.append('\"');
sb.append(srcFile.getCanonicalPath());
sb.append('\"');
boolean compile = compile(sb.toString());
if (!compile)
throw new IllegalArgumentException("Couldn't compile : "
+ errorStream.toString() + "\n" + code);
final URL url = tempDir.toURI().toURL();
URLClassLoader loader = new URLClassLoader(new URL[] { url },
parentClassLoader);
Class<?> class1 = loader.loadClass(classname);
return class1;
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new WrappedException(e);
} finally {
cleanUpTmpFolder(tempDir);
}
}
protected void cleanUpTmpFolder(File tempDir) {
try {
Files.cleanFolder(tempDir, new FileFilter() {
public boolean accept(File pathname) {
return !pathname.getName().endsWith(".class");
}
}, true, true);
} catch (FileNotFoundException e) {
// ignore
}
}
public void compileAll(Map<String, String> toCompile) {
File tempDir = createTempDir();
StringBuilder fileNamesToCompile = new StringBuilder();
try {
for (Entry<String, String> sourceToCompile : toCompile.entrySet()) {
final String classNameAsPath = sourceToCompile.getKey().replace('.',
File.separatorChar);
final File srcFile = new File(tempDir, classNameAsPath + ".java");
createFolderStructure(srcFile.getParentFile());
final File targetFile = new File(tempDir, classNameAsPath + ".class");
if (targetFile.exists())
targetFile.delete();
srcFile.createNewFile();
Files.writeStringIntoFile(srcFile.getCanonicalPath(), sourceToCompile.getValue());
fileNamesToCompile.append(" ");
fileNamesToCompile.append('\"');
fileNamesToCompile.append(srcFile.getCanonicalPath());
fileNamesToCompile.append('\"');
}
errorStream.setDelegate(new ByteArrayOutputStream());
StringBuilder sb = new StringBuilder(getComplianceLevelArg());
sb.append(" ");
sb.append(getClasspathArgs());
sb.append(" ");
sb.append(fileNamesToCompile);
boolean compile = compile(sb.toString());
if (!compile)
throw new IllegalArgumentException("Couldn't compile : "
+ errorStream.toString() + "\n" + fileNamesToCompile);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new WrappedException(e);
} finally {
cleanUpTmpFolder(tempDir);
}
}
}