• First of all, we take a look at class EclipseStarter
  •    1 /*******************************************************************************
       2  * Copyright (c) 2003, 2012 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;
      16 import java.lang.reflect.Method;
      17 import java.net.*;
      18 import java.security.CodeSource;
      19 import java.security.ProtectionDomain;
      20 import java.util.*;
      21 import org.eclipse.core.runtime.internal.adaptor.*;
      22 import org.eclipse.osgi.framework.adaptor.*;
      23 import org.eclipse.osgi.framework.internal.core.*;
      24 import org.eclipse.osgi.framework.internal.core.Constants;
      25 import org.eclipse.osgi.framework.log.FrameworkLog;
      26 import org.eclipse.osgi.framework.log.FrameworkLogEntry;
      27 import org.eclipse.osgi.internal.baseadaptor.BaseStorageHook;
      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  * @noextend This class is not intended to be subclassed by clients.
      55  */
      56 public class EclipseStarter {
      57     private static FrameworkAdaptor adaptor;
      58     private static BundleContext context;
      59     private static boolean initialize = false;
      60     public static boolean debug = false;
      61     private static boolean running = false;
      62     private static Framework framework = null;
      63     private static ServiceRegistration<?> defaultMonitorRegistration = null;
      64     private static ServiceRegistration<?> appLauncherRegistration = null;
      65     private static ServiceRegistration<?> splashStreamRegistration = null;
      66 
      67     // command line arguments
      68     private static final String CLEAN = "-clean"; //$NON-NLS-1$
      69     private static final String CONSOLE = "-console"; //$NON-NLS-1$
      70     private static final String CONSOLE_LOG = "-consoleLog"; //$NON-NLS-1$
      71     private static final String DEBUG = "-debug"; //$NON-NLS-1$
      72     private static final String INITIALIZE = "-initialize"; //$NON-NLS-1$
      73     private static final String DEV = "-dev"; //$NON-NLS-1$
      74     private static final String WS = "-ws"; //$NON-NLS-1$
      75     private static final String OS = "-os"; //$NON-NLS-1$
      76     private static final String ARCH = "-arch"; //$NON-NLS-1$
      77     private static final String NL = "-nl"; //$NON-NLS-1$
      78     private static final String NL_EXTENSIONS = "-nlExtensions"; //$NON-NLS-1$
      79     private static final String CONFIGURATION = "-configuration"; //$NON-NLS-1$    
      80     private static final String USER = "-user"; //$NON-NLS-1$
      81     private static final String NOEXIT = "-noExit"; //$NON-NLS-1$
      82     private static final String LAUNCHER = "-launcher"; //$NON-NLS-1$
      83 
      84     // this is more of an Eclipse argument but this OSGi implementation stores its 
      85     // metadata alongside Eclipse's.
      86     private static final String DATA = "-data"; //$NON-NLS-1$
      87 
      88     // System properties
      89     public static final String PROP_BUNDLES = "osgi.bundles"; //$NON-NLS-1$
      90     public static final String PROP_BUNDLES_STARTLEVEL = "osgi.bundles.defaultStartLevel"; //$NON-NLS-1$ //The start level used to install the bundles
      91     public static final String PROP_EXTENSIONS = "osgi.framework.extensions"; //$NON-NLS-1$
      92     public static final String PROP_INITIAL_STARTLEVEL = "osgi.startLevel"; //$NON-NLS-1$ //The start level when the fwl start
      93     public static final String PROP_DEBUG = "osgi.debug"; //$NON-NLS-1$
      94     public static final String PROP_DEV = "osgi.dev"; //$NON-NLS-1$
      95     public static final String PROP_CLEAN = "osgi.clean"; //$NON-NLS-1$
      96     public static final String PROP_CONSOLE = "osgi.console"; //$NON-NLS-1$
      97     public static final String PROP_CONSOLE_CLASS = "osgi.consoleClass"; //$NON-NLS-1$
      98     public static final String PROP_CHECK_CONFIG = "osgi.checkConfiguration"; //$NON-NLS-1$
      99     public static final String PROP_OS = "osgi.os"; //$NON-NLS-1$
     100     public static final String PROP_WS = "osgi.ws"; //$NON-NLS-1$
     101     public static final String PROP_NL = "osgi.nl"; //$NON-NLS-1$
     102     private static final String PROP_NL_EXTENSIONS = "osgi.nl.extensions"; //$NON-NLS-1$
     103     public static final String PROP_ARCH = "osgi.arch"; //$NON-NLS-1$
     104     public static final String PROP_ADAPTOR = "osgi.adaptor"; //$NON-NLS-1$
     105     public static final String PROP_SYSPATH = "osgi.syspath"; //$NON-NLS-1$
     106     public static final String PROP_LOGFILE = "osgi.logfile"; //$NON-NLS-1$
     107     public static final String PROP_FRAMEWORK = "osgi.framework"; //$NON-NLS-1$
     108     public static final String PROP_INSTALL_AREA = "osgi.install.area"; //$NON-NLS-1$
     109     public static final String PROP_FRAMEWORK_SHAPE = "osgi.framework.shape"; //$NON-NLS-1$ //the shape of the fwk (jar, or folder)
     110     public static final String PROP_NOSHUTDOWN = "osgi.noShutdown"; //$NON-NLS-1$
     111     private static final String PROP_FORCED_RESTART = "osgi.forcedRestart"; //$NON-NLS-1$
     112 
     113     public static final String PROP_EXITCODE = "eclipse.exitcode"; //$NON-NLS-1$
     114     public static final String PROP_EXITDATA = "eclipse.exitdata"; //$NON-NLS-1$
     115     public static final String PROP_CONSOLE_LOG = "eclipse.consoleLog"; //$NON-NLS-1$
     116     public static final String PROP_IGNOREAPP = "eclipse.ignoreApp"; //$NON-NLS-1$
     117     public static final String PROP_REFRESH_BUNDLES = "eclipse.refreshBundles"; //$NON-NLS-1$
     118     private static final String PROP_ALLOW_APPRELAUNCH = "eclipse.allowAppRelaunch"; //$NON-NLS-1$
     119     private static final String PROP_APPLICATION_LAUNCHDEFAULT = "eclipse.application.launchDefault"; //$NON-NLS-1$
     120 
     121     private static final String FILE_SCHEME = "file:"; //$NON-NLS-1$
     122     private static final String REFERENCE_SCHEME = "reference:"; //$NON-NLS-1$
     123     private static final String REFERENCE_PROTOCOL = "reference"; //$NON-NLS-1$
     124     private static final String INITIAL_LOCATION = "initial@"; //$NON-NLS-1$
     125     /** string containing the classname of the adaptor to be used in this framework instance */
     126     protected static final String DEFAULT_ADAPTOR_CLASS = "org.eclipse.osgi.baseadaptor.BaseAdaptor"; //$NON-NLS-1$
     127 
     128     private static final int DEFAULT_INITIAL_STARTLEVEL = 6; // default value for legacy purposes
     129     private static final String DEFAULT_BUNDLES_STARTLEVEL = "4"; //$NON-NLS-1$
     130 
     131     private static FrameworkLog log;
     132     // directory of serch candidates keyed by directory abs path -> directory listing (bug 122024)
     133     private static Map<String, String[]> searchCandidates = new HashMap<String, String[]>(4);
     134     private static EclipseAppLauncher appLauncher;
     135     private static List<Runnable> shutdownHandlers;
     136 
     137     private static ConsoleManager consoleMgr = null;
     138 
     139     /**
     140      * This is the main to start osgi.
     141      * It only works when the framework is being jared as a single jar
     142      */
     143     public static void main(String[] args) throws Exception {
     144         if (FrameworkProperties.getProperty("eclipse.startTime") == null) //$NON-NLS-1$
     145             FrameworkProperties.setProperty("eclipse.startTime", Long.toString(System.currentTimeMillis())); //$NON-NLS-1$
     146         if (FrameworkProperties.getProperty(PROP_NOSHUTDOWN) == null)
     147             FrameworkProperties.setProperty(PROP_NOSHUTDOWN, "true"); //$NON-NLS-1$
     148         // set the compatibility boot delegation flag to false to get "standard" OSGi behavior WRT boot delegation (bug 178477)
     149         if (FrameworkProperties.getProperty(Constants.OSGI_COMPATIBILITY_BOOTDELEGATION) == null)
     150             FrameworkProperties.setProperty(Constants.OSGI_COMPATIBILITY_BOOTDELEGATION, "false"); //$NON-NLS-1$
     151         Object result = run(args, null);
     152         if (result instanceof Integer && !Boolean.valueOf(FrameworkProperties.getProperty(PROP_NOSHUTDOWN)).booleanValue())
     153             System.exit(((Integer) result).intValue());
     154     }
     155 
     156     /**
     157      * Launches the platform and runs a single application. The application is either identified
     158      * in the given arguments (e.g., -application &lt;app id&gt;) or in the <code>eclipse.application</code> 
     159      * System property.  This convenience method starts 
     160      * up the platform, runs the indicated application, and then shuts down the 
     161      * platform. The platform must not be running already. 
     162      * 
     163      * @param args the command line-style arguments used to configure the platform
     164      * @param endSplashHandler the block of code to run to tear down the splash 
     165      *     screen or <code>null</code> if no tear down is required
     166      * @return the result of running the application
     167      * @throws Exception if anything goes wrong
     168      */
     169     public static Object run(String[] args, Runnable endSplashHandler) throws Exception {
     170         if (Profile.PROFILE && Profile.STARTUP)
     171             Profile.logEnter("EclipseStarter.run()", null); //$NON-NLS-1$
     172         if (running)
     173             throw new IllegalStateException(EclipseAdaptorMsg.ECLIPSE_STARTUP_ALREADY_RUNNING);
     174         boolean startupFailed = true;
     175         try {
     176             startup(args, endSplashHandler);
     177             startupFailed = false;
     178             if (Boolean.valueOf(FrameworkProperties.getProperty(PROP_IGNOREAPP)).booleanValue() || isForcedRestart())
     179                 return null;
     180             return run(null);
     181         } catch (Throwable e) {
     182             // ensure the splash screen is down
     183             if (endSplashHandler != null)
     184                 endSplashHandler.run();
     185             // may use startupFailed to understand where the error happened
     186             FrameworkLogEntry logEntry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, startupFailed ? EclipseAdaptorMsg.ECLIPSE_STARTUP_STARTUP_ERROR : EclipseAdaptorMsg.ECLIPSE_STARTUP_APP_ERROR, 1, e, null);
     187             if (log != null)
     188                 log.log(logEntry);
     189             else
     190                 // TODO desperate measure - ideally, we should write this to disk (a la Main.log)
     191                 e.printStackTrace();
     192         } finally {
     193             try {
     194                 // The application typically sets the exit code however the framework can request that
     195                 // it be re-started. We need to check for this and potentially override the exit code.
     196                 if (isForcedRestart())
     197                     FrameworkProperties.setProperty(PROP_EXITCODE, "23"); //$NON-NLS-1$
     198                 if (!Boolean.valueOf(FrameworkProperties.getProperty(PROP_NOSHUTDOWN)).booleanValue())
     199                     shutdown();
     200             } catch (Throwable e) {
     201                 FrameworkLogEntry logEntry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, EclipseAdaptorMsg.ECLIPSE_STARTUP_SHUTDOWN_ERROR, 1, e, null);
     202                 if (log != null)
     203                     log.log(logEntry);
     204                 else
     205                     // TODO desperate measure - ideally, we should write this to disk (a la Main.log)
     206                     e.printStackTrace();
     207             }
     208             if (Profile.PROFILE && Profile.STARTUP)
     209                 Profile.logExit("EclipseStarter.run()"); //$NON-NLS-1$
     210             if (Profile.PROFILE) {
     211                 String report = Profile.getProfileLog();
     212                 // avoiding writing to the console if there is nothing to print
     213                 if (report != null && report.length() > 0)
     214                     System.out.println(report);
     215             }
     216         }
     217         // we only get here if an error happened
     218         if (FrameworkProperties.getProperty(PROP_EXITCODE) == null) {
     219             FrameworkProperties.setProperty(PROP_EXITCODE, "13"); //$NON-NLS-1$
     220             FrameworkProperties.setProperty(PROP_EXITDATA, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_ERROR_CHECK_LOG, log == null ? null : log.getFile().getPath()));
     221         }
     222         return null;
     223     }
     224 
     225     /**
     226      * Returns true if the platform is already running, false otherwise.
     227      * @return whether or not the platform is already running
     228      */
     229     public static boolean isRunning() {
     230         return running;
     231     }
     232 
     233     /**
     234      * Starts the platform and sets it up to run a single application. The application is either identified
     235      * in the given arguments (e.g., -application &lt;app id&gt;) or in the <code>eclipse.application</code>
     236      * System property.  The platform must not be running already. 
     237      * <p>
     238      * The given runnable (if not <code>null</code>) is used to tear down the splash screen if required.
     239      * </p>
     240      * @param args the arguments passed to the application
     241      * @return BundleContext the context of the system bundle
     242      * @throws Exception if anything goes wrong
     243      */
     244     public static BundleContext startup(String[] args, Runnable endSplashHandler) throws Exception {
     245         if (Profile.PROFILE && Profile.STARTUP)
     246             Profile.logEnter("EclipseStarter.startup()", null); //$NON-NLS-1$
     247         if (running)
     248             throw new IllegalStateException(EclipseAdaptorMsg.ECLIPSE_STARTUP_ALREADY_RUNNING);
     249         FrameworkProperties.initializeProperties();
     250         processCommandLine(args);
     251         LocationManager.initializeLocations();
     252         loadConfigurationInfo();
     253         finalizeProperties();
     254         if (Profile.PROFILE)
     255             Profile.initProps(); // catch any Profile properties set in eclipse.properties...
     256         if (Profile.PROFILE && Profile.STARTUP)
     257             Profile.logTime("EclipseStarter.startup()", "props inited"); //$NON-NLS-1$ //$NON-NLS-2$
     258         adaptor = createAdaptor();
     259         log = adaptor.getFrameworkLog();
     260         if (Profile.PROFILE && Profile.STARTUP)
     261             Profile.logTime("EclipseStarter.startup()", "adapter created"); //$NON-NLS-1$ //$NON-NLS-2$
     262         framework = new Framework(adaptor);
     263         if (Profile.PROFILE && Profile.STARTUP)
     264             Profile.logTime("EclipseStarter.startup()", "OSGi created"); //$NON-NLS-1$ //$NON-NLS-2$
     265         context = framework.getBundle(0).getBundleContext();
     266         registerFrameworkShutdownHandlers();
     267         publishSplashScreen(endSplashHandler);
     268         if (Profile.PROFILE && Profile.STARTUP)
     269             Profile.logTime("EclipseStarter.startup()", "osgi launched"); //$NON-NLS-1$ //$NON-NLS-2$
     270         consoleMgr = ConsoleManager.startConsole(framework);
     271         if (Profile.PROFILE && Profile.STARTUP) {
     272             Profile.logTime("EclipseStarter.startup()", "console started"); //$NON-NLS-1$ //$NON-NLS-2$
     273         }
     274         framework.launch();
     275         // save the cached timestamp before loading basic bundles; this is needed so we can do a proper timestamp check when logging resolver errors
     276         long stateStamp = adaptor.getState().getTimeStamp();
     277         Bundle[] startBundles = loadBasicBundles();
     278 
     279         if (startBundles == null || ("true".equals(FrameworkProperties.getProperty(PROP_REFRESH_BUNDLES)) && refreshPackages(getCurrentBundles(false)))) { //$NON-NLS-1$
     280             waitForShutdown();
     281             return context; // cannot continue; loadBasicBundles caused refreshPackages to shutdown the framework
     282         }
     283 
     284         if (Profile.PROFILE && Profile.STARTUP)
     285             Profile.logTime("EclipseStarter.startup()", "loading basic bundles"); //$NON-NLS-1$ //$NON-NLS-2$
     286 
     287         // set the framework start level to the ultimate value.  This will actually start things
     288         // running if they are persistently active.
     289         setStartLevel(getStartLevel());
     290         if (Profile.PROFILE && Profile.STARTUP)
     291             Profile.logTime("EclipseStarter.startup()", "StartLevel set"); //$NON-NLS-1$ //$NON-NLS-2$
     292         // they should all be active by this time
     293         ensureBundlesActive(startBundles);
     294 
     295         // in the case where the built-in console is disabled we should try to start the console bundle
     296         try {
     297             consoleMgr.checkForConsoleBundle();
     298         } catch (BundleException e) {
     299             FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, e.getMessage(), 0, e, null);
     300             log.log(entry);
     301         }
     302         if (debug || FrameworkProperties.getProperty(PROP_DEV) != null)
     303             // only spend time showing unresolved bundles in dev/debug mode and the state has changed
     304             if (stateStamp != adaptor.getState().getTimeStamp())
     305                 logUnresolvedBundles(context.getBundles());
     306         running = true;
     307         if (Profile.PROFILE && Profile.STARTUP)
     308             Profile.logExit("EclipseStarter.startup()"); //$NON-NLS-1$
     309         return context;
     310     }
     311 
     312     private static int getStartLevel() {
     313         String level = FrameworkProperties.getProperty(PROP_INITIAL_STARTLEVEL);
     314         if (level != null)
     315             try {
     316                 return Integer.parseInt(level);
     317             } catch (NumberFormatException e) {
     318                 if (debug)
     319                     System.out.println("Start level = " + level + "  parsed. Using hardcoded default: 6"); //$NON-NLS-1$ //$NON-NLS-2$
     320             }
     321         return DEFAULT_INITIAL_STARTLEVEL;
     322     }
     323 
     324     /**
     325      * Runs the application for which the platform was started. The platform 
     326      * must be running. 
     327      * <p>
     328      * The given argument is passed to the application being run.  If it is <code>null</code>
     329      * then the command line arguments used in starting the platform, and not consumed
     330      * by the platform code, are passed to the application as a <code>String[]</code>.
     331      * </p>
     332      * @param argument the argument passed to the application. May be <code>null</code>
     333      * @return the result of running the application
     334      * @throws Exception if anything goes wrong
     335      */
     336     public static Object run(Object argument) throws Exception {
     337         if (Profile.PROFILE && Profile.STARTUP)
     338             Profile.logEnter("EclipseStarter.run(Object)()", null); //$NON-NLS-1$
     339         if (!running)
     340             throw new IllegalStateException(EclipseAdaptorMsg.ECLIPSE_STARTUP_NOT_RUNNING);
     341         // if we are just initializing, do not run the application just return.
     342         if (initialize)
     343             return new Integer(0);
     344         try {
     345             if (appLauncher == null) {
     346                 boolean launchDefault = Boolean.valueOf(FrameworkProperties.getProperty(PROP_APPLICATION_LAUNCHDEFAULT, "true")).booleanValue(); //$NON-NLS-1$
     347                 // create the ApplicationLauncher and register it as a service
     348                 appLauncher = new EclipseAppLauncher(context, Boolean.valueOf(FrameworkProperties.getProperty(PROP_ALLOW_APPRELAUNCH)).booleanValue(), launchDefault, log);
     349                 appLauncherRegistration = context.registerService(ApplicationLauncher.class.getName(), appLauncher, null);
     350                 // must start the launcher AFTER service restration because this method 
     351                 // blocks and runs the application on the current thread.  This method 
     352                 // will return only after the application has stopped.
     353                 return appLauncher.start(argument);
     354             }
     355             return appLauncher.reStart(argument);
     356         } catch (Exception e) {
     357             if (log != null && context != null) // context can be null if OSGi failed to launch (bug 151413)
     358                 logUnresolvedBundles(context.getBundles());
     359             throw e;
     360         }
     361     }
     362 
     363     /**
     364      * Shuts down the Platform. The state of the Platform is not automatically 
     365      * saved before shutting down. 
     366      * <p>
     367      * On return, the Platform will no longer be running (but could be re-launched 
     368      * with another call to startup). If relaunching, care must be taken to reinitialize
     369      * any System properties which the platform uses (e.g., osgi.instance.area) as
     370      * some policies in the platform do not allow resetting of such properties on 
     371      * subsequent runs.
     372      * </p><p>
     373      * Any objects handed out by running Platform, 
     374      * including Platform runnables obtained via getRunnable, will be 
     375      * permanently invalid. The effects of attempting to invoke methods 
     376      * on invalid objects is undefined. 
     377      * </p>
     378      * @throws Exception if anything goes wrong
     379      */
     380     public static void shutdown() throws Exception {
     381         if (!running || framework == null)
     382             return;
     383         if (appLauncherRegistration != null)
     384             appLauncherRegistration.unregister();
     385         if (splashStreamRegistration != null)
     386             splashStreamRegistration.unregister();
     387         if (defaultMonitorRegistration != null)
     388             defaultMonitorRegistration.unregister();
     389         if (appLauncher != null)
     390             appLauncher.shutdown();
     391         appLauncherRegistration = null;
     392         appLauncher = null;
     393         splashStreamRegistration = null;
     394         defaultMonitorRegistration = null;
     395         if (consoleMgr != null) {
     396             consoleMgr.stopConsole();
     397             consoleMgr = null;
     398         }
     399         framework.close();
     400         framework = null;
     401         context = null;
     402         running = false;
     403     }
     404 
     405     private static void ensureBundlesActive(Bundle[] bundles) {
     406         ServiceTracker<StartLevel, StartLevel> 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<StartLevel, StartLevel>(context, StartLevel.class.getName(), null);
     418                         tracker.open();
     419                     }
     420                     StartLevel sl = 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<BundleDescription, List<VersionConstraint>> missing = new HashMap<BundleDescription, List<VersionConstraint>>();
     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             List<VersionConstraint> constraints = missing.get(bundle);
     453             if (constraints == null) {
     454                 constraints = new ArrayList<VersionConstraint>();
     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<BundleDescription> iter = missing.keySet().iterator(); iter.hasNext(); rootIndex++) {
     465                 BundleDescription description = iter.next();
     466                 String symbolicName = description.getSymbolicName() == null ? FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME : description.getSymbolicName();
     467                 String generalMessage = NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_ERROR_BUNDLE_NOT_RESOLVED, description.getLocation());
     468                 List<VersionConstraint> constraints = 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(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         List<FrameworkLogEntry> allChildren = new ArrayList<FrameworkLogEntry>();
     480         for (int i = 0; i < bundles.length; i++)
     481             if (bundles[i].getState() == Bundle.INSTALLED) {
     482                 String symbolicName = bundles[i].getSymbolicName() == null ? FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME : bundles[i].getSymbolicName();
     483                 String 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, allChildren.toArray(new FrameworkLogEntry[allChildren.size()])));
     508     }
     509 
     510     private static void publishSplashScreen(final Runnable endSplashHandler) {
     511         if (endSplashHandler == null)
     512             return;
     513         // register the output stream to the launcher if it exists
     514         try {
     515             Method method = endSplashHandler.getClass().getMethod("getOutputStream", new Class[0]); //$NON-NLS-1$
     516             Object outputStream = method.invoke(endSplashHandler, new Object[0]);
     517             if (outputStream instanceof OutputStream) {
     518                 Dictionary<String, Object> osProperties = new Hashtable<String, Object>();
     519                 osProperties.put("name", "splashstream"); //$NON-NLS-1$//$NON-NLS-2$
     520                 splashStreamRegistration = context.registerService(OutputStream.class.getName(), outputStream, osProperties);
     521             }
     522         } catch (Exception ex) {
     523             // ignore
     524         }
     525         // keep this splash handler as the default startup monitor
     526         try {
     527             Dictionary<String, Object> monitorProps = new Hashtable<String, Object>();
     528             monitorProps.put(Constants.SERVICE_RANKING, new Integer(Integer.MIN_VALUE));
     529             defaultMonitorRegistration = context.registerService(StartupMonitor.class.getName(), new DefaultStartupMonitor(endSplashHandler), monitorProps);
     530         } catch (IllegalStateException e) {
     531             //splash handler did not provide the necessary methods, ignore it
     532         }
     533     }
     534 
     535     @SuppressWarnings("deprecation")
     536     private static URL searchForBundle(String name, String parent) throws MalformedURLException {
     537         URL url = null;
     538         File fileLocation = null;
     539         boolean reference = false;
     540         try {
     541             new URL(name); // quick check to see if the name is a valid URL
     542             url = new URL(new File(parent).toURL(), name);
     543         } catch (MalformedURLException e) {
     544             // TODO this is legacy support for non-URL names.  It should be removed eventually.
     545             // if name was not a URL then construct one.  
     546             // Assume it should be a reference and that it is relative.  This support need not 
     547             // be robust as it is temporary..
     548             File child = new File(name);
     549             fileLocation = child.isAbsolute() ? child : new File(parent, name);
     550             url = new URL(REFERENCE_PROTOCOL, null, fileLocation.toURL().toExternalForm());
     551             reference = true;
     552         }
     553         // if the name was a URL then see if it is relative.  If so, insert syspath.
     554         if (!reference) {
     555             URL baseURL = url;
     556             // if it is a reference URL then strip off the reference: and set base to the file:...
     557             if (url.getProtocol().equals(REFERENCE_PROTOCOL)) {
     558                 reference = true;
     559                 String baseSpec = url.getFile();
     560                 if (baseSpec.startsWith(FILE_SCHEME)) {
     561                     File child = new File(baseSpec.substring(5));
     562                     baseURL = child.isAbsolute() ? child.toURL() : new File(parent, child.getPath()).toURL();
     563                 } else
     564                     baseURL = new URL(baseSpec);
     565             }
     566 
     567             fileLocation = new File(baseURL.getFile());
     568             // if the location is relative, prefix it with the parent
     569             if (!fileLocation.isAbsolute())
     570                 fileLocation = new File(parent, fileLocation.toString());
     571         }
     572         // If the result is a reference then search for the real result and 
     573         // reconstruct the answer.
     574         if (reference) {
     575             String result = searchFor(fileLocation.getName(), new File(fileLocation.getParent()).getAbsolutePath());
     576             if (result != null)
     577                 url = new URL(REFERENCE_PROTOCOL, null, FILE_SCHEME + result);
     578             else
     579                 return null;
     580         }
     581 
     582         // finally we have something worth trying    
     583         try {
     584             URLConnection result = url.openConnection();
     585             result.connect();
     586             return url;
     587         } catch (IOException e) {
     588             //            int i = location.lastIndexOf('_');
     589             //            return i == -1? location : location.substring(0, i);
     590             return null;
     591         }
     592     }
     593 
     594     /*
     595      * Ensure all basic bundles are installed, resolved and scheduled to start. Returns an array containing
     596      * all basic bundles that are marked to start. 
     597      * Returns null if the framework has been shutdown as a result of refreshPackages
     598      */
     599     private static Bundle[] loadBasicBundles() {
     600         long startTime = System.currentTimeMillis();
     601         String osgiBundles = FrameworkProperties.getProperty(PROP_BUNDLES);
     602         String osgiExtensions = FrameworkProperties.getProperty(PROP_EXTENSIONS);
     603         if (osgiExtensions != null && osgiExtensions.length() > 0) {
     604             osgiBundles = osgiExtensions + ',' + osgiBundles;
     605             FrameworkProperties.setProperty(PROP_BUNDLES, osgiBundles);
     606         }
     607         String[] installEntries = getArrayFromList(osgiBundles, ","); //$NON-NLS-1$
     608         // get the initial bundle list from the installEntries
     609         InitialBundle[] initialBundles = getInitialBundles(installEntries);
     610         // get the list of currently installed initial bundles from the framework
     611         Bundle[] curInitBundles = getCurrentBundles(true);
     612 
     613         // list of bundles to be refreshed
     614         List<Bundle> toRefresh = new ArrayList<Bundle>(curInitBundles.length);
     615         // uninstall any of the currently installed bundles that do not exist in the 
     616         // initial bundle list from installEntries.
     617         uninstallBundles(curInitBundles, initialBundles, toRefresh);
     618 
     619         // install the initialBundles that are not already installed.
     620         List<Bundle> startBundles = new ArrayList<Bundle>(installEntries.length);
     621         List<Bundle> lazyActivationBundles = new ArrayList<Bundle>(installEntries.length);
     622         installBundles(initialBundles, curInitBundles, startBundles, lazyActivationBundles, toRefresh);
     623 
     624         // If we installed/uninstalled something, force a refresh of all installed/uninstalled bundles
     625         if (!toRefresh.isEmpty() && refreshPackages(toRefresh.toArray(new Bundle[toRefresh.size()])))
     626             return null; // cannot continue; refreshPackages shutdown the framework
     627 
     628         // schedule all basic bundles to be started
     629         Bundle[] startInitBundles = startBundles.toArray(new Bundle[startBundles.size()]);
     630         Bundle[] lazyInitBundles = lazyActivationBundles.toArray(new Bundle[lazyActivationBundles.size()]);
     631         startBundles(startInitBundles, lazyInitBundles);
     632 
     633         if (debug)
     634             System.out.println("Time to load bundles: " + (System.currentTimeMillis() - startTime)); //$NON-NLS-1$
     635         return startInitBundles;
     636     }
     637 
     638     private static InitialBundle[] getInitialBundles(String[] installEntries) {
     639         searchCandidates.clear();
     640         List<InitialBundle> result = new ArrayList<InitialBundle>(installEntries.length);
     641         int defaultStartLevel = Integer.parseInt(FrameworkProperties.getProperty(PROP_BUNDLES_STARTLEVEL, DEFAULT_BUNDLES_STARTLEVEL));
     642         String syspath = getSysPath();
     643         // should canonicalize the syspath.
     644         try {
     645             syspath = new File(syspath).getCanonicalPath();
     646         } catch (IOException ioe) {
     647             // do nothing
     648         }
     649         for (int i = 0; i < installEntries.length; i++) {
     650             String name = installEntries[i];
     651             int level = defaultStartLevel;
     652             boolean start = false;
     653             int index = name.lastIndexOf('@');
     654             if (index >= 0) {
     655                 String[] attributes = getArrayFromList(name.substring(index + 1, name.length()), ":"); //$NON-NLS-1$
     656                 for (int j = 0; j < attributes.length; j++) {
     657                     String attribute = attributes[j];
     658                     if (attribute.equals("start")) //$NON-NLS-1$
     659                         start = true;
     660                     else {
     661                         try {
     662                             level = Integer.parseInt(attribute);
     663                         } catch (NumberFormatException e) { // bug 188089
     664                             index = name.length();
     665                             continue;
     666                         }
     667                     }
     668                 }
     669                 name = name.substring(0, index);
     670             }
     671             try {
     672                 URL location = searchForBundle(name, syspath);
     673                 if (location == null) {
     674                     FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_BUNDLE_NOT_FOUND, installEntries[i]), 0, null, null);
     675                     log.log(entry);
     676                     // skip this entry
     677                     continue;
     678                 }
     679                 location = makeRelative(LocationManager.getInstallLocation().getURL(), location);
     680                 String locationString = INITIAL_LOCATION + location.toExternalForm();
     681                 result.add(new InitialBundle(locationString, location, level, start));
     682             } catch (IOException e) {
     683                 log.log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, e.getMessage(), 0, e, null));
     684             }
     685         }
     686         return result.toArray(new InitialBundle[result.size()]);
     687     }
     688 
     689     // returns true if the refreshPackages operation caused the framework to shutdown
     690     private static boolean refreshPackages(Bundle[] bundles) {
     691         ServiceReference<?> packageAdminRef = context.getServiceReference(PackageAdmin.class.getName());
     692         PackageAdmin packageAdmin = null;
     693         if (packageAdminRef != null)
     694             packageAdmin = (PackageAdmin) context.getService(packageAdminRef);
     695         if (packageAdmin == null)
     696             return false;
     697         // TODO this is such a hack it is silly.  There are still cases for race conditions etc
     698         // but this should allow for some progress...
     699         final Semaphore semaphore = new Semaphore(0);
     700         StartupEventListener listener = new StartupEventListener(semaphore, FrameworkEvent.PACKAGES_REFRESHED);
     701         context.addFrameworkListener(listener);
     702         context.addBundleListener(listener);
     703         packageAdmin.refreshPackages(bundles);
     704         context.ungetService(packageAdminRef);
     705         updateSplash(semaphore, listener);
     706         if (isForcedRestart())
     707             return true;
     708         return false;
     709     }
     710 
     711     private static void waitForShutdown() {
     712         if (!isForcedRestart())
     713             return;
     714         // wait for the system bundle to stop
     715         Bundle systemBundle = framework.getBundle(0);
     716         int i = 0;
     717         while (i < 5000 && (systemBundle.getState() & (Bundle.STARTING | Bundle.ACTIVE | Bundle.STOPPING)) != 0) {
     718             i += 200;
     719             try {
     720                 Thread.sleep(200);
     721             } catch (InterruptedException e) {
     722                 break;
     723             }
     724         }
     725     }
     726 
     727     /**
     728      *  Creates and returns the adaptor
     729      *
     730      *  @return a FrameworkAdaptor object
     731      */
     732     private static FrameworkAdaptor createAdaptor() throws Exception {
     733         String adaptorClassName = FrameworkProperties.getProperty(PROP_ADAPTOR, DEFAULT_ADAPTOR_CLASS);
     734         Class<?> adaptorClass = Class.forName(adaptorClassName);
     735         Class<?>[] constructorArgs = new Class[] {String[].class};
     736         Constructor<?> constructor = adaptorClass.getConstructor(constructorArgs);
     737         return (FrameworkAdaptor) constructor.newInstance(new Object[] {new String[0]});
     738     }
     739 
     740     private static String[] processCommandLine(String[] args) throws Exception {
     741         EclipseEnvironmentInfo.setAllArgs(args);
     742         if (args.length == 0) {
     743             EclipseEnvironmentInfo.setFrameworkArgs(args);
     744             EclipseEnvironmentInfo.setAllArgs(args);
     745             return args;
     746         }
     747         int[] configArgs = new int[args.length];
     748         configArgs[0] = -1; // need to initialize the first element to something that could not be an index.
     749         int configArgIndex = 0;
     750         for (int i = 0; i < args.length; i++) {
     751             boolean found = false;
     752             // check for args without parameters (i.e., a flag arg)
     753 
     754             // check if debug should be enabled for the entire platform
     755             // If this is the last arg or there is a following arg (i.e., arg+1 has a leading -), 
     756             // simply enable debug.  Otherwise, assume that that the following arg is
     757             // actually the filename of an options file.  This will be processed below.
     758             if (args[i].equalsIgnoreCase(DEBUG) && ((i + 1 == args.length) || ((i + 1 < args.length) && (args[i + 1].startsWith("-"))))) { //$NON-NLS-1$
     759                 FrameworkProperties.setProperty(PROP_DEBUG, ""); //$NON-NLS-1$
     760                 debug = true;
     761                 found = true;
     762             }
     763 
     764             // check if development mode should be enabled for the entire platform
     765             // If this is the last arg or there is a following arg (i.e., arg+1 has a leading -), 
     766             // simply enable development mode.  Otherwise, assume that that the following arg is
     767             // actually some additional development time class path entries.  This will be processed below.
     768             if (args[i].equalsIgnoreCase(DEV) && ((i + 1 == args.length) || ((i + 1 < args.length) && (args[i + 1].startsWith("-"))))) { //$NON-NLS-1$
     769                 FrameworkProperties.setProperty(PROP_DEV, ""); //$NON-NLS-1$
     770                 found = true;
     771             }
     772 
     773             // look for the initialization arg
     774             if (args[i].equalsIgnoreCase(INITIALIZE)) {
     775                 initialize = true;
     776                 found = true;
     777             }
     778 
     779             // look for the clean flag.
     780             if (args[i].equalsIgnoreCase(CLEAN)) {
     781                 FrameworkProperties.setProperty(PROP_CLEAN, "true"); //$NON-NLS-1$
     782                 found = true;
     783             }
     784 
     785             // look for the consoleLog flag
     786             if (args[i].equalsIgnoreCase(CONSOLE_LOG)) {
     787                 FrameworkProperties.setProperty(PROP_CONSOLE_LOG, "true"); //$NON-NLS-1$
     788                 found = true;
     789             }
     790 
     791             // look for the console with no port.  
     792             if (args[i].equalsIgnoreCase(CONSOLE) && ((i + 1 == args.length) || ((i + 1 < args.length) && (args[i + 1].startsWith("-"))))) { //$NON-NLS-1$
     793                 FrameworkProperties.setProperty(PROP_CONSOLE, ""); //$NON-NLS-1$
     794                 found = true;
     795             }
     796 
     797             if (args[i].equalsIgnoreCase(NOEXIT)) {
     798                 FrameworkProperties.setProperty(PROP_NOSHUTDOWN, "true"); //$NON-NLS-1$
     799                 found = true;
     800             }
     801 
     802             if (found) {
     803                 configArgs[configArgIndex++] = i;
     804                 continue;
     805             }
     806             // check for args with parameters. If we are at the last argument or if the next one
     807             // has a '-' as the first character, then we can't have an arg with a parm so continue.
     808             if (i == args.length - 1 || args[i + 1].startsWith("-")) { //$NON-NLS-1$
     809                 continue;
     810             }
     811             String arg = args[++i];
     812 
     813             // look for the console and port.  
     814             if (args[i - 1].equalsIgnoreCase(CONSOLE)) {
     815                 FrameworkProperties.setProperty(PROP_CONSOLE, arg);
     816                 found = true;
     817             }
     818 
     819             // look for the configuration location .  
     820             if (args[i - 1].equalsIgnoreCase(CONFIGURATION)) {
     821                 FrameworkProperties.setProperty(LocationManager.PROP_CONFIG_AREA, arg);
     822                 found = true;
     823             }
     824 
     825             // look for the data location for this instance.  
     826             if (args[i - 1].equalsIgnoreCase(DATA)) {
     827                 FrameworkProperties.setProperty(LocationManager.PROP_INSTANCE_AREA, arg);
     828                 found = true;
     829             }
     830 
     831             // look for the user location for this instance.  
     832             if (args[i - 1].equalsIgnoreCase(USER)) {
     833                 FrameworkProperties.setProperty(LocationManager.PROP_USER_AREA, arg);
     834                 found = true;
     835             }
     836 
     837             // look for the launcher location
     838             if (args[i - 1].equalsIgnoreCase(LAUNCHER)) {
     839                 FrameworkProperties.setProperty(LocationManager.PROP_LAUNCHER, arg);
     840                 found = true;
     841             }
     842             // look for the development mode and class path entries.  
     843             if (args[i - 1].equalsIgnoreCase(DEV)) {
     844                 FrameworkProperties.setProperty(PROP_DEV, arg);
     845                 found = true;
     846             }
     847 
     848             // look for the debug mode and option file location.  
     849             if (args[i - 1].equalsIgnoreCase(DEBUG)) {
     850                 FrameworkProperties.setProperty(PROP_DEBUG, arg);
     851                 debug = true;
     852                 found = true;
     853             }
     854 
     855             // look for the window system.  
     856             if (args[i - 1].equalsIgnoreCase(WS)) {
     857                 FrameworkProperties.setProperty(PROP_WS, arg);
     858                 found = true;
     859             }
     860 
     861             // look for the operating system
     862             if (args[i - 1].equalsIgnoreCase(OS)) {
     863                 FrameworkProperties.setProperty(PROP_OS, arg);
     864                 found = true;
     865             }
     866 
     867             // look for the system architecture
     868             if (args[i - 1].equalsIgnoreCase(ARCH)) {
     869                 FrameworkProperties.setProperty(PROP_ARCH, arg);
     870                 found = true;
     871             }
     872 
     873             // look for the nationality/language
     874             if (args[i - 1].equalsIgnoreCase(NL)) {
     875                 FrameworkProperties.setProperty(PROP_NL, arg);
     876                 found = true;
     877             }
     878 
     879             // look for the locale extensions
     880             if (args[i - 1].equalsIgnoreCase(NL_EXTENSIONS)) {
     881                 FrameworkProperties.setProperty(PROP_NL_EXTENSIONS, arg);
     882                 found = true;
     883             }
     884 
     885             // done checking for args.  Remember where an arg was found 
     886             if (found) {
     887                 configArgs[configArgIndex++] = i - 1;
     888                 configArgs[configArgIndex++] = i;
     889             }
     890         }
     891 
     892         // remove all the arguments consumed by this argument parsing
     893         if (configArgIndex == 0) {
     894             EclipseEnvironmentInfo.setFrameworkArgs(new String[0]);
     895             EclipseEnvironmentInfo.setAppArgs(args);
     896             return args;
     897         }
     898         String[] appArgs = new String[args.length - configArgIndex];
     899         String[] frameworkArgs = new String[configArgIndex];
     900         configArgIndex = 0;
     901         int j = 0;
     902         int k = 0;
     903         for (int i = 0; i < args.length; i++) {
     904             if (i == configArgs[configArgIndex]) {
     905                 frameworkArgs[k++] = args[i];
     906                 configArgIndex++;
     907             } else
     908                 appArgs[j++] = args[i];
     909         }
     910         EclipseEnvironmentInfo.setFrameworkArgs(frameworkArgs);
     911         EclipseEnvironmentInfo.setAppArgs(appArgs);
     912         return appArgs;
     913     }
     914 
     915     /**
     916      * Returns the result of converting a list of comma-separated tokens into an array
     917      * 
     918      * @return the array of string tokens
     919      * @param prop the initial comma-separated string
     920      */
     921     private static String[] getArrayFromList(String prop, String separator) {
     922         return ManifestElement.getArrayFromList(prop, separator);
     923     }
     924 
     925     protected static String getSysPath() {
     926         String result = FrameworkProperties.getProperty(PROP_SYSPATH);
     927         if (result != null)
     928             return result;
     929         result = getSysPathFromURL(FrameworkProperties.getProperty(PROP_FRAMEWORK));
     930         if (result == null)
     931             result = getSysPathFromCodeSource();
     932         if (result == null)
     933             throw new IllegalStateException("Can not find the system path."); //$NON-NLS-1$
     934         if (Character.isUpperCase(result.charAt(0))) {
     935             char[] chars = result.toCharArray();
     936             chars[0] = Character.toLowerCase(chars[0]);
     937             result = new String(chars);
     938         }
     939         FrameworkProperties.setProperty(PROP_SYSPATH, result);
     940         return result;
     941     }
     942 
     943     private static String getSysPathFromURL(String urlSpec) {
     944         if (urlSpec == null)
     945             return null;
     946         URL url = LocationHelper.buildURL(urlSpec, false);
     947         if (url == null)
     948             return null;
     949         File fwkFile = new File(url.getFile());
     950         fwkFile = new File(fwkFile.getAbsolutePath());
     951         fwkFile = new File(fwkFile.getParent());
     952         return fwkFile.getAbsolutePath();
     953     }
     954 
     955     private static String getSysPathFromCodeSource() {
     956         ProtectionDomain pd = EclipseStarter.class.getProtectionDomain();
     957         if (pd == null)
     958             return null;
     959         CodeSource cs = pd.getCodeSource();
     960         if (cs == null)
     961             return null;
     962         URL url = cs.getLocation();
     963         if (url == null)
     964             return null;
     965         String result = url.getFile();
     966         if (result.endsWith(".jar")) { //$NON-NLS-1$
     967             result = result.substring(0, result.lastIndexOf('/'));
     968             if ("folder".equals(FrameworkProperties.getProperty(PROP_FRAMEWORK_SHAPE))) //$NON-NLS-1$
     969                 result = result.substring(0, result.lastIndexOf('/'));
     970         } else {
     971             if (result.endsWith("/")) //$NON-NLS-1$
     972                 result = result.substring(0, result.length() - 1);
     973             result = result.substring(0, result.lastIndexOf('/'));
     974             result = result.substring(0, result.lastIndexOf('/'));
     975         }
     976         return result;
     977     }
     978 
     979     private static Bundle[] getCurrentBundles(boolean includeInitial) {
     980         Bundle[] installed = context.getBundles();
     981         List<Bundle> initial = new ArrayList<Bundle>();
     982         for (int i = 0; i < installed.length; i++) {
     983             Bundle bundle = installed[i];
     984             if (bundle.getLocation().startsWith(INITIAL_LOCATION)) {
     985                 if (includeInitial)
     986                     initial.add(bundle);
     987             } else if (!includeInitial && bundle.getBundleId() != 0)
     988                 initial.add(bundle);
     989         }
     990         return initial.toArray(new Bundle[initial.size()]);
     991     }
     992 
     993     private static Bundle getBundleByLocation(String location, Bundle[] bundles) {
     994         for (int i = 0; i < bundles.length; i++) {
     995             Bundle bundle = bundles[i];
     996             if (location.equalsIgnoreCase(bundle.getLocation()))
     997                 return bundle;
     998         }
     999         return null;
    1000     }
    1001 
    1002     private static void uninstallBundles(Bundle[] curInitBundles, InitialBundle[] newInitBundles, List<Bundle> toRefresh) {
    1003         for (int i = 0; i < curInitBundles.length; i++) {
    1004             boolean found = false;
    1005             for (int j = 0; j < newInitBundles.length; j++) {
    1006                 if (curInitBundles[i].getLocation().equalsIgnoreCase(newInitBundles[j].locationString)) {
    1007                     found = true;
    1008                     break;
    1009                 }
    1010             }
    1011             if (!found)
    1012                 try {
    1013                     curInitBundles[i].uninstall();
    1014                     toRefresh.add(curInitBundles[i]);
    1015                 } catch (BundleException e) {
    1016                     FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_FAILED_UNINSTALL, curInitBundles[i].getLocation()), 0, e, null);
    1017                     log.log(entry);
    1018                 }
    1019         }
    1020     }
    1021 
    1022     private static void installBundles(InitialBundle[] initialBundles, Bundle[] curInitBundles, List<Bundle> startBundles, List<Bundle> lazyActivationBundles, List<Bundle> toRefresh) {
    1023         ServiceReference<?> reference = context.getServiceReference(StartLevel.class.getName());
    1024         StartLevel startService = null;
    1025         if (reference != null)
    1026             startService = (StartLevel) context.getService(reference);
    1027         try {
    1028             for (int i = 0; i < initialBundles.length; i++) {
    1029                 Bundle osgiBundle = getBundleByLocation(initialBundles[i].locationString, curInitBundles);
    1030                 try {
    1031                     // don't need to install if it is already installed
    1032                     if (osgiBundle == null) {
    1033                         InputStream in = initialBundles[i].location.openStream();
    1034                         try {
    1035                             osgiBundle = context.installBundle(initialBundles[i].locationString, in);
    1036                         } catch (BundleException e) {
    1037                             StatusException status = e instanceof StatusException ? (StatusException) e : null;
    1038                             if (status != null && status.getStatusCode() == StatusException.CODE_OK && status.getStatus() instanceof Bundle) {
    1039                                 osgiBundle = (Bundle) status.getStatus();
    1040                             } else
    1041                                 throw e;
    1042                         }
    1043                         // only check for lazy activation header if this is a newly installed bundle and is not marked for persistent start
    1044                         if (!initialBundles[i].start && hasLazyActivationPolicy(osgiBundle))
    1045                             lazyActivationBundles.add(osgiBundle);
    1046                     }
    1047                     // always set the startlevel incase it has changed (bug 111549)
    1048                     // this is a no-op if the level is the same as previous launch.
    1049                     if ((osgiBundle.getState() & Bundle.UNINSTALLED) == 0 && initialBundles[i].level >= 0 && startService != null)
    1050                         startService.setBundleStartLevel(osgiBundle, initialBundles[i].level);
    1051                     // if this bundle is supposed to be started then add it to the start list
    1052                     if (initialBundles[i].start)
    1053                         startBundles.add(osgiBundle);
    1054                     // include basic bundles in case they were not resolved before
    1055                     if ((osgiBundle.getState() & Bundle.INSTALLED) != 0)
    1056                         toRefresh.add(osgiBundle);
    1057                 } catch (BundleException e) {
    1058                     FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_FAILED_INSTALL, initialBundles[i].location), 0, e, null);
    1059                     log.log(entry);
    1060                 } catch (IOException e) {
    1061                     FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_FAILED_INSTALL, initialBundles[i].location), 0, e, null);
    1062                     log.log(entry);
    1063                 }
    1064             }
    1065         } finally {
    1066             if (reference != null)
    1067                 context.ungetService(reference);
    1068         }
    1069     }
    1070 
    1071     @SuppressWarnings("deprecation")
    1072     private static boolean hasLazyActivationPolicy(Bundle target) {
    1073         // check the bundle manifest to see if it defines a lazy activation policy
    1074         Dictionary<String, String> headers = target.getHeaders(""); //$NON-NLS-1$
    1075         // first check to see if this is a fragment bundle
    1076         String fragmentHost = headers.get(Constants.FRAGMENT_HOST);
    1077         if (fragmentHost != null)
    1078             return false; // do not activate fragment bundles
    1079         // look for the OSGi defined Bundle-ActivationPolicy header
    1080         String activationPolicy = headers.get(Constants.BUNDLE_ACTIVATIONPOLICY);
    1081         try {
    1082             if (activationPolicy != null) {
    1083                 ManifestElement[] elements = ManifestElement.parseHeader(Constants.BUNDLE_ACTIVATIONPOLICY, activationPolicy);
    1084                 if (elements != null && elements.length > 0) {
    1085                     // if the value is "lazy" then it has a lazy activation poliyc
    1086                     if (Constants.ACTIVATION_LAZY.equals(elements[0].getValue()))
    1087                         return true;
    1088                 }
    1089             } else {
    1090                 // check for Eclipse specific lazy start headers "Eclipse-LazyStart" and "Eclipse-AutoStart"
    1091                 String eclipseLazyStart = headers.get(Constants.ECLIPSE_LAZYSTART);
    1092                 if (eclipseLazyStart == null)
    1093                     eclipseLazyStart = headers.get(Constants.ECLIPSE_AUTOSTART);
    1094                 ManifestElement[] elements = ManifestElement.parseHeader(Constants.ECLIPSE_LAZYSTART, eclipseLazyStart);
    1095                 if (elements != null && elements.length > 0) {
    1096                     // if the value is true then it is lazy activated
    1097                     if ("true".equals(elements[0].getValue())) //$NON-NLS-1$
    1098                         return true;
    1099                     // otherwise it is only lazy activated if it defines an exceptions directive.
    1100                     else if (elements[0].getDirective("exceptions") != null) //$NON-NLS-1$
    1101                         return true;
    1102                 }
    1103             }
    1104         } catch (BundleException be) {
    1105             // ignore this
    1106         }
    1107         return false;
    1108     }
    1109 
    1110     private static void startBundles(Bundle[] startBundles, Bundle[] lazyBundles) {
    1111         for (int i = 0; i < startBundles.length; i++)
    1112             startBundle(startBundles[i], 0);
    1113         for (int i = 0; i < lazyBundles.length; i++)
    1114             startBundle(lazyBundles[i], Bundle.START_ACTIVATION_POLICY);
    1115     }
    1116 
    1117     private static void startBundle(Bundle bundle, int options) {
    1118         try {
    1119             bundle.start(options);
    1120         } catch (BundleException e) {
    1121             if ((bundle.getState() & Bundle.RESOLVED) != 0) {
    1122                 // only log errors if the bundle is resolved
    1123                 FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_FAILED_START, bundle.getLocation()), 0, e, null);
    1124                 log.log(entry);
    1125             }
    1126         }
    1127     }
    1128 
    1129     private static void loadConfigurationInfo() {
    1130         Location configArea = LocationManager.getConfigurationLocation();
    1131         if (configArea == null)
    1132             return;
    1133 
    1134         URL location = null;
    1135         try {
    1136             location = new URL(configArea.getURL().toExternalForm() + LocationManager.CONFIG_FILE);
    1137         } catch (MalformedURLException e) {
    1138             // its ok.  This should never happen
    1139         }
    1140         mergeProperties(FrameworkProperties.getProperties(), loadProperties(location));
    1141     }
    1142 
    1143     private static Properties loadProperties(URL location) {
    1144         Properties result = new Properties();
    1145         if (location == null)
    1146             return result;
    1147         try {
    1148             InputStream in = location.openStream();
    1149             try {
    1150                 result.load(in);
    1151             } finally {
    1152                 in.close();
    1153             }
    1154         } catch (IOException e) {
    1155             // its ok if there is no file.  We'll just use the defaults for everything
    1156             // TODO but it might be nice to log something with gentle wording (i.e., it is not an error)
    1157         }
    1158         return substituteVars(result);
    1159     }
    1160 
    1161     private static Properties substituteVars(Properties result) {
    1162         if (result == null) {
    1163             //nothing todo.
    1164             return null;
    1165         }
    1166         for (Enumeration<Object> eKeys = result.keys(); eKeys.hasMoreElements();) {
    1167             Object key = eKeys.nextElement();
    1168             if (key instanceof String) {
    1169                 String value = result.getProperty((String) key);
    1170                 if (value != null)
    1171                     result.put(key, BaseStorageHook.substituteVars(value));
    1172             }
    1173         }
    1174         return result;
    1175     }
    1176 
    1177     /**
    1178      * Returns a URL which is equivalent to the given URL relative to the
    1179      * specified base URL. Works only for file: URLs
    1180      * @throws MalformedURLException 
    1181      */
    1182     private static URL makeRelative(URL base, URL location) throws MalformedURLException {
    1183         if (base == null)
    1184             return location;
    1185         if (!"file".equals(base.getProtocol())) //$NON-NLS-1$
    1186             return location;
    1187         if (!location.getProtocol().equals(REFERENCE_PROTOCOL))
    1188             return location; // we can only make reference urls relative
    1189         URL nonReferenceLocation = new URL(location.getPath());
    1190         // if some URL component does not match, return the original location
    1191         if (!base.getProtocol().equals(nonReferenceLocation.getProtocol()))
    1192             return location;
    1193         File locationPath = new File(nonReferenceLocation.getPath());
    1194         // if location is not absolute, return original location 
    1195         if (!locationPath.isAbsolute())
    1196             return location;
    1197         File relativePath = makeRelative(new File(base.getPath()), locationPath);
    1198         String urlPath = relativePath.getPath();
    1199         if (File.separatorChar != '/')
    1200             urlPath = urlPath.replace(File.separatorChar, '/');
    1201         if (nonReferenceLocation.getPath().endsWith("/")) //$NON-NLS-1$
    1202             // restore original trailing slash 
    1203             urlPath += '/';
    1204         // couldn't use File to create URL here because it prepends the path with user.dir 
    1205         URL relativeURL = new URL(base.getProtocol(), base.getHost(), base.getPort(), urlPath);
    1206         // now make it back to a reference URL
    1207         relativeURL = new URL(REFERENCE_SCHEME + relativeURL.toExternalForm());
    1208         return relativeURL;
    1209     }
    1210 
    1211     private static File makeRelative(File base, File location) {
    1212         if (!location.isAbsolute())
    1213             return location;
    1214         File relative = new File(new FilePath(base).makeRelative(new FilePath(location)));
    1215         return relative;
    1216     }
    1217 
    1218     private static void mergeProperties(Properties destination, Properties source) {
    1219         for (Enumeration<?> e = source.keys(); e.hasMoreElements();) {
    1220             String key = (String) e.nextElement();
    1221             String value = source.getProperty(key);
    1222             if (destination.getProperty(key) == null)
    1223                 destination.setProperty(key, value);
    1224         }
    1225     }
    1226 
    1227     private static void setStartLevel(final int value) {
    1228         ServiceReference<?> reference = context.getServiceReference(StartLevel.class.getName());
    1229         final StartLevel startLevel = reference != null ? (StartLevel) context.getService(reference) : null;
    1230         if (startLevel == null)
    1231             return;
    1232         final Semaphore semaphore = new Semaphore(0);
    1233         StartupEventListener listener = new StartupEventListener(semaphore, FrameworkEvent.STARTLEVEL_CHANGED);
    1234         context.addFrameworkListener(listener);
    1235         context.addBundleListener(listener);
    1236         startLevel.setStartLevel(value);
    1237         context.ungetService(reference);
    1238         updateSplash(semaphore, listener);
    1239     }
    1240 
    1241     static class StartupEventListener implements SynchronousBundleListener, FrameworkListener {
    1242         private final Semaphore semaphore;
    1243         private final int frameworkEventType;
    1244 
    1245         public StartupEventListener(Semaphore semaphore, int frameworkEventType) {
    1246             this.semaphore = semaphore;
    1247             this.frameworkEventType = frameworkEventType;
    1248         }
    1249 
    1250         public void bundleChanged(BundleEvent event) {
    1251             if (event.getBundle().getBundleId() == 0 && event.getType() == BundleEvent.STOPPING)
    1252                 semaphore.release();
    1253         }
    1254 
    1255         public void frameworkEvent(FrameworkEvent event) {
    1256             if (event.getType() == frameworkEventType)
    1257                 semaphore.release();
    1258         }
    1259 
    1260     }
    1261 
    1262     private static void updateSplash(Semaphore semaphore, StartupEventListener listener) {
    1263         ServiceTracker<StartupMonitor, StartupMonitor> monitorTracker = new ServiceTracker<StartupMonitor, StartupMonitor>(context, StartupMonitor.class.getName(), null);
    1264         monitorTracker.open();
    1265         try {
    1266             while (true) {
    1267                 StartupMonitor monitor = monitorTracker.getService();
    1268                 if (monitor != null) {
    1269                     try {
    1270                         monitor.update();
    1271                     } catch (Throwable e) {
    1272                         // ignore exceptions thrown by the monitor
    1273                     }
    1274                 }
    1275                 // can we acquire the semaphore yet?
    1276                 if (semaphore.acquire(50))
    1277                     break; //done
    1278                 //else still working, spin another update
    1279             }
    1280         } finally {
    1281             if (listener != null) {
    1282                 context.removeFrameworkListener(listener);
    1283                 context.removeBundleListener(listener);
    1284             }
    1285             monitorTracker.close();
    1286         }
    1287     }
    1288 
    1289     /**
    1290      * Searches for the given target directory immediately under
    1291      * the given start location.  If one is found then this location is returned; 
    1292      * otherwise an exception is thrown.
    1293      * 
    1294      * @return the location where target directory was found
    1295      * @param start the location to begin searching
    1296      */
    1297     private static String searchFor(final String target, String start) {
    1298         String[] candidates = searchCandidates.get(start);
    1299         if (candidates == null) {
    1300             File startFile = new File(start);
    1301             // Pre-check if file exists, if not, and it contains escape characters,
    1302             // try decoding the path
    1303             if (!startFile.exists() && start.indexOf('%') >= 0) {
    1304                 String decodePath = FrameworkProperties.decode(start);
    1305                 File f = new File(decodePath);
    1306                 if (f.exists())
    1307                     startFile = f;
    1308             }
    1309             candidates = startFile.list();
    1310             if (candidates != null)
    1311                 searchCandidates.put(start, candidates);
    1312         }
    1313         if (candidates == null)
    1314             return null;
    1315         String result = null;
    1316         Object[] maxVersion = null;
    1317         boolean resultIsFile = false;
    1318         for (int i = 0; i < candidates.length; i++) {
    1319             String candidateName = candidates[i];
    1320             if (!candidateName.startsWith(target))
    1321                 continue;
    1322             boolean simpleJar = false;
    1323             final char versionSep = candidateName.length() > target.length() ? candidateName.charAt(target.length()) : 0;
    1324             if (candidateName.length() > target.length() && versionSep != '_' && versionSep != '-') {
    1325                 // make sure this is not just a jar with no (_|-)version tacked on the end
    1326                 if (candidateName.length() == 4 + target.length() && candidateName.endsWith(".jar")) //$NON-NLS-1$
    1327                     simpleJar = true;
    1328                 else
    1329                     // name does not match the target properly with an (_|-) version at the end
    1330                     continue;
    1331             }
    1332             // Note: directory with version suffix is always > than directory without version suffix
    1333             String version = candidateName.length() > target.length() + 1 && (versionSep == '_' || versionSep == '-') ? candidateName.substring(target.length() + 1) : ""; //$NON-NLS-1$ 
    1334             Object[] currentVersion = getVersionElements(version);
    1335             if (currentVersion != null && compareVersion(maxVersion, currentVersion) < 0) {
    1336                 File candidate = new File(start, candidateName);
    1337                 boolean candidateIsFile = candidate.isFile();
    1338                 // if simple jar; make sure it is really a file before accepting it
    1339                 if (!simpleJar || candidateIsFile) {
    1340                     result = candidate.getAbsolutePath();
    1341                     resultIsFile = candidateIsFile;
    1342                     maxVersion = currentVersion;
    1343                 }
    1344             }
    1345         }
    1346         if (result == null)
    1347             return null;
    1348         return result.replace(File.separatorChar, '/') + (resultIsFile ? "" : "/"); //$NON-NLS-1$ //$NON-NLS-2$
    1349     }
    1350 
    1351     /**
    1352      * Do a quick parse of version identifier so its elements can be correctly compared.
    1353      * If we are unable to parse the full version, remaining elements are initialized
    1354      * with suitable defaults.
    1355      * @return an array of size 4; first three elements are of type Integer (representing
    1356      * major, minor and service) and the fourth element is of type String (representing
    1357      * qualifier).  A value of null is returned if there are no valid Integers.  Note, that 
    1358      * returning anything else will cause exceptions in the caller.
    1359      */
    1360     private static Object[] getVersionElements(String version) {
    1361         Object[] result = {new Integer(-1), new Integer(-1), new Integer(-1), ""}; //$NON-NLS-1$
    1362         StringTokenizer t = new StringTokenizer(version, "."); //$NON-NLS-1$
    1363         String token;
    1364         for (int i = 0; t.hasMoreTokens() && i < 4; i++) {
    1365             token = t.nextToken();
    1366             if (i < 3) {
    1367                 // major, minor or service ... numeric values
    1368                 try {
    1369                     result[i] = new Integer(token);
    1370                 } catch (Exception e) {
    1371                     if (i == 0)
    1372                         return null; // return null if no valid numbers are present
    1373                     // invalid number format - use default numbers (-1) for the rest
    1374                     break;
    1375                 }
    1376             } else {
    1377                 // qualifier ... string value
    1378                 result[i] = token;
    1379             }
    1380         }
    1381         return result;
    1382     }
    1383 
    1384     /**
    1385      * Compares version strings. 
    1386      * @return result of comparison, as integer;
    1387      * <code><0</code> if left < right;
    1388      * <code>0</code> if left == right;
    1389      * <code>>0</code> if left > right;
    1390      */
    1391     private static int compareVersion(Object[] left, Object[] right) {
    1392         if (left == null)
    1393             return -1;
    1394         int result = ((Integer) left[0]).compareTo((Integer) right[0]); // compare major
    1395         if (result != 0)
    1396             return result;
    1397 
    1398         result = ((Integer) left[1]).compareTo((Integer) right[1]); // compare minor
    1399         if (result != 0)
    1400             return result;
    1401 
    1402         result = ((Integer) left[2]).compareTo((Integer) right[2]); // compare service
    1403         if (result != 0)
    1404             return result;
    1405 
    1406         return ((String) left[3]).compareTo((String) right[3]); // compare qualifier
    1407     }
    1408 
    1409     private static void finalizeProperties() {
    1410         // if check config is unknown and we are in dev mode, 
    1411         if (FrameworkProperties.getProperty(PROP_DEV) != null && FrameworkProperties.getProperty(PROP_CHECK_CONFIG) == null)
    1412             FrameworkProperties.setProperty(PROP_CHECK_CONFIG, "true"); //$NON-NLS-1$
    1413     }
    1414 
    1415     private static class InitialBundle {
    1416         public final String locationString;
    1417         public final URL location;
    1418         public final int level;
    1419         public final boolean start;
    1420 
    1421         InitialBundle(String locationString, URL location, int level, boolean start) {
    1422             this.locationString = locationString;
    1423             this.location = location;
    1424             this.level = level;
    1425             this.start = start;
    1426         }
    1427     }
    1428 
    1429     /**
    1430      * Sets the initial properties for the platform.  
    1431      * This method must be called before calling the {@link  #run(String[], Runnable)} or 
    1432      * {@link #startup(String[], Runnable)} methods for the properties to be used in 
    1433      * a launched instance of the platform.  
    1434      * <p>
    1435      * If the specified properties contains a null value then the key for that value 
    1436      * will be cleared from the properties of the platform.
    1437      * </p>
    1438      * @param initialProperties the initial properties to set for the platform.
    1439      * @since 3.2
    1440      */
    1441     public static void setInitialProperties(Map<String, String> initialProperties) {
    1442         if (initialProperties == null || initialProperties.isEmpty())
    1443             return;
    1444         for (Map.Entry<String, String> entry : initialProperties.entrySet()) {
    1445             if (entry.getValue() != null)
    1446                 FrameworkProperties.setProperty(entry.getKey(), entry.getValue());
    1447             else
    1448                 FrameworkProperties.clearProperty(entry.getKey());
    1449         }
    1450     }
    1451 
    1452     /**
    1453      * Returns the context of the system bundle.  A value of 
    1454      * <code>null</code> is returned if the platform is not running.
    1455      * @return the context of the system bundle
    1456      * @throws java.lang.SecurityException If the caller does not have the
    1457      *         appropriate <code>AdminPermission[system.bundle,CONTEXT]</code>, and
    1458      *         the Java Runtime Environment supports permissions.
    1459      */
    1460     public static BundleContext getSystemBundleContext() {
    1461         if (context == null || !running)
    1462             return null;
    1463         return context.getBundle().getBundleContext();
    1464     }
    1465 
    1466     private static boolean isForcedRestart() {
    1467         return Boolean.valueOf(FrameworkProperties.getProperty(PROP_FORCED_RESTART)).booleanValue();
    1468     }
    1469 
    1470     /*
    1471      * NOTE: This is an internal/experimental method used by launchers that need to react when the framework
    1472      * is shutdown internally.
    1473      * 
    1474      * Adds a framework shutdown handler. <p>
    1475      * A handler implements the {@link Runnable} interface.  When the framework is shutdown
    1476      * the {@link Runnable#run()} method is called for each registered handler.  Handlers should 
    1477      * make no assumptions on the thread it is being called from.  If a handler object is 
    1478      * registered multiple times it will be called once for each registration.
    1479      * <p>
    1480      * At the time a handler is called the framework is shutdown.  Handlers must not depend on 
    1481      * a running framework to execute or attempt to load additional classes from bundles 
    1482      * installed in the framework.
    1483      * @param handler the framework shutdown handler
    1484      * @throws IllegalStateException if the platform is already running
    1485      */
    1486     static void internalAddFrameworkShutdownHandler(Runnable handler) {
    1487         if (running)
    1488             throw new IllegalStateException(EclipseAdaptorMsg.ECLIPSE_STARTUP_ALREADY_RUNNING);
    1489 
    1490         if (shutdownHandlers == null)
    1491             shutdownHandlers = new ArrayList<Runnable>();
    1492 
    1493         shutdownHandlers.add(handler);
    1494     }
    1495 
    1496     /*
    1497      * NOTE: This is an internal/experimental method used by launchers that need to react when the framework
    1498      * is shutdown internally.
    1499      * 
    1500      * Removes a framework shutdown handler. <p>
    1501      * @param handler the framework shutdown handler
    1502      * @throws IllegalStateException if the platform is already running
    1503      */
    1504     static void internalRemoveFrameworkShutdownHandler(Runnable handler) {
    1505         if (running)
    1506             throw new IllegalStateException(EclipseAdaptorMsg.ECLIPSE_STARTUP_ALREADY_RUNNING);
    1507 
    1508         if (shutdownHandlers != null)
    1509             shutdownHandlers.remove(handler);
    1510     }
    1511 
    1512     private static void registerFrameworkShutdownHandlers() {
    1513         if (shutdownHandlers == null)
    1514             return;
    1515 
    1516         final Bundle systemBundle = context.getBundle();
    1517         for (Iterator<Runnable> it = shutdownHandlers.iterator(); it.hasNext();) {
    1518             final Runnable handler = it.next();
    1519             BundleListener listener = new BundleListener() {
    1520                 public void bundleChanged(BundleEvent event) {
    1521                     if (event.getBundle() == systemBundle && event.getType() == BundleEvent.STOPPED) {
    1522                         handler.run();
    1523                     }
    1524                 }
    1525             };
    1526             context.addBundleListener(listener);
    1527         }
    1528     }
    1529 }
    ElipseStarter

相关文章:

  • 2021-12-08
  • 2022-12-23
  • 2021-12-19
  • 2021-12-23
  • 2021-05-19
  • 2021-12-22
  • 2022-12-23
猜你喜欢
  • 2021-12-07
  • 2021-08-24
  • 2021-12-30
  • 2022-01-19
  • 2021-05-26
  • 2021-12-20
  • 2021-07-25
相关资源
相似解决方案