package com.baselet.element.old.custom; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.baselet.control.config.Config; import com.baselet.control.config.SharedConfig; import com.baselet.control.constants.Constants; import com.baselet.control.enums.Program; import com.baselet.control.enums.RuntimeType; import com.baselet.control.util.Path; import com.baselet.custom.CompileError; import com.baselet.element.interfaces.GridElement; import com.baselet.element.old.element.ErrorOccurred; public class CustomElementCompiler { private static final Logger log = LoggerFactory.getLogger(CustomElementCompiler.class); private static CustomElementCompiler compiler; private static final String templatefile = "Default.java"; private final String template; private final Pattern template_pattern; private Matcher template_match; private final String classname; private int beforecodelines; // lines of code before the custom code begins (for error processing) private List<CompileError> compilation_errors; private boolean global_error; public static CustomElementCompiler getInstance() { if (compiler == null) { compiler = new CustomElementCompiler(); } return compiler; } private final File sourcefile; private CustomElementCompiler() { global_error = false; compilation_errors = new ArrayList<CompileError>(); beforecodelines = 0; template_pattern = Pattern.compile("(.*)(/\\*\\*\\*\\*CUSTOM_CODE START\\*\\*\\*\\*/\n)(.*)(\n\\s\\s/\\*\\*\\*\\*CUSTOM_CODE END\\*\\*\\*\\*/)(.*)", Pattern.DOTALL); template = loadJavaSource(new File(Path.customElements() + templatefile)); if (!"".equals(template)) { template_match = template_pattern.matcher(template); try { if (template_match.matches()) { beforecodelines = template_match.group(1).split(Constants.NEWLINE).length; } else { global_error = true; } } catch (Exception ex) { ex.printStackTrace(); } } else { global_error = true; } classname = Constants.CUSTOM_ELEMENT_CLASSNAME; sourcefile = new File(Path.temp() + classname + ".java"); sourcefile.deleteOnExit(); new File(Path.temp() + classname + ".class").deleteOnExit(); } // compiles the element and returns the new entity if successful private CustomElement compile(String code) { saveJavaSource(code); CustomElement entity = null; compilation_errors.clear(); try { StringWriter compilerErrorMessageSW = new StringWriter(); // catch compiler messages PrintWriter compilerErrorMessagePW = new PrintWriter(compilerErrorMessageSW); String javaVersion = "-\"1.6\""; // custom elements use Java6 (previously SystemInfo.JAVA_VERSION, but this only works if the compiler.jar supports the system java version which is not guaranteed) String classpath = "-classpath \"" + createClasspath() + "\""; String sourcefile = "\"" + this.sourcefile.getAbsolutePath() + "\""; // Compiler Information at http://dev.eclipse.org/viewcvs/index.cgi/jdt-core-home/howto/batch%20compile/batchCompile.html?revision=1.7 @SuppressWarnings("deprecation") boolean compilationSuccessful = org.eclipse.jdt.internal.compiler.batch.Main.compile( javaVersion + " " + classpath + " " + sourcefile, new PrintWriter(System.out), compilerErrorMessagePW); if (compilationSuccessful) { FileClassLoader fcl = new FileClassLoader(Thread.currentThread().getContextClassLoader()); Class<?> c = fcl.findClass(classname); // load class by type name if (c != null) { entity = (CustomElement) c.newInstance(); } } else { compilation_errors = CompileError.getListFromString(compilerErrorMessageSW.toString(), beforecodelines); } } catch (Exception e) { log.error(null, e); } if (entity == null) { entity = new CustomElementWithErrors(compilation_errors); } return entity; } private String createClasspath() { // If the Eclipse Plugin is started from Eclipse (for debugging), the other projects are linked source dirs and therefore all classes are in the same target dir if (!Path.executable().endsWith(".jar") && Program.getInstance().getRuntimeType() == RuntimeType.ECLIPSE_PLUGIN) { return Path.executable() + "target/classes"; } else { return Path.executable() + "\"" + File.pathSeparator + "\"" + Path.executableShared(); } } // loads the source from a file private String loadJavaSource(File sourceFile) { // LME3 StringBuilder sb = new StringBuilder(""); if (sourceFile != null && sourceFile.getName().endsWith(".java")) { try { BufferedReader br = new BufferedReader(new FileReader(sourceFile)); String line; while ((line = br.readLine()) != null) { sb.append(line).append(Constants.NEWLINE); } br.close(); } catch (Exception e) { log.error(null, e); } } return sb.toString().replaceAll("\r\n", Constants.NEWLINE); } // saves the source to a file private void saveJavaSource(String code) { // LME3 BufferedWriter bw = null; try { bw = new BufferedWriter(new FileWriter(sourcefile, false)); bw.write(parseCodeIntoTemplate(code)); bw.flush(); } catch (IOException e) { log.error(null, e); } finally { if (bw != null) { try { bw.close(); } catch (IOException e) { e.printStackTrace(); } } } } private String parseCodeFromTemplate(String template) { Matcher m = template_pattern.matcher(template); if (m.matches()) { return m.group(3); } else { return ""; } } private String parseCodeIntoTemplate(String code) { return template_match.group(1).replaceFirst("<!CLASSNAME!>", classname) + template_match.group(2) + code + template_match.group(4) + template_match.group(5); } public GridElement genEntity(String code, ErrorHandler errorhandler) { if (!Config.getInstance().isEnable_custom_elements()) { String errorMessage = "Custom Elements are disabled\nEnabled them in the Options\nOnly open them from trusted\nsources to avoid malicious code execution!"; if (SharedConfig.getInstance().isDev_mode()) { errorMessage += "\n------------------------------------\n" + code; } return new ErrorOccurred(errorMessage); } if (global_error) { return new ErrorOccurred(); } if (code == null) { code = parseCodeFromTemplate(template); } CustomElement element = compile(code); if (errorhandler != null) { errorhandler.addErrors(compilation_errors); } element.setCode(code); return element; } public GridElement genEntity(String code) { return this.genEntity(code, null); } public GridElement genEntityFromTemplate(String templatename, ErrorHandler errorhandler) { String template = loadJavaSource(new File(Path.customElements() + templatename + ".java")); if (!"".equals(template)) { return this.genEntity(parseCodeFromTemplate(template), errorhandler); } return null; } }