001: /*
002: License $Id: CompilerFactory.java,v 1.13 2005/01/02 22:02:30 hendriks73 Exp $
003:
004: Copyright (c) 2001-2005 tagtraum industries.
005:
006: LGPL
007: ====
008:
009: jo! is free software; you can redistribute it and/or
010: modify it under the terms of the GNU Lesser General Public
011: License as published by the Free Software Foundation; either
012: version 2.1 of the License, or (at your option) any later version.
013:
014: jo! is distributed in the hope that it will be useful,
015: but WITHOUT ANY WARRANTY; without even the implied warranty of
016: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017: Lesser General Public License for more details.
018:
019: You should have received a copy of the GNU Lesser General Public
020: License along with this library; if not, write to the Free Software
021: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
022:
023: For LGPL see <http://www.fsf.org/copyleft/lesser.txt>
024:
025:
026: Sun license
027: ===========
028:
029: This release contains software by Sun Microsystems. Therefore
030: the following conditions have to be met, too. They apply to the
031: files
032:
033: - lib/mail.jar
034: - lib/activation.jar
035: - lib/jsse.jar
036: - lib/jcert.jar
037: - lib/jaxp.jar
038: - lib/crimson.jar
039: - lib/servlet.jar
040: - lib/jnet.jar
041: - lib/jaas.jar
042: - lib/jaasmod.jar
043:
044: contained in this release.
045:
046: a. Licensee may not modify the Java Platform
047: Interface (JPI, identified as classes contained within the javax
048: package or any subpackages of the javax package), by creating additional
049: classes within the JPI or otherwise causing the addition to or modification
050: of the classes in the JPI. In the event that Licensee creates any
051: Java-related API and distribute such API to others for applet or
052: application development, you must promptly publish broadly, an accurate
053: specification for such API for free use by all developers of Java-based
054: software.
055:
056: b. Software is confidential copyrighted information of Sun and
057: title to all copies is retained by Sun and/or its licensors. Licensee
058: shall not modify, decompile, disassemble, decrypt, extract, or otherwise
059: reverse engineer Software. Software may not be leased, assigned, or
060: sublicensed, in whole or in part. Software is not designed or intended
061: for use in on-line control of aircraft, air traffic, aircraft navigation
062: or aircraft communications; or in the design, construction, operation or
063: maintenance of any nuclear facility. Licensee warrants that it will not
064: use or redistribute the Software for such purposes.
065:
066: c. Software is provided "AS IS," without a warranty
067: of any kind. ALL EXPRESS OR IMPLIED REPRESENTATIONS AND WARRANTIES,
068: INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
069: PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
070:
071: d. This License is effective until terminated. Licensee may
072: terminate this License at any time by destroying all copies of Software.
073: This License will terminate immediately without notice from Sun if Licensee
074: fails to comply with any provision of this License. Upon such termination,
075: Licensee must destroy all copies of Software.
076:
077: e. Software, including technical data, is subject to U.S.
078: export control laws, including the U.S. Export Administration Act and its
079: associated regulations, and may be subject to export or import regulations
080: in other countries. Licensee agrees to comply strictly with all such
081: regulations and acknowledges that it has the responsibility to obtain
082: licenses to export, re-export, or import Software. Software may not be
083: downloaded, or otherwise exported or re-exported (i) into, or to a national
084: or resident of, Cuba, Iraq, Iran, North Korea, Libya, Sudan, Syria or any
085: country to which the U.S. has embargoed goods; or (ii) to anyone on the
086: U.S. Treasury Department's list of Specially Designated Nations or the U.S.
087: Commerce Department's Table of Denial Orders.
088:
089:
090: Feedback
091: ========
092:
093: We encourage your feedback and suggestions and want to use your feedback to
094: improve the Software. Send all such feedback to:
095: <feedback@tagtraum.com>
096:
097: For more information on tagtraum industries and jo!
098: please see <http://www.tagtraum.com/>.
099:
100:
101: */
102: package com.tagtraum.framework.compiler;
103:
104: import com.tagtraum.framework.util.URLHelper;
105:
106: import java.io.File;
107: import java.io.IOException;
108: import java.net.MalformedURLException;
109: import java.net.URL;
110: import java.net.URLClassLoader;
111: import java.util.ArrayList;
112: import java.util.List;
113: import java.util.Arrays;
114:
115: /**
116: * Gets a compiler.
117: *
118: * @author <a href="mailto:hs@tagtraum.com">Hendrik Schreiber</a>
119: * @version 1.1beta1 $Id: CompilerFactory.java,v 1.13 2005/01/02 22:02:30 hendriks73 Exp $
120: */
121: public class CompilerFactory {
122:
123: /**
124: * Source-Version
125: */
126: public static String vcid = "$Id: CompilerFactory.java,v 1.13 2005/01/02 22:02:30 hendriks73 Exp $";
127: public static final boolean WINDOWS = System.getProperty("os.name")
128: .toLowerCase().startsWith("win");
129:
130: private static boolean debug = false;
131: private static Compiler[] compilers;
132:
133: private static String PROGRAM_FILES_DIR;
134:
135: static {
136: if (WINDOWS) {
137: try {
138: // this will fail on JDK < 1.5
139: PROGRAM_FILES_DIR = System.getenv("ProgramFiles");
140: // get rid of C:\
141: PROGRAM_FILES_DIR = PROGRAM_FILES_DIR.substring(3);
142: } catch (Throwable t) {
143: PROGRAM_FILES_DIR = "Program Files";
144: }
145: }
146: }
147:
148: // unix searchpath
149: private static String[] unixSearchpath = new String[] { "", "lib/",
150: "usr/", "bin/", "usr/local/", "usr/local/bin/",
151: "usr/local/java/bin/", "usr/bin/", "usr/bin/java/bin/",
152: "usr/java/bin/", "usr/lib/java/bin/" // more???
153: };
154:
155: // WINDOWS searchpath
156: private static String[] windowsSearchpath = new String[] { "",
157: PROGRAM_FILES_DIR + "\\Java\\jdk1.5.0\\bin\\",
158: "j2sdk1.4.2_05\\bin\\", "j2sdk1.4.2_04\\bin\\",
159: "j2sdk1.4.2_03\\bin\\", "j2sdk1.4.2_02\\bin\\",
160: "j2sdk1.4.2_01\\bin\\", "j2sdk1.4.2\\bin\\",
161: "j2sdk1.4.1\\bin\\", "j2sdk1.4.0_01\\bin\\",
162: "j2sdk1.4.0\\bin\\", "jdk1.4\\bin\\", "jdk1.3.1\\bin\\",
163: "jdk1.3\\bin\\", "jdk1.2.2\\bin\\", "jdk1.2.1\\bin\\",
164: "jdk1.2.0\\bin\\", "jdk1.2\\bin\\", };
165:
166: public static void setDebug(boolean aDebug) {
167: debug = aDebug;
168: }
169:
170: public static boolean getDebug() {
171: return debug;
172: }
173:
174: public static String[] getUnixSearchpath() {
175: return unixSearchpath;
176: }
177:
178: /**
179: * Lets you set the Unix searchpath for command line compilers.
180: * Note that paths should start without the file system root symbol. In the case
181: * of Unix this is <code>/</code>
182: */
183: public static void setUnixSearchpath(String[] usp) {
184: if (usp == null)
185: throw new NullPointerException();
186: unixSearchpath = usp;
187: }
188:
189: public static String[] getWindowsSearchpath() {
190: return windowsSearchpath;
191: }
192:
193: /**
194: * Lets you set the Windows searchpath for command line compilers.
195: * Note that paths should start without the file system root symbol. In the case
196: * of Windows these are <code>c:\</code>, <code>d:\</code>, etc.
197: */
198: public static void setWindowsSearchpath(String[] wsp) {
199: if (wsp == null)
200: throw new NullPointerException();
201: windowsSearchpath = wsp;
202: }
203:
204: /**
205: * Instantiates a new Compiler.
206: */
207: public static Compiler newInstance(String compilerCommand) {
208: return new CommandLineCompiler(compilerCommand);
209: }
210:
211: /**
212: * Instantiates a new Compiler.
213: */
214: public synchronized static Compiler newInstance()
215: throws CompilerException {
216: if (compilers != null) {
217: return compilers[0].newInstance();
218: }
219: newInstances();
220: return compilers[0].newInstance();
221: }
222:
223: /**
224: * Instantiates all available compilers.
225: */
226: public synchronized static Compiler[] newInstances()
227: throws CompilerException {
228: if (compilers != null) {
229: Compiler[] newCompilers = new Compiler[compilers.length];
230: for (int i = 0; i < compilers.length; i++) {
231: newCompilers[i] = compilers[i].newInstance();
232: }
233: return newCompilers;
234: }
235: List compilerList = new ArrayList();
236: Compiler c = searchForSunCompiler("Modern builtin javac",
237: "com.sun.tools.javac.Main", ModernSunCompiler.class);
238: if (c != null)
239: compilerList.add(c);
240: c = searchForSunCompiler("Classic builtin javac",
241: "sun.tools.javac.Main", SunCompiler.class);
242: if (c != null)
243: compilerList.add(c);
244:
245: // jikes
246: if (debug) {
247: System.out.println("Looking for 'jikes'");
248: }
249: if (isProgramExecutable("jikes"))
250: compilerList.add(0, new JikesCompiler());
251: else {
252: File[] paths = searchFile(WINDOWS ? "jikes.exe" : "jikes");
253: for (int i = 0; i < paths.length; i++)
254: compilerList.add(0, new JikesCompiler(paths[i]));
255: }
256:
257: // javac
258: if (debug) {
259: System.out.println("Looking for 'javac'");
260: }
261: // check exec javac only, if we are desperate and haven't found anything else yet (hs)
262: if (compilerList.isEmpty() && isProgramExecutable("javac"))
263: compilerList.add(new JavacCompiler());
264: else {
265: File[] paths = searchFile(WINDOWS ? "javac.exe" : "javac");
266: for (int i = 0; i < paths.length; i++)
267: compilerList.add(new JavacCompiler(paths[i]));
268: }
269:
270: if (compilerList.isEmpty()) {
271: throw new CompilerNotFoundException();
272: }
273: compilers = (Compiler[]) compilerList
274: .toArray(new Compiler[compilerList.size()]);
275: return compilers;
276: }
277:
278: private static boolean isProgramExecutable(String command) {
279: try {
280: Process p = Runtime.getRuntime().exec(command);
281: if (debug) {
282: System.out.println("Found '" + command + "'");
283: }
284: // make sure the dangling process doesn't block anything
285: new StreamPumper(p.getErrorStream(), debug ? System.out
286: : null).start();
287: new StreamPumper(p.getInputStream(), debug ? System.out
288: : null).start();
289: return true;
290: } catch (IOException ioe) {
291: return false;
292: }
293: }
294:
295: private static Compiler searchForSunCompiler(String name,
296: String classname, Class compilerClass) {
297: Compiler compiler = null;
298: if (debug) {
299: System.out.println("Searching for " + name + ".");
300: }
301: if (debug) {
302: System.out.println("Looking for '" + classname + "'");
303: }
304: try {
305: // try to automatically add tools.jar to classpath...
306: try {
307: URL[] urls = new URL[1];
308: urls[0] = URLHelper.make(System
309: .getProperty("java.home")
310: + "/../lib/tools.jar");
311: if (debug) {
312: System.out.println("Adding " + urls[0]
313: + " to classpath.");
314: }
315: ClassLoader cl = new URLClassLoader(urls);
316: Class.forName(classname, true, cl);
317: } catch (MalformedURLException mfue) {
318: Class.forName(classname);
319: }
320: compiler = (Compiler) compilerClass.newInstance();
321: if (debug) {
322: System.out.println("Found '" + classname + "'");
323: }
324: } catch (ClassNotFoundException cnfe) {
325: if (debug) {
326: System.out.println("Couldn't find class '" + classname
327: + "'");
328: }
329: } catch (InstantiationException e) {
330: e.printStackTrace();
331: } catch (IllegalAccessException e) {
332: e.printStackTrace();
333: }
334: return compiler;
335: }
336:
337: /**
338: * Searches for the compiler in common paths.
339: *
340: * @return path without the file name or null if not found
341: */
342: public static File[] searchFile(String filename) {
343: if (debug)
344: System.out.println("Looking for '" + filename
345: + "' in common paths.");
346: String[] searchPath;
347: if (WINDOWS) {
348: searchPath = windowsSearchpath;
349: } else {
350: searchPath = unixSearchpath;
351: }
352: File[] roots = File.listRoots();
353: ArrayList files = new ArrayList();
354: for (int i = 0; i < roots.length; i++) {
355: String rootName = roots[i].toString().toLowerCase();
356: // skipping floppy disc drives, because of annoying popup WINDOWS in JDK 1.4.0
357: if (WINDOWS
358: && (rootName.indexOf("a:") != -1 || rootName
359: .toString().indexOf("b:") != -1))
360: continue;
361: // also skip drives we cannot write to, as they are most likely cdroms drives etc
362: // thanks to Fabrizio Fortino
363: if (!roots[i].canWrite())
364: continue;
365: for (int j = 0; j < searchPath.length; j++) {
366: File file = new File(roots[i], searchPath[j] + filename);
367: if (debug)
368: System.out.println("Checking " + file);
369: try {
370: if (file.exists() && file.isFile()) {
371: if (debug)
372: System.out.println("Found '" + filename
373: + "' in " + file.toString());
374: files.add(file);
375: }
376: } catch (Exception e) {
377: }
378: }
379: }
380: if (debug && files.isEmpty())
381: System.out.println("Couldn't find '" + filename + "'");
382: return (File[]) files.toArray(new File[files.size()]);
383: }
384:
385: /**
386: * Minimal Test.
387: */
388: public static void main(String[] args) throws Exception {
389: debug = true;
390:
391: newInstances();
392: System.out.println();
393: System.out.println(Arrays.asList(newInstances()));
394: }
395:
396: }
|