KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > runtime > adaptor > EclipseStarter


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

12 package org.eclipse.core.runtime.adaptor;
13
14 import java.io.*;
15 import java.lang.reflect.Constructor JavaDoc;
16 import java.lang.reflect.Method JavaDoc;
17 import java.net.*;
18 import java.security.CodeSource JavaDoc;
19 import java.security.ProtectionDomain JavaDoc;
20 import java.util.*;
21 import org.eclipse.core.runtime.internal.adaptor.*;
22 import org.eclipse.osgi.framework.adaptor.FilePath;
23 import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor;
24 import org.eclipse.osgi.framework.internal.core.*;
25 import org.eclipse.osgi.framework.internal.core.Constants;
26 import org.eclipse.osgi.framework.log.FrameworkLog;
27 import org.eclipse.osgi.framework.log.FrameworkLogEntry;
28 import org.eclipse.osgi.internal.profile.Profile;
29 import org.eclipse.osgi.service.datalocation.Location;
30 import org.eclipse.osgi.service.resolver.*;
31 import org.eclipse.osgi.service.runnable.ApplicationLauncher;
32 import org.eclipse.osgi.service.runnable.StartupMonitor;
33 import org.eclipse.osgi.util.ManifestElement;
34 import org.eclipse.osgi.util.NLS;
35 import org.osgi.framework.*;
36 import org.osgi.service.packageadmin.PackageAdmin;
37 import org.osgi.service.startlevel.StartLevel;
38 import org.osgi.util.tracker.ServiceTracker;
39
40 /**
41  * Special startup class for the Eclipse Platform. This class cannot be
42  * instantiated; all functionality is provided by static methods.
43  * <p>
44  * The Eclipse Platform makes heavy use of Java class loaders for loading
45  * plug-ins. Even the Eclipse Runtime itself and the OSGi framework need
46  * to be loaded by special class loaders. The upshot is that a
47  * client program (such as a Java main program, a servlet) cannot
48  * reference any part of Eclipse directly. Instead, a client must use this
49  * loader class to start the platform, invoking functionality defined
50  * in plug-ins, and shutting down the platform when done.
51  * </p>
52  * <p>Note that the fields on this class are not API. </p>
53  * @since 3.0
54  */

55 public class EclipseStarter {
56     private static FrameworkAdaptor adaptor;
57     private static BundleContext context;
58     private static boolean initialize = false;
59     public static boolean debug = false;
60     private static boolean running = false;
61     private static OSGi osgi = null;
62     private static ServiceRegistration defaultMonitorRegistration = null;
63     private static ServiceRegistration appLauncherRegistration = null;
64     private static ServiceRegistration splashStreamRegistration = null;
65
66     // command line arguments
67
private static final String JavaDoc CLEAN = "-clean"; //$NON-NLS-1$
68
private static final String JavaDoc CONSOLE = "-console"; //$NON-NLS-1$
69
private static final String JavaDoc CONSOLE_LOG = "-consoleLog"; //$NON-NLS-1$
70
private static final String JavaDoc DEBUG = "-debug"; //$NON-NLS-1$
71
private static final String JavaDoc INITIALIZE = "-initialize"; //$NON-NLS-1$
72
private static final String JavaDoc DEV = "-dev"; //$NON-NLS-1$
73
private static final String JavaDoc WS = "-ws"; //$NON-NLS-1$
74
private static final String JavaDoc OS = "-os"; //$NON-NLS-1$
75
private static final String JavaDoc ARCH = "-arch"; //$NON-NLS-1$
76
private static final String JavaDoc NL = "-nl"; //$NON-NLS-1$
77
private static final String JavaDoc CONFIGURATION = "-configuration"; //$NON-NLS-1$
78
private static final String JavaDoc USER = "-user"; //$NON-NLS-1$
79
private static final String JavaDoc NOEXIT = "-noExit"; //$NON-NLS-1$
80

81     // this is more of an Eclipse argument but this OSGi implementation stores its
82
// metadata alongside Eclipse's.
83
private static final String JavaDoc DATA = "-data"; //$NON-NLS-1$
84

85     // System properties
86
public static final String JavaDoc PROP_BUNDLES = "osgi.bundles"; //$NON-NLS-1$
87
public static final String JavaDoc PROP_BUNDLES_STARTLEVEL = "osgi.bundles.defaultStartLevel"; //$NON-NLS-1$ //The start level used to install the bundles
88
public static final String JavaDoc PROP_EXTENSIONS = "osgi.framework.extensions"; //$NON-NLS-1$
89
public static final String JavaDoc PROP_INITIAL_STARTLEVEL = "osgi.startLevel"; //$NON-NLS-1$ //The start level when the fwl start
90
public static final String JavaDoc PROP_DEBUG = "osgi.debug"; //$NON-NLS-1$
91
public static final String JavaDoc PROP_DEV = "osgi.dev"; //$NON-NLS-1$
92
public static final String JavaDoc PROP_CLEAN = "osgi.clean"; //$NON-NLS-1$
93
public static final String JavaDoc PROP_CONSOLE = "osgi.console"; //$NON-NLS-1$
94
public static final String JavaDoc PROP_CONSOLE_CLASS = "osgi.consoleClass"; //$NON-NLS-1$
95
public static final String JavaDoc PROP_CHECK_CONFIG = "osgi.checkConfiguration"; //$NON-NLS-1$
96
public static final String JavaDoc PROP_OS = "osgi.os"; //$NON-NLS-1$
97
public static final String JavaDoc PROP_WS = "osgi.ws"; //$NON-NLS-1$
98
public static final String JavaDoc PROP_NL = "osgi.nl"; //$NON-NLS-1$
99
public static final String JavaDoc PROP_ARCH = "osgi.arch"; //$NON-NLS-1$
100
public static final String JavaDoc PROP_ADAPTOR = "osgi.adaptor"; //$NON-NLS-1$
101
public static final String JavaDoc PROP_SYSPATH = "osgi.syspath"; //$NON-NLS-1$
102
public static final String JavaDoc PROP_LOGFILE = "osgi.logfile"; //$NON-NLS-1$
103
public static final String JavaDoc PROP_FRAMEWORK = "osgi.framework"; //$NON-NLS-1$
104
public static final String JavaDoc PROP_INSTALL_AREA = "osgi.install.area"; //$NON-NLS-1$
105
public static final String JavaDoc PROP_FRAMEWORK_SHAPE = "osgi.framework.shape"; //$NON-NLS-1$ //the shape of the fwk (jar, or folder)
106
public static final String JavaDoc PROP_NOSHUTDOWN = "osgi.noShutdown"; //$NON-NLS-1$
107
private static final String JavaDoc PROP_FORCED_RESTART = "osgi.forcedRestart"; //$NON-NLS-1$
108

109     public static final String JavaDoc PROP_EXITCODE = "eclipse.exitcode"; //$NON-NLS-1$
110
public static final String JavaDoc PROP_EXITDATA = "eclipse.exitdata"; //$NON-NLS-1$
111
public static final String JavaDoc PROP_CONSOLE_LOG = "eclipse.consoleLog"; //$NON-NLS-1$
112
public static final String JavaDoc PROP_IGNOREAPP = "eclipse.ignoreApp"; //$NON-NLS-1$
113
public static final String JavaDoc PROP_REFRESH_BUNDLES = "eclipse.refreshBundles"; //$NON-NLS-1$
114
private static final String JavaDoc PROP_ALLOW_APPRELAUNCH = "eclipse.allowAppRelaunch"; //$NON-NLS-1$
115
private static final String JavaDoc PROP_APPLICATION_LAUNCHDEFAULT = "eclipse.application.launchDefault"; //$NON-NLS-1$
116

117     private static final String JavaDoc FILE_SCHEME = "file:"; //$NON-NLS-1$
118
private static final String JavaDoc REFERENCE_SCHEME = "reference:"; //$NON-NLS-1$
119
private static final String JavaDoc REFERENCE_PROTOCOL = "reference"; //$NON-NLS-1$
120
private static final String JavaDoc INITIAL_LOCATION = "initial@"; //$NON-NLS-1$
121
/** string containing the classname of the adaptor to be used in this framework instance */
122     protected static final String JavaDoc DEFAULT_ADAPTOR_CLASS = "org.eclipse.osgi.baseadaptor.BaseAdaptor"; //$NON-NLS-1$
123

124     private static final int DEFAULT_INITIAL_STARTLEVEL = 6; // default value for legacy purposes
125
private static final String JavaDoc DEFAULT_BUNDLES_STARTLEVEL = "4"; //$NON-NLS-1$
126
// Console information
127
protected static final String JavaDoc DEFAULT_CONSOLE_CLASS = "org.eclipse.osgi.framework.internal.core.FrameworkConsole"; //$NON-NLS-1$
128
private static final String JavaDoc CONSOLE_NAME = "OSGi Console"; //$NON-NLS-1$
129

130     private static Runnable JavaDoc console;
131     private static FrameworkLog log;
132     // directory of serch candidates keyed by directory abs path -> directory listing (bug 122024)
133
private static HashMap searchCandidates = new HashMap(4);
134     private static EclipseAppLauncher appLauncher;
135     private static List shutdownHandlers;
136
137     /**
138      * This is the main to start osgi.
139      * It only works when the framework is being jared as a single jar
140      */

141     public static void main(String JavaDoc[] args) throws Exception JavaDoc {
142         if (FrameworkProperties.getProperty("eclipse.startTime") == null) //$NON-NLS-1$
143
FrameworkProperties.setProperty("eclipse.startTime", Long.toString(System.currentTimeMillis())); //$NON-NLS-1$
144
if (FrameworkProperties.getProperty(PROP_NOSHUTDOWN) == null)
145             FrameworkProperties.setProperty(PROP_NOSHUTDOWN, "true"); //$NON-NLS-1$
146
// set the compatibility boot delegation flag to false to get "standard" OSGi behavior WRT boot delegation (bug 178477)
147
if (FrameworkProperties.getProperty(Constants.OSGI_COMPATIBILITY_BOOTDELEGATION) == null)
148             FrameworkProperties.setProperty(Constants.OSGI_COMPATIBILITY_BOOTDELEGATION, "false"); //$NON-NLS-1$
149
run(args, null);
150     }
151
152     /**
153      * Launches the platform and runs a single application. The application is either identified
154      * in the given arguments (e.g., -application &ltapp id&gt) or in the <code>eclipse.application</code>
155      * System property. This convenience method starts
156      * up the platform, runs the indicated application, and then shuts down the
157      * platform. The platform must not be running already.
158      *
159      * @param args the command line-style arguments used to configure the platform
160      * @param endSplashHandler the block of code to run to tear down the splash
161      * screen or <code>null</code> if no tear down is required
162      * @return the result of running the application
163      * @throws Exception if anything goes wrong
164      */

165     public static Object JavaDoc run(String JavaDoc[] args, Runnable JavaDoc endSplashHandler) throws Exception JavaDoc {
166         if (Profile.PROFILE && Profile.STARTUP)
167             Profile.logEnter("EclipseStarter.run()", null); //$NON-NLS-1$
168
if (running)
169             throw new IllegalStateException JavaDoc(EclipseAdaptorMsg.ECLIPSE_STARTUP_ALREADY_RUNNING);
170         boolean startupFailed = true;
171         try {
172             startup(args, endSplashHandler);
173             startupFailed = false;
174             if (Boolean.valueOf(FrameworkProperties.getProperty(PROP_IGNOREAPP)).booleanValue() || isForcedRestart())
175                 return null;
176             return run(null);
177         } catch (Throwable JavaDoc e) {
178             // ensure the splash screen is down
179
if (endSplashHandler != null)
180                 endSplashHandler.run();
181             // may use startupFailed to understand where the error happened
182
FrameworkLogEntry logEntry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, startupFailed ? EclipseAdaptorMsg.ECLIPSE_STARTUP_STARTUP_ERROR : EclipseAdaptorMsg.ECLIPSE_STARTUP_APP_ERROR, 1, e, null);
183             if (log != null) {
184                 log.log(logEntry);
185                 if (context != null) // this can be null if OSGi failed to launch (bug 151413)
186
logUnresolvedBundles(context.getBundles());
187             } else
188                 // TODO desperate measure - ideally, we should write this to disk (a la Main.log)
189
e.printStackTrace();
190         } finally {
191             try {
192                 // The application typically sets the exit code however the framework can request that
193
// it be re-started. We need to check for this and potentially override the exit code.
194
if (isForcedRestart())
195                     FrameworkProperties.setProperty(PROP_EXITCODE, "23"); //$NON-NLS-1$
196
if (!Boolean.valueOf(FrameworkProperties.getProperty(PROP_NOSHUTDOWN)).booleanValue())
197                     shutdown();
198             } catch (Throwable JavaDoc e) {
199                 FrameworkLogEntry logEntry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, EclipseAdaptorMsg.ECLIPSE_STARTUP_SHUTDOWN_ERROR, 1, e, null);
200                 if (log != null)
201                     log.log(logEntry);
202                 else
203                     // TODO desperate measure - ideally, we should write this to disk (a la Main.log)
204
e.printStackTrace();
205             }
206             if (Profile.PROFILE && Profile.STARTUP)
207                 Profile.logExit("EclipseStarter.run()"); //$NON-NLS-1$
208
if (Profile.PROFILE) {
209                 String JavaDoc report = Profile.getProfileLog();
210                 // avoiding writing to the console if there is nothing to print
211
if (report != null && report.length() > 0)
212                     System.out.println(report);
213             }
214         }
215         // we only get here if an error happened
216
FrameworkProperties.setProperty(PROP_EXITCODE, "13"); //$NON-NLS-1$
217
FrameworkProperties.setProperty(PROP_EXITDATA, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_ERROR_CHECK_LOG, log == null ? null : log.getFile().getPath()));
218         return null;
219     }
220
221     /**
222      * Returns true if the platform is already running, false otherwise.
223      * @return whether or not the platform is already running
224      */

225     public static boolean isRunning() {
226         return running;
227     }
228
229     protected static FrameworkLog createFrameworkLog() {
230         FrameworkLog frameworkLog;
231         String JavaDoc logFileProp = FrameworkProperties.getProperty(EclipseStarter.PROP_LOGFILE);
232         if (logFileProp != null) {
233             frameworkLog = new EclipseLog(new File(logFileProp));
234         } else {
235             Location location = LocationManager.getConfigurationLocation();
236             File configAreaDirectory = null;
237             if (location != null)
238                 // TODO assumes the URL is a file: url
239
configAreaDirectory = new File(location.getURL().getFile());
240
241             if (configAreaDirectory != null) {
242                 String JavaDoc logFileName = Long.toString(System.currentTimeMillis()) + ".log"; //$NON-NLS-1$
243
File logFile = new File(configAreaDirectory, logFileName);
244                 FrameworkProperties.setProperty(EclipseStarter.PROP_LOGFILE, logFile.getAbsolutePath());
245                 frameworkLog = new EclipseLog(logFile);
246             } else
247                 frameworkLog = new EclipseLog();
248         }
249         if ("true".equals(FrameworkProperties.getProperty(EclipseStarter.PROP_CONSOLE_LOG))) //$NON-NLS-1$
250
frameworkLog.setConsoleLog(true);
251         return frameworkLog;
252     }
253
254     /**
255      * Starts the platform and sets it up to run a single application. The application is either identified
256      * in the given arguments (e.g., -application &ltapp id&gt) or in the <code>eclipse.application</code>
257      * System property. The platform must not be running already.
258      * <p>
259      * The given runnable (if not <code>null</code>) is used to tear down the splash screen if required.
260      * </p>
261      * @param args the arguments passed to the application
262      * @return BundleContext the context of the system bundle
263      * @throws Exception if anything goes wrong
264      */

265     public static BundleContext startup(String JavaDoc[] args, Runnable JavaDoc endSplashHandler) throws Exception JavaDoc {
266         if (Profile.PROFILE && Profile.STARTUP)
267             Profile.logEnter("EclipseStarter.startup()", null); //$NON-NLS-1$
268
if (running)
269             throw new IllegalStateException JavaDoc(EclipseAdaptorMsg.ECLIPSE_STARTUP_ALREADY_RUNNING);
270         initializeProperties();
271         processCommandLine(args);
272         LocationManager.initializeLocations();
273         loadConfigurationInfo();
274         finalizeProperties();
275         if (Profile.PROFILE)
276             Profile.initProps(); // catch any Profile properties set in eclipse.properties...
277
if (Profile.PROFILE && Profile.STARTUP)
278             Profile.logTime("EclipseStarter.startup()", "props inited"); //$NON-NLS-1$ //$NON-NLS-2$
279
adaptor = createAdaptor();
280         log = adaptor.getFrameworkLog();
281         if (Profile.PROFILE && Profile.STARTUP)
282             Profile.logTime("EclipseStarter.startup()", "adapter created"); //$NON-NLS-1$ //$NON-NLS-2$
283
osgi = new OSGi(adaptor);
284         if (Profile.PROFILE && Profile.STARTUP)
285             Profile.logTime("EclipseStarter.startup()", "OSGi created"); //$NON-NLS-1$ //$NON-NLS-2$
286
context = osgi.getBundleContext();
287         registerFrameworkShutdownHandlers();
288         publishSplashScreen(endSplashHandler);
289         osgi.launch();
290         if (Profile.PROFILE && Profile.STARTUP)
291             Profile.logTime("EclipseStarter.startup()", "osgi launched"); //$NON-NLS-1$ //$NON-NLS-2$
292
String JavaDoc consolePort = FrameworkProperties.getProperty(PROP_CONSOLE);
293         if (consolePort != null) {
294             startConsole(osgi, new String JavaDoc[0], consolePort);
295             if (Profile.PROFILE && Profile.STARTUP)
296                 Profile.logTime("EclipseStarter.startup()", "console started"); //$NON-NLS-1$ //$NON-NLS-2$
297
}
298         if ("true".equals(FrameworkProperties.getProperty(PROP_REFRESH_BUNDLES)) && refreshPackages(getCurrentBundles(false))) //$NON-NLS-1$
299
return context; // cannot continue; refreshPackages shutdown the framework
300
if (Profile.PROFILE && Profile.STARTUP)
301             Profile.logTime("EclipseStarter.startup()", "loading basic bundles"); //$NON-NLS-1$ //$NON-NLS-2$
302
long stateStamp = adaptor.getState().getTimeStamp();
303         Bundle[] startBundles = loadBasicBundles();
304         if (startBundles == null)
305             return context; // cannot continue; loadBasicBundles caused refreshPackages to shutdown the framework
306
// set the framework start level to the ultimate value. This will actually start things
307
// running if they are persistently active.
308
setStartLevel(getStartLevel());
309         if (Profile.PROFILE && Profile.STARTUP)
310             Profile.logTime("EclipseStarter.startup()", "StartLevel set"); //$NON-NLS-1$ //$NON-NLS-2$
311
// they should all be active by this time
312
ensureBundlesActive(startBundles);
313         if (debug || FrameworkProperties.getProperty(PROP_DEV) != null)
314             // only spend time showing unresolved bundles in dev/debug mode and the state has changed
315
if (stateStamp != adaptor.getState().getTimeStamp())
316                 logUnresolvedBundles(context.getBundles());
317         running = true;
318         if (Profile.PROFILE && Profile.STARTUP)
319             Profile.logExit("EclipseStarter.startup()"); //$NON-NLS-1$
320
return context;
321     }
322
323     private static int getStartLevel() {
324         String JavaDoc level = FrameworkProperties.getProperty(PROP_INITIAL_STARTLEVEL);
325         if (level != null)
326             try {
327                 return Integer.parseInt(level);
328             } catch (NumberFormatException JavaDoc e) {
329                 if (debug)
330                     System.out.println("Start level = " + level + " parsed. Using hardcoded default: 6"); //$NON-NLS-1$ //$NON-NLS-2$
331
}
332         return DEFAULT_INITIAL_STARTLEVEL;
333     }
334
335     /**
336      * Runs the application for which the platform was started. The platform
337      * must be running.
338      * <p>
339      * The given argument is passed to the application being run. If it is <code>null</code>
340      * then the command line arguments used in starting the platform, and not consumed
341      * by the platform code, are passed to the application as a <code>String[]</code>.
342      * </p>
343      * @param argument the argument passed to the application. May be <code>null</code>
344      * @return the result of running the application
345      * @throws Exception if anything goes wrong
346      */

347     public static Object JavaDoc run(Object JavaDoc argument) throws Exception JavaDoc {
348         if (Profile.PROFILE && Profile.STARTUP)
349             Profile.logEnter("EclipseStarter.run(Object)()", null); //$NON-NLS-1$
350
if (!running)
351             throw new IllegalStateException JavaDoc(EclipseAdaptorMsg.ECLIPSE_STARTUP_NOT_RUNNING);
352         // if we are just initializing, do not run the application just return.
353
if (initialize)
354             return new Integer JavaDoc(0);
355         if (appLauncher == null) {
356             boolean launchDefault = Boolean.valueOf(FrameworkProperties.getProperty(PROP_APPLICATION_LAUNCHDEFAULT, "true")).booleanValue(); //$NON-NLS-1$
357
// create the ApplicationLauncher and register it as a service
358
appLauncher = new EclipseAppLauncher(context, Boolean.valueOf(FrameworkProperties.getProperty(PROP_ALLOW_APPRELAUNCH)).booleanValue(), launchDefault, log);
359             appLauncherRegistration = context.registerService(ApplicationLauncher.class.getName(), appLauncher, null);
360             // must start the launcher AFTER service restration because this method
361
// blocks and runs the application on the current thread. This method
362
// will return only after the application has stopped.
363
return appLauncher.start(argument);
364         }
365         return appLauncher.reStart(argument);
366     }
367
368     /**
369      * Shuts down the Platform. The state of the Platform is not automatically
370      * saved before shutting down.
371      * <p>
372      * On return, the Platform will no longer be running (but could be re-launched
373      * with another call to startup). If relaunching, care must be taken to reinitialize
374      * any System properties which the platform uses (e.g., osgi.instance.area) as
375      * some policies in the platform do not allow resetting of such properties on
376      * subsequent runs.
377      * </p><p>
378      * Any objects handed out by running Platform,
379      * including Platform runnables obtained via getRunnable, will be
380      * permanently invalid. The effects of attempting to invoke methods
381      * on invalid objects is undefined.
382      * </p>
383      * @throws Exception if anything goes wrong
384      */

385     public static void shutdown() throws Exception JavaDoc {
386         if (!running || osgi == null)
387             return;
388         if (appLauncherRegistration != null)
389             appLauncherRegistration.unregister();
390         if (splashStreamRegistration != null)
391             splashStreamRegistration.unregister();
392         if (defaultMonitorRegistration != null)
393             defaultMonitorRegistration.unregister();
394         appLauncherRegistration = null;
395         appLauncher = null;
396         splashStreamRegistration = null;
397         defaultMonitorRegistration = null;
398         stopConsole();
399         osgi.close();
400         osgi = null;
401         context = null;
402         running = false;
403     }
404
405     private static void ensureBundlesActive(Bundle[] bundles) {
406         ServiceTracker tracker = null;
407         try {
408             for (int i = 0; i < bundles.length; i++) {
409                 if (bundles[i].getState() != Bundle.ACTIVE) {
410                     if (bundles[i].getState() == Bundle.INSTALLED) {
411                         // Log that the bundle is not resolved
412
log.log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_ERROR_BUNDLE_NOT_RESOLVED, bundles[i].getLocation()), 0, null, null));
413                         continue;
414                     }
415                     // check that the startlevel allows the bundle to be active (111550)
416
if (tracker == null) {
417                         tracker = new ServiceTracker(context, StartLevel.class.getName(), null);
418                         tracker.open();
419                     }
420                     StartLevel sl = (StartLevel) tracker.getService();
421                     if (sl != null && (sl.getBundleStartLevel(bundles[i]) <= sl.getStartLevel())) {
422                         log.log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_ERROR_BUNDLE_NOT_ACTIVE, bundles[i]), 0, null, null));
423                     }
424                 }
425             }
426         } finally {
427             if (tracker != null)
428                 tracker.close();
429         }
430     }
431
432     private static void logUnresolvedBundles(Bundle[] bundles) {
433         State state = adaptor.getState();
434         FrameworkLog logService = adaptor.getFrameworkLog();
435         StateHelper stateHelper = adaptor.getPlatformAdmin().getStateHelper();
436
437         // first lets look for missing leaf constraints (bug 114120)
438
VersionConstraint[] leafConstraints = stateHelper.getUnsatisfiedLeaves(state.getBundles());
439         // hash the missing leaf constraints by the declaring bundles
440
Map missing = new HashMap();
441         for (int i = 0; i < leafConstraints.length; i++) {
442             // only include non-optional and non-dynamic constraint leafs
443
if (leafConstraints[i] instanceof BundleSpecification && ((BundleSpecification) leafConstraints[i]).isOptional())
444                 continue;
445             if (leafConstraints[i] instanceof ImportPackageSpecification) {
446                 if (ImportPackageSpecification.RESOLUTION_OPTIONAL.equals(((ImportPackageSpecification) leafConstraints[i]).getDirective(Constants.RESOLUTION_DIRECTIVE)))
447                     continue;
448                 if (ImportPackageSpecification.RESOLUTION_DYNAMIC.equals(((ImportPackageSpecification) leafConstraints[i]).getDirective(Constants.RESOLUTION_DIRECTIVE)))
449                     continue;
450             }
451             BundleDescription bundle = leafConstraints[i].getBundle();
452             ArrayList constraints = (ArrayList) missing.get(bundle);
453             if (constraints == null) {
454                 constraints = new ArrayList();
455                 missing.put(bundle, constraints);
456             }
457             constraints.add(leafConstraints[i]);
458         }
459
460         // found some bundles with missing leaf constraints; log them first
461
if (missing.size() > 0) {
462             FrameworkLogEntry[] rootChildren = new FrameworkLogEntry[missing.size()];
463             int rootIndex = 0;
464             for (Iterator iter = missing.keySet().iterator(); iter.hasNext(); rootIndex++) {
465                 BundleDescription description = (BundleDescription) iter.next();
466                 String JavaDoc symbolicName = description.getSymbolicName() == null ? FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME : description.getSymbolicName();
467                 String JavaDoc generalMessage = NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_ERROR_BUNDLE_NOT_RESOLVED, description.getLocation());
468                 ArrayList constraints = (ArrayList) missing.get(description);
469                 FrameworkLogEntry[] logChildren = new FrameworkLogEntry[constraints.size()];
470                 for (int i = 0; i < logChildren.length; i++)
471                     logChildren[i] = new FrameworkLogEntry(symbolicName, FrameworkLogEntry.WARNING, 0, MessageHelper.getResolutionFailureMessage((VersionConstraint) constraints.get(i)), 0, null, null);
472                 rootChildren[rootIndex] = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.WARNING, 0, generalMessage, 0, null, logChildren);
473             }
474             logService.log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.WARNING, 0, EclipseAdaptorMsg.ECLIPSE_STARTUP_ROOTS_NOT_RESOLVED, 0, null, rootChildren));
475         }
476
477         // There may be some bundles unresolved for other reasons, causing the system to be unresolved
478
// log all unresolved constraints now
479
ArrayList allChildren = new ArrayList();
480         for (int i = 0; i < bundles.length; i++)
481             if (bundles[i].getState() == Bundle.INSTALLED) {
482                 String JavaDoc symbolicName = bundles[i].getSymbolicName() == null ? FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME : bundles[i].getSymbolicName();
483                 String JavaDoc generalMessage = NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_ERROR_BUNDLE_NOT_RESOLVED, bundles[i]);
484                 BundleDescription description = state.getBundle(bundles[i].getBundleId());
485                 // for some reason, the state does not know about that bundle
486
if (description == null)
487                     continue;
488                 FrameworkLogEntry[] logChildren = null;
489                 VersionConstraint[] unsatisfied = stateHelper.getUnsatisfiedConstraints(description);
490                 if (unsatisfied.length > 0) {
491                     // the bundle wasn't resolved due to some of its constraints were unsatisfiable
492
logChildren = new FrameworkLogEntry[unsatisfied.length];
493                     for (int j = 0; j < unsatisfied.length; j++)
494                         logChildren[j] = new FrameworkLogEntry(symbolicName, FrameworkLogEntry.WARNING, 0, MessageHelper.getResolutionFailureMessage(unsatisfied[j]), 0, null, null);
495                 } else {
496                     ResolverError[] resolverErrors = state.getResolverErrors(description);
497                     if (resolverErrors.length > 0) {
498                         logChildren = new FrameworkLogEntry[resolverErrors.length];
499                         for (int j = 0; j < resolverErrors.length; j++)
500                             logChildren[j] = new FrameworkLogEntry(symbolicName, FrameworkLogEntry.WARNING, 0, resolverErrors[j].toString(), 0, null, null);
501                     }
502                 }
503
504                 allChildren.add(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.WARNING, 0, generalMessage, 0, null, logChildren));
505             }
506         if (allChildren.size() > 0)
507             logService.log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.WARNING, 0, EclipseAdaptorMsg.ECLIPSE_STARTUP_ALL_NOT_RESOLVED, 0, null, (FrameworkLogEntry[]) allChildren.toArray(new FrameworkLogEntry[allChildren.size()])));
508     }
509
510     private static void publishSplashScreen(final Runnable JavaDoc endSplashHandler) {
511         if (endSplashHandler == null)
512             return;
513         // register the output stream to the launcher if it exists
514
try {
515             Method JavaDoc method = endSplashHandler.getClass().getMethod("getOutputStream", new Class JavaDoc[0]); //$NON-NLS-1$
516
Object JavaDoc outputStream = method.invoke(endSplashHandler, new Object JavaDoc[0]);
517             if (outputStream instanceof OutputStream) {
518                 Dictionary osProperties = new Hashtable();
519                 osProperties.put("name", "splashstream"); //$NON-NLS-1$//$NON-NLS-2$
520
splashStreamRegistration = context.registerService(OutputStream.class.getName(), outputStream, osProperties);
521             }
522         } catch (Exception JavaDoc ex) {
523             // ignore
524
}
525         // keep this splash handler as the default startup monitor
526
try {
527             Dictionary monitorProps = new Hashtable();
528             monitorProps.put(Constants.SERVICE_RANKING, new Integer JavaDoc(Integer.MIN_VALUE));
529             defaultMonitorRegistration = context.registerService(StartupMonitor.class.getName(), new DefaultStartupMonitor(endSplashHandler), monitorProps);
530         } catch (IllegalStateException JavaDoc e) {
531             //splash handler did not provide the necessary methods, ignore it
532
}
533     }
534
535     private static URL searchForBundle(String JavaDoc name, String JavaDoc parent) throws MalformedURLException {
536         URL url = null;
537         File fileLocation = null;
538         boolean reference = false;
539         try {
540             new URL(name); // quick check to see if the name is a valid URL
541
url = new URL(new File(parent).toURL(), name);
542         } catch (MalformedURLException e) {
543             // TODO this is legacy support for non-URL names. It should be removed eventually.
544
// if name was not a URL then construct one.
545
// Assume it should be a reference and htat it is relative. This support need not
546
// be robust as it is temporary..
547
File child = new File(name);
548             fileLocation = child.isAbsolute() ? child : new File(parent, name);
549             url = new URL(REFERENCE_PROTOCOL, null, fileLocation.toURL().toExternalForm());
550             reference = true;
551         }
552         // if the name was a URL then see if it is relative. If so, insert syspath.
553
if (!reference) {
554             URL baseURL = url;
555             // if it is a reference URL then strip off the reference: and set base to the file:...
556
if (url.getProtocol().equals(REFERENCE_PROTOCOL)) {
557                 reference = true;
558                 String JavaDoc baseSpec = url.getFile();
559                 if (baseSpec.startsWith(FILE_SCHEME)) {
560                     File child = new File(baseSpec.substring(5));
561                     baseURL = child.isAbsolute() ? child.toURL() : new File(parent, child.getPath()).toURL();
562                 } else
563                     baseURL = new URL(baseSpec);
564             }
565
566             fileLocation = new File(baseURL.getFile());
567             // if the location is relative, prefix it with the parent
568
if (!fileLocation.isAbsolute())
569                 fileLocation = new File(parent, fileLocation.toString());
570         }
571         // If the result is a reference then search for the real result and
572
// reconstruct the answer.
573
if (reference) {
574             String JavaDoc result = searchFor(fileLocation.getName(), new File(fileLocation.getParent()).getAbsolutePath());
575             if (result != null)
576                 url = new URL(REFERENCE_PROTOCOL, null, FILE_SCHEME + result);
577             else
578                 return null;
579         }
580
581         // finally we have something worth trying
582
try {
583             URLConnection result = url.openConnection();
584             result.connect();
585             return url;
586         } catch (IOException e) {
587             // int i = location.lastIndexOf('_');
588
// return i == -1? location : location.substring(0, i);
589
return null;
590         }
591     }
592
593     /*
594      * Ensure all basic bundles are installed, resolved and scheduled to start. Returns an array containing
595      * all basic bundles that are marked to start.
596      * Returns null if the framework has been shutdown as a result of refreshPackages
597      */

598     private static Bundle[] loadBasicBundles() throws IOException {
599         long startTime = System.currentTimeMillis();
600         String JavaDoc osgiBundles = FrameworkProperties.getProperty(PROP_BUNDLES);
601         String JavaDoc osgiExtensions = FrameworkProperties.getProperty(PROP_EXTENSIONS);
602         if (osgiExtensions != null && osgiExtensions.length() > 0) {
603             osgiBundles = osgiExtensions + ',' + osgiBundles;
604             FrameworkProperties.setProperty(PROP_BUNDLES, osgiBundles);
605         }
606         String JavaDoc[] installEntries = getArrayFromList(osgiBundles, ","); //$NON-NLS-1$
607
// get the initial bundle list from the installEntries
608
InitialBundle[] initialBundles = getInitialBundles(installEntries);
609         // get the list of currently installed initial bundles from the framework
610
Bundle[] curInitBundles = getCurrentBundles(true);
611
612         // list of bundles to be refreshed
613
List toRefresh = new ArrayList(curInitBundles.length);
614         // uninstall any of the currently installed bundles that do not exist in the
615
// initial bundle list from installEntries.
616
uninstallBundles(curInitBundles, initialBundles, toRefresh);
617
618         // install the initialBundles that are not already installed.
619
ArrayList startBundles = new ArrayList(installEntries.length);
620         ArrayList lazyActivationBundles = new ArrayList(installEntries.length);
621         installBundles(initialBundles, curInitBundles, startBundles, lazyActivationBundles, toRefresh);
622
623         // If we installed/uninstalled something, force a refresh of all installed/uninstalled bundles
624
if (!toRefresh.isEmpty() && refreshPackages((Bundle[]) toRefresh.toArray(new Bundle[toRefresh.size()])))
625             return null; // cannot continue; refreshPackages shutdown the framework
626

627         // schedule all basic bundles to be started
628
Bundle[] startInitBundles = (Bundle[]) startBundles.toArray(new Bundle[startBundles.size()]);
629         Bundle[] lazyInitBundles = (Bundle[]) lazyActivationBundles.toArray(new Bundle[lazyActivationBundles.size()]);
630         startBundles(startInitBundles, lazyInitBundles);
631
632         if (debug)
633             System.out.println("Time to load bundles: " + (System.currentTimeMillis() - startTime)); //$NON-NLS-1$
634
return startInitBundles;
635     }
636
637     private static InitialBundle[] getInitialBundles(String JavaDoc[] installEntries) throws MalformedURLException {
638         searchCandidates.clear();
639         ArrayList result = new ArrayList(installEntries.length);
640         int defaultStartLevel = Integer.parseInt(FrameworkProperties.getProperty(PROP_BUNDLES_STARTLEVEL, DEFAULT_BUNDLES_STARTLEVEL));
641         String JavaDoc syspath = getSysPath();
642         // should canonicalize the syspath.
643
try {
644             syspath = new File(syspath).getCanonicalPath();
645         } catch (IOException ioe) {
646             // do nothing
647
}
648         for (int i = 0; i < installEntries.length; i++) {
649             String JavaDoc name = installEntries[i];
650             int level = defaultStartLevel;
651             boolean start = false;
652             int index = name.indexOf('@');
653             if (index >= 0) {
654                 String JavaDoc[] attributes = getArrayFromList(name.substring(index + 1, name.length()), ":"); //$NON-NLS-1$
655
name = name.substring(0, index);
656                 for (int j = 0; j < attributes.length; j++) {
657                     String JavaDoc attribute = attributes[j];
658                     if (attribute.equals("start")) //$NON-NLS-1$
659
start = true;
660                     else
661                         level = Integer.parseInt(attribute);
662                 }
663             }
664             URL location = searchForBundle(name, syspath);
665             if (location == null) {
666                 FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_BUNDLE_NOT_FOUND, installEntries[i]), 0, null, null);
667                 log.log(entry);
668                 // skip this entry
669
continue;
670             }
671             location = makeRelative(LocationManager.getInstallLocation().getURL(), location);
672             String JavaDoc locationString = INITIAL_LOCATION + location.toExternalForm();
673             result.add(new InitialBundle(locationString, location, level, start));
674         }
675         return (InitialBundle[]) result.toArray(new InitialBundle[result.size()]);
676     }
677
678     // returns true if the refreshPackages operation caused the framework to shutdown
679
private static boolean refreshPackages(Bundle[] bundles) {
680         ServiceReference packageAdminRef = context.getServiceReference(PackageAdmin.class.getName());
681         PackageAdmin packageAdmin = null;
682         if (packageAdminRef != null) {
683             packageAdmin = (PackageAdmin) context.getService(packageAdminRef);
684             if (packageAdmin == null)
685                 return false;
686         }
687         // TODO this is such a hack it is silly. There are still cases for race conditions etc
688
// but this should allow for some progress...
689
final Semaphore semaphore = new Semaphore(0);
690         FrameworkListener listener = new FrameworkListener() {
691             public void frameworkEvent(FrameworkEvent event) {
692                 if (event.getType() == FrameworkEvent.PACKAGES_REFRESHED)
693                     semaphore.release();
694             }
695         };
696         context.addFrameworkListener(listener);
697         packageAdmin.refreshPackages(bundles);
698         context.ungetService(packageAdminRef);
699         updateSplash(semaphore, listener);
700         if (isForcedRestart()) {
701             // wait for the system bundle to stop
702
Bundle systemBundle = context.getBundle(0);
703             int i = 0;
704             while (i < 5000 && (systemBundle.getState() & (Bundle.ACTIVE | Bundle.STOPPING)) != 0) {
705                 i += 200;
706                 try {
707                     Thread.sleep(200);
708                 } catch (InterruptedException JavaDoc e) {
709                     break;
710                 }
711             }
712             return true;
713         }
714         return false;
715     }
716
717     /**
718      * Invokes the OSGi Console on another thread
719      *
720      * @param equinox The current OSGi instance for the console to attach to
721      * @param consoleArgs An String array containing commands from the command line
722      * for the console to execute
723      * @param consolePort the port on which to run the console. Empty string implies the default port.
724      */

725     private static void startConsole(OSGi equinox, String JavaDoc[] consoleArgs, String JavaDoc consolePort) {
726         try {
727             String JavaDoc consoleClassName = FrameworkProperties.getProperty(PROP_CONSOLE_CLASS, DEFAULT_CONSOLE_CLASS);
728             Class JavaDoc consoleClass = Class.forName(consoleClassName);
729             Class JavaDoc[] parameterTypes;
730             Object JavaDoc[] parameters;
731             if (consolePort.length() == 0) {
732                 parameterTypes = new Class JavaDoc[] {OSGi.class, String JavaDoc[].class};
733                 parameters = new Object JavaDoc[] {equinox, consoleArgs};
734             } else {
735                 parameterTypes = new Class JavaDoc[] {OSGi.class, int.class, String JavaDoc[].class};
736                 parameters = new Object JavaDoc[] {equinox, new Integer JavaDoc(consolePort), consoleArgs};
737             }
738             Constructor JavaDoc constructor = consoleClass.getConstructor(parameterTypes);
739             console = (Runnable JavaDoc) constructor.newInstance(parameters);
740             Thread JavaDoc t = new Thread JavaDoc(console, CONSOLE_NAME);
741             t.start();
742         } catch (NumberFormatException JavaDoc nfe) {
743             // TODO log or something other than write on System.err
744
System.err.println(NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_INVALID_PORT, consolePort));
745         } catch (Exception JavaDoc ex) {
746             System.out.println(NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_FAILED_FIND, CONSOLE_NAME));
747         }
748
749     }
750
751     /**
752      * Stops the OSGi Command console
753      *
754      */

755     private static void stopConsole() {
756         if (console == null)
757             return;
758         try {
759             Method JavaDoc shutdownMethod = console.getClass().getMethod("shutdown", null); //$NON-NLS-1$
760
shutdownMethod.invoke(console, null);
761         } catch (Exception JavaDoc ex) {
762             System.err.println(ex.getMessage());
763         }
764     }
765
766     /**
767      * Creates and returns the adaptor
768      *
769      * @return a FrameworkAdaptor object
770      */

771     private static FrameworkAdaptor createAdaptor() throws Exception JavaDoc {
772         String JavaDoc adaptorClassName = FrameworkProperties.getProperty(PROP_ADAPTOR, DEFAULT_ADAPTOR_CLASS);
773         Class JavaDoc adaptorClass = Class.forName(adaptorClassName);
774         Class JavaDoc[] constructorArgs = new Class JavaDoc[] {String JavaDoc[].class};
775         Constructor JavaDoc constructor = adaptorClass.getConstructor(constructorArgs);
776         return (FrameworkAdaptor) constructor.newInstance(new Object JavaDoc[] {new String JavaDoc[0]});
777     }
778
779     private static String JavaDoc[] processCommandLine(String JavaDoc[] args) throws Exception JavaDoc {
780         EclipseEnvironmentInfo.setAllArgs(args);
781         if (args.length == 0) {
782             EclipseEnvironmentInfo.setFrameworkArgs(args);
783             EclipseEnvironmentInfo.setAllArgs(args);
784             return args;
785         }
786         int[] configArgs = new int[args.length];
787         configArgs[0] = -1; // need to initialize the first element to something that could not be an index.
788
int configArgIndex = 0;
789         for (int i = 0; i < args.length; i++) {
790             boolean found = false;
791             // check for args without parameters (i.e., a flag arg)
792

793             // check if debug should be enabled for the entire platform
794
// If this is the last arg or there is a following arg (i.e., arg+1 has a leading -),
795
// simply enable debug. Otherwise, assume that that the following arg is
796
// actually the filename of an options file. This will be processed below.
797
if (args[i].equalsIgnoreCase(DEBUG) && ((i + 1 == args.length) || ((i + 1 < args.length) && (args[i + 1].startsWith("-"))))) { //$NON-NLS-1$
798
FrameworkProperties.setProperty(PROP_DEBUG, ""); //$NON-NLS-1$
799
debug = true;
800                 found = true;
801             }
802
803             // check if development mode should be enabled for the entire platform
804
// If this is the last arg or there is a following arg (i.e., arg+1 has a leading -),
805
// simply enable development mode. Otherwise, assume that that the following arg is
806
// actually some additional development time class path entries. This will be processed below.
807
if (args[i].equalsIgnoreCase(DEV) && ((i + 1 == args.length) || ((i + 1 < args.length) && (args[i + 1].startsWith("-"))))) { //$NON-NLS-1$
808
FrameworkProperties.setProperty(PROP_DEV, ""); //$NON-NLS-1$
809
found = true;
810             }
811
812             // look for the initialization arg
813
if (args[i].equalsIgnoreCase(INITIALIZE)) {
814                 initialize = true;
815                 found = true;
816             }
817
818             // look for the clean flag.
819
if (args[i].equalsIgnoreCase(CLEAN)) {
820                 FrameworkProperties.setProperty(PROP_CLEAN, "true"); //$NON-NLS-1$
821
found = true;
822             }
823
824             // look for the consoleLog flag
825
if (args[i].equalsIgnoreCase(CONSOLE_LOG)) {
826                 FrameworkProperties.setProperty(PROP_CONSOLE_LOG, "true"); //$NON-NLS-1$
827
found = true;
828             }
829
830             // look for the console with no port.
831
if (args[i].equalsIgnoreCase(CONSOLE) && ((i + 1 == args.length) || ((i + 1 < args.length) && (args[i + 1].startsWith("-"))))) { //$NON-NLS-1$
832
FrameworkProperties.setProperty(PROP_CONSOLE, ""); //$NON-NLS-1$
833
found = true;
834             }
835
836             if (args[i].equalsIgnoreCase(NOEXIT)) {
837                 FrameworkProperties.setProperty(PROP_NOSHUTDOWN, "true"); //$NON-NLS-1$
838
found = true;
839             }
840
841             if (found) {
842                 configArgs[configArgIndex++] = i;
843                 continue;
844             }
845             // check for args with parameters. If we are at the last argument or if the next one
846
// has a '-' as the first character, then we can't have an arg with a parm so continue.
847
if (i == args.length - 1 || args[i + 1].startsWith("-")) { //$NON-NLS-1$
848
continue;
849             }
850             String JavaDoc arg = args[++i];
851
852             // look for the console and port.
853
if (args[i - 1].equalsIgnoreCase(CONSOLE)) {
854                 FrameworkProperties.setProperty(PROP_CONSOLE, arg);
855                 found = true;
856             }
857
858             // look for the configuration location .
859
if (args[i - 1].equalsIgnoreCase(CONFIGURATION)) {
860                 FrameworkProperties.setProperty(LocationManager.PROP_CONFIG_AREA, arg);
861                 found = true;
862             }
863
864             // look for the data location for this instance.
865
if (args[i - 1].equalsIgnoreCase(DATA)) {
866                 FrameworkProperties.setProperty(LocationManager.PROP_INSTANCE_AREA, arg);
867                 found = true;
868             }
869
870             // look for the user location for this instance.
871
if (args[i - 1].equalsIgnoreCase(USER)) {
872                 FrameworkProperties.setProperty(LocationManager.PROP_USER_AREA, arg);
873                 found = true;
874             }
875
876             // look for the development mode and class path entries.
877
if (args[i - 1].equalsIgnoreCase(DEV)) {
878                 FrameworkProperties.setProperty(PROP_DEV, arg);
879                 found = true;
880             }
881
882             // look for the debug mode and option file location.
883
if (args[i - 1].equalsIgnoreCase(DEBUG)) {
884                 FrameworkProperties.setProperty(PROP_DEBUG, arg);
885                 debug = true;
886                 found = true;
887             }
888
889             // look for the window system.
890
if (args[i - 1].equalsIgnoreCase(WS)) {
891                 FrameworkProperties.setProperty(PROP_WS, arg);
892                 found = true;
893             }
894
895             // look for the operating system
896
if (args[i - 1].equalsIgnoreCase(OS)) {
897                 FrameworkProperties.setProperty(PROP_OS, arg);
898                 found = true;
899             }
900
901             // look for the system architecture
902
if (args[i - 1].equalsIgnoreCase(ARCH)) {
903                 FrameworkProperties.setProperty(PROP_ARCH, arg);
904                 found = true;
905             }
906
907             // look for the nationality/language
908
if (args[i - 1].equalsIgnoreCase(NL)) {
909                 FrameworkProperties.setProperty(PROP_NL, arg);
910                 found = true;
911             }
912             // done checking for args. Remember where an arg was found
913
if (found) {
914                 configArgs[configArgIndex++] = i - 1;
915                 configArgs[configArgIndex++] = i;
916             }
917         }
918
919         // remove all the arguments consumed by this argument parsing
920
if (configArgIndex == 0) {
921             EclipseEnvironmentInfo.setFrameworkArgs(new String JavaDoc[0]);
922             EclipseEnvironmentInfo.setAppArgs(args);
923             return args;
924         }
925         String JavaDoc[] appArgs = new String JavaDoc[args.length - configArgIndex];
926         String JavaDoc[] frameworkArgs = new String JavaDoc[configArgIndex];
927         configArgIndex = 0;
928         int j = 0;
929         int k = 0;
930         for (int i = 0; i < args.length; i++) {
931             if (i == configArgs[configArgIndex]) {
932                 frameworkArgs[k++] = args[i];
933                 configArgIndex++;
934             } else
935                 appArgs[j++] = args[i];
936         }
937         EclipseEnvironmentInfo.setFrameworkArgs(frameworkArgs);
938         EclipseEnvironmentInfo.setAppArgs(appArgs);
939         return appArgs;
940     }
941
942     /**
943      * Returns the result of converting a list of comma-separated tokens into an array
944      *
945      * @return the array of string tokens
946      * @param prop the initial comma-separated string
947      */

948     private static String JavaDoc[] getArrayFromList(String JavaDoc prop, String JavaDoc separator) {
949         return ManifestElement.getArrayFromList(prop, separator);
950     }
951
952     protected static String JavaDoc getSysPath() {
953         String JavaDoc result = FrameworkProperties.getProperty(PROP_SYSPATH);
954         if (result != null)
955             return result;
956         result = getSysPathFromURL(FrameworkProperties.getProperty(PROP_FRAMEWORK));
957         if (result == null)
958             result = getSysPathFromCodeSource();
959         if (result == null)
960             throw new IllegalStateException JavaDoc("Can not find the system path."); //$NON-NLS-1$
961
if (Character.isUpperCase(result.charAt(0))) {
962             char[] chars = result.toCharArray();
963             chars[0] = Character.toLowerCase(chars[0]);
964             result = new String JavaDoc(chars);
965         }
966         FrameworkProperties.setProperty(PROP_SYSPATH, result);
967         return result;
968     }
969
970     private static String JavaDoc getSysPathFromURL(String JavaDoc urlSpec) {
971         if (urlSpec == null)
972             return null;
973         URL url = null;
974         try {
975             url = new URL(urlSpec);
976         } catch (MalformedURLException e) {
977             return null;
978         }
979         File fwkFile = new File(url.getFile());
980         fwkFile = new File(fwkFile.getAbsolutePath());
981         fwkFile = new File(fwkFile.getParent());
982         return fwkFile.getAbsolutePath();
983     }
984
985     private static String JavaDoc getSysPathFromCodeSource() {
986         ProtectionDomain JavaDoc pd = EclipseStarter.class.getProtectionDomain();
987         if (pd == null)
988             return null;
989         CodeSource JavaDoc cs = pd.getCodeSource();
990         if (cs == null)
991             return null;
992         URL url = cs.getLocation();
993         if (url == null)
994             return null;
995         String JavaDoc result = url.getFile();
996         if (result.endsWith(".jar")) { //$NON-NLS-1$
997
result = result.substring(0, result.lastIndexOf('/'));
998             if ("folder".equals(FrameworkProperties.getProperty(PROP_FRAMEWORK_SHAPE))) //$NON-NLS-1$
999
result = result.substring(0, result.lastIndexOf('/'));
1000        } else {
1001            if (result.endsWith("/")) //$NON-NLS-1$
1002
result = result.substring(0, result.length() - 1);
1003            result = result.substring(0, result.lastIndexOf('/'));
1004            result = result.substring(0, result.lastIndexOf('/'));
1005        }
1006        return result;
1007    }
1008
1009    private static Bundle[] getCurrentBundles(boolean includeInitial) {
1010        Bundle[] installed = context.getBundles();
1011        ArrayList initial = new ArrayList();
1012        for (int i = 0; i < installed.length; i++) {
1013            Bundle bundle = installed[i];
1014            if (bundle.getLocation().startsWith(INITIAL_LOCATION)) {
1015                if (includeInitial)
1016                    initial.add(bundle);
1017            } else if (!includeInitial && bundle.getBundleId() != 0)
1018                initial.add(bundle);
1019        }
1020        return (Bundle[]) initial.toArray(new Bundle[initial.size()]);
1021    }
1022
1023    private static Bundle getBundleByLocation(String JavaDoc location, Bundle[] bundles) {
1024        for (int i = 0; i < bundles.length; i++) {
1025            Bundle bundle = bundles[i];
1026            if (location.equalsIgnoreCase(bundle.getLocation()))
1027                return bundle;
1028        }
1029        return null;
1030    }
1031
1032    private static void uninstallBundles(Bundle[] curInitBundles, InitialBundle[] newInitBundles, List toRefresh) {
1033        for (int i = 0; i < curInitBundles.length; i++) {
1034            boolean found = false;
1035            for (int j = 0; j < newInitBundles.length; j++) {
1036                if (curInitBundles[i].getLocation().equalsIgnoreCase(newInitBundles[j].locationString)) {
1037                    found = true;
1038                    break;
1039                }
1040            }
1041            if (!found)
1042                try {
1043                    curInitBundles[i].uninstall();
1044                    toRefresh.add(curInitBundles[i]);
1045                } catch (BundleException e) {
1046                    FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_FAILED_UNINSTALL, curInitBundles[i].getLocation()), 0, e, null);
1047                    log.log(entry);
1048                }
1049        }
1050    }
1051
1052    private static void installBundles(InitialBundle[] initialBundles, Bundle[] curInitBundles, ArrayList startBundles, ArrayList lazyActivationBundles, List toRefresh) {
1053        ServiceReference reference = context.getServiceReference(StartLevel.class.getName());
1054        StartLevel startService = null;
1055        if (reference != null)
1056            startService = (StartLevel) context.getService(reference);
1057        try {
1058            for (int i = 0; i < initialBundles.length; i++) {
1059                Bundle osgiBundle = getBundleByLocation(initialBundles[i].locationString, curInitBundles);
1060                try {
1061                    // don't need to install if it is already installed
1062
if (osgiBundle == null) {
1063                        InputStream in = initialBundles[i].location.openStream();
1064                        osgiBundle = context.installBundle(initialBundles[i].locationString, in);
1065                        // only check for lazy activation header if this is a newly installed bundle and is not marked for persistent start
1066
if (!initialBundles[i].start && hasLazyActivationPolicy(osgiBundle))
1067                            lazyActivationBundles.add(osgiBundle);
1068                    }
1069                    // always set the startlevel incase it has changed (bug 111549)
1070
// this is a no-op if the level is the same as previous launch.
1071
if ((osgiBundle.getState() & Bundle.UNINSTALLED) == 0 && initialBundles[i].level >= 0 && startService != null)
1072                        startService.setBundleStartLevel(osgiBundle, initialBundles[i].level);
1073                    // if this bundle is supposed to be started then add it to the start list
1074
if (initialBundles[i].start)
1075                        startBundles.add(osgiBundle);
1076                    // include basic bundles in case they were not resolved before
1077
if ((osgiBundle.getState() & Bundle.INSTALLED) != 0)
1078                        toRefresh.add(osgiBundle);
1079                } catch (BundleException e) {
1080                    FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_FAILED_INSTALL, initialBundles[i].location), 0, e, null);
1081                    log.log(entry);
1082                } catch (IOException e) {
1083                    FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_FAILED_INSTALL, initialBundles[i].location), 0, e, null);
1084                    log.log(entry);
1085                }
1086            }
1087        } finally {
1088            if (reference != null)
1089                context.ungetService(reference);
1090        }
1091    }
1092
1093    private static boolean hasLazyActivationPolicy(Bundle target) {
1094        // check the bundle manifest to see if it defines a lazy activation policy
1095
Dictionary headers = target.getHeaders(""); //$NON-NLS-1$
1096
// first check to see if this is a fragment bundle
1097
String JavaDoc fragmentHost = (String JavaDoc) headers.get(Constants.FRAGMENT_HOST);
1098        if (fragmentHost != null)
1099            return false; // do not activate fragment bundles
1100
// look for the OSGi defined Bundle-ActivationPolicy header
1101
String JavaDoc activationPolicy = (String JavaDoc) headers.get(Constants.BUNDLE_ACTIVATIONPOLICY);
1102        try {
1103            if (activationPolicy != null) {
1104                ManifestElement[] elements = ManifestElement.parseHeader(Constants.BUNDLE_ACTIVATIONPOLICY, activationPolicy);
1105                if (elements != null && elements.length > 0) {
1106                    // if the value is "lazy" then it has a lazy activation poliyc
1107
if (Constants.ACTIVATION_LAZY.equals(elements[0].getValue()))
1108                        return true;
1109                }
1110            } else {
1111                // check for Eclipse specific lazy start headers "Eclipse-LazyStart" and "Eclipse-AutoStart"
1112
String JavaDoc eclipseLazyStart = (String JavaDoc) headers.get(Constants.ECLIPSE_LAZYSTART);
1113                if (eclipseLazyStart == null)
1114                    eclipseLazyStart = (String JavaDoc) headers.get(Constants.ECLIPSE_AUTOSTART);
1115                ManifestElement[] elements = ManifestElement.parseHeader(Constants.ECLIPSE_LAZYSTART, eclipseLazyStart);
1116                if (elements != null && elements.length > 0) {
1117                    // if the value is true then it is lazy activated
1118
if ("true".equals(elements[0].getValue())) //$NON-NLS-1$
1119
return true;
1120                    // otherwise it is only lazy activated if it defines an exceptions directive.
1121
else if (elements[0].getDirective("exceptions") != null) //$NON-NLS-1$
1122
return true;
1123                }
1124            }
1125        } catch (BundleException be) {
1126            // ignore this
1127
}
1128        return false;
1129    }
1130
1131    private static void startBundles(Bundle[] startBundles, Bundle[] lazyBundles) {
1132        for (int i = 0; i < startBundles.length; i++)
1133            startBundle(startBundles[i], 0);
1134        for (int i = 0; i < lazyBundles.length; i++)
1135            startBundle(lazyBundles[i], Bundle.START_ACTIVATION_POLICY);
1136    }
1137
1138    private static void startBundle(Bundle bundle, int options) {
1139        try {
1140            bundle.start(options);
1141        } catch (BundleException e) {
1142            if ((bundle.getState() & Bundle.RESOLVED) != 0) {
1143                // only log errors if the bundle is resolved
1144
FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_FAILED_START, bundle.getLocation()), 0, e, null);
1145                log.log(entry);
1146            }
1147        }
1148    }
1149
1150    private static void loadConfigurationInfo() {
1151        Location configArea = LocationManager.getConfigurationLocation();
1152        if (configArea == null)
1153            return;
1154
1155        URL location = null;
1156        try {
1157            location = new URL(configArea.getURL().toExternalForm() + LocationManager.CONFIG_FILE);
1158        } catch (MalformedURLException e) {
1159            // its ok. This should never happen
1160
}
1161        mergeProperties(FrameworkProperties.getProperties(), loadProperties(location));
1162    }
1163
1164    private static Properties loadProperties(URL location) {
1165        Properties result = new Properties();
1166        if (location == null)
1167            return result;
1168        try {
1169            InputStream in = location.openStream();
1170            try {
1171                result.load(in);
1172            } finally {
1173                in.close();
1174            }
1175        } catch (IOException e) {
1176            // its ok if there is no file. We'll just use the defaults for everything
1177
// TODO but it might be nice to log something with gentle wording (i.e., it is not an error)
1178
}
1179        return result;
1180    }
1181
1182    /**
1183     * Returns a URL which is equivalent to the given URL relative to the
1184     * specified base URL. Works only for file: URLs
1185     * @throws MalformedURLException
1186     */

1187    private static URL makeRelative(URL base, URL location) throws MalformedURLException {
1188        if (base == null)
1189            return location;
1190        if (!"file".equals(base.getProtocol())) //$NON-NLS-1$
1191
return location;
1192        if (!location.getProtocol().equals(REFERENCE_PROTOCOL))
1193            return location; // we can only make reference urls relative
1194
URL nonReferenceLocation = new URL(location.getPath());
1195        // if some URL component does not match, return the original location
1196
if (!base.getProtocol().equals(nonReferenceLocation.getProtocol()))
1197            return location;
1198        File locationPath = new File(nonReferenceLocation.getPath());
1199        // if location is not absolute, return original location
1200
if (!locationPath.isAbsolute())
1201            return location;
1202        File relativePath = makeRelative(new File(base.getPath()), locationPath);
1203        String JavaDoc urlPath = relativePath.getPath();
1204        if (File.separatorChar != '/')
1205            urlPath = urlPath.replace(File.separatorChar, '/');
1206        if (nonReferenceLocation.getPath().endsWith("/")) //$NON-NLS-1$
1207
// restore original trailing slash
1208
urlPath += '/';
1209        // couldn't use File to create URL here because it prepends the path with user.dir
1210
URL relativeURL = new URL(base.getProtocol(), base.getHost(), base.getPort(), urlPath);
1211        // now make it back to a reference URL
1212
relativeURL = new URL(REFERENCE_SCHEME + relativeURL.toExternalForm());
1213        return relativeURL;
1214    }
1215
1216    private static File makeRelative(File base, File location) {
1217        if (!location.isAbsolute())
1218            return location;
1219        File relative = new File(new FilePath(base).makeRelative(new FilePath(location)));
1220        return relative;
1221    }
1222
1223    private static void mergeProperties(Properties destination, Properties source) {
1224        for (Enumeration e = source.keys(); e.hasMoreElements();) {
1225            String JavaDoc key = (String JavaDoc) e.nextElement();
1226            String JavaDoc value = source.getProperty(key);
1227            if (destination.getProperty(key) == null)
1228                destination.put(key, value);
1229        }
1230    }
1231
1232    private static void setStartLevel(final int value) {
1233        ServiceReference reference = context.getServiceReference(StartLevel.class.getName());
1234        final StartLevel startLevel = reference != null ? (StartLevel) context.getService(reference) : null;
1235        if (startLevel == null)
1236            return;
1237        final Semaphore semaphore = new Semaphore(0);
1238        FrameworkListener listener = new FrameworkListener() {
1239            public void frameworkEvent(FrameworkEvent event) {
1240                if (event.getType() == FrameworkEvent.STARTLEVEL_CHANGED && startLevel.getStartLevel() == value)
1241                    semaphore.release();
1242            }
1243        };
1244        context.addFrameworkListener(listener);
1245        startLevel.setStartLevel(value);
1246        context.ungetService(reference);
1247        updateSplash(semaphore, listener);
1248    }
1249
1250    private static void updateSplash(Semaphore semaphore, FrameworkListener listener) {
1251        ServiceTracker monitorTracker = new ServiceTracker(context, StartupMonitor.class.getName(), null);
1252        monitorTracker.open();
1253        try {
1254            while (true) {
1255                StartupMonitor monitor = (StartupMonitor) monitorTracker.getService();
1256                if (monitor != null) {
1257                    try {
1258                        monitor.update();
1259                    } catch (Throwable JavaDoc e) {
1260                        // ignore exceptions thrown by the monitor
1261
}
1262                }
1263                // can we acquire the semaphore yet?
1264
if (semaphore.acquire(50))
1265                    break; //done
1266
//else still working, spin another update
1267
}
1268        } finally {
1269            if (listener != null)
1270                context.removeFrameworkListener(listener);
1271            monitorTracker.close();
1272        }
1273    }
1274
1275    /**
1276     * Searches for the given target directory immediately under
1277     * the given start location. If one is found then this location is returned;
1278     * otherwise an exception is thrown.
1279     *
1280     * @return the location where target directory was found
1281     * @param start the location to begin searching
1282     */

1283    private static String JavaDoc searchFor(final String JavaDoc target, String JavaDoc start) {
1284        String JavaDoc[] candidates = (String JavaDoc[]) searchCandidates.get(start);
1285        if (candidates == null) {
1286            candidates = new File(start).list();
1287            if (candidates != null)
1288                searchCandidates.put(start, candidates);
1289        }
1290        if (candidates == null)
1291            return null;
1292        String JavaDoc result = null;
1293        Object JavaDoc[] maxVersion = null;
1294        for (int i = 0; i < candidates.length; i++) {
1295            String JavaDoc candidateName = candidates[i];
1296            if (!candidateName.startsWith(target))
1297                continue;
1298            boolean simpleJar = false;
1299            if (candidateName.length() > target.length() && candidateName.charAt(target.length()) != '_') {
1300                // make sure this is not just a jar with no _version tacked on the end
1301
if (candidateName.length() == 4 + target.length() && candidateName.endsWith(".jar")) //$NON-NLS-1$
1302
simpleJar = true;
1303                else
1304                    // name does not match the target properly with an _version at the end
1305
continue;
1306            }
1307            // Note: directory with version suffix is always > than directory without version suffix
1308
String JavaDoc version = candidateName.length() > target.length() + 1 && candidateName.charAt(target.length()) == '_' ? candidateName.substring(target.length() + 1) : ""; //$NON-NLS-1$
1309
Object JavaDoc[] currentVersion = getVersionElements(version);
1310            if (currentVersion != null && compareVersion(maxVersion, currentVersion) < 0) {
1311                File candidate = new File(start, candidateName);
1312                // if simple jar; make sure it is really a file before accepting it
1313
if (!simpleJar || candidate.isFile()) {
1314                    result = candidate.getAbsolutePath();
1315                    maxVersion = currentVersion;
1316                }
1317            }
1318        }
1319        if (result == null)
1320            return null;
1321        return result.replace(File.separatorChar, '/') + "/"; //$NON-NLS-1$
1322
}
1323
1324    /**
1325     * Do a quick parse of version identifier so its elements can be correctly compared.
1326     * If we are unable to parse the full version, remaining elements are initialized
1327     * with suitable defaults.
1328     * @return an array of size 4; first three elements are of type Integer (representing
1329     * major, minor and service) and the fourth element is of type String (representing
1330     * qualifier). A value of null is returned if there are no valid Integers. Note, that
1331     * returning anything else will cause exceptions in the caller.
1332     */

1333    private static Object JavaDoc[] getVersionElements(String JavaDoc version) {
1334        Object JavaDoc[] result = {new Integer JavaDoc(-1), new Integer JavaDoc(-1), new Integer JavaDoc(-1), ""}; //$NON-NLS-1$
1335
StringTokenizer t = new StringTokenizer(version, "."); //$NON-NLS-1$
1336
String JavaDoc token;
1337        for (int i = 0; t.hasMoreTokens() && i < 4; i++) {
1338            token = t.nextToken();
1339            if (i < 3) {
1340                // major, minor or service ... numeric values
1341
try {
1342                    result[i] = new Integer JavaDoc(token);
1343                } catch (Exception JavaDoc e) {
1344                    if (i == 0)
1345                        return null; // return null if no valid numbers are present
1346
// invalid number format - use default numbers (-1) for the rest
1347
break;
1348                }
1349            } else {
1350                // qualifier ... string value
1351
result[i] = token;
1352            }
1353        }
1354        return result;
1355    }
1356
1357    /**
1358     * Compares version strings.
1359     * @return result of comparison, as integer;
1360     * <code><0</code> if left < right;
1361     * <code>0</code> if left == right;
1362     * <code>>0</code> if left > right;
1363     */

1364    private static int compareVersion(Object JavaDoc[] left, Object JavaDoc[] right) {
1365        if (left == null)
1366            return -1;
1367        int result = ((Integer JavaDoc) left[0]).compareTo((Integer JavaDoc) right[0]); // compare major
1368
if (result != 0)
1369            return result;
1370
1371        result = ((Integer JavaDoc) left[1]).compareTo((Integer JavaDoc) right[1]); // compare minor
1372
if (result != 0)
1373            return result;
1374
1375        result = ((Integer JavaDoc) left[2]).compareTo((Integer JavaDoc) right[2]); // compare service
1376
if (result != 0)
1377            return result;
1378
1379        return ((String JavaDoc) left[3]).compareTo((String JavaDoc) right[3]); // compare qualifier
1380
}
1381
1382    private static void initializeProperties() {
1383        // initialize some framework properties that must always be set
1384
if (FrameworkProperties.getProperty(PROP_FRAMEWORK) == null || FrameworkProperties.getProperty(PROP_INSTALL_AREA) == null) {
1385            CodeSource JavaDoc cs = EclipseStarter.class.getProtectionDomain().getCodeSource();
1386            if (cs == null)
1387                throw new IllegalArgumentException JavaDoc(NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_PROPS_NOT_SET, PROP_FRAMEWORK + ", " + PROP_INSTALL_AREA)); //$NON-NLS-1$
1388
URL url = cs.getLocation();
1389            // allow props to be preset
1390
if (FrameworkProperties.getProperty(PROP_FRAMEWORK) == null)
1391                FrameworkProperties.setProperty(PROP_FRAMEWORK, url.toExternalForm());
1392            if (FrameworkProperties.getProperty(PROP_INSTALL_AREA) == null) {
1393                String JavaDoc filePart = url.getFile();
1394                FrameworkProperties.setProperty(PROP_INSTALL_AREA, filePart.substring(0, filePart.lastIndexOf('/')));
1395            }
1396        }
1397        // always decode these properties
1398
FrameworkProperties.setProperty(PROP_FRAMEWORK, decode(FrameworkProperties.getProperty(PROP_FRAMEWORK)));
1399        FrameworkProperties.setProperty(PROP_INSTALL_AREA, decode(FrameworkProperties.getProperty(PROP_INSTALL_AREA)));
1400    }
1401
1402    private static void finalizeProperties() {
1403        // if check config is unknown and we are in dev mode,
1404
if (FrameworkProperties.getProperty(PROP_DEV) != null && FrameworkProperties.getProperty(PROP_CHECK_CONFIG) == null)
1405            FrameworkProperties.setProperty(PROP_CHECK_CONFIG, "true"); //$NON-NLS-1$
1406
}
1407
1408    private static class InitialBundle {
1409        public final String JavaDoc locationString;
1410        public final URL location;
1411        public final int level;
1412        public final boolean start;
1413
1414        InitialBundle(String JavaDoc locationString, URL location, int level, boolean start) {
1415            this.locationString = locationString;
1416            this.location = location;
1417            this.level = level;
1418            this.start = start;
1419        }
1420    }
1421
1422    private static String JavaDoc decode(String JavaDoc urlString) {
1423        //try to use Java 1.4 method if available
1424
try {
1425            Class JavaDoc clazz = URLDecoder.class;
1426            Method JavaDoc method = clazz.getDeclaredMethod("decode", new Class JavaDoc[] {String JavaDoc.class, String JavaDoc.class}); //$NON-NLS-1$
1427
//first encode '+' characters, because URLDecoder incorrectly converts
1428
//them to spaces on certain class library implementations.
1429
if (urlString.indexOf('+') >= 0) {
1430                int len = urlString.length();
1431                StringBuffer JavaDoc buf = new StringBuffer JavaDoc(len);
1432                for (int i = 0; i < len; i++) {
1433                    char c = urlString.charAt(i);
1434                    if (c == '+')
1435                        buf.append("%2B"); //$NON-NLS-1$
1436
else
1437                        buf.append(c);
1438                }
1439                urlString = buf.toString();
1440            }
1441            Object JavaDoc result = method.invoke(null, new Object JavaDoc[] {urlString, "UTF-8"}); //$NON-NLS-1$
1442
if (result != null)
1443                return (String JavaDoc) result;
1444        } catch (Exception JavaDoc e) {
1445            //JDK 1.4 method not found -- fall through and decode by hand
1446
}
1447        //decode URL by hand
1448
boolean replaced = false;
1449        byte[] encodedBytes = urlString.getBytes();
1450        int encodedLength = encodedBytes.length;
1451        byte[] decodedBytes = new byte[encodedLength];
1452        int decodedLength = 0;
1453        for (int i = 0; i < encodedLength; i++) {
1454            byte b = encodedBytes[i];
1455            if (b == '%') {
1456                byte enc1 = encodedBytes[++i];
1457                byte enc2 = encodedBytes[++i];
1458                b = (byte) ((hexToByte(enc1) << 4) + hexToByte(enc2));
1459                replaced = true;
1460            }
1461            decodedBytes[decodedLength++] = b;
1462        }
1463        if (!replaced)
1464            return urlString;
1465        try {
1466            return new String JavaDoc(decodedBytes, 0, decodedLength, "UTF-8"); //$NON-NLS-1$
1467
} catch (UnsupportedEncodingException e) {
1468            //use default encoding
1469
return new String JavaDoc(decodedBytes, 0, decodedLength);
1470        }
1471    }
1472
1473    private static int hexToByte(byte b) {
1474        switch (b) {
1475            case '0' :
1476                return 0;
1477            case '1' :
1478                return 1;
1479            case '2' :
1480                return 2;
1481            case '3' :
1482                return 3;
1483            case '4' :
1484                return 4;
1485            case '5' :
1486                return 5;
1487            case '6' :
1488                return 6;
1489            case '7' :
1490                return 7;
1491            case '8' :
1492                return 8;
1493            case '9' :
1494                return 9;
1495            case 'A' :
1496            case 'a' :
1497                return 10;
1498            case 'B' :
1499            case 'b' :
1500                return 11;
1501            case 'C' :
1502            case 'c' :
1503                return 12;
1504            case 'D' :
1505            case 'd' :
1506                return 13;
1507            case 'E' :
1508            case 'e' :
1509                return 14;
1510            case 'F' :
1511            case 'f' :
1512                return 15;
1513            default :
1514                throw new IllegalArgumentException JavaDoc("Switch error decoding URL"); //$NON-NLS-1$
1515
}
1516    }
1517
1518    /**
1519     * Sets the initial properties for the platform.
1520     * This method must be called before calling the {@link #run(String[], Runnable)} or
1521     * {@link #startup(String[], Runnable)} methods for the properties to be used in
1522     * a launched instance of the platform.
1523     * <p>
1524     * If the specified properties contains a null value then the key for that value
1525     * will be cleared from the properties of the platform.
1526     * </p>
1527     * @param initialProperties the initial properties to set for the platform.
1528     * @since 3.2
1529     */

1530    public static void setInitialProperties(Map initialProperties) {
1531        if (initialProperties == null || initialProperties.isEmpty())
1532            return;
1533        for (Iterator it = initialProperties.entrySet().iterator(); it.hasNext();) {
1534            Map.Entry entry = (Map.Entry) it.next();
1535            if (entry.getValue() != null)
1536                FrameworkProperties.setProperty((String JavaDoc) entry.getKey(), (String JavaDoc) entry.getValue());
1537            else
1538                FrameworkProperties.clearProperty((String JavaDoc) entry.getKey());
1539        }
1540    }
1541
1542    /**
1543     * Returns the context of the system bundle. A value of
1544     * <code>null</code> is returned if the platform is not running.
1545     * @return the context of the system bundle
1546     * @throws java.lang.SecurityException If the caller does not have the
1547     * appropriate <code>AdminPermission[system.bundle,CONTEXT]</code>, and
1548     * the Java Runtime Environment supports permissions.
1549     */

1550    public static BundleContext getSystemBundleContext() {
1551        if (context == null || !running)
1552            return null;
1553        return context.getBundle().getBundleContext();
1554    }
1555
1556    private static boolean isForcedRestart() {
1557        return Boolean.valueOf(FrameworkProperties.getProperty(PROP_FORCED_RESTART)).booleanValue();
1558    }
1559
1560    /*
1561     * NOTE: This is an internal/experimental method used by launchers that need to react when the framework
1562     * is shutdown internally.
1563     *
1564     * Adds a framework shutdown handler. <p>
1565     * A handler implements the {@link Runnable} interface. When the framework is shutdown
1566     * the {@link Runnable#run()} method is called for each registered handler. Handlers should
1567     * make no assumptions on the thread it is being called from. If a handler object is
1568     * registered multiple times it will be called once for each registration.
1569     * <p>
1570     * At the time a handler is called the framework is shutdown. Handlers must not depend on
1571     * a running framework to execute or attempt to load additional classes from bundles
1572     * installed in the framework.
1573     * @param handler the framework shutdown handler
1574     * @throws IllegalStateException if the platform is already running
1575     */

1576    static void internalAddFrameworkShutdownHandler(Runnable JavaDoc handler) {
1577        if (running)
1578            throw new IllegalStateException JavaDoc(EclipseAdaptorMsg.ECLIPSE_STARTUP_ALREADY_RUNNING);
1579
1580        if (shutdownHandlers == null)
1581            shutdownHandlers = new ArrayList();
1582
1583        shutdownHandlers.add(handler);
1584    }
1585
1586    /*
1587     * NOTE: This is an internal/experimental method used by launchers that need to react when the framework
1588     * is shutdown internally.
1589     *
1590     * Removes a framework shutdown handler. <p>
1591     * @param handler the framework shutdown handler
1592     * @throws IllegalStateException if the platform is already running
1593     */

1594    static void internalRemoveFrameworkShutdownHandler(Runnable JavaDoc handler) {
1595        if (running)
1596            throw new IllegalStateException JavaDoc(EclipseAdaptorMsg.ECLIPSE_STARTUP_ALREADY_RUNNING);
1597
1598        if (shutdownHandlers != null)
1599            shutdownHandlers.remove(handler);
1600    }
1601
1602    private static void registerFrameworkShutdownHandlers() {
1603        if (shutdownHandlers == null)
1604            return;
1605
1606        final Bundle systemBundle = context.getBundle();
1607        for (Iterator it = shutdownHandlers.iterator(); it.hasNext();) {
1608            final Runnable JavaDoc handler = (Runnable JavaDoc) it.next();
1609            BundleListener listener = new BundleListener() {
1610                public void bundleChanged(BundleEvent event) {
1611                    if (event.getBundle() == systemBundle && event.getType() == BundleEvent.STOPPED) {
1612                        handler.run();
1613                    }
1614                }
1615            };
1616            context.addBundleListener(listener);
1617        }
1618    }
1619}
1620
Popular Tags