Source Code Cross Referenced for CompilerRunnableForJavaC.java in  » IDE » Schmortopf » Schmortopf » OutputManager » 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 » IDE » Schmortopf » Schmortopf.OutputManager 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        package Schmortopf.OutputManager;
002:
003:        /**                                                
004:         *  The Runnable, which carries out compilation with SUN's JavaC compiler.
005:         *  Called by outputManager methods of this package.
006:         *  The CompilerRunnable will compile the files complete or                   
007:         *  to the first 10 errors.
008:         *         
009:         *  When it ends, it will set the attributes of the outputManager :
010:         *  - classesWereCompiledAFirstTime
011:         *  - classesWereCompiledWithoutErrors
012:         *  and reenable the starterbutton
013:         *        
014:         *  It is designed to be called in the ThreadEngine threadcontext.
015:         *  The ThreadEngine guarantees that the CompilerRunnable and other                              
016:         *  tasks (for example the ones, which scan dependencies) are carried out
017:         *  in sequence. This prevents race conditions.
018:         *                                                               
019:         */
020:
021:        import javax.swing.*;
022:        import java.io.*;
023:        import java.util.*;
024:
025:        import Schmortopf.Main.IDE_ProjectFrameProvider;
026:        import Schmortopf.Utility.SchmortopfConstants;
027:        import Language.Language;
028:        import Schmortopf.OutputManager.Processes.ProcessManager;
029:        import Schmortopf.Utility.io.FileUtilities;
030:        import Schmortopf.Utility.CommentedBoolean;
031:        import Schmortopf.Utility.StringUtilities;
032:        import Shared.Logging.Log;
033:
034:        public class CompilerRunnableForJavaC implements  Runnable {
035:
036:            // Notice regarding GC assistance :
037:            // This is quite easy here, because except the run() method,
038:            // all others are private and called from the inside of the run method.
039:            // Therefore we just can set all references of bigger objects to null
040:            // at the end of the run() method, and the GC should scan the dependencies
041:            // faster and therefore faster see, when this object isn't referenced anymore.
042:
043:            private OutputManager outputManager; // GC: set to null at the end of the run() method
044:            private IDE_ProjectFrameProvider projectFrameProvider; // GC: set to null at the end of the run() method
045:
046:            private final String javacExePath;
047:            private final String sourceDirectoryPath;
048:            private final String targetClassDirectoryPath;
049:            private String[] sourceFilePathNames;
050:            private final String mainClassFilePath;
051:            private final String jdkBasisPath;
052:            private final JButton compileButton;
053:            private final JButton executeButton;
054:            private final boolean isProcessingProject; // single file, if false
055:            private final boolean launchAfterCompilation;
056:            private final String[] additionalLibraryPathes;
057:
058:            // Set after a complete compiler run
059:            private boolean compilingWasSuccessful = true;
060:
061:            // Contains the number of all found and printed errors
062:            // during the run.
063:            private int numberOfErrors = 0;
064:
065:            private long startTime;
066:
067:            private int decodeErrorMessagesCalls = 0; // debug attribute
068:
069:            // The errorbuffer is used on failures of the mechanism itself.
070:            // In some situations, the decoder fails and the IDE prints an
071:            // Internal Error message. In this case, we at least can show
072:            // the content of this buffer for the user, so he can see the
073:            // compiler error messages ( in text format )
074:            private Vector errorLinesBuffer = new Vector(); // GC: set to null at the end of the run() method
075:
076:            //  The number of all files, which were compiled by JavaC
077:            //  on its way through the import dependency chain.
078:            //  This is equal or (usually much) bigger than the number of
079:            //  changed files by the programmer.
080:            private int totalNumberOfCompiledFiles = 0;
081:
082:            // Additional compiler output count statistics:
083:            private int numberOfLoadedFiles = 0;
084:            private int numberOfParsedFiles = 0;
085:            private int numberOfCheckedFiles = 0;
086:            private int numberOfWrittenFiles = 0;
087:
088:            // When this flag isn't set, the compiler is started in normal mode
089:            // and compiles all projectfiles. If it's set, the compiler is started
090:            // in selective mode and only will see java sources from changed files
091:            // and files, which in any way depend on changed files.
092:            private boolean classesWereCompiledAFirstTime;
093:
094:            // The value of this depends on the compiler mode:
095:            // In normal mode, this is the same as the passed sourceDirectoryPath,
096:            // but in selective mode, its the path to the temp directory, to where
097:            // the files to be compiled are written.
098:            // It is used by the method decodeSingleErrorMessage().                                       
099:            private String selectedSourceDirectoryPath = "";
100:            private boolean selectiveCompileModeIsSet = false;
101:
102:            private String compilerVersion;
103:
104:            public CompilerRunnableForJavaC(final OutputManager outputManager,
105:                    final String javacExePath,
106:                    final String sourceDirectoryPath,
107:                    final String targetClassDirectoryPath,
108:                    final String[] sourceFilePathNames,
109:                    final String mainClassFilePath, final String jdkBasisPath,
110:                    final String[] additionalLibraryPathes,
111:                    final boolean classesWereCompiledAFirstTime,
112:                    final JButton compileButton, final JButton executeButton,
113:                    final boolean isProcessingProject,
114:                    final boolean launchAfterCompilation, final long startTime,
115:                    final IDE_ProjectFrameProvider projectFrameProvider,
116:                    final String compilerVersion) {
117:                this .outputManager = outputManager;
118:                this .javacExePath = javacExePath;
119:                this .sourceDirectoryPath = sourceDirectoryPath;
120:                this .targetClassDirectoryPath = targetClassDirectoryPath;
121:                this .sourceFilePathNames = sourceFilePathNames;
122:                this .mainClassFilePath = mainClassFilePath;
123:                this .jdkBasisPath = jdkBasisPath;
124:                this .additionalLibraryPathes = additionalLibraryPathes;
125:                this .classesWereCompiledAFirstTime = classesWereCompiledAFirstTime;
126:                this .compileButton = compileButton;
127:                this .executeButton = executeButton;
128:                this .isProcessingProject = isProcessingProject;
129:                this .launchAfterCompilation = launchAfterCompilation;
130:                this .startTime = startTime;
131:                this .projectFrameProvider = projectFrameProvider;
132:                this .compilerVersion = compilerVersion;
133:            } // Constructor
134:
135:            /**
136:             *  run method, which starts javac one time for all files.
137:             */
138:            public void run() {
139:                // Debug time measurement for this run() method:
140:                final long runMethodStartTime = System.currentTimeMillis();
141:                try {
142:                    // For memory reasons, generate subarrays with maxFilesPerCall elements.
143:                    // Compiling >> maxFilesPerCall files per call can easily cause out of memory errors.
144:                    // Already compiled files of each subarray are subtracted from
145:                    // the list, so they aren't compiled again unnecessarily.
146:                    // maxFilesPerCall is set depending on the memory, which was verified
147:                    // on the startup of Schmortopf. (faster, than doing it each time).
148:                    // Note that on the call this.compileFileList() to the compiler,
149:                    // the javac application again is started with -J-Xms and -J-Xmx options,
150:                    // which reserve additional memory for javac proportional to
151:                    // the number of filesPerCall.
152:                    int maxMemOnStartup = this .projectFrameProvider
153:                            .getMainFrameProvider()
154:                            .getVerifiedAvailableMemoryMB();
155:                    // filesPerCall :  125 files upto   50 MB free initially
156:                    //                 500 files for > 100 MB free initially
157:                    //                1000 files for > 150 MB free initially
158:                    //                2000 files for > 200 MB free initially
159:                    int maxFilesPerCall = 125;
160:                    if (maxMemOnStartup > 50) {
161:                        maxFilesPerCall = maxMemOnStartup * maxMemOnStartup
162:                                / 20;
163:                    }
164:                    // collect now :
165:                    Vector filesToBeCompiled = new Vector();
166:                    for (int i = 0; i < this .sourceFilePathNames.length; i++) {
167:                        filesToBeCompiled
168:                                .addElement(this .sourceFilePathNames[i]);
169:                    }
170:                    boolean listCompiledSuccessfully = true; // break on errors
171:                    int numberOfAlreadyCompiledFiles = 0;
172:                    while ((filesToBeCompiled.size() > 0)
173:                            && (listCompiledSuccessfully)) {
174:                        int partialListNumber = filesToBeCompiled.size();
175:                        if (partialListNumber > maxFilesPerCall)
176:                            partialListNumber = maxFilesPerCall;
177:                        String[] partialFileList = new String[partialListNumber];
178:                        int partialFileListIndex = 0;
179:                        for (int i = 0; i < partialListNumber; i++) {
180:                            partialFileList[i] = (String) filesToBeCompiled
181:                                    .elementAt(0); // always the first
182:                            filesToBeCompiled.removeElementAt(0);
183:                        }
184:
185:                        // If ALL classes already were compiled a first time,
186:                        // and if we can compile all in one run, we can feed javac only with the
187:                        // sourcefiles, which really need to be compiled, and only let it
188:                        // see the class files [of the previous run] of all other files :
189:                        boolean selectiveCompileModeIsAllowed = ((this .classesWereCompiledAFirstTime) && (filesToBeCompiled
190:                                .size() == 0));
191:
192:                        /* Debug
193:                        if( filesToBeCompiled.size() == 0 ) // enough memory for all files
194:                         {
195:                           outputManager.printLine( "Starting JavaC compile task for " +
196:                                                    partialListNumber + " files. [in 1 run]");
197:                         }
198:                        else // piecewise compiling, cause memory low
199:                         {
200:                           outputManager.printLine( "Starting JavaC compile task for " +
201:                                                    partialListNumber + " files and " +
202:                                                    filesToBeCompiled.size() + " files left.");
203:                         }
204:                        End Debug */
205:
206:                        /* Debug
207:                        outputManager.printLine("Files passed to JavaC for compiling [max 20 printed out] are :");
208:                        for( int i=0; i < partialFileList.length; i++ )
209:                         {
210:                           int nr = i+1;
211:                           outputManager.printLine( " " + nr + ")  " + partialFileList[i] );
212:                           if( i > 19 )
213:                            {
214:                               outputManager.printLine("Output stopped after 20 files...");
215:                               break;
216:                            }
217:                         }
218:                        outputManager.printLine(" ");
219:                        End Debug */
220:
221:                        // Start the compile task and get the compiled files :
222:                        String[] compiledClassFiles = this .compileFileList(
223:                                partialFileList, numberOfAlreadyCompiledFiles,
224:                                selectiveCompileModeIsAllowed);
225:
226:                        listCompiledSuccessfully = !(compiledClassFiles == null);
227:                        if (listCompiledSuccessfully) {
228:                            numberOfAlreadyCompiledFiles += compiledClassFiles.length;
229:                            // Remove all pathnames of compiled files, which are found
230:                            // in the filesToBeCompiled Vector :
231:                            for (int ri = 0; ri < compiledClassFiles.length; ri++) {
232:                                // The compiledClassFiles have no ending, but the path is the
233:                                // output class path, whereas the filepathes in the filesToBeCompiled
234:                                // are in the projectfile directory.
235:                                // For identifying already compiled files, we must transform the pathes
236:                                // of the compiledFiles into the project directory :
237:                                int startCut = this .targetClassDirectoryPath
238:                                        .length();
239:                                String relativeFilePath = compiledClassFiles[ri]
240:                                        .substring(startCut);
241:                                String projectFilePath = this .sourceDirectoryPath
242:                                        + relativeFilePath + ".java";
243:                                this .removeStringInStringVector(
244:                                        filesToBeCompiled, projectFilePath);
245:                            }
246:                        }
247:                    } // while
248:                    this .compilingWasSuccessful = listCompiledSuccessfully;
249:                } catch (final Exception anyEx) {
250:                    this .compilingWasSuccessful = false;
251:                    System.gc();
252:                    SwingUtilities.invokeLater(new Runnable() {
253:                        public void run() {
254:                            outputManager
255:                                    .printErrorLine("Compiler Exception. Unable to compile all files.");
256:                            Log
257:                                    .Error("Compiler Exception. Unable to compile all files.");
258:                            Log.Error(anyEx);
259:                        }
260:                    });
261:                } catch (final Error anyError) {
262:                    this .compilingWasSuccessful = false;
263:                    System.gc();
264:                    SwingUtilities.invokeLater(new Runnable() {
265:                        public void run() {
266:                            outputManager
267:                                    .printErrorLine("Compiler Error. Unable to compile all files.");
268:                            Log
269:                                    .Error("Compiler Error. Unable to compile all files.");
270:                            Log.Error(anyError);
271:                        }
272:                    });
273:                }
274:
275:                SwingUtilities.invokeLater(new Runnable() {
276:                    public void run() {
277:                        if (compilingWasSuccessful) {
278:                            if (sourceFilePathNames.length > 0) {
279:                                long elapsedTimeOfCompiling = (System
280:                                        .currentTimeMillis() - startTime) / 1000;
281:                                final String compileMessage = Language
282:                                        .Translate(
283:                                                "Compiled %1 files successfully in %2 sec",
284:                                                "" + sourceFilePathNames.length,
285:                                                "" + elapsedTimeOfCompiling);
286:                                outputManager.setCompilerInfoLabel(
287:                                        compileMessage, false);
288:                                outputManager.printLine(compileMessage + "  "
289:                                        + makeLowLevelFileStatisticsLine());
290:                                // Tell it the outputmanager :                                        
291:                                outputManager
292:                                        .setClassesWereCompiledAFirstTime(true);
293:                                outputManager
294:                                        .setClassesWereCompiledWithoutErrors(true);
295:                            } else {
296:                                outputManager
297:                                        .setCompilerInfoLabel(
298:                                                Language
299:                                                        .Translate("Compiler: All classes are up to date."),
300:                                                false);
301:                            }
302:                            if (launchAfterCompilation) {
303:                                outputManager.doExecute(mainClassFilePath);
304:                            }
305:
306:                            /* Debug: totalNumberOfCompiledFiles should equal sourceFilePathNames.length:
307:                            final String testMessage = "Total number compiled by JavaC = " + totalNumberOfCompiledFiles;
308:                            outputManager.printLine(testMessage);
309:                             */
310:
311:                        } else {
312:                            String message = Language
313:                                    .Translate("Compiling stopped:  ");
314:                            if (numberOfErrors == 0) // Should not occure.
315:                            {
316:                                message += Language
317:                                        .Translate("Internal error."); // -> examine std output... ide problem.
318:
319:                                /*
320:                                // Debug output for this case:
321:                                Log.Error("------------ Compiler: Internal error ---------------");
322:                                Log.Error("--- decodeErrorMessagesCalls= " + decodeErrorMessagesCalls );
323:                                Log.Error("------------ Compiler: Internal error ---------------");
324:                                // We at least can output the unprocessed error lines, if they have been any :
325:                                for( int i=0; i < errorLinesBuffer.size(); i++ )
326:                                 {
327:                                   Log.Error( (String)errorLinesBuffer.elementAt(i) );
328:                                 }
329:                                 */
330:
331:                            } else if (numberOfErrors == 1) {
332:                                message += Language
333:                                        .Translate("An error has been found.");
334:                            } else {
335:                                message += Language.Translate(
336:                                        "% errors have been found.", ""
337:                                                + numberOfErrors);
338:                            }
339:                            outputManager.setCompilerInfoLabel(message, false);
340:                            // Tell it to the outputmanager :
341:                            outputManager
342:                                    .setClassesWereCompiledWithoutErrors(false);
343:                            // Additionally, *IF* there are no processes running (which can write on the
344:                            // output area anytime, we don't need chronological order and do the
345:                            // user a favour by scrolling the view to the top where the error lines
346:                            // do start in this case:
347:                            if (outputManager.getProcessManager()
348:                                    .getNumberOfRunningProcesses() == 0) {
349:                                outputManager.scrollUpEditorTextPane(); // No EDT required here
350:                            }
351:                        }
352:                        compileButton.setEnabled(true);
353:                        executeButton.setEnabled(true);
354:                    }
355:                });
356:
357:                // Free associations for helping the GC.
358:                // Because some actions above are processed delayed, we must delay this too :
359:                SwingUtilities.invokeLater(new Runnable() {
360:                    public void run() {
361:                        outputManager = null;
362:                        projectFrameProvider = null;
363:                        errorLinesBuffer.setSize(0);
364:                        errorLinesBuffer = null;
365:                        sourceFilePathNames = null;
366:                    }
367:                });
368:
369:                /* Debug: Time measurement:
370:                long runMethodElapsedTime = System.currentTimeMillis() - runMethodStartTime;
371:                Log.Info(">>> CompilerRunnableForJavaC.run() time for run()= " +
372:                                   runMethodElapsedTime + "  [ms]" );
373:                 */
374:
375:            } // run
376:
377:            /**
378:             *  Compiles the passed file list. returns true, if all was compiled.
379:             *  Returns an array which consists of the pathnames of all compiled files,
380:             *  which also can have zero length.
381:             *  If the compiler stopped with an error, null is returned to indicate that.
382:             */
383:            private String[] compileFileList(
384:                    final String[] raw_SourceFilePathNamesPartList,
385:                    final int numberOfAlreadyCompiledFiles,
386:                    final boolean selectiveCompileModeIsAllowed)
387:                    throws Exception, Error {
388:                long compileFileListStartTime = System.currentTimeMillis();
389:
390:                String[] compiledFiles = null; // is the returned attribute
391:                // Defaults for normal (non selective) compile mode:
392:                this .selectedSourceDirectoryPath = this .sourceDirectoryPath;
393:                String[] sourceFilePathNamesPartList = raw_SourceFilePathNamesPartList;
394:
395:                // Test and set selectiveCompileMode:
396:                // If selectiveCompileModeIsAllowed is set, and if we have less than 500 files for
397:                // compiling, we try to do it in selectiveCompileMode:
398:                // In this case, we copy the files for compiling into a separate temp directory
399:                // and let javac see only these sourcefiles, and all class files in the
400:                // output directory. Condition for this is, that all files have been compiled
401:                // one time before.
402:                this .selectiveCompileModeIsSet = false;
403:                if ((selectiveCompileModeIsAllowed)
404:                        && (sourceFilePathNamesPartList.length < 500)) {
405:                    // Try to copy all to the temp directory and get their pathes:
406:                    String tempSourceDirPath = ""; // Used on error, when we fallback for user information
407:                    try {
408:                        File outputDirectory = new File(
409:                                this .targetClassDirectoryPath);
410:                        String outputDirectoryName = outputDirectory.getName();
411:                        if (outputDirectory.exists()) {
412:                            if (outputDirectory.isDirectory()) {
413:                                File parentDirectory = outputDirectory
414:                                        .getParentFile();
415:                                // We must keep it unique, so concurrent compiler runs won't interfere:
416:                                String tempSourceDirName = outputDirectoryName
417:                                        + "SRC.temp";
418:                                File tempSourceDirectory = new File(
419:                                        parentDirectory, tempSourceDirName);
420:                                tempSourceDirPath = tempSourceDirectory
421:                                        .getPath();
422:                                boolean success = true;
423:                                if (tempSourceDirectory.exists()) {
424:                                    // Remove anything in it:
425:                                    success = FileUtilities
426:                                            .MakeDirectoryEmpty(tempSourceDirectory);
427:                                } else {
428:                                    tempSourceDirectory.mkdirs();
429:                                }
430:                                if (success) {
431:                                    // Copy all source files into the temp directory,
432:                                    // keep project relative subfolders associated with the package pathes
433:                                    // and overwrite the sourceFilePathNamesPartList elements with the
434:                                    // destination names, once all has succeeded.
435:                                    int skipLength = sourceDirectoryPath
436:                                            .length();
437:
438:                                    String[] selectiveModeSourceFilePathNamesPartList = new String[sourceFilePathNamesPartList.length];
439:                                    String relativeSourcePath = null;
440:                                    String targetPath = null;
441:                                    File targetFile = null;
442:                                    File parentDir = null;
443:                                    for (int fileIndex = 0; fileIndex < sourceFilePathNamesPartList.length; fileIndex++) {
444:                                        relativeSourcePath = sourceFilePathNamesPartList[fileIndex]
445:                                                .substring(skipLength);
446:                                        targetPath = tempSourceDirectory
447:                                                .getPath()
448:                                                + relativeSourcePath;
449:
450:                                        //this.outputManager.printLine(">src= " + sourceFilePathNamesPartList[fileIndex]);
451:                                        //this.outputManager.printLine(">relative src= " + relativeSourcePath);
452:                                        //this.outputManager.printLine(">target= " + targetPath);
453:
454:                                        selectiveModeSourceFilePathNamesPartList[fileIndex] = targetPath;
455:
456:                                        // Create the parentdirectory:
457:                                        targetFile = new File(targetPath);
458:                                        parentDir = targetFile.getParentFile();
459:                                        parentDir.mkdirs();
460:                                        // And copy:
461:                                        final CommentedBoolean fileCopyResult = FileUtilities
462:                                                .FileCopy(
463:                                                        sourceFilePathNamesPartList[fileIndex],
464:                                                        targetPath);
465:                                        if (!fileCopyResult.isTrue) {
466:                                            throw new Exception(
467:                                                    "FileCopy failed to "
468:                                                            + targetPath);
469:                                        }
470:                                        relativeSourcePath = null;
471:                                        targetPath = null;
472:                                        targetFile = null;
473:                                        parentDir = null;
474:                                    } // for
475:                                    // If we come here, no exception was thrown, so we can continue:
476:                                    // Overwrite the source array with the one containing the selected files only,
477:                                    // and set the new path and the ok flag:
478:
479:                                    //this.outputManager.printLine("selectiveCompileModeIsSet = true OUTCOMMENTED");
480:                                    this .selectedSourceDirectoryPath = tempSourceDirectory
481:                                            .getPath();
482:                                    sourceFilePathNamesPartList = selectiveModeSourceFilePathNamesPartList;
483:                                    this .selectiveCompileModeIsSet = true;
484:                                }
485:                                parentDirectory = null;
486:                                tempSourceDirectory = null;
487:                                tempSourceDirName = null;
488:                            }
489:                        }
490:                        outputDirectory = null;
491:                        outputDirectoryName = null;
492:                    } catch (Exception anyEx) {
493:                        // fallback to normal mode.
494:                        this .outputManager
495:                                .printLine(">------------------------------------------");
496:                        this .outputManager
497:                                .printLine(">Compiler: Selective mode could not be set.");
498:                        this .outputManager.printLine(">Compiler: Reason: "
499:                                + anyEx.getMessage());
500:                        this .outputManager
501:                                .printLine(">Compiler: Check, if you have enough disk space on "
502:                                        + tempSourceDirPath);
503:                        this .outputManager
504:                                .printLine(">------------------------------------------");
505:                    }
506:                } // selectedSourceDirectoryPath
507:
508:                /* Debug:
509:                if( this.selectiveCompileModeIsSet )
510:                 {
511:                   this.outputManager.printLine(">Compiler: Runs in selective mode.");
512:                 }
513:                else
514:                 {
515:                   this.outputManager.printLine(">Compiler: Runs in normal mode.");
516:                 }
517:                 */
518:
519:                // Debug:
520:                //final long elapsed1 = System.currentTimeMillis() - compileFileListStartTime;
521:                //Log.Info("compileFileList: elapsed1= " + elapsed1);
522:                // Write the temporary file which contains the source files to be compiled :
523:                // Location independent of compile mode.
524:                String sourcesFilePathName = this .sourceDirectoryPath
525:                        + SchmortopfConstants.OSDelimiter + "compiling.txt";
526:                File sourcesFile = new File(sourcesFilePathName);
527:                FileOutputStream fileOut = new FileOutputStream(sourcesFile);
528:                BufferedOutputStream bufOut = new BufferedOutputStream(fileOut);
529:                String this Line;
530:                for (int i = 0; i < sourceFilePathNamesPartList.length; i++) {
531:                    this Line = sourceFilePathNamesPartList[i] + "\n";
532:                    bufOut.write(this Line.getBytes());
533:                }
534:                bufOut.flush();
535:                bufOut.close();
536:                bufOut = null;
537:                fileOut = null;
538:                this Line = null;
539:                sourcesFile = null;
540:                // Build the compiler arguments.
541:                // Pass xmx and xms commands to the javac jvm, which reserve
542:                // additional memory proportional to the number of files to be compiled.
543:                String[] args;
544:                int specialMemory_MB = sourceFilePathNamesPartList.length / 4;
545:                // Divider was 6 upto 1.3_07, but this caused javac 1.4.2_01 to
546:                // go outofmemory seldomly, but javac 1.4.2_03 always goes outofmemory
547:                // for 1500+ files. Therefore set to 4 for version 1.3_08 Jan. 2004.
548:                // 250 MB for 1000 source files to be compiled in one call.
549:                if (specialMemory_MB < 64)
550:                    specialMemory_MB = 64;
551:                // Max JVM memory set to specialMemory_MB: (would be 64MB default)
552:                // Note that just setting a high value wouldn't work, at least on
553:                // some Mac OSX computers, which seemed to try to reserve the xmx
554:                // memory on startup. There it failed, if the system didnt have
555:                // that amount of REAL memory (virtual memory didnt count..).
556:                String xmxArg = "-J-Xmx" + Integer.toString(specialMemory_MB)
557:                        + "m";
558:                // Startsize set to 16MB: (would be 2MB default)
559:                String xmsArg = "-J-Xms" + Integer.toString(16) + "m";
560:                // Note that SUN changed src.jar to src.zip in jdk 1.4
561:
562:                // Add all library pathes to the sourceLibrariesPathNames string :
563:                final StringBuffer sourceLibrariesPathNames = new StringBuffer(
564:                        "");
565:
566:                // Add the directory containing the class files, if selective mode is set:
567:                if (this .selectiveCompileModeIsSet) {
568:                    sourceLibrariesPathNames
569:                            .append(this .targetClassDirectoryPath);
570:                    if (additionalLibraryPathes.length > 0) {
571:                        sourceLibrariesPathNames.append(";");
572:                    }
573:                }
574:
575:                if (additionalLibraryPathes.length > 0) {
576:                    for (int libIndex = 0; libIndex < additionalLibraryPathes.length; libIndex++) {
577:                        sourceLibrariesPathNames
578:                                .append(additionalLibraryPathes[libIndex]);
579:                        if (libIndex < additionalLibraryPathes.length - 1) {
580:                            sourceLibrariesPathNames.append(";");
581:                        }
582:                    } // for
583:                }
584:
585:                // For the 1.4, 1.5 compiler, we add the -source=1.x switch, so
586:                // assert directives are recognized and compiled by 1.4 and
587:                // generics,static imports.. are compiled by 1.5.
588:                if (compilerVersion.startsWith("1.4")
589:                        || compilerVersion.startsWith("1.5")) {
590:                    String compilerVersionTag = compilerVersion
591:                            .startsWith("1.4") ? "1.4" : "1.5";
592:                    if (sourceLibrariesPathNames.length() > 0) {
593:                        // include libs in special classpath:
594:                        args = new String[] { this .javacExePath, "-d",
595:                                this .targetClassDirectoryPath, xmsArg, xmxArg,
596:                                "-classpath",
597:                                sourceLibrariesPathNames.toString(),
598:                                "-sourcepath",
599:                                this .selectedSourceDirectoryPath, "-source",
600:                                compilerVersionTag, "-verbose", // this is !*NEEDED*! always
601:                                "-nowarn", // make this an option in future
602:                                "@" + sourcesFilePathName };
603:                    } else {
604:                        // no special classpath :
605:                        args = new String[] { this .javacExePath, "-d",
606:                                this .targetClassDirectoryPath, xmsArg, xmxArg,
607:                                "-sourcepath",
608:                                this .selectedSourceDirectoryPath, "-source",
609:                                compilerVersionTag, "-verbose", // this is !*NEEDED*! always
610:                                "-nowarn", // make this an option in future
611:                                "@" + sourcesFilePathName };
612:                    }
613:                } else {
614:                    // Usual case for 1.3 jdks :
615:                    if (sourceLibrariesPathNames.length() > 0) {
616:                        // include libs in special classpath:
617:                        args = new String[] { this .javacExePath, "-d",
618:                                this .targetClassDirectoryPath, xmsArg, xmxArg,
619:                                "-classpath",
620:                                sourceLibrariesPathNames.toString(),
621:                                "-sourcepath",
622:                                this .selectedSourceDirectoryPath, "-verbose", // this is !*NEEDED*! always
623:                                "-nowarn", // make this an option in future
624:                                "@" + sourcesFilePathName };
625:                    } else {
626:                        // no special classpath :
627:                        args = new String[] { this .javacExePath, "-d",
628:                                this .targetClassDirectoryPath, xmsArg, xmxArg,
629:                                "-sourcepath",
630:                                this .selectedSourceDirectoryPath, "-verbose", // this is !*NEEDED*! always
631:                                "-nowarn", // make this an option in future
632:                                "@" + sourcesFilePathName };
633:                    }
634:                } // else
635:
636:                // Debug:
637:                //final long elapsed2 = System.currentTimeMillis() - compileFileListStartTime;
638:                //Log.Info("compileFileList: elapsed2= " + elapsed2);
639:
640:                this .outputManager.printLine("Calling compiler "
641:                        + this .javacExePath);
642:
643:                // The stream, which buffers the whole output (stdout and err)
644:                // and updates the compiler display in realtime on one side
645:                // as well as serves as source for parsing the output for
646:                // errormessages at the end. (This stream also has a compilerinfo thread
647:                // which processes info updates for the compiler info label. This thread
648:                // must be stopped by calling compilerOutputStream.terminate(), when we
649:                // are through all :
650:                final CompilerOutputStreamForJavaC compilerOutputStream = new CompilerOutputStreamForJavaC(
651:                        this .outputManager, numberOfAlreadyCompiledFiles);
652:                // Start the java compiler now :
653:                final Runtime rt = Runtime.getRuntime();
654:                final Process compilerProcess = rt.exec(args);
655:
656:                // Debug:
657:                //final long elapsed3 = System.currentTimeMillis() - compileFileListStartTime;
658:                //Log.Info("compileFileList: elapsed3= " + elapsed3);
659:
660:                // Redirect both javac outputstreams to the CompilerOutputStream :
661:                // JavaC writes verbose messages to the error outputstream.
662:                final CompilerOutputProcessor compilerOutputProcessor = new CompilerOutputProcessor(
663:                        compilerProcess.getInputStream(), compilerOutputStream);
664:                compilerOutputProcessor.start();
665:                final CompilerOutputProcessor compilerErrorOutputProcessor = new CompilerOutputProcessor(
666:                        compilerProcess.getErrorStream(), compilerOutputStream);
667:                compilerErrorOutputProcessor.start();
668:
669:                // Debug:
670:                //final long elapsed4 = System.currentTimeMillis() - compileFileListStartTime;
671:                //Log.Info("compileFileList: elapsed4= " + elapsed4);
672:
673:                // Pass the process to the processmanager, so it will display it
674:                // and gives the possibility for the user to kill the process by a mouseclick:
675:                this .outputManager.getProcessManager().addToRunningProcesses(
676:                        ProcessManager.COMPILER_PROCESS, compilerProcess,
677:                        this .javacExePath, "");
678:
679:                // If javac pops up a systemframe, bring our frame to front.
680:                // We test that tree times :
681:                JFrame theDevelopFrame = this .outputManager.getProjectFrame()
682:                        .getParentFrameForChildren();
683:                theDevelopFrame.toFront();
684:                Thread.sleep(80);
685:                theDevelopFrame.toFront();
686:                Thread.sleep(80);
687:                theDevelopFrame.toFront();
688:
689:                // Debug:
690:                //final long elapsed5 = System.currentTimeMillis() - compileFileListStartTime;
691:                //Log.Info("compileFileList: elapsed5= " + elapsed5);
692:
693:                // Wait for termination and get the return value :
694:                final int exitValue = compilerProcess.waitFor();
695:                boolean listWasCompiledSuccessfully = (exitValue == 0);
696:
697:                // Debug:
698:                //final long elapsed6 = System.currentTimeMillis() - compileFileListStartTime;
699:                //Log.Info("compileFileList: elapsed6= " + elapsed6);
700:
701:                // Tell the outputmanager to remove this process from its list:
702:                this .outputManager.getProcessManager()
703:                        .removeFromRunningProcesses(compilerProcess);
704:                if (listWasCompiledSuccessfully) {
705:                    // Remove all files from the compilerlist :
706:                    for (int i = 0; i < sourceFilePathNamesPartList.length; i++) {
707:                        String pathToBeRemoved = sourceFilePathNamesPartList[i];
708:                        // An additional work, if the compiler works in selective mode:
709:                        // In this case, the sourcefiles to be compiled have been copied
710:                        // to a temp directory this.selectedSourceDirectoryPath, which
711:                        // must be replaced by the original file basis directory, which is
712:                        // this.sourceDirectoryPath, otherwise the error buttons won't work:
713:                        if (this .selectiveCompileModeIsSet) {
714:                            pathToBeRemoved = pathToBeRemoved
715:                                    .substring(this .selectedSourceDirectoryPath
716:                                            .length());
717:                            pathToBeRemoved = this .sourceDirectoryPath
718:                                    + pathToBeRemoved;
719:                        }
720:                        this .outputManager
721:                                .removeSourceFilePathFromCompilerList(pathToBeRemoved);
722:                        pathToBeRemoved = null; // GC assistance
723:                    } // for
724:                    compiledFiles = compilerOutputStream
725:                            .getPathNamesOfCompiledClasses();
726:
727:                    /* Start Debug: Print out the first 60 lines of the compiler output :
728:                    outputManager.printLine(" ");
729:                    outputManager.printLine("----------- START First 60 lines of the javac parsing output --------");
730:                    String[] lines = StringUtilities.SplitString(compilerOutputStream.toString(),"\n");
731:                    int writtenTestLines = 0;
732:                    for( int lineIndex=0; lineIndex < lines.length; lineIndex++ )
733:                     {
734:                       if( lines[lineIndex].startsWith("[parsing started") )
735:                        {
736:                          writtenTestLines++;
737:                          outputManager.printLine( "" + writtenTestLines + ") " + lines[lineIndex] );
738:                          if( writtenTestLines > 60 ) break;
739:                        }
740:                     }
741:                    outputManager.printLine("----------- END First 60 lines of the compiler output --------");
742:                    outputManager.printLine(" ");
743:                     End Debug */
744:
745:                } else {
746:                    // Make sure, the compiler output text area is or becomes visible for the user :
747:                    this .outputManager.getProjectFrame()
748:                            .checkPopupCompilerOutputPanel();
749:                    // and print the error text and button output :
750:                    final String compilerOutput = compilerOutputStream
751:                            .toString();
752:                    this .decodeErrorMessages(compilerOutput);
753:                    compiledFiles = null; // indicates the error, as this is returned
754:                }
755:
756:                // Debug:         
757:                //final long elapsed7 = System.currentTimeMillis() - compileFileListStartTime;
758:                //Log.Info("compileFileList: elapsed7= " + elapsed7);
759:
760:                // Now we wait, until both compilerOutputProcessor have
761:                // processed their buffers and have shut down, or until
762:                // a security time has passed :
763:                long startTime = System.currentTimeMillis();
764:                while (true) {
765:                    if (compilerOutputProcessor.getHasTerminated()
766:                            && compilerErrorOutputProcessor.getHasTerminated()) {
767:                        // This is the normal operation - the 2 processor threads
768:                        // automatically were shut down, when javac terminated.
769:                        break;
770:                    }
771:                    Thread.sleep(100);
772:                    if (System.currentTimeMillis() - startTime > 10000) {
773:                        Log.Warn("*** Caution: Unable to shut down some");
774:                        Log.Warn("*** output processing tasks. This could");
775:                        Log.Warn("*** slow down the program execution.");
776:                        break;
777:                    }
778:                }
779:
780:                // Debug:
781:                //final long elapsed8 = System.currentTimeMillis() - compileFileListStartTime;
782:                //Log.Info("compileFileList: elapsed8= " + elapsed8);
783:
784:                // Update counters for this list:
785:                this .numberOfLoadedFiles += compilerErrorOutputProcessor
786:                        .getNumberOfLoadedFiles();
787:                this .numberOfParsedFiles += compilerErrorOutputProcessor
788:                        .getNumberOfParsedFiles();
789:                this .numberOfCheckedFiles += compilerErrorOutputProcessor
790:                        .getNumberOfCheckedFiles();
791:                this .numberOfWrittenFiles += compilerErrorOutputProcessor
792:                        .getNumberOfWrittenFiles();
793:                this .totalNumberOfCompiledFiles += compilerOutputStream
794:                        .getNumberOfCompiledFiles();
795:                // Shut down the compilerOutputStreams info updater too :
796:                compilerOutputStream.terminate();
797:                sourceFilePathNamesPartList = null;
798:                args = null;
799:                xmxArg = null;
800:                xmsArg = null;
801:                return compiledFiles;
802:            } // compileFileList
803:
804:            /**
805:             *  Returns a lowlevel counter statistics about number of files
806:             *  loaded,parsed,checked and written by the compiler.
807:             *  I call it lowlevel, because there can be multiple files
808:             *  associated to one java source file, if this file contains multiple
809:             *  inner classes or anonymous classes.
810:             */
811:            private String makeLowLevelFileStatisticsLine() {
812:                final StringBuffer buf = new StringBuffer("  ( ");
813:                buf.append(Language.Translate("Disk") + ":");
814:                buf.append(" " + this .numberOfLoadedFiles + " "
815:                        + Language.Translate("loaded") + ",");
816:                buf.append(" " + this .numberOfParsedFiles + " "
817:                        + Language.Translate("parsed") + ",");
818:                buf.append(" " + this .numberOfCheckedFiles + " "
819:                        + Language.Translate("checked") + ",");
820:                buf.append(" " + this .numberOfWrittenFiles + " "
821:                        + Language.Translate("written") + " )");
822:                return buf.toString();
823:            } // makeLowLevelFileStatisticsLine
824:
825:            private void decodeErrorMessages(final String compilerOutput) {
826:
827:                this .decodeErrorMessagesCalls++;
828:                this .errorLinesBuffer.addElement(compilerOutput);
829:
830:                // Decompose the lines, but skip all lines, which start with a "[" sign,
831:                // because these are usual compiler infos in the "-verbose" mode, which
832:                // is used ALWAYS.
833:                String[] tokens = StringUtilities.SplitString(compilerOutput,
834:                        "\n");
835:                final Vector linesVector = new Vector();
836:                for (int i = 0; i < tokens.length; i++) {
837:                    // Exclude file check,load and wrote messages, which all start
838:                    // with a [ sign :
839:                    if (!tokens[i].startsWith("[")) {
840:                        linesVector.addElement(tokens[i]);
841:                    }
842:                }
843:                final String[] lines = new String[linesVector.size()];
844:                linesVector.copyInto(lines);
845:
846:                // Intercept java.lang.OutOfMemoryError messages right here -
847:                // as this makes further things senseless :
848:                for (int i = 0; i < lines.length; i++) {
849:                    if (lines[i].indexOf("java.lang.OutOfMemoryError") >= 0) {
850:                        try {
851:                            System.gc();
852:                            Thread.sleep(300);
853:                            System.gc();
854:                        } catch (Exception any234765) {
855:                        }
856:                        JOptionPane
857:                                .showMessageDialog(
858:                                        this .projectFrameProvider
859:                                                .getParentFrameForChildren(),
860:                                        Language
861:                                                .Translate("An out-of-memory error has occured.\nYour system has not enough free memory\nfor compiling the files.")
862:                                                + "\n");
863:                        return;
864:                    }
865:                }
866:
867:                /* Start Debug: just output all lines :
868:                this.outputManager.printLine("|-------- rawoutput start ------------------------- ");
869:                for( int i=0; i < lines.length; i++ )
870:                 {
871:                   this.outputManager.printLine("| line" + i + " = $" + lines[i] + "$" );
872:                 }
873:                this.outputManager.printLine("|-------- rawoutput end -------------------------");
874:                 End Debug */
875:
876:                // For JavaC, each error description starts with a line, which contains
877:                // the sequences ".java" and ": ".
878:                // It contains 3 or more lines each.
879:                // One line should contain a ^ sign, which is the locationpointer.
880:                final Vector singleMessageVector = new Vector();
881:                for (int i = 0; i < lines.length; i++) {
882:                    if ((lines[i].indexOf(".java") > 0)
883:                            && (lines[i].indexOf(": ") > 0)) {
884:                        // new single message starts :
885:                        if (singleMessageVector.size() > 0) {
886:                            // send what we have until now :
887:                            final String[] singleMessageLines = new String[singleMessageVector
888:                                    .size()];
889:                            singleMessageVector.copyInto(singleMessageLines);
890:                            this .decodeSingleErrorMessage(singleMessageLines);
891:                        }
892:                        singleMessageVector.removeAllElements();
893:                    }
894:                    singleMessageVector.addElement(lines[i]);
895:                } // for
896:                // Test the rest message: If it too starts with a valid error descriptor,
897:                // send it too :
898:                if (singleMessageVector.size() > 0) {
899:                    // send what we have until now :
900:                    final String[] singleMessageLines = new String[singleMessageVector
901:                            .size()];
902:                    singleMessageVector.copyInto(singleMessageLines);
903:                    if ((singleMessageLines[0].indexOf(".java") > 0)
904:                            && (singleMessageLines[0].indexOf(": ") > 0)) {
905:                        this .decodeSingleErrorMessage(singleMessageLines);
906:                    } else {
907:                        // Obviously we couldnt parse this correctly, so we at least
908:                        // print it as it is :
909:                        for (int i = 0; i < singleMessageLines.length; i++) {
910:                            this .outputManager
911:                                    .printErrorLine(singleMessageLines[i]);
912:                        }
913:                    }
914:                }
915:            } // decodeErrorMessages
916:
917:            private void decodeSingleErrorMessage(final String[] errorLines) {
918:                this .numberOfErrors++;
919:
920:                final String[] parsedErrorLines = new String[errorLines.length];
921:                for (int i = 0; i < parsedErrorLines.length; i++) {
922:                    parsedErrorLines[i] = "";
923:                }
924:
925:                // The first one is the descriptor. Extract the filePath :
926:                final String descriptor = errorLines[0]; // exists always
927:                int numberEndIndex = descriptor.indexOf(": ");
928:                if (numberEndIndex > 0) {
929:                    // go back to previous : sign :
930:                    int numberStartIndex = numberEndIndex - 1;
931:                    while ((descriptor.charAt(numberStartIndex) != ':')
932:                            && (numberStartIndex > 0)) {
933:                        numberStartIndex--;
934:                    }
935:                    if (numberStartIndex > 0) {
936:                        String filePath = descriptor.substring(0,
937:                                numberStartIndex);
938:                        final String lineNumberString = descriptor.substring(
939:                                numberStartIndex + 1, numberEndIndex);
940:                        // Get the lineNumber
941:                        int lineNumber = -1;
942:                        try {
943:                            lineNumber = Integer.parseInt(lineNumberString);
944:                        } catch (Exception anyEx) {
945:                        }
946:                        // The linenumber must be decremented by one :
947:                        lineNumber -= 1;
948:                        // Get the first pased errorline :
949:                        parsedErrorLines[0] = descriptor.substring(
950:                                numberEndIndex + 2, descriptor.length() - 1);
951:                        // Move the other ones and catch the locationPointer line,
952:                        // which consists of spaces and one ^ sign :
953:                        int column = -1;
954:                        for (int i = 1; i < errorLines.length; i++) {
955:                            parsedErrorLines[i] = errorLines[i];
956:                            final int c = errorLines[i].indexOf('^');
957:                            if (c >= 0) {
958:                                column = c;
959:                            }
960:                        }
961:
962:                        // An additional work, if the compiler works in selective mode:
963:                        // In this case, the sourcefiles to be compiled have been copied
964:                        // to a temp directory this.selectedSourceDirectoryPath, which
965:                        // must be replaced by the original file basis directory, which is
966:                        // this.sourceDirectoryPath, otherwise the error buttons won't work:
967:                        if (this .selectiveCompileModeIsSet) {
968:                            filePath = filePath
969:                                    .substring(this .selectedSourceDirectoryPath
970:                                            .length());
971:                            filePath = this .sourceDirectoryPath + filePath;
972:                        }
973:                        outputManager.appendErrorDescriptionForJavaC(filePath,
974:                                parsedErrorLines, lineNumber, column);
975:                    }
976:                }
977:            } // decodeSingleErrorMessage
978:
979:            private void removeStringInStringVector(Vector vector, String string) {
980:                int vIndex = 0;
981:                while (vIndex < vector.size()) {
982:                    String this Element = (String) vector.elementAt(vIndex);
983:                    if (this Element.equals(string)) {
984:                        vector.removeElementAt(vIndex);
985:                    } else {
986:                        vIndex++;
987:                    }
988:                }
989:            }
990:
991:        } // CompilerRunnableForJavaC
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.