6363 * (i) the location of tools.jar in the Java JDK installed on this machine (so DrJava can invoke the javac compiler
6464 * stored in tools.jar)
6565 * (ii) the argument string for invoking the main JVM (notably -X options used to determine maximum heap size, etc.)
66+ *
67+ * Here is a summary of the launch mechanism of DrJava:
68+ *
69+ * 1. DrJava.main will be started.
70+ *
71+ * 2. DrJava.handleCommandLineArgs scans the command line arguments.
72+ * 2.1. This involves determining if the -new parameter forces a new instance.
73+ *
74+ * 3. DrJava.configureAndLoadDrJavaRoot determines if remote control should be used:
75+ * 3.1. If -new doesn't force a new instance
76+ * 3.2. and REMOTE_CONTROL_ENABLED
77+ * 3.3. and files have been specified on the command line
78+ * 3.4. and the remote control server can be contacted
79+ * 3.5. then DrJava will open the files in an existing instance and quit
80+ *
81+ * 4. DrJava.configureAndLoadDrJavaRoot determines if a restart is necessary:
82+ * 4.1. If MASTER_JVM_XMX is set
83+ * 4.2. or MASTER_JVM_ARGS is set
84+ * 4.3. then DrJava will attempt to restart itself with the specified JVM arguments
85+ * 4.4. Files that have arrived via Mac OS X's handleOpenFile event up to this point
86+ * are included in the main arguments for the restarted DrJava.
87+ * 4.5. If that fails, DrJava will ask if the user wants to delete the settings in the .drjava file
88+ * 4.5.1. If the user says "yes", DrJava will attempt another restart. If that fails, DrJava gives up.
89+ * 4.5.2. If the user says "no", DrJava gives up.
90+ * 4.6. If additional files arrive via the handleOpenFile event, DrJava will
91+ * attempt to use the remote control to open the files in the restarted DrJava.
92+ * 4.6.1. DrJava will perform NUM_REMOTE_CONTROL_RETRIES attempts to contact the
93+ * remote control server, with WAIT_BEFORE_REMOTE_CONTROL_RETRY ms of sleep time in between.
94+ *
95+ * 5. If neither the remote control was used nor a restart was necessary, DrJava will
96+ * call DrJavaRoot.main.
97+ * 5.1. Files that have arrived via Mac OS X's handleOpenFile event up to this point
98+ * are included in the arguments for DrJavaRoot.main.
99+ * 5.2. If additional files arrive via the handleOpenFile event, DrJava will
100+ * MainFrame.handleRemoteOpenFile.
101+ *
66102 * @version $Id$
67103 */
68104public class DrJava {
@@ -79,9 +115,25 @@ public class DrJava {
79115 * connecting to an already running instance. */
80116 static volatile boolean _forceNewInstance = false ;
81117
118+ /** true if a new DrJava needs to be restarted to adjust parameters. */
119+ static volatile boolean _doRestart = false ;
120+
121+ /** true if DrJava has already launched the new instance. */
122+ static volatile boolean _alreadyRestarted = false ;
123+
124+ /** true if the restarted DrJava will use remote control, and we can try to
125+ * pass along files to open that arrived too late. */
126+ static volatile boolean _restartedDrJavaUsesRemoteControl = true ;
127+
82128 /** Time in millisecond before restarting DrJava to change the heap size, etc. is deemed a success. */
83129 private static final int WAIT_BEFORE_DECLARING_SUCCESS = 5000 ;
84130
131+ /** Number of times we retry opening with the remote control. */
132+ private static final int NUM_REMOTE_CONTROL_RETRIES = 15 ;
133+
134+ /** Time in millisecond that we wait before making another remote control attempt. */
135+ private static final int WAIT_BEFORE_REMOTE_CONTROL_RETRY = 500 ;
136+
85137 /* Config objects can't be public static final, since we have to delay construction until we know the
86138 * config file's location. (Might be specified on command line.) Instead, use accessor methods to
87139 * prevent others from assigning new values. */
@@ -102,16 +154,72 @@ public class DrJava {
102154 public static FileConfiguration getConfig () { return _config ; }
103155
104156 /** @return an array of the files that were passed on the command line. */
105- public static String [] getFilesToOpen () { return _filesToOpen .toArray (new String [0 ]); }
157+ public static synchronized String [] getFilesToOpen () { return _filesToOpen .toArray (new String [0 ]); }
106158
107159 /** Add a file to the list of files to open. */
108- public static void addFileToOpen (String s ) {
160+ public static synchronized void addFileToOpen (String s ) {
109161 _filesToOpen .add (s );
110162 boolean isProjectFile =
111163 s .endsWith (OptionConstants .PROJECT_FILE_EXTENSION ) ||
112164 s .endsWith (OptionConstants .PROJECT_FILE_EXTENSION2 ) ||
113165 s .endsWith (OptionConstants .OLD_PROJECT_FILE_EXTENSION );
114166 _forceNewInstance |= isProjectFile ;
167+ if (_doRestart && _alreadyRestarted ) {
168+ _log .log ("addFileToOpen: already done the restart, trying to use remote control" );
169+ // we already did the restart, try to use the remote control to open the file
170+ if (DrJava .getConfig ().getSetting (edu .rice .cs .drjava .config .OptionConstants .REMOTE_CONTROL_ENABLED )) {
171+ _log .log ("\t remote control..." );
172+ openWithRemoteControl (_filesToOpen ,NUM_REMOTE_CONTROL_RETRIES );
173+ _log .log ("\t clearing _filesToOpen" );
174+ clearFilesToOpen ();
175+ }
176+ }
177+ }
178+
179+ /** Clear the list of files to open. */
180+ public static synchronized void clearFilesToOpen () {
181+ _filesToOpen .clear ();
182+ }
183+
184+ /** Open the specified files using the remote control. If the remote control server is not
185+ * running, numAttempts attempts will be made, with WAIT_BEFORE_REMOTE_CONTROL_RETRY
186+ * ms of sleep time in between.
187+ * @param files files to open with remote control
188+ * @param number of attempts to be made
189+ * @return true if successful
190+ */
191+ public static synchronized boolean openWithRemoteControl (ArrayList <String > files , int numAttempts ) {
192+ if (!DrJava .getConfig ().getSetting (edu .rice .cs .drjava .config .OptionConstants .REMOTE_CONTROL_ENABLED ) ||
193+ !_restartedDrJavaUsesRemoteControl ||
194+ (files .size ()==0 )) return false ;
195+
196+ ArrayList <String > fs = new ArrayList <String >(files );
197+ int failCount = 0 ;
198+ while (failCount <numAttempts ) {
199+ try {
200+ RemoteControlClient .openFile (null );
201+ if (RemoteControlClient .isServerRunning ()) {
202+ // existing instance is running and responding
203+ for (int i = 0 ; i < fs .size (); ++i ) {
204+ _log .log ("opening with remote control " +fs .get (i ));
205+ RemoteControlClient .openFile (new File (fs .get (i )));
206+ files .remove (fs .get (i ));
207+ }
208+ return true ; // success
209+ }
210+ else {
211+ ++failCount ;
212+ _log .log ("Failed to open with remote control, attempt " +failCount +" of " +NUM_REMOTE_CONTROL_RETRIES );
213+ if (failCount >=numAttempts ) return false ; // failure
214+ try { Thread .sleep (WAIT_BEFORE_REMOTE_CONTROL_RETRY ); }
215+ catch (InterruptedException ie ) { /* just try again now */ }
216+ }
217+ }
218+ catch (IOException ioe ) {
219+ ioe .printStackTrace ();
220+ }
221+ }
222+ return false ; // failure
115223 }
116224
117225 /** @return true if the debug console should be enabled */
@@ -138,20 +246,7 @@ public static void configureAndLoadDrJavaRoot(String[] args) {
138246 if (!_forceNewInstance &&
139247 DrJava .getConfig ().getSetting (edu .rice .cs .drjava .config .OptionConstants .REMOTE_CONTROL_ENABLED ) &&
140248 (_filesToOpen .size () > 0 )) {
141- try {
142- RemoteControlClient .openFile (null );
143- if (RemoteControlClient .isServerRunning ()) {
144- // existing instance is running and responding
145- for (int i = 0 ; i < _filesToOpen .size (); ++i ) {
146- RemoteControlClient .openFile (new File (_filesToOpen .get (i )));
147- }
148- // files opened in existing instance, quit
149- System .exit (0 );
150- }
151- }
152- catch (IOException ioe ) {
153- ioe .printStackTrace ();
154- }
249+ if (openWithRemoteControl (_filesToOpen ,1 )) System .exit (0 ); // files opened in existing instance, quit
155250 }
156251
157252 // The code below is in a loop so that DrJava can retry launching itself
@@ -162,12 +257,11 @@ public static void configureAndLoadDrJavaRoot(String[] args) {
162257 while (failCount < 2 ) {
163258 // Restart if there are custom JVM args
164259 String masterMemory = getConfig ().getSetting (MASTER_JVM_XMX ).trim ();
165- boolean restart = (getConfig ().getSetting (MASTER_JVM_ARGS ).length () > 0 )
260+ boolean _doRestart = (getConfig ().getSetting (MASTER_JVM_ARGS ).length () > 0 )
166261 || (!"" .equals (masterMemory ) && !OptionConstants .heapSizeChoices .get (0 ).equals (masterMemory ));
167- _log .log ("restart : " +restart );
262+ _log .log ("_doRestart : " +_doRestart );
168263
169264 LinkedList <String > classArgs = new LinkedList <String >();
170- classArgs .addAll (_filesToOpen );
171265
172266 // Add the parameters "-debugConsole" to classArgsList if _showDebugConsole is true
173267 if (_showDebugConsole ) { classArgs .addFirst ("-debugConsole" ); }
@@ -178,7 +272,21 @@ public static void configureAndLoadDrJavaRoot(String[] args) {
178272 classArgs .addFirst ("-config" );
179273 }
180274
181- if (restart ) {
275+ synchronized (DrJava .class ) {
276+ classArgs .addAll (_filesToOpen );
277+ clearFilesToOpen ();
278+ _log .log ("_filesToOpen copied into class arguments, clearing _filesToOpen" );
279+ }
280+
281+ if (_doRestart ) {
282+ if (DrJava .getConfig ().getSetting (edu .rice .cs .drjava .config .OptionConstants .REMOTE_CONTROL_ENABLED )) {
283+ // at this time, OUR remote control server hasn't been started yet
284+ // if one is running, then we won't be able to contact the restarted DrJava
285+ _restartedDrJavaUsesRemoteControl = !RemoteControlClient .isServerRunning ();
286+ } else {
287+ // no remote control
288+ _restartedDrJavaUsesRemoteControl = false ;
289+ }
182290
183291 // Run a new copy of DrJava and exit
184292 try {
@@ -193,16 +301,20 @@ public static void configureAndLoadDrJavaRoot(String[] args) {
193301 jvmb = jvmb .classPath (edu .rice .cs .plt .iter .IterUtil .asSizedIterable (extendedClassPath ));
194302 _log .log ("JVMBuilder: jvmArguments = " +jvmb .jvmArguments ());
195303 _log .log ("JVMBuilder: classPath = " +jvmb .classPath ());
304+ _log .log ("JVMBuilder: mainParams = " +classArgs );
196305
197306 // start new DrJava
198307 Process p = jvmb .start (DrJavaRoot .class .getName (), classArgs );
308+ _alreadyRestarted = true ;
309+ _log .log ("_alreadyRestarted = true" );
199310 DelayedInterrupter timeout = new DelayedInterrupter (WAIT_BEFORE_DECLARING_SUCCESS );
200311 try {
201312 int exitValue = p .waitFor ();
202313 timeout .abort ();
203314 failed = (exitValue != 0 );
204315 }
205316 catch (InterruptedException e ) { /* timeout was reached */ }
317+ _log .log ("failed = " +failed );
206318 if (failed ) {
207319 if (failCount > 0 ) {
208320 // 2nd time that spawning has failed, give up
@@ -212,7 +324,7 @@ public static void configureAndLoadDrJavaRoot(String[] args) {
212324 "https://sourceforge.net/projects/drjava/" ,
213325 "Could Not Start DrJava" ,
214326 JOptionPane .ERROR_MESSAGE );
215- System .exit (0 );
327+ System .exit (1 );
216328 }
217329 else {
218330 // 1st time that spawning has failed, offer to reset configuration
@@ -230,6 +342,11 @@ public static void configureAndLoadDrJavaRoot(String[] args) {
230342 continue ;
231343 }
232344 }
345+ else {
346+ // check if there are any files left in _filesToOpen
347+ _log .log ("not failed, send remaining files via remote control: " +_filesToOpen );
348+ openWithRemoteControl (_filesToOpen , NUM_REMOTE_CONTROL_RETRIES );
349+ }
233350 }
234351 catch (IOException ioe ) {
235352 // Display error
@@ -246,6 +363,13 @@ public static void configureAndLoadDrJavaRoot(String[] args) {
246363 else {
247364 // No restart -- just invoke DrJavaRoot.main.
248365 DrJavaRoot .main (classArgs .toArray (new String [0 ]));
366+ // when we return from here, DrJavaRoot._mainFrame has been initialized
367+ // but we may still have files in _filesToOpen that were not processed
368+ // do that now
369+ ArrayList <String > fs = new ArrayList <String >(_filesToOpen );
370+ for (String f : fs ) {
371+ DrJavaRoot .handleRemoteOpenFile (new File (f ), -1 );
372+ }
249373 }
250374 break ;
251375 }
@@ -268,8 +392,6 @@ static boolean handleCommandLineArgs(String[] args) {
268392 int argIndex = 0 ;
269393 int len = args .length ;
270394 _log .log ("handleCommandLineArgs. _filesToOpen: " + _filesToOpen );
271- _log .log ("\t _filesToOpen cleared" );
272- _filesToOpen .clear ();
273395
274396 while (argIndex < len ) {
275397 String arg = args [argIndex ++];
@@ -444,7 +566,7 @@ protected static void _saveConfig() {
444566 /* Erase all non-final bindings created in this class. Only used in testing. */
445567 public static void cleanUp () {
446568 _log .log ("cleanUp. _filesToOpen: " + _filesToOpen );
447- _filesToOpen . clear ();
569+ clearFilesToOpen ();
448570 _log .log ("\t _filesToOpen cleared" );
449571 _jvmArgs .clear ();
450572 // Do not set _config or _propertiesFile to null because THEY ARE static
0 commit comments