Source Code Cross Referenced for Compiler.java in  » Scripting » janino-2.5.11 » org » codehaus » janino » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Scripting » janino 2.5.11 » org.codehaus.janino 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Janino - An embedded Java[TM] compiler
003:         *
004:         * Copyright (c) 2001-2007, Arno Unkrig
005:         * All rights reserved.
006:         *
007:         * Redistribution and use in source and binary forms, with or without
008:         * modification, are permitted provided that the following conditions
009:         * are met:
010:         *
011:         *    1. Redistributions of source code must retain the above copyright
012:         *       notice, this list of conditions and the following disclaimer.
013:         *    2. Redistributions in binary form must reproduce the above
014:         *       copyright notice, this list of conditions and the following
015:         *       disclaimer in the documentation and/or other materials
016:         *       provided with the distribution.
017:         *    3. The name of the author may not be used to endorse or promote
018:         *       products derived from this software without specific prior
019:         *       written permission.
020:         *
021:         * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
022:         * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
023:         * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
024:         * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
025:         * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
026:         * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
027:         * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
028:         * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
029:         * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
030:         * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
031:         * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
032:         */
033:
034:        package org.codehaus.janino;
035:
036:        import java.util.*;
037:        import java.io.*;
038:
039:        import org.codehaus.janino.Parser.ParseException;
040:        import org.codehaus.janino.Scanner.ScanException;
041:        import org.codehaus.janino.UnitCompiler.ErrorHandler;
042:        import org.codehaus.janino.tools.Disassembler;
043:        import org.codehaus.janino.util.*;
044:        import org.codehaus.janino.util.enumerator.*;
045:        import org.codehaus.janino.util.resource.*;
046:
047:        /**
048:         * A simplified substitute for the <tt>javac</tt> tool.
049:         *
050:         * Usage:
051:         * <pre>
052:         * java org.codehaus.janino.Compiler \
053:         *           [ -d <i>destination-dir</i> ] \
054:         *           [ -sourcepath <i>dirlist</i> ] \
055:         *           [ -classpath <i>dirlist</i> ] \
056:         *           [ -extdirs <i>dirlist</i> ] \
057:         *           [ -bootclasspath <i>dirlist</i> ] \
058:         *           [ -encoding <i>encoding</i> ] \
059:         *           [ -verbose ] \
060:         *           [ -g:none ] \
061:         *           [ -g:{lines,vars,source} ] \
062:         *           [ -warn:<i>pattern-list</i> ] \
063:         *           <i>source-file</i> ...
064:         * java org.codehaus.janino.Compiler -help
065:         * </pre>
066:         */
067:        public class Compiler {
068:            private static final boolean DEBUG = false;
069:
070:            /**
071:             * Command line interface.
072:             */
073:            public static void main(String[] args) {
074:                File destinationDirectory = Compiler.NO_DESTINATION_DIRECTORY;
075:                File[] optionalSourcePath = null;
076:                File[] classPath = { new File(".") };
077:                File[] optionalExtDirs = null;
078:                File[] optionalBootClassPath = null;
079:                String optionalCharacterEncoding = null;
080:                boolean verbose = false;
081:                EnumeratorSet debuggingInformation = DebuggingInformation.DEFAULT_DEBUGGING_INFORMATION;
082:                StringPattern[] warningHandlePatterns = Compiler.DEFAULT_WARNING_HANDLE_PATTERNS;
083:                boolean rebuild = false;
084:
085:                // Process command line options.
086:                int i;
087:                for (i = 0; i < args.length; ++i) {
088:                    String arg = args[i];
089:                    if (arg.charAt(0) != '-')
090:                        break;
091:                    if (arg.equals("-d")) {
092:                        destinationDirectory = new File(args[++i]);
093:                    } else if (arg.equals("-sourcepath")) {
094:                        optionalSourcePath = PathResourceFinder
095:                                .parsePath(args[++i]);
096:                    } else if (arg.equals("-classpath")) {
097:                        classPath = PathResourceFinder.parsePath(args[++i]);
098:                    } else if (arg.equals("-extdirs")) {
099:                        optionalExtDirs = PathResourceFinder
100:                                .parsePath(args[++i]);
101:                    } else if (arg.equals("-bootclasspath")) {
102:                        optionalBootClassPath = PathResourceFinder
103:                                .parsePath(args[++i]);
104:                    } else if (arg.equals("-encoding")) {
105:                        optionalCharacterEncoding = args[++i];
106:                    } else if (arg.equals("-verbose")) {
107:                        verbose = true;
108:                    } else if (arg.equals("-g")) {
109:                        debuggingInformation = DebuggingInformation.ALL;
110:                    } else if (arg.startsWith("-g:")) {
111:                        try {
112:                            debuggingInformation = new EnumeratorSet(
113:                                    DebuggingInformation.class, arg
114:                                            .substring(3));
115:                        } catch (EnumeratorFormatException ex) {
116:                            System.err.println("Invalid debugging option \""
117:                                    + arg + "\", only \""
118:                                    + DebuggingInformation.ALL + "\" allowed");
119:                            System.exit(1);
120:                        }
121:                    } else if (arg.startsWith("-warn:")) {
122:                        warningHandlePatterns = StringPattern
123:                                .parseCombinedPattern(arg.substring(6));
124:                    } else if (arg.equals("-rebuild")) {
125:                        rebuild = true;
126:                    } else if (arg.equals("-help")) {
127:                        for (int j = 0; j < Compiler.USAGE.length; ++j)
128:                            System.out.println(Compiler.USAGE[j]);
129:                        System.exit(1);
130:                    } else {
131:                        System.err
132:                                .println("Unrecognized command line option \""
133:                                        + arg + "\"; try \"-help\".");
134:                        System.exit(1);
135:                    }
136:                }
137:
138:                // Get source file names.
139:                if (i == args.length) {
140:                    System.err
141:                            .println("No source files given on command line; try \"-help\".");
142:                    System.exit(1);
143:                }
144:                File[] sourceFiles = new File[args.length - i];
145:                for (int j = i; j < args.length; ++j)
146:                    sourceFiles[j - i] = new File(args[j]);
147:
148:                // Create the compiler object.
149:                final Compiler compiler = new Compiler(optionalSourcePath,
150:                        classPath, optionalExtDirs, optionalBootClassPath,
151:                        destinationDirectory, optionalCharacterEncoding,
152:                        verbose, debuggingInformation, warningHandlePatterns,
153:                        rebuild);
154:
155:                // Compile source files.
156:                try {
157:                    compiler.compile(sourceFiles);
158:                } catch (Exception e) {
159:                    System.err.println(e.toString());
160:                    System.exit(1);
161:                }
162:            }
163:
164:            private static final String[] USAGE = {
165:                    "Usage:",
166:                    "",
167:                    "  java " + Compiler.class.getName()
168:                            + " [ <option> ] ... <source-file> ...",
169:                    "",
170:                    "Supported <option>s are:",
171:                    "  -d <output-dir>           Where to save class files",
172:                    "  -sourcepath <dirlist>     Where to look for other source files",
173:                    "  -classpath <dirlist>      Where to look for other class files",
174:                    "  -extdirs <dirlist>        Where to look for other class files",
175:                    "  -bootclasspath <dirlist>  Where to look for other class files",
176:                    "  -encoding <encoding>      Encoding of source files, e.g. \"UTF-8\" or \"ISO-8859-1\"",
177:                    "  -verbose",
178:                    "  -g                        Generate all debugging info",
179:                    "  -g:none                   Generate no debugging info",
180:                    "  -g:{lines,vars,source}    Generate only some debugging info",
181:                    "  -warn:<pattern-list>      Issue certain warnings; examples:",
182:                    "    -warn:*                 Enables all warnings",
183:                    "    -warn:IASF              Only warn against implicit access to static fields",
184:                    "    -warn:*-IASF            Enables all warnings, except those against implicit",
185:                    "                            access to static fields",
186:                    "    -warn:*-IA*+IASF        Enables all warnings, except those against implicit",
187:                    "                            accesses, but do warn against implicit access to",
188:                    "                            static fields",
189:                    "  -rebuild                  Compile all source files, even if the class files",
190:                    "                            seems up-to-date",
191:                    "  -help",
192:                    "",
193:                    "The default encoding in this environment is \""
194:                            + new InputStreamReader(new ByteArrayInputStream(
195:                                    new byte[0])).getEncoding() + "\".", };
196:
197:            private/*final*/ResourceFinder classFileFinder;
198:            public static final ResourceFinder FIND_NEXT_TO_SOURCE_FILE = null; // Special value for "classFileResourceFinder".
199:            private/*final*/ResourceCreator classFileCreator;
200:            public static final ResourceCreator CREATE_NEXT_TO_SOURCE_FILE = null; // Special value for "classFileResourceCreator".
201:            private/*final*/String optionalCharacterEncoding;
202:            private/*final*/Benchmark benchmark;
203:            private/*final*/EnumeratorSet debuggingInformation;
204:            private/*final*/WarningHandler optionalWarningHandler;
205:            private UnitCompiler.ErrorHandler optionalCompileErrorHandler = null;
206:
207:            private/*final*/IClassLoader iClassLoader;
208:            private final ArrayList parsedCompilationUnits = new ArrayList(); // UnitCompiler
209:
210:            /**
211:             * Initialize a Java<sup>TM</sup> compiler with the given parameters.
212:             * <p>
213:             * Classes are searched in the following order:
214:             * <ul>
215:             *   <li>If <code>optionalBootClassPath</code> is <code>null</code>:
216:             *   <ul>
217:             *     <li>Through the system class loader of the JVM that runs JANINO
218:             *   </ul>
219:             *   <li>If <code>optionalBootClassPath</code> is not <code>null</code>:
220:             *   <ul>
221:             *     <li>Through the <code>optionalBootClassPath</code>
222:             *   </ul>
223:             *   <li>If <code>optionalExtDirs</code> is not <code>null</code>:
224:             *   <ul>
225:             *     <li>Through the <code>optionalExtDirs</code>
226:             *   </ul>
227:             *   <li>Through the <code>classPath</code>
228:             *   <li>If <code>optionalSourcePath</code> is <code>null</code>:
229:             *   <ul>
230:             *     <li>Through source files found on the <code>classPath</code>
231:             *   </ul>
232:             *   <li>If <code>optionalSourcePath</code> is not <code>null</code>:
233:             *   <ul>
234:             *     <li>Through source files found on the <code>sourcePath</code>
235:             *   </ul>
236:             * </ul>
237:             * <p>
238:             * The file name of a class file that represents class "pkg.Example"
239:             * is determined as follows:
240:             * <ul>
241:             *   <li>
242:             *   If <code>optionalDestinationDirectory</code> is not {@link #NO_DESTINATION_DIRECTORY}:
243:             *   <code><i>optionalDestinationDirectory</i>/pkg/Example.class</code>
244:             *   <li>
245:             *   If <code>optionalDestinationDirectory</code> is {@link #NO_DESTINATION_DIRECTORY}:
246:             *   <code>dir1/dir2/Example.class</code> (Assuming that the file name of the
247:             *   source file that declares the class was
248:             *   <code>dir1/dir2/Any.java</code>.)
249:             * </ul>
250:             *
251:             * @see #DEFAULT_WARNING_HANDLE_PATTERNS
252:             */
253:            public Compiler(final File[] optionalSourcePath,
254:                    final File[] classPath, final File[] optionalExtDirs,
255:                    final File[] optionalBootClassPath,
256:                    final File destinationDirectory,
257:                    final String optionalCharacterEncoding, boolean verbose,
258:                    EnumeratorSet debuggingInformation,
259:                    StringPattern[] warningHandlePatterns, boolean rebuild) {
260:                this (
261:                        new PathResourceFinder( // sourceFinder
262:                                optionalSourcePath == null ? classPath
263:                                        : optionalSourcePath),
264:                        Compiler.createJavacLikePathIClassLoader(
265:                                // iClassLoader
266:                                optionalBootClassPath, optionalExtDirs,
267:                                classPath),
268:                        ( // classFileFinder
269:                        rebuild ? ResourceFinder.EMPTY_RESOURCE_FINDER
270:                                : destinationDirectory == Compiler.NO_DESTINATION_DIRECTORY ? Compiler.FIND_NEXT_TO_SOURCE_FILE
271:                                        : new DirectoryResourceFinder(
272:                                                destinationDirectory)),
273:                        ( // classFileCreator
274:                        destinationDirectory == Compiler.NO_DESTINATION_DIRECTORY ? Compiler.CREATE_NEXT_TO_SOURCE_FILE
275:                                : new DirectoryResourceCreator(
276:                                        destinationDirectory)),
277:                        optionalCharacterEncoding, // optionalCharacterEncoding
278:                        verbose, // verbose
279:                        debuggingInformation, // debuggingInformation
280:                        new FilterWarningHandler(
281:                                // optionalWarningHandler
282:                                warningHandlePatterns,
283:                                new SimpleWarningHandler() // <= Anonymous class here is complicated because the enclosing instance is not fully initialized yet 
284:                        ));
285:
286:                this .benchmark
287:                        .report("*** JANINO - an embedded compiler for the Java(TM) programming language");
288:                this .benchmark
289:                        .report("*** For more information visit http://janino.codehaus.org");
290:                this .benchmark.report("Source path", optionalSourcePath);
291:                this .benchmark.report("Class path", classPath);
292:                this .benchmark.report("Ext dirs", optionalExtDirs);
293:                this .benchmark.report("Boot class path", optionalBootClassPath);
294:                this .benchmark.report("Destination directory",
295:                        destinationDirectory);
296:                this .benchmark.report("Character encoding",
297:                        optionalCharacterEncoding);
298:                this .benchmark.report("Verbose", new Boolean(verbose));
299:                this .benchmark.report("Debugging information",
300:                        debuggingInformation);
301:                this .benchmark.report("Warning handle patterns",
302:                        warningHandlePatterns);
303:                this .benchmark.report("Rebuild", new Boolean(rebuild));
304:            }
305:
306:            public static final File NO_DESTINATION_DIRECTORY = null; // Backwards compatibility -- previously, "null" was officially documented
307:
308:            public static class SimpleWarningHandler implements  WarningHandler {
309:                public void handleWarning(String handle, String message,
310:                        Location optionalLocation) {
311:                    StringBuffer sb = new StringBuffer();
312:                    if (optionalLocation != null)
313:                        sb.append(optionalLocation).append(": ");
314:                    sb.append("Warning ").append(handle).append(": ").append(
315:                            message);
316:                    System.err.println(sb.toString());
317:                }
318:            }
319:
320:            public static final StringPattern[] DEFAULT_WARNING_HANDLE_PATTERNS = StringPattern.PATTERNS_NONE;
321:
322:            /**
323:             * To mimic the behavior of JAVAC with a missing "-d" command line option,
324:             * pass {@link #FIND_NEXT_TO_SOURCE_FILE} as the <code>classFileResourceFinder</code> and
325:             * {@link #CREATE_NEXT_TO_SOURCE_FILE} as the <code>classFileResourceCreator</code>.
326:             * <p>
327:             * If it is impossible to check whether an already-compiled class file
328:             * exists, or if you want to enforce recompilation, pass
329:             * {@link ResourceFinder#EMPTY_RESOURCE_FINDER} as the
330:             * <code>classFileResourceFinder</code>.
331:             * 
332:             * @param sourceFinder Finds extra Java compilation units that need to be compiled (a.k.a. "sourcepath")
333:             * @param iClassLoader loads auxiliary {@link IClass}es; e.g. <code>new ClassLoaderIClassLoader(ClassLoader)</code>
334:             * @param classFileFinder Where to look for up-to-date class files that need not be compiled
335:             * @param classFileCreator Used to store generated class files
336:             * @param optionalCharacterEncoding
337:             * @param verbose
338:             * @param debuggingInformation a combination of <code>Java.DEBUGGING_...</code>
339:             * @param optionalWarningHandler used to issue warnings
340:             */
341:            public Compiler(ResourceFinder sourceFinder,
342:                    IClassLoader iClassLoader, ResourceFinder classFileFinder,
343:                    ResourceCreator classFileCreator,
344:                    final String optionalCharacterEncoding, boolean verbose,
345:                    EnumeratorSet debuggingInformation,
346:                    WarningHandler optionalWarningHandler) {
347:                this .classFileFinder = classFileFinder;
348:                this .classFileCreator = classFileCreator;
349:                this .optionalCharacterEncoding = optionalCharacterEncoding;
350:                this .benchmark = new Benchmark(verbose);
351:                this .debuggingInformation = debuggingInformation;
352:                this .optionalWarningHandler = optionalWarningHandler;
353:
354:                // Set up the IClassLoader.
355:                this .iClassLoader = new CompilerIClassLoader(sourceFinder,
356:                        iClassLoader);
357:            }
358:
359:            /**
360:             * Install a custom {@link UnitCompiler.ErrorHandler}. The default
361:             * {@link UnitCompiler.ErrorHandler} prints the first 20 compile errors to
362:             * {@link System#err} and then throws a {@link CompileException}.
363:             * <p>
364:             * Passing <code>null</code> restores the default {@link UnitCompiler.ErrorHandler}.
365:             * <p>
366:             * Notice that scan and parse errors are <i>not</i> redirected to this {@link ErrorHandler},
367:             * instead, they cause a {@link ScanException} or a {@link ParseException} to be thrown.
368:             * Also, the {@link Compiler} may choose to throw {@link CompileException}s in certain,
369:             * fatal compile error situations, even if an {@link ErrorHandler} is installed.
370:             * <p>
371:             * In other words: In situations where compilation can reasonably continue after a compile
372:             * error, the {@link ErrorHandler} is called; all other error conditions cause a
373:             * {@link CompileException}, {@link ParseException} or {@link ScanException} to be thrown.
374:             */
375:            public void setCompileErrorHandler(
376:                    UnitCompiler.ErrorHandler optionalCompileErrorHandler) {
377:                this .optionalCompileErrorHandler = optionalCompileErrorHandler;
378:            }
379:
380:            /**
381:             * Create an {@link IClassLoader} that looks for classes in the given "boot class
382:             * path", then in the given "extension directories", and then in the given
383:             * "class path".
384:             * <p>
385:             * The default for the <code>optionalBootClassPath</code> is the path defined in
386:             * the system property "sun.boot.class.path", and the default for the
387:             * <code>optionalExtensionDirs</code> is the path defined in the "java.ext.dirs"
388:             * system property.
389:             */
390:            private static IClassLoader createJavacLikePathIClassLoader(
391:                    final File[] optionalBootClassPath,
392:                    final File[] optionalExtDirs, final File[] classPath) {
393:                ResourceFinder bootClassPathResourceFinder = new PathResourceFinder(
394:                        optionalBootClassPath == null ? PathResourceFinder
395:                                .parsePath(System
396:                                        .getProperty("sun.boot.class.path"))
397:                                : optionalBootClassPath);
398:                ResourceFinder extensionDirectoriesResourceFinder = new JarDirectoriesResourceFinder(
399:                        optionalExtDirs == null ? PathResourceFinder
400:                                .parsePath(System.getProperty("java.ext.dirs"))
401:                                : optionalExtDirs);
402:                ResourceFinder classPathResourceFinder = new PathResourceFinder(
403:                        classPath);
404:
405:                // We can load classes through "ResourceFinderIClassLoader"s, which means
406:                // they are read into "ClassFile" objects, or we can load classes through
407:                // "ClassLoaderIClassLoader"s, which means they are loaded into the JVM.
408:                //
409:                // In my environment, the latter is slightly faster. No figures about
410:                // resource usage yet.
411:                //
412:                // In applications where the generated classes are not loaded into the
413:                // same JVM instance, we should avoid to use the
414:                // ClassLoaderIClassLoader, because that assumes that final fields have
415:                // a constant value, even if not compile-time-constant but only
416:                // initialization-time constant. The classical example is
417:                // "File.separator", which is non-blank final, but not compile-time-
418:                // constant.
419:                if (true) {
420:                    IClassLoader icl;
421:                    icl = new ResourceFinderIClassLoader(
422:                            bootClassPathResourceFinder, null);
423:                    icl = new ResourceFinderIClassLoader(
424:                            extensionDirectoriesResourceFinder, icl);
425:                    icl = new ResourceFinderIClassLoader(
426:                            classPathResourceFinder, icl);
427:                    return icl;
428:                } else {
429:                    ClassLoader cl;
430:
431:                    cl = SimpleCompiler.BOOT_CLASS_LOADER;
432:                    cl = new ResourceFinderClassLoader(
433:                            bootClassPathResourceFinder, cl);
434:                    cl = new ResourceFinderClassLoader(
435:                            extensionDirectoriesResourceFinder, cl);
436:                    cl = new ResourceFinderClassLoader(classPathResourceFinder,
437:                            cl);
438:
439:                    return new ClassLoaderIClassLoader(cl);
440:                }
441:            }
442:
443:            /**
444:             * Reads a set of Java<sup>TM</sup> compilation units (a.k.a. "source
445:             * files") from the file system, compiles them into a set of "class
446:             * files" and stores these in the file system. Additional source files are
447:             * parsed and compiled on demand through the "source path" set of
448:             * directories.
449:             * <p>
450:             * For example, if the source path comprises the directories "A/B" and "../C",
451:             * then the source file for class "com.acme.Main" is searched in
452:             * <dl>
453:             *   <dd>A/B/com/acme/Main.java
454:             *   <dd>../C/com/acme/Main.java
455:             * </dl>
456:             * Notice that it does make a difference whether you pass multiple source
457:             * files to {@link #compile(File[])} or if you invoke
458:             * {@link #compile(File[])} multiply: In the former case, the source
459:             * files may contain arbitrary references among each other (even circular
460:             * ones). In the latter case, only the source files on the source path
461:             * may contain circular references, not the <code>sourceFiles</code>.
462:             * <p>
463:             * This method must be called exactly once after object construction.
464:             * <p>
465:             * Compile errors are reported as described at
466:             * {@link #setCompileErrorHandler(UnitCompiler.ErrorHandler)}.
467:             *
468:             * @param sourceFiles Contain the compilation units to compile
469:             * @return <code>true</code> for backwards compatibility (return value can safely be ignored)
470:             * @throws CompileException Fatal compilation error, or the {@link CompileException} thrown be the installed compile error handler
471:             * @throws ParseException Parse error
472:             * @throws ScanException Scan error
473:             * @throws IOException Occurred when reading from the <code>sourceFiles</code>
474:             */
475:            public boolean compile(File[] sourceFiles)
476:                    throws Scanner.ScanException, Parser.ParseException,
477:                    CompileException, IOException {
478:                this .benchmark.report("Source files", sourceFiles);
479:
480:                Resource[] sourceFileResources = new Resource[sourceFiles.length];
481:                for (int i = 0; i < sourceFiles.length; ++i)
482:                    sourceFileResources[i] = new FileResource(sourceFiles[i]);
483:                this .compile(sourceFileResources);
484:                return true;
485:            }
486:
487:            /**
488:             * See {@link #compile(File[])}.
489:             *
490:             * @param sourceResources Contain the compilation units to compile
491:             * @return <code>true</code> for backwards compatibility (return value can safely be ignored)
492:             */
493:            public boolean compile(Resource[] sourceResources)
494:                    throws Scanner.ScanException, Parser.ParseException,
495:                    CompileException, IOException {
496:
497:                // Set up the compile error handler as described at "setCompileErrorHandler()".
498:                UnitCompiler.ErrorHandler ceh = (this .optionalCompileErrorHandler != null ? this .optionalCompileErrorHandler
499:                        : new UnitCompiler.ErrorHandler() {
500:                            int compileErrorCount = 0;
501:
502:                            public void handleError(String message,
503:                                    Location optionalLocation)
504:                                    throws CompileException {
505:                                CompileException ex = new CompileException(
506:                                        message, optionalLocation);
507:                                if (++this .compileErrorCount >= 20)
508:                                    throw ex;
509:                                System.err.println(ex.getMessage());
510:                            }
511:                        });
512:
513:                this .benchmark.beginReporting();
514:                try {
515:
516:                    // Parse all source files.
517:                    this .parsedCompilationUnits.clear();
518:                    for (int i = 0; i < sourceResources.length; ++i) {
519:                        if (Compiler.DEBUG)
520:                            System.out.println("Compiling \""
521:                                    + sourceResources[i] + "\"");
522:                        this .parsedCompilationUnits.add(new UnitCompiler(this 
523:                                .parseCompilationUnit(sourceResources[i]
524:                                        .getFileName(), // fileName
525:                                        new BufferedInputStream(
526:                                                sourceResources[i].open()), // inputStream
527:                                        this .optionalCharacterEncoding // optionalCharacterEncoding
528:                                ), this .iClassLoader));
529:                    }
530:
531:                    // Compile all parsed compilation units. The vector of parsed CUs may
532:                    // grow while they are being compiled, but eventually all CUs will
533:                    // be compiled.
534:                    for (int i = 0; i < this .parsedCompilationUnits.size(); ++i) {
535:                        UnitCompiler unitCompiler = (UnitCompiler) this .parsedCompilationUnits
536:                                .get(i);
537:                        Java.CompilationUnit cu = unitCompiler.compilationUnit;
538:                        if (cu.optionalFileName == null)
539:                            throw new RuntimeException();
540:                        File sourceFile = new File(cu.optionalFileName);
541:
542:                        unitCompiler.setCompileErrorHandler(ceh);
543:                        unitCompiler
544:                                .setWarningHandler(this .optionalWarningHandler);
545:
546:                        this .benchmark
547:                                .beginReporting("Compiling compilation unit \""
548:                                        + sourceFile + "\"");
549:                        ClassFile[] classFiles;
550:                        try {
551:
552:                            // Compile the compilation unit.
553:                            classFiles = unitCompiler
554:                                    .compileUnit(this .debuggingInformation);
555:                        } finally {
556:                            this .benchmark.endReporting();
557:                        }
558:
559:                        // Store the compiled classes and interfaces into class files.
560:                        this .benchmark
561:                                .beginReporting("Storing "
562:                                        + classFiles.length
563:                                        + " class file(s) resulting from compilation unit \""
564:                                        + sourceFile + "\"");
565:                        try {
566:                            for (int j = 0; j < classFiles.length; ++j) {
567:                                this .storeClassFile(classFiles[j], sourceFile);
568:                            }
569:                        } finally {
570:                            this .benchmark.endReporting();
571:                        }
572:                    }
573:                } finally {
574:                    this .benchmark.endReporting("Compiled "
575:                            + this .parsedCompilationUnits.size()
576:                            + " compilation unit(s)");
577:                }
578:                return true;
579:            }
580:
581:            /**
582:             * Read one compilation unit from a file and parse it.
583:             * <p>
584:             * The <code>inputStream</code> is closed before the method returns.
585:             * @return the parsed compilation unit
586:             */
587:            private Java.CompilationUnit parseCompilationUnit(String fileName,
588:                    InputStream inputStream, String optionalCharacterEncoding)
589:                    throws Scanner.ScanException, Parser.ParseException,
590:                    IOException {
591:                try {
592:                    Scanner scanner = new Scanner(fileName, inputStream,
593:                            optionalCharacterEncoding);
594:                    scanner.setWarningHandler(this .optionalWarningHandler);
595:                    Parser parser = new Parser(scanner);
596:                    parser.setWarningHandler(this .optionalWarningHandler);
597:
598:                    this .benchmark.beginReporting("Parsing \"" + fileName
599:                            + "\"");
600:                    try {
601:                        return parser.parseCompilationUnit();
602:                    } finally {
603:                        this .benchmark.endReporting();
604:                    }
605:                } finally {
606:                    inputStream.close();
607:                }
608:            }
609:
610:            /**
611:             * Construct the name of a file that could store the byte code of the class with the given
612:             * name.
613:             * <p>
614:             * If <code>optionalDestinationDirectory</code> is non-null, the returned path is the
615:             * <code>optionalDestinationDirectory</code> plus the package of the class (with dots replaced
616:             * with file separators) plus the class name plus ".class". Example:
617:             * "destdir/pkg1/pkg2/Outer$Inner.class"
618:             * <p>
619:             * If <code>optionalDestinationDirectory</code> is null, the returned path is the
620:             * directory of the <code>sourceFile</code> plus the class name plus ".class". Example:
621:             * "srcdir/Outer$Inner.class"
622:             * @param className E.g. "pkg1.pkg2.Outer$Inner"
623:             * @param sourceFile E.g. "srcdir/Outer.java"
624:             * @param optionalDestinationDirectory E.g. "destdir"
625:             */
626:            public static File getClassFile(String className, File sourceFile,
627:                    File optionalDestinationDirectory) {
628:                if (optionalDestinationDirectory != null) {
629:                    return new File(optionalDestinationDirectory, ClassFile
630:                            .getClassFileResourceName(className));
631:                } else {
632:                    int idx = className.lastIndexOf('.');
633:                    return new File(sourceFile.getParentFile(), ClassFile
634:                            .getClassFileResourceName(className
635:                                    .substring(idx + 1)));
636:                }
637:            }
638:
639:            /**
640:             * Store the byte code of this {@link ClassFile} in the file system. Directories are created
641:             * as necessary.
642:             * @param classFile
643:             * @param sourceFile Required to compute class file path if no destination directory given
644:             */
645:            public void storeClassFile(ClassFile classFile,
646:                    final File sourceFile) throws IOException {
647:                String classFileResourceName = ClassFile
648:                        .getClassFileResourceName(classFile.getThisClassName());
649:
650:                // Determine where to create the class file.
651:                ResourceCreator rc;
652:                if (this .classFileCreator != Compiler.CREATE_NEXT_TO_SOURCE_FILE) {
653:                    rc = this .classFileCreator;
654:                } else {
655:
656:                    // If the JAVAC option "-d" is given, place the class file next
657:                    // to the source file, irrespective of the package name.
658:                    rc = new FileResourceCreator() {
659:                        protected File getFile(String resourceName) {
660:                            return new File(sourceFile.getParentFile(),
661:                                    resourceName.substring(resourceName
662:                                            .lastIndexOf('/') + 1));
663:                        }
664:                    };
665:                }
666:                OutputStream os = rc.createResource(classFileResourceName);
667:                try {
668:                    if (DEBUG) {
669:                        ByteArrayOutputStream baos = new ByteArrayOutputStream();
670:                        classFile.store(baos);
671:                        byte[] ba = baos.toByteArray();
672:                        System.out.println("*** Disassembly of class \""
673:                                + classFile.getThisClassName() + "\":");
674:                        try {
675:                            new Disassembler().disasm(new ByteArrayInputStream(
676:                                    ba));
677:                            System.out.flush();
678:                        } catch (IOException ex) {
679:                            throw new RuntimeException(
680:                                    "SNO: IOException despite ByteArrayInputStream");
681:                        }
682:                        os.write(ba);
683:                    } else {
684:                        classFile.store(os);
685:                    }
686:                } catch (IOException ex) {
687:                    try {
688:                        os.close();
689:                    } catch (IOException e) {
690:                    }
691:                    os = null;
692:                    if (!rc.deleteResource(classFileResourceName))
693:                        throw new IOException(
694:                                "Could not delete incompletely written class file \""
695:                                        + classFileResourceName + "\"");
696:                    throw ex;
697:                } finally {
698:                    if (os != null)
699:                        try {
700:                            os.close();
701:                        } catch (IOException e) {
702:                        }
703:                }
704:            }
705:
706:            /**
707:             * A specialized {@link IClassLoader} that loads {@link IClass}es from the following
708:             * sources:
709:             * <ol>
710:             *   <li>An already-parsed compilation unit
711:             *   <li>A class file in the output directory (if existant and younger than source file)
712:             *   <li>A source file in any of the source path directories
713:             *   <li>The parent class loader
714:             * </ol>
715:             * Notice that the {@link CompilerIClassLoader} is an inner class of {@link Compiler} and
716:             * heavily uses {@link Compiler}'s members.
717:             */
718:            private class CompilerIClassLoader extends IClassLoader {
719:                private final ResourceFinder sourceFinder;
720:
721:                /**
722:                 * @param sourceFinder Where to look for source files
723:                 * @param optionalParentIClassLoader {@link IClassLoader} through which {@link IClass}es are to be loaded
724:                 */
725:                public CompilerIClassLoader(ResourceFinder sourceFinder,
726:                        IClassLoader optionalParentIClassLoader) {
727:                    super (optionalParentIClassLoader);
728:                    this .sourceFinder = sourceFinder;
729:                    super .postConstruct();
730:                }
731:
732:                /**
733:                 * @param type field descriptor of the {@IClass} to load, e.g. "Lpkg1/pkg2/Outer$Inner;"
734:                 * @return <code>null</code> if a the type could not be found
735:                 * @throws ClassNotFoundException if an exception was raised while loading the {@link IClass}
736:                 */
737:                protected IClass findIClass(final String type)
738:                        throws ClassNotFoundException {
739:                    if (Compiler.DEBUG)
740:                        System.out.println("type = " + type);
741:
742:                    // Determine the class name.
743:                    String className = Descriptor.toClassName(type); // E.g. "pkg1.pkg2.Outer$Inner"
744:                    if (Compiler.DEBUG)
745:                        System.out.println("2 className = \"" + className
746:                                + "\"");
747:
748:                    // Do not attempt to load classes from package "java".
749:                    if (className.startsWith("java."))
750:                        return null;
751:
752:                    // Determine the name of the top-level class.
753:                    String topLevelClassName;
754:                    {
755:                        int idx = className.indexOf('$');
756:                        topLevelClassName = idx == -1 ? className : className
757:                                .substring(0, idx);
758:                    }
759:
760:                    // Check the already-parsed compilation units.
761:                    for (int i = 0; i < Compiler.this .parsedCompilationUnits
762:                            .size(); ++i) {
763:                        UnitCompiler uc = (UnitCompiler) Compiler.this .parsedCompilationUnits
764:                                .get(i);
765:                        IClass res = uc.findClass(topLevelClassName);
766:                        if (res != null) {
767:                            if (!className.equals(topLevelClassName)) {
768:                                res = uc.findClass(className);
769:                                if (res == null)
770:                                    return null;
771:                            }
772:                            this .defineIClass(res);
773:                            return res;
774:                        }
775:                    }
776:
777:                    // Search source path for uncompiled class.
778:                    final Resource sourceResource = this .sourceFinder
779:                            .findResource(ClassFile
780:                                    .getSourceResourceName(className));
781:                    if (sourceResource == null)
782:                        return null;
783:
784:                    // Find an existing class file.
785:                    Resource classFileResource;
786:                    if (Compiler.this .classFileFinder != Compiler.FIND_NEXT_TO_SOURCE_FILE) {
787:                        classFileResource = Compiler.this .classFileFinder
788:                                .findResource(ClassFile
789:                                        .getClassFileResourceName(className));
790:                    } else {
791:                        if (!(sourceResource instanceof  FileResource))
792:                            return null;
793:                        File classFile = new File(
794:                                ((FileResource) sourceResource).getFile()
795:                                        .getParentFile(), ClassFile
796:                                        .getClassFileResourceName(className
797:                                                .substring(className
798:                                                        .lastIndexOf('.') + 1)));
799:                        classFileResource = classFile.exists() ? new FileResource(
800:                                classFile)
801:                                : null;
802:                    }
803:
804:                    // Compare source modification time against class file modification time.
805:                    if (classFileResource != null
806:                            && sourceResource.lastModified() <= classFileResource
807:                                    .lastModified()) {
808:
809:                        // The class file is up-to-date; load it.
810:                        return this 
811:                                .defineIClassFromClassFileResource(classFileResource);
812:                    } else {
813:
814:                        // Source file not yet compiled or younger than class file.
815:                        return this .defineIClassFromSourceResource(
816:                                sourceResource, className);
817:                    }
818:                }
819:
820:                /**
821:                 * Parse the compilation unit stored in the given <code>sourceResource</code>, remember it in
822:                 * <code>Compiler.this.parsedCompilationUnits</code> (it may declare other classes that
823:                 * are needed later), find the declaration of the type with the given
824:                 * <code>className</code>, and define it in the {@link IClassLoader}.
825:                 * <p>
826:                 * Notice that the CU is not compiled here!
827:                 */
828:                private IClass defineIClassFromSourceResource(
829:                        Resource sourceResource, String className)
830:                        throws ClassNotFoundException {
831:
832:                    // Parse the source file.
833:                    UnitCompiler uc;
834:                    try {
835:                        Java.CompilationUnit cu = Compiler.this 
836:                                .parseCompilationUnit(sourceResource
837:                                        .getFileName(), // fileName
838:                                        new BufferedInputStream(sourceResource
839:                                                .open()), // inputStream
840:                                        Compiler.this .optionalCharacterEncoding // optionalCharacterEncoding
841:                                );
842:                        uc = new UnitCompiler(cu, Compiler.this .iClassLoader);
843:                    } catch (IOException ex) {
844:                        throw new ClassNotFoundException(
845:                                "Parsing compilation unit \"" + sourceResource
846:                                        + "\"", ex);
847:                    } catch (Parser.ParseException ex) {
848:                        throw new ClassNotFoundException(
849:                                "Parsing compilation unit \"" + sourceResource
850:                                        + "\"", ex);
851:                    } catch (Scanner.ScanException ex) {
852:                        throw new ClassNotFoundException(
853:                                "Parsing compilation unit \"" + sourceResource
854:                                        + "\"", ex);
855:                    } catch (CompileException ex) {
856:                        throw new ClassNotFoundException(
857:                                "Parsing compilation unit \"" + sourceResource
858:                                        + "\"", ex);
859:                    }
860:
861:                    // Remember compilation unit for later compilation.
862:                    Compiler.this .parsedCompilationUnits.add(uc);
863:
864:                    // Define the class.
865:                    IClass res = uc.findClass(className);
866:                    if (res == null) {
867:
868:                        // This is a really complicated case: We may find a source file on the source
869:                        // path that seemingly contains the declaration of the class we are looking
870:                        // for, but doesn't. This is possible if the underlying file system has
871:                        // case-insensitive file names and/or file names that are limited in length
872:                        // (e.g. DOS 8.3).
873:                        return null;
874:                    }
875:                    this .defineIClass(res);
876:                    return res;
877:                }
878:
879:                /**
880:                 * Open the given <code>classFileResource</code>, read its contents, define it in the
881:                 * {@link IClassLoader}, and resolve it (this step may involve loading more classes).
882:                 */
883:                private IClass defineIClassFromClassFileResource(
884:                        Resource classFileResource)
885:                        throws ClassNotFoundException {
886:                    Compiler.this .benchmark
887:                            .beginReporting("Loading class file \""
888:                                    + classFileResource.getFileName() + "\"");
889:                    try {
890:                        InputStream is = null;
891:                        ClassFile cf;
892:                        try {
893:                            cf = new ClassFile(new BufferedInputStream(
894:                                    classFileResource.open()));
895:                        } catch (IOException ex) {
896:                            throw new ClassNotFoundException(
897:                                    "Opening class file resource \""
898:                                            + classFileResource + "\"", ex);
899:                        } finally {
900:                            if (is != null)
901:                                try {
902:                                    is.close();
903:                                } catch (IOException e) {
904:                                }
905:                        }
906:                        ClassFileIClass result = new ClassFileIClass(cf, // classFile
907:                                CompilerIClassLoader.this  // iClassLoader
908:                        );
909:
910:                        // Important: We must FIRST call "defineIClass()" so that the
911:                        // new IClass is known to the IClassLoader, and THEN
912:                        // "resolveAllClasses()", because otherwise endless recursion could
913:                        // occur.
914:                        this.defineIClass(result);
915:                        result.resolveAllClasses();
916:
917:                        return result;
918:                    } finally {
919:                        Compiler.this.benchmark.endReporting();
920:                    }
921:                }
922:            }
923:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.