001: /*BEGIN_COPYRIGHT_BLOCK
002: *
003: * Copyright (c) 2001-2007, JavaPLT group at Rice University (javaplt@rice.edu)
004: * All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions are met:
008: * * Redistributions of source code must retain the above copyright
009: * notice, this list of conditions and the following disclaimer.
010: * * Redistributions in binary form must reproduce the above copyright
011: * notice, this list of conditions and the following disclaimer in the
012: * documentation and/or other materials provided with the distribution.
013: * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
014: * names of its contributors may be used to endorse or promote products
015: * derived from this software without specific prior written permission.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
018: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
019: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
020: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
021: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
022: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
023: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
024: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
025: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
026: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
027: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028: *
029: * This software is Open Source Initiative approved Open Source Software.
030: * Open Source Initative Approved is a trademark of the Open Source Initiative.
031: *
032: * This file is part of DrJava. Download the current version of this project
033: * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
034: *
035: * END_COPYRIGHT_BLOCK*/
036:
037: package edu.rice.cs.drjava;
038:
039: import java.io.*;
040: import java.net.URL;
041: import java.net.URLClassLoader;
042: import java.net.MalformedURLException;
043: import java.util.Arrays;
044: import java.util.StringTokenizer;
045: import java.util.jar.JarFile;
046: import javax.swing.UIManager;
047: import javax.swing.*;
048: import java.awt.dnd.*;
049: import java.awt.datatransfer.*;
050:
051: import edu.rice.cs.util.FileOpenSelector;
052: import edu.rice.cs.util.UnexpectedException;
053: import edu.rice.cs.util.OutputStreamRedirector;
054: import edu.rice.cs.util.newjvm.ExecJVM;
055: import edu.rice.cs.util.swing.Utilities;
056:
057: import edu.rice.cs.drjava.ui.MainFrame;
058: import edu.rice.cs.drjava.ui.SplashScreen;
059: import edu.rice.cs.drjava.ui.ClassPathFilter;
060: import edu.rice.cs.drjava.ui.DrJavaErrorWindow;
061: import edu.rice.cs.drjava.ui.DrJavaErrorHandler;
062: import edu.rice.cs.drjava.ui.SimpleInteractionsWindow;
063: import edu.rice.cs.drjava.model.*;
064: import edu.rice.cs.drjava.model.compiler.*;
065: import edu.rice.cs.drjava.platform.PlatformFactory;
066: import edu.rice.cs.drjava.config.FileConfiguration;
067: import edu.rice.cs.drjava.config.*;
068:
069: import static edu.rice.cs.drjava.config.OptionConstants.*;
070:
071: /** Main class for DrJava.
072: * @version $Id: DrJavaRoot.java 4260 2007-10-10 20:28:34Z mgricken $
073: */
074: public class DrJavaRoot {
075:
076: /* Constants for language levels */
077: public static final int FULL_JAVA = 0;
078: public static final int ELEMENTARY_LEVEL = 1;
079: public static final int INTERMEDIATE_LEVEL = 2;
080: public static final int ADVANCED_LEVEL = 3;
081: public static final String[] LANGUAGE_LEVEL_EXTENSIONS = new String[] {
082: "java", "dj0", "dj1", "dj2" };
083:
084: /** Class to probe to see if the debugger is available */
085: public static final String TEST_DEBUGGER_CLASS = "com.sun.jdi.Bootstrap";
086:
087: private static final PrintStream _consoleOut = System.out;
088: private static final PrintStream _consoleErr = System.err;
089:
090: // /** This field is only used in the instance of this class in the Interpreter JVM. */
091:
092: private static boolean _attemptingAugmentedClassPath = false;
093: private static SimpleInteractionsWindow _debugConsole = null;
094:
095: private static boolean anyLineNumbersSpecified = false;
096:
097: /** Main frame of this DrJava instance. */
098: private static MainFrame _mainFrame = null;
099:
100: /* Config objects can't be public static final, since we have to delay construction until we know the
101: * config file's location. (Might be specified on command line.) Instead, use accessor methods to
102: * prevent others from assigning new values. */
103:
104: public static void main(final String[] args) {
105: // Platform-specific UI setup.
106: PlatformFactory.ONLY.beforeUISetup();
107:
108: // Utilities.show("DrJavaRoot started with args = " + Arrays.toString(args));
109: // let DrJava class handle command line arguments
110: if (!DrJava.handleCommandLineArgs(args)) {
111: System.exit(0);
112: }
113:
114: final String[] filesToOpen = DrJava.getFilesToOpen();
115: final int numFiles = filesToOpen.length;
116:
117: /* files to open held in filesToOpen[0:numFiles-1] which may be an initial segment of filesToOpen */
118:
119: /* In some unit test cases, creating a MainFrame in the main thread generated index out of bounds exceptions. It appear that this
120: * creation process generates some swing events that are processed by the event thread. Hence we need to create the MainFrame in
121: * the event thread.
122: */
123: // Utilities.invokeAndWait(new Runnable() {
124: // public void run() {
125: try {
126: String configLAFName = DrJava.getConfig().getSetting(
127: LOOK_AND_FEEL);
128: String currLAFName = UIManager.getLookAndFeel().getClass()
129: .getName();
130: if (!configLAFName.equals(currLAFName))
131: UIManager.setLookAndFeel(configLAFName);
132:
133: // The MainFrame *must* be constructed after the compiler setup process has
134: // occurred; otherwise, the list of compilers in the UI will be wrong.
135:
136: // Utilities.showDebug("Creating MainFrame");
137:
138: _mainFrame = new MainFrame();
139:
140: // Utilities.showDebug("MainFrame created");
141:
142: // Make sure all uncaught exceptions are shown in an DrJavaErrorHandler
143: DrJavaErrorWindow.setFrame(_mainFrame);
144: System.setProperty("sun.awt.exception.handler",
145: "edu.rice.cs.drjava.ui.DrJavaErrorHandler");
146:
147: // false means "do not jump to the line number that may be specified, just open the file"
148: _openCommandLineFiles(_mainFrame, filesToOpen, numFiles,
149: false);
150:
151: /* This call on invokeLater only runs in the main thread, so we use SwingUtilities rather than Utilities.
152: * We use invokeLater here ensure all files have finished loading and added to the fileview before the MainFrame
153: * is set visible. When this was not done, we occasionally encountered a NullPointerException on start up when
154: * specifying a file (ex: java -jar drjava.jar somefile.java)
155: */
156: SwingUtilities.invokeLater(new Runnable() {
157: public void run() {
158: _mainFrame.start();
159: if (anyLineNumbersSpecified) {
160: // this time, we do want to jump to the line number
161: _openCommandLineFiles(_mainFrame, filesToOpen,
162: numFiles, true);
163: }
164: }
165: });
166:
167: // redirect stdout to DrJava's console
168: System.setOut(new PrintStream(new OutputStreamRedirector() {
169: public void print(String s) {
170: _mainFrame.getModel().systemOutPrint(s);
171: }
172: }));
173:
174: // redirect stderr to DrJava's console
175: System.setErr(new PrintStream(new OutputStreamRedirector() {
176: public void print(String s) {
177: _mainFrame.getModel().systemErrPrint(s);
178: }
179: }));
180:
181: // Utilities.showDebug("showDebugConsole flag = " + DrJava.getShowDebugConsole());
182: // Show debug console if enabled
183: if (DrJava.getShowDebugConsole())
184: showDrJavaDebugConsole(_mainFrame);
185: } catch (Throwable t) {
186: // Show any errors to the real System.err and in an DrJavaErrorHandler
187: _consoleErr.println(t.getClass().getName() + ": "
188: + t.getMessage());
189: t.printStackTrace(_consoleErr);
190: System.out.println("error thrown");
191: new DrJavaErrorHandler().handle(t);
192: }
193: // }
194: // });
195: }
196:
197: /** Handle the list of files specified on the command line. Feature request #509701.
198: * If file exists, open it in DrJava. Otherwise, ignore it.
199: * Is there a better way to handle nonexistent files? Dialog box, maybe?
200: */
201: static void openCommandLineFiles(final MainFrame mf,
202: final String[] filesToOpen, boolean jump) {
203: openCommandLineFiles(mf, filesToOpen, filesToOpen.length, jump);
204: }
205:
206: /** Handle the list of files specified on the command line. Feature request #509701. If the final element in
207: * filesToOpen is a pathSeparator, it opens the debug console. If file exists, open it in DrJava. Otherwise, ignore
208: * it. Is there a better way to handle nonexistent files? Dialog box, maybe?
209: * Why the wait?
210: */
211: static void openCommandLineFiles(final MainFrame mf,
212: final String[] filesToOpen, final int len,
213: final boolean jump) {
214: Utilities.invokeAndWait(new Runnable() {
215: public void run() {
216: _openCommandLineFiles(mf, filesToOpen, len, jump);
217: }
218: });
219: }
220:
221: private static void _openCommandLineFiles(final MainFrame mf,
222: String[] filesToOpen, int len, boolean jump) {
223: // Utilities.showDebug("Files to open: " + Arrays.toString(filesToOpen));
224: anyLineNumbersSpecified = false;
225: for (int i = 0; i < len; i++) {
226: String currFileName = filesToOpen[i];
227:
228: // check if the file contains a line number
229: // the line number can be specified at the end of the file name,
230: // separated by File.pathSeparator
231: int lineNo = -1;
232: int pathSepIndex = currFileName
233: .indexOf(File.pathSeparatorChar);
234: if (pathSepIndex >= 0) {
235: try {
236: lineNo = new Integer(currFileName
237: .substring(pathSepIndex + 1));
238: anyLineNumbersSpecified = true;
239: } catch (NumberFormatException nfe) {
240: lineNo = -1;
241: }
242: currFileName = currFileName.substring(0, pathSepIndex);
243: }
244:
245: boolean isProjectFile = currFileName.endsWith(".pjt");
246: final File file = new File(currFileName).getAbsoluteFile();
247: FileOpenSelector command = new FileOpenSelector() {
248: public File[] getFiles() {
249: return new File[] { file };
250: }
251: };
252: try {
253: if (isProjectFile) {
254: mf.openProject(command);
255: } else {
256: if (jump && (lineNo >= 0)) {
257: // if a line number has been specified, open the file using MainFrame.open,
258: // then use invokeLater to run MainFrame._jumpToLine.
259: // note: this can only be done after MainFrame.start() has been called.
260: mf.open(command);
261: final int l = lineNo;
262: edu.rice.cs.util.swing.Utilities
263: .invokeLater(new Runnable() {
264: public void run() {
265: mf._jumpToLine(l);
266: }
267: });
268: } else {
269: // without line number, use the model's openFile.
270: mf.getModel().openFile(command);
271: }
272: }
273: }
274:
275: catch (FileNotFoundException ex) {
276: // TODO: show a dialog? (file not found)
277: } catch (SecurityException se) {
278: // TODO: show a dialog? (file not found)
279: } catch (AlreadyOpenException aoe) {
280: // This explicitly does nothing to ignore duplicate files.
281: } catch (FileMovedException aoe) {
282: // This explicitly does nothing to ignore duplicate files.
283: } catch (IOException ex) {
284: // TODO: show a dialog? (file not found)
285: } catch (Exception ex) {
286: throw new UnexpectedException(ex);
287: }
288: }
289: }
290:
291: /** Shows a separate interactions window with a reference to DrJava's MainFrame defined as "mainFrame".
292: * Useful for debugging DrJava.
293: * @param mf MainFrame to define in the new window
294: */
295: public static void showDrJavaDebugConsole(MainFrame mf) {
296: if (_debugConsole == null) {
297: _debugConsole = new SimpleInteractionsWindow(
298: "DrJava Debug Console") {
299: protected void close() {
300: dispose();
301: _debugConsole = null;
302: }
303: };
304: _debugConsole.defineConstant("mainFrame", mf);
305: _debugConsole.defineConstant("model", mf.getModel());
306: _debugConsole.defineConstant("config", DrJava.getConfig());
307: _debugConsole.setInterpreterPrivateAccessible(true);
308: _debugConsole.setVisible(true);
309: } else
310: _debugConsole.toFront();
311: }
312:
313: /** Get the actual System.err stream.
314: * @return System.err
315: */
316: public static PrintStream consoleErr() {
317: return _consoleErr;
318: }
319:
320: /** Get the actual System.out stream.
321: * @return System.out
322: */
323: public static PrintStream consoleOut() {
324: return _consoleOut;
325: }
326:
327: /** User dragged something into the component. */
328: public static void dragEnter(DropTargetDragEvent dropTargetDragEvent) {
329: _mainFrame.dragEnter(dropTargetDragEvent);
330: }
331:
332: /** User dropped something on the component. */
333: public static void drop(DropTargetDropEvent dropTargetDropEvent) {
334: _mainFrame.drop(dropTargetDropEvent);
335: }
336: }
|