Source Code Cross Referenced for Compiler.java in  » Scripting » jacl » 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 » jacl » org.codehaus.janino 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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