KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > rice > cs > drjava > model > DefaultJavadocModel


1 /*BEGIN_COPYRIGHT_BLOCK
2  *
3  * This file is part of DrJava. Download the current version of this project from http://www.drjava.org/
4  * or http://sourceforge.net/projects/drjava/
5  *
6  * DrJava Open Source License
7  *
8  * Copyright (C) 2001-2005 JavaPLT group at Rice University (javaplt@rice.edu). All rights reserved.
9  *
10  * Developed by: Java Programming Languages Team, Rice University, http://www.cs.rice.edu/~javaplt/
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
13  * documentation files (the "Software"), to deal with the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
15  * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
16  *
17  * - Redistributions of source code must retain the above copyright notice, this list of conditions and the
18  * following disclaimers.
19  * - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
20  * following disclaimers in the documentation and/or other materials provided with the distribution.
21  * - Neither the names of DrJava, the JavaPLT, Rice University, nor the names of its contributors may be used to
22  * endorse or promote products derived from this Software without specific prior written permission.
23  * - Products derived from this software may not be called "DrJava" nor use the term "DrJava" as part of their
24  * names without prior written permission from the JavaPLT group. For permission, write to javaplt@rice.edu.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
27  * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28  * CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
29  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30  * WITH THE SOFTWARE.
31  *
32 END_COPYRIGHT_BLOCK*/

33
34 package edu.rice.cs.drjava.model;
35
36 import java.io.File JavaDoc;
37 import java.io.IOException JavaDoc;
38 import java.util.HashSet JavaDoc;
39 import java.util.ArrayList JavaDoc;
40 import java.util.LinkedList JavaDoc;
41 import java.util.List JavaDoc;
42 import java.util.Collection JavaDoc;
43
44 import edu.rice.cs.plt.io.IOUtil;
45 import edu.rice.cs.util.FileOps;
46 import edu.rice.cs.util.ArgumentTokenizer;
47 import edu.rice.cs.util.DirectorySelector;
48 import edu.rice.cs.util.FileOpenSelector;
49 import edu.rice.cs.drjava.model.FileSaveSelector;
50 import edu.rice.cs.util.OperationCanceledException;
51 import edu.rice.cs.util.newjvm.ExecJVM;
52 import edu.rice.cs.drjava.DrJava;
53 import edu.rice.cs.drjava.config.Configuration;
54 import edu.rice.cs.drjava.config.OptionConstants;
55 import edu.rice.cs.drjava.config.FileOption;
56 import edu.rice.cs.drjava.platform.PlatformFactory;
57 import edu.rice.cs.drjava.platform.PlatformSupport;
58 import edu.rice.cs.drjava.model.compiler.CompilerErrorModel;
59 import edu.rice.cs.drjava.model.compiler.CompilerError;
60 import edu.rice.cs.drjava.model.definitions.InvalidPackageException;
61
62 /** Default implementation of JavadocModel interface; generates Javadoc HTML files for a set of documents.
63  * @version $Id: DefaultJavadocModel.java 4096 2007-01-30 02:37:18Z rcartwright $
64  */

65 public class DefaultJavadocModel implements JavadocModel {
66
67   /** Used by CompilerErrorModel to open documents that have errors. */
68   private GlobalModel _model;
69
70   /**Manages listeners to this model. */
71   private final JavadocEventNotifier _notifier = new JavadocEventNotifier();
72
73   /** The error model containing all current Javadoc errors. */
74   private CompilerErrorModel _javadocErrorModel;
75
76   /** Main constructor.
77    * @param model Source of documents for this JavadocModel
78    */

79   public DefaultJavadocModel(GlobalModel model) {
80     _model = model;
81     _javadocErrorModel = new CompilerErrorModel();
82   }
83
84   //-------------------------- Listener Management --------------------------//
85

86   /** Add a JavadocListener to the model.
87    * @param listener a listener that reacts to Javadoc events
88    */

89   public void addListener(JavadocListener listener) { _notifier.addListener(listener); }
90
91   /** Remove a JavadocListener from the model. If the listener is not currently
92    * listening to this model, this method has no effect.
93    * @param listener a listener that reacts to Javadoc events
94    */

95   public void removeListener(JavadocListener listener) { _notifier.removeListener(listener); }
96
97   /** Removes all JavadocListeners from this model. */
98   public void removeAllListeners() { _notifier.removeAllListeners(); }
99
100   //----------------------------- Error Results -----------------------------//
101

102   /** Accessor for the Javadoc error model.
103    * @return the CompilerErrorModel managing Javadoc errors.
104    */

105   public CompilerErrorModel getJavadocErrorModel() { return _javadocErrorModel; }
106
107   /** Clears all current Javadoc errors. */
108   public void resetJavadocErrors() {
109     _javadocErrorModel = new CompilerErrorModel();
110   }
111
112   // -------------------- Javadoc All Documents --------------------
113

114   /** Javadocs all open documents, after ensuring that all are saved. The user provides a destination, and the global
115     * model provides the package info. Must run in the event-handling thread.
116     * @param select a command object for selecting a directory and warning a user about bad input
117     * @param saver a command object for saving a document (if it moved/changed)
118     * @param classPath a collection of classpath elements to be used by Javadoc
119     * @throws IOException if there is a problem manipulating files
120     */

121   public void javadocAll(DirectorySelector select, final FileSaveSelector saver, final String JavaDoc classPath)
122     throws IOException JavaDoc {
123         
124     /* Only javadoc if all are saved. Removed because it is already done inside suggestJavadocDestination; fixes bug
125        where pop-up is shown twice) */

126     if (_model.hasModifiedDocuments() || _model.hasUntitledDocuments()) { return; } /* abort if files remain unsaved */
127     
128     Configuration config = DrJava.getConfig();
129     File JavaDoc destDir = config.getSetting(OptionConstants.JAVADOC_DESTINATION);
130     
131     // Get the destination directory via the DirectorySelector, if appropriate.
132
try {
133       if (destDir.equals(FileOption.NULL_FILE)) {
134         /* This is the default, stock behavior of a new install. If no destination is set, don't pass
135          anything to the ui command. Let the command object decide what to do. */

136         destDir = select.getDirectory(null);
137       }
138       else
139         // Otherwise, tell the command object to prefer the config's default.
140
destDir = select.getDirectory(destDir);
141       
142       // Make sure the destination is usable.
143
while (!destDir.exists() || !destDir.isDirectory() || !destDir.canWrite()) {
144         if (!destDir.getPath().equals("") && !destDir.exists()) {
145           // If the choice doesn't exist, ask to create it.
146
boolean create = select.askUser
147             ("The directory you chose does not exist:\n'" + destDir + "'\nWould you like to create it?",
148              "Create Directory?");
149           if (create) {
150             boolean dirMade = destDir.mkdirs();
151             if (! dirMade) throw new IOException JavaDoc("Could not create directory: " + destDir);
152           }
153           else return;
154         }
155         else if (!destDir.isDirectory() || destDir.getPath().equals("")) {
156           // We can't use it if it isn't a directory
157
select.warnUser("The file you chose is not a directory:\n" +
158                           "'" + destDir + "'\n" +
159                           "Please choose another.",
160                           "Not a Directory!");
161           destDir = select.getDirectory(null);
162         }
163         else {
164           //If the directory isn't writable, tell the user and ask again.
165
select.warnUser("The directory you chose is not writable:\n" +
166                           "'" + destDir + "'\n" +
167                           "Please choose another directory.",
168                           "Cannot Write to Destination!");
169           destDir = select.getDirectory(null);
170         }
171       }
172     }
173     catch (OperationCanceledException oce) { return; } // If the user cancels anywhere, silently return.
174

175     _notifier.javadocStarted(); // fire first so _javadocAllWorker can fire javadocEnded
176
// Start a new thread to do the work.
177
final File JavaDoc destDirF = destDir;
178     new Thread JavaDoc("DrJava Javadoc Thread") {
179       public void run() { _javadocAllWorker(destDirF, saver, classPath); }
180     }.start();
181   }
182
183   /** This method handles most of the logic of performing a Javadoc operation, once we know that it won't be canceled.
184     * @param destDirFile the destination directory for the doc files
185     * @param saver a command object for saving a document (if it moved/changed)
186     * @param classpath an array of classpath elements to be used by Javadoc
187     */

188   private void _javadocAllWorker(File JavaDoc destDirFile, FileSaveSelector saver, String JavaDoc classPath) {
189     
190 // if (!_ensureValidToolsJar()) return; // addresses on 1.3/1.4 incompatiblies; no longer relevant
191

192     String JavaDoc destDir = destDirFile.getAbsolutePath();
193
194     // Accumulate a set of arguments to JavaDoc - package or file names.
195
HashSet JavaDoc<String JavaDoc> docUnits = new HashSet JavaDoc<String JavaDoc>(); // units to send to Javadoc (packages or files)
196
HashSet JavaDoc<File JavaDoc> sourceRootSet = new HashSet JavaDoc<File JavaDoc>(); // set of unique source roots for open files
197
HashSet JavaDoc<File JavaDoc> defaultRoots = new HashSet JavaDoc<File JavaDoc>(); // source roots for files in default package
198
HashSet JavaDoc<String JavaDoc> topLevelPacks = new HashSet JavaDoc<String JavaDoc>(); // top level package names to include
199

200     // This depends on the current value of the "javadoc.all.packages" option.
201
boolean docAll = DrJava.getConfig().getSetting(OptionConstants.JAVADOC_FROM_ROOTS).booleanValue();
202
203     // Each document has a package hierarchy to traverse.
204
for (OpenDefinitionsDocument doc: _model.getOpenDefinitionsDocuments()) {
205       File JavaDoc file = null;
206
207       try {
208         // This will throw an IllegalStateException if no file can be found
209
file = _getFileFromDocument(doc, saver);
210
211         // File shouldn't be null here, but just in case...
212
if (file == null) throw new IllegalStateException JavaDoc("No file for this document.");
213
214         File JavaDoc sourceRoot = doc.getSourceRoot();
215         String JavaDoc pack = doc.getPackageName();
216
217         if (pack.equals("")) {
218           // No package name for this file
219
if (! defaultRoots.contains(sourceRoot)) {
220             // This file uses the default package.
221
// Include all the other source files at the source root.
222
// But don't do it if we've already done it for this directory.
223
defaultRoots.add(sourceRoot);
224             Iterable JavaDoc<File JavaDoc> javaFiles = IOUtil.attemptListFilesAsIterable(sourceRoot, IOUtil.extensionFileFilter("java"));
225             for (File JavaDoc f: javaFiles) { docUnits.add(f.getAbsolutePath()); }
226           }
227         }
228         else {
229           // There is a package name
230
String JavaDoc topLevelPack;
231           File JavaDoc searchRoot;
232
233           int index = pack.indexOf('.');
234           if (docAll && index != -1) {
235             // We need to doc all packages from the root level down.
236

237             // TODO: write a unit test for a package name w/ no dot!
238
// (This was broken before, but it works now)
239
topLevelPack = pack.substring(0, index);
240             searchRoot = new File JavaDoc(sourceRoot, topLevelPack);
241           }
242           else {
243             // Only look in the current package or deeper
244
topLevelPack = pack;
245             searchRoot = new File JavaDoc(sourceRoot, pack.replace('.', File.separatorChar));
246           }
247
248           // But we don't want to traverse the hierarchy more than once.
249
if (! topLevelPacks.contains(topLevelPack) || ! sourceRootSet.contains(sourceRoot)) {
250             // HashSets don't have duplicates, so it's ok to add both in either case
251
topLevelPacks.add(topLevelPack);
252             sourceRootSet.add(sourceRoot);
253             docUnits.addAll(FileOps.packageExplore(topLevelPack, searchRoot));
254           }
255         }
256       }
257       catch (IllegalStateException JavaDoc ise) {
258         // No file for this document; skip it
259
}
260       catch (IOException JavaDoc ioe) {
261         // There was a problem getting the file for this document.
262
// Kill javadoc and display the exception as an error.
263
// _notifier.javadocStarted(); // fire first so it can fire javadocEnded // already done above
264
_showCompilerError(ioe.getMessage(), file);
265         return;
266       }
267       catch (InvalidPackageException ipe) {
268         // Bad package - kill the javadoc operation and display the exception
269
// as an error.
270
// _notifier.javadocStarted(); // fire first so it can fire javadocEnded // already done above
271
_showCompilerError(ipe.getMessage(), file);
272          return;
273       }
274     }
275
276     // Don't attempt to create Javadoc if no files are open, or if open file is unnamed.
277
if (docUnits.size() == 0) return;
278
279     // Build the source path.
280
final StringBuilder JavaDoc sourcePath = new StringBuilder JavaDoc();
281     final String JavaDoc separator = System.getProperty("path.separator");
282     sourceRootSet.addAll(defaultRoots);
283     final File JavaDoc[] sourceRoots = sourceRootSet.toArray(new File JavaDoc[sourceRootSet.size()]);
284     for (int a = 0 ; a < sourceRoots.length; a++) {
285       if (a != 0) sourcePath.append(separator);
286       sourcePath.append(sourceRoots[a].getAbsolutePath());
287     }
288
289     // Generate all command line arguments
290
ArrayList JavaDoc<String JavaDoc> args = _buildCommandLineArgs(docUnits, destDir, sourcePath.toString(), classPath);
291
292     // Run the actual Javadoc process
293
_runJavadoc(args, classPath, destDirFile, true);
294   }
295
296
297
298   // -------------------- Javadoc Current Document --------------------
299

300   /** Generates Javadoc for the given document only, after ensuring it is saved. Saves the output in a temp directory
301     * which is passed to _javadocDocuemntWorker, which is passed to a subsequent javadocEnded event.
302     * @param doc Document to generate Javadoc for
303     * @param saver a command object for saving the document (if it moved/changed)
304     * @param classPath a collection of classpath elements to be used by Javadoc
305     *
306     * @throws IOException if there is a problem manipulating files
307     */

308   public void javadocDocument(final OpenDefinitionsDocument doc, final FileSaveSelector saver, final String JavaDoc classPath)
309     throws IOException JavaDoc {
310     // Prompt to save if necessary
311
// (TO DO: should only need to save the current document)
312
if (doc.isUntitled() || doc.isModifiedSinceSave()) _notifier.saveBeforeJavadoc();
313
314     // Make sure it is saved
315
if (doc.isUntitled() || doc.isModifiedSinceSave()) return; // The user didn't save, so don't generate Javadoc
316

317     // Try to get the file from the document
318
final File JavaDoc file = _getFileFromDocument(doc, saver);
319
320     // Generate to a temporary directory
321
final File JavaDoc destDir = IOUtil.createAndMarkTempDirectory("DrJava-javadoc", "");
322
323     _notifier.javadocStarted(); // fire first so _javadocDocumntWorker can fire javadocEnded
324
// Start a new thread to do the work.
325
new Thread JavaDoc("DrJava Javadoc Thread") {
326       public void run() { _javadocDocumentWorker(destDir, file, classPath); }
327     }.start();
328   }
329
330   /** Handles most of the logic for generating Javadoc for a single file, once we know that it won't be canceled.
331     * @param destDirFile the destination directory for the doc files
332     * @param docFile the file of the document
333     * @param classpath an array of classpath elements to be used by Javadoc
334     */

335   private void _javadocDocumentWorker(File JavaDoc destDir, File JavaDoc docFile, String JavaDoc classPath) {
336 // if (!_ensureValidToolsJar()) return; // addresses on 1.3/1.4 incompatiblies; no longer relevant
337

338     // Generate all command line arguments
339
String JavaDoc destDirName = destDir.getAbsolutePath();
340     ArrayList JavaDoc<String JavaDoc> args = _buildCommandLineArgs(docFile, destDirName, classPath);
341
342     // Run the actual Javadoc process
343
_runJavadoc(args, classPath, destDir, false);
344   }
345
346
347
348   // -------------------- Helper Methods --------------------
349

350   /** Suggests a default location for generating Javadoc, based on the given document's source root. (Appends
351     * JavadocModel.SUGGESTED_DIR_NAME to the sourceroot.) Ensures that the document is saved first, or else no
352     * reasonable suggestion will be found.
353     * @param doc Document with the source root to use as the default.
354     * @return Suggested destination directory, or null if none could be determined.
355     */

356   public File JavaDoc suggestJavadocDestination(OpenDefinitionsDocument doc) {
357     _attemptSaveAllDocuments();
358
359     try {
360       File JavaDoc sourceRoot = doc.getSourceRoot();
361       return new File JavaDoc(sourceRoot, SUGGESTED_DIR_NAME);
362     }
363     catch (InvalidPackageException ipe) { return null; }
364   }
365
366   /**
367    * If any documents are modified, this gives the user a chance
368    * to save them before proceeding.
369    *
370    * Callers can check _getter.hasModifiedDocuments() after calling
371    * this method to determine if the user cancelled the save process.
372    */

373   private void _attemptSaveAllDocuments() {
374     // Only javadoc if all are saved.
375
if (_model.hasModifiedDocuments() || _model.hasUntitledDocuments()) _notifier.saveBeforeJavadoc();
376   }
377
378 // /** Ensures that a valid version of tools.jar is being used for our classpath.
379
// * Ends the process with an error and returns false if not.
380
// * Using JDK 1.4 with a 1.3 tools.jar is invalid, but using JDK 1.3 with
381
// * a 1.4 tools.jar is ok.
382
// */
383
// private boolean _ensureValidToolsJar() {
384
// PlatformSupport platform = PlatformFactory.ONLY;
385
// String version = platform.getJavaSpecVersion();
386
// if (!"1.3".equals(version) && platform.has13ToolsJar()) {
387
// String msg =
388
// "There is an incompatible version of tools.jar on your\n" +
389
// "classpath, so Javadoc cannot run.\n" +
390
// "(tools.jar is version 1.3, JDK is version " + version + ")";
391
// _notifier.javadocStarted(); // fire first so it can fire javadocEnded
392
// _showCompilerError(msg, null);
393
// return false;
394
// }
395
// return true;
396
// }
397

398   /** Treats the given message as a Javadoc error, firing the end event necessary to show the error. The
399     * javadocStarted() event <i>must</i> have already been fired, and Javadoc generation must halt after calling this
400     * method.
401     * @param msg Message to display as an error
402     * @param f File that caused the error
403     */

404   private void _showCompilerError(String JavaDoc msg, File JavaDoc f) {
405     CompilerError[] errors = new CompilerError[1];
406     errors[0] = new CompilerError(f, -1, -1, msg, false);
407     _javadocErrorModel = new CompilerErrorModel(errors, _model);
408     _notifier.javadocEnded(false, null, false);
409   }
410
411   /**
412    * Tell the listeners that we're starting to generate Javadoc,
413    * start a new process to actually generate it, and then tell
414    * the listeners when we're done.
415    *
416    * @param args Command line arguments to pass to Javadoc
417    * @param classpath Classpath to pass to Javadoc
418    * @param destDirFile Directory where the results are being saved
419    * @param allDocs Whether we are running over all open documents
420    */

421   private void _runJavadoc(ArrayList JavaDoc<String JavaDoc> args, String JavaDoc classPath, File JavaDoc destDirFile, boolean allDocs) {
422     // Start a new process to execute Javadoc and tell listeners it has started
423
// And finally, when we're done notify the listeners with a success flag
424
boolean result;
425     try {
426       // Notify all listeners that Javadoc is starting.
427
// _notifier.javadocStarted(); // already done in worker methods
428

429       result = _javadoc(args.toArray(new String JavaDoc[args.size()]), classPath);
430
431       // If success and we're generating current, make sure the temp
432
// directory gets deleted on exit.
433
if (result && !allDocs) IOUtil.deleteOnExitRecursively(destDirFile);
434
435       // Notify all listeners that we're done.
436
_notifier.javadocEnded(result, destDirFile, allDocs);
437     }
438     catch (Throwable JavaDoc e) {
439       // This fires javadocEnded, showing the error
440
_showCompilerError(e.getMessage(), null);
441     }
442   }
443
444   /** This function invokes javadoc. It should work for all versions of Java from 1.3 on, assuming
445    * com.sun.tools.javadoc is in the classpath (located in the same tools.jar archive as the compiler
446    * and debugging framework
447    *
448    * @param args the command-line arguments for Javadoc
449    * @param classpath an array of classpath elements to use in the Javadoc JVM
450    * @return true if Javadoc succeeded in building the HTML, otherwise false
451    */

452   private boolean _javadoc(String JavaDoc[] args, String JavaDoc classPath) throws IOException JavaDoc {
453     final String JavaDoc JAVADOC_CLASS = "com.sun.tools.javadoc.Main";
454     Process JavaDoc javadocProcess;
455     
456     // TODO: clean up this code, particularly the busy-wait
457

458     double version = Double.valueOf(System.getProperty("java.specification.version"));
459     String JavaDoc[] jvmArgs = new String JavaDoc[0];
460     
461     // We must set the classpath so our new Javadoc JVM can see everything the interactions pane can see.
462
javadocProcess = ExecJVM.runJVM(JAVADOC_CLASS, args, new String JavaDoc[]{classPath}, jvmArgs, FileOption.NULL_FILE);
463
464     //System.err.println("javadoc started with args:\n" + Arrays.asList(args));
465

466     /* waitFor() call appears to block indefinitely in 1.4.1, because the process will block if output buffers get full.
467      * Yes, this is extremely retarded.
468      */

469 // value = javadocProcess.waitFor();
470

471     // We have to use a busy-wait and vent output buffers.
472
LinkedList JavaDoc<String JavaDoc> outLines = new LinkedList JavaDoc<String JavaDoc>();
473     LinkedList JavaDoc<String JavaDoc> errLines = new LinkedList JavaDoc<String JavaDoc>();
474     boolean done = false;
475     while (!done) {
476       try {
477         Thread.sleep(500);
478         javadocProcess.exitValue();
479         done = true;
480       }
481       catch (InterruptedException JavaDoc e) {
482         // try again
483
}
484       catch (IllegalThreadStateException JavaDoc e) {
485         ExecJVM.ventBuffers(javadocProcess, outLines, errLines);
486       }
487     }
488     ExecJVM.ventBuffers(javadocProcess, outLines, errLines);
489 // System.err.println("Javadoc process completed.");
490

491     // Unfortunately, javadoc returns 1 for normal errors and for exceptions.
492
// We cannot tell them apart without parsing.
493

494     ArrayList JavaDoc<CompilerError> errors = _extractErrors(outLines);
495     errors.addAll(_extractErrors(errLines));
496
497     _javadocErrorModel = new CompilerErrorModel
498       (errors.toArray(new CompilerError[errors.size()]), _model);
499 // System.out.println("built Javadoc error model");
500

501     // Returns true if no "real" errors have occurred.
502
return _javadocErrorModel.hasOnlyWarnings();
503   }
504
505   /**
506    * Reads through a LinkedList of text lines, looking for Javadoc errors.
507    * This code will detect Exceptions and Errors thrown during generation of
508    * the output, as well as errors and warnings generated by Javadoc.
509    * This code works for both JDK 1.3 and 1.4, assuming you pass in data
510    * from the correct stream. (Be safe and check both.)
511    * @param lines a LinkedList of Strings representing lines of text
512    * @return an ArrayList of CompilerErrors corresponding to the text
513    */

514   private ArrayList JavaDoc<CompilerError> _extractErrors(LinkedList JavaDoc lines) {
515     // Javadoc never produces more than 100 errors, so this will never auto-expand.
516
ArrayList JavaDoc<CompilerError> errors = new ArrayList JavaDoc<CompilerError>(100);
517
518     final String JavaDoc ERROR_INDICATOR = "Error: ";
519     final String JavaDoc EXCEPTION_INDICATOR = "Exception: ";
520     final String JavaDoc BAD_FLAG_INDICATOR = "invalid flag:";
521     while (lines.size() > 0) {
522 // System.out.println("[javadoc raw error] " + output);
523

524       String JavaDoc output = (String JavaDoc) lines.removeFirst();
525
526       // Check for the telltale signs of a thrown exception or error.
527
int errStart;
528       errStart = output.indexOf(ERROR_INDICATOR);
529
530       // If we haven't found an error, look for an exception.
531
if (errStart == -1) {
532         errStart = output.indexOf(EXCEPTION_INDICATOR);
533       }
534
535       // If we haven't found either, look for a bad flag report.
536
if (errStart == -1) {
537         errStart = output.indexOf(BAD_FLAG_INDICATOR);
538       }
539
540       if (errStart != -1) {
541         // If we found one, put the entirety of stderr in one CompilerError.
542
final StringBuilder JavaDoc buf = new StringBuilder JavaDoc(60 * lines.size());
543         buf.append(output);
544         while (lines.size() > 0) {
545           output = (String JavaDoc) lines.removeFirst();
546           buf.append('\n');
547           buf.append(output);
548         }
549         errors.add(new CompilerError(buf.toString(), false));
550       }
551       else {
552         // Otherwise, parser for a normal error message.
553
CompilerError error = _parseJavadocErrorLine(output);
554         if (error != null) {
555           errors.add(error);
556 // System.err.println("[javadoc err]" + error);
557
}
558       }
559     }
560
561     return errors;
562   }
563
564   /**
565    * Parse a line of text written by Javadoc to stderr in order to see if it
566    * lists a specific file (and optionally, a line number) and error message.
567    * If so, create a corresponding CompilerError. If an exception stack trace
568    * is encountered, all following text is copied into a new CompilerError.
569    *
570    * @param line the line of JavaDoc error output to parse - possibly null
571    * @return if the error output contains the text ".java:", a CompilerError with the file,
572    * message, and line number (if present) where the error occurred. Otherwise, returns null.
573    */

574   private CompilerError _parseJavadocErrorLine(String JavaDoc line) {
575     // First things first: check input.
576
if (line == null) {
577       return null;
578     }
579
580     final String JavaDoc JAVA_INDICATOR = ".java:";
581     final String JavaDoc GJ_INDICATOR = ".gj:";
582
583     CompilerError error = null;
584
585     // if the line doesn't have a file and a line number, it is context printed out for a previous error.
586
// We can ignore it, becuase the user gets this when they click the error message in our GUI.
587
int errStart = line.indexOf(JAVA_INDICATOR);
588
589     // Also look for a GJ file extension.
590
if (errStart == -1) {
591       errStart = line.indexOf(GJ_INDICATOR);
592     }
593
594     if (errStart != -1) {
595       // filename is everything up to and including the '.java'
596
String JavaDoc fileName = line.substring(0, errStart+5);
597
598       // line number is all contiguous number characters after the colon
599
int lineno = -1;
600       final StringBuilder JavaDoc linenoString = new StringBuilder JavaDoc();
601       int pos = errStart+6;
602       while ((line.charAt(pos) >= '0') && (line.charAt(pos) <= '9')) {
603         linenoString.append(line.charAt(pos));
604         pos++;
605       }
606       // Hopefully, there is a colon after the line number but before the error message.
607
// If so, record the line number.
608
// Otherwise, try to recover by just using everything after ERR_INDICATOR as the error message
609
if (line.charAt(pos) == ':') {
610         try {
611           // Adjust Javadoc's one-based line numbers to our zero-based indeces.
612
lineno = Integer.valueOf(linenoString.toString()).intValue() -1;
613         } catch (NumberFormatException JavaDoc e) {
614         }
615       } else {
616         pos = errStart;
617       }
618
619       // error message is everything after the colon and space that are after the line number
620
String JavaDoc errMessage = line.substring(pos+2);
621
622       // check to see if the first word in the error message is "warning"
623
boolean isWarning = false;
624       if (errMessage.substring(0, 7).equalsIgnoreCase("warning")) {
625         isWarning = true;
626       }
627
628       if (lineno >= 0) {
629         error = new CompilerError(new File JavaDoc(fileName), lineno, 0, errMessage, false);
630           
631       } else {
632         error = new CompilerError(new File JavaDoc(fileName), errMessage, false);
633       }
634     }
635     return error;
636   }
637
638
639
640   /**
641    * Attempts to get the file from the given document.
642    * If the file has moved, we use the given FileSaveSelector to let the user save it
643    * in a new location.
644    *
645    * @param doc OpenDefinitionsDocument from which to get the file
646    * @param saver FileSaveSelector to allow the user to save the file if it has moved.
647    *
648    * @throws IllegalStateException if the doc has no file (hasn't been saved)
649    * @throws IOException if the file can't be saved after it was moved
650    */

651   private File JavaDoc _getFileFromDocument(OpenDefinitionsDocument doc, FileSaveSelector saver) throws IOException JavaDoc {
652     try {
653       // This call will abort the iteration if there is no file, unless we can recover (like for a FileMovedException).
654
return doc.getFile();
655     }
656     catch (FileMovedException fme) {
657       // The file has moved - prompt the user to recover.
658
// XXX: This is probably not thread safe!
659
if (saver.shouldSaveAfterFileMoved(doc, fme.getFile())) {
660         try {
661           doc.saveFileAs(saver);
662           return doc.getFile();
663         }
664         catch (FileMovedException fme2) {
665           // If the user is this intent on shooting themselves in the foot,
666
// get out of the way.
667
fme2.printStackTrace();
668           throw new IOException JavaDoc("Could not find file: " + fme2);
669         }
670       }
671       else {
672         throw new IllegalStateException JavaDoc("No file exists for this document.");
673       }
674     }
675   }
676
677   /**
678    * Builds a list of command line arguments to pass to the new process
679    * when generating Javadoc for a collection of files or packages.
680    *
681    * The list includes arguments to set the sourcepath and to
682    * link against online library documentation.
683    *
684    * @param docUnits All files or packages to include in the Javadoc
685    * @param destDir Destination directory to pass
686    * @param sourcePath Full sourcepath to pass
687    * @param classPath All classpath entries to pass
688    */

689   protected ArrayList JavaDoc<String JavaDoc> _buildCommandLineArgs(Collection JavaDoc<String JavaDoc> docUnits,
690                                                     String JavaDoc destDir,
691                                                     String JavaDoc sourcePath,
692                                                     String JavaDoc classPath)
693   {
694     ArrayList JavaDoc<String JavaDoc> args = new ArrayList JavaDoc<String JavaDoc>();
695     _addBasicArguments(args, destDir, sourcePath, classPath);
696     _addOnlineLinkArguments(args);
697     args.addAll(docUnits);
698     return args;
699   }
700
701   /**
702    * Builds a list of command line arguments to pass to the new process
703    * when generating Javadoc for a single file.
704    *
705    * The list does not include arguments for source path or
706    * online links to documentation.
707    *
708    * @param file the file
709    * @param destDir Destination directory to pass
710    * @param classPath All classpath entries to pass
711    */

712   protected ArrayList JavaDoc<String JavaDoc> _buildCommandLineArgs(File JavaDoc file, String JavaDoc destDir,
713                                                     String JavaDoc classPath)
714   {
715     ArrayList JavaDoc<String JavaDoc> args = new ArrayList JavaDoc<String JavaDoc>();
716     _addBasicArguments(args, destDir, "", classPath);
717     _addSingleDocArguments(args);
718     args.add(file.getAbsolutePath());
719     return args;
720   }
721
722   /**
723    * Adds all the basic command line arguments to the args list, for
724    * generating Javadoc for either a single or collection of files.
725    *
726    * @param args List of arguments
727    * @param destDir Destination directory to pass
728    * @param sourcePath Full sourcepath to pass, or the empty string (NOT NULL).
729    * @param classpath All classpath entries to pass
730    */

731   private void _addBasicArguments(ArrayList JavaDoc<String JavaDoc> args,
732                                   String JavaDoc destDir,
733                                   String JavaDoc sourcePath,
734                                   String JavaDoc classPath)
735   {
736     // Determine the access level
737
Configuration config = DrJava.getConfig();
738     final String JavaDoc accLevel = config.getSetting(OptionConstants.JAVADOC_ACCESS_LEVEL);
739     final StringBuilder JavaDoc accArg = new StringBuilder JavaDoc(10);
740     accArg.append('-');
741     accArg.append(accLevel);
742
743     // Add access level, source path, and dest dir
744
args.add(accArg.toString());
745     if (!sourcePath.equals("")) {
746       args.add("-sourcepath");
747       args.add(sourcePath);
748     }
749     args.add("-d");
750     args.add(destDir);
751     
752     // Add classpath
753
args.add("-classpath");
754     args.add(classPath);
755
756     // Add custom args specified by the user
757
String JavaDoc custom = config.getSetting(OptionConstants.JAVADOC_CUSTOM_PARAMS);
758     args.addAll(ArgumentTokenizer.tokenize(custom));
759   }
760
761   /**
762    * Adds command line arguments for links to online library documentation
763    * to the given list of command line arguments.
764    * @param args List of arguments to modify
765    */

766   private void _addOnlineLinkArguments(ArrayList JavaDoc<String JavaDoc> args) {
767     Configuration config = DrJava.getConfig();
768     String JavaDoc linkVersion = config.getSetting(OptionConstants.JAVADOC_LINK_VERSION);
769     if (linkVersion.equals(OptionConstants.JAVADOC_1_3_TEXT)) {
770       args.add("-link");
771       args.add(config.getSetting(OptionConstants.JAVADOC_1_3_LINK));
772     }
773     else if (linkVersion.equals(OptionConstants.JAVADOC_1_4_TEXT)) {
774       args.add("-link");
775       args.add(config.getSetting(OptionConstants.JAVADOC_1_4_LINK));
776     }
777     else if (linkVersion.equals(OptionConstants.JAVADOC_1_5_TEXT)) {
778       args.add("-link");
779       args.add(config.getSetting(OptionConstants.JAVADOC_1_5_LINK));
780     }
781   }
782
783   /**
784    * Adds command line arguments for generating a single Javadoc file,
785    * suppressing most of the navigation on the page.
786    * @param args List of arguments to modify.
787    */

788   private void _addSingleDocArguments(ArrayList JavaDoc<String JavaDoc> args) {
789     args.add("-noindex");
790     args.add("-notree");
791     args.add("-nohelp");
792     args.add("-nonavbar");
793   }
794 }
795
Popular Tags