001 /*
002 Copyright (c) 2009 Olivier Chafik, All Rights Reserved
003
004 This file is part of JNAerator (http://jnaerator.googlecode.com/).
005
006 JNAerator is free software: you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation, either version 3 of the License, or
009 (at your option) any later version.
010
011 JNAerator is distributed in the hope that it will be useful,
012 but WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014 GNU General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with JNAerator. If not, see <http://www.gnu.org/licenses/>.
018 */
019 package com.ochafik.lang.compiler;
020
021 import java.util.*;
022 import java.util.regex.Pattern;
023 import java.io.*;
024 import java.net.MalformedURLException;
025 import java.net.URL;
026 import java.net.URLConnection;
027 import java.net.URLDecoder;
028
029 import javax.tools.*;
030 import javax.tools.Diagnostic.Kind;
031
032 import com.ochafik.io.IOUtils;
033 import com.ochafik.util.listenable.Adapter;
034 import com.ochafik.util.string.RegexUtils;
035 import com.ochafik.util.string.StringUtils;
036
037 public class CompilerUtils {
038
039 public static String getClassPath(Class<?> c, File cacheDirectory) throws MalformedURLException, IOException {
040
041 URL resource = c.getResource(c.getSimpleName() + ".class");
042 if (resource != null) {
043 String resstr = resource.toString();
044 // if (resstr.contains("Prog/"))
045 // resstr = "jar:http://ochafik.free.fr/Java/jnaerator.jar!/...";
046
047 if (resstr.matches("jar:.*!.*"))
048 resstr = resstr.substring("jar:".length(), resstr.indexOf("!"));
049 else {
050 String p = '/' + c.getName().replace('.', '/') + ".class";
051 if (resstr.endsWith(p))
052 resstr = resstr.substring(0, resstr.length() - p.length());
053 }
054 return getLocalFile(new URL(resstr), cacheDirectory).toString();
055 }
056 /*
057 if (resource != null) {
058 String resstr = resource.toString();
059 if (resstr.matches("jar:file:.*!.*"))
060 return resstr.substring("jar:file:".length(), resstr.indexOf("!"));
061 else if (resstr.matches("jar:http:.*!.*"))
062 return resstr.substring("jar:".length(), resstr.indexOf("!"));
063 else {
064 String p = '/' + c.getName().replace('.', '/') + ".class";
065 if (resstr.endsWith(p))
066 return resstr.substring(0, resstr.length() - p.length());
067 }
068 }*/
069 return null;
070 }
071 public static Set<String> getClassPaths(File cacheDirectory, Class<?>... cs) throws MalformedURLException, IOException {
072 Set<String> ret = new TreeSet<String>();
073 for (Class<?> c : cs) {
074 String cp ;
075 if (c == null || (cp = getClassPath(c, cacheDirectory)) == null)
076 continue;
077 ret.add(cp);
078 }
079 return ret;
080 }
081 static Map<String, File> localURLCaches = new HashMap<String, File>();
082 static File getLocalFile(URL remoteFile, File cacheDirectory) throws IOException {
083 if ("file".equals(remoteFile.getProtocol()))
084 return new File(URLDecoder.decode(remoteFile.getFile(), "utf-8"));
085
086 String remoteStr = remoteFile.toString();
087 File f = localURLCaches.get(remoteStr);
088 if (f == null) {
089 String fileName = new File(remoteStr).getName();
090 URLConnection con = null;
091 try {
092 con = remoteFile.openConnection();
093 } catch (IOException ex) {
094 ex.printStackTrace();
095 }
096 if (cacheDirectory != null) {
097 f = new File(cacheDirectory, fileName);
098 if (f.exists() && (con == null || f.lastModified() > con.getLastModified())) {
099 System.out.println("Reusing cached file " + f);
100 if (con != null)
101 con.getInputStream().close();
102 return f;
103 }
104 } else {
105 f = File.createTempFile(fileName, ".jar");
106 f.deleteOnExit();
107 }
108 System.out.print("Downloading file " + remoteFile + " to " + f);
109
110 InputStream in = new BufferedInputStream(remoteFile.openStream());
111 try {
112 OutputStream out = new BufferedOutputStream(new FileOutputStream(f));
113 try {
114 //System.out.print("Downloading file '" + remoteStr + "'...");
115 long length = IOUtils.readWrite(in, out);
116 System.out.println(" OK (" + length + " bytes)");
117 localURLCaches.put(remoteStr, f.getAbsoluteFile());
118 } finally {
119 out.close();
120 }
121 } finally {
122 in.close();
123 }
124 }
125 return f;
126 }
127 public static void compile(JavaCompiler compiler, MemoryFileManager fileManager, DiagnosticCollector<JavaFileObject> diagnostics, String sourceCompatibility, File cacheDirectory, Class<?>...classpathHints) throws MalformedURLException, IOException {
128 //JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
129 System.out.println("compiler = " + (compiler == null ? "<none found>" : compiler.getClass().getName()));
130 Set<String> bootclasspaths = getClassPaths(cacheDirectory, classpathHints);
131 bootclasspaths.addAll(getClassPaths(cacheDirectory, String.class));
132 String bootclasspath = StringUtils.implode(bootclasspaths, File.pathSeparator);
133 System.out.println("bootclasspath = " + bootclasspath);
134 Iterable<? extends JavaFileObject> fileObjects = fileManager.getJavaFileObjects();
135 List<String> options = sourceCompatibility == null ? null : Arrays.asList(
136 "-target", sourceCompatibility,
137 "-source", sourceCompatibility,
138 "-bootclasspath", bootclasspath, //"/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Classes/classes.jar",//bootclasspath,
139 "-classpath", bootclasspath //"/Users/ochafik/Prog/Java/bin/jnaerator.jar"//
140 //"http://ochafik.free.fr/Java/jnaerator.jar"//bootclasspath
141 );
142 // DebugUtils.println(fileManager.inputs.values());
143 compiler.getTask(null, fileManager, diagnostics, options, null, fileObjects).call();
144
145 // for (final Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
146 // if (diagnostic == null)
147 // continue;
148 // //diagnostic.getKind()
149 // //System.out.format("Error on line %d in %d%n", diagnostic.getLineNumber(), diagnostic.getSource());//.toUri());
150 // if (diagnostic.getKind() == Kind.ERROR) {
151 // System.err.println("\n" + diagnostic.getSource().toUri() + ":");
152 // System.err.println(RegexUtils.regexReplace(Pattern.compile("\n"), "\n" + diagnostic.getSource().getCharContent(true), new Adapter<String[], String>() {
153 // int line = 0;
154 //
155 // @Override
156 // public String adapt(String[] value) {
157 // line++;
158 // return "\n" + line + ":" + (diagnostic.getLineNumber() == line ? ">>>" : "") +"\t\t";
159 // }
160 // }));
161 // }
162 //// System.out.println("Error on line " + diagnostic.getLineNumber() + ":" + diagnostic.getColumnNumber() + " in " + (diagnostic.getSource() == null ? "<unknown source>" : diagnostic.getSource().getName()) + ": " + diagnostic.getMessage(Locale.getDefault()));
163 // }
164 }
165
166 public static JavaCompiler getJavaCompiler(boolean preferJavac) throws FileNotFoundException {
167 JavaCompiler compiler;
168 if (preferJavac) {
169 compiler = ToolProvider.getSystemJavaCompiler();
170 if (compiler != null)
171 return compiler;
172 }
173 try {
174 compiler = (JavaCompiler)Class.forName("org.eclipse.jdt.internal.compiler.tool.EclipseCompiler").newInstance();
175 } catch (Exception e) {
176 compiler = ToolProvider.getSystemJavaCompiler();
177 if (compiler == null)
178 throw new FileNotFoundException("No Java compiler found (not run from JDK, no Eclipse Compiler in classpath)");
179 }
180 return compiler;
181 }
182 public static void main2(String[] args) {
183 try {
184 String jarOut = args.length == 0 ? "out.jar" : args[0];
185
186 JavaCompiler compiler = getJavaCompiler(false);
187
188 DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
189 MemoryFileManager fileManager = new MemoryFileManager(compiler.getStandardFileManager(diagnostics, null, null));
190 fileManager.addSourceInput("test/Main.java", "package test; public class Main { }");
191 fileManager.close();
192
193 compile(compiler, fileManager, diagnostics, null, null);
194 for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
195 //diagnostic.getKind()
196 //System.out.format("Error on line %d in %d%n", diagnostic.getLineNumber(), diagnostic.getSource());//.toUri());
197 System.out.format("Error on line " + diagnostic.getLineNumber() + ":" + diagnostic.getLineNumber() + " in " + diagnostic.getSource());//.toUri());
198 }
199
200 boolean outputSources = true;
201 System.out.println("Writing " + jarOut + (outputSources ? " with" : " without") + " sources");
202 fileManager.writeJar(new FileOutputStream(jarOut), outputSources, null);
203
204 } catch (IOException ex) {
205 ex.printStackTrace();
206 }
207 }
208 }
209