KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > equinox > launcher > Main


1 /*******************************************************************************
2  * Copyright (c) 2000, 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.equinox.launcher;
12
13 import java.io.*;
14 import java.lang.reflect.InvocationTargetException JavaDoc;
15 import java.lang.reflect.Method JavaDoc;
16 import java.net.*;
17 import java.security.*;
18 import java.util.*;
19 import java.util.zip.ZipEntry JavaDoc;
20 import java.util.zip.ZipFile JavaDoc;
21 import org.eclipse.equinox.internal.launcher.Constants;
22
23 /**
24  * The launcher for Eclipse.
25  *
26  * <b>Note:</b> This class should not be referenced programmatically by
27  * other Java code. This class exists only for the purpose of launching Eclipse
28  * from the command line. To launch Eclipse programmatically, use
29  * org.eclipse.core.runtime.adaptor.EclipseStarter. The fields and methods
30  * on this class are not API.
31  */

32 public class Main {
33     /**
34      * Indicates whether this instance is running in debug mode.
35      */

36     protected boolean debug = false;
37
38     /**
39      * The location of the launcher to run.
40      */

41     protected String JavaDoc bootLocation = null;
42
43     /**
44      * The location of the install root
45      */

46     protected URL installLocation = null;
47
48     /**
49      * The location of the configuration information for this instance
50      */

51     protected URL configurationLocation = null;
52
53     /**
54      * The location of the configuration information in the install root
55      */

56     protected String JavaDoc parentConfigurationLocation = null;
57
58     /**
59      * The id of the bundle that will contain the framework to run. Defaults to org.eclipse.osgi.
60      */

61     protected String JavaDoc framework = OSGI;
62
63     /**
64      * The extra development time class path entries for the framework.
65      */

66     protected String JavaDoc devClassPath = null;
67
68     /*
69      * The extra development time class path entries for all bundles.
70      */

71     private Properties devClassPathProps = null;
72
73     /**
74      * Indicates whether this instance is running in development mode.
75      */

76     protected boolean inDevelopmentMode = false;
77     
78     /**
79      * Indicates which OS was passed in with -os
80      */

81     protected String JavaDoc os = null;
82     protected String JavaDoc ws = null;
83     protected String JavaDoc arch = null;
84
85 // private String name = null; // The name to brand the launcher
86
// private String launcher = null; // The full path to the launcher
87
private String JavaDoc library = null;
88     private String JavaDoc exitData = null;
89
90     private String JavaDoc vm = null;
91     private String JavaDoc[] vmargs = null;
92     private String JavaDoc[] commands = null;
93     String JavaDoc[] extensionPaths = null;
94
95     JNIBridge bridge = null;
96     
97     // splash handling
98
private boolean showSplash = false;
99     private String JavaDoc splashLocation = null;
100     private String JavaDoc endSplash = null;
101     private boolean initialize = false;
102     private boolean splashDown = false;
103     public final class SplashHandler extends Thread JavaDoc {
104         public void run() {
105             takeDownSplash();
106         }
107         public void updateSplash() {
108             if(bridge != null) {
109                 bridge.updateSplash();
110             }
111         }
112     }
113     private final Thread JavaDoc splashHandler = new SplashHandler();
114
115     //splash screen system properties
116
public static final String JavaDoc SPLASH_HANDLE = "org.eclipse.equinox.launcher.splash.handle"; //$NON-NLS-1$
117
public static final String JavaDoc SPLASH_LOCATION = "org.eclipse.equinox.launcher.splash.location"; //$NON-NLS-1$
118

119     // command line args
120
private static final String JavaDoc FRAMEWORK = "-framework"; //$NON-NLS-1$
121
private static final String JavaDoc INSTALL = "-install"; //$NON-NLS-1$
122
private static final String JavaDoc INITIALIZE = "-initialize"; //$NON-NLS-1$
123
private static final String JavaDoc VM = "-vm"; //$NON-NLS-1$
124
private static final String JavaDoc VMARGS = "-vmargs"; //$NON-NLS-1$
125
private static final String JavaDoc DEBUG = "-debug"; //$NON-NLS-1$
126
private static final String JavaDoc DEV = "-dev"; //$NON-NLS-1$
127
private static final String JavaDoc CONFIGURATION = "-configuration"; //$NON-NLS-1$
128
private static final String JavaDoc NOSPLASH = "-nosplash"; //$NON-NLS-1$
129
private static final String JavaDoc SHOWSPLASH = "-showsplash"; //$NON-NLS-1$
130
private static final String JavaDoc EXITDATA = "-exitdata"; //$NON-NLS-1$
131
private static final String JavaDoc NAME = "-name"; //$NON-NLS-1$
132
private static final String JavaDoc LAUNCHER = "-launcher"; //$NON-NLS-1$
133
private static final String JavaDoc LIBRARY = "--launcher.library"; //$NON-NLS-1$
134
private static final String JavaDoc NL = "-nl"; //$NON-NLS-1$
135
private static final String JavaDoc ENDSPLASH = "-endsplash"; //$NON-NLS-1$
136
private static final String JavaDoc SPLASH_IMAGE = "splash.bmp"; //$NON-NLS-1$
137
private static final String JavaDoc CLEAN = "-clean"; //$NON-NLS-1$
138
private static final String JavaDoc NOEXIT = "-noExit"; //$NON-NLS-1$
139
private static final String JavaDoc OS = "-os"; //$NON-NLS-1$
140
private static final String JavaDoc WS = "-ws"; //$NON-NLS-1$
141
private static final String JavaDoc ARCH = "-arch"; //$NON-NLS-1$
142
private static final String JavaDoc STARTUP = "-startup"; //$NON-NLS-1$
143

144     private static final String JavaDoc OSGI = "org.eclipse.osgi"; //$NON-NLS-1$
145
private static final String JavaDoc STARTER = "org.eclipse.core.runtime.adaptor.EclipseStarter"; //$NON-NLS-1$
146
private static final String JavaDoc PLATFORM_URL = "platform:/base/"; //$NON-NLS-1$
147
private static final String JavaDoc ECLIPSE_PROPERTIES = "eclipse.properties"; //$NON-NLS-1$
148
private static final String JavaDoc FILE_SCHEME = "file:"; //$NON-NLS-1$
149
protected static final String JavaDoc REFERENCE_SCHEME = "reference:"; //$NON-NLS-1$
150
protected static final String JavaDoc JAR_SCHEME = "jar:"; //$NON-NLS-1$
151

152     // constants: configuration file location
153
private static final String JavaDoc CONFIG_DIR = "configuration/"; //$NON-NLS-1$
154
private static final String JavaDoc CONFIG_FILE = "config.ini"; //$NON-NLS-1$
155
private static final String JavaDoc CONFIG_FILE_TEMP_SUFFIX = ".tmp"; //$NON-NLS-1$
156
private static final String JavaDoc CONFIG_FILE_BAK_SUFFIX = ".bak"; //$NON-NLS-1$
157
private static final String JavaDoc ECLIPSE = "eclipse"; //$NON-NLS-1$
158
private static final String JavaDoc PRODUCT_SITE_MARKER = ".eclipseproduct"; //$NON-NLS-1$
159
private static final String JavaDoc PRODUCT_SITE_ID = "id"; //$NON-NLS-1$
160
private static final String JavaDoc PRODUCT_SITE_VERSION = "version"; //$NON-NLS-1$
161

162     // constants: System property keys and/or configuration file elements
163
private static final String JavaDoc PROP_USER_HOME = "user.home"; //$NON-NLS-1$
164
private static final String JavaDoc PROP_USER_DIR = "user.dir"; //$NON-NLS-1$
165
private static final String JavaDoc PROP_INSTALL_AREA = "osgi.install.area"; //$NON-NLS-1$
166
private static final String JavaDoc PROP_CONFIG_AREA = "osgi.configuration.area"; //$NON-NLS-1$
167
private static final String JavaDoc PROP_CONFIG_AREA_DEFAULT = "osgi.configuration.area.default"; //$NON-NLS-1$
168
private static final String JavaDoc PROP_BASE_CONFIG_AREA = "osgi.baseConfiguration.area"; //$NON-NLS-1$
169
private static final String JavaDoc PROP_SHARED_CONFIG_AREA = "osgi.sharedConfiguration.area"; //$NON-NLS-1$
170
private static final String JavaDoc PROP_CONFIG_CASCADED = "osgi.configuration.cascaded"; //$NON-NLS-1$
171
protected static final String JavaDoc PROP_FRAMEWORK = "osgi.framework"; //$NON-NLS-1$
172
private static final String JavaDoc PROP_SPLASHPATH = "osgi.splashPath"; //$NON-NLS-1$
173
private static final String JavaDoc PROP_SPLASHLOCATION = "osgi.splashLocation"; //$NON-NLS-1$
174
private static final String JavaDoc PROP_CLASSPATH = "osgi.frameworkClassPath"; //$NON-NLS-1$
175
private static final String JavaDoc PROP_EXTENSIONS = "osgi.framework.extensions"; //$NON-NLS-1$
176
private static final String JavaDoc PROP_FRAMEWORK_SYSPATH = "osgi.syspath"; //$NON-NLS-1$
177
private static final String JavaDoc PROP_FRAMEWORK_SHAPE = "osgi.framework.shape"; //$NON-NLS-1$
178
private static final String JavaDoc PROP_LOGFILE = "osgi.logfile"; //$NON-NLS-1$
179
private static final String JavaDoc PROP_REQUIRED_JAVA_VERSION = "osgi.requiredJavaVersion"; //$NON-NLS-1$
180
private static final String JavaDoc PROP_PARENT_CLASSLOADER = "osgi.parentClassloader"; //$NON-NLS-1$
181
private static final String JavaDoc PROP_FRAMEWORK_PARENT_CLASSLOADER = "osgi.frameworkParentClassloader"; //$NON-NLS-1$
182
private static final String JavaDoc PROP_NL = "osgi.nl"; //$NON-NLS-1$
183
static final String JavaDoc PROP_NOSHUTDOWN = "osgi.noShutdown"; //$NON-NLS-1$
184
private static final String JavaDoc PROP_DEBUG = "osgi.debug"; //$NON-NLS-1$
185

186     private static final String JavaDoc PROP_EXITCODE = "eclipse.exitcode"; //$NON-NLS-1$
187
private static final String JavaDoc PROP_EXITDATA = "eclipse.exitdata"; //$NON-NLS-1$
188

189     private static final String JavaDoc PROP_VM = "eclipse.vm"; //$NON-NLS-1$
190
private static final String JavaDoc PROP_VMARGS = "eclipse.vmargs"; //$NON-NLS-1$
191
private static final String JavaDoc PROP_COMMANDS = "eclipse.commands"; //$NON-NLS-1$
192
private static final String JavaDoc PROP_ECLIPSESECURITY = "eclipse.security"; //$NON-NLS-1$
193

194     // Data mode constants for user, configuration and data locations.
195
private static final String JavaDoc NONE = "@none"; //$NON-NLS-1$
196
private static final String JavaDoc NO_DEFAULT = "@noDefault"; //$NON-NLS-1$
197
private static final String JavaDoc USER_HOME = "@user.home"; //$NON-NLS-1$
198
private static final String JavaDoc USER_DIR = "@user.dir"; //$NON-NLS-1$
199

200     // types of parent classloaders the framework can have
201
private static final String JavaDoc PARENT_CLASSLOADER_APP = "app"; //$NON-NLS-1$
202
private static final String JavaDoc PARENT_CLASSLOADER_EXT = "ext"; //$NON-NLS-1$
203
private static final String JavaDoc PARENT_CLASSLOADER_BOOT = "boot"; //$NON-NLS-1$
204
private static final String JavaDoc PARENT_CLASSLOADER_CURRENT = "current"; //$NON-NLS-1$
205

206     // log file handling
207
protected static final String JavaDoc SESSION = "!SESSION"; //$NON-NLS-1$
208
protected static final String JavaDoc ENTRY = "!ENTRY"; //$NON-NLS-1$
209
protected static final String JavaDoc MESSAGE = "!MESSAGE"; //$NON-NLS-1$
210
protected static final String JavaDoc STACK = "!STACK"; //$NON-NLS-1$
211
protected static final int ERROR = 4;
212     protected static final String JavaDoc PLUGIN_ID = "org.eclipse.equinox.launcher"; //$NON-NLS-1$
213
protected File JavaDoc logFile = null;
214     protected BufferedWriter log = null;
215     protected boolean newSession = true;
216
217     /**
218      * A structured form for a version identifier.
219      *
220      * @see http://java.sun.com/j2se/versioning_naming.html for information on valid version strings
221      */

222     static class Identifier {
223         private static final String JavaDoc DELIM = ". _-"; //$NON-NLS-1$
224
private int major, minor, service;
225         Identifier(int major, int minor, int service) {
226             super();
227             this.major = major;
228             this.minor = minor;
229             this.service = service;
230         }
231         /**
232          * @throws NumberFormatException if cannot parse the major and minor version components
233          */

234         Identifier(String JavaDoc versionString) {
235             super();
236             StringTokenizer tokenizer = new StringTokenizer(versionString, DELIM);
237
238             // major
239
if (tokenizer.hasMoreTokens())
240                 major = Integer.parseInt(tokenizer.nextToken());
241
242             // minor
243
if (tokenizer.hasMoreTokens())
244                 minor = Integer.parseInt(tokenizer.nextToken());
245
246             try {
247                 // service
248
if (tokenizer.hasMoreTokens())
249                     service = Integer.parseInt(tokenizer.nextToken());
250             } catch (NumberFormatException JavaDoc nfe) {
251                 // ignore the service qualifier in that case and default to 0
252
// this will allow us to tolerate other non-conventional version numbers
253
}
254         }
255         /**
256          * Returns true if this id is considered to be greater than or equal to the given baseline.
257          * e.g.
258          * 1.2.9 >= 1.3.1 -> false
259          * 1.3.0 >= 1.3.1 -> false
260          * 1.3.1 >= 1.3.1 -> true
261          * 1.3.2 >= 1.3.1 -> true
262          * 2.0.0 >= 1.3.1 -> true
263          */

264         boolean isGreaterEqualTo(Identifier minimum) {
265             if (major < minimum.major)
266                 return false;
267             if (major > minimum.major)
268                 return true;
269             // major numbers are equivalent so check minor
270
if (minor < minimum.minor)
271                 return false;
272             if (minor > minimum.minor)
273                 return true;
274             // minor numbers are equivalent so check service
275
return service >= minimum.service;
276         }
277     }
278
279     private String JavaDoc getWS() {
280         if (ws != null)
281             return ws;
282         String JavaDoc os = getOS();
283         if (os.equals(Constants.OS_WIN32))
284             return Constants.WS_WIN32;
285         if (os.equals(Constants.OS_LINUX))
286             return Constants.WS_GTK;
287         if (os.equals(Constants.OS_MACOSX))
288             return Constants.WS_CARBON;
289         if (os.equals(Constants.OS_HPUX))
290             return Constants.WS_MOTIF;
291         if (os.equals(Constants.OS_AIX))
292             return Constants.WS_MOTIF;
293         if (os.equals(Constants.OS_SOLARIS))
294             return Constants.WS_MOTIF;
295         if (os.equals(Constants.OS_QNX))
296             return Constants.WS_PHOTON;
297         return Constants.WS_UNKNOWN;
298     }
299     private String JavaDoc getOS() {
300         if (os != null)
301             return os;
302         String JavaDoc osName = System.getProperties().getProperty("os.name"); //$NON-NLS-1$
303
if (osName.regionMatches(true, 0, Constants.OS_WIN32, 0, 3))
304             return Constants.OS_WIN32;
305         // EXCEPTION: All mappings of SunOS convert to Solaris
306
if (osName.equalsIgnoreCase(Constants.INTERNAL_OS_SUNOS))
307             return Constants.OS_SOLARIS;
308         if (osName.equalsIgnoreCase(Constants.INTERNAL_OS_LINUX))
309             return Constants.OS_LINUX;
310         if (osName.equalsIgnoreCase(Constants.INTERNAL_OS_QNX))
311             return Constants.OS_QNX;
312         if (osName.equalsIgnoreCase(Constants.INTERNAL_OS_AIX))
313             return Constants.OS_AIX;
314         if (osName.equalsIgnoreCase(Constants.INTERNAL_OS_HPUX))
315             return Constants.OS_HPUX;
316         // os.name on Mac OS can be either Mac OS or Mac OS X
317
if (osName.regionMatches(true, 0, Constants.INTERNAL_OS_MACOSX, 0, Constants.INTERNAL_OS_MACOSX.length()))
318             return Constants.OS_MACOSX;
319         return Constants.OS_UNKNOWN;
320     }
321     private String JavaDoc getArch() {
322         if (arch != null)
323             return arch;
324         String JavaDoc name = System.getProperties().getProperty("os.arch");//$NON-NLS-1$
325
// Map i386 architecture to x86
326
if (name.equalsIgnoreCase(Constants.INTERNAL_ARCH_I386))
327             return Constants.ARCH_X86;
328         // Map amd64 architecture to x86_64
329
else if (name.equalsIgnoreCase(Constants.INTERNAL_AMD64))
330             return Constants.ARCH_X86_64;
331
332         return name;
333     }
334     
335     /**
336      * Sets up the JNI bridge to native calls
337      */

338     private void setupJNI(URL[] defaultPath) {
339         String JavaDoc libPath = null;
340         
341         if (library != null) {
342             File JavaDoc lib = new File JavaDoc(library);
343             if(lib.isDirectory()) {
344                 libPath = searchFor("eclipse", lib.getAbsolutePath()); //$NON-NLS-1$
345
} else if(lib.exists()){
346                 libPath = lib.getAbsolutePath();
347             }
348         }
349         if(libPath == null) {
350             //find our fragment name
351
String JavaDoc fragmentOS = getOS();
352             StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(PLUGIN_ID);
353             buffer.append('.');
354             buffer.append(getWS());
355             buffer.append('.');
356             buffer.append(fragmentOS);
357             if(!fragmentOS.equals("macosx")){ //$NON-NLS-1$
358
buffer.append('.');
359                 buffer.append(getArch());
360             }
361             String JavaDoc fragmentName = buffer.toString();
362             String JavaDoc fragment = null;
363             if (inDevelopmentMode) {
364                 String JavaDoc devPathList = devClassPathProps.getProperty(PLUGIN_ID);
365                 String JavaDoc[] locations = getArrayFromList(devPathList);
366                 if (locations.length > 0) {
367                     File JavaDoc location = new File JavaDoc(locations[0]);
368                     if (location.isAbsolute()) {
369                         String JavaDoc dir = location.getParent();
370                         fragment = searchFor(fragmentName, dir);
371                         if (fragment != null)
372                             libPath = searchFor("eclipse", fragment); //$NON-NLS-1$
373
}
374                 }
375             }
376             if (libPath == null && bootLocation != null) {
377                 URL[] urls = defaultPath;
378                 if (urls != null && urls.length > 0) {
379                     //the last one is most interesting
380
for (int i = urls.length - 1; i >= 0 && libPath == null; i--) {
381                         File JavaDoc entryFile = new File JavaDoc(urls[i].getFile());
382                         String JavaDoc dir = entryFile.getParent();
383                         if (inDevelopmentMode) {
384                             String JavaDoc devDir = dir + "/" + PLUGIN_ID + "/fragments"; //$NON-NLS-1$ //$NON-NLS-2$
385
fragment = searchFor(fragmentName, devDir);
386                         }
387                         if (fragment == null)
388                             fragment = searchFor(fragmentName, dir);
389                         if (fragment != null)
390                             libPath = searchFor("eclipse", fragment); //$NON-NLS-1$
391
}
392                 }
393             }
394             if(libPath == null) {
395                 URL install = getInstallLocation();
396                 String JavaDoc location = install.getFile();
397                 location += "/plugins/"; //$NON-NLS-1$
398
fragment = searchFor(fragmentName, location);
399                 if (fragment != null)
400                     libPath = searchFor("eclipse", fragment); //$NON-NLS-1$
401
}
402         }
403         library = libPath;
404         if(library != null)
405             bridge = new JNIBridge(library);
406     }
407     
408     /**
409      * Executes the launch.
410      *
411      * @param args command-line arguments
412      * @exception Exception thrown if a problem occurs during the launch
413      */

414     protected void basicRun(String JavaDoc[] args) throws Exception JavaDoc {
415         System.getProperties().put("eclipse.startTime", Long.toString(System.currentTimeMillis())); //$NON-NLS-1$
416
commands = args;
417         String JavaDoc[] passThruArgs = processCommandLine(args);
418         
419         if (!debug)
420             // debug can be specified as system property as well
421
debug = System.getProperty(PROP_DEBUG) != null;
422         setupVMProperties();
423         processConfiguration();
424         
425         // need to ensure that getInstallLocation is called at least once to initialize the value.
426
// Do this AFTER processing the configuration to allow the configuration to set
427
// the install location.
428
getInstallLocation();
429
430         // locate boot plugin (may return -dev mode variations)
431
URL[] bootPath = getBootPath(bootLocation);
432         
433         //Set up the JNI bridge. We need to know the install location to find the shared library
434
setupJNI(bootPath);
435         
436         //ensure minimum Java version, do this after JNI is set up so that we can write an error message
437
//with exitdata if we fail.
438
if (!checkVersion(System.getProperty("java.version"), System.getProperty(PROP_REQUIRED_JAVA_VERSION))) //$NON-NLS-1$
439
return;
440         
441         setSecurityPolicy(bootPath);
442         // splash handling is done here, because the default case needs to know
443
// the location of the boot plugin we are going to use
444
handleSplash(bootPath);
445
446         beforeFwkInvocation();
447         invokeFramework(passThruArgs, bootPath);
448     }
449
450     protected void beforeFwkInvocation() {
451         //Nothing to do.
452
}
453     
454     protected void setSecurityPolicy(URL[] bootPath) {
455         String JavaDoc eclipseSecurity = System.getProperty(PROP_ECLIPSESECURITY);
456         if (eclipseSecurity != null) {
457             SecurityManager JavaDoc sm = System.getSecurityManager();
458             boolean setSM = false;
459             if (sm == null) {
460                 if (eclipseSecurity.length() < 1) {
461                     eclipseSecurity = "java.lang.SecurityManager"; //$NON-NLS-1$
462
}
463                 try {
464                     Class JavaDoc clazz = Class.forName(eclipseSecurity);
465                     sm = (SecurityManager JavaDoc) clazz.newInstance();
466                     setSM = true;
467                 }
468                 catch (Throwable JavaDoc t) {
469                     System.getProperties().put("java.security.manager", eclipseSecurity); // let the framework try to load it later. //$NON-NLS-1$
470
}
471             }
472             
473             ProtectionDomain domain = Main.class.getProtectionDomain();
474             CodeSource source = null;
475             if (domain != null)
476                 source = Main.class.getProtectionDomain().getCodeSource();
477             if (domain == null || source == null) {
478                 log("Can not automatically set the security manager. Please use a policy file."); //$NON-NLS-1$
479
return;
480             }
481             // get the list of codesource URLs to grant AllPermission to
482
URL[] rootURLs = new URL[bootPath.length + 1];
483             rootURLs[0] = source.getLocation();
484             System.arraycopy(bootPath, 0, rootURLs, 1, bootPath.length);
485             // replace the security policy
486
Policy eclipsePolicy = new EclipsePolicy(Policy.getPolicy(), rootURLs);
487             Policy.setPolicy(eclipsePolicy);
488             if (setSM)
489                 System.setSecurityManager(sm);
490         }
491     }
492
493     private void invokeFramework(String JavaDoc[] passThruArgs, URL[] bootPath) throws ClassNotFoundException JavaDoc, NoSuchMethodException JavaDoc, IllegalAccessException JavaDoc, Error JavaDoc, Exception JavaDoc, InvocationTargetException JavaDoc {
494         String JavaDoc type = System.getProperty(PROP_FRAMEWORK_PARENT_CLASSLOADER, System.getProperty(PROP_PARENT_CLASSLOADER, PARENT_CLASSLOADER_BOOT));
495         ClassLoader JavaDoc parent = null;
496         if (PARENT_CLASSLOADER_APP.equalsIgnoreCase(type))
497             parent = ClassLoader.getSystemClassLoader();
498         else if (PARENT_CLASSLOADER_EXT.equalsIgnoreCase(type)) {
499             ClassLoader JavaDoc appCL = ClassLoader.getSystemClassLoader();
500             if (appCL != null)
501                 parent = appCL.getParent();
502         } else if (PARENT_CLASSLOADER_CURRENT.equalsIgnoreCase(type))
503                 parent = this.getClass().getClassLoader();
504         URLClassLoader loader = new StartupClassLoader(bootPath, parent);
505         Class JavaDoc clazz = loader.loadClass(STARTER);
506         Method JavaDoc method = clazz.getDeclaredMethod("run", new Class JavaDoc[] {String JavaDoc[].class, Runnable JavaDoc.class}); //$NON-NLS-1$
507
try {
508             method.invoke(clazz, new Object JavaDoc[] {passThruArgs, splashHandler});
509         } catch (InvocationTargetException JavaDoc e) {
510             if (e.getTargetException() instanceof Error JavaDoc)
511                 throw (Error JavaDoc) e.getTargetException();
512             else if (e.getTargetException() instanceof Exception JavaDoc)
513                 throw (Exception JavaDoc) e.getTargetException();
514             else
515                 //could be a subclass of Throwable!
516
throw e;
517         }
518     }
519
520     /**
521      * Checks whether the given available version is greater or equal to the
522      * given required version.
523      * <p>Will set PROP_EXITCODE/PROP_EXITDATA accordingly if check fails.</p>
524      *
525      * @return a boolean indicating whether the checking passed
526      */

527     private boolean checkVersion(String JavaDoc availableVersion, String JavaDoc requiredVersion) {
528         if (requiredVersion == null || availableVersion == null)
529             return true;
530         try {
531             Identifier required = new Identifier(requiredVersion);
532             Identifier available = new Identifier(availableVersion);
533             boolean compatible = available.isGreaterEqualTo(required);
534             if (!compatible) {
535                 // any non-zero value should do it - 14 used to be used for version incompatibility in Eclipse 2.1
536
System.getProperties().put(PROP_EXITCODE, "14"); //$NON-NLS-1$
537
System.getProperties().put(PROP_EXITDATA, "<title>Incompatible JVM</title>Version " + availableVersion + " of the JVM is not suitable for this product. Version: "+ requiredVersion + " or greater is required."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
538
}
539             return compatible;
540         } catch (SecurityException JavaDoc e) {
541             // If the security manager won't allow us to get the system property, continue for
542
// now and let things fail later on their own if necessary.
543
return true;
544         } catch (NumberFormatException JavaDoc e) {
545             // If the version string was in a format that we don't understand, continue and
546
// let things fail later on their own if necessary.
547
return true;
548         }
549     }
550     
551     /**
552      * Returns a string representation of the given URL String. This converts
553      * escaped sequences (%..) in the URL into the appropriate characters.
554      * NOTE: due to class visibility there is a copy of this method
555      * in InternalBootLoader
556      */

557     protected String JavaDoc decode(String JavaDoc urlString) {
558         //try to use Java 1.4 method if available
559
try {
560             Class JavaDoc clazz = URLDecoder.class;
561             Method JavaDoc method = clazz.getDeclaredMethod("decode", new Class JavaDoc[] {String JavaDoc.class, String JavaDoc.class}); //$NON-NLS-1$
562
//first encode '+' characters, because URLDecoder incorrectly converts
563
//them to spaces on certain class library implementations.
564
if (urlString.indexOf('+') >= 0) {
565                 int len = urlString.length();
566                 StringBuffer JavaDoc buf = new StringBuffer JavaDoc(len);
567                 for (int i = 0; i < len; i++) {
568                     char c = urlString.charAt(i);
569                     if (c == '+')
570                         buf.append("%2B"); //$NON-NLS-1$
571
else
572                         buf.append(c);
573                 }
574                 urlString = buf.toString();
575             }
576             Object JavaDoc result = method.invoke(null, new Object JavaDoc[] {urlString, "UTF-8"}); //$NON-NLS-1$
577
if (result != null)
578                 return (String JavaDoc) result;
579         } catch (Exception JavaDoc e) {
580             //JDK 1.4 method not found -- fall through and decode by hand
581
}
582         //decode URL by hand
583
boolean replaced = false;
584         byte[] encodedBytes = urlString.getBytes();
585         int encodedLength = encodedBytes.length;
586         byte[] decodedBytes = new byte[encodedLength];
587         int decodedLength = 0;
588         for (int i = 0; i < encodedLength; i++) {
589             byte b = encodedBytes[i];
590             if (b == '%') {
591                 if(i+2 >= encodedLength)
592                     throw new IllegalArgumentException JavaDoc("Malformed URL (\""+urlString+"\"): % must be followed by 2 digits."); //$NON-NLS-1$//$NON-NLS-2$
593
byte enc1 = encodedBytes[++i];
594                 byte enc2 = encodedBytes[++i];
595                 b = (byte) ((hexToByte(enc1) << 4) + hexToByte(enc2));
596                 replaced = true;
597             }
598             decodedBytes[decodedLength++] = b;
599         }
600         if (!replaced)
601             return urlString;
602         try {
603             return new String JavaDoc(decodedBytes, 0, decodedLength, "UTF-8"); //$NON-NLS-1$
604
} catch (UnsupportedEncodingException e) {
605             //use default encoding
606
return new String JavaDoc(decodedBytes, 0, decodedLength);
607         }
608     }
609
610     /**
611      * Returns the result of converting a list of comma-separated tokens into an array
612      *
613      * @return the array of string tokens
614      * @param prop the initial comma-separated string
615      */

616     protected String JavaDoc[] getArrayFromList(String JavaDoc prop) {
617         if (prop == null || prop.trim().equals("")) //$NON-NLS-1$
618
return new String JavaDoc[0];
619         Vector list = new Vector();
620         StringTokenizer tokens = new StringTokenizer(prop, ","); //$NON-NLS-1$
621
while (tokens.hasMoreTokens()) {
622             String JavaDoc token = tokens.nextToken().trim();
623             if (!token.equals("")) //$NON-NLS-1$
624
list.addElement(token);
625         }
626         return list.isEmpty() ? new String JavaDoc[0] : (String JavaDoc[]) list.toArray(new String JavaDoc[list.size()]);
627     }
628
629     /**
630      * Returns the <code>URL</code>-based class path describing where the boot classes
631      * are located when running in development mode.
632      *
633      * @return the url-based class path
634      * @param base the base location
635      * @exception MalformedURLException if a problem occurs computing the class path
636      */

637     private URL[] getDevPath(URL base) throws IOException {
638         ArrayList result = new ArrayList(5);
639         if (inDevelopmentMode)
640             addDevEntries(base, result, OSGI);
641         //The jars from the base always need to be added, even when running in dev mode (bug 46772)
642
addBaseJars(base, result);
643         return (URL[]) result.toArray(new URL[result.size()]);
644     }
645
646     URL constructURL(URL url, String JavaDoc name) {
647         //Recognize the following URLs
648
//url: file:foo/dir/
649
//url: file:foo/file.jar
650

651         String JavaDoc externalForm = url.toExternalForm();
652         if (externalForm.endsWith(".jar")) { //$NON-NLS-1$
653
try {
654                 return new URL(JAR_SCHEME + url + "!/" + name); //$NON-NLS-1$
655
} catch (MalformedURLException e) {
656                 //Ignore
657
}
658         }
659         
660         try {
661             return new URL(url, name);
662         } catch (MalformedURLException e) {
663             //Ignore
664
return null;
665         }
666     }
667     private void readFrameworkExtensions(URL base, ArrayList result) throws IOException {
668         String JavaDoc[] extensions = getArrayFromList(System.getProperties().getProperty(PROP_EXTENSIONS));
669         String JavaDoc parent = new File JavaDoc(base.getFile()).getParent().toString();
670         ArrayList extensionResults = new ArrayList(extensions.length);
671         for (int i = 0; i < extensions.length; i++) {
672             //Search the extension relatively to the osgi plugin
673
String JavaDoc path = searchFor(extensions[i], parent);
674             if (path == null) {
675                 log("Could not find extension: " + extensions[i]); //$NON-NLS-1$
676
continue;
677             }
678             if (debug)
679                 System.out.println("Loading extension: " + extensions[i]); //$NON-NLS-1$
680

681             URL extensionURL = null;
682             if (installLocation.getProtocol().equals("file")) { //$NON-NLS-1$
683
extensionResults.add(path);
684                 extensionURL = new File JavaDoc(path).toURL();
685             } else
686                 extensionURL = new URL(installLocation.getProtocol(), installLocation.getHost(), installLocation.getPort(), path);
687
688             //Load a property file of the extension, merge its content, and in case of dev mode add the bin entries
689
Properties extensionProperties = null;
690             try {
691                 extensionProperties = loadProperties(constructURL(extensionURL, ECLIPSE_PROPERTIES));
692             } catch (IOException e) {
693                 if (debug)
694                     System.out.println("\t" + ECLIPSE_PROPERTIES + " not found"); //$NON-NLS-1$ //$NON-NLS-2$
695
}
696             String JavaDoc extensionClassPath = null;
697             if (extensionProperties != null)
698                 extensionClassPath = extensionProperties.getProperty(PROP_CLASSPATH);
699             else // this is a "normal" RFC 101 framework extension bundle just put the base path on the classpath
700
extensionProperties = new Properties();
701             String JavaDoc[] entries = extensionClassPath == null || extensionClassPath.length() == 0 ? new String JavaDoc[] {""} : getArrayFromList(extensionClassPath); //$NON-NLS-1$
702
String JavaDoc qualifiedPath;
703             if (System.getProperty(PROP_CLASSPATH)==null)
704                 qualifiedPath = "."; //$NON-NLS-1$
705
else
706                 qualifiedPath = ""; //$NON-NLS-1$
707
for (int j = 0; j < entries.length; j++)
708                 qualifiedPath += ", " + FILE_SCHEME + path + entries[j]; //$NON-NLS-1$
709
extensionProperties.put(PROP_CLASSPATH, qualifiedPath);
710             mergeProperties(System.getProperties(), extensionProperties);
711             if (inDevelopmentMode)
712                 addDevEntries(extensionURL, result, extensions[i]);
713         }
714         extensionPaths = (String JavaDoc[]) extensionResults.toArray(new String JavaDoc[extensionResults.size()]);
715     }
716
717     private void addBaseJars(URL base, ArrayList result) throws IOException {
718         String JavaDoc baseJarList = System.getProperty(PROP_CLASSPATH);
719         if (baseJarList == null) {
720             readFrameworkExtensions(base, result);
721             baseJarList = System.getProperties().getProperty(PROP_CLASSPATH);
722         }
723         
724         File JavaDoc fwkFile = new File JavaDoc(base.getFile());
725         boolean fwkIsDirectory = fwkFile.isDirectory();
726         //We found where the fwk is, remember it and its shape
727
if (fwkIsDirectory) {
728             System.getProperties().put(PROP_FRAMEWORK_SHAPE, "folder");//$NON-NLS-1$
729
} else {
730             System.getProperties().put(PROP_FRAMEWORK_SHAPE, "jar");//$NON-NLS-1$
731
}
732         String JavaDoc fwkPath = new File JavaDoc(new File JavaDoc(base.getFile()).getParent()).getAbsolutePath();
733         if (Character.isUpperCase(fwkPath.charAt(0))) {
734             char[] chars = fwkPath.toCharArray();
735             chars[0] = Character.toLowerCase(chars[0]);
736             fwkPath = new String JavaDoc(chars);
737         }
738         System.getProperties().put(PROP_FRAMEWORK_SYSPATH, fwkPath);
739         
740         String JavaDoc[] baseJars = getArrayFromList(baseJarList);
741         if (baseJars.length == 0) {
742             if (!inDevelopmentMode && new File JavaDoc(base.getFile()).isDirectory())
743                 throw new IOException("Unable to initialize " + PROP_CLASSPATH); //$NON-NLS-1$
744
addEntry(base, result);
745             return;
746         }
747         for (int i = 0; i < baseJars.length; i++) {
748             String JavaDoc string = baseJars[i];
749             try {
750                 // if the string is a file: URL then *carefully* construct the
751
// URL. Otherwisejust try to build a URL. In either case, if we fail, use
752
// string as something to tack on the end of the base.
753

754                 if (string.equals(".")) { //$NON-NLS-1$
755
addEntry(base, result);
756                 }
757                 URL url = null;
758                 if (string.startsWith(FILE_SCHEME))
759                     url = new File JavaDoc(string.substring(5)).toURL();
760                 else
761                     url = new URL(string);
762                 addEntry(url, result);
763             } catch (MalformedURLException e) {
764                 addEntry(new URL(base, string), result);
765             }
766         }
767     }
768
769     protected void addEntry(URL url, List result) {
770         if (new File JavaDoc(url.getFile()).exists())
771             result.add(url);
772     }
773
774     private void addDevEntries(URL base, List result, String JavaDoc symbolicName) throws MalformedURLException {
775         if (devClassPathProps == null)
776             return; // do nothing
777
String JavaDoc devPathList = devClassPathProps.getProperty(symbolicName);
778         if (devPathList == null)
779             devPathList = devClassPathProps.getProperty("*"); //$NON-NLS-1$
780
String JavaDoc[] locations = getArrayFromList(devPathList);
781         for (int i = 0; i < locations.length; i++) {
782             String JavaDoc location = locations[i];
783             File JavaDoc path = new File JavaDoc(location);
784             URL url;
785             if (path.isAbsolute())
786                 url = path.toURL();
787             else {
788                 // dev path is relative, combine with base location
789
char lastChar = location.charAt(location.length() - 1);
790                 if ((location.endsWith(".jar") || (lastChar == '/' || lastChar == '\\'))) //$NON-NLS-1$
791
url = new URL(base, location);
792                 else
793                     url = new URL(base, location + "/"); //$NON-NLS-1$
794
}
795             addEntry(url, result);
796         }
797     }
798
799     /**
800      * Returns the <code>URL</code>-based class path describing where the boot classes are located.
801      *
802      * @return the url-based class path
803      * @param base the base location
804      * @exception MalformedURLException if a problem occurs computing the class path
805      */

806     protected URL[] getBootPath(String JavaDoc base) throws IOException {
807         URL url = null;
808         if (base != null) {
809             url = buildURL(base, true);
810         } else {
811             // search in the root location
812
url = getInstallLocation();
813             String JavaDoc path = new File JavaDoc(url.getFile(), "plugins").toString(); //$NON-NLS-1$
814
path = searchFor(framework, path);
815             if (path == null)
816                 throw new RuntimeException JavaDoc("Could not find framework"); //$NON-NLS-1$
817
if (url.getProtocol().equals("file")) //$NON-NLS-1$
818
url = new File JavaDoc(path).toURL();
819             else
820                 url = new URL(url.getProtocol(), url.getHost(), url.getPort(), path);
821         }
822         if (System.getProperty(PROP_FRAMEWORK) == null)
823             System.getProperties().put(PROP_FRAMEWORK, url.toExternalForm());
824         if (debug)
825             System.out.println("Framework located:\n " + url.toExternalForm()); //$NON-NLS-1$
826
// add on any dev path elements
827
URL[] result = getDevPath(url);
828         if (debug) {
829             System.out.println("Framework classpath:"); //$NON-NLS-1$
830
for (int i = 0; i < result.length; i++)
831                 System.out.println(" " + result[i].toExternalForm()); //$NON-NLS-1$
832
}
833         return result;
834     }
835
836     /**
837      * Searches for the given target directory starting in the "plugins" subdirectory
838      * of the given location. If one is found then this location is returned;
839      * otherwise an exception is thrown.
840      *
841      * @return the location where target directory was found
842      * @param start the location to begin searching
843      */

844     protected String JavaDoc searchFor(final String JavaDoc target, String JavaDoc start) {
845         return searchFor(target, null, start);
846     }
847     protected String JavaDoc searchFor(final String JavaDoc target, final String JavaDoc targetSuffix, String JavaDoc start) {
848         // Note that File.list only gives you file names not the complete path from start
849
String JavaDoc[] candidates = new File JavaDoc(start).list();
850         if (candidates == null)
851             return null;
852         
853         ArrayList matches = new ArrayList(2);
854         for (int i = 0; i < candidates.length; i++)
855             if (candidates[i].equals(target) || candidates[i].startsWith(target + "_")) //$NON-NLS-1$
856
matches.add(candidates[i]);
857         String JavaDoc[] names = (String JavaDoc[]) matches.toArray(new String JavaDoc[matches.size()]);
858         int result = findMax(names);
859         if (result == -1)
860             return null;
861         File JavaDoc candidate = new File JavaDoc(start, names[result]);
862         return candidate.getAbsolutePath().replace(File.separatorChar, '/') + (candidate.isDirectory() ? "/" : ""); //$NON-NLS-1$//$NON-NLS-2$
863
}
864
865     protected int findMax(String JavaDoc[] candidates) {
866         int result = -1;
867         Object JavaDoc maxVersion = null;
868         for (int i = 0; i < candidates.length; i++) {
869             String JavaDoc name = candidates[i];
870             String JavaDoc version = ""; //$NON-NLS-1$ // Note: directory with version suffix is always > than directory without version suffix
871
int index = name.indexOf('_');
872             if (index != -1)
873                 version = name.substring(index + 1);
874             Object JavaDoc currentVersion = getVersionElements(version);
875             if (maxVersion == null) {
876                 result = i;
877                 maxVersion = currentVersion;
878             } else {
879                 if (compareVersion((Object JavaDoc[]) maxVersion, (Object JavaDoc[]) currentVersion) < 0) {
880                     result = i;
881                     maxVersion = currentVersion;
882                 }
883             }
884         }
885         return result;
886     }
887     /**
888      * Compares version strings.
889      * @return result of comparison, as integer;
890      * <code><0</code> if left < right;
891      * <code>0</code> if left == right;
892      * <code>>0</code> if left > right;
893      */

894     private int compareVersion(Object JavaDoc[] left, Object JavaDoc[] right) {
895
896         int result = ((Integer JavaDoc) left[0]).compareTo((Integer JavaDoc) right[0]); // compare major
897
if (result != 0)
898             return result;
899
900         result = ((Integer JavaDoc) left[1]).compareTo((Integer JavaDoc) right[1]); // compare minor
901
if (result != 0)
902             return result;
903
904         result = ((Integer JavaDoc) left[2]).compareTo((Integer JavaDoc) right[2]); // compare service
905
if (result != 0)
906             return result;
907
908         return ((String JavaDoc) left[3]).compareTo((String JavaDoc) right[3]); // compare qualifier
909
}
910
911     /**
912      * Do a quick parse of version identifier so its elements can be correctly compared.
913      * If we are unable to parse the full version, remaining elements are initialized
914      * with suitable defaults.
915      * @return an array of size 4; first three elements are of type Integer (representing
916      * major, minor and service) and the fourth element is of type String (representing
917      * qualifier). Note, that returning anything else will cause exceptions in the caller.
918      */

919     private Object JavaDoc[] getVersionElements(String JavaDoc version) {
920         if (version.endsWith(".jar")) //$NON-NLS-1$
921
version = version.substring(0, version.length() - 4);
922         Object JavaDoc[] result = {new Integer JavaDoc(0), new Integer JavaDoc(0), new Integer JavaDoc(0), ""}; //$NON-NLS-1$
923
StringTokenizer t = new StringTokenizer(version, "."); //$NON-NLS-1$
924
String JavaDoc token;
925         int i = 0;
926         while (t.hasMoreTokens() && i < 4) {
927             token = t.nextToken();
928             if (i < 3) {
929                 // major, minor or service ... numeric values
930
try {
931                     result[i++] = new Integer JavaDoc(token);
932                 } catch (Exception JavaDoc e) {
933                     // invalid number format - use default numbers (0) for the rest
934
break;
935                 }
936             } else {
937                 // qualifier ... string value
938
result[i++] = token;
939             }
940         }
941         return result;
942     }
943
944     private static URL buildURL(String JavaDoc spec, boolean trailingSlash) {
945         if (spec == null)
946             return null;
947         boolean isFile = spec.startsWith(FILE_SCHEME);
948         try {
949             if (isFile) {
950                 File JavaDoc toAdjust = new File JavaDoc(spec.substring(5));
951                 if (toAdjust.isDirectory())
952                     return adjustTrailingSlash(toAdjust.toURL(), trailingSlash);
953                     return toAdjust.toURL();
954             }
955                 return new URL(spec);
956         } catch (MalformedURLException e) {
957             // if we failed and it is a file spec, there is nothing more we can do
958
// otherwise, try to make the spec into a file URL.
959
if (isFile)
960                 return null;
961             try {
962                 File JavaDoc toAdjust = new File JavaDoc(spec);
963                 if (toAdjust.isDirectory())
964                     return adjustTrailingSlash(toAdjust.toURL(), trailingSlash);
965                     return toAdjust.toURL();
966             } catch (MalformedURLException e1) {
967                 return null;
968             }
969         }
970     }
971
972     private static URL adjustTrailingSlash(URL url, boolean trailingSlash) throws MalformedURLException {
973         String JavaDoc file = url.getFile();
974         if (trailingSlash == (file.endsWith("/"))) //$NON-NLS-1$
975
return url;
976         file = trailingSlash ? file + "/" : file.substring(0, file.length() - 1); //$NON-NLS-1$
977
return new URL(url.getProtocol(), url.getHost(), file);
978     }
979
980     private URL buildLocation(String JavaDoc property, URL defaultLocation, String JavaDoc userDefaultAppendage) {
981         URL result = null;
982         String JavaDoc location = System.getProperty(property);
983         System.getProperties().remove(property);
984         // if the instance location is not set, predict where the workspace will be and
985
// put the instance area inside the workspace meta area.
986
try {
987             if (location == null)
988                 result = defaultLocation;
989             else if (location.equalsIgnoreCase(NONE))
990                 return null;
991             else if (location.equalsIgnoreCase(NO_DEFAULT))
992                 result = buildURL(location, true);
993             else {
994                 if (location.startsWith(USER_HOME)) {
995                     String JavaDoc base = substituteVar(location, USER_HOME, PROP_USER_HOME);
996                     location = new File JavaDoc(base, userDefaultAppendage).getAbsolutePath();
997                 } else if (location.startsWith(USER_DIR)) {
998                     String JavaDoc base = substituteVar(location, USER_DIR, PROP_USER_DIR);
999                     location = new File JavaDoc(base, userDefaultAppendage).getAbsolutePath();
1000                }
1001                result = buildURL(location, true);
1002            }
1003        } finally {
1004            if (result != null)
1005                System.getProperties().put(property, result.toExternalForm());
1006        }
1007        return result;
1008    }
1009
1010    private String JavaDoc substituteVar(String JavaDoc source, String JavaDoc var, String JavaDoc prop) {
1011        String JavaDoc value = System.getProperty(prop, ""); //$NON-NLS-1$
1012
return value + source.substring(var.length());
1013    }
1014
1015    /**
1016     * Retuns the default file system path for the configuration location.
1017     * By default the configuration information is in the installation directory
1018     * if this is writeable. Otherwise it is located somewhere in the user.home
1019     * area relative to the current product.
1020     * @return the default file system path for the configuration information
1021     */

1022    private String JavaDoc computeDefaultConfigurationLocation() {
1023        // 1) We store the config state relative to the 'eclipse' directory if possible
1024
// 2) If this directory is read-only
1025
// we store the state in <user.home>/.eclipse/<application-id>_<version> where <user.home>
1026
// is unique for each local user, and <application-id> is the one
1027
// defined in .eclipseproduct marker file. If .eclipseproduct does not
1028
// exist, use "eclipse" as the application-id.
1029

1030        URL install = getInstallLocation();
1031        // TODO a little dangerous here. Basically we have to assume that it is a file URL.
1032
if (install.getProtocol().equals("file")) { //$NON-NLS-1$
1033
File JavaDoc installDir = new File JavaDoc(install.getFile());
1034            if (canWrite(installDir))
1035                return installDir.getAbsolutePath() + File.separator + CONFIG_DIR;
1036        }
1037        // We can't write in the eclipse install dir so try for some place in the user's home dir
1038
return computeDefaultUserAreaLocation(CONFIG_DIR);
1039    }
1040
1041    private static boolean canWrite(File JavaDoc installDir) {
1042        if (installDir.canWrite() == false)
1043            return false;
1044
1045        if (!installDir.isDirectory())
1046            return false;
1047
1048        File JavaDoc fileTest = null;
1049        try {
1050            // we use the .dll suffix to properly test on Vista virtual directories
1051
// on Vista you are not allowed to write executable files on virtual directories like "Program Files"
1052
fileTest = File.createTempFile("writtableArea", ".dll", installDir); //$NON-NLS-1$ //$NON-NLS-2$
1053
} catch (IOException e) {
1054            //If an exception occured while trying to create the file, it means that it is not writtable
1055
return false;
1056        } finally {
1057            if (fileTest != null)
1058                fileTest.delete();
1059        }
1060        return true;
1061    }
1062    
1063    /**
1064     * Returns a files system path for an area in the user.home region related to the
1065     * current product. The given appendage is added to this base location
1066     * @param pathAppendage the path segments to add to computed base
1067     * @return a file system location in the user.home area related the the current
1068     * product and the given appendage
1069     */

1070    private String JavaDoc computeDefaultUserAreaLocation(String JavaDoc pathAppendage) {
1071        // we store the state in <user.home>/.eclipse/<application-id>_<version> where <user.home>
1072
// is unique for each local user, and <application-id> is the one
1073
// defined in .eclipseproduct marker file. If .eclipseproduct does not
1074
// exist, use "eclipse" as the application-id.
1075
URL installURL = getInstallLocation();
1076        if (installURL == null)
1077            return null;
1078        File JavaDoc installDir = new File JavaDoc(installURL.getFile());
1079        // compute an install dir hash to prevent configuration area collisions with other eclipse installs
1080
int hashCode;
1081        try {
1082            hashCode = installDir.getCanonicalPath().hashCode();
1083        } catch (IOException ioe) {
1084            // fall back to absolute path
1085
hashCode = installDir.getAbsolutePath().hashCode();
1086        }
1087        if (hashCode < 0)
1088            hashCode = -(hashCode);
1089        String JavaDoc installDirHash = String.valueOf(hashCode);
1090
1091        String JavaDoc appName = "." + ECLIPSE; //$NON-NLS-1$
1092
File JavaDoc eclipseProduct = new File JavaDoc(installDir, PRODUCT_SITE_MARKER);
1093        if (eclipseProduct.exists()) {
1094            Properties props = new Properties();
1095            try {
1096                props.load(new FileInputStream(eclipseProduct));
1097                String JavaDoc appId = props.getProperty(PRODUCT_SITE_ID);
1098                if (appId == null || appId.trim().length() == 0)
1099                    appId = ECLIPSE;
1100                String JavaDoc appVersion = props.getProperty(PRODUCT_SITE_VERSION);
1101                if (appVersion == null || appVersion.trim().length() == 0)
1102                    appVersion = ""; //$NON-NLS-1$
1103
appName += File.separator + appId + "_" + appVersion + "_" + installDirHash; //$NON-NLS-1$ //$NON-NLS-2$
1104
} catch (IOException e) {
1105                // Do nothing if we get an exception. We will default to a standard location
1106
// in the user's home dir.
1107
// add the hash to help prevent collisions
1108
appName += File.separator + installDirHash;
1109            }
1110        } else {
1111            // add the hash to help prevent collisions
1112
appName += File.separator + installDirHash;
1113        }
1114        String JavaDoc userHome = System.getProperty(PROP_USER_HOME);
1115        return new File JavaDoc(userHome, appName + "/" + pathAppendage).getAbsolutePath(); //$NON-NLS-1$
1116
}
1117
1118    /**
1119     * Runs this launcher with the arguments specified in the given string.
1120     *
1121     * @param argString the arguments string
1122     */

1123    public static void main(String JavaDoc argString) {
1124        Vector list = new Vector(5);
1125        for (StringTokenizer tokens = new StringTokenizer(argString, " "); tokens.hasMoreElements();) //$NON-NLS-1$
1126
list.addElement(tokens.nextElement());
1127        main((String JavaDoc[]) list.toArray(new String JavaDoc[list.size()]));
1128    }
1129
1130    /**
1131     * Runs the platform with the given arguments. The arguments must identify
1132     * an application to run (e.g., <code>-application com.example.application</code>).
1133     * After running the application <code>System.exit(N)</code> is executed.
1134     * The value of N is derived from the value returned from running the application.
1135     * If the application's return value is an <code>Integer</code>, N is this value.
1136     * In all other cases, N = 0.
1137     * <p>
1138     * Clients wishing to run the platform without a following <code>System.exit</code>
1139     * call should use <code>run()</code>.
1140     * </p>
1141     *
1142     * @param args the command line arguments
1143     * @see #run(String[])
1144     */

1145    public static void main(String JavaDoc[] args) {
1146        int result = 0;
1147        try {
1148            result = new Main().run(args);
1149        } catch (Throwable JavaDoc t) {
1150            // This is *really* unlikely to happen - run() takes care of exceptional situations.
1151
// In case something weird happens, just dump stack - logging is not available at this point
1152
t.printStackTrace();
1153        } finally {
1154            if (!Boolean.getBoolean(PROP_NOSHUTDOWN))
1155            // make sure we always terminate the VM
1156
System.exit(result);
1157        }
1158    }
1159
1160
1161    /**
1162     * Runs the platform with the given arguments. The arguments must identify
1163     * an application to run (e.g., <code>-application com.example.application</code>).
1164     * Returns the value returned from running the application.
1165     * If the application's return value is an <code>Integer</code>, N is this value.
1166     * In all other cases, N = 0.
1167     *
1168     * @param args the command line arguments
1169     */

1170    public int run(String JavaDoc[] args) {
1171        int result = 0;
1172        try {
1173            basicRun(args);
1174            String JavaDoc exitCode = System.getProperty(PROP_EXITCODE);
1175            try {
1176                result = exitCode == null ? 0 : Integer.parseInt(exitCode);
1177            } catch (NumberFormatException JavaDoc e) {
1178                result = 17;
1179            }
1180        } catch (Throwable JavaDoc e) {
1181            // only log the exceptions if they have not been caught by the
1182
// EclipseStarter (i.e., if the exitCode is not 13)
1183
if (!"13".equals(System.getProperty(PROP_EXITCODE))) { //$NON-NLS-1$
1184
log("Exception launching the Eclipse Platform:"); //$NON-NLS-1$
1185
log(e);
1186                String JavaDoc message = "An error has occurred"; //$NON-NLS-1$
1187
if (logFile == null)
1188                    message += " and could not be logged: \n" + e.getMessage(); //$NON-NLS-1$
1189
else
1190                    message += ". See the log file\n" + logFile.getAbsolutePath(); //$NON-NLS-1$
1191
System.getProperties().put(PROP_EXITDATA, message);
1192            }
1193            // Return "unlucky" 13 as the exit code. The executable will recognize
1194
// this constant and display a message to the user telling them that
1195
// there is information in their log file.
1196
result = 13;
1197        } finally {
1198            // always try putting down the splash screen just in case the application failed to do so
1199
takeDownSplash();
1200            if(bridge != null)
1201                bridge.uninitialize();
1202        }
1203        // Return an int exit code and ensure the system property is set.
1204
System.getProperties().put(PROP_EXITCODE, Integer.toString(result));
1205        setExitData();
1206        return result;
1207    }
1208
1209    private void setExitData() {
1210        String JavaDoc data = System.getProperty(PROP_EXITDATA);
1211        if (data == null || bridge == null)
1212            return;
1213        bridge.setExitData(exitData, data);
1214    }
1215    
1216    /**
1217     * Processes the command line arguments. The general principle is to NOT
1218     * consume the arguments and leave them to be processed by Eclipse proper.
1219     * There are a few args which are directed towards main() and a few others
1220     * which we need to know about. Very few should actually be consumed here.
1221     *
1222     * @return the arguments to pass through to the launched application
1223     * @param args the command line arguments
1224     */

1225    protected String JavaDoc[] processCommandLine(String JavaDoc[] args) {
1226        if (args.length == 0)
1227            return args;
1228        int[] configArgs = new int[args.length];
1229        configArgs[0] = -1; // need to initialize the first element to something that could not be an index.
1230
int configArgIndex = 0;
1231        for (int i = 0; i < args.length; i++) {
1232            boolean found = false;
1233            // check for args without parameters (i.e., a flag arg)
1234
// check if debug should be enabled for the entire platform
1235
if (args[i].equalsIgnoreCase(DEBUG)) {
1236                debug = true;
1237                // passed thru this arg (i.e., do not set found = true)
1238
continue;
1239            }
1240
1241            // look for and consume the nosplash directive. This supercedes any
1242
// -showsplash command that might be present.
1243
if (args[i].equalsIgnoreCase(NOSPLASH)) {
1244                splashDown = true;
1245                found = true;
1246            }
1247
1248            if (args[i].equalsIgnoreCase(NOEXIT)) {
1249                System.getProperties().put(PROP_NOSHUTDOWN, "true"); //$NON-NLS-1$
1250
found = true;
1251            }
1252            
1253            // check if this is initialization pass
1254
if (args[i].equalsIgnoreCase(INITIALIZE)) {
1255                initialize = true;
1256                // passed thru this arg (i.e., do not set found = true)
1257
continue;
1258            }
1259
1260            // check if development mode should be enabled for the entire platform
1261
// If this is the last arg or there is a following arg (i.e., arg+1 has a leading -),
1262
// simply enable development mode. Otherwise, assume that that the following arg is
1263
// actually some additional development time class path entries. This will be processed below.
1264
if (args[i].equalsIgnoreCase(DEV) && ((i + 1 == args.length) || ((i + 1 < args.length) && (args[i + 1].startsWith("-"))))) { //$NON-NLS-1$
1265
inDevelopmentMode = true;
1266                // do not mark the arg as found so it will be passed through
1267
continue;
1268            }
1269
1270            // look for the command to use to show the splash screen
1271
if (args[i].equalsIgnoreCase(SHOWSPLASH)) {
1272                showSplash = true;
1273                found = true;
1274                //consume optional parameter for showsplash
1275
if (i + 1 < args.length && !args[i+1].startsWith("-")) { //$NON-NLS-1$
1276
configArgs[configArgIndex++] = i++;
1277                    splashLocation = args[i];
1278                }
1279            }
1280            
1281            // done checking for args. Remember where an arg was found
1282
if (found) {
1283                configArgs[configArgIndex++] = i;
1284                continue;
1285            }
1286
1287            // look for the VM args arg. We have to do that before looking to see
1288
// if the next element is a -arg as the thing following -vmargs may in
1289
// fact be another -arg.
1290
if (args[i].equalsIgnoreCase(VMARGS)) {
1291                // consume the -vmargs arg itself
1292
args[i] = null;
1293                i++;
1294                vmargs = new String JavaDoc[args.length - i];
1295                for (int j = 0; i < args.length; i++) {
1296                    vmargs[j++] = args[i];
1297                    args[i] = null;
1298                }
1299                continue;
1300            }
1301
1302            // check for args with parameters. If we are at the last argument or if the next one
1303
// has a '-' as the first character, then we can't have an arg with a parm so continue.
1304
if (i == args.length - 1 || args[i + 1].startsWith("-")) //$NON-NLS-1$
1305
continue;
1306            String JavaDoc arg = args[++i];
1307
1308            // look for the development mode and class path entries.
1309
if (args[i - 1].equalsIgnoreCase(DEV)) {
1310                inDevelopmentMode = true;
1311                devClassPathProps = processDevArg(arg);
1312                if (devClassPathProps != null) {
1313                    devClassPath = devClassPathProps.getProperty(OSGI);
1314                    if (devClassPath == null)
1315                        devClassPath = devClassPathProps.getProperty("*"); //$NON-NLS-1$
1316
}
1317                continue;
1318            }
1319
1320            // look for the framework to run
1321
if (args[i - 1].equalsIgnoreCase(FRAMEWORK)) {
1322                framework = arg;
1323                found = true;
1324            }
1325
1326            if (args[i - 1].equalsIgnoreCase(OS)) {
1327                os = arg;
1328                // passed thru this arg
1329
continue;
1330            }
1331            
1332            if (args[i - 1].equalsIgnoreCase(WS)) {
1333                ws = arg;
1334                continue;
1335            }
1336            
1337            if (args[i - 1].equalsIgnoreCase(ARCH)) {
1338                arch = arg;
1339                continue;
1340            }
1341            
1342            // look for explicitly set install root
1343
// Consume the arg here to ensure that the launcher and Eclipse get the
1344
// same value as each other.
1345
if (args[i - 1].equalsIgnoreCase(INSTALL)) {
1346                System.getProperties().put(PROP_INSTALL_AREA, arg);
1347                found = true;
1348            }
1349
1350            // look for the configuration to use.
1351
// Consume the arg here to ensure that the launcher and Eclipse get the
1352
// same value as each other.
1353
if (args[i - 1].equalsIgnoreCase(CONFIGURATION)) {
1354                System.getProperties().put(PROP_CONFIG_AREA, arg);
1355                found = true;
1356            }
1357
1358            if (args[i - 1].equalsIgnoreCase(EXITDATA)) {
1359                exitData = arg;
1360                found = true;
1361            }
1362            
1363            // look for the name to use by the launcher
1364
if (args[i - 1].equalsIgnoreCase(NAME)) {
1365                //not doing anything with this right now, but still consume it
1366
//name = arg;
1367
found = true;
1368            }
1369
1370            // look for the startup jar used
1371
if (args[i - 1].equalsIgnoreCase(STARTUP)) {
1372                //not doing anything with this right now, but still consume it
1373
//startup = arg;
1374
found = true;
1375            }
1376            
1377            // look for the launcher location
1378
if (args[i - 1].equalsIgnoreCase(LAUNCHER)) {
1379                //not doing anything with this right now, but still consume it
1380
//launcher = arg;
1381
found = true;
1382            }
1383            
1384            if (args[i - 1].equalsIgnoreCase(LIBRARY)) {
1385                library = arg;
1386                found = true;
1387            }
1388            
1389            // look for the command to use to end the splash screen
1390
if (args[i - 1].equalsIgnoreCase(ENDSPLASH)) {
1391                endSplash = arg;
1392                found = true;
1393            }
1394
1395            // look for the VM location arg
1396
if (args[i - 1].equalsIgnoreCase(VM)) {
1397                vm = arg;
1398                found = true;
1399            }
1400
1401            //look for the nl setting
1402
if (args[i - 1].equalsIgnoreCase(NL)) {
1403                System.getProperties().put(PROP_NL, arg);
1404                found = true;
1405            }
1406            
1407            // done checking for args. Remember where an arg was found
1408
if (found) {
1409                configArgs[configArgIndex++] = i - 1;
1410                configArgs[configArgIndex++] = i;
1411            }
1412        }
1413        // remove all the arguments consumed by this argument parsing
1414
String JavaDoc[] passThruArgs = new String JavaDoc[args.length - configArgIndex - (vmargs == null ? 0 : vmargs.length + 1)];
1415        configArgIndex = 0;
1416        int j = 0;
1417        for (int i = 0; i < args.length; i++) {
1418            if (i == configArgs[configArgIndex])
1419                configArgIndex++;
1420            else if (args[i] != null)
1421                passThruArgs[j++] = args[i];
1422        }
1423        return passThruArgs;
1424    }
1425
1426    private Properties processDevArg(String JavaDoc arg) {
1427        if (arg == null)
1428            return null;
1429        try {
1430            URL location = new URL(arg);
1431            return load(location, null);
1432        } catch (MalformedURLException e) {
1433            // the arg was not a URL so use it as is.
1434
Properties result = new Properties();
1435            result.put("*", arg); //$NON-NLS-1$
1436
return result;
1437        } catch (IOException e) {
1438            // TODO consider logging here
1439
return null;
1440        }
1441    }
1442
1443    private URL getConfigurationLocation() {
1444        if (configurationLocation != null)
1445            return configurationLocation;
1446        configurationLocation = buildLocation(PROP_CONFIG_AREA, null, ""); //$NON-NLS-1$
1447
if (configurationLocation == null) {
1448            configurationLocation = buildLocation(PROP_CONFIG_AREA_DEFAULT, null, ""); //$NON-NLS-1$
1449
if (configurationLocation == null)
1450                configurationLocation = buildURL(computeDefaultConfigurationLocation(), true);
1451        }
1452        if (configurationLocation != null)
1453            System.getProperties().put(PROP_CONFIG_AREA, configurationLocation.toExternalForm());
1454        if (debug)
1455            System.out.println("Configuration location:\n " + configurationLocation); //$NON-NLS-1$
1456
return configurationLocation;
1457    }
1458
1459    private void processConfiguration() {
1460        // if the configuration area is not already defined, discover the config area by
1461
// trying to find a base config area. This is either defined in a system property or
1462
// is computed relative to the install location.
1463
// Note that the config info read here is only used to determine a value
1464
// for the user configuration area
1465
URL baseConfigurationLocation = null;
1466        Properties baseConfiguration = null;
1467        if (System.getProperty(PROP_CONFIG_AREA) == null) {
1468            String JavaDoc baseLocation = System.getProperty(PROP_BASE_CONFIG_AREA);
1469            if (baseLocation != null)
1470                // here the base config cannot have any symbolic (e..g, @xxx) entries. It must just
1471
// point to the config file.
1472
baseConfigurationLocation = buildURL(baseLocation, true);
1473            if (baseConfigurationLocation == null)
1474                try {
1475                    // here we access the install location but this is very early. This case will only happen if
1476
// the config area is not set and the base config area is not set (or is bogus).
1477
// In this case we compute based on the install location.
1478
baseConfigurationLocation = new URL(getInstallLocation(), CONFIG_DIR);
1479                } catch (MalformedURLException e) {
1480                    // leave baseConfigurationLocation null
1481
}
1482            baseConfiguration = loadConfiguration(baseConfigurationLocation);
1483            if (baseConfiguration != null) {
1484                // if the base sets the install area then use that value if the property. We know the
1485
// property is not already set.
1486
String JavaDoc location = baseConfiguration.getProperty(PROP_CONFIG_AREA);
1487                if (location != null)
1488                    System.getProperties().put(PROP_CONFIG_AREA, location);
1489                // if the base sets the install area then use that value if the property is not already set.
1490
// This helps in selfhosting cases where you cannot easily compute the install location
1491
// from the code base.
1492
location = baseConfiguration.getProperty(PROP_INSTALL_AREA);
1493                if (location != null && System.getProperty(PROP_INSTALL_AREA) == null)
1494                    System.getProperties().put(PROP_INSTALL_AREA, location);
1495            }
1496        }
1497
1498        // Now we know where the base configuration is supposed to be. Go ahead and load
1499
// it and merge into the System properties. Then, if cascaded, read the parent configuration
1500
// Note that the parent may or may not be the same parent as we read above since the
1501
// base can define its parent. The first parent we read was either defined by the user
1502
// on the command line or was the one in the install dir.
1503
// if the config or parent we are about to read is the same as the base config we read above,
1504
// just reuse the base
1505
Properties configuration = baseConfiguration;
1506        if (configuration == null || !getConfigurationLocation().equals(baseConfigurationLocation))
1507            configuration = loadConfiguration(getConfigurationLocation());
1508        mergeProperties(System.getProperties(), configuration);
1509        if ("false".equalsIgnoreCase(System.getProperty(PROP_CONFIG_CASCADED))) //$NON-NLS-1$
1510
// if we are not cascaded then remove the parent property even if it was set.
1511
System.getProperties().remove(PROP_SHARED_CONFIG_AREA);
1512        else {
1513            ensureAbsolute(PROP_SHARED_CONFIG_AREA);
1514            URL sharedConfigURL = buildLocation(PROP_SHARED_CONFIG_AREA, null, ""); //$NON-NLS-1$
1515
if (sharedConfigURL == null)
1516                try {
1517                    // there is no shared config value so compute one
1518
sharedConfigURL = new URL(getInstallLocation(), CONFIG_DIR);
1519                } catch (MalformedURLException e) {
1520                    // leave sharedConfigurationLocation null
1521
}
1522            // if the parent location is different from the config location, read it too.
1523
if (sharedConfigURL != null) {
1524                if (sharedConfigURL.equals(getConfigurationLocation()))
1525                    // remove the property to show that we do not have a parent.
1526
System.getProperties().remove(PROP_SHARED_CONFIG_AREA);
1527                else {
1528                    // if the parent we are about to read is the same as the base config we read above,
1529
// just reuse the base
1530
configuration = baseConfiguration;
1531                    if (!sharedConfigURL.equals(baseConfigurationLocation))
1532                        configuration = loadConfiguration(sharedConfigURL);
1533                    mergeProperties(System.getProperties(), configuration);
1534                    System.getProperties().put(PROP_SHARED_CONFIG_AREA, sharedConfigURL.toExternalForm());
1535                    if (debug)
1536                        System.out.println("Shared configuration location:\n " + sharedConfigURL.toExternalForm()); //$NON-NLS-1$
1537
}
1538            }
1539        }
1540        // setup the path to the framework
1541
String JavaDoc urlString = System.getProperty(PROP_FRAMEWORK, null);
1542        if (urlString != null) {
1543            URL url = buildURL(urlString, true);
1544            System.getProperties().put(PROP_FRAMEWORK, url.toExternalForm());
1545            bootLocation = resolve(urlString);
1546        }
1547    }
1548
1549    /**
1550     * Ensures the value for a system property is an absolute URL. Relative URLs are translated to
1551     * absolute URLs by taking the install URL as reference.
1552     *
1553     * @param locationProperty the key for a system property containing a URL
1554     */

1555    private void ensureAbsolute(String JavaDoc locationProperty) {
1556        String JavaDoc propertyValue = System.getProperty(locationProperty);
1557        if (propertyValue == null)
1558            // property not defined
1559
return;
1560        URL locationURL = null;
1561        try {
1562            locationURL = new URL(propertyValue);
1563        } catch (MalformedURLException e) {
1564            // property is not a valid URL
1565
return;
1566        }
1567        String JavaDoc locationPath = locationURL.getPath();
1568        if (locationPath.startsWith("/")) //$NON-NLS-1$
1569
// property value is absolute
1570
return;
1571        URL installURL = getInstallLocation();
1572        if (!locationURL.getProtocol().equals(installURL.getProtocol()))
1573            // not same protocol
1574
return;
1575        try {
1576            URL absoluteURL = new URL(installURL, locationPath);
1577            System.getProperties().put(locationProperty, absoluteURL.toExternalForm());
1578        } catch (MalformedURLException e) {
1579            // should not happen - the relative URL is known to be valid
1580
}
1581    }
1582
1583    /**
1584     * Returns url of the location this class was loaded from
1585     */

1586    private URL getInstallLocation() {
1587        if (installLocation != null)
1588            return installLocation;
1589
1590        // value is not set so compute the default and set the value
1591
String JavaDoc installArea = System.getProperty(PROP_INSTALL_AREA);
1592        if (installArea != null) {
1593            installLocation = buildURL(installArea, true);
1594            if (installLocation == null)
1595                throw new IllegalStateException JavaDoc("Install location is invalid: " + installArea); //$NON-NLS-1$
1596
System.getProperties().put(PROP_INSTALL_AREA, installLocation.toExternalForm());
1597            if (debug)
1598                System.out.println("Install location:\n " + installLocation); //$NON-NLS-1$
1599
return installLocation;
1600        }
1601
1602        ProtectionDomain domain = Main.class.getProtectionDomain();
1603        CodeSource source = null;
1604        URL result = null;
1605        if (domain != null)
1606            source = domain.getCodeSource();
1607        if (source == null || domain == null) {
1608            if (debug)
1609                System.out.println("CodeSource location is null. Defaulting the install location to file:startup.jar"); //$NON-NLS-1$
1610
try {
1611                result = new URL("file:startup.jar"); //$NON-NLS-1$
1612
} catch (MalformedURLException e2) {
1613                //Ignore
1614
}
1615        }
1616        if (source != null)
1617            result = source.getLocation();
1618        
1619        String JavaDoc path = decode(result.getFile());
1620        // normalize to not have leading / so we can check the form
1621
File JavaDoc file = new File JavaDoc(path);
1622        path = file.toString().replace('\\', '/');
1623        // TODO need a better test for windows
1624
// If on Windows then canonicalize the drive letter to be lowercase.
1625
// remember that there may be UNC paths
1626
if (File.separatorChar == '\\')
1627            if (Character.isUpperCase(path.charAt(0))) {
1628                char[] chars = path.toCharArray();
1629                chars[0] = Character.toLowerCase(chars[0]);
1630                path = new String JavaDoc(chars);
1631            }
1632        if (path.toLowerCase().endsWith(".jar")) //$NON-NLS-1$
1633
path = path.substring(0, path.lastIndexOf("/") + 1); //$NON-NLS-1$
1634
if (path.toLowerCase().endsWith("/plugins/")) //$NON-NLS-1$
1635
path = path.substring(0, path.length() - "/plugins/".length()); //$NON-NLS-1$
1636
try {
1637            try {
1638                // create a file URL (via File) to normalize the form (e.g., put
1639
// the leading / on if necessary)
1640
path = new File JavaDoc(path).toURL().getFile();
1641            } catch (MalformedURLException e1) {
1642                // will never happen. The path is straight from a URL.
1643
}
1644            installLocation = new URL(result.getProtocol(), result.getHost(), result.getPort(), path);
1645            System.getProperties().put(PROP_INSTALL_AREA, installLocation.toExternalForm());
1646        } catch (MalformedURLException e) {
1647            // TODO Very unlikely case. log here.
1648
}
1649        if (debug)
1650            System.out.println("Install location:\n " + installLocation); //$NON-NLS-1$
1651
return installLocation;
1652    }
1653
1654    /*
1655     * Load the given configuration file
1656     */

1657    private Properties loadConfiguration(URL url) {
1658        Properties result = null;
1659        try {
1660            url = new URL(url, CONFIG_FILE);
1661        } catch (MalformedURLException e) {
1662            return null;
1663        }
1664        try {
1665            if (debug)
1666                System.out.print("Configuration file:\n " + url.toString()); //$NON-NLS-1$
1667
result = loadProperties(url);
1668            if (debug)
1669                System.out.println(" loaded"); //$NON-NLS-1$
1670
} catch (IOException e) {
1671            if (debug)
1672                System.out.println(" not found or not read"); //$NON-NLS-1$
1673
}
1674        return result;
1675    }
1676
1677    private Properties loadProperties(URL url) throws IOException {
1678        // try to load saved configuration file (watch for failed prior save())
1679
if (url == null)
1680            return null;
1681        Properties result = null;
1682        IOException originalException = null;
1683        try {
1684            result = load(url, null); // try to load config file
1685
} catch (IOException e1) {
1686            originalException = e1;
1687            try {
1688                result = load(url, CONFIG_FILE_TEMP_SUFFIX); // check for failures on save
1689
} catch (IOException e2) {
1690                try {
1691                    result = load(url, CONFIG_FILE_BAK_SUFFIX); // check for failures on save
1692
} catch (IOException e3) {
1693                    throw originalException; // we tried, but no config here ...
1694
}
1695            }
1696        }
1697        return result;
1698    }
1699
1700    /*
1701     * Load the configuration
1702     */

1703    private Properties load(URL url, String JavaDoc suffix) throws IOException {
1704        // figure out what we will be loading
1705
if (suffix != null && !suffix.equals("")) //$NON-NLS-1$
1706
url = new URL(url.getProtocol(), url.getHost(), url.getPort(), url.getFile() + suffix);
1707
1708        // try to load saved configuration file
1709
Properties props = new Properties();
1710        InputStream is = null;
1711        try {
1712            is = url.openStream();
1713            props.load(is);
1714        } finally {
1715            if (is != null)
1716                try {
1717                    is.close();
1718                } catch (IOException e) {
1719                    //ignore failure to close
1720
}
1721        }
1722        return props;
1723    }
1724
1725    /*
1726     * Handle splash screen.
1727     * We support 2 startup scenarios:
1728     *
1729     * (1) the executable launcher put up the splash screen. In that
1730     * scenario we are invoked with -endsplash command which is
1731     * fully formed to take down the splash screen
1732     *
1733     * (2) the executable launcher did not put up the splash screen,
1734     * but invokes Eclipse with partially formed -showsplash command.
1735     * In this scenario we determine which splash to display (based on
1736     * feature information) and then call -showsplash command.
1737     *
1738     * In both scenarios we pass a handler (Runnable) to the platform.
1739     * The handler is called as a result of the launched application calling
1740     * Platform.endSplash(). In the first scenario this results in the
1741     * -endsplash command being executed. In the second scenario this
1742     * results in the process created as a result of the -showsplash command
1743     * being destroyed.
1744     *
1745     * @param defaultPath search path for the boot plugin
1746     */

1747    private void handleSplash(URL[] defaultPath) {
1748        // run without splash if we are initializing or nosplash
1749
// was specified (splashdown = true)
1750
if (initialize || splashDown || bridge == null) {
1751            showSplash = false;
1752            endSplash = null;
1753            return;
1754        }
1755        
1756        if (showSplash || endSplash != null) {
1757            // Register the endSplashHandler to be run at VM shutdown. This hook will be
1758
// removed once the splash screen has been taken down.
1759
try {
1760                Runtime.getRuntime().addShutdownHook(splashHandler);
1761            } catch(Throwable JavaDoc ex) {
1762                // Best effort to register the handler
1763
}
1764        }
1765
1766        // if -endsplash is specified, use it and ignore any -showsplash command
1767
if (endSplash != null) {
1768            showSplash = false;
1769            return;
1770        }
1771
1772        // check if we are running without a splash screen
1773
if (!showSplash)
1774            return;
1775
1776        // determine the splash location
1777
splashLocation = getSplashLocation(defaultPath);
1778        if (debug)
1779            System.out.println("Splash location:\n " + splashLocation); //$NON-NLS-1$
1780
if (splashLocation == null)
1781            return;
1782        
1783        bridge.showSplash(splashLocation);
1784        long handle = bridge.getSplashHandle();
1785        if(handle != 0 && handle != -1) {
1786            System.getProperties().put(SPLASH_HANDLE, String.valueOf(handle));
1787            System.getProperties().put(SPLASH_LOCATION, splashLocation);
1788            bridge.updateSplash();
1789        }
1790    }
1791
1792    /*
1793     * Take down the splash screen.
1794     */

1795    protected void takeDownSplash() {
1796        if (splashDown || bridge == null) // splash is already down
1797
return;
1798
1799        splashDown = bridge.takeDownSplash();
1800        System.getProperties().remove(SPLASH_HANDLE);
1801        
1802        try {
1803            Runtime.getRuntime().removeShutdownHook(splashHandler);
1804        } catch (Throwable JavaDoc e) {
1805            // OK to ignore this, happens when the VM is already shutting down
1806
}
1807    }
1808
1809    /*
1810     * Return path of the splash image to use. First search the defined splash path.
1811     * If that does not work, look for a default splash. Currently the splash must be in the file system
1812     * so the return value here is the file system path.
1813     */

1814    private String JavaDoc getSplashLocation(URL[] bootPath) {
1815        //check the path passed in from -showsplash first. The old launcher passed a timeout value
1816
//as the argument, so only use it if it isn't a number and the file exists.
1817
if(splashLocation != null && !Character.isDigit(splashLocation.charAt(0)) && new File JavaDoc(splashLocation).exists()) {
1818            System.getProperties().put(PROP_SPLASHLOCATION, splashLocation);
1819            return splashLocation;
1820        }
1821        String JavaDoc result = System.getProperty(PROP_SPLASHLOCATION);
1822        if (result != null)
1823            return result;
1824        String JavaDoc splashPath = System.getProperty(PROP_SPLASHPATH);
1825        if (splashPath != null) {
1826            String JavaDoc[] entries = getArrayFromList(splashPath);
1827            ArrayList path = new ArrayList(entries.length);
1828            for (int i = 0; i < entries.length; i++) {
1829                String JavaDoc entry = resolve(entries[i]);
1830                if (entry == null || entry.startsWith(FILE_SCHEME)) {
1831                    File JavaDoc entryFile = new File JavaDoc(entry.substring(5).replace('/', File.separatorChar));
1832                    entry = searchFor(entryFile.getName(), entryFile.getParent());
1833                    if (entry != null)
1834                        path.add(entry);
1835                } else
1836                    log("Invalid splash path entry: " + entries[i]); //$NON-NLS-1$
1837
}
1838            // see if we can get a splash given the splash path
1839
result = searchForSplash((String JavaDoc[]) path.toArray(new String JavaDoc[path.size()]));
1840            if (result != null) {
1841                System.getProperties().put(PROP_SPLASHLOCATION, result);
1842                return result;
1843            }
1844        }
1845
1846        // can't find it on the splashPath so look for a default splash
1847
String JavaDoc temp = bootPath[0].getFile(); // take the first path element
1848
temp = temp.replace('/', File.separatorChar);
1849        int ix = temp.lastIndexOf("plugins" + File.separator); //$NON-NLS-1$
1850
if (ix != -1) {
1851            int pix = temp.indexOf(File.separator, ix + 8);
1852            if (pix != -1) {
1853                temp = temp.substring(0, pix);
1854                result = searchForSplash(new String JavaDoc[] {temp});
1855                if (result != null)
1856                    System.getProperties().put(PROP_SPLASHLOCATION, result);
1857            }
1858        }
1859        return result;
1860    }
1861
1862    /*
1863     * Do a locale-sensitive lookup of splash image
1864     */

1865    private String JavaDoc searchForSplash(String JavaDoc[] searchPath) {
1866        if (searchPath == null)
1867            return null;
1868
1869        // Get the splash screen for the specified locale
1870
String JavaDoc locale = (String JavaDoc) System.getProperties().get(PROP_NL);
1871        if (locale == null)
1872            locale = Locale.getDefault().toString();
1873        String JavaDoc[] nlVariants = buildNLVariants(locale);
1874
1875        for (int i=0; i<nlVariants.length; i++) {
1876            for (int j=0; j<searchPath.length; j++) {
1877                // do we have a JAR?
1878
if (isJAR(searchPath[j])) {
1879                    String JavaDoc result = extractSplashFromJAR(searchPath[j], nlVariants[i]);
1880                    if (result != null)
1881                        return result;
1882                } else {
1883                    // we have a file or a directory
1884
String JavaDoc path = searchPath[j];
1885                    if (!path.endsWith(File.separator))
1886                        path += File.separator;
1887                    path += nlVariants[i];
1888                    File JavaDoc result = new File JavaDoc(path);
1889                    if (result.exists())
1890                        return result.getAbsolutePath(); // return the first match found [20063]
1891
}
1892            }
1893        }
1894
1895        // sorry, could not find splash image
1896
return null;
1897    }
1898
1899    /**
1900     * Transfers all available bytes from the given input stream to the given output stream.
1901     * Regardless of failure, this method closes both streams.
1902     */

1903    private static void transferStreams(InputStream source, OutputStream destination) {
1904        byte[] buffer = new byte[8096];
1905        try {
1906            while (true) {
1907                int bytesRead = -1;
1908                try {
1909                    bytesRead = source.read(buffer);
1910                } catch (IOException e) {
1911                    return;
1912                }
1913                if (bytesRead == -1)
1914                    break;
1915                try {
1916                    destination.write(buffer, 0, bytesRead);
1917                } catch (IOException e) {
1918                    return;
1919                }
1920            }
1921        } finally {
1922            try {
1923                source.close();
1924            } catch (IOException e) {
1925                // ignore
1926
} finally {
1927                //close destination in finally in case source.close fails
1928
try {
1929                    destination.close();
1930                } catch (IOException e) {
1931                    // ignore
1932
}
1933            }
1934        }
1935    }
1936
1937    /*
1938     * Look for the specified spash file in the given JAR and extract it to the config
1939     * area for caching purposes.
1940     */

1941    private String JavaDoc extractSplashFromJAR(String JavaDoc jarPath, String JavaDoc splashPath) {
1942        String JavaDoc configLocation = System.getProperty(PROP_CONFIG_AREA);
1943        if (configLocation == null) {
1944            log("Configuration area not set yet. Unable to extract splash from JAR'd plug-in: " + jarPath); //$NON-NLS-1$
1945
return null;
1946        }
1947        URL configURL = buildURL(configLocation, false);
1948        if (configURL == null)
1949            return null;
1950        // cache the splash in the equinox launcher sub-dir in the config area
1951
File JavaDoc splash = new File JavaDoc(configURL.getPath(), PLUGIN_ID);
1952        //include the name of the jar in the cache location
1953
File JavaDoc jarFile = new File JavaDoc(jarPath);
1954        String JavaDoc cache = jarFile.getName();
1955        if(cache.endsWith(".jar")) //$NON-NLS-1$
1956
cache = cache.substring(0, cache.length() - 4);
1957        splash = new File JavaDoc(splash, cache);
1958        splash = new File JavaDoc(splash, splashPath);
1959        // if we have already extracted this file before, then return
1960
if (splash.exists()) {
1961            // if we are running with -clean then delete the cached splash file
1962
boolean clean = false;
1963            for (int i=0; i<commands.length; i++) {
1964                if (CLEAN.equalsIgnoreCase(commands[i])) {
1965                    clean = true;
1966                    splash.delete();
1967                    break;
1968                }
1969            }
1970            if (!clean)
1971                return splash.getAbsolutePath();
1972        }
1973        ZipFile JavaDoc file;
1974        try {
1975            file = new ZipFile JavaDoc(jarPath);
1976        } catch (IOException e) {
1977            log("Exception looking for splash in JAR file: " + jarPath); //$NON-NLS-1$
1978
log(e);
1979            return null;
1980        }
1981        ZipEntry JavaDoc entry = file.getEntry(splashPath.replace(File.separatorChar, '/'));
1982        if (entry == null)
1983            return null;
1984        InputStream input = null;
1985        try {
1986            input = file.getInputStream(entry);
1987        } catch (IOException e) {
1988            log("Exception opening splash: " + entry.getName() + " in JAR file: " + jarPath); //$NON-NLS-1$ //$NON-NLS-2$
1989
log(e);
1990            return null;
1991        }
1992        new File JavaDoc(splash.getParent()).mkdirs();
1993        OutputStream output;
1994        try {
1995            output = new BufferedOutputStream(new FileOutputStream(splash));
1996        } catch (FileNotFoundException e) {
1997            try {
1998                input.close();
1999            } catch (IOException e1) {
2000                // ignore
2001
}
2002            return null;
2003        }
2004        transferStreams(input, output);
2005        return splash.exists() ? splash.getAbsolutePath() : null;
2006    }
2007
2008    /*
2009     * Return a boolean value indicating whether or not the given
2010     * path represents a JAR file.
2011     */

2012    private boolean isJAR(String JavaDoc path) {
2013        if (path.endsWith(File.separator))
2014            return false;
2015        int index = path.lastIndexOf('.');
2016        if (index == -1)
2017            return false;
2018        index++;
2019        // handle the case where we have a '.' at the end
2020
if (index >= path.length())
2021            return false;
2022        return "JAR".equalsIgnoreCase(path.substring(index)); //$NON-NLS-1$
2023
}
2024
2025    /*
2026     * Build an array of path suffixes based on the given NL which is suitable
2027     * for splash path searching. The returned array contains paths in order
2028     * from most specific to most generic. So, in the FR_fr locale, it will return
2029     * "nl/fr/FR/splash.bmp", then "nl/fr/splash.bmp", and finally "splash.bmp".
2030     * (we always search the root)
2031     */

2032    private static String JavaDoc[] buildNLVariants(String JavaDoc locale) {
2033        //build list of suffixes for loading resource bundles
2034
String JavaDoc nl = locale;
2035        ArrayList result = new ArrayList(4);
2036        int lastSeparator;
2037        while (true) {
2038            result.add("nl" + File.separatorChar + nl.replace('_', File.separatorChar) + File.separatorChar + SPLASH_IMAGE); //$NON-NLS-1$
2039
lastSeparator = nl.lastIndexOf('_');
2040            if (lastSeparator == -1)
2041                break;
2042            nl = nl.substring(0, lastSeparator);
2043        }
2044        //add the empty suffix last (most general)
2045
result.add(SPLASH_IMAGE);
2046        return (String JavaDoc[]) result.toArray(new String JavaDoc[result.size()]);
2047    }
2048
2049    /*
2050     * resolve platform:/base/ URLs
2051     */

2052    private String JavaDoc resolve(String JavaDoc urlString) {
2053        // handle the case where people mistakenly spec a refererence: url.
2054
if (urlString.startsWith(REFERENCE_SCHEME)) {
2055            urlString = urlString.substring(10);
2056            System.getProperties().put(PROP_FRAMEWORK, urlString);
2057        }
2058        if (urlString.startsWith(PLATFORM_URL)) {
2059            String JavaDoc path = urlString.substring(PLATFORM_URL.length());
2060            return getInstallLocation() + path;
2061        }
2062            return urlString;
2063    }
2064
2065    /*
2066     * Entry point for logging.
2067     */

2068    protected synchronized void log(Object JavaDoc obj) {
2069        if (obj == null)
2070            return;
2071        try {
2072            openLogFile();
2073            try {
2074                if (newSession) {
2075                    log.write(SESSION);
2076                    log.write(' ');
2077                    String JavaDoc timestamp = new Date().toString();
2078                    log.write(timestamp);
2079                    log.write(' ');
2080                    for (int i = SESSION.length() + timestamp.length(); i < 78; i++)
2081                        log.write('-');
2082                    log.newLine();
2083                    newSession = false;
2084                }
2085                write(obj);
2086            } finally {
2087                if (logFile == null) {
2088                    if (log != null)
2089                        log.flush();
2090                } else
2091                    closeLogFile();
2092            }
2093        } catch (Exception JavaDoc e) {
2094            System.err.println("An exception occurred while writing to the platform log:"); //$NON-NLS-1$
2095
e.printStackTrace(System.err);
2096            System.err.println("Logging to the console instead."); //$NON-NLS-1$
2097
//we failed to write, so dump log entry to console instead
2098
try {
2099                log = logForStream(System.err);
2100                write(obj);
2101                log.flush();
2102            } catch (Exception JavaDoc e2) {
2103                System.err.println("An exception occurred while logging to the console:"); //$NON-NLS-1$
2104
e2.printStackTrace(System.err);
2105            }
2106        } finally {
2107            log = null;
2108        }
2109    }
2110
2111    /*
2112     * This should only be called from #log()
2113     */

2114    private void write(Object JavaDoc obj) throws IOException {
2115        if (obj == null)
2116            return;
2117        if (obj instanceof Throwable JavaDoc) {
2118            log.write(STACK);
2119            log.newLine();
2120            ((Throwable JavaDoc) obj).printStackTrace(new PrintWriter(log));
2121        } else {
2122            log.write(ENTRY);
2123            log.write(' ');
2124            log.write(PLUGIN_ID);
2125            log.write(' ');
2126            log.write(String.valueOf(ERROR));
2127            log.write(' ');
2128            log.write(String.valueOf(0));
2129            log.write(' ');
2130            log.write(getDate(new Date()));
2131            log.newLine();
2132            log.write(MESSAGE);
2133            log.write(' ');
2134            log.write(String.valueOf(obj));
2135        }
2136        log.newLine();
2137    }
2138
2139    protected String JavaDoc getDate(Date date) {
2140        Calendar c = Calendar.getInstance();
2141        c.setTime(date);
2142        StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
2143        appendPaddedInt(c.get(Calendar.YEAR), 4, sb).append('-');
2144        appendPaddedInt(c.get(Calendar.MONTH) + 1, 2, sb).append('-');
2145        appendPaddedInt(c.get(Calendar.DAY_OF_MONTH), 2, sb).append(' ');
2146        appendPaddedInt(c.get(Calendar.HOUR_OF_DAY), 2, sb).append(':');
2147        appendPaddedInt(c.get(Calendar.MINUTE), 2, sb).append(':');
2148        appendPaddedInt(c.get(Calendar.SECOND), 2, sb).append('.');
2149        appendPaddedInt(c.get(Calendar.MILLISECOND), 3, sb);
2150        return sb.toString();
2151    }
2152
2153    private StringBuffer JavaDoc appendPaddedInt(int value, int pad, StringBuffer JavaDoc buffer) {
2154        pad = pad - 1;
2155        if (pad == 0)
2156            return buffer.append(Integer.toString(value));
2157        int padding = (int) Math.pow(10, pad);
2158        if (value >= padding)
2159            return buffer.append(Integer.toString(value));
2160        while (padding > value && padding > 1) {
2161            buffer.append('0');
2162            padding = padding / 10;
2163        }
2164        buffer.append(value);
2165        return buffer;
2166    }
2167
2168    private void computeLogFileLocation() {
2169        String JavaDoc logFileProp = System.getProperty(PROP_LOGFILE);
2170        if (logFileProp != null) {
2171            if (logFile == null || !logFileProp.equals(logFile.getAbsolutePath())) {
2172                logFile = new File JavaDoc(logFileProp);
2173                new File JavaDoc(logFile.getParent()).mkdirs();
2174            }
2175            return;
2176        }
2177
2178        // compute the base location and then append the name of the log file
2179
URL base = buildURL(System.getProperty(PROP_CONFIG_AREA), false);
2180        if (base == null)
2181            return;
2182        logFile = new File JavaDoc(base.getPath(), Long.toString(System.currentTimeMillis()) + ".log"); //$NON-NLS-1$
2183
new File JavaDoc(logFile.getParent()).mkdirs();
2184        System.getProperties().put(PROP_LOGFILE, logFile.getAbsolutePath());
2185    }
2186
2187    /**
2188     * Converts an ASCII character representing a hexadecimal
2189     * value into its integer equivalent.
2190     */

2191    private int hexToByte(byte b) {
2192        switch (b) {
2193            case '0' :
2194                return 0;
2195            case '1' :
2196                return 1;
2197            case '2' :
2198                return 2;
2199            case '3' :
2200                return 3;
2201            case '4' :
2202                return 4;
2203            case '5' :
2204                return 5;
2205            case '6' :
2206                return 6;
2207            case '7' :
2208                return 7;
2209            case '8' :
2210                return 8;
2211            case '9' :
2212                return 9;
2213            case 'A' :
2214            case 'a' :
2215                return 10;
2216            case 'B' :
2217            case 'b' :
2218                return 11;
2219            case 'C' :
2220            case 'c' :
2221                return 12;
2222            case 'D' :
2223            case 'd' :
2224                return 13;
2225            case 'E' :
2226            case 'e' :
2227                return 14;
2228            case 'F' :
2229            case 'f' :
2230                return 15;
2231            default :
2232                throw new IllegalArgumentException JavaDoc("Switch error decoding URL"); //$NON-NLS-1$
2233
}
2234    }
2235
2236    private void openLogFile() throws IOException {
2237        computeLogFileLocation();
2238        try {
2239            log = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(logFile.getAbsolutePath(), true), "UTF-8")); //$NON-NLS-1$
2240
} catch (IOException e) {
2241            logFile = null;
2242            throw e;
2243        }
2244    }
2245
2246    private BufferedWriter logForStream(OutputStream output) {
2247        try {
2248            return new BufferedWriter(new OutputStreamWriter(output, "UTF-8")); //$NON-NLS-1$
2249
} catch (UnsupportedEncodingException e) {
2250            return new BufferedWriter(new OutputStreamWriter(output));
2251        }
2252    }
2253
2254    private void closeLogFile() throws IOException {
2255        try {
2256            if (log != null) {
2257                log.flush();
2258                log.close();
2259            }
2260        } finally {
2261            log = null;
2262        }
2263    }
2264
2265    private void mergeProperties(Properties destination, Properties source) {
2266        if (destination == null || source == null)
2267            return;
2268        for (Enumeration e = source.keys(); e.hasMoreElements();) {
2269            String JavaDoc key = (String JavaDoc) e.nextElement();
2270            if (key.equals(PROP_CLASSPATH)) {
2271                String JavaDoc destinationClasspath = destination.getProperty(PROP_CLASSPATH);
2272                String JavaDoc sourceClasspath = source.getProperty(PROP_CLASSPATH);
2273                if (destinationClasspath == null)
2274                    destinationClasspath = sourceClasspath;
2275                else
2276                    destinationClasspath = destinationClasspath + sourceClasspath;
2277                destination.put(PROP_CLASSPATH, destinationClasspath);
2278                continue;
2279            }
2280            String JavaDoc value = source.getProperty(key);
2281            if (destination.getProperty(key) == null)
2282                destination.put(key, value);
2283        }
2284    }
2285
2286    private void setupVMProperties() {
2287        if (vm != null)
2288            System.getProperties().put(PROP_VM, vm);
2289        setMultiValueProperty(PROP_VMARGS, vmargs);
2290        setMultiValueProperty(PROP_COMMANDS, commands);
2291    }
2292
2293    private void setMultiValueProperty(String JavaDoc property, String JavaDoc[] value) {
2294        if (value != null) {
2295            StringBuffer JavaDoc result = new StringBuffer JavaDoc(300);
2296            for (int i = 0; i < value.length; i++) {
2297                if (value[i] != null) {
2298                    result.append(value[i]);
2299                    result.append('\n');
2300                }
2301            }
2302            System.getProperties().put(property, result.toString());
2303        }
2304    }
2305
2306    /*
2307     * NOTE: It is ok here for EclipsePolicy to use 1.4 methods because the methods
2308     * that it calls them from don't exist in Foundation so they will never be called. A more
2309     * detailed explanation from Tom:
2310     *
2311     * They will never get called because in a pre 1.4 VM the methods
2312     * getPermissions(CodeSource) and implies(ProtectionDomain, Permission) are
2313     * undefined on the Policy class which is what EclipsePolicy extends. EclipsePolicy
2314     * implements these two methods so it can proxy them to the parent Policy.
2315     * But since these methods are not actually defined on Policy in a pre-1.4 VM
2316     * nobody will actually call them (unless they casted the policy to EclipsePolicy and
2317     * called our methods)
2318     */

2319    private class EclipsePolicy extends Policy {
2320        // The policy that this EclipsePolicy is replacing
2321
private Policy policy;
2322
2323        // The set of URLs to give AllPermissions to; this is the set of bootURLs
2324
private URL[] urls;
2325
2326        // The AllPermissions collection
2327
private PermissionCollection allPermissions;
2328
2329        // The AllPermission permission
2330
Permission allPermission = new AllPermission();
2331
2332        EclipsePolicy(Policy policy, URL[] urls) {
2333            this.policy = policy;
2334            this.urls = urls;
2335            allPermissions = new PermissionCollection() {
2336                private static final long serialVersionUID = 3258131349494708277L;
2337
2338                // A simple PermissionCollection that only has AllPermission
2339
public void add(Permission permission) {
2340                    //no adding to this policy
2341
}
2342
2343                public boolean implies(Permission permission) {
2344                    return true;
2345                }
2346
2347                public Enumeration elements() {
2348                    return new Enumeration() {
2349                        int cur = 0;
2350
2351                        public boolean hasMoreElements() {
2352                            return cur < 1;
2353                        }
2354
2355                        public Object JavaDoc nextElement() {
2356                            if (cur == 0) {
2357                                cur = 1;
2358                                return allPermission;
2359                            }
2360                                throw new NoSuchElementException();
2361                        }
2362                    };
2363                }
2364            };
2365        }
2366
2367        public PermissionCollection getPermissions(CodeSource codesource) {
2368            if (contains(codesource.getLocation()))
2369                return allPermissions;
2370            return policy == null ? allPermissions : policy.getPermissions(codesource);
2371        }
2372
2373        public PermissionCollection getPermissions(ProtectionDomain domain) {
2374            if (contains(domain.getCodeSource().getLocation()))
2375                return allPermissions;
2376            return policy == null ? allPermissions : policy.getPermissions(domain);
2377        }
2378
2379        public boolean implies(ProtectionDomain domain, Permission permission) {
2380            if (contains(domain.getCodeSource().getLocation()))
2381                return true;
2382            return policy == null ? true : policy.implies(domain, permission);
2383        }
2384
2385        public void refresh() {
2386            if (policy != null)
2387                policy.refresh();
2388        }
2389
2390        private boolean contains(URL url) {
2391            // Check to see if this URL is in our set of URLs to give AllPermissions to.
2392
for (int i = 0; i < urls.length; i++) {
2393                // We do simple equals test here because we assume the URLs will be the same objects.
2394
if (urls[i] == url)
2395                    return true;
2396            }
2397            return false;
2398        }
2399    }
2400
2401    private class StartupClassLoader extends URLClassLoader {
2402
2403        public StartupClassLoader(URL[] urls) {
2404            super(urls);
2405        }
2406
2407        public StartupClassLoader(URL[] urls, ClassLoader JavaDoc parent) {
2408            super(urls, parent);
2409        }
2410
2411        public StartupClassLoader(URL[] urls, ClassLoader JavaDoc parent, URLStreamHandlerFactory factory) {
2412            super(urls, parent, factory);
2413        }
2414
2415        protected String JavaDoc findLibrary(String JavaDoc name) {
2416            if (extensionPaths == null)
2417                return super.findLibrary(name);
2418            String JavaDoc libName = System.mapLibraryName(name);
2419            for (int i = 0; i < extensionPaths.length; i++) {
2420                File JavaDoc libFile = new File JavaDoc(extensionPaths[i], libName);
2421                if (libFile.isFile())
2422                    return libFile.getAbsolutePath();
2423            }
2424            return super.findLibrary(name);
2425        }
2426    }
2427}
2428
Popular Tags