KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > internal > ide > application > IDEApplication


1 /*******************************************************************************
2  * Copyright (c) 2003, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.ui.internal.ide.application;
12
13 import java.io.File JavaDoc;
14 import java.io.FileInputStream JavaDoc;
15 import java.io.FileOutputStream JavaDoc;
16 import java.io.IOException JavaDoc;
17 import java.io.OutputStream JavaDoc;
18 import java.net.MalformedURLException JavaDoc;
19 import java.net.URL JavaDoc;
20 import java.util.Properties JavaDoc;
21
22 import org.eclipse.core.runtime.IConfigurationElement;
23 import org.eclipse.core.runtime.IExecutableExtension;
24 import org.eclipse.core.runtime.IStatus;
25 import org.eclipse.core.runtime.Platform;
26 import org.eclipse.core.runtime.Status;
27 import org.eclipse.equinox.app.IApplication;
28 import org.eclipse.equinox.app.IApplicationContext;
29 import org.eclipse.jface.dialogs.MessageDialog;
30 import org.eclipse.osgi.service.datalocation.Location;
31 import org.eclipse.osgi.util.NLS;
32 import org.eclipse.swt.SWT;
33 import org.eclipse.swt.widgets.Display;
34 import org.eclipse.swt.widgets.MessageBox;
35 import org.eclipse.swt.widgets.Shell;
36 import org.eclipse.ui.IWorkbench;
37 import org.eclipse.ui.PlatformUI;
38 import org.eclipse.ui.internal.ide.ChooseWorkspaceData;
39 import org.eclipse.ui.internal.ide.ChooseWorkspaceDialog;
40 import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
41 import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
42 import org.eclipse.ui.internal.ide.StatusUtil;
43
44 /**
45  * The "main program" for the Eclipse IDE.
46  *
47  * @since 3.0
48  */

49 public class IDEApplication implements IApplication, IExecutableExtension {
50
51     /**
52      * The name of the folder containing metadata information for the workspace.
53      */

54     public static final String JavaDoc METADATA_FOLDER = ".metadata"; //$NON-NLS-1$
55

56     private static final String JavaDoc VERSION_FILENAME = "version.ini"; //$NON-NLS-1$
57

58     private static final String JavaDoc WORKSPACE_VERSION_KEY = "org.eclipse.core.runtime"; //$NON-NLS-1$
59

60     private static final String JavaDoc WORKSPACE_VERSION_VALUE = "1"; //$NON-NLS-1$
61

62     private static final String JavaDoc PROP_EXIT_CODE = "eclipse.exitcode"; //$NON-NLS-1$
63

64     /**
65      * A special return code that will be recognized by the launcher and used to
66      * restart the workbench.
67      */

68     private static final Integer JavaDoc EXIT_RELAUNCH = new Integer JavaDoc(24);
69
70     /**
71      * The ID of the application plug-in
72      */

73     public static final String JavaDoc PLUGIN_ID = "org.eclipse.ui.ide.application"; //$NON-NLS-1$
74

75     /**
76      * Creates a new IDE application.
77      */

78     public IDEApplication() {
79         // There is nothing to do for IDEApplication
80
}
81
82     /* (non-Javadoc)
83      * @see org.eclipse.equinox.app.IApplication#start(org.eclipse.equinox.app.IApplicationContext context)
84      */

85     public Object JavaDoc start(IApplicationContext appContext) throws Exception JavaDoc {
86         Display display = createDisplay();
87
88         try {
89             Shell shell = new Shell(display, SWT.ON_TOP);
90
91             try {
92                 if (!checkInstanceLocation(shell)) {
93                     Platform.endSplash();
94                     return EXIT_OK;
95                 }
96             } finally {
97                 if (shell != null) {
98                     shell.dispose();
99                 }
100             }
101
102             // create the workbench with this advisor and run it until it exits
103
// N.B. createWorkbench remembers the advisor, and also registers
104
// the workbench globally so that all UI plug-ins can find it using
105
// PlatformUI.getWorkbench() or AbstractUIPlugin.getWorkbench()
106
int returnCode = PlatformUI.createAndRunWorkbench(display,
107                     new IDEWorkbenchAdvisor());
108
109             // the workbench doesn't support relaunch yet (bug 61809) so
110
// for now restart is used, and exit data properties are checked
111
// here to substitute in the relaunch return code if needed
112
if (returnCode != PlatformUI.RETURN_RESTART) {
113                 return EXIT_OK;
114             }
115
116             // if the exit code property has been set to the relaunch code, then
117
// return that code now, otherwise this is a normal restart
118
return EXIT_RELAUNCH.equals(Integer.getInteger(PROP_EXIT_CODE)) ? EXIT_RELAUNCH
119                     : EXIT_RESTART;
120         } finally {
121             if (display != null) {
122                 display.dispose();
123             }
124         }
125     }
126
127     /**
128      * Creates the display used by the application.
129      *
130      * @return the display used by the application
131      */

132     protected Display createDisplay() {
133         return PlatformUI.createDisplay();
134     }
135
136     /* (non-Javadoc)
137      * @see org.eclipse.core.runtime.IExecutableExtension#setInitializationData(org.eclipse.core.runtime.IConfigurationElement, java.lang.String, java.lang.Object)
138      */

139     public void setInitializationData(IConfigurationElement config,
140             String JavaDoc propertyName, Object JavaDoc data) {
141         // There is nothing to do for IDEApplication
142
}
143
144     /**
145      * Return true if a valid workspace path has been set and false otherwise.
146      * Prompt for and set the path if possible and required.
147      *
148      * @return true if a valid instance location has been set and false
149      * otherwise
150      */

151     private boolean checkInstanceLocation(Shell shell) {
152         // -data @none was specified but an ide requires workspace
153
Location instanceLoc = Platform.getInstanceLocation();
154         if (instanceLoc == null) {
155             MessageDialog
156                     .openError(
157                             shell,
158                             IDEWorkbenchMessages.IDEApplication_workspaceMandatoryTitle,
159                             IDEWorkbenchMessages.IDEApplication_workspaceMandatoryMessage);
160             return false;
161         }
162
163         // -data "/valid/path", workspace already set
164
if (instanceLoc.isSet()) {
165             // make sure the meta data version is compatible (or the user has
166
// chosen to overwrite it).
167
if (!checkValidWorkspace(shell, instanceLoc.getURL())) {
168                 return false;
169             }
170
171             // at this point its valid, so try to lock it and update the
172
// metadata version information if successful
173
try {
174                 if (instanceLoc.lock()) {
175                     writeWorkspaceVersion();
176                     return true;
177                 }
178                 
179                 // we failed to create the directory.
180
// Two possibilities:
181
// 1. directory is already in use
182
// 2. directory could not be created
183
File JavaDoc workspaceDirectory = new File JavaDoc(instanceLoc.getURL().getFile());
184                 if (workspaceDirectory.exists()) {
185                     MessageDialog.openError(
186                             shell,
187                             IDEWorkbenchMessages.IDEApplication_workspaceCannotLockTitle,
188                             IDEWorkbenchMessages.IDEApplication_workspaceCannotLockMessage);
189                 } else {
190                     MessageDialog.openError(
191                             shell,
192                             IDEWorkbenchMessages.IDEApplication_workspaceCannotBeSetTitle,
193                             IDEWorkbenchMessages.IDEApplication_workspaceCannotBeSetMessage);
194                 }
195             } catch (IOException JavaDoc e) {
196                 IDEWorkbenchPlugin.log("Could not obtain lock for workspace location", //$NON-NLS-1$
197
e);
198                 MessageDialog
199                 .openError(
200                         shell,
201                         IDEWorkbenchMessages.InternalError,
202                         e.getMessage());
203             }
204             return false;
205         }
206
207         // -data @noDefault or -data not specified, prompt and set
208
ChooseWorkspaceData launchData = new ChooseWorkspaceData(instanceLoc
209                 .getDefault());
210
211         boolean force = false;
212         while (true) {
213             URL JavaDoc workspaceUrl = promptForWorkspace(shell, launchData, force);
214             if (workspaceUrl == null) {
215                 return false;
216             }
217
218             // if there is an error with the first selection, then force the
219
// dialog to open to give the user a chance to correct
220
force = true;
221
222             try {
223                 // the operation will fail if the url is not a valid
224
// instance data area, so other checking is unneeded
225
if (instanceLoc.setURL(workspaceUrl, true)) {
226                     launchData.writePersistedData();
227                     writeWorkspaceVersion();
228                     return true;
229                 }
230             } catch (IllegalStateException JavaDoc e) {
231                 MessageDialog
232                         .openError(
233                                 shell,
234                                 IDEWorkbenchMessages.IDEApplication_workspaceCannotBeSetTitle,
235                                 IDEWorkbenchMessages.IDEApplication_workspaceCannotBeSetMessage);
236                 return false;
237             }
238
239             // by this point it has been determined that the workspace is
240
// already in use -- force the user to choose again
241
MessageDialog.openError(shell, IDEWorkbenchMessages.IDEApplication_workspaceInUseTitle,
242                     IDEWorkbenchMessages.IDEApplication_workspaceInUseMessage);
243         }
244     }
245
246     /**
247      * Open a workspace selection dialog on the argument shell, populating the
248      * argument data with the user's selection. Perform first level validation
249      * on the selection by comparing the version information. This method does
250      * not examine the runtime state (e.g., is the workspace already locked?).
251      *
252      * @param shell
253      * @param launchData
254      * @param force
255      * setting to true makes the dialog open regardless of the
256      * showDialog value
257      * @return An URL storing the selected workspace or null if the user has
258      * canceled the launch operation.
259      */

260     private URL JavaDoc promptForWorkspace(Shell shell, ChooseWorkspaceData launchData,
261             boolean force) {
262         URL JavaDoc url = null;
263         do {
264             // don't use the parent shell to make the dialog a top-level
265
// shell. See bug 84881.
266
new ChooseWorkspaceDialog(null, launchData, false, true).prompt(force);
267             String JavaDoc instancePath = launchData.getSelection();
268             if (instancePath == null) {
269                 return null;
270             }
271
272             // the dialog is not forced on the first iteration, but is on every
273
// subsequent one -- if there was an error then the user needs to be
274
// allowed to fix it
275
force = true;
276
277             // 70576: don't accept empty input
278
if (instancePath.length() <= 0) {
279                 MessageDialog
280                 .openError(
281                         shell,
282                         IDEWorkbenchMessages.IDEApplication_workspaceEmptyTitle,
283                         IDEWorkbenchMessages.IDEApplication_workspaceEmptyMessage);
284                 continue;
285             }
286
287             // create the workspace if it does not already exist
288
File JavaDoc workspace = new File JavaDoc(instancePath);
289             if (!workspace.exists()) {
290                 workspace.mkdir();
291             }
292
293             try {
294                 // Don't use File.toURL() since it adds a leading slash that Platform does not
295
// handle properly. See bug 54081 for more details.
296
String JavaDoc path = workspace.getAbsolutePath().replace(
297                         File.separatorChar, '/');
298                 url = new URL JavaDoc("file", null, path); //$NON-NLS-1$
299
} catch (MalformedURLException JavaDoc e) {
300                 MessageDialog
301                         .openError(
302                                 shell,
303                                 IDEWorkbenchMessages.IDEApplication_workspaceInvalidTitle,
304                                 IDEWorkbenchMessages.IDEApplication_workspaceInvalidMessage);
305                 continue;
306             }
307         } while (!checkValidWorkspace(shell, url));
308
309         return url;
310     }
311
312     /**
313      * Return true if the argument directory is ok to use as a workspace and
314      * false otherwise. A version check will be performed, and a confirmation
315      * box may be displayed on the argument shell if an older version is
316      * detected.
317      *
318      * @return true if the argument URL is ok to use as a workspace and false
319      * otherwise.
320      */

321     private boolean checkValidWorkspace(Shell shell, URL JavaDoc url) {
322         // a null url is not a valid workspace
323
if (url == null) {
324             return false;
325         }
326
327         String JavaDoc version = readWorkspaceVersion(url);
328
329         // if the version could not be read, then there is not any existing
330
// workspace data to trample, e.g., perhaps its a new directory that
331
// is just starting to be used as a workspace
332
if (version == null) {
333             return true;
334         }
335
336         final int ide_version = Integer.parseInt(WORKSPACE_VERSION_VALUE);
337         int workspace_version = Integer.parseInt(version);
338
339         // equality test is required since any version difference (newer
340
// or older) may result in data being trampled
341
if (workspace_version == ide_version) {
342             return true;
343         }
344
345         // At this point workspace has been detected to be from a version
346
// other than the current ide version -- find out if the user wants
347
// to use it anyhow.
348
String JavaDoc title = IDEWorkbenchMessages.IDEApplication_versionTitle;
349         String JavaDoc message = NLS.bind(IDEWorkbenchMessages.IDEApplication_versionMessage, url.getFile());
350
351         MessageBox mbox = new MessageBox(shell, SWT.OK | SWT.CANCEL
352                 | SWT.ICON_WARNING | SWT.APPLICATION_MODAL);
353         mbox.setText(title);
354         mbox.setMessage(message);
355         return mbox.open() == SWT.OK;
356     }
357
358     /**
359      * Look at the argument URL for the workspace's version information. Return
360      * that version if found and null otherwise.
361      */

362     private static String JavaDoc readWorkspaceVersion(URL JavaDoc workspace) {
363         File JavaDoc versionFile = getVersionFile(workspace, false);
364         if (versionFile == null || !versionFile.exists()) {
365             return null;
366         }
367
368         try {
369             // Although the version file is not spec'ed to be a Java properties
370
// file, it happens to follow the same format currently, so using
371
// Properties to read it is convenient.
372
Properties JavaDoc props = new Properties JavaDoc();
373             FileInputStream JavaDoc is = new FileInputStream JavaDoc(versionFile);
374             try {
375                 props.load(is);
376             } finally {
377                 is.close();
378             }
379
380             return props.getProperty(WORKSPACE_VERSION_KEY);
381         } catch (IOException JavaDoc e) {
382             IDEWorkbenchPlugin.log("Could not read version file", new Status( //$NON-NLS-1$
383
IStatus.ERROR, IDEWorkbenchPlugin.IDE_WORKBENCH,
384                     IStatus.ERROR,
385                     e.getMessage() == null ? "" : e.getMessage(), //$NON-NLS-1$,
386
e));
387             return null;
388         }
389     }
390
391     /**
392      * Write the version of the metadata into a known file overwriting any
393      * existing file contents. Writing the version file isn't really crucial,
394      * so the function is silent about failure
395      */

396     private static void writeWorkspaceVersion() {
397         Location instanceLoc = Platform.getInstanceLocation();
398         if (instanceLoc == null || instanceLoc.isReadOnly()) {
399             return;
400         }
401
402         File JavaDoc versionFile = getVersionFile(instanceLoc.getURL(), true);
403         if (versionFile == null) {
404             return;
405         }
406
407         OutputStream JavaDoc output = null;
408         try {
409             String JavaDoc versionLine = WORKSPACE_VERSION_KEY + '='
410                     + WORKSPACE_VERSION_VALUE;
411
412             output = new FileOutputStream JavaDoc(versionFile);
413             output.write(versionLine.getBytes("UTF-8")); //$NON-NLS-1$
414
} catch (IOException JavaDoc e) {
415             IDEWorkbenchPlugin.log("Could not write version file", //$NON-NLS-1$
416
StatusUtil.newStatus(IStatus.ERROR, e.getMessage(), e));
417         } finally {
418             try {
419                 if (output != null) {
420                     output.close();
421                 }
422             } catch (IOException JavaDoc e) {
423                 // do nothing
424
}
425         }
426     }
427
428     /**
429      * The version file is stored in the metadata area of the workspace. This
430      * method returns an URL to the file or null if the directory or file does
431      * not exist (and the create parameter is false).
432      *
433      * @param create
434      * If the directory and file does not exist this parameter
435      * controls whether it will be created.
436      * @return An url to the file or null if the version file does not exist or
437      * could not be created.
438      */

439     private static File JavaDoc getVersionFile(URL JavaDoc workspaceUrl, boolean create) {
440         if (workspaceUrl == null) {
441             return null;
442         }
443
444         try {
445             // make sure the directory exists
446
File JavaDoc metaDir = new File JavaDoc(workspaceUrl.getPath(), METADATA_FOLDER);
447             if (!metaDir.exists() && (!create || !metaDir.mkdir())) {
448                 return null;
449             }
450
451             // make sure the file exists
452
File JavaDoc versionFile = new File JavaDoc(metaDir, VERSION_FILENAME);
453             if (!versionFile.exists()
454                     && (!create || !versionFile.createNewFile())) {
455                 return null;
456             }
457
458             return versionFile;
459         } catch (IOException JavaDoc e) {
460             // cannot log because instance area has not been set
461
return null;
462         }
463     }
464
465     /* (non-Javadoc)
466      * @see org.eclipse.equinox.app.IApplication#stop()
467      */

468     public void stop() {
469         final IWorkbench workbench = PlatformUI.getWorkbench();
470         if (workbench == null)
471             return;
472         final Display display = workbench.getDisplay();
473         display.syncExec(new Runnable JavaDoc() {
474             public void run() {
475                 if (!display.isDisposed())
476                     workbench.close();
477             }
478         });
479     }
480 }
481
Popular Tags