2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2010 - 2011 - Calixte DENIZET <calixte@contrib.scilab.org>
5 * This file must be used under the terms of the CeCILL.
6 * This source file is licensed as described in the file COPYING, which
7 * you should have received as part of this distribution. The terms
8 * are also available at
9 * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
13 package org.scilab.modules.external_objects_java;
16 import java.io.FileReader;
17 import java.io.IOException;
18 import java.io.StringWriter;
19 import java.lang.reflect.InvocationTargetException;
20 import java.lang.reflect.Method;
21 import java.net.MalformedURLException;
23 import java.net.URLClassLoader;
25 import java.util.Arrays;
26 import java.util.ArrayList;
27 import java.util.List;
28 import java.util.Locale;
29 import java.util.ServiceLoader;
30 import java.util.logging.Level;
32 import javax.tools.Diagnostic;
33 import javax.tools.DiagnosticCollector;
34 import javax.tools.FileObject;
35 import javax.tools.ForwardingJavaFileManager;
36 import javax.tools.JavaCompiler;
37 import javax.tools.JavaFileObject;
38 import javax.tools.SimpleJavaFileObject;
39 import javax.tools.StandardJavaFileManager;
40 import javax.tools.ToolProvider;
41 import javax.tools.JavaCompiler.CompilationTask;
42 import javax.tools.JavaFileObject.Kind;
45 * Class to provide a java compiler to JIMS.
46 * Try to find the compiler provide with JDK and if it is not found, use the Eclipse Compiler for Java
47 * @author Calixte DENIZET
49 @SuppressWarnings("serial")
50 public class ScilabJavaCompiler {
52 private static final String JAVACOMPILER = "javax.tools.JavaCompiler";
53 private static final String BINPATH = System.getProperty("java.io.tmpdir") + File.separator + "JIMS" + File.separator + "bin";
55 private static JavaCompiler compiler;
58 new File(System.getProperty("java.io.tmpdir") + File.separator + "JIMS").mkdir();
59 new File(BINPATH).mkdir();
61 URL binURL = new File(BINPATH).toURI().toURL();
62 addURLToClassPath(binURL);
63 } catch (MalformedURLException e) {
64 System.err.println(e);
69 * Just find a compiler
71 private static void findCompiler() throws ScilabJavaException {
72 if (compiler == null) {
74 compiler = ToolProvider.getSystemJavaCompiler();
75 } catch (Exception e) { }
77 if (compiler == null) {
78 ServiceLoader<JavaCompiler> jcompilers = ServiceLoader.load(JavaCompiler.class);
79 for (JavaCompiler jc : jcompilers) {
87 if (compiler == null) {
88 throw new ScilabJavaException("No java compiler in the classpath\nCheck for tools.jar (comes from JDK) or ecj-3.6.x.jar (Eclipse Compiler for Java)");
94 * Compile code got as string
95 * @param className the class name
96 * @param code the lines giving the code to compile
97 * @return an integer corresponding to the compiled and loaded class.
99 public static int compileCode(String className, String[] code) throws ScilabJavaException {
102 DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
103 StandardJavaFileManager stdFileManager = compiler.getStandardFileManager(null, Locale.getDefault(), null);
104 ClassFileManager manager = new ClassFileManager(stdFileManager);
105 List<SimpleJavaFileObject> compilationUnits = new ArrayList<SimpleJavaFileObject>();
106 boolean isFile = true;
107 SourceString sourceString = null;
108 for (String s : code) {
109 File f = new File(s);
110 if (!f.exists() || !f.canRead()) {
117 for (String s : code) {
118 File f = new File(s);
119 compilationUnits.add(new SourceFile(f));
122 sourceString = new SourceString(className, code);
123 compilationUnits.add(sourceString);
126 String[] compileOptions = new String[] {"-d", BINPATH} ;
127 Iterable<String> options = Arrays.asList(compileOptions);
129 CompilationTask task = compiler.getTask(null, manager, diagnostics, options, null, compilationUnits);
130 boolean success = task.call();
136 return ScilabClassLoader.loadJavaClass(manager.className, true);
139 StringBuffer buf = new StringBuffer();
140 for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
141 buf.append(diagnostic.toString());
145 throw new ScilabJavaException(buf.toString());
150 * Add a class in the classpath
151 * @param url the class url
153 public static void addURLToClassPath(URL url) {
154 URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
156 final Method method = URLClassLoader.class.getDeclaredMethod("addURL", new Class[] {URL.class});
157 method.setAccessible(true);
158 method.invoke(sysloader , new Object[] {url});
159 } catch (NoSuchMethodException e) {
160 System.err.println("Error: Cannot find the declared method: " + e.getLocalizedMessage());
161 } catch (IllegalAccessException e) {
162 System.err.println("Error: Illegal access: " + e.getLocalizedMessage());
163 } catch (InvocationTargetException e) {
164 System.err.println("Error: Could not invocate target: " + e.getLocalizedMessage());
169 * Inner class to handle String as File
171 private static class SourceString extends SimpleJavaFileObject {
173 private final String code;
175 private SourceString(String className, String[] code) {
176 super(new File(BINPATH + "/" + className.replace('.', '/') + Kind.SOURCE.extension).toURI(), Kind.SOURCE);
178 StringBuffer buf = new StringBuffer();
179 for (String str : code) {
183 this.code = buf.toString();
186 public CharSequence getCharContent(boolean ignoreEncodingErrors) {
192 * Inner class to handle String as File
194 private static class SourceFile extends SimpleJavaFileObject {
198 private SourceFile(File f) {
199 super(f.toURI(), Kind.SOURCE);
203 public CharSequence getCharContent(boolean ignoreEncodingErrors) {
205 FileReader reader = new FileReader(f);
206 char[] buffer = new char[1024];
207 StringBuffer sb = new StringBuffer();
210 while ((r = reader.read(buffer, 0, 1024)) != -1) {
211 sb.append(buffer, 0, r);
217 } catch (Exception e) {
223 private static class ClassFileManager extends ForwardingJavaFileManager {
227 public ClassFileManager(StandardJavaFileManager standardManager) {
228 super(standardManager);
232 public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
233 if (sibling instanceof SourceString) {
234 this.className = className.replace('/', '.');
237 if (ScilabJavaObject.debug) {
238 ScilabJavaObject.logger.log(Level.INFO, "Compilation of class \'" + className + "\'");
241 return super.getJavaFileForOutput(location, className, kind, sibling);