blob: eddf088f86201e098c91ffbf636db2692f8f6f38 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 itemis AG (http://www.itemis.eu) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package com.itemis.xtext.codebuff;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import org.apache.log4j.Logger;
import org.eclipse.emf.common.util.WrappedException;
import com.google.common.collect.Lists;
import com.google.common.io.Files;
public class Antlr4ToolFacade {
private static final String TARGETTOCOPYTOKENSTO = "/org/antlr/codebuff/";
private static final String SRC_GEN = "/src-gen/";
private static final String ORG_ANTLR_CODEBUFF = "org.antlr.codebuff";
private final static Logger log = Logger.getLogger(Antlr4ToolFacade.class);
public final static String className = "org.antlr.v4.Tool";
private ClassLoader loader = Antlr4ToolFacade.class.getClassLoader();
public void setLoader(ClassLoader loader) {
this.loader = loader;
}
private String downloadURL = "http://central.maven.org/maven2/org/antlr/antlr4/4.5.3/antlr4-4.5.3.jar";
private boolean askBeforeDownload = true;
public static final String ANTLR4GEN = "antlr4gen";
public static final String TARGETFOLDER = ANTLR4GEN + "/target/";
public void setAskBeforeDownload(boolean shouldAsk) {
this.askBeforeDownload = shouldAsk;
}
public void setDownloadFrom(String downloadURL) {
this.downloadURL = downloadURL;
}
private String downloadTo = "./antlr-4.5.3.jar";
public void setDownloadTo(String path) {
this.downloadTo = path;
}
protected File file() {
return new File(downloadTo);
}
protected String getToolRunnerClassName() {
return className;
}
protected ClassLoader initializedClassLoader() {
try {
loader.loadClass(getToolRunnerClassName());
return loader;
} catch (ClassNotFoundException e) {
if (!file().exists()) {
if (!download())
return null;
}
if (file().exists()) {
try {
URL url = file().toURI().toURL();
loader = new URLClassLoader(new URL[] { url }, null);
return loader;
} catch (MalformedURLException e1) {
log.error(e1.getMessage(), e1);
}
}
return null;
}
}
public boolean download() {
try {
if (askBeforeDownload) {
boolean ok = false;
while (!ok) {
System.err.print(
"\n*ATTENTION*\nIt is recommended to use the ANTLR 4 parser generator (BSD licence - http://www.antlr.org/license.html).\nDo you agree to download it (size 1MB) from '"
+ downloadURL + "'? (type 'y' or 'n' and hit enter)");
int read = System.in.read();
if (read == 'n') {
return false;
} else if (read == 'y') {
ok = true;
}
}
}
log.info("downloading file from '" + downloadURL + "' ...");
BufferedInputStream in = new BufferedInputStream(new URL(downloadURL).openStream());
try {
FileOutputStream out = new FileOutputStream(file());
try {
byte[] buffer = new byte[2048];
int readBytes = -1;
while ((readBytes = in.read(buffer)) != -1) {
out.write(buffer, 0, readBytes);
}
} finally {
out.close();
}
} finally {
in.close();
}
log.info("finished downloading.");
} catch (IOException e) {
System.err.println("Downloading ANTLR4 parser generator failed: " + e.getMessage());
return false;
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
if (initializedClassLoader() == null) {
log.error("Loaded jar doesn't contain " + className);
return false;
}
return true;
}
private IllegalStateException getNoClassFoundException() {
return new IllegalStateException("Couldn't find ANTLR generator on class path. Please download manually from '"
+ downloadURL + "' and put it on the classpath.");
}
public void runWithEncodingAndParams(String grammarFullPath, String explicitEncoding) {
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
try {
ClassLoader myLoader = initializedClassLoader();
Thread.currentThread().setContextClassLoader(myLoader);
Class<?> class1 = myLoader.loadClass(className);
if (class1 == null)
throw getNoClassFoundException();
Object[] args = new Object[] { new String[] { grammarFullPath, "-o", ANTLR4GEN + SRC_GEN, "-package", ORG_ANTLR_CODEBUFF } };
Constructor<?> constructor = class1.getConstructor(new Class[] { String[].class });
Object newInstance = constructor.newInstance(args);
log.info("Loading AntLR 4 grammar.");
Method loadGrammar = class1.getMethod("loadGrammar", new Class[] { String.class });
Object grammar = loadGrammar.invoke(newInstance, grammarFullPath);
//Method process = class1.getMethod("process", new Class[] { grammar.getClass(), boolean.class });
Method process = class1.getMethod("processGrammarsOnCommandLine");
log.info("Generate AntLR 4 parser.");
//process.invoke(newInstance, grammar, true);
process.invoke(newInstance);
// Compile to code to target folder!
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
File src_gen_folder = new File("./" + ANTLR4GEN + SRC_GEN);
ArrayList<File> filesToCompile = Lists.newArrayList();
for (File child : src_gen_folder.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith("java");
}
})) {
filesToCompile.add(child);
}
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
Iterable<? extends JavaFileObject> javaFileObjectsFromFiles = fileManager
.getJavaFileObjectsFromFiles(filesToCompile);
List<String> optionList = new ArrayList<String>();
// set compiler's classpath to be same as the runtime's
optionList.addAll(Arrays.asList("-classpath",
System.getProperty("java.class.path") + ";" + file().getAbsolutePath(), "-d", TARGETFOLDER));
log.info("Compile AntLR 4 Parser with optionList "+ optionList.toString());
compiler.getTask(null, fileManager, null, optionList, null, javaFileObjectsFromFiles).call();
fileManager.close();
for( File child : src_gen_folder.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith("tokens");
}
})) {
Files.copy(child, new File(TARGETFOLDER + TARGETTOCOPYTOKENSTO + child.getName()));
}
} catch (Exception e) {
throw new WrappedException(e);
} finally {
Thread.currentThread().setContextClassLoader(contextClassLoader);
}
}
public boolean isWorkable() {
return initializedClassLoader() != null;
}
}