|
Javac |
|
1 /* 2 * 3 * Copyright (c) 1998-2001, The University of Sheffield. 4 * 5 * This file is part of GATE (see http://gate.ac.uk/), and is free 6 * software, licenced under the GNU Library General Public License, 7 * Version 2, June 1991 (in the distribution as file licence.html, 8 * and also available at http://gate.ac.uk/gate/licence.html). 9 * 10 * Valentin Tablan, 18/Feb/2002 11 * 12 * $Id: Javac.java,v 1.15 2003/07/29 12:46:53 valyt Exp $ 13 */ 14 package gate.util; 15 16 import com.sun.tools.javac.Main; 17 18 import java.io.*; 19 import java.util.*; 20 21 import gate.util.*; 22 import gate.creole.ExecutionException; 23 import gate.*; 24 25 /** 26 * This class copiles a set of java sources by accessing the java compiler 27 * from tools.jar file in the jdk. 28 * All processing is done without touching the disk. 29 */ 30 public class Javac implements GateConstants{ 31 32 /** 33 * Compiles a set of java sources and loads the compiled classes in the gate 34 * class loader. 35 * @param sources a map from fully qualified classname to java source 36 * @throws GateException in case of a compilation error or warning. 37 * In the case of warnings the compiled classes are loaded before the error is 38 * raised. 39 */ 40 public static void loadClasses(Map sources)throws GateException{ 41 if(classLoader == null) classLoader = Gate.getClassLoader(); 42 File workDir; 43 File srcDir; 44 File classesDir; 45 try{ 46 workDir = File.createTempFile("gate", ""); 47 if(!workDir.delete()) throw new GateRuntimeException( 48 "Cannot delete a temporary file!"); 49 if(! workDir.mkdir())throw new GateRuntimeException( 50 "Cannot create a temporary directory!"); 51 srcDir = new File(workDir, "src"); 52 if(! srcDir.mkdir())throw new GateRuntimeException( 53 "Cannot create a temporary directory!"); 54 classesDir = new File(workDir, "classes"); 55 if(! classesDir.mkdir())throw new GateRuntimeException( 56 "Cannot create a temporary directory!"); 57 }catch(IOException ioe){ 58 throw new ExecutionException(ioe); 59 } 60 61 List sourceFiles = new ArrayList(); 62 List sourceListings = new ArrayList(); 63 64 Iterator fileIter = sources.keySet().iterator(); 65 while(fileIter.hasNext()){ 66 String className = (String)fileIter.next(); 67 List pathComponents = getPathComponents(className); 68 String source = (String)sources.get(className); 69 File directory = getDirectory(srcDir, pathComponents); 70 String fileName = (String) pathComponents.get(pathComponents.size() - 1); 71 File srcFile = new File(directory, fileName + ".java"); 72 try{ 73 FileWriter fw = new FileWriter(srcFile); 74 fw.write(source); 75 fw.flush();fw.close(); 76 sourceFiles.add(srcFile.getCanonicalPath()); 77 sourceListings.add(source); 78 }catch(IOException ioe){ 79 throw new GateException(ioe); 80 } 81 } 82 //all source files have now been saved to disk 83 //Prepare the arguments for the javac invocation 84 List args = new ArrayList(); 85 args.add("-sourcepath"); 86 args.add(srcDir.getAbsolutePath()); 87 args.add("-d"); 88 args.add(classesDir.getAbsolutePath()); 89 //call the compiler for each class in turn so we can get the errors 90 //make a copy of the arguments in case we need to call calss by class 91 List argsSave = new ArrayList(args); 92 args.addAll(sourceFiles); 93 //steal the Err stream 94 PrintStream oldErr = System.err; 95 System.setErr(new PrintStream(new ByteArrayOutputStream())); 96 97 int res = Main.compile((String[])args.toArray(new String[args.size()])); 98 //restore the err stream 99 System.setErr(oldErr); 100 101 boolean errors = res != 0; 102 if(errors){ 103 //we got errors: call class by class 104 args = argsSave; 105 for(int i = 0; i < sourceFiles.size(); i++){ 106 String aSourceFile = (String)sourceFiles.get(i); 107 args.add(aSourceFile); 108 //call the compiler 109 res = Main.compile((String[])args.toArray(new String[args.size()])); 110 if(res != 0){ 111 //javac writes the error to System.err; let's print the source as well 112 Err.prln("\nThe offending input was:\n"); 113 String source = (String)sourceListings.get(i); 114 source = Strings.addLineNumbers(source); 115 Err.prln(source); 116 } 117 args.remove(args.size() -1); 118 } 119 120 } 121 122 // args.addAll(sourceFiles); 123 124 //load the newly compiled classes 125 //load all classes from the classes directory 126 try{ 127 loadAllClasses(classesDir, null); 128 }catch(IOException ioe){ 129 throw new GateException(ioe); 130 } 131 132 //delete the work directory 133 Files.rmdir(workDir); 134 135 if(errors) throw new GateException( 136 "There were errors; see error log for details!"); 137 } 138 139 /** 140 * Breaks a class name into path components. 141 * @param classname 142 * @return 143 */ 144 protected static List getPathComponents(String classname){ 145 //break the classname into pieces 146 StringTokenizer strTok = new StringTokenizer(classname, ".", false); 147 List pathComponents = new ArrayList(); 148 while(strTok.hasMoreTokens()){ 149 String pathComponent = strTok.nextToken(); 150 pathComponents.add(pathComponent); 151 } 152 return pathComponents; 153 } 154 155 /** 156 * Gets a file inside a parent directory from a list of path components. 157 * @param workDir 158 * @param pathComponents 159 * @return 160 */ 161 protected static File getDirectory(File workDir, List pathComponents){ 162 File currentDir = workDir; 163 for(int i = 0; i < pathComponents.size() - 1; i++){ 164 String dirName = (String)pathComponents.get(i); 165 //create a new dir in the current directory 166 currentDir = new File(currentDir, dirName); 167 if(currentDir.exists()){ 168 if(currentDir.isDirectory()){ 169 //nothing to do 170 }else{ 171 throw new GateRuntimeException( 172 "Path exists but is not a directory ( " + 173 currentDir.toString() + ")!"); 174 } 175 }else{ 176 if (!currentDir.mkdir()) 177 throw new GateRuntimeException( 178 "Cannot create a temporary directory!"); 179 } 180 } 181 return currentDir; 182 } 183 184 /** 185 * Loads the entire hierarchy of classes found in a parent directory. 186 * @param classesDirectory 187 */ 188 protected static void loadAllClasses(File classesDirectory, 189 String packageName) throws IOException{ 190 File[] files = classesDirectory.listFiles(); 191 //adjust the package name 192 if(packageName == null){ 193 //top level directory -> not a package name 194 packageName = ""; 195 }else{ 196 //internal directory -> a package name 197 packageName += packageName.length() == 0 ? 198 classesDirectory.getName() : 199 "." + classesDirectory.getName(); 200 } 201 202 for(int i = 0; i < files.length; i++){ 203 if(files[i].isDirectory()) loadAllClasses(files[i], packageName); 204 else{ 205 String filename = files[i].getName(); 206 if(filename.endsWith(".class")){ 207 String className = packageName + "." + 208 filename.substring(0, filename.length() - 6); 209 //load the class from the file 210 byte[] bytes = Files.getByteArray(files[i]); 211 classLoader.defineGateClass(className, bytes, 0, bytes.length); 212 } 213 } 214 } 215 216 } 217 protected static GateClassLoader classLoader; 218 } 219
|
Javac |
|