KickJava   Java API By Example, From Geeks To Geeks.

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


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
37 import java.awt.EventQueue JavaDoc;
38
39 import java.io.File JavaDoc;
40 import java.io.FileFilter JavaDoc;
41 import java.io.IOException JavaDoc;
42 import java.io.OutputStream JavaDoc;
43
44 import java.net.MalformedURLException JavaDoc;
45 import java.net.URL JavaDoc;
46
47 import java.rmi.RemoteException JavaDoc;
48
49 import java.util.ArrayList JavaDoc;
50 import java.util.LinkedList JavaDoc;
51 import java.util.List JavaDoc;
52 import java.util.Vector JavaDoc;
53 import java.util.StringTokenizer JavaDoc;
54
55 import javax.swing.text.BadLocationException JavaDoc;
56 import javax.swing.SwingUtilities JavaDoc;
57
58 import edu.rice.cs.util.ClassPathVector;
59 import edu.rice.cs.util.FileOpenSelector;
60 import edu.rice.cs.drjava.model.FileSaveSelector;
61 import edu.rice.cs.util.FileOps;
62 import edu.rice.cs.util.OperationCanceledException;
63 import edu.rice.cs.util.UnexpectedException;
64 import edu.rice.cs.util.newjvm.AbstractMasterJVM;
65 import edu.rice.cs.util.text.EditDocumentException;
66 import edu.rice.cs.util.swing.Utilities;
67
68 import edu.rice.cs.drjava.DrJava;
69 import edu.rice.cs.drjava.config.OptionConstants;
70 import edu.rice.cs.drjava.config.OptionEvent;
71 import edu.rice.cs.drjava.config.OptionListener;
72
73 import edu.rice.cs.drjava.model.definitions.ClassNameNotFoundException;
74 import edu.rice.cs.drjava.model.definitions.DefinitionsDocument;
75 import edu.rice.cs.drjava.model.definitions.InvalidPackageException;
76 import edu.rice.cs.drjava.model.debug.Breakpoint;
77 import edu.rice.cs.drjava.model.debug.Debugger;
78 import edu.rice.cs.drjava.model.debug.DebugException;
79 import edu.rice.cs.drjava.model.debug.JPDADebugger;
80 import edu.rice.cs.drjava.model.debug.NoDebuggerAvailable;
81 import edu.rice.cs.drjava.model.debug.DebugListener;
82 import edu.rice.cs.drjava.model.debug.DebugWatchData;
83 import edu.rice.cs.drjava.model.debug.DebugThreadData;
84 import edu.rice.cs.drjava.model.repl.DefaultInteractionsModel;
85 import edu.rice.cs.drjava.model.repl.DummyInteractionsListener;
86 import edu.rice.cs.drjava.model.repl.InteractionsDocument;
87 import edu.rice.cs.drjava.model.repl.InteractionsDJDocument;
88 import edu.rice.cs.drjava.model.repl.InteractionsListener;
89 import edu.rice.cs.drjava.model.repl.InteractionsScriptModel;
90 import edu.rice.cs.drjava.model.repl.newjvm.MainJVM;
91 import edu.rice.cs.drjava.model.compiler.CompilerListener;
92 import edu.rice.cs.drjava.model.compiler.CompilerModel;
93 import edu.rice.cs.drjava.model.compiler.DefaultCompilerModel;
94 import edu.rice.cs.drjava.model.junit.DefaultJUnitModel;
95 import edu.rice.cs.drjava.model.junit.JUnitModel;
96 import edu.rice.cs.drjava.ui.MainFrame;
97
98 import java.io.*;
99
100 /** Handles the bulk of DrJava's program logic. The UI components interface with the GlobalModel through its public
101  * methods, and the GlobalModel responds via the GlobalModelListener interface. This removes the dependency on the
102  * UI for the logical flow of the program's features. With the current implementation, we can finally test the compile
103  * functionality of DrJava, along with many other things. <p>
104  * @version $Id: DefaultGlobalModel.java 4099 2007-01-30 22:37:16Z dlsmith $
105  */

106 public class DefaultGlobalModel extends AbstractGlobalModel {
107   
108   /* FIELDS */
109   
110   /* static Log _log inherited from AbstractGlobalModel */
111   
112   /* Interpreter fields */
113   
114   /** The document used in the Interactions model. */
115   protected final InteractionsDJDocument _interactionsDocument;
116   
117   /** RMI interface to the Interactions JVM. */
118   final MainJVM _jvm;
119   
120   /** Interface between the InteractionsDocument and the JavaInterpreter, which runs in a separate JVM. */
121   protected final DefaultInteractionsModel _interactionsModel;
122   
123   /** Core listener attached to interactions model */
124   protected InteractionsListener _interactionsListener = new InteractionsListener() {
125     public void interactionStarted() { }
126     
127     public void interactionEnded() { }
128     
129     public void interactionErrorOccurred(int offset, int length) { }
130     
131     public void interpreterResetting() { }
132     
133     public void interpreterReady(File JavaDoc wd) {
134       File JavaDoc buildDir = _state.getBuildDirectory();
135       if (buildDir != null) {
136         // System.out.println("adding for reset: " + _state.getBuildDirectory().getAbsolutePath());
137
try {
138           _jvm.addBuildDirectoryClassPath(FileOps.toURL(new File JavaDoc(buildDir.getAbsolutePath())));
139         } catch(MalformedURLException JavaDoc murle) {
140           // edit this later! this is bad! we should handle this exception better!
141
throw new RuntimeException JavaDoc(murle);
142         }
143       }
144     }
145     
146     public void interpreterResetFailed(Throwable JavaDoc t) { }
147     
148     public void interpreterExited(int status) { }
149     
150     public void interpreterChanged(boolean inProgress) { }
151     
152     public void interactionIncomplete() { }
153     
154     public void slaveJVMUsed() { }
155   };
156   
157   private CompilerListener _clearInteractionsListener =
158     new CompilerListener() {
159     public void compileStarted() { }
160     
161     public void compileEnded(File JavaDoc workDir, List JavaDoc<? extends File JavaDoc> excludedFiles) {
162       // Only clear interactions if there were no errors and unit testing is not in progress
163
if ( ((_compilerModel.getNumErrors() == 0) || (_compilerModel.getCompilerErrorModel().hasOnlyWarnings()))
164             && ! _junitModel.isTestInProgress() && _resetAfterCompile) {
165         resetInteractions(workDir); // use same working directory as current interpreter
166
}
167     }
168     public void saveBeforeCompile() { }
169     public void saveUntitled() { }
170   };
171     
172   // ---- Compiler Fields ----
173

174   /** CompilerModel manages all compiler functionality. */
175   private final CompilerModel _compilerModel;
176   
177   /** Whether or not to reset the interactions JVM after compiling. Should only be false in test cases. */
178   private volatile boolean _resetAfterCompile = true;
179   
180   /** Number of errors in last compilation. compilerModel._numErrors is trashed when the compile model is reset. */
181   private volatile int _numCompErrors = 0;
182   
183   /* JUnit Fields */
184   
185   /** JUnitModel manages all JUnit functionality. */
186   private final DefaultJUnitModel _junitModel;
187   
188   /* Javadoc Fields */
189   
190   /** Manages all Javadoc functionality. */
191   protected final JavadocModel _javadocModel;
192   
193   /* Debugger Fields */
194   
195   /** Interface to the integrated debugger. If unavailable, set NoDebuggerAvailable.ONLY. */
196   private volatile Debugger _debugger = NoDebuggerAvailable.ONLY;
197   
198   /* CONSTRUCTORS */
199   
200   /** Constructs a new GlobalModel. Creates a new MainJVM and starts its Interpreter JVM. */
201   public DefaultGlobalModel() {
202 // AbstractMasterJVM._log.log(this + " has called contstructor for DefaultGlobal Model");
203
File JavaDoc workDir = Utilities.TEST_MODE ? new File JavaDoc(System.getProperty("user.home")) : getWorkingDirectory();
204     _jvm = new MainJVM(workDir);
205 // AbstractMasterJVM._log.log(this + " has created a new MainJVM");
206
_compilerModel = new DefaultCompilerModel(this);
207     _junitModel = new DefaultJUnitModel(_jvm, _compilerModel, this);
208     _javadocModel = new DefaultJavadocModel(this);
209     _interactionsDocument = new InteractionsDJDocument();
210
211     _interactionsModel = new DefaultInteractionsModel(this, _jvm, _interactionsDocument, workDir);
212     _interactionsModel.addListener(_interactionsListener);
213     _jvm.setInteractionsModel(_interactionsModel);
214     _jvm.setJUnitModel(_junitModel);
215     
216     _jvm.setOptionArgs(DrJava.getConfig().getSetting(SLAVE_JVM_ARGS));
217     
218     DrJava.getConfig().addOptionListener(SLAVE_JVM_ARGS, new OptionListener<String JavaDoc>() {
219       public void optionChanged(OptionEvent<String JavaDoc> oe) { _jvm.setOptionArgs(oe.value); }
220     });
221     
222     _createDebugger();
223         
224     // Chain notifiers so that all events also go to GlobalModelListeners.
225
_interactionsModel.addListener(_notifier);
226     _compilerModel.addListener(_notifier);
227     _junitModel.addListener(_notifier);
228     _javadocModel.addListener(_notifier);
229         
230     // Listen to compiler to clear interactions appropriately.
231
// XXX: The tests need this to be registered after _notifier, sadly.
232
// This is obnoxiously order-dependent, but it works for now.
233
_compilerModel.addListener(_clearInteractionsListener);
234     
235     // Note: starting the JVM in another thread does not appear to improve performance
236
// AbstractMasterJVM._log.log("Starting the interpreter in " + this);
237
_jvm.startInterpreterJVM();
238     
239 // Any lightweight parsing has been disabled until we have something that is beneficial and works better in the background.
240
// _parsingControl = new DefaultLightWeightParsingControl(this);
241
}
242   
243
244 // public void compileAll() throws IOException{
245
//// ScrollableDialog sd = new ScrollableDialog(null, "DefaultGlobalModel.compileAll() called", "", "");
246
//// sd.show();
247
// _state.compileAll();
248
// }
249

250
251 // public void junitAll() { _state.junitAll(); }
252

253   /** Sets the build directory for a project. */
254   public void setBuildDirectory(File JavaDoc f) {
255     _state.setBuildDirectory(f);
256     if (f != null) {
257       // System.out.println("adding: " + f.getAbsolutePath());
258
try {
259         _jvm.addBuildDirectoryClassPath(FileOps.toURL(new File JavaDoc(f.getAbsolutePath())));
260       }
261       catch(MalformedURLException JavaDoc murle) {
262         // TODO! change this! we should handle this exception better!
263
// show a popup like "invalide build directory" or something
264
throw new RuntimeException JavaDoc(murle);
265       }
266     }
267     
268     _notifier.projectBuildDirChanged();
269     setProjectChanged(true);
270     setClassPathChanged(true);
271   }
272  
273   // ----- METHODS -----
274

275   /** @return the interactions model. */
276   public DefaultInteractionsModel getInteractionsModel() { return _interactionsModel; }
277   
278   /** @return InteractionsDJDocument in use by the InteractionsDocument. */
279   public InteractionsDJDocument getSwingInteractionsDocument() { return _interactionsDocument; }
280   
281   public InteractionsDocument getInteractionsDocument() { return _interactionsModel.getDocument(); }
282   
283   /** Gets the CompilerModel, which provides all methods relating to compilers. */
284   public CompilerModel getCompilerModel() { return _compilerModel; }
285   
286   /** Gets the JUnitModel, which provides all methods relating to JUnit testing. */
287   public JUnitModel getJUnitModel() { return _junitModel; }
288   
289   /** Gets the JavadocModel, which provides all methods relating to Javadoc. */
290   public JavadocModel getJavadocModel() { return _javadocModel; }
291   
292   public int getNumCompErrors() { return _numCompErrors; }
293   public void setNumCompErrors(int num) { _numCompErrors = num; }
294   
295   /** Prepares this model to be thrown away. Never called in practice outside of quit(), except in tests. */
296   public void dispose() {
297     // Kill the interpreter
298
_jvm.killInterpreter(null);
299     // Commented out because it invokes UnicastRemoteObject.unexport
300
// try { _jvm.dispose(); }
301
// catch(RemoteException e) { /* ignore */ }
302
_notifier.removeAllListeners(); // removes the global model listeners!
303
}
304
305   /** Disposes of external resources. Kills the slave JVM. */
306   public void disposeExternalResources() {
307     // Kill the interpreter
308
_jvm.killInterpreter(null);
309   }
310   
311   public void resetInteractions(File JavaDoc wd) { resetInteractions(wd, false); }
312  
313   /** Clears and resets the slave JVM with working directory wd. Also clears the console if the option is
314    * indicated (on by default). The reset operation is suppressed if the existing slave JVM has not been
315    * used, {@code wd} matches its working directory, and forceReset is false. {@code wd} may be {@code null}
316    * if a valid directory cannot be determined. In that case, the former working directory is used.
317    */

318   public void resetInteractions(File JavaDoc wd, boolean forceReset) {
319 // _log.log("DefaultGlobalModel.resetInteractions called");
320
File JavaDoc workDir = _interactionsModel.getWorkingDirectory();
321     if (wd == null) { wd = workDir; }
322 // _log.log("New working directory = " + wd +"; current working directory = " + workDir + ";");
323

324     if (! forceReset && ! _jvm.slaveJVMUsed() && ! isClassPathChanged() && wd.equals(workDir)) {
325     // Eliminate resetting interpreter (slaveJVM) since it has already been reset appropriately.
326
// _log.log("Suppressing resetting of interactions pane");
327
_interactionsModel._notifyInterpreterReady(wd);
328       return;
329     }
330 // _log.log("Resetting interactions with working directory = " + wd);
331
if (DrJava.getConfig().getSetting(STICKY_INTERACTIONS_DIRECTORY)) {
332       // update the setting
333
DrJava.getConfig().setSetting(LAST_INTERACTIONS_DIRECTORY, wd);
334     }
335     _interactionsModel.resetInterpreter(wd);
336   }
337
338   /** Interprets the current given text at the prompt in the interactions pane. */
339   public void interpretCurrentInteraction() { _interactionsModel.interpretCurrentInteraction(); }
340
341   /** Interprets file selected in the FileOpenSelector. Assumes strings have no trailing whitespace. Interpretation is
342    * aborted after the first error.
343    */

344   public void loadHistory(FileOpenSelector selector) throws IOException JavaDoc { _interactionsModel.loadHistory(selector); }
345
346   /** Loads the history/histories from the given selector. */
347   public InteractionsScriptModel loadHistoryAsScript(FileOpenSelector selector)
348     throws IOException JavaDoc, OperationCanceledException {
349     return _interactionsModel.loadHistoryAsScript(selector);
350   }
351
352   /** Clears the interactions history */
353   public void clearHistory() { _interactionsModel.getDocument().clearHistory(); }
354
355   /** Saves the unedited version of the current history to a file
356    * @param selector File to save to
357    */

358   public void saveHistory(FileSaveSelector selector) throws IOException JavaDoc {
359     _interactionsModel.getDocument().saveHistory(selector);
360   }
361
362   /** Saves the edited version of the current history to a file
363    * @param selector File to save to
364    * @param editedVersion Edited verison of the history which will be saved to file instead of the lines saved in
365    * the history. The saved file will still include any tags needed to recognize it as a history file.
366    */

367   public void saveHistory(FileSaveSelector selector, String JavaDoc editedVersion) throws IOException JavaDoc {
368     _interactionsModel.getDocument().saveHistory(selector, editedVersion);
369   }
370
371   /** Returns the entire history as a String with semicolons as needed. */
372   public String JavaDoc getHistoryAsStringWithSemicolons() {
373     return _interactionsModel.getDocument().getHistoryAsStringWithSemicolons();
374   }
375
376   /** Returns the entire history as a String. */
377   public String JavaDoc getHistoryAsString() {
378     return _interactionsModel.getDocument().getHistoryAsString();
379   }
380
381   /** Called when the debugger wants to print a message. Inserts a newline. */
382   public void printDebugMessage(String JavaDoc s) {
383     _interactionsModel.getDocument().
384       insertBeforeLastPrompt(s + "\n", InteractionsDocument.DEBUGGER_STYLE);
385   }
386
387   /** Blocks until the interpreter has registered. */
388   public void waitForInterpreter() { _jvm.ensureInterpreterConnected(); }
389
390
391   /** Returns the current classpath in use by the Interpreter JVM. */
392   public ClassPathVector getInteractionsClassPath() { return _jvm.getClassPath(); }
393   
394   /** Sets whether or not the Interactions JVM will be reset after a compilation succeeds. This should ONLY be used
395    * in tests! This method is not supported by AbstractGlobalModel.
396    * @param shouldReset Whether to reset after compiling
397    */

398   void setResetAfterCompile(boolean shouldReset) { _resetAfterCompile = shouldReset; }
399
400   /** Gets the Debugger used by DrJava. */
401   public Debugger getDebugger() { return _debugger; }
402
403   /** Returns an available port number to use for debugging the interactions JVM.
404    * @throws IOException if unable to get a valid port number.
405    */

406   public int getDebugPort() throws IOException JavaDoc { return _interactionsModel.getDebugPort(); }
407
408   // ---------- ConcreteOpenDefDoc inner class ----------
409

410   /** Inner class to handle operations on each of the open DefinitionsDocuments by the GlobalModel. <br><br>
411     * This was at one time called the <code>DefinitionsDocumentHandler</code>
412     * but was renamed (2004-Jun-8) to be more descriptive/intuitive.
413     */

414   class ConcreteOpenDefDoc extends AbstractGlobalModel.ConcreteOpenDefDoc {
415     /** Standard constructor for a document read from a file. Initializes this ODD's DD.
416       * @param f file describing DefinitionsDocument to manage
417       */

418     ConcreteOpenDefDoc(File JavaDoc f) { super(f); }
419     
420     /* Standard constructor for a new document (no associated file) */
421     ConcreteOpenDefDoc() { super(); }
422     
423     /** Starting compiling this document. Used only for unit testing */
424     public void startCompile() throws IOException JavaDoc { _compilerModel.compile(ConcreteOpenDefDoc.this); }
425     
426     private volatile InteractionsListener _runMain;
427
428     /** Runs the main method in this document in the interactions pane after resetting interactions with the source
429       * root for this document as the working directory. Warns the use if the class files for the doucment are not
430       * up to date. Fires an event to signal when execution is about to begin.
431       * NOTE: this code normally runs in the event thread; it cannot block waiting for an event that is triggered by
432       * event thread execution!
433       * @exception ClassNameNotFoundException propagated from getFirstTopLevelClass()
434       * @exception IOException propagated from GlobalModel.compileAll()
435       */

436     public void runMain() throws ClassNameNotFoundException, IOException JavaDoc {
437       assert EventQueue.isDispatchThread();
438       
439       // Get the class name for this document, the first top level class in the document.
440
final String JavaDoc className = getDocument().getQualifiedClassName();
441       final InteractionsDocument iDoc = _interactionsModel.getDocument();
442       if (! checkIfClassFileInSync()) {
443         iDoc.insertBeforeLastPrompt(DOCUMENT_OUT_OF_SYNC_MSG, InteractionsDocument.ERROR_STYLE);
444         return;
445       }
446       
447       final boolean wasDebuggerEnabled = getDebugger().isReady();
448       
449       _runMain = new DummyInteractionsListener() {
450         public void interpreterReady(File JavaDoc wd) {
451           // Restart debugger if it was previously enabled and is now off
452
if (wasDebuggerEnabled && (! getDebugger().isReady())) {
453             try { getDebugger().startUp(); } catch(DebugException de) { /* ignore, continue without debugger */ }
454           }
455           
456           // Load the proper text into the interactions document
457
iDoc.clearCurrentInput();
458           iDoc.append("java " + className, null);
459           
460           // Finally, execute the new interaction and record that event
461
_interactionsModel.interpretCurrentInteraction();
462           _notifier.runStarted(ConcreteOpenDefDoc.this);
463           SwingUtilities.invokeLater(new Runnable JavaDoc() {
464             public void run() {
465               /* Remove _runMain listener AFTER this interpreterReady listener completes and DROPS it acquireReadLock on
466                * _interactionsModel._notifier. */

467               _interactionsModel.removeListener(_runMain);
468             }
469           });
470           
471         }
472       };
473       
474       _interactionsModel.addListener(_runMain);
475       
476       File JavaDoc workDir;
477       if (isProjectActive()) workDir = getWorkingDirectory(); // use working directory for project
478
else {
479         // use source root of current document
480
try { workDir = getSourceRoot(); }
481         catch (InvalidPackageException e) { workDir = null; }
482       }
483       // Reset interactions to the soure root for this document; class will be executed when new interpreter is ready
484
resetInteractions(workDir);
485     }
486
487     /** Runs JUnit on the current document. Requires that all source documents are compiled before proceeding. */
488     public void startJUnit() throws ClassNotFoundException JavaDoc, IOException JavaDoc { _junitModel.junit(this); }
489
490     /** Generates Javadoc for this document, saving the output to a temporary directory. The location is provided to
491       * the javadocEnded event on the given listener.
492       * java@param saver FileSaveSelector for saving the file if it needs to be saved
493       */

494     public void generateJavadoc(FileSaveSelector saver) throws IOException JavaDoc {
495       // Use the model's classpath, and use the EventNotifier as the listener
496
_javadocModel.javadocDocument(this, saver, getClassPath().toString());
497     }
498
499     /** Called to indicate the document is being closed, so to remove all related state from the debug manager. */
500     public void removeFromDebugger() {
501       while (getBreakpointManager().getRegions().size() > 0) {
502         Breakpoint bp = getBreakpointManager().getRegions().get(0);
503         getBreakpointManager().removeRegion(bp);
504       }
505     }
506   } /* End of ConcreteOpenDefDoc */
507   
508   /** Creates a ConcreteOpenDefDoc for a new DefinitionsDocument.
509    * @return OpenDefinitionsDocument object for a new document
510    */

511   protected ConcreteOpenDefDoc _createOpenDefinitionsDocument() { return new ConcreteOpenDefDoc(); }
512   
513    /** Creates a ConcreteOpenDefDoc for a given file f
514    * @return OpenDefinitionsDocument object for f
515    */

516   protected ConcreteOpenDefDoc _createOpenDefinitionsDocument(File JavaDoc f) throws IOException JavaDoc {
517     if (! f.exists()) throw new FileNotFoundException("file " + f + " cannot be found");
518     return new ConcreteOpenDefDoc(f);
519   }
520   
521   /** Adds the source root for doc to the interactions classpath; this function is a helper to _openFiles.
522    * @param doc the document to add to the classpath
523    */

524   protected void addDocToClassPath(OpenDefinitionsDocument doc) {
525     try {
526       File JavaDoc classPath = doc.getSourceRoot();
527       try {
528         URL JavaDoc pathURL = FileOps.toURL(classPath);
529         if (doc.isAuxiliaryFile())
530           _interactionsModel.addProjectFilesClassPath(pathURL);
531         else _interactionsModel.addExternalFilesClassPath(pathURL);
532         setClassPathChanged(true);
533       }
534       catch(MalformedURLException JavaDoc murle) { /* fail silently */ }
535     }
536     catch (InvalidPackageException e) {
537       // Invalid package-- don't add it to classpath
538
}
539   }
540    
541   /** Instantiates the integrated debugger if the "debugger.enabled" config option is set to true. Leaves it
542    * at null if not.
543    */

544   private void _createDebugger() {
545     try {
546       _debugger = new JPDADebugger(this);
547       _jvm.setDebugModel((JPDADebugger) _debugger);
548
549       // add listener to set the project file to "changed" when a breakpoint or watch is added, removed, or changed
550
getBreakpointManager().addListener(new RegionManagerListener<Breakpoint>() {
551         public void regionAdded(final Breakpoint bp, int index) { setProjectChanged(true); }
552         public void regionChanged(final Breakpoint bp, int index) { setProjectChanged(true); }
553         public void regionRemoved(final Breakpoint bp) {
554           try {
555             getDebugger().removeBreakpoint(bp);
556           } catch(DebugException de) { /* just ignore it */ }
557           setProjectChanged(true);
558           }
559       });
560       getBookmarkManager().addListener(new RegionManagerListener<DocumentRegion>() {
561         public void regionAdded(DocumentRegion r, int index) { setProjectChanged(true); }
562         public void regionChanged(DocumentRegion r, int index) { setProjectChanged(true); }
563         public void regionRemoved(DocumentRegion r) { setProjectChanged(true); }
564       });
565       
566       _debugger.addListener(new DebugListener() {
567         public void watchSet(final DebugWatchData w) { setProjectChanged(true); }
568         public void watchRemoved(final DebugWatchData w) { setProjectChanged(true); }
569         
570         public void regionAdded(final Breakpoint bp, int index) { }
571         public void regionChanged(final Breakpoint bp, int index) { }
572         public void regionRemoved(final Breakpoint bp) { }
573         public void debuggerStarted() { }
574         public void debuggerShutdown() { }
575         public void threadLocationUpdated(OpenDefinitionsDocument doc, int lineNumber, boolean shouldHighlight) { }
576         public void breakpointReached(final Breakpoint bp) { }
577         public void stepRequested() { }
578         public void currThreadSuspended() { }
579         public void currThreadResumed() { }
580         public void threadStarted() { }
581         public void currThreadDied() { }
582         public void nonCurrThreadDied() { }
583         public void currThreadSet(DebugThreadData thread) { }
584       });
585     }
586     catch( NoClassDefFoundError JavaDoc ncdfe ) {
587       // JPDA not available, so we won't use it.
588
_debugger = NoDebuggerAvailable.ONLY;
589     }
590     catch( UnsupportedClassVersionError JavaDoc ucve ) {
591       // Wrong version of JPDA, so we won't use it.
592
_debugger = NoDebuggerAvailable.ONLY;
593     }
594     catch( Throwable JavaDoc t ) {
595       // Something went wrong in initialization, don't use debugger
596
_debugger = NoDebuggerAvailable.ONLY;
597     }
598   }
599
600   /** Get the class path to be used in all class-related operations.
601    * TODO: Insure that this is used wherever appropriate.
602    */

603   public ClassPathVector getClassPath() {
604     ClassPathVector result = new ClassPathVector();
605     
606     if (isProjectActive()) {
607       File JavaDoc buildDir = getBuildDirectory();
608       if (buildDir != null) { _addFileToClassPath(buildDir, result); }
609       
610       /* We prefer to assume the project root is the project's source root, rather than
611        * checking *every* file in the project for its source root. This is a bit problematic,
612        * because "Compile Project" won't care if the user has multiple source roots (or even just a
613        * single "src" subdirectory), and the user in this situation (assuming the build dir is
614        * null) wouldn't notice a problem until trying to access the compiled classes in the
615        * Interactions.
616        */

617       File JavaDoc projRoot = getProjectRoot();
618       if (projRoot != null) { _addFileToClassPath(projRoot, result); }
619       
620       ClassPathVector projectExtras = getExtraClassPath();
621       if (projectExtras != null) { result.addAll(projectExtras); }
622     }
623     else {
624       for (File JavaDoc f : getSourceRootSet()) { _addFileToClassPath(f, result); }
625     }
626       
627     Vector JavaDoc<File JavaDoc> globalExtras = DrJava.getConfig().getSetting(EXTRA_CLASSPATH);
628     if (globalExtras != null) {
629       for (File JavaDoc f : globalExtras) { _addFileToClassPath(f, result); }
630     }
631     
632     /* We must add JUnit to the class path. We do so by including the current JVM's class path.
633      * This is not ideal, because all other classes on the current class path (including all of DrJava's
634      * internal classes) are also included. But we're probably stuck doing something like this if we
635      * want to continue bundling JUnit with DrJava.
636      */

637     String JavaDoc currentClassPath = System.getProperty("java.class.path");
638     if (currentClassPath != null) {
639       // TODO: Parsing this string needs to only happen once, not every time this method is invoked.
640
StringTokenizer JavaDoc tokens = new StringTokenizer JavaDoc(currentClassPath, File.pathSeparator);
641       while (tokens.hasMoreTokens()) {
642         _addFileToClassPath(new File JavaDoc(tokens.nextToken()), result);
643       }
644     }
645     
646     return result;
647   }
648     
649   /** Helper for getClassPath: add a File, rather than a URL, to the given path */
650   private void _addFileToClassPath(File JavaDoc f, ClassPathVector cp) {
651     /* TODO: This conversion should be done somewhere where errors can be reported to the user --
652       for example, when a file is selected in the preferences dialog. */

653     try { cp.add(FileOps.toURL(f)); }
654     catch (MalformedURLException JavaDoc e) { /* ignore */ }
655   }
656   
657   /** Adds the project root (if a project is open), the source roots for other open documents, the paths in the
658     * "extra classpath" config option, as well as any project-specific classpaths to the interpreter's classpath.
659     * This method is called in DefaultInteractionsModel when the interpreter becomes ready.
660     */

661   public void resetInteractionsClassPath() {
662     ClassPathVector projectExtras = getExtraClassPath();
663     //System.out.println("Adding project classpath vector to interactions classpath: " + projectExtras);
664
if (projectExtras != null) for (URL JavaDoc cpE : projectExtras) { _interactionsModel.addProjectClassPath(cpE); }
665     
666     Vector JavaDoc<File JavaDoc> cp = DrJava.getConfig().getSetting(EXTRA_CLASSPATH);
667     if (cp != null) {
668       for (File JavaDoc f : cp) {
669         try { _interactionsModel.addExtraClassPath(FileOps.toURL(f)); }
670         catch(MalformedURLException JavaDoc murle) {
671           System.out.println("File " + f + " in your extra classpath could not be parsed to a URL; " +
672                              "it may contain un-URL-encodable characters.");
673         }
674       }
675     }
676     
677     for (OpenDefinitionsDocument odd: getAuxiliaryDocuments()) {
678       // this forwards directly to InterpreterJVM.addClassPath(String)
679
try { _interactionsModel.addProjectFilesClassPath(FileOps.toURL(odd.getSourceRoot())); }
680       catch(MalformedURLException JavaDoc murle) { /* fail silently */ }
681       catch(InvalidPackageException e) { /* ignore it */ }
682     }
683     
684     for (OpenDefinitionsDocument odd: getNonProjectDocuments()) {
685       // this forwards directly to InterpreterJVM.addClassPath(String)
686
try {
687         File JavaDoc sourceRoot = odd.getSourceRoot();
688         if (sourceRoot != null) _interactionsModel.addExternalFilesClassPath(FileOps.toURL(sourceRoot));
689       }
690       catch(MalformedURLException JavaDoc murle) { /* ignore it */ }
691       catch(InvalidPackageException e) { /* ignore it */ }
692     }
693     
694     // add project source root to projectFilesClassPath. All files in project tree have this root.
695

696     try { _interactionsModel.addProjectFilesClassPath(FileOps.toURL(getProjectRoot())); }
697     catch(MalformedURLException JavaDoc murle) { /* fail silently */ }
698     setClassPathChanged(false); // reset classPathChanged state
699
}
700   
701 // private class ExtraClasspathOptionListener implements OptionListener<Vector<File>> {
702
// public void optionChanged (OptionEvent<Vector<File>> oce) {
703
// Vector<File> cp = oce.value;
704
// if (cp != null) {
705
// for (File f: cp) {
706
// // this forwards directly to InterpreterJVM.addClassPath(String)
707
// try { _interactionsModel.addExtraClassPath(f.toURL()); }
708
// catch(MalformedURLException murle) {
709
// /* do nothing; findbugs signals a bug unless this catch clause spans more than two lines */
710
// }
711
// }
712
// }
713
// }
714
// }
715

716 }
717
Popular Tags