Java tutorial
/* * Java's Cool, IDE for French Computer Sciences Students * Copyright (C) 2012 Philippe VIENNE, INRIA * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.javascool.compiler; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import javax.tools.Diagnostic; import javax.tools.JavaFileObject; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.logging.Level; import java.util.logging.Logger; /** * Gestionnaire de compilation pour un code ayant une relation avec une Proglet. Gre d'un bout l'autre la compilation * et l'execution d'un code JVS dpendant d'une proglet. Si aucune proglet n'est communiqu alors on peut considrer que * c'est un Java pur compiler. * <p/> * La proglet JVS par dfaut est "ingredients" est en fait un code JVS qui est retranscrit en Java sans ajout de * fonctions. * * @eprecated Vous devez utiliser le compilateur du package org.javascool.manager.proglets. Celui ci n'est plus maintenu. * * @author Philippe VIENNE (PhilippeGeek@gmail.com) * @since 5.0 */ public class ProgletCodeCompiler { /** * Le rpertoire pour les compilations temporaires */ private static final File tmpDirectory = new File(FileUtils.getTempDirectory(), "javascool-compiler"); static { tmpDirectory.mkdirs(); } /** * L'identificateur de la proglet native de la version compil. */ public static final String DEFAULT_PROGLET = "ingrediants"; /** * L'identificateur de la proglet utilis. */ private String proglet; /** * Le translator de la proget. Si la proglet n'en dclare pas, alors on prend l'officiel {@link * DefaultJVSTranslator} */ private JVSTranslator translator; /** * Le compilateur utilis. */ private Compiler compiler; /** * Le fichier compiler. */ private File jvsFile; /** * Cre un compilateur pour une proglet dsign * * @param progletName Le nom de code de la proglet */ protected ProgletCodeCompiler(String progletName) { if (isDefaultProglet(progletName)) return; // On ne charge rien si c'est la proglet native assertProgletExists(progletName); proglet = progletName; } /** * Crer un compilateur pour une proglet avec un code JVS pass en argument. Ce constructeur permet de faire de la * compilation la vol sans tre oblig de pass par un Fichier. Les resources du code seront alors considr * comme tant dans le rpertoire racine de l'utilisateur. * * @param progletName Le nom de code de la proglet * @param code Le code JVS compiler */ public ProgletCodeCompiler(String progletName, String code) { this(progletName); try { File tmpFolder = new File(tmpDirectory, code.hashCode() + "-compile"); tmpFolder.mkdirs(); jvsFile = File.createTempFile("JVSCompileSource", ".jvs", tmpFolder); FileUtils.writeStringToFile(jvsFile, code); } catch (IOException e) { throw new IllegalStateException("On ne peut pas crer le fichier temporaire dans " + new File(tmpDirectory, code.hashCode() + "-compile")); } } /** * Cre un compilateur pour une proglet avec un Fichier JVS pass en argument. Ce constructeur va permtre de * controller une compilation au sein d'un rpertoire donne qui sera par la suite le rpertoire de resource du * programme. * * @param progletName Le nom de code de la proglet * @param jvsFile Le fichier JVS compiler */ public ProgletCodeCompiler(String progletName, File jvsFile) { this(progletName); assertFileExists(jvsFile); this.jvsFile = jvsFile.getAbsoluteFile(); } /** * Permet de dterminer si la proglet est celle native ou pas. <p>La proglet Native est une proglet implmentant * uniquement les specs par dfaut. C'est la proglet "ABCDAlgo" qui est aussi appel "ingrediants". Cette proglet * native n'a aucun Translator, Functions et autres artifacts dfinit.</p> <p/> <p>A contrario, les autres proglets * peuvent avoir des artifacts dfinits selon les specifications de Java's Cool. Pour les connatres, il faut aller * sur : <a href="http://javascool.github.com/doc/developper/specification.html">Le site officiel</a></p> * * @param progletName Le nom de la proglet tester * @return vrai si c'est la proglet native */ private static boolean isDefaultProglet(String progletName) { return progletName == null || progletName.equals(DEFAULT_PROGLET); } /** * Vrifie qu'un fichier existe bel et bien et que c'est un fichier * * @param file Le fichier vrifier */ private static void assertFileExists(File file) { try { if (file == null) throw new Exception(); if (!file.exists()) throw new Exception(); if (file.isDirectory()) throw new Exception(); } catch (Exception e) { throw new IllegalArgumentException("Le fichier " + file + " n'existe pas"); } } /** * Vrifie si une proglet est prsente dans le Classpath actuelle * * @param progletName Le nom de la proglet valider */ private static void assertProgletExists(String progletName) { try { IOUtils.toString(ProgletCodeCompiler.class.getClassLoader() .getResourceAsStream("org/javascool/proglets/" + progletName + "/proglet.json")); } catch (Exception e) { throw new IllegalArgumentException( "La proglet " + progletName + " n'existe pas dans le Classpath actuel."); } } /** * Lance la compilation du code. * * @return Les erreurs de compilations provenant de Java */ public ArrayList<Diagnostic<? extends JavaFileObject>> compile() { translator = getTranslatorForProglet(proglet); setUpTranslator(); translator.getJavaCode(); // On lance un premier Parse // On tablie l o sera le fichier compil String[] path = translator.getFullClassname().split("\\."); path[path.length - 1] = path[path.length - 1] + ".class"; File classFile = FileUtils.getFile(jvsFile.getParentFile(), path); classFile.getParentFile().mkdirs(); // On en fait de mme pour le fichier java path = translator.getFullClassname().split("\\."); path[path.length - 1] = path[path.length - 1] + ".java"; File javaFile = FileUtils.getFile(jvsFile.getParentFile(), path); javaFile.getParentFile().mkdirs(); // On traduit le JVS vers du Java try { FileUtils.writeStringToFile(javaFile, translator.getJavaCode()); } catch (IOException e) { throw new RuntimeException("Impossible d'crire le fichier Java", e); } compiler = new Compiler(jvsFile.getParentFile(), translator.getFullClassname()); // On compile le Java et on retourne le rsultat return compiler.compile(); } /** * Configure le translator pour lui ajouter les Imports necessaires */ private void setUpTranslator() { translator.addDefaultImports(); // On vrifie bien qu'on est dans un monde Java's Cool (Imports, Runnable ...) try { ProgletCodeCompiler.class.getClassLoader() .loadClass("org.javascool.proglets." + this.proglet + ".Functions"); translator.addImport("org.javascool.proglets." + this.proglet + ".Functions.*", true); } catch (ClassNotFoundException e) { Logger.getAnonymousLogger().log(Level.INFO, "Aucun fonction ajouter avec la proglet " + this.proglet); } // Dans ce cas on ne fais rien car il n'y a pas de Functions.java } /** * Permet d'obtenir un instance du Runnable compil. * * @return Une instance du runnable * @throws ClassNotFoundException Bien souvent, cela veut dire que la classe n'as pas pu tre compil * @throws IllegalStateException Dans le cas o une erreur impromptu survient. */ public Runnable getCompiledRunnable() throws ClassNotFoundException, IllegalStateException { Class<?> compiledClass = compiler.getClassLoader().loadClass(translator.getFullClassname()); try { return (Runnable) compiledClass.newInstance(); } catch (ClassCastException e) { throw new IllegalStateException("La classe compil n'est pas un Runnable", e); } catch (IllegalAccessException e) { throw new IllegalStateException("La classe compil n'est pas accessible", e); } catch (InstantiationException e) { throw new IllegalStateException("La classe compil ne peut pas tre cr comme objet", e); } } /** * Cherche si la proglet dfinit un Translator. Permet d'acceder aux translators des package du Classpath. * * @param progletName L'identificateur de la proglet * @return Le Translator utiliser pour cette proglet */ protected JVSTranslator getTranslatorForProglet(String progletName) { if (!isDefaultProglet(progletName)) { try { Class<?> translatorClass = ProgletCodeCompiler.class.getClassLoader() .loadClass("org.javascool.proglets." + this.proglet + ".Translator"); translator = (JVSTranslator) translatorClass.getDeclaredConstructor(File.class) .newInstance(jvsFile); } catch (ClassNotFoundException e) { Logger.getAnonymousLogger().log(Level.INFO, "Aucun Translator pour " + progletName); } // Dans ce cas on ne fais rien car il n'y a pas de Functions.java catch (Exception e) { throw new IllegalStateException("Impossible de crer un translator."); } } try { return new DefaultJVSTranslator(jvsFile); } catch (IOException e) { throw new IllegalStateException("Impossible de crer un translator sur le fichier ouvrir"); } } }