Eclipse Startup

  • 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
  • main() in class EclipseStarter
  •  1     /**
     2      * This is the main to start osgi.
     3      * It only works when the framework is being jared as a single jar
     4      */
     5     public static void main(String[] args) throws Exception {
     6         if (FrameworkProperties.getProperty("eclipse.startTime") == null) //$NON-NLS-1$
     7             FrameworkProperties.setProperty("eclipse.startTime", Long.toString(System.currentTimeMillis())); //$NON-NLS-1$
     8         if (FrameworkProperties.getProperty(PROP_NOSHUTDOWN) == null)
     9             FrameworkProperties.setProperty(PROP_NOSHUTDOWN, "true"); //$NON-NLS-1$
    10         // set the compatibility boot delegation flag to false to get "standard" OSGi behavior WRT boot delegation (bug 178477)
    11         if (FrameworkProperties.getProperty(Constants.OSGI_COMPATIBILITY_BOOTDELEGATION) == null)
    12             FrameworkProperties.setProperty(Constants.OSGI_COMPATIBILITY_BOOTDELEGATION, "false"); //$NON-NLS-1$
    13         Object result = run(args, null);
    14         if (result instanceof Integer && !Boolean.valueOf(FrameworkProperties.getProperty(PROP_NOSHUTDOWN)).booleanValue())
    15             System.exit(((Integer) result).intValue());
    16     }
  • run() in class ElipseStarter
  •  1     /**
     2      * Launches the platform and runs a single application. The application is either identified
     3      * in the given arguments (e.g., -application &lt;app id&gt;) or in the <code>eclipse.application</code> 
     4      * System property.  This convenience method starts 
     5      * up the platform, runs the indicated application, and then shuts down the 
     6      * platform. The platform must not be running already. 
     7      * 
     8      * @param args the command line-style arguments used to configure the platform
     9      * @param endSplashHandler the block of code to run to tear down the splash 
    10      *     screen or <code>null</code> if no tear down is required
    11      * @return the result of running the application
    12      * @throws Exception if anything goes wrong
    13      */
    14     public static Object run(String[] args, Runnable endSplashHandler) throws Exception {
    15         if (Profile.PROFILE && Profile.STARTUP)
    16             Profile.logEnter("EclipseStarter.run()", null); //$NON-NLS-1$
    17         if (running)
    18             throw new IllegalStateException(EclipseAdaptorMsg.ECLIPSE_STARTUP_ALREADY_RUNNING);
    19         boolean startupFailed = true;
    20         try {
    21             startup(args, endSplashHandler);//endSplashHandler == null
    22             startupFailed = false;
    23             if (Boolean.valueOf(FrameworkProperties.getProperty(PROP_IGNOREAPP)).booleanValue() || isForcedRestart())
    24                 return null;
    25             return run(null);//make EclipseAppLauncher run to starup platform
    26         } catch (Throwable e) {
    27             // ensure the splash screen is down
    28             if (endSplashHandler != null)
    29                 endSplashHandler.run();
    30             // may use startupFailed to understand where the error happened
    31             FrameworkLogEntry logEntry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, startupFailed ? EclipseAdaptorMsg.ECLIPSE_STARTUP_STARTUP_ERROR : EclipseAdaptorMsg.ECLIPSE_STARTUP_APP_ERROR, 1, e, null);
    32             if (log != null)
    33                 log.log(logEntry);
    34             else
    35                 // TODO desperate measure - ideally, we should write this to disk (a la Main.log)
    36                 e.printStackTrace();
    37         } finally {
    38             try {
    39                 // The application typically sets the exit code however the framework can request that
    40                 // it be re-started. We need to check for this and potentially override the exit code.
    41                 if (isForcedRestart())
    42                     FrameworkProperties.setProperty(PROP_EXITCODE, "23"); //$NON-NLS-1$
    43                 if (!Boolean.valueOf(FrameworkProperties.getProperty(PROP_NOSHUTDOWN)).booleanValue())
    44                     shutdown();
    45             } catch (Throwable e) {
    46                 FrameworkLogEntry logEntry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, EclipseAdaptorMsg.ECLIPSE_STARTUP_SHUTDOWN_ERROR, 1, e, null);
    47                 if (log != null)
    48                     log.log(logEntry);
    49                 else
    50                     // TODO desperate measure - ideally, we should write this to disk (a la Main.log)
    51                     e.printStackTrace();
    52             }
    53             if (Profile.PROFILE && Profile.STARTUP)
    54                 Profile.logExit("EclipseStarter.run()"); //$NON-NLS-1$
    55             if (Profile.PROFILE) {
    56                 String report = Profile.getProfileLog();
    57                 // avoiding writing to the console if there is nothing to print
    58                 if (report != null && report.length() > 0)
    59                     System.out.println(report);
    60             }
    61         }
    62         // we only get here if an error happened
    63         if (FrameworkProperties.getProperty(PROP_EXITCODE) == null) {
    64             FrameworkProperties.setProperty(PROP_EXITCODE, "13"); //$NON-NLS-1$
    65             FrameworkProperties.setProperty(PROP_EXITDATA, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_ERROR_CHECK_LOG, log == null ? null : log.getFile().getPath()));
    66         }
    67         return null;
    68     }
  • startup in class ElicpseStartup
  •  1     /**
     2      * Starts the platform and sets it up to run a single application. The application is either identified
     3      * in the given arguments (e.g., -application &lt;app id&gt;) or in the <code>eclipse.application</code>
     4      * System property.  The platform must not be running already. 
     5      * <p>
     6      * The given runnable (if not <code>null</code>) is used to tear down the splash screen if required.
     7      * </p>
     8      * @param args the arguments passed to the application
     9      * @return BundleContext the context of the system bundle
    10      * @throws Exception if anything goes wrong
    11      */
    12     public static BundleContext startup(String[] args, Runnable endSplashHandler) throws Exception {
    13         if (Profile.PROFILE && Profile.STARTUP)
    14             Profile.logEnter("EclipseStarter.startup()", null); //$NON-NLS-1$
    15         if (running)
    16             throw new IllegalStateException(EclipseAdaptorMsg.ECLIPSE_STARTUP_ALREADY_RUNNING);
    17         FrameworkProperties.initializeProperties(); // initialize some framework properties that must always be set
    18         processCommandLine(args);
    19         LocationManager.initializeLocations();
    20         loadConfigurationInfo();
    21         finalizeProperties();
    22         if (Profile.PROFILE)
    23             Profile.initProps(); // catch any Profile properties set in eclipse.properties...
    24         if (Profile.PROFILE && Profile.STARTUP)
    25             Profile.logTime("EclipseStarter.startup()", "props inited"); //$NON-NLS-1$ //$NON-NLS-2$
    26         adaptor = createAdaptor();
    27         log = adaptor.getFrameworkLog();
    28         if (Profile.PROFILE && Profile.STARTUP)
    29             Profile.logTime("EclipseStarter.startup()", "adapter created"); //$NON-NLS-1$ //$NON-NLS-2$
    30         framework = new Framework(adaptor);
    31         if (Profile.PROFILE && Profile.STARTUP)
    32             Profile.logTime("EclipseStarter.startup()", "OSGi created"); //$NON-NLS-1$ //$NON-NLS-2$
    33         context = framework.getBundle(0).getBundleContext();
    34         registerFrameworkShutdownHandlers();
    35         publishSplashScreen(endSplashHandler);
    36         if (Profile.PROFILE && Profile.STARTUP)
    37             Profile.logTime("EclipseStarter.startup()", "osgi launched"); //$NON-NLS-1$ //$NON-NLS-2$
    38         consoleMgr = ConsoleManager.startConsole(framework);
    39         if (Profile.PROFILE && Profile.STARTUP) {
    40             Profile.logTime("EclipseStarter.startup()", "console started"); //$NON-NLS-1$ //$NON-NLS-2$
    41         }
    42         framework.launch();
    43         // save the cached timestamp before loading basic bundles; this is needed so we can do a proper timestamp check when logging resolver errors
    44         long stateStamp = adaptor.getState().getTimeStamp();
    45         Bundle[] startBundles = loadBasicBundles();
    46 
    47         if (startBundles == null || ("true".equals(FrameworkProperties.getProperty(PROP_REFRESH_BUNDLES)) && refreshPackages(getCurrentBundles(false)))) { //$NON-NLS-1$
    48             waitForShutdown();
    49             return context; // cannot continue; loadBasicBundles caused refreshPackages to shutdown the framework
    50         }
    51 
    52         if (Profile.PROFILE && Profile.STARTUP)
    53             Profile.logTime("EclipseStarter.startup()", "loading basic bundles"); //$NON-NLS-1$ //$NON-NLS-2$
    54 
    55         // set the framework start level to the ultimate value.  This will actually start things
    56         // running if they are persistently active.
    57         setStartLevel(getStartLevel());
    58         if (Profile.PROFILE && Profile.STARTUP)
    59             Profile.logTime("EclipseStarter.startup()", "StartLevel set"); //$NON-NLS-1$ //$NON-NLS-2$
    60         // they should all be active by this time
    61         ensureBundlesActive(startBundles);
    62 
    63         // in the case where the built-in console is disabled we should try to start the console bundle
    64         try {
    65             consoleMgr.checkForConsoleBundle();
    66         } catch (BundleException e) {
    67             FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, e.getMessage(), 0, e, null);
    68             log.log(entry);
    69         }
    70         if (debug || FrameworkProperties.getProperty(PROP_DEV) != null)
    71             // only spend time showing unresolved bundles in dev/debug mode and the state has changed
    72             if (stateStamp != adaptor.getState().getTimeStamp())
    73                 logUnresolvedBundles(context.getBundles());
    74         running = true;
    75         if (Profile.PROFILE && Profile.STARTUP)
    76             Profile.logExit("EclipseStarter.startup()"); //$NON-NLS-1$
    77         return context;
    78     }
  • processCommandLine() in class ElicpseStartup
  •   1     private static String[] processCommandLine(String[] args) throws Exception {
      2         EclipseEnvironmentInfo.setAllArgs(args);//set environment information for use by application runing on Elicpse
      3         if (args.length == 0) {
      4             EclipseEnvironmentInfo.setFrameworkArgs(args);
      5             EclipseEnvironmentInfo.setAllArgs(args);
      6             return args;
      7         }
      8         int[] configArgs = new int[args.length];
      9         configArgs[0] = -1; // need to initialize the first element to something that could not be an index.
     10         int configArgIndex = 0;
     11         for (int i = 0; i < args.length; i++) {
     12             boolean found = false;
     13             // check for args without parameters (i.e., a flag arg)
     14 
     15             // check if debug should be enabled for the entire platform
     16             // If this is the last arg or there is a following arg (i.e., arg+1 has a leading -), 
     17             // simply enable debug.  Otherwise, assume that that the following arg is
     18             // actually the filename of an options file.  This will be processed below.
     19             if (args[i].equalsIgnoreCase(DEBUG) && ((i + 1 == args.length) || ((i + 1 < args.length) && (args[i + 1].startsWith("-"))))) { //$NON-NLS-1$
     20                 FrameworkProperties.setProperty(PROP_DEBUG, ""); //$NON-NLS-1$
     21                 debug = true;
     22                 found = true;
     23             }
     24 
     25             // check if development mode should be enabled for the entire platform
     26             // If this is the last arg or there is a following arg (i.e., arg+1 has a leading -), 
     27             // simply enable development mode.  Otherwise, assume that that the following arg is
     28             // actually some additional development time class path entries.  This will be processed below.
     29             if (args[i].equalsIgnoreCase(DEV) && ((i + 1 == args.length) || ((i + 1 < args.length) && (args[i + 1].startsWith("-"))))) { //$NON-NLS-1$
     30                 FrameworkProperties.setProperty(PROP_DEV, ""); //$NON-NLS-1$
     31                 found = true;
     32             }
     33 
     34             // look for the initialization arg
     35             if (args[i].equalsIgnoreCase(INITIALIZE)) {
     36                 initialize = true;
     37                 found = true;
     38             }
     39 
     40             // look for the clean flag.
     41             if (args[i].equalsIgnoreCase(CLEAN)) {
     42                 FrameworkProperties.setProperty(PROP_CLEAN, "true"); //$NON-NLS-1$
     43                 found = true;
     44             }
     45 
     46             // look for the consoleLog flag
     47             if (args[i].equalsIgnoreCase(CONSOLE_LOG)) {
     48                 FrameworkProperties.setProperty(PROP_CONSOLE_LOG, "true"); //$NON-NLS-1$
     49                 found = true;
     50             }
     51 
     52             // look for the console with no port.  
     53             if (args[i].equalsIgnoreCase(CONSOLE) && ((i + 1 == args.length) || ((i + 1 < args.length) && (args[i + 1].startsWith("-"))))) { //$NON-NLS-1$
     54                 FrameworkProperties.setProperty(PROP_CONSOLE, ""); //$NON-NLS-1$
     55                 found = true;
     56             }
     57 
     58             if (args[i].equalsIgnoreCase(NOEXIT)) {
     59                 FrameworkProperties.setProperty(PROP_NOSHUTDOWN, "true"); //$NON-NLS-1$
     60                 found = true;
     61             }
     62 
     63             if (found) {
     64                 configArgs[configArgIndex++] = i;
     65                 continue;
     66             }
     67             // check for args with parameters. If we are at the last argument or if the next one
     68             // has a '-' as the first character, then we can't have an arg with a parm so continue.
     69             if (i == args.length - 1 || args[i + 1].startsWith("-")) { //$NON-NLS-1$
     70                 continue;
     71             }
     72             String arg = args[++i];
     73 
     74             // look for the console and port.  
     75             if (args[i - 1].equalsIgnoreCase(CONSOLE)) {
     76                 FrameworkProperties.setProperty(PROP_CONSOLE, arg);
     77                 found = true;
     78             }
     79 
     80             // look for the configuration location .  
     81             if (args[i - 1].equalsIgnoreCase(CONFIGURATION)) {
     82                 FrameworkProperties.setProperty(LocationManager.PROP_CONFIG_AREA, arg);
     83                 found = true;
     84             }
     85 
     86             // look for the data location for this instance.  
     87             if (args[i - 1].equalsIgnoreCase(DATA)) {
     88                 FrameworkProperties.setProperty(LocationManager.PROP_INSTANCE_AREA, arg);
     89                 found = true;
     90             }
     91 
     92             // look for the user location for this instance.  
     93             if (args[i - 1].equalsIgnoreCase(USER)) {
     94                 FrameworkProperties.setProperty(LocationManager.PROP_USER_AREA, arg);
     95                 found = true;
     96             }
     97 
     98             // look for the launcher location
     99             if (args[i - 1].equalsIgnoreCase(LAUNCHER)) {
    100                 FrameworkProperties.setProperty(LocationManager.PROP_LAUNCHER, arg);
    101                 found = true;
    102             }
    103             // look for the development mode and class path entries.  
    104             if (args[i - 1].equalsIgnoreCase(DEV)) {
    105                 FrameworkProperties.setProperty(PROP_DEV, arg);
    106                 found = true;
    107             }
    108 
    109             // look for the debug mode and option file location.  
    110             if (args[i - 1].equalsIgnoreCase(DEBUG)) {
    111                 FrameworkProperties.setProperty(PROP_DEBUG, arg);
    112                 debug = true;
    113                 found = true;
    114             }
    115 
    116             // look for the window system.  
    117             if (args[i - 1].equalsIgnoreCase(WS)) {
    118                 FrameworkProperties.setProperty(PROP_WS, arg);
    119                 found = true;
    120             }
    121 
    122             // look for the operating system
    123             if (args[i - 1].equalsIgnoreCase(OS)) {
    124                 FrameworkProperties.setProperty(PROP_OS, arg);
    125                 found = true;
    126             }
    127 
    128             // look for the system architecture
    129             if (args[i - 1].equalsIgnoreCase(ARCH)) {
    130                 FrameworkProperties.setProperty(PROP_ARCH, arg);
    131                 found = true;
    132             }
    133 
    134             // look for the nationality/language
    135             if (args[i - 1].equalsIgnoreCase(NL)) {
    136                 FrameworkProperties.setProperty(PROP_NL, arg);
    137                 found = true;
    138             }
    139 
    140             // look for the locale extensions
    141             if (args[i - 1].equalsIgnoreCase(NL_EXTENSIONS)) {
    142                 FrameworkProperties.setProperty(PROP_NL_EXTENSIONS, arg);
    143                 found = true;
    144             }
    145 
    146             // done checking for args.  Remember where an arg was found 
    147             if (found) {
    148                 configArgs[configArgIndex++] = i - 1;
    149                 configArgs[configArgIndex++] = i;
    150             }
    151         }
    152 
    153         // remove all the arguments consumed by this argument parsing
    154         if (configArgIndex == 0) {
    155             EclipseEnvironmentInfo.setFrameworkArgs(new String[0]);
    156             EclipseEnvironmentInfo.setAppArgs(args);
    157             return args;
    158         }
    159         String[] appArgs = new String[args.length - configArgIndex];
    160         String[] frameworkArgs = new String[configArgIndex];
    161         configArgIndex = 0;
    162         int j = 0;
    163         int k = 0;
    164         for (int i = 0; i < args.length; i++) {
    165             if (i == configArgs[configArgIndex]) {
    166                 frameworkArgs[k++] = args[i];
    167                 configArgIndex++;
    168             } else
    169                 appArgs[j++] = args[i];
    170         }
    171         EclipseEnvironmentInfo.setFrameworkArgs(frameworkArgs);
    172         EclipseEnvironmentInfo.setAppArgs(appArgs);
    173         return appArgs;
    174     }
  • LocationManager
  •   1 /*******************************************************************************
      2  * Copyright (c) 2004, 2011 IBM Corporation and others.
      3  * All rights reserved. This program and the accompanying materials
      4  * are made available under the terms of the Eclipse Public License v1.0
      5  * which accompanies this distribution, and is available at
      6  * http://www.eclipse.org/legal/epl-v10.html
      7  * 
      8  * Contributors:
      9  *     IBM Corporation - initial API and implementation
     10  *******************************************************************************/
     11 package org.eclipse.core.runtime.adaptor;
     12 
     13 import java.io.*;
     14 import java.net.MalformedURLException;
     15 import java.net.URL;
     16 import java.util.Properties;
     17 import org.eclipse.core.runtime.internal.adaptor.*;
     18 import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor;
     19 import org.eclipse.osgi.framework.internal.core.Constants;
     20 import org.eclipse.osgi.framework.internal.core.FrameworkProperties;
     21 import org.eclipse.osgi.internal.baseadaptor.AdaptorUtil;
     22 import org.eclipse.osgi.service.datalocation.Location;
     23 
     24 /**
     25  * This class is used to manage the various Locations for Eclipse.
     26  * <p>
     27  * Clients may not extend this class.
     28  * </p>
     29  * @since 3.1
     30  * @noextend This class is not intended to be subclassed by clients.
     31  */
     32 public class LocationManager {
     33     private static Location installLocation = null;
     34     private static Location configurationLocation = null;
     35     private static Location userLocation = null;
     36     private static Location instanceLocation = null;
     37     private static Location eclipseHomeLocation = null;
     38 
     39     public static final String READ_ONLY_AREA_SUFFIX = ".readOnly"; //$NON-NLS-1$
     40     public static final String PROP_INSTALL_AREA = "osgi.install.area"; //$NON-NLS-1$
     41     public static final String PROP_CONFIG_AREA = "osgi.configuration.area"; //$NON-NLS-1$
     42     public static final String PROP_CONFIG_AREA_DEFAULT = "osgi.configuration.area.default"; //$NON-NLS-1$
     43     public static final String PROP_SHARED_CONFIG_AREA = "osgi.sharedConfiguration.area"; //$NON-NLS-1$
     44     public static final String PROP_INSTANCE_AREA = "osgi.instance.area"; //$NON-NLS-1$
     45     public static final String PROP_INSTANCE_AREA_DEFAULT = "osgi.instance.area.default"; //$NON-NLS-1$
     46     public static final String PROP_USER_AREA = "osgi.user.area"; //$NON-NLS-1$
     47     public static final String PROP_USER_AREA_DEFAULT = "osgi.user.area.default"; //$NON-NLS-1$
     48     public static final String PROP_MANIFEST_CACHE = "osgi.manifest.cache"; //$NON-NLS-1$
     49     public static final String PROP_USER_HOME = "user.home"; //$NON-NLS-1$
     50     public static final String PROP_USER_DIR = "user.dir"; //$NON-NLS-1$
     51     public static final String PROP_HOME_LOCATION_AREA = "eclipse.home.location"; //$NON-NLS-1$
     52     static final String PROP_LAUNCHER = "eclipse.launcher"; //$NON-NLS-1$
     53 
     54     // configuration area file/dir names
     55     public static final String BUNDLES_DIR = "bundles"; //$NON-NLS-1$
     56     public static final String STATE_FILE = ".state"; //$NON-NLS-1$
     57     public static final String LAZY_FILE = ".lazy"; //$NON-NLS-1$
     58     public static final String BUNDLE_DATA_FILE = ".bundledata"; //$NON-NLS-1$
     59     public static final String MANIFESTS_DIR = "manifests"; //$NON-NLS-1$
     60     public static final String CONFIG_FILE = "config.ini"; //$NON-NLS-1$
     61     public static final String ECLIPSE_PROPERTIES = "eclipse.properties"; //$NON-NLS-1$
     62 
     63     // Constants for configuration location discovery
     64     private static final String ECLIPSE = "eclipse"; //$NON-NLS-1$
     65     private static final String PRODUCT_SITE_MARKER = ".eclipseproduct"; //$NON-NLS-1$
     66     private static final String PRODUCT_SITE_ID = "id"; //$NON-NLS-1$
     67     private static final String PRODUCT_SITE_VERSION = "version"; //$NON-NLS-1$
     68 
     69     private static final String CONFIG_DIR = "configuration"; //$NON-NLS-1$
     70 
     71     // Data mode constants for user, configuration and data locations.
     72     private static final String NONE = "@none"; //$NON-NLS-1$
     73     private static final String NO_DEFAULT = "@noDefault"; //$NON-NLS-1$
     74     private static final String USER_HOME = "@user.home"; //$NON-NLS-1$
     75     private static final String USER_DIR = "@user.dir"; //$NON-NLS-1$
     76     // Placeholder for hashcode of installation directory
     77     private static final String INSTALL_HASH_PLACEHOLDER = "@install.hash"; //$NON-NLS-1$
     78 
     79     private static final String INSTANCE_DATA_AREA_PREFIX = ".metadata/.plugins/"; //$NON-NLS-1$
     80 
     81     /**
     82      * Builds a URL with the given specification
     83      * @param spec the URL specification
     84      * @param trailingSlash flag to indicate a trailing slash on the spec
     85      * @return a URL
     86      */
     87     public static URL buildURL(String spec, boolean trailingSlash) {
     88         return LocationHelper.buildURL(spec, trailingSlash);
     89     }
     90 
     91     private static void mungeConfigurationLocation() {
     92         // if the config property was set, munge it for backwards compatibility.
     93         String location = FrameworkProperties.getProperty(PROP_CONFIG_AREA);
     94         if (location != null) {
     95             if (location.endsWith(".cfg")) { //$NON-NLS-1$
     96                 int index = location.lastIndexOf('/');
     97                 if (index < 0)
     98                     index = location.lastIndexOf('\\');
     99                 location = location.substring(0, index + 1);
    100                 FrameworkProperties.setProperty(PROP_CONFIG_AREA, location);
    101             }
    102         }
    103     }
    104 
    105     /**
    106      * Initializes the Location objects for the LocationManager.
    107      */
    108     public static void initializeLocations() {
    109         // set the osgi storage area if it exists
    110         String osgiStorage = FrameworkProperties.getProperty(Constants.FRAMEWORK_STORAGE);
    111         if (osgiStorage != null)
    112             FrameworkProperties.setProperty(PROP_CONFIG_AREA, osgiStorage);
    113         // do install location initialization first since others may depend on it
    114         // assumes that the property is already set
    115         installLocation = buildLocation(PROP_INSTALL_AREA, null, "", true, false, null); //$NON-NLS-1$
    116 
    117         // TODO not sure what the data area prefix should be here for the user area
    118         Location temp = buildLocation(PROP_USER_AREA_DEFAULT, null, "", false, false, null); //$NON-NLS-1$
    119         URL defaultLocation = temp == null ? null : temp.getURL();
    120         if (defaultLocation == null)
    121             defaultLocation = buildURL(new File(FrameworkProperties.getProperty(PROP_USER_HOME), "user").getAbsolutePath(), true); //$NON-NLS-1$
    122         userLocation = buildLocation(PROP_USER_AREA, defaultLocation, "", false, false, null); //$NON-NLS-1$
    123 
    124         temp = buildLocation(PROP_INSTANCE_AREA_DEFAULT, null, "", false, false, INSTANCE_DATA_AREA_PREFIX); //$NON-NLS-1$
    125         defaultLocation = temp == null ? null : temp.getURL();
    126         if (defaultLocation == null)
    127             defaultLocation = buildURL(new File(FrameworkProperties.getProperty(PROP_USER_DIR), "workspace").getAbsolutePath(), true); //$NON-NLS-1$
    128         instanceLocation = buildLocation(PROP_INSTANCE_AREA, defaultLocation, "", false, false, INSTANCE_DATA_AREA_PREFIX); //$NON-NLS-1$
    129 
    130         mungeConfigurationLocation();
    131         // compute a default but it is very unlikely to be used since main will have computed everything
    132         temp = buildLocation(PROP_CONFIG_AREA_DEFAULT, null, "", false, false, null); //$NON-NLS-1$
    133         defaultLocation = temp == null ? null : temp.getURL();
    134         if (defaultLocation == null && FrameworkProperties.getProperty(PROP_CONFIG_AREA) == null)
    135             // only compute the default if the configuration area property is not set
    136             defaultLocation = buildURL(computeDefaultConfigurationLocation(), true);
    137         configurationLocation = buildLocation(PROP_CONFIG_AREA, defaultLocation, "", false, false, null); //$NON-NLS-1$
    138         // get the parent location based on the system property. This will have been set on the 
    139         // way in either by the caller/user or by main.  There will be no parent location if we are not 
    140         // cascaded.
    141         URL parentLocation = computeSharedConfigurationLocation();
    142         if (parentLocation != null && !parentLocation.equals(configurationLocation.getURL())) {
    143             Location parent = new BasicLocation(null, parentLocation, true, null);
    144             ((BasicLocation) configurationLocation).setParent(parent);
    145         }
    146         initializeDerivedConfigurationLocations();
    147 
    148         if (FrameworkProperties.getProperty(PROP_HOME_LOCATION_AREA) == null) {
    149             String eclipseLauncher = FrameworkProperties.getProperty(PROP_LAUNCHER);
    150             String eclipseHomeLocationPath = getEclipseHomeLocation(eclipseLauncher);
    151             if (eclipseHomeLocationPath != null)
    152                 FrameworkProperties.setProperty(PROP_HOME_LOCATION_AREA, eclipseHomeLocationPath);
    153         }
    154         // if eclipse.home.location is not set then default to osgi.install.area
    155         if (FrameworkProperties.getProperty(PROP_HOME_LOCATION_AREA) == null && FrameworkProperties.getProperty(PROP_INSTALL_AREA) != null)
    156             FrameworkProperties.setProperty(PROP_HOME_LOCATION_AREA, FrameworkProperties.getProperty(PROP_INSTALL_AREA));
    157         eclipseHomeLocation = buildLocation(PROP_HOME_LOCATION_AREA, null, "", true, true, null); //$NON-NLS-1$
    158     }
    159 
    160     private static String getEclipseHomeLocation(String launcher) {
    161         if (launcher == null)
    162             return null;
    163         File launcherFile = new File(launcher);
    164         if (launcherFile.getParent() == null)
    165             return null;
    166         File launcherDir = new File(launcherFile.getParent());
    167         // check for mac os; the os check is copied from EclipseEnvironmentInfo.
    168         String macosx = org.eclipse.osgi.service.environment.Constants.OS_MACOSX;
    169         if (macosx.equals(EclipseEnvironmentInfo.getDefault().getOS()))
    170             launcherDir = getMacOSEclipsoeHomeLocation(launcherDir);
    171         return (launcherDir.exists() && launcherDir.isDirectory()) ? launcherDir.getAbsolutePath() : null;
    172     }
    173 
    174     private static File getMacOSEclipsoeHomeLocation(File launcherDir) {
    175         // TODO for now we go up three directories from the launcher dir as long as the parent dir is named MacOS; is this always the case?
    176         // TODO not sure if case is important
    177         if (!launcherDir.getName().equalsIgnoreCase("macos")) //$NON-NLS-1$
    178             return launcherDir; // don't do the up three stuff if not in macos directory
    179         String launcherParent = launcherDir.getParent();
    180         if (launcherParent != null)
    181             launcherParent = new File(launcherParent).getParent();
    182         if (launcherParent != null)
    183             launcherParent = new File(launcherParent).getParent();
    184         return launcherParent == null ? null : new File(launcherParent);
    185     }
    186 
    187     @SuppressWarnings("deprecation")
    188     private static Location buildLocation(String property, URL defaultLocation, String userDefaultAppendage, boolean readOnlyDefault, boolean computeReadOnly, String dataAreaPrefix) {
    189         String location = FrameworkProperties.clearProperty(property);
    190         // the user/product may specify a non-default readOnly setting   
    191         String userReadOnlySetting = FrameworkProperties.getProperty(property + READ_ONLY_AREA_SUFFIX);
    192         boolean readOnly = (userReadOnlySetting == null ? readOnlyDefault : Boolean.valueOf(userReadOnlySetting).booleanValue());
    193         // if the instance location is not set, predict where the workspace will be and 
    194         // put the instance area inside the workspace meta area.
    195         if (location == null)
    196             return new BasicLocation(property, defaultLocation, userReadOnlySetting != null || !computeReadOnly ? readOnly : !canWrite(defaultLocation), dataAreaPrefix);
    197         String trimmedLocation = location.trim();
    198         if (trimmedLocation.equalsIgnoreCase(NONE))
    199             return null;
    200         if (trimmedLocation.equalsIgnoreCase(NO_DEFAULT))
    201             return new BasicLocation(property, null, readOnly, dataAreaPrefix);
    202         if (trimmedLocation.startsWith(USER_HOME)) {
    203             String base = substituteVar(location, USER_HOME, PROP_USER_HOME);
    204             location = new File(base, userDefaultAppendage).getAbsolutePath();
    205         } else if (trimmedLocation.startsWith(USER_DIR)) {
    206             String base = substituteVar(location, USER_DIR, PROP_USER_DIR);
    207             location = new File(base, userDefaultAppendage).getAbsolutePath();
    208         }
    209         int idx = location.indexOf(INSTALL_HASH_PLACEHOLDER);
    210         if (idx == 0) {
    211             throw new RuntimeException("The location cannot start with '" + INSTALL_HASH_PLACEHOLDER + "': " + location); //$NON-NLS-1$ //$NON-NLS-2$
    212         } else if (idx > 0) {
    213             location = location.substring(0, idx) + getInstallDirHash() + location.substring(idx + INSTALL_HASH_PLACEHOLDER.length());
    214         }
    215         URL url = buildURL(location, true);
    216         BasicLocation result = null;
    217         if (url != null) {
    218             result = new BasicLocation(property, null, userReadOnlySetting != null || !computeReadOnly ? readOnly : !canWrite(url), dataAreaPrefix);
    219             result.setURL(url, false);
    220         }
    221         return result;
    222     }
    223 
    224     private static String substituteVar(String source, String var, String prop) {
    225         String value = FrameworkProperties.getProperty(prop, ""); //$NON-NLS-1$
    226         return value + source.substring(var.length());
    227     }
    228 
    229     private static void initializeDerivedConfigurationLocations() {
    230         if (FrameworkProperties.getProperty(PROP_MANIFEST_CACHE) == null)
    231             FrameworkProperties.setProperty(PROP_MANIFEST_CACHE, getConfigurationFile(MANIFESTS_DIR).getAbsolutePath());
    232     }
    233 
    234     private static URL computeInstallConfigurationLocation() {
    235         String property = FrameworkProperties.getProperty(PROP_INSTALL_AREA);
    236         if (property != null)
    237             return LocationHelper.buildURL(property, true);
    238         return null;
    239     }
    240 
    241     private static URL computeSharedConfigurationLocation() {
    242         String property = FrameworkProperties.getProperty(PROP_SHARED_CONFIG_AREA);
    243         if (property == null)
    244             return null;
    245         try {
    246             URL sharedConfigurationURL = LocationHelper.buildURL(property, true);
    247             if (sharedConfigurationURL == null)
    248                 return null;
    249             if (sharedConfigurationURL.getPath().startsWith("/")) //$NON-NLS-1$
    250                 // absolute
    251                 return sharedConfigurationURL;
    252             URL installURL = installLocation.getURL();
    253             if (!sharedConfigurationURL.getProtocol().equals(installURL.getProtocol()))
    254                 // different protocol
    255                 return sharedConfigurationURL;
    256             sharedConfigurationURL = new URL(installURL, sharedConfigurationURL.getPath());
    257             FrameworkProperties.setProperty(PROP_SHARED_CONFIG_AREA, sharedConfigurationURL.toExternalForm());
    258         } catch (MalformedURLException e) {
    259             // do nothing here since it is basically impossible to get a bogus url 
    260         }
    261         return null;
    262     }
    263 
    264     private static String computeDefaultConfigurationLocation() {
    265         // 1) We store the config state relative to the 'eclipse' directory if possible
    266         // 2) If this directory is read-only 
    267         //    we store the state in <user.home>/.eclipse/<application-id>_<version> where <user.home> 
    268         //    is unique for each local user, and <application-id> is the one 
    269         //    defined in .eclipseproduct marker file. If .eclipseproduct does not
    270         //    exist, use "eclipse" as the application-id.
    271 
    272         URL installURL = computeInstallConfigurationLocation();
    273         if (installURL != null && "file".equals(installURL.getProtocol())) { //$NON-NLS-1$
    274             File installDir = new File(installURL.getFile());
    275             File defaultConfigDir = new File(installDir, CONFIG_DIR);
    276             if (!defaultConfigDir.exists())
    277                 defaultConfigDir.mkdirs();
    278             if (defaultConfigDir.exists() && AdaptorUtil.canWrite(defaultConfigDir))
    279                 return defaultConfigDir.getAbsolutePath();
    280         }
    281         // We can't write in the eclipse install dir so try for some place in the user's home dir
    282         return computeDefaultUserAreaLocation(CONFIG_DIR);
    283     }
    284 
    285     private static boolean canWrite(URL location) {
    286         if (location != null && "file".equals(location.getProtocol())) { //$NON-NLS-1$
    287             File locationDir = new File(location.getFile());
    288             if (!locationDir.exists())
    289                 locationDir.mkdirs();
    290             if (locationDir.exists() && AdaptorUtil.canWrite(locationDir))
    291                 return true;
    292         }
    293         return false;
    294     }
    295 
    296     private static String computeDefaultUserAreaLocation(String pathAppendage) {
    297         //    we store the state in <user.home>/.eclipse/<application-id>_<version> where <user.home> 
    298         //    is unique for each local user, and <application-id> is the one 
    299         //    defined in .eclipseproduct marker file. If .eclipseproduct does not
    300         //    exist, use "eclipse" as the application-id.
    301         String installProperty = FrameworkProperties.getProperty(PROP_INSTALL_AREA);
    302         URL installURL = buildURL(installProperty, true);
    303         if (installURL == null)
    304             return null;
    305         File installDir = new File(installURL.getFile());
    306         String installDirHash = getInstallDirHash();
    307 
    308         String appName = "." + ECLIPSE; //$NON-NLS-1$
    309         File eclipseProduct = new File(installDir, PRODUCT_SITE_MARKER);
    310         if (eclipseProduct.exists()) {
    311             Properties props = new Properties();
    312             try {
    313                 props.load(new FileInputStream(eclipseProduct));
    314                 String appId = props.getProperty(PRODUCT_SITE_ID);
    315                 if (appId == null || appId.trim().length() == 0)
    316                     appId = ECLIPSE;
    317                 String appVersion = props.getProperty(PRODUCT_SITE_VERSION);
    318                 if (appVersion == null || appVersion.trim().length() == 0)
    319                     appVersion = ""; //$NON-NLS-1$
    320                 appName += File.separator + appId + "_" + appVersion + "_" + installDirHash; //$NON-NLS-1$ //$NON-NLS-2$
    321             } catch (IOException e) {
    322                 // Do nothing if we get an exception.  We will default to a standard location 
    323                 // in the user's home dir.
    324                 // add the hash to help prevent collisions
    325                 appName += File.separator + installDirHash;
    326             }
    327         } else {
    328             // add the hash to help prevent collisions
    329             appName += File.separator + installDirHash;
    330         }
    331         String userHome = FrameworkProperties.getProperty(PROP_USER_HOME);
    332         return new File(userHome, appName + "/" + pathAppendage).getAbsolutePath(); //$NON-NLS-1$
    333     }
    334 
    335     /**
    336      * Return hash code identifying an absolute installation path
    337      * @return hash code as String
    338      */
    339     private static String getInstallDirHash() {
    340         // compute an install dir hash to prevent configuration area collisions with other eclipse installs
    341         String installProperty = FrameworkProperties.getProperty(PROP_INSTALL_AREA);
    342         URL installURL = buildURL(installProperty, true);
    343         if (installURL == null)
    344             return ""; //$NON-NLS-1$
    345         File installDir = new File(installURL.getFile());
    346         int hashCode;
    347         try {
    348             hashCode = installDir.getCanonicalPath().hashCode();
    349         } catch (IOException ioe) {
    350             // fall back to absolute path
    351             hashCode = installDir.getAbsolutePath().hashCode();
    352         }
    353         if (hashCode < 0)
    354             hashCode = -(hashCode);
    355         String installDirHash = String.valueOf(hashCode);
    356         return installDirHash;
    357     }
    358 
    359     /**
    360      * Returns the user Location object
    361      * @return the user Location object
    362      */
    363     public static Location getUserLocation() {
    364         return userLocation;
    365     }
    366 
    367     /**
    368      * Returns the configuration Location object
    369      * @return the configuration Location object
    370      */
    371     public static Location getConfigurationLocation() {
    372         return configurationLocation;
    373     }
    374 
    375     /**
    376      * Returns the install Location object
    377      * @return the install Location object
    378      */
    379     public static Location getInstallLocation() {
    380         return installLocation;
    381     }
    382 
    383     /**
    384      * Returns the instance Location object
    385      * @return the instance Location object
    386      */
    387     public static Location getInstanceLocation() {
    388         return instanceLocation;
    389     }
    390 
    391     public static Location getEclipseHomeLocation() {
    392         return eclipseHomeLocation;
    393     }
    394 
    395     /**
    396      * Returns the File object under the configuration location used for the OSGi configuration
    397      * @return the OSGi configuration directory
    398      */
    399     public static File getOSGiConfigurationDir() {
    400         // TODO assumes the URL is a file: url
    401         return new File(configurationLocation.getURL().getFile(), FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME);
    402     }
    403 
    404     /**
    405      * Returns a file from the configuration area that can be used by the framework
    406      * @param filename the filename
    407      * @return a file from the configuration area
    408      */
    409     public static File getConfigurationFile(String filename) {
    410         File dir = getOSGiConfigurationDir();
    411         if (!dir.exists())
    412             dir.mkdirs();
    413         return new File(dir, filename);
    414     }
    415 }
    LocationManager
  • createAdaptor

DEFAULT_ADAPTER_CLASS = org.eclipse.osgi.baseadaptor.BaseAdaptor

  1 /*******************************************************************************
  2  * Copyright (c) 2005, 2011 IBM Corporation and others.
  3  * All rights reserved. This program and the accompanying materials
  4  * are made available under the terms of the Eclipse Public License v1.0
  5  * which accompanies this distribution, and is available at
  6  * http://www.eclipse.org/legal/epl-v10.html
  7  *
  8  * Contributors:
  9  *     IBM Corporation - initial API and implementation
 10  *******************************************************************************/
 11 
 12 package org.eclipse.osgi.baseadaptor;
 13 
 14 import java.io.*;
 15 import java.net.URL;
 16 import java.net.URLConnection;
 17 import java.util.*;
 18 import org.eclipse.core.runtime.adaptor.LocationManager;
 19 import org.eclipse.osgi.baseadaptor.bundlefile.BundleFile;
 20 import org.eclipse.osgi.baseadaptor.hooks.*;
 21 import org.eclipse.osgi.framework.adaptor.*;
 22 import org.eclipse.osgi.framework.debug.Debug;
 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.*;
 28 import org.eclipse.osgi.service.resolver.PlatformAdmin;
 29 import org.eclipse.osgi.service.resolver.State;
 30 import org.eclipse.osgi.util.NLS;
 31 import org.osgi.framework.*;
 32 import org.osgi.framework.wiring.BundleWiring;
 33 
 34 /**
 35  * A Framework adaptor implementation that allows additional functionality to be
 36  * hooked in.  Hooks are configured using {@link HookConfigurator}
 37  * objects.   A framework extension may add hook configurators which can be used
 38  * to add hooks to the {@link HookRegistry}.
 39  * @see HookConfigurator
 40  * @see HookRegistry
 41  * @see AdaptorHook
 42  * @since 3.2
 43  */
 44 public class BaseAdaptor implements FrameworkAdaptor {
 45     // System property used to set the parent classloader type (boot is the default)
 46     private static final String PROP_PARENT_CLASSLOADER = "osgi.parentClassloader"; //$NON-NLS-1$
 47     // A parent classloader type that specifies the application classloader
 48     private static final String PARENT_CLASSLOADER_APP = "app"; //$NON-NLS-1$
 49     // A parent classloader type that specifies the extension classlaoder
 50     private static final String PARENT_CLASSLOADER_EXT = "ext"; //$NON-NLS-1$
 51     // A parent classloader type that specifies the boot classlaoder
 52     private static final String PARENT_CLASSLOADER_BOOT = "boot"; //$NON-NLS-1$
 53     // A parent classloader type that specifies the framework classlaoder
 54     private static final String PARENT_CLASSLOADER_FWK = "fwk"; //$NON-NLS-1$
 55     // The BundleClassLoader parent to use when creating BundleClassLoaders.
 56     private static ClassLoader bundleClassLoaderParent;
 57     static {
 58         // check property for specified parent
 59         // check the osgi defined property first
 60         String type = FrameworkProperties.getProperty(Constants.FRAMEWORK_BUNDLE_PARENT);
 61         if (type != null) {
 62             if (Constants.FRAMEWORK_BUNDLE_PARENT_FRAMEWORK.equals(type))
 63                 type = PARENT_CLASSLOADER_FWK;
 64         } else {
 65             type = FrameworkProperties.getProperty(BaseAdaptor.PROP_PARENT_CLASSLOADER, BaseAdaptor.PARENT_CLASSLOADER_BOOT);
 66         }
 67 
 68         if (BaseAdaptor.PARENT_CLASSLOADER_FWK.equalsIgnoreCase(type))
 69             bundleClassLoaderParent = FrameworkAdaptor.class.getClassLoader();
 70         else if (BaseAdaptor.PARENT_CLASSLOADER_APP.equalsIgnoreCase(type))
 71             bundleClassLoaderParent = ClassLoader.getSystemClassLoader();
 72         else if (BaseAdaptor.PARENT_CLASSLOADER_EXT.equalsIgnoreCase(type)) {
 73             ClassLoader appCL = ClassLoader.getSystemClassLoader();
 74             if (appCL != null)
 75                 bundleClassLoaderParent = appCL.getParent();
 76         }
 77         // default to boot classloader
 78         if (bundleClassLoaderParent == null)
 79             bundleClassLoaderParent = new ClassLoader(Object.class.getClassLoader()) {/* boot class loader*/};
 80     }
 81 
 82     private Framework eventPublisher;
 83     private boolean stopping;
 84     private HookRegistry hookRegistry;
 85     private FrameworkLog log;
 86     private BundleContext context;
 87     private BaseStorage storage;
 88     private BundleWatcher bundleWatcher;
 89 
 90     /**
 91      * Constructs a BaseAdaptor.
 92      * @param args arguments passed to the adaptor by the framework.
 93      */
 94     public BaseAdaptor(String[] args) {
 95         if (LocationManager.getConfigurationLocation() == null)
 96             LocationManager.initializeLocations();
 97         hookRegistry = new HookRegistry(this);
 98         FrameworkLogEntry[] errors = hookRegistry.initialize();
 99         if (errors.length > 0)
100             for (int i = 0; i < errors.length; i++)
101                 getFrameworkLog().log(errors[i]);
102         // get the storage after the registry has been initialized
103         storage = getStorage();
104         // TODO consider passing args to BaseAdaptorHooks
105     }
106 
107     /**
108      * This method will call all configured adaptor hooks {@link AdaptorHook#initialize(BaseAdaptor)} method.
109      * @see FrameworkAdaptor#initialize(EventPublisher)
110      */
111     public void initialize(EventPublisher publisher) {
112         this.eventPublisher = (Framework) publisher;
113         // set the adaptor for the adaptor hooks
114         AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks();
115         for (int i = 0; i < adaptorHooks.length; i++)
116             adaptorHooks[i].initialize(this);
117     }
118 
119     /**
120      * @see FrameworkAdaptor#initializeStorage()
121      */
122     public void initializeStorage() throws IOException {
123         storage.initialize(this);
124     }
125 
126     /**
127      * @throws IOException 
128      * @see FrameworkAdaptor#compactStorage()
129      */
130     public void compactStorage() throws IOException {
131         storage.compact();
132     }
133 
134     /**
135      * This method will call all the configured adaptor hook {@link AdaptorHook#addProperties(Properties)} methods.
136      * @see FrameworkAdaptor#getProperties()
137      */
138     public Properties getProperties() {
139         Properties props = new Properties();
140         String resource = FrameworkProperties.getProperty(Constants.OSGI_PROPERTIES, Constants.DEFAULT_OSGI_PROPERTIES);
141         try {
142             InputStream in = null;
143             File file = new File(resource);
144             if (file.exists())
145                 in = new FileInputStream(file);
146             if (in == null)
147                 in = getClass().getResourceAsStream(resource);
148             if (in != null) {
149                 try {
150                     props.load(new BufferedInputStream(in));
151                 } finally {
152                     try {
153                         in.close();
154                     } catch (IOException ee) {
155                         // nothing to do
156                     }
157                 }
158             } else {
159                 if (Debug.DEBUG_GENERAL)
160                     Debug.println("Skipping osgi.properties: " + resource); //$NON-NLS-1$
161             }
162         } catch (IOException e) {
163             if (Debug.DEBUG_GENERAL)
164                 Debug.println("Unable to load osgi.properties: " + e.getMessage()); //$NON-NLS-1$
165         }
166         // add the storage properties
167         storage.addProperties(props);
168         // add the properties from each adaptor hook
169         AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks();
170         for (int i = 0; i < adaptorHooks.length; i++)
171             adaptorHooks[i].addProperties(props);
172         return props;
173     }
174 
175     /**
176      * @see FrameworkAdaptor#getInstalledBundles()
177      */
178     public BundleData[] getInstalledBundles() {
179         return storage.getInstalledBundles();
180     }
181 
182     /**
183      * This method will call each configured adaptor hook {@link AdaptorHook#mapLocationToURLConnection(String)} method
184      * until one returns a non-null value.  If none of the adaptor hooks return a non-null value then the 
185      * string is used to construct a new URL object to open a new url connection.
186      * 
187      * @see FrameworkAdaptor#mapLocationToURLConnection(String)
188      */
189     public URLConnection mapLocationToURLConnection(String location) throws BundleException {
190         try {
191             URLConnection result = null;
192             // try the adaptor hooks first;
193             AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks();
194             for (int i = 0; i < adaptorHooks.length; i++) {
195                 result = adaptorHooks[i].mapLocationToURLConnection(location);
196                 if (result != null)
197                     return result;
198             }
199             // just do the default
200             return (new URL(location).openConnection());
201         } catch (IOException e) {
202             throw new BundleException(NLS.bind(AdaptorMsg.ADAPTOR_URL_CREATE_EXCEPTION, location), e);
203         }
204     }
205 
206     /**
207      * @see FrameworkAdaptor#installBundle(String, URLConnection)
208      */
209     public BundleOperation installBundle(String location, URLConnection source) {
210         return storage.installBundle(location, source);
211     }
212 
213     /**
214      * @see FrameworkAdaptor#updateBundle(BundleData, URLConnection)
215      */
216     public BundleOperation updateBundle(BundleData bundledata, URLConnection source) {
217         return storage.updateBundle((BaseData) bundledata, source);
218     }
219 
220     /**
221      * @see FrameworkAdaptor#uninstallBundle(BundleData)
222      */
223     public BundleOperation uninstallBundle(BundleData bundledata) {
224         return storage.uninstallBundle((BaseData) bundledata);
225     }
226 
227     /**
228      * @see FrameworkAdaptor#getTotalFreeSpace()
229      */
230     public long getTotalFreeSpace() throws IOException {
231         return storage.getFreeSpace();
232     }
233 
234     /**
235      * @throws IOException 
236      * @see FrameworkAdaptor#getPermissionStorage()
237      */
238     public PermissionStorage getPermissionStorage() throws IOException {
239         return storage.getPermissionStorage();
240     }
241 
242     /**
243      * This method calls all the configured adaptor hook {@link AdaptorHook#frameworkStart(BundleContext)} methods.
244      * @see FrameworkAdaptor#frameworkStart(BundleContext)
245      */
246     public void frameworkStart(BundleContext fwContext) throws BundleException {
247         this.context = fwContext;
248         stopping = false;
249         // always start the storage first
250         storage.frameworkStart(fwContext);
251         AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks();
252         for (int i = 0; i < adaptorHooks.length; i++)
253             adaptorHooks[i].frameworkStart(fwContext);
254     }
255 
256     /**
257      * This method calls all the configured adaptor hook {@link AdaptorHook#frameworkStop(BundleContext)} methods.
258      * @see FrameworkAdaptor#frameworkStop(BundleContext)
259      */
260     public void frameworkStop(BundleContext fwContext) throws BundleException {
261         // first inform all configured adaptor hooks
262         AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks();
263         for (int i = 0; i < adaptorHooks.length; i++)
264             adaptorHooks[i].frameworkStop(fwContext);
265         // stop the storage last
266         storage.frameworkStop(fwContext);
267     }
268 
269     /**
270      * This method calls all the configured adaptor hook {@link AdaptorHook#frameworkStopping(BundleContext)} methods.
271      * @see FrameworkAdaptor#frameworkStopping(BundleContext)
272      */
273     public void frameworkStopping(BundleContext fwContext) {
274         stopping = true;
275         // always tell storage of stopping first
276         storage.frameworkStopping(fwContext);
277         // inform all configured adaptor hooks last
278         AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks();
279         for (int i = 0; i < adaptorHooks.length; i++)
280             adaptorHooks[i].frameworkStopping(fwContext);
281     }
282 
283     /**
284      * @see FrameworkAdaptor#getInitialBundleStartLevel()
285      */
286     public int getInitialBundleStartLevel() {
287         return storage.getInitialBundleStartLevel();
288     }
289 
290     /**
291      * @see FrameworkAdaptor#setInitialBundleStartLevel(int)
292      */
293     public void setInitialBundleStartLevel(int value) {
294         storage.setInitialBundleStartLevel(value);
295     }
296 
297     /**
298      * This method calls all configured adaptor hook  {@link AdaptorHook#createFrameworkLog()} methods 
299      * until the first one returns a non-null value.  If none of the adaptor hooks return a non-null
300      * value then a framework log implementation which does nothing is returned.
301      * @see FrameworkAdaptor#getFrameworkLog()
302      */
303     public FrameworkLog getFrameworkLog() {
304         if (log != null)
305             return log;
306         AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks();
307         for (int i = 0; i < adaptorHooks.length; i++) {
308             log = adaptorHooks[i].createFrameworkLog();
309             if (log != null)
310                 return log;
311         }
312         log = new FrameworkLog() {
313             public void log(FrameworkEvent frameworkEvent) {
314                 log(new FrameworkLogEntry(frameworkEvent.getBundle().getSymbolicName() == null ? frameworkEvent.getBundle().getLocation() : frameworkEvent.getBundle().getSymbolicName(), FrameworkLogEntry.ERROR, 0, "FrameworkEvent.ERROR", 0, frameworkEvent.getThrowable(), null)); //$NON-NLS-1$
315             }
316 
317             public void log(FrameworkLogEntry logEntry) {
318                 System.err.print(logEntry.getEntry() + " "); //$NON-NLS-1$
319                 System.err.println(logEntry.getMessage());
320                 if (logEntry.getThrowable() != null)
321                     logEntry.getThrowable().printStackTrace(System.err);
322             }
323 
324             public void setWriter(Writer newWriter, boolean append) {
325                 // do nothing
326             }
327 
328             /**
329              * @throws IOException  
330              */
331             public void setFile(File newFile, boolean append) throws IOException {
332                 // do nothing
333             }
334 
335             public File getFile() {
336                 // do nothing
337                 return null;
338             }
339 
340             public void setConsoleLog(boolean consoleLog) {
341                 // do nothing
342             }
343 
344             public void close() {
345                 // do nothing
346             }
347         };
348         return log;
349     }
350 
351     /**
352      * @see FrameworkAdaptor#createSystemBundleData()
353      */
354     public BundleData createSystemBundleData() throws BundleException {
355         return new SystemBundleData(this);
356     }
357 
358     /**
359      * @see FrameworkAdaptor#getBundleWatcher()
360      */
361     public BundleWatcher getBundleWatcher() {
362         if (bundleWatcher != null)
363             return bundleWatcher;
364         final BundleWatcher[] watchers = hookRegistry.getWatchers();
365         if (watchers.length == 0)
366             return null;
367         bundleWatcher = new BundleWatcher() {
368             public void watchBundle(Bundle bundle, int type) {
369                 for (int i = 0; i < watchers.length; i++)
370                     watchers[i].watchBundle(bundle, type);
371             }
372         };
373         return bundleWatcher;
374     }
375 
376     /**
377      * @see FrameworkAdaptor#getPlatformAdmin()
378      */
379     public PlatformAdmin getPlatformAdmin() {
380         return storage.getStateManager();
381     }
382 
383     /**
384      * @see FrameworkAdaptor#getState()
385      */
386     public State getState() {
387         return storage.getStateManager().getSystemState();
388     }
389 
390     /**
391      * This method calls all the configured classloading hooks {@link ClassLoadingHook#getBundleClassLoaderParent()} methods 
392      * until one returns a non-null value.
393      * @see FrameworkAdaptor#getBundleClassLoaderParent()
394      */
395     public ClassLoader getBundleClassLoaderParent() {
396         // ask the configured adaptor hooks first
397         ClassLoader result = null;
398         ClassLoadingHook[] cpManagerHooks = getHookRegistry().getClassLoadingHooks();
399         for (int i = 0; i < cpManagerHooks.length; i++) {
400             result = cpManagerHooks[i].getBundleClassLoaderParent();
401             if (result != null)
402                 return result;
403         }
404         // none of the configured adaptor hooks gave use a parent loader; use the default
405         return bundleClassLoaderParent;
406     }
407 
408     /**
409      * This method calls all the configured adaptor hooks  {@link AdaptorHook#handleRuntimeError(Throwable)} methods.
410      * @see FrameworkAdaptor#handleRuntimeError(Throwable)
411      */
412     public void handleRuntimeError(Throwable error) {
413         AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks();
414         for (int i = 0; i < adaptorHooks.length; i++)
415             adaptorHooks[i].handleRuntimeError(error);
416     }
417 
418     /**
419      * Returns true if the {@link #frameworkStopping(BundleContext)} method has been called
420      * @return true if the framework is stopping
421      */
422     public boolean isStopping() {
423         return stopping;
424     }
425 
426     /**
427      * Returns the event publisher for this BaseAdaptor
428      * @return the event publisher for this BaseAdaptor
429      */
430     public EventPublisher getEventPublisher() {
431         return eventPublisher;
432     }
433 
434     /**
435      * Returns the <code>HookRegistry</code> object for this adaptor.
436      * @return the <code>HookRegistry</code> object for this adaptor.
437      */
438     public HookRegistry getHookRegistry() {
439         return hookRegistry;
440     }
441 
442     /**
443      * Returns the system bundle's context
444      * @return the system bundle's context
445      */
446     public BundleContext getContext() {
447         return context;
448     }
449 
450     /**
451      * Returns the bundle with the specified identifier.  This method 
452      * does not invoke and bundle find hooks and therefore does not 
453      * allow bundle find hooks to hide a bundle from the caller.
454      * 
455      * @param id The identifier of the bundle to retrieve.
456      * @return A {@code Bundle} object or {@code null} if the identifier does
457      *         not match any installed bundle.
458      */
459     public Bundle getBundle(long id) {
460         return eventPublisher.getBundle(id);
461     }
462 
463     /**
464      * Creates a bundle file object for the given content and base data. 
465      * This method must delegate to each configured bundle file factory 
466      * {@link BundleFileFactoryHook#createBundleFile(Object, BaseData, boolean)} method until one 
467      * factory returns a non-null value.  If no bundle file factory returns a non-null value 
468      * then the the default behavior will be performed.
469      * <p>
470      * If the specified content is <code>null</code> then the base content of the specified 
471      * bundledata must be found before calling any bundle file factories.
472      * </p>
473      * <p>
474      * After the bundle file has been created each configured bundle file wrapper factory
475      * {@link BundleFileWrapperFactoryHook#wrapBundleFile(BundleFile, Object, BaseData, boolean)}
476      * method is called to wrap the bundle file.
477      * </p>
478      * @param content The object which contains the content of a bundle file. A value of 
479      * <code>null</code> indicates that the storage must find the base content for the 
480      * specified BaseData.
481      * @param data The BaseData associated with the content
482      * @return a BundleFile object.
483      * @throws IOException if an error occured while creating the BundleFile
484      */
485     public BundleFile createBundleFile(Object content, BaseData data) throws IOException {
486         return storage.createBundleFile(content, data);
487     }
488 
489     /**
490      * Returns true if the persistent storage is read-only
491      * @return true if the persistent storage is read-only
492      */
493     public boolean isReadOnly() {
494         return storage.isReadOnly();
495     }
496 
497     /*
498      * This is an experimental method to allow adaptors to replace the storage implementation by 
499      * extending BaseAdaptor and overriding this method.  This method is experimental.
500      * @return a base storage object.
501      */
502     protected BaseStorage getStorage() {
503         if (storage != null)
504             return storage;
505         // this bit of code assumes the registry is initialized with a BaseStorageHook
506         // we want to make sure we are using the same BaseStorage instance as the BaseStorageHook
507         StorageHook[] hooks = hookRegistry.getStorageHooks();
508         for (int i = 0; i < hooks.length && storage == null; i++)
509             if (hooks[i] instanceof BaseStorageHook)
510                 storage = ((BaseStorageHook) hooks[i]).getStorage();
511         return storage;
512     }
513 
514     /**
515      * @see FrameworkAdaptor#findEntries(List, String, String, int)
516      */
517     public Enumeration<URL> findEntries(List<BundleData> datas, String path, String filePattern, int options) {
518         List<BundleFile> bundleFiles = new ArrayList<BundleFile>(datas.size());
519         for (BundleData data : datas)
520             bundleFiles.add(((BaseData) data).getBundleFile());
521         // search all the bundle files
522         List<String> pathList = listEntryPaths(bundleFiles, path, filePattern, options);
523         // return null if no entries found
524         if (pathList.size() == 0)
525             return null;
526         // create an enumeration to enumerate the pathList
527         final String[] pathArray = pathList.toArray(new String[pathList.size()]);
528         final BundleData[] dataArray = datas.toArray(new BundleData[datas.size()]);
529         return new Enumeration<URL>() {
530             private int curPathIndex = 0;
531             private int curDataIndex = 0;
532             private URL nextElement = null;
533 
534             public boolean hasMoreElements() {
535                 if (nextElement != null)
536                     return true;
537                 getNextElement();
538                 return nextElement != null;
539             }
540 
541             public URL nextElement() {
542                 if (!hasMoreElements())
543                     throw new NoSuchElementException();
544                 URL result = nextElement;
545                 // force the next element search
546                 getNextElement();
547                 return result;
548             }
549 
550             private void getNextElement() {
551                 nextElement = null;
552                 if (curPathIndex >= pathArray.length)
553                     // reached the end of the pathArray; no more elements
554                     return;
555                 while (nextElement == null && curPathIndex < pathArray.length) {
556                     String curPath = pathArray[curPathIndex];
557                     // search the datas until we have searched them all
558                     while (nextElement == null && curDataIndex < dataArray.length)
559                         nextElement = dataArray[curDataIndex++].getEntry(curPath);
560                     // we have searched all datas then advance to the next path 
561                     if (curDataIndex >= dataArray.length) {
562                         curPathIndex++;
563                         curDataIndex = 0;
564                     }
565                 }
566             }
567         };
568     }
569 
570     /**
571      * Returns the names of resources available from a list of bundle files.
572      * No duplicate resource names are returned, each name is unique.
573      * @param bundleFiles the list of bundle files to search in
574      * @param path The path name in which to look.
575      * @param filePattern The file name pattern for selecting resource names in
576      *        the specified path.
577      * @param options The options for listing resource names.
578      * @return a list of resource names.  If no resources are found then
579      * the empty list is returned.
580      * @see BundleWiring#listResources(String, String, int)
581      */
582     public List<String> listEntryPaths(List<BundleFile> bundleFiles, String path, String filePattern, int options) {
583         // a list used to store the results of the search
584         List<String> pathList = new ArrayList<String>();
585         Filter patternFilter = null;
586         Hashtable<String, String> patternProps = null;
587         if (filePattern != null) {
588             // Optimization: If the file pattern does not include a wildcard  or escape  char then it must represent a single file.
589             // Avoid pattern matching and use BundleFile.getEntry() if recursion was not requested.
590             if ((options & BundleWiring.FINDENTRIES_RECURSE) == 0 && filePattern.indexOf('*') == -1 && filePattern.indexOf('\\') == -1) {
591                 if (path.length() == 0)
592                     path = filePattern;
593                 else
594                     path += path.charAt(path.length() - 1) == '/' ? filePattern : '/' + filePattern;
595                 for (BundleFile bundleFile : bundleFiles) {
596                     if (bundleFile.getEntry(path) != null && !pathList.contains(path))
597                         pathList.add(path);
598                 }
599                 return pathList;
600             }
601             // For when the file pattern includes a wildcard.
602             try {
603                 // create a file pattern filter with 'filename' as the key
604                 patternFilter = FilterImpl.newInstance("(filename=" + sanitizeFilterInput(filePattern) + ")"); //$NON-NLS-1$ //$NON-NLS-2$
605                 // create a single hashtable to be shared during the recursive search
606                 patternProps = new Hashtable<String, String>(2);
607             } catch (InvalidSyntaxException e) {
608                 // something unexpected happened; log error and return nothing
609                 Bundle b = context == null ? null : context.getBundle();
610                 eventPublisher.publishFrameworkEvent(FrameworkEvent.ERROR, b, e);
611                 return pathList;
612             }
613         }
614         // find the entry paths for the datas
615         for (BundleFile bundleFile : bundleFiles) {
616             listEntryPaths(bundleFile, path, patternFilter, patternProps, options, pathList);
617         }
618         return pathList;
619     }
620 
621     private String sanitizeFilterInput(String filePattern) throws InvalidSyntaxException {
622         StringBuffer buffer = null;
623         boolean foundEscape = false;
624         for (int i = 0; i < filePattern.length(); i++) {
625             char c = filePattern.charAt(i);
626             switch (c) {
627                 case '\\' :
628                     // we either used the escape found or found a new escape.
629                     foundEscape = foundEscape ? false : true;
630                     if (buffer != null)
631                         buffer.append(c);
632                     break;
633                 case '(' :
634                 case ')' :
635                     if (!foundEscape) {
636                         if (buffer == null) {
637                             buffer = new StringBuffer(filePattern.length() + 16);
638                             buffer.append(filePattern.substring(0, i));
639                         }
640                         // must escape with '\'
641                         buffer.append('\\');
642                     } else {
643                         foundEscape = false; // used the escape found
644                     }
645                     if (buffer != null)
646                         buffer.append(c);
647                     break;
648                 default :
649                     // if we found an escape it has been used
650                     foundEscape = false;
651                     if (buffer != null)
652                         buffer.append(c);
653                     break;
654             }
655         }
656         if (foundEscape)
657             throw new InvalidSyntaxException("Trailing escape characters must be escaped.", filePattern); //$NON-NLS-1$
658         return buffer == null ? filePattern : buffer.toString();
659     }
660 
661     private List<String> listEntryPaths(BundleFile bundleFile, String path, Filter patternFilter, Hashtable<String, String> patternProps, int options, List<String> pathList) {
662         if (pathList == null)
663             pathList = new ArrayList<String>();
664         Enumeration<String> entryPaths = bundleFile.getEntryPaths(path);
665         if (entryPaths == null)
666             return pathList;
667         while (entryPaths.hasMoreElements()) {
668             String entry = entryPaths.nextElement();
669             int lastSlash = entry.lastIndexOf('/');
670             if (patternProps != null) {
671                 int secondToLastSlash = entry.lastIndexOf('/', lastSlash - 1);
672                 int fileStart;
673                 int fileEnd = entry.length();
674                 if (lastSlash < 0)
675                     fileStart = 0;
676                 else if (lastSlash != entry.length() - 1)
677                     fileStart = lastSlash + 1;
678                 else {
679                     fileEnd = lastSlash; // leave the lastSlash out
680                     if (secondToLastSlash < 0)
681                         fileStart = 0;
682                     else
683                         fileStart = secondToLastSlash + 1;
684                 }
685                 String fileName = entry.substring(fileStart, fileEnd);
686                 // set the filename to the current entry
687                 patternProps.put("filename", fileName); //$NON-NLS-1$
688             }
689             // prevent duplicates and match on the patternFilter
690             if (!pathList.contains(entry) && (patternFilter == null || patternFilter.matchCase(patternProps)))
691                 pathList.add(entry);
692             // recurse only into entries that are directories
693             if (((options & BundleWiring.FINDENTRIES_RECURSE) != 0) && !entry.equals(path) && entry.length() > 0 && lastSlash == (entry.length() - 1))
694                 listEntryPaths(bundleFile, entry, patternFilter, patternProps, options, pathList);
695         }
696         return pathList;
697     }
698 
699 }
BaseAdaptor
  • 1 private static FrameworkAdaptor createAdaptor() throws Exception {
    2         String adaptorClassName = FrameworkProperties.getProperty(PROP_ADAPTOR, DEFAULT_ADAPTOR_CLASS);
    3         Class<?> adaptorClass = Class.forName(adaptorClassName);
    4         Class<?>[] constructorArgs = new Class[] {String[].class};
    5         Constructor<?> constructor = adaptorClass.getConstructor(constructorArgs);
    6         return (FrameworkAdaptor) constructor.newInstance(new Object[] {new String[0]});
    7     }
  • Create a new Framework
  • 1 framework = new Framework(adaptor); 
       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  *******************************************************************************/
      11 package org.eclipse.osgi.framework.internal.core;
      12 
      13 import java.io.*;
      14 import java.lang.reflect.*;
      15 import java.net.*;
      16 import java.security.*;
      17 import java.util.*;
      18 import org.eclipse.core.runtime.internal.adaptor.ContextFinder;
      19 import org.eclipse.osgi.baseadaptor.BaseAdaptor;
      20 import org.eclipse.osgi.framework.adaptor.*;
      21 import org.eclipse.osgi.framework.debug.Debug;
      22 import org.eclipse.osgi.framework.eventmgr.*;
      23 import org.eclipse.osgi.framework.internal.protocol.ContentHandlerFactory;
      24 import org.eclipse.osgi.framework.internal.protocol.StreamHandlerFactory;
      25 import org.eclipse.osgi.framework.log.FrameworkLogEntry;
      26 import org.eclipse.osgi.framework.util.SecureAction;
      27 import org.eclipse.osgi.internal.loader.*;
      28 import org.eclipse.osgi.internal.permadmin.EquinoxSecurityManager;
      29 import org.eclipse.osgi.internal.permadmin.SecurityAdmin;
      30 import org.eclipse.osgi.internal.profile.Profile;
      31 import org.eclipse.osgi.internal.serviceregistry.*;
      32 import org.eclipse.osgi.signedcontent.SignedContentFactory;
      33 import org.eclipse.osgi.util.ManifestElement;
      34 import org.eclipse.osgi.util.NLS;
      35 import org.osgi.framework.*;
      36 import org.osgi.framework.hooks.bundle.*;
      37 import org.osgi.util.tracker.ServiceTracker;
      38 
      39 /**
      40  * Core OSGi Framework class.
      41  */
      42 public class Framework implements EventPublisher, Runnable {
      43     // System property used to set the context classloader parent classloader type (ccl is the default)
      44     private static final String PROP_CONTEXTCLASSLOADER_PARENT = "osgi.contextClassLoaderParent"; //$NON-NLS-1$
      45     private static final String CONTEXTCLASSLOADER_PARENT_APP = "app"; //$NON-NLS-1$
      46     private static final String CONTEXTCLASSLOADER_PARENT_EXT = "ext"; //$NON-NLS-1$
      47     private static final String CONTEXTCLASSLOADER_PARENT_BOOT = "boot"; //$NON-NLS-1$
      48     private static final String CONTEXTCLASSLOADER_PARENT_FWK = "fwk"; //$NON-NLS-1$
      49 
      50     public static final String PROP_FRAMEWORK_THREAD = "osgi.framework.activeThreadType"; //$NON-NLS-1$
      51     public static final String THREAD_NORMAL = "normal"; //$NON-NLS-1$
      52     public static final String PROP_EQUINOX_SECURITY = "eclipse.security"; //$NON-NLS-1$
      53     public static final String SECURITY_OSGI = "osgi"; //$NON-NLS-1$
      54 
      55     private static String J2SE = "J2SE-"; //$NON-NLS-1$
      56     private static String JAVASE = "JavaSE-"; //$NON-NLS-1$
      57     private static String PROFILE_EXT = ".profile"; //$NON-NLS-1$
      58     /** FrameworkAdaptor specific functions. */
      59     protected FrameworkAdaptor adaptor;
      60     /** Framework properties object.  A reference to the 
      61      * System.getProperies() object.  The properties from
      62      * the adaptor will be merged into these properties.
      63      */
      64     protected Properties properties;
      65     /** Has the framework been started */
      66     protected boolean active;
      67     /** Event indicating the reason for shutdown*/
      68     private FrameworkEvent[] shutdownEvent;
      69     /** The bundles installed in the framework */
      70     protected BundleRepository bundles;
      71     /** Package Admin object. This object manages the exported packages. */
      72     protected PackageAdminImpl packageAdmin;
      73     /** PermissionAdmin and ConditionalPermissionAdmin impl. This object manages the bundle permissions. */
      74     protected SecurityAdmin securityAdmin;
      75     /** Startlevel object. This object manages the framework and bundle startlevels */
      76     protected StartLevelManager startLevelManager;
      77     /** The ServiceRegistry */
      78     private ServiceRegistry serviceRegistry;
      79     private final int BSN_VERSION;
      80     private static final int BSN_VERSION_SINGLE = 1;
      81     private static final int BSN_VERSION_MULTIPLE = 2;
      82     private static final int BSN_VERSION_MANAGED = 3;
      83 
      84     /*
      85      * The following maps objects keep track of event listeners
      86      * by BundleContext.  Each element is a Map that is the set
      87      * of event listeners for a particular BundleContext.  The max number of
      88      * elements each of the following maps will have is the number of bundles
      89      * installed in the Framework.
      90      */
      91     // Map of BundleContexts for bundle's BundleListeners.
      92     private final Map<BundleContextImpl, CopyOnWriteIdentityMap<BundleListener, BundleListener>> allBundleListeners = new HashMap<BundleContextImpl, CopyOnWriteIdentityMap<BundleListener, BundleListener>>();
      93     protected static final int BUNDLEEVENT = 1;
      94     // Map of BundleContexts for bundle's SynchronousBundleListeners.
      95     private final Map<BundleContextImpl, CopyOnWriteIdentityMap<SynchronousBundleListener, SynchronousBundleListener>> allSyncBundleListeners = new HashMap<BundleContextImpl, CopyOnWriteIdentityMap<SynchronousBundleListener, SynchronousBundleListener>>();
      96     protected static final int BUNDLEEVENTSYNC = 2;
      97     /* SERVICEEVENT(3) is now handled by ServiceRegistry */
      98     // Map of BundleContexts for bundle's FrameworkListeners.
      99     private final Map<BundleContextImpl, CopyOnWriteIdentityMap<FrameworkListener, FrameworkListener>> allFrameworkListeners = new HashMap<BundleContextImpl, CopyOnWriteIdentityMap<FrameworkListener, FrameworkListener>>();
     100     protected static final int FRAMEWORKEVENT = 4;
     101     protected static final int BATCHEVENT_BEGIN = Integer.MIN_VALUE + 1;
     102     protected static final int BATCHEVENT_END = Integer.MIN_VALUE;
     103     static final String eventHookName = EventHook.class.getName();
     104     static final String findHookName = FindHook.class.getName();
     105     static final String collisionHookName = CollisionHook.class.getName();
     106     /** EventManager for event delivery. */
     107     protected EventManager eventManager;
     108     /* Reservation object for install synchronization */
     109     private Map<String, Thread> installLock;
     110     /** System Bundle object */
     111     protected InternalSystemBundle systemBundle;
     112     private String[] bootDelegation;
     113     private String[] bootDelegationStems;
     114     private boolean bootDelegateAll = false;
     115     public final boolean contextBootDelegation = "true".equals(FrameworkProperties.getProperty("osgi.context.bootdelegation", "true")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
     116     public final boolean compatibiltyBootDelegation = "true".equals(FrameworkProperties.getProperty(Constants.OSGI_COMPATIBILITY_BOOTDELEGATION, "true")); //$NON-NLS-1$ //$NON-NLS-2$
     117     private final boolean allowRefreshDuplicateBSN = Boolean.TRUE.toString().equals(FrameworkProperties.getProperty(Constants.REFRESH_DUPLICATE_BSN, "true")); //$NON-NLS-1$
     118     ClassLoaderDelegateHook[] delegateHooks;
     119     private volatile boolean forcedRestart = false;
     120     /**
     121      * The AliasMapper used to alias OS Names.
     122      */
     123     protected static AliasMapper aliasMapper = new AliasMapper();
     124     SecureAction secureAction = AccessController.doPrivileged(SecureAction.createSecureAction());
     125     // cache of AdminPermissions keyed by Bundle ID
     126     private final Map<Long, Map<String, AdminPermission>> adminPermissions = new HashMap<Long, Map<String, AdminPermission>>();
     127 
     128     // we need to hold these so that we can unregister them at shutdown
     129     private StreamHandlerFactory streamHandlerFactory;
     130     private ContentHandlerFactory contentHandlerFactory;
     131 
     132     private volatile ServiceTracker<SignedContentFactory, SignedContentFactory> signedContentFactory;
     133     private volatile ContextFinder contextFinder;
     134 
     135     /* 
     136      * We need to make sure that the GetDataFileAction class loads early to prevent a ClassCircularityError when checking permissions.
     137      * see bug 161561
     138      */
     139     static {
     140         Class<?> c;
     141         c = GetDataFileAction.class;
     142         c.getName(); // to prevent compiler warnings
     143     }
     144 
     145     static class GetDataFileAction implements PrivilegedAction<File> {
     146         private AbstractBundle bundle;
     147         private String filename;
     148 
     149         public GetDataFileAction(AbstractBundle bundle, String filename) {
     150             this.bundle = bundle;
     151             this.filename = filename;
     152         }
     153 
     154         public File run() {
     155             return bundle.getBundleData().getDataFile(filename);
     156         }
     157     }
     158 
     159     /**
     160      * Constructor for the Framework instance. This method initializes the
     161      * framework to an unlaunched state.
     162      *  
     163      */
     164     public Framework(FrameworkAdaptor adaptor) {
     165         if (Profile.PROFILE && Profile.STARTUP)
     166             Profile.logEnter("Framework.initialze()", null); //$NON-NLS-1$
     167         String bsnVersion = FrameworkProperties.getProperty(Constants.FRAMEWORK_BSNVERSION);
     168         if (Constants.FRAMEWORK_BSNVERSION_SINGLE.equals(bsnVersion)) {
     169             BSN_VERSION = BSN_VERSION_SINGLE;
     170         } else if (Constants.FRAMEWORK_BSNVERSION_MULTIPLE.equals(bsnVersion)) {
     171             BSN_VERSION = BSN_VERSION_MULTIPLE;
     172         } else {
     173             BSN_VERSION = BSN_VERSION_MANAGED;
     174         }
     175         long start = System.currentTimeMillis();
     176         this.adaptor = adaptor;
     177         delegateHooks = adaptor instanceof BaseAdaptor ? ((BaseAdaptor) adaptor).getHookRegistry().getClassLoaderDelegateHooks() : null;
     178         active = false;
     179         installSecurityManager();
     180         if (Debug.DEBUG_SECURITY) {
     181             Debug.println("SecurityManager: " + System.getSecurityManager()); //$NON-NLS-1$
     182             Debug.println("ProtectionDomain of Framework.class: \n" + this.getClass().getProtectionDomain()); //$NON-NLS-1$
     183         }
     184         setNLSFrameworkLog();
     185         // initialize ContextFinder
     186         initializeContextFinder();
     187         /* initialize the adaptor */
     188         adaptor.initialize(this);
     189         if (Profile.PROFILE && Profile.STARTUP)
     190             Profile.logTime("Framework.initialze()", "adapter initialized"); //$NON-NLS-1$//$NON-NLS-2$
     191         try {
     192             adaptor.initializeStorage();
     193         } catch (IOException e) /* fatal error */{
     194             throw new RuntimeException(e.getMessage(), e);
     195         }
     196         if (Profile.PROFILE && Profile.STARTUP)
     197             Profile.logTime("Framework.initialze()", "adapter storage initialized"); //$NON-NLS-1$//$NON-NLS-2$
     198         /*
     199          * This must be done before calling any of the framework getProperty
     200          * methods.
     201          */
     202         initializeProperties(adaptor.getProperties());
     203         /* initialize admin objects */
     204         packageAdmin = new PackageAdminImpl(this);
     205         try {
     206             // always create security admin even with security off
     207             securityAdmin = new SecurityAdmin(null, this, adaptor.getPermissionStorage());
     208         } catch (IOException e) /* fatal error */{
     209             e.printStackTrace();
     210             throw new RuntimeException(e.getMessage(), e);
     211         }
     212         if (Profile.PROFILE && Profile.STARTUP)
     213             Profile.logTime("Framework.initialze()", "done init props & new PermissionAdminImpl"); //$NON-NLS-1$//$NON-NLS-2$
     214         startLevelManager = new StartLevelManager(this);
     215         /* create the event manager and top level event dispatchers */
     216         eventManager = new EventManager("Framework Event Dispatcher"); //$NON-NLS-1$
     217         if (Profile.PROFILE && Profile.STARTUP)
     218             Profile.logTime("Framework.initialze()", "done new EventManager"); //$NON-NLS-1$ //$NON-NLS-2$
     219         /* create the service registry */
     220         serviceRegistry = new ServiceRegistry(this);
     221         // Initialize the installLock; there is no way of knowing 
     222         // what the initial size should be, at most it will be the number
     223         // of threads trying to install a bundle (probably a very low number).
     224         installLock = new HashMap<String, Thread>(10);
     225         /* create the system bundle */
     226         createSystemBundle();
     227         loadVMProfile(); // load VM profile after the system bundle has been created
     228         setBootDelegation(); //set boot delegation property after system exports have been set
     229         if (Profile.PROFILE && Profile.STARTUP)
     230             Profile.logTime("Framework.initialze()", "done createSystemBundle"); //$NON-NLS-1$ //$NON-NLS-2$
     231         /* install URLStreamHandlerFactory */
     232         installURLStreamHandlerFactory(systemBundle.context, adaptor);
     233         /* install ContentHandlerFactory for OSGi URLStreamHandler support */
     234         installContentHandlerFactory(systemBundle.context, adaptor);
     235         if (Profile.PROFILE && Profile.STARTUP)
     236             Profile.logTime("Framework.initialze()", "done new URLStream/Content HandlerFactory"); //$NON-NLS-1$//$NON-NLS-2$
     237         /* create bundle objects for all installed bundles. */
     238         BundleData[] bundleDatas = adaptor.getInstalledBundles();
     239         bundles = new BundleRepository(bundleDatas == null ? 10 : bundleDatas.length + 1);
     240         /* add the system bundle to the Bundle Repository */
     241         bundles.add(systemBundle);
     242         if (bundleDatas != null) {
     243             for (int i = 0; i < bundleDatas.length; i++) {
     244                 try {
     245                     AbstractBundle bundle = AbstractBundle.createBundle(bundleDatas[i], this, true);
     246                     bundles.add(bundle);
     247                 } catch (BundleException be) {
     248                     // This is not a fatal error. Publish the framework event.
     249                     publishFrameworkEvent(FrameworkEvent.ERROR, systemBundle, be);
     250                 }
     251             }
     252         }
     253         if (Debug.DEBUG_GENERAL)
     254             System.out.println("Initialize the framework: " + (System.currentTimeMillis() - start)); //$NON-NLS-1$
     255         if (Profile.PROFILE && Profile.STARTUP)
     256             Profile.logExit("Framework.initialize()"); //$NON-NLS-1$
     257     }
     258 
     259     public FrameworkAdaptor getAdaptor() {
     260         return adaptor;
     261     }
     262 
     263     public ClassLoaderDelegateHook[] getDelegateHooks() {
     264         return delegateHooks;
     265     }
     266 
     267     public ServiceRegistry getServiceRegistry() {
     268         return serviceRegistry;
     269     }
     270 
     271     private void setNLSFrameworkLog() {
     272         try {
     273             Field frameworkLogField = NLS.class.getDeclaredField("frameworkLog"); //$NON-NLS-1$
     274             frameworkLogField.setAccessible(true);
     275             frameworkLogField.set(null, adaptor.getFrameworkLog());
     276         } catch (Exception e) {
     277             adaptor.getFrameworkLog().log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, e.getMessage(), 0, e, null));
     278         }
     279     }
     280 
     281     private void createSystemBundle() {
     282         try {
     283             systemBundle = new InternalSystemBundle(this);
     284             systemBundle.getBundleData().setBundle(systemBundle);
     285         } catch (BundleException e) { // fatal error
     286             e.printStackTrace();
     287             throw new RuntimeException(NLS.bind(Msg.OSGI_SYSTEMBUNDLE_CREATE_EXCEPTION, e.getMessage()), e);
     288         }
     289     }
     290 
     291     /**
     292      * Initialize the System properties by copying properties from the adaptor
     293      * properties object. This method is called by the initialize method.
     294      *  
     295      */
     296     protected void initializeProperties(Properties adaptorProperties) {
     297         properties = FrameworkProperties.getProperties();
     298         Enumeration<?> enumKeys = adaptorProperties.propertyNames();
     299         while (enumKeys.hasMoreElements()) {
     300             String key = (String) enumKeys.nextElement();
     301             if (properties.getProperty(key) == null) {
     302                 properties.put(key, adaptorProperties.getProperty(key));
     303             }
     304         }
     305         properties.put(Constants.FRAMEWORK_VENDOR, Constants.OSGI_FRAMEWORK_VENDOR);
     306         properties.put(Constants.FRAMEWORK_VERSION, Constants.OSGI_FRAMEWORK_VERSION);
     307         String value = properties.getProperty(Constants.FRAMEWORK_PROCESSOR);
     308         if (value == null) {
     309             value = properties.getProperty(Constants.JVM_OS_ARCH);
     310             if (value != null) {
     311                 properties.put(Constants.FRAMEWORK_PROCESSOR, aliasMapper.aliasProcessor(value));
     312             }
     313         }
     314         value = properties.getProperty(Constants.FRAMEWORK_OS_NAME);
     315         if (value == null) {
     316             value = properties.getProperty(Constants.JVM_OS_NAME);
     317             try {
     318                 String canonicalValue = (String) aliasMapper.aliasOSName(value);
     319                 if (canonicalValue != null) {
     320                     value = canonicalValue;
     321                 }
     322             } catch (ClassCastException ex) {
     323                 //A vector was returned from the alias mapper.
     324                 //The alias mapped to more than one canonical value
     325                 //such as "win32" for example
     326             }
     327             if (value != null) {
     328                 properties.put(Constants.FRAMEWORK_OS_NAME, value);
     329             }
     330         }
     331         value = properties.getProperty(Constants.FRAMEWORK_OS_VERSION);
     332         if (value == null) {
     333             value = properties.getProperty(Constants.JVM_OS_VERSION);
     334             if (value != null) {
     335                 // only use the value upto the first space
     336                 int space = value.indexOf(' ');
     337                 if (space > 0) {
     338                     value = value.substring(0, space);
     339                 }
     340                 // fix up cases where the os version does not make a valid Version string.
     341                 int major = 0, minor = 0, micro = 0;
     342                 String qualifier = ""; //$NON-NLS-1$
     343                 try {
     344                     StringTokenizer st = new StringTokenizer(value, ".", true); //$NON-NLS-1$
     345                     major = parseVersionInt(st.nextToken());
     346 
     347                     if (st.hasMoreTokens()) {
     348                         st.nextToken(); // consume delimiter
     349                         minor = parseVersionInt(st.nextToken());
     350 
     351                         if (st.hasMoreTokens()) {
     352                             st.nextToken(); // consume delimiter
     353                             micro = parseVersionInt(st.nextToken());
     354 
     355                             if (st.hasMoreTokens()) {
     356                                 st.nextToken(); // consume delimiter
     357                                 qualifier = st.nextToken();
     358                             }
     359                         }
     360                     }
     361                 } catch (NoSuchElementException e) {
     362                     // ignore, use the values parsed so far
     363                 }
     364                 try {
     365                     value = new Version(major, minor, micro, qualifier).toString();
     366                 } catch (IllegalArgumentException e) {
     367                     // must be an invalid qualifier; just ignore it
     368                     value = new Version(major, minor, micro).toString();
     369                 }
     370                 properties.put(Constants.FRAMEWORK_OS_VERSION, value);
     371             }
     372         }
     373         value = properties.getProperty(Constants.FRAMEWORK_LANGUAGE);
     374         if (value == null)
     375             // set the value of the framework language property
     376             properties.put(Constants.FRAMEWORK_LANGUAGE, Locale.getDefault().getLanguage());
     377         // set the support properties for fragments and require-bundle (bug 173090)
     378         properties.put(Constants.SUPPORTS_FRAMEWORK_FRAGMENT, "true"); //$NON-NLS-1$
     379         properties.put(Constants.SUPPORTS_FRAMEWORK_REQUIREBUNDLE, "true"); //$NON-NLS-1$
     380         properties.put(Constants.FRAMEWORK_UUID, new UniversalUniqueIdentifier().toString());
     381     }
     382 
     383     private int parseVersionInt(String value) {
     384         try {
     385             return Integer.parseInt(value);
     386         } catch (NumberFormatException e) {
     387             // try up to the first non-number char
     388             StringBuffer sb = new StringBuffer(value.length());
     389             char[] chars = value.toCharArray();
     390             for (int i = 0; i < chars.length; i++) {
     391                 if (!Character.isDigit(chars[i]))
     392                     break;
     393                 sb.append(chars[i]);
     394             }
     395             if (sb.length() > 0)
     396                 return Integer.parseInt(sb.toString());
     397             return 0;
     398         }
     399     }
     400 
     401     private void setBootDelegation() {
     402         // set the boot delegation according to the osgi boot delegation property
     403         String bootDelegationProp = properties.getProperty(Constants.FRAMEWORK_BOOTDELEGATION);
     404         if (bootDelegationProp == null)
     405             return;
     406         if (bootDelegationProp.trim().length() == 0)
     407             return;
     408         String[] bootPackages = ManifestElement.getArrayFromList(bootDelegationProp);
     409         List<String> exactMatch = new ArrayList<String>(bootPackages.length);
     410         List<String> stemMatch = new ArrayList<String>(bootPackages.length);
     411         for (int i = 0; i < bootPackages.length; i++) {
     412             if (bootPackages[i].equals("*")) { //$NON-NLS-1$
     413                 bootDelegateAll = true;
     414                 return;
     415             } else if (bootPackages[i].endsWith("*")) { //$NON-NLS-1$
     416                 if (bootPackages[i].length() > 2 && bootPackages[i].endsWith(".*")) //$NON-NLS-1$
     417                     stemMatch.add(bootPackages[i].substring(0, bootPackages[i].length() - 1));
     418             } else {
     419                 exactMatch.add(bootPackages[i]);
     420             }
     421         }
     422         if (!exactMatch.isEmpty())
     423             bootDelegation = exactMatch.toArray(new String[exactMatch.size()]);
     424         if (!stemMatch.isEmpty())
     425             bootDelegationStems = stemMatch.toArray(new String[stemMatch.size()]);
     426     }
     427 
     428     @SuppressWarnings("deprecation")
     429     private void loadVMProfile() {
     430         Properties profileProps = findVMProfile();
     431         String systemExports = properties.getProperty(Constants.FRAMEWORK_SYSTEMPACKAGES);
     432         // set the system exports property using the vm profile; only if the property is not already set
     433         if (systemExports == null) {
     434             systemExports = profileProps.getProperty(Constants.FRAMEWORK_SYSTEMPACKAGES);
     435             if (systemExports != null)
     436                 properties.put(Constants.FRAMEWORK_SYSTEMPACKAGES, systemExports);
     437         }
     438         // set the org.osgi.framework.bootdelegation property according to the java profile
     439         String type = properties.getProperty(Constants.OSGI_JAVA_PROFILE_BOOTDELEGATION); // a null value means ignore
     440         String profileBootDelegation = profileProps.getProperty(Constants.FRAMEWORK_BOOTDELEGATION);
     441         if (Constants.OSGI_BOOTDELEGATION_OVERRIDE.equals(type)) {
     442             if (profileBootDelegation == null)
     443                 properties.remove(Constants.FRAMEWORK_BOOTDELEGATION); // override with a null value
     444             else
     445                 properties.put(Constants.FRAMEWORK_BOOTDELEGATION, profileBootDelegation); // override with the profile value
     446         } else if (Constants.OSGI_BOOTDELEGATION_NONE.equals(type))
     447             properties.remove(Constants.FRAMEWORK_BOOTDELEGATION); // remove the bootdelegation property in case it was set
     448         // set the org.osgi.framework.executionenvironment property according to the java profile
     449         if (properties.getProperty(Constants.FRAMEWORK_EXECUTIONENVIRONMENT) == null) {
     450             // get the ee from the java profile; if no ee is defined then try the java profile name
     451             String ee = profileProps.getProperty(Constants.FRAMEWORK_EXECUTIONENVIRONMENT, profileProps.getProperty(Constants.OSGI_JAVA_PROFILE_NAME));
     452             if (ee != null)
     453                 properties.put(Constants.FRAMEWORK_EXECUTIONENVIRONMENT, ee);
     454         }
     455         // set the org.osgi.framework.system.capabilities property according to the java profile
     456         if (properties.getProperty(Constants.FRAMEWORK_SYSTEMCAPABILITIES) == null) {
     457             String systemCapabilities = profileProps.getProperty(Constants.FRAMEWORK_SYSTEMCAPABILITIES);
     458             if (systemCapabilities != null)
     459                 properties.put(Constants.FRAMEWORK_SYSTEMCAPABILITIES, systemCapabilities);
     460         }
     461     }
     462 
     463     private Properties findVMProfile() {
     464         Properties result = new Properties();
     465         // Find the VM profile name using J2ME properties
     466         String j2meConfig = properties.getProperty(Constants.J2ME_MICROEDITION_CONFIGURATION);
     467         String j2meProfiles = properties.getProperty(Constants.J2ME_MICROEDITION_PROFILES);
     468         String vmProfile = null;
     469         String javaEdition = null;
     470         Version javaVersion = null;
     471         if (j2meConfig != null && j2meConfig.length() > 0 && j2meProfiles != null && j2meProfiles.length() > 0) {
     472             // save the vmProfile based off of the config and profile
     473             // use the last profile; assuming that is the highest one
     474             String[] j2meProfileList = ManifestElement.getArrayFromList(j2meProfiles, " "); //$NON-NLS-1$
     475             if (j2meProfileList != null && j2meProfileList.length > 0)
     476                 vmProfile = j2meConfig + '_' + j2meProfileList[j2meProfileList.length - 1];
     477         } else {
     478             // No J2ME properties; use J2SE properties
     479             // Note that the CDC spec appears not to require VM implementations to set the
     480             // javax.microedition properties!!  So we will try to fall back to the 
     481             // java.specification.name property, but this is pretty ridiculous!!
     482             String javaSpecVersion = properties.getProperty("java.specification.version"); //$NON-NLS-1$
     483             // set the profile and EE based off of the java.specification.version
     484             // TODO We assume J2ME Foundation and J2SE here.  need to support other profiles J2EE ...
     485             if (javaSpecVersion != null) {
     486                 StringTokenizer st = new StringTokenizer(javaSpecVersion, " _-"); //$NON-NLS-1$
     487                 javaSpecVersion = st.nextToken();
     488                 String javaSpecName = properties.getProperty("java.specification.name"); //$NON-NLS-1$
     489                 // See bug 291269 we check for Foundation Specification and Foundation Profile Specification
     490                 if (javaSpecName != null && (javaSpecName.indexOf("Foundation Specification") >= 0 || javaSpecName.indexOf("Foundation Profile Specification") >= 0)) //$NON-NLS-1$ //$NON-NLS-2$
     491                     vmProfile = "CDC-" + javaSpecVersion + "_Foundation-" + javaSpecVersion; //$NON-NLS-1$ //$NON-NLS-2$
     492                 else {
     493                     // look for JavaSE if 1.6 or greater; otherwise look for J2SE
     494                     Version v16 = new Version("1.6"); //$NON-NLS-1$
     495                     javaEdition = J2SE;
     496                     try {
     497                         javaVersion = new Version(javaSpecVersion);
     498                         if (v16.compareTo(javaVersion) <= 0)
     499                             javaEdition = JAVASE;
     500                     } catch (IllegalArgumentException e) {
     501                         // do nothing
     502                     }
     503                     vmProfile = javaEdition + javaSpecVersion;
     504                 }
     505             }
     506         }
     507         URL url = null;
     508         // check for the java profile property for a url
     509         String propJavaProfile = FrameworkProperties.getProperty(Constants.OSGI_JAVA_PROFILE);
     510         if (propJavaProfile != null)
     511             try {
     512                 // we assume a URL
     513                 url = new URL(propJavaProfile);
     514             } catch (MalformedURLException e1) {
     515                 // try using a relative path in the system bundle
     516                 url = findInSystemBundle(propJavaProfile);
     517             }
     518         if (url == null && vmProfile != null) {
     519             // look for a profile in the system bundle based on the vm profile
     520             String javaProfile = vmProfile + PROFILE_EXT;
     521             url = findInSystemBundle(javaProfile);
     522             if (url == null)
     523                 url = getNextBestProfile(javaEdition, javaVersion);
     524         }
     525         if (url == null)
     526             // the profile url is still null then use the osgi min profile in OSGi by default
     527             url = findInSystemBundle("OSGi_Minimum-1.2.profile"); //$NON-NLS-1$
     528         if (url != null) {
     529             InputStream in = null;
     530             try {
     531                 in = url.openStream();
     532                 result.load(new BufferedInputStream(in));
     533             } catch (IOException e) {
     534                 // TODO consider logging ...
     535             } finally {
     536                 if (in != null)
     537                     try {
     538                         in.close();
     539                     } catch (IOException ee) {
     540                         // do nothing
     541                     }
     542             }
     543         }
     544         // set the profile name if it does not provide one
     545         if (result.getProperty(Constants.OSGI_JAVA_PROFILE_NAME) == null)
     546             if (vmProfile != null)
     547                 result.put(Constants.OSGI_JAVA_PROFILE_NAME, vmProfile.replace('_', '/'));
     548             else
     549                 // last resort; default to the absolute minimum profile name for the framework
     550                 result.put(Constants.OSGI_JAVA_PROFILE_NAME, "OSGi/Minimum-1.2"); //$NON-NLS-1$
     551         return result;
     552     }
     553 
     554     private URL getNextBestProfile(String javaEdition, Version javaVersion) {
     555         if (javaVersion == null || (javaEdition != J2SE && javaEdition != JAVASE))
     556             return null; // we cannot automatically choose the next best profile unless this is a J2SE or JavaSE vm
     557         URL bestProfile = findNextBestProfile(javaEdition, javaVersion);
     558         if (bestProfile == null && javaEdition == JAVASE)
     559             // if this is a JavaSE VM then search for a lower J2SE profile
     560             bestProfile = findNextBestProfile(J2SE, javaVersion);
     561         return bestProfile;
     562     }
     563 
     564     private URL findNextBestProfile(String javaEdition, Version javaVersion) {
     565         URL result = null;
     566         int minor = javaVersion.getMinor();
     567         do {
     568             result = findInSystemBundle(javaEdition + javaVersion.getMajor() + "." + minor + PROFILE_EXT); //$NON-NLS-1$
     569             minor = minor - 1;
     570         } while (result == null && minor > 0);
     571         return result;
     572     }
     573 
     574     private URL findInSystemBundle(String entry) {
     575         URL result = systemBundle.getEntry0(entry);
     576         if (result == null) {
     577             // Check the ClassLoader in case we're launched off the Java boot classpath
     578             ClassLoader loader = getClass().getClassLoader();
     579             result = loader == null ? ClassLoader.getSystemResource(entry) : loader.getResource(entry);
     580         }
     581         return result;
     582     }
     583 
     584     /**
     585      * This method return the state of the framework.
     586      *  
     587      */
     588     protected boolean isActive() {
     589         return (active);
     590     }
     591 
     592     /**
     593      * This method is called to destory the framework instance.
     594      *  
     595      */
     596     public synchronized void close() {
     597         if (adaptor == null)
     598             return;
     599         if (active)
     600             shutdown(FrameworkEvent.STOPPED);
     601 
     602         synchronized (bundles) {
     603             List<AbstractBundle> allBundles = bundles.getBundles();
     604             int size = allBundles.size();
     605             for (int i = 0; i < size; i++) {
     606                 AbstractBundle bundle = allBundles.get(i);
     607                 bundle.close();
     608             }
     609             bundles.removeAllBundles();
     610         }
     611         serviceRegistry = null;
     612         allBundleListeners.clear();
     613         allSyncBundleListeners.clear();
     614         allFrameworkListeners.clear();
     615         if (eventManager != null) {
     616             eventManager.close();
     617             eventManager = null;
     618         }
     619         secureAction = null;
     620         packageAdmin = null;
     621         adaptor = null;
     622         uninstallURLStreamHandlerFactory();
     623         uninstallContentHandlerFactory();
     624         if (System.getSecurityManager() instanceof EquinoxSecurityManager)
     625             System.setSecurityManager(null);
     626     }
     627 
     628     /**
     629      * Start the framework.
     630      * 
     631      * When the framework is started. The following actions occur: 1. Event
     632      * handling is enabled. Events can now be delivered to listeners. 2. All
     633      * bundles which are recorded as started are started as described in the
     634      * Bundle.start() method. These bundles are the bundles that were started
     635      * when the framework was last stopped. Reports any exceptions that occur
     636      * during startup using FrameworkEvents. 3. A FrameworkEvent of type
     637      * FrameworkEvent.STARTED is broadcast.
     638      *  
     639      */
     640     public synchronized void launch() {
     641         /* Return if framework already started */
     642         if (active) {
     643             return;
     644         }
     645         /* mark framework as started */
     646         active = true;
     647         shutdownEvent = new FrameworkEvent[1];
     648         if (THREAD_NORMAL.equals(FrameworkProperties.getProperty(PROP_FRAMEWORK_THREAD, THREAD_NORMAL))) {
     649             Thread fwkThread = new Thread(this, "Framework Active Thread"); //$NON-NLS-1$
     650             fwkThread.setDaemon(false);
     651             fwkThread.start();
     652         }
     653         /* Resume systembundle */
     654         if (Debug.DEBUG_GENERAL) {
     655             Debug.println("Trying to launch framework"); //$NON-NLS-1$
     656         }
     657         systemBundle.resume();
     658         signedContentFactory = new ServiceTracker<SignedContentFactory, SignedContentFactory>(systemBundle.getBundleContext(), SignedContentFactory.class.getName(), null);
     659         signedContentFactory.open();
     660     }
     661 
     662     /**
     663      * Stop the framework.
     664      * 
     665      * When the framework is stopped. The following actions occur: 1. Suspend
     666      * all started bundles as described in the Bundle.stop method except that
     667      * the bundle is recorded as started. These bundles will be restarted when
     668      * the framework is next started. Reports any exceptions that occur during
     669      * stopping using FrameworkEvents. 2. Event handling is disabled.
     670      *  
     671      */
     672     public synchronized void shutdown(int eventType) {
     673         /* Return if framework already stopped */
     674         if (!active)
     675             return;
     676         this.shutdownEvent[0] = new FrameworkEvent(eventType, systemBundle, null);
     677         /*
     678          * set the state of the System Bundle to STOPPING.
     679          * this must be done first according to section 4.19.2 from the OSGi R3 spec.  
     680          */
     681         systemBundle.state = Bundle.STOPPING;
     682         publishBundleEvent(BundleEvent.STOPPING, systemBundle); // need to send system bundle stopping event 
     683         /* call the FrameworkAdaptor.frameworkStopping method first */
     684         try {
     685             adaptor.frameworkStopping(systemBundle.getContext());
     686         } catch (Throwable t) {
     687             publishFrameworkEvent(FrameworkEvent.ERROR, systemBundle, t);
     688         }
     689         /* Suspend systembundle */
     690         if (Debug.DEBUG_GENERAL) {
     691             Debug.println("Trying to shutdown Framework"); //$NON-NLS-1$
     692         }
     693         systemBundle.suspend();
     694         try {
     695             adaptor.compactStorage();
     696         } catch (IOException e) {
     697             publishFrameworkEvent(FrameworkEvent.ERROR, systemBundle, e);
     698         }
     699         if (signedContentFactory != null)
     700             signedContentFactory.close();
     701         /* mark framework as stopped */
     702         active = false;
     703         notifyAll();
     704     }
     705 
     706     /**
     707      * Create a new Bundle object.
     708      * @param bundledata the BundleData of the Bundle to create
     709      */
     710     AbstractBundle createAndVerifyBundle(int operationType, Bundle target, BundleData bundledata, boolean setBundle) throws BundleException {
     711         // Check for a bundle already installed with the same symbolic name and version.
     712         if (BSN_VERSION != BSN_VERSION_MULTIPLE && bundledata.getSymbolicName() != null) {
     713             List<AbstractBundle> installedBundles = getBundleBySymbolicName(bundledata.getSymbolicName(), bundledata.getVersion());
     714             if (operationType == CollisionHook.UPDATING) {
     715                 installedBundles.remove(target);
     716             }
     717             if (BSN_VERSION == BSN_VERSION_MANAGED && !installedBundles.isEmpty()) {
     718                 notifyCollisionHooks(operationType, target, installedBundles);
     719             }
     720             if (!installedBundles.isEmpty()) {
     721                 Bundle installedBundle = installedBundles.iterator().next();
     722                 String msg = NLS.bind(Msg.BUNDLE_INSTALL_SAME_UNIQUEID, new Object[] {installedBundle.getSymbolicName(), installedBundle.getVersion().toString(), installedBundle.getLocation()});
     723                 throw new DuplicateBundleException(msg, installedBundle);
     724             }
     725         }
     726         return AbstractBundle.createBundle(bundledata, this, setBundle);
     727     }
     728 
     729     private class DuplicateBundleException extends BundleException implements StatusException {
     730         private static final long serialVersionUID = 135669822846323624L;
     731         private transient Bundle duplicate;
     732 
     733         public DuplicateBundleException(String msg, Bundle duplicate) {
     734             super(msg, BundleException.DUPLICATE_BUNDLE_ERROR);
     735             this.duplicate = duplicate;
     736         }
     737 
     738         public Object getStatus() {
     739             return duplicate;
     740         }
     741 
     742         public int getStatusCode() {
     743             return StatusException.CODE_OK;
     744         }
     745 
     746     }
     747 
     748     /**
     749      * Retrieve the value of the named environment property. Values are
     750      * provided for the following properties:
     751      * <dl>
     752      * <dt><code>org.osgi.framework.version</code>
     753      * <dd>The version of the framework.
     754      * <dt><code>org.osgi.framework.vendor</code>
     755      * <dd>The vendor of this framework implementation.
     756      * <dt><code>org.osgi.framework.language</code>
     757      * <dd>The language being used. See ISO 639 for possible values.
     758      * <dt><code>org.osgi.framework.os.name</code>
     759      * <dd>The name of the operating system of the hosting computer.
     760      * <dt><code>org.osgi.framework.os.version</code>
     761      * <dd>The version number of the operating system of the hosting computer.
     762      * <dt><code>org.osgi.framework.processor</code>
     763      * <dd>The name of the processor of the hosting computer.
     764      * </dl>
     765      * 
     766      * <p>
     767      * Note: These last four properties are used by the <code>Bundle-NativeCode</code>
     768      * manifest header's matching algorithm for selecting native code.
     769      * 
     770      * @param key
     771      *            The name of the requested property.
     772      * @return The value of the requested property, or <code>null</code> if
     773      *         the property is undefined.
     774      */
     775     public String getProperty(String key) {
     776         return properties.getProperty(key);
     777     }
     778 
     779     /**
     780      * Retrieve the value of the named environment property. Values are
     781      * provided for the following properties:
     782      * <dl>
     783      * <dt><code>org.osgi.framework.version</code>
     784      * <dd>The version of the framework.
     785      * <dt><code>org.osgi.framework.vendor</code>
     786      * <dd>The vendor of this framework implementation.
     787      * <dt><code>org.osgi.framework.language</code>
     788      * <dd>The language being used. See ISO 639 for possible values.
     789      * <dt><code>org.osgi.framework.os.name</code>
     790      * <dd>The name of the operating system of the hosting computer.
     791      * <dt><code>org.osgi.framework.os.version</code>
     792      * <dd>The version number of the operating system of the hosting computer.
     793      * <dt><code>org.osgi.framework.processor</code>
     794      * <dd>The name of the processor of the hosting computer.
     795      * </dl>
     796      * 
     797      * <p>
     798      * Note: These last four properties are used by the <code>Bundle-NativeCode</code>
     799      * manifest header's matching algorithm for selecting native code.
     800      * 
     801      * @param key
     802      *            The name of the requested property.
     803      * @param def
     804      *            A default value is the requested property is not present.
     805      * @return The value of the requested property, or the default value if the
     806      *         property is undefined.
     807      */
     808     protected String getProperty(String key, String def) {
     809         return properties.getProperty(key, def);
     810     }
     811 
     812     /**
     813      * Set a system property.
     814      * 
     815      * @param key
     816      *            The name of the property to set.
     817      * @param value
     818      *            The value to set.
     819      * @return The previous value of the property or null if the property was
     820      *         not previously set.
     821      */
     822     protected Object setProperty(String key, String value) {
     823         return properties.put(key, value);
     824     }
     825 
     826     /**
     827      * Install a bundle from an InputStream.
     828      * 
     829      * @param location
     830      *            The location identifier of the bundle to install.
     831      * @param in
     832      *            The InputStream from which the bundle will be read.  If null
     833      *            then the location is used to get the bundle content.
     834      * @return The Bundle of the installed bundle.
     835      */
     836     AbstractBundle installBundle(final String location, final InputStream in, final BundleContextImpl origin) throws BundleException {
     837         if (Debug.DEBUG_GENERAL) {
     838             Debug.println("install from inputstream: " + location + ", " + in); //$NON-NLS-1$ //$NON-NLS-2$
     839         }
     840         final AccessControlContext callerContext = AccessController.getContext();
     841         return installWorker(location, new PrivilegedExceptionAction<AbstractBundle>() {
     842             public AbstractBundle run() throws BundleException {
     843                 /* Map the InputStream or location to a URLConnection */
     844                 URLConnection source = in != null ? new BundleSource(in) : adaptor.mapLocationToURLConnection(location);
     845                 /* call the worker to install the bundle */
     846                 return installWorkerPrivileged(location, source, callerContext, origin);
     847             }
     848         }, origin);
     849     }
     850 
     851     /**
     852      * Worker method to install a bundle. It obtains the reservation for the
     853      * location and calls the specified action.
     854      * 
     855      * @param location
     856      *            The location identifier of the bundle to install.
     857      * @param action
     858      *            A PrivilegedExceptionAction which calls the real worker.
     859      * @return The {@link AbstractBundle}of the installed bundle.
     860      * @exception BundleException
     861      *                If the action throws an error.
     862      */
     863     protected AbstractBundle installWorker(String location, PrivilegedExceptionAction<AbstractBundle> action, BundleContext origin) throws BundleException {
     864         synchronized (installLock) {
     865             while (true) {
     866                 /* Check that the bundle is not already installed. */
     867                 AbstractBundle bundle = getBundleByLocation(location);
     868                 /* If already installed, return bundle object */
     869                 if (bundle != null) {
     870                     Bundle visible = origin.getBundle(bundle.getBundleId());
     871                     if (visible == null) {
     872                         BundleData data = bundle.getBundleData();
     873                         String msg = NLS.bind(Msg.BUNDLE_INSTALL_SAME_UNIQUEID, new Object[] {data.getSymbolicName(), data.getVersion().toString(), data.getLocation()});
     874                         throw new BundleException(msg, BundleException.REJECTED_BY_HOOK);
     875                     }
     876                     return bundle;
     877                 }
     878                 Thread current = Thread.currentThread();
     879                 /* Check for and make reservation */
     880                 Thread reservation = installLock.put(location, current);
     881                 /* if the location is not already reserved */
     882                 if (reservation == null) {
     883                     /* we have made the reservation and can continue */
     884                     break;
     885                 }
     886                 /* the location was already reserved */
     887                 /*
     888                  * If the reservation is held by the current thread, we have
     889                  * recursed to install the same bundle!
     890                  */
     891                 if (current.equals(reservation)) {
     892                     throw new BundleException(Msg.BUNDLE_INSTALL_RECURSION_EXCEPTION, BundleException.STATECHANGE_ERROR);
     893                 }
     894                 try {
     895                     /* wait for the reservation to be released */
     896                     installLock.wait();
     897                 } catch (InterruptedException e) {
     898                     Thread.currentThread().interrupt();
     899                     throw new BundleException("Thread has been interrupted while waiting for the location lock.", e); //$NON-NLS-1$
     900                 }
     901             }
     902         }
     903         /* Don't call adaptor while holding the install lock */
     904         try {
     905             AbstractBundle bundle = AccessController.doPrivileged(action);
     906             publishBundleEvent(new BundleEvent(BundleEvent.INSTALLED, bundle, origin.getBundle()));
     907             return bundle;
     908         } catch (PrivilegedActionException e) {
     909             if (e.getException() instanceof RuntimeException)
     910                 throw (RuntimeException) e.getException();
     911             throw (BundleException) e.getException();
     912         } finally {
     913             synchronized (installLock) {
     914                 /* release reservation */
     915                 installLock.remove(location);
     916                 /* wake up all waiters */
     917                 installLock.notifyAll();
     918             }
     919         }
     920     }
     921 
     922     /**
     923      * Worker method to install a bundle. It calls the FrameworkAdaptor object
     924      * to install the bundle in persistent storage.
     925      * 
     926      * @param location
     927      *            The location identifier of the bundle to install.
     928      * @param source
     929      *            The URLConnection from which the bundle will be read.
     930      * @param callerContext
     931      *            The caller access control context
     932      * @param origin 
     933      *            The origin bundle context that is installing the the bundle
     934      * @return The {@link AbstractBundle}of the installed bundle.
     935      * @exception BundleException
     936      *                If the provided stream cannot be read.
     937      */
     938     protected AbstractBundle installWorkerPrivileged(String location, URLConnection source, AccessControlContext callerContext, BundleContextImpl origin) throws BundleException {
     939         BundleOperation storage = adaptor.installBundle(location, source);
     940         final AbstractBundle bundle;
     941         try {
     942             BundleData bundledata = storage.begin();
     943             bundle = createAndVerifyBundle(CollisionHook.INSTALLING, origin.getBundle(), bundledata, true);
     944 
     945             BundleWatcher bundleStats = adaptor.getBundleWatcher();
     946             if (bundleStats != null)
     947                 bundleStats.watchBundle(bundle, BundleWatcher.START_INSTALLING);
     948 
     949             try {
     950                 bundle.load();
     951                 if (System.getSecurityManager() != null) {
     952                     final boolean extension = (bundledata.getType() & (BundleData.TYPE_BOOTCLASSPATH_EXTENSION | BundleData.TYPE_FRAMEWORK_EXTENSION | BundleData.TYPE_EXTCLASSPATH_EXTENSION)) != 0;
     953                     // must check for AllPermission before allow a bundle extension to be installed
     954                     if (extension && !bundle.hasPermission(new AllPermission()))
     955                         throw new BundleException(Msg.BUNDLE_EXTENSION_PERMISSION, BundleException.SECURITY_ERROR, new SecurityException(Msg.BUNDLE_EXTENSION_PERMISSION));
     956                     try {
     957                         AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
     958                             public Object run() throws Exception {
     959                                 checkAdminPermission(bundle, AdminPermission.LIFECYCLE);
     960                                 if (extension) // need special permission to install extension bundles
     961                                     checkAdminPermission(bundle, AdminPermission.EXTENSIONLIFECYCLE);
     962                                 return null;
     963                             }
     964                         }, callerContext);
     965                     } catch (PrivilegedActionException e) {
     966                         throw e.getException();
     967                     }
     968                 }
     969                 // must add the bundle before committing (bug 330905)
     970                 bundles.add(bundle);
     971                 storage.commit(false);
     972             } catch (Throwable error) {
     973                 bundles.remove(bundle);
     974                 synchronized (bundles) {
     975                     bundle.unload();
     976                 }
     977                 bundle.close();
     978                 throw error;
     979             } finally {
     980                 if (bundleStats != null)
     981                     bundleStats.watchBundle(bundle, BundleWatcher.END_INSTALLING);
     982             }
     983 
     984         } catch (Throwable t) {
     985             try {
     986                 storage.undo();
     987             } catch (BundleException ee) {
     988                 publishFrameworkEvent(FrameworkEvent.ERROR, systemBundle, ee);
     989             }
     990             if (t instanceof SecurityException)
     991                 throw (SecurityException) t;
     992             if (t instanceof BundleException)
     993                 throw (BundleException) t;
     994             throw new BundleException(t.getMessage(), t);
     995         }
     996         return bundle;
     997     }
     998 
     999     /**
    1000      * Retrieve the bundle that has the given unique identifier.
    1001      * 
    1002      * @param id
    1003      *            The identifier of the bundle to retrieve.
    1004      * @return A {@link AbstractBundle}object, or <code>null</code> if the
    1005      *         identifier doesn't match any installed bundle.
    1006      */
    1007     // changed visibility to gain access through the adaptor
    1008     public AbstractBundle getBundle(long id) {
    1009         synchronized (bundles) {
    1010             return bundles.getBundle(id);
    1011         }
    1012     }
    1013 
    1014     AbstractBundle getBundle(final BundleContextImpl context, long id) {
    1015         AbstractBundle bundle = getBundle(id);
    1016         // TODO we make the system bundle special because there are lots of places
    1017         // where we assume the system bundle can get all bundles
    1018         if (bundle == null || context.getBundle().getBundleId() == 0)
    1019             return bundle;
    1020         List<AbstractBundle> single = new ArrayList<AbstractBundle>(1);
    1021         single.add(bundle);
    1022         notifyFindHooks(context, single);
    1023         return single.size() == 0 ? null : bundle;
    1024     }
    1025 
    1026     public BundleContextImpl getSystemBundleContext() {
    1027         if (systemBundle == null)
    1028             return null;
    1029         return systemBundle.context;
    1030     }
    1031 
    1032     public PackageAdminImpl getPackageAdmin() {
    1033         return packageAdmin;
    1034     }
    1035 
    1036     /**
    1037      * Retrieve the bundles that has the given symbolic name and version.
    1038      * 
    1039      * @param symbolicName
    1040      *            The symbolic name of the bundle to retrieve
    1041      * @param version The version of the bundle to retrieve
    1042      * @return A collection of {@link AbstractBundle} that match the symbolic name and version
    1043      */
    1044     public List<AbstractBundle> getBundleBySymbolicName(String symbolicName, Version version) {
    1045         synchronized (bundles) {
    1046             return bundles.getBundles(symbolicName, version);
    1047         }
    1048     }
    1049 
    1050     /**
    1051      * Retrieve the BundleRepository of all installed bundles. The list is
    1052      * valid at the time of the call to getBundles, but the framework is a very
    1053      * dynamic environment and bundles can be installed or uninstalled at
    1054      * anytime.
    1055      * 
    1056      * @return The BundleRepository.
    1057      */
    1058     protected BundleRepository getBundles() {
    1059         return (bundles);
    1060     }
    1061 
    1062     /**
    1063      * Retrieve a list of all installed bundles. The list is valid at the time
    1064      * of the call to getBundleAlls, but the framework is a very dynamic
    1065      * environment and bundles can be installed or uninstalled at anytime.
    1066      * 
    1067      * @return An Array of {@link AbstractBundle}objects, one object per installed
    1068      *         bundle.
    1069      */
    1070     protected AbstractBundle[] getAllBundles() {
    1071         synchronized (bundles) {
    1072             List<AbstractBundle> allBundles = bundles.getBundles();
    1073             int size = allBundles.size();
    1074             if (size == 0) {
    1075                 return (null);
    1076             }
    1077             AbstractBundle[] bundlelist = new AbstractBundle[size];
    1078             allBundles.toArray(bundlelist);
    1079             return (bundlelist);
    1080         }
    1081     }
    1082 
    1083     AbstractBundle[] getBundles(final BundleContextImpl context) {
    1084         List<AbstractBundle> allBundles;
    1085         synchronized (bundles) {
    1086             allBundles = new ArrayList<AbstractBundle>(bundles.getBundles());
    1087         }
    1088         notifyFindHooks(context, allBundles);
    1089         return allBundles.toArray(new AbstractBundle[allBundles.size()]);
    1090     }
    1091 
    1092     private void notifyFindHooks(final BundleContextImpl context, List<AbstractBundle> allBundles) {
    1093         final Collection<Bundle> shrinkable = new ShrinkableCollection<Bundle>(allBundles);
    1094         if (System.getSecurityManager() == null) {
    1095             notifyFindHooksPriviledged(context, shrinkable);
    1096         } else {
    1097             AccessController.doPrivileged(new PrivilegedAction<Object>() {
    1098                 public Object run() {
    1099                     notifyFindHooksPriviledged(context, shrinkable);
    1100                     return null;
    1101                 }
    1102             });
    1103         }
    1104     }
    1105 
    1106     void notifyFindHooksPriviledged(final BundleContextImpl context, final Collection<Bundle> allBundles) {
    1107         if (Debug.DEBUG_HOOKS) {
    1108             Debug.println("notifyBundleFindHooks(" + allBundles + ")"); //$NON-NLS-1$ //$NON-NLS-2$ 
    1109         }
    1110         getServiceRegistry().notifyHooksPrivileged(new HookContext() {
    1111             public void call(Object hook, ServiceRegistration<?> hookRegistration) throws Exception {
    1112                 if (hook instanceof FindHook) {
    1113                     ((FindHook) hook).find(context, allBundles);
    1114                 }
    1115             }
    1116 
    1117             public String getHookClassName() {
    1118                 return findHookName;
    1119             }
    1120 
    1121             public String getHookMethodName() {
    1122                 return "find"; //$NON-NLS-1$ 
    1123             }
    1124         });
    1125     }
    1126 
    1127     private void notifyCollisionHooks(final int operationType, final Bundle target, List<AbstractBundle> collisionCandidates) {
    1128         final Collection<Bundle> shrinkable = new ShrinkableCollection<Bundle>(collisionCandidates);
    1129         if (System.getSecurityManager() == null) {
    1130             notifyCollisionHooksPriviledged(operationType, target, shrinkable);
    1131         } else {
    1132             AccessController.doPrivileged(new PrivilegedAction<Object>() {
    1133                 public Object run() {
    1134                     notifyCollisionHooksPriviledged(operationType, target, shrinkable);
    1135                     return null;
    1136                 }
    1137             });
    1138         }
    1139     }
    1140 
    1141     void notifyCollisionHooksPriviledged(final int operationType, final Bundle target, final Collection<Bundle> collisionCandidates) {
    1142         if (Debug.DEBUG_HOOKS) {
    1143             Debug.println("notifyCollisionHooks(" + operationType + ", " + target + ", " + collisionCandidates + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ 
    1144         }
    1145         getServiceRegistry().notifyHooksPrivileged(new HookContext() {
    1146             public void call(Object hook, ServiceRegistration<?> hookRegistration) throws Exception {
    1147                 if (hook instanceof CollisionHook) {
    1148                     ((CollisionHook) hook).filterCollisions(operationType, target, collisionCandidates);
    1149                 }
    1150             }
    1151 
    1152             public String getHookClassName() {
    1153                 return collisionHookName;
    1154             }
    1155 
    1156             public String getHookMethodName() {
    1157                 return "filterCollisions"; //$NON-NLS-1$ 
    1158             }
    1159         });
    1160     }
    1161 
    1162     /**
    1163      * Resume a bundle.
    1164      * 
    1165      * @param bundle
    1166      *            Bundle to resume.
    1167      */
    1168     protected void resumeBundle(AbstractBundle bundle) {
    1169         if (bundle.isActive()) {
    1170             // if bundle is active.
    1171             return;
    1172         }
    1173         try {
    1174             if (Debug.DEBUG_GENERAL) {
    1175                 Debug.println("Trying to resume bundle " + bundle); //$NON-NLS-1$
    1176             }
    1177             bundle.resume();
    1178         } catch (BundleException be) {
    1179             if (Debug.DEBUG_GENERAL) {
    1180                 Debug.println("Bundle resume exception: " + be.getMessage()); //$NON-NLS-1$
    1181                 Debug.printStackTrace(be.getNestedException() == null ? be : be.getNestedException());
    1182             }
    1183             publishFrameworkEvent(FrameworkEvent.ERROR, bundle, be);
    1184         }
    1185     }
    1186 
    1187     /**
    1188      * Suspend a bundle.
    1189      * 
    1190      * @param bundle
    1191      *            Bundle to suspend.
    1192      * @param lock
    1193      *            true if state change lock should be held when returning from
    1194      *            this method.
    1195      * @return true if bundle was active and is now suspended.
    1196      */
    1197     protected boolean suspendBundle(AbstractBundle bundle, boolean lock) {
    1198         boolean changed = false;
    1199         if (!bundle.isActive() || bundle.isFragment()) {
    1200             // if bundle is not active or is a fragment then do nothing.
    1201             return changed;
    1202         }
    1203         try {
    1204             if (Debug.DEBUG_GENERAL) {
    1205                 Debug.println("Trying to suspend bundle " + bundle); //$NON-NLS-1$
    1206             }
    1207             bundle.suspend(lock);
    1208         } catch (BundleException be) {
    1209             if (Debug.DEBUG_GENERAL) {
    1210                 Debug.println("Bundle suspend exception: " + be.getMessage()); //$NON-NLS-1$
    1211                 Debug.printStackTrace(be.getNestedException() == null ? be : be.getNestedException());
    1212             }
    1213             publishFrameworkEvent(FrameworkEvent.ERROR, bundle, be);
    1214         }
    1215         if (!bundle.isActive()) {
    1216             changed = true;
    1217         }
    1218         return (changed);
    1219     }
    1220 
    1221     /**
    1222      * Locate an installed bundle with a given identity.
    1223      * 
    1224      * @param location
    1225      *            string for the bundle
    1226      * @return Bundle object for bundle with the specified location or null if
    1227      *         no bundle is installed with the specified location.
    1228      */
    1229     protected AbstractBundle getBundleByLocation(String location) {
    1230         synchronized (bundles) {
    1231             // this is not optimized; do not think it will get called
    1232             // that much.
    1233             final String finalLocation = location;
    1234 
    1235             //Bundle.getLocation requires AdminPermission (metadata)
    1236             return AccessController.doPrivileged(new PrivilegedAction<AbstractBundle>() {
    1237                 public AbstractBundle run() {
    1238                     List<AbstractBundle> allBundles = bundles.getBundles();
    1239                     int size = allBundles.size();
    1240                     for (int i = 0; i < size; i++) {
    1241                         AbstractBundle bundle = allBundles.get(i);
    1242                         if (finalLocation.equals(bundle.getLocation())) {
    1243                             return bundle;
    1244                         }
    1245                     }
    1246                     return null;
    1247                 }
    1248             });
    1249         }
    1250     }
    1251 
    1252     /**
    1253      * Locate an installed bundle with a given symbolic name
    1254      * 
    1255      * @param symbolicName
    1256      *            The symbolic name for the bundle
    1257      * @return Bundle object for bundle with the specified Unique or null if no
    1258      *         bundle is installed with the specified symbolicName.
    1259      */
    1260     protected AbstractBundle[] getBundleBySymbolicName(String symbolicName) {
    1261         synchronized (bundles) {
    1262             return bundles.getBundles(symbolicName);
    1263         }
    1264     }
    1265 
    1266     /**
    1267      * Creates a <code>File</code> object for a file in the persistent
    1268      * storage area provided for the bundle by the framework. If the adaptor
    1269      * does not have file system support, this method will return <code>null</code>.
    1270      * 
    1271      * <p>
    1272      * A <code>File</code> object for the base directory of the persistent
    1273      * storage area provided for the context bundle by the framework can be
    1274      * obtained by calling this method with the empty string ("") as the
    1275      * parameter.
    1276      */
    1277     protected File getDataFile(final AbstractBundle bundle, final String filename) {
    1278         return AccessController.doPrivileged(new GetDataFileAction(bundle, filename));
    1279     }
    1280 
    1281     /**
    1282      * Check for specific AdminPermission (RFC 73)
    1283      */
    1284     protected void checkAdminPermission(Bundle bundle, String action) {
    1285         SecurityManager sm = System.getSecurityManager();
    1286         if (sm != null)
    1287             sm.checkPermission(getAdminPermission(bundle, action));
    1288     }
    1289 
    1290     // gets AdminPermission objects from a cache to reduce the number of AdminPermission
    1291     // objects that are created.
    1292     private AdminPermission getAdminPermission(Bundle bundle, String action) {
    1293         synchronized (adminPermissions) {
    1294             Long ID = new Long(bundle.getBundleId());
    1295             Map<String, AdminPermission> bundlePermissions = adminPermissions.get(ID);
    1296             if (bundlePermissions == null) {
    1297                 bundlePermissions = new HashMap<String, AdminPermission>();
    1298                 adminPermissions.put(ID, bundlePermissions);
    1299             }
    1300             AdminPermission result = bundlePermissions.get(action);
    1301             if (result == null) {
    1302                 result = new AdminPermission(bundle, action);
    1303                 bundlePermissions.put(action, result);
    1304             }
    1305             return result;
    1306         }
    1307     }
    1308 
    1309     /**
    1310      * This is necessary for running from a JXE, otherwise the SecurityManager
    1311      * is set much later than we would like!
    1312      */
    1313     protected void installSecurityManager() {
    1314         String securityManager = FrameworkProperties.getProperty(Constants.FRAMEWORK_SECURITY, FrameworkProperties.getProperty(PROP_EQUINOX_SECURITY, FrameworkProperties.getProperty("java.security.manager")));
    1315         if (securityManager != null) {
    1316             SecurityManager sm = System.getSecurityManager();
    1317             if (sm == null) {
    1318                 if (securityManager.length() == 0)
    1319                     sm = new SecurityManager(); // use the default one from java
    1320                 else if (securityManager.equals(SECURITY_OSGI))
    1321                     sm = new EquinoxSecurityManager(); // use an OSGi enabled manager that understands postponed conditions
    1322                 else {
    1323                     // try to use a specific classloader by classname
    1324                     try {
    1325                         Class<?> clazz = Class.forName(securityManager);
    1326                         sm = (SecurityManager) clazz.newInstance();
    1327                     } catch (ClassNotFoundException e) {
    1328                         // do nothing
    1329                     } catch (ClassCastException e) {
    1330                         // do nothing
    1331                     } catch (InstantiationException e) {
    1332                         // do nothing
    1333                     } catch (IllegalAccessException e) {
    1334                         // do nothing
    1335                     }
    1336                 }
    1337                 if (sm == null)
    1338                     throw new NoClassDefFoundError(securityManager);
    1339                 if (Debug.DEBUG_SECURITY)
    1340                     Debug.println("Setting SecurityManager to: " + sm); //$NON-NLS-1$
    1341                 System.setSecurityManager(sm);
    1342                 return;
    1343             }
    1344         }
    1345     }
    1346 
    1347     void addFrameworkListener(FrameworkListener listener, BundleContextImpl context) {
    1348         synchronized (allFrameworkListeners) {
    1349             CopyOnWriteIdentityMap<FrameworkListener, FrameworkListener> listeners = allFrameworkListeners.get(context);
    1350             if (listeners == null) {
    1351                 listeners = new CopyOnWriteIdentityMap<FrameworkListener, FrameworkListener>();
    1352                 allFrameworkListeners.put(context, listeners);
    1353             }
    1354             listeners.put(listener, listener);
    1355         }
    1356     }
    1357 
    1358     void removeFrameworkListener(FrameworkListener listener, BundleContextImpl context) {
    1359         synchronized (allFrameworkListeners) {
    1360             CopyOnWriteIdentityMap<FrameworkListener, FrameworkListener> listeners = allFrameworkListeners.get(context);
    1361             if (listeners != null)
    1362                 listeners.remove(listener);
    1363         }
    1364     }
    1365 
    1366     void removeAllListeners(BundleContextImpl context) {
    1367         synchronized (allBundleListeners) {
    1368             allBundleListeners.remove(context);
    1369         }
    1370         synchronized (allSyncBundleListeners) {
    1371             allSyncBundleListeners.remove(context);
    1372         }
    1373         synchronized (allFrameworkListeners) {
    1374             allFrameworkListeners.remove(context);
    1375         }
    1376     }
    1377 
    1378     /**
    1379      * Deliver a FrameworkEvent.
    1380      * 
    1381      * @param type
    1382      *            FrameworkEvent type.
    1383      * @param bundle
    1384      *            Affected bundle or null for system bundle.
    1385      * @param throwable
    1386      *            Related exception or null.
    1387      */
    1388     public void publishFrameworkEvent(int type, Bundle bundle, Throwable throwable) {
    1389         publishFrameworkEvent(type, bundle, throwable, (FrameworkListener[]) null);
    1390     }
    1391 
    1392     public void publishFrameworkEvent(int type, Bundle bundle, Throwable throwable, final FrameworkListener... listeners) {
    1393         if (bundle == null)
    1394             bundle = systemBundle;
    1395         final FrameworkEvent event = new FrameworkEvent(type, bundle, throwable);
    1396         if (System.getSecurityManager() == null) {
    1397             publishFrameworkEventPrivileged(event, listeners);
    1398         } else {
    1399             AccessController.doPrivileged(new PrivilegedAction<Object>() {
    1400                 public Object run() {
    1401                     publishFrameworkEventPrivileged(event, listeners);
    1402                     return null;
    1403                 }
    1404             });
    1405         }
    1406     }
    1407 
    1408     public void publishFrameworkEventPrivileged(FrameworkEvent event, FrameworkListener... callerListeners) {
    1409         // Build the listener snapshot
    1410         Map<BundleContextImpl, Set<Map.Entry<FrameworkListener, FrameworkListener>>> listenerSnapshot;
    1411         synchronized (allFrameworkListeners) {
    1412             listenerSnapshot = new HashMap<BundleContextImpl, Set<Map.Entry<FrameworkListener, FrameworkListener>>>(allFrameworkListeners.size());
    1413             for (Map.Entry<BundleContextImpl, CopyOnWriteIdentityMap<FrameworkListener, FrameworkListener>> entry : allFrameworkListeners.entrySet()) {
    1414                 CopyOnWriteIdentityMap<FrameworkListener, FrameworkListener> listeners = entry.getValue();
    1415                 if (!listeners.isEmpty()) {
    1416                     listenerSnapshot.put(entry.getKey(), listeners.entrySet());
    1417                 }
    1418             }
    1419         }
    1420         // If framework event hook were defined they would be called here
    1421 
    1422         // deliver the event to the snapshot
    1423         ListenerQueue<FrameworkListener, FrameworkListener, FrameworkEvent> queue = newListenerQueue();
    1424 
    1425         // add the listeners specified by the caller first
    1426         if (callerListeners != null && callerListeners.length > 0) {
    1427             Map<FrameworkListener, FrameworkListener> listeners = new HashMap<FrameworkListener, FrameworkListener>();
    1428             for (FrameworkListener listener : callerListeners) {
    1429                 if (listener != null)
    1430                     listeners.put(listener, listener);
    1431             }
    1432             // We use the system bundle context as the dispatcher
    1433             if (listeners.size() > 0) {
    1434                 @SuppressWarnings({"rawtypes", "unchecked"})
    1435                 EventDispatcher<FrameworkListener, FrameworkListener, FrameworkEvent> dispatcher = (EventDispatcher) getSystemBundleContext();
    1436                 queue.queueListeners(listeners.entrySet(), dispatcher);
    1437             }
    1438         }
    1439 
    1440         for (Map.Entry<BundleContextImpl, Set<Map.Entry<FrameworkListener, FrameworkListener>>> entry : listenerSnapshot.entrySet()) {
    1441             @SuppressWarnings({"rawtypes", "unchecked"})
    1442             EventDispatcher<FrameworkListener, FrameworkListener, FrameworkEvent> dispatcher = (EventDispatcher) entry.getKey();
    1443             Set<Map.Entry<FrameworkListener, FrameworkListener>> listeners = entry.getValue();
    1444             queue.queueListeners(listeners, dispatcher);
    1445         }
    1446 
    1447         queue.dispatchEventAsynchronous(FRAMEWORKEVENT, event);
    1448     }
    1449 
    1450     void addBundleListener(BundleListener listener, BundleContextImpl context) {
    1451         if (listener instanceof SynchronousBundleListener) {
    1452             checkAdminPermission(context.getBundle(), AdminPermission.LISTENER);
    1453             synchronized (allSyncBundleListeners) {
    1454                 CopyOnWriteIdentityMap<SynchronousBundleListener, SynchronousBundleListener> listeners = allSyncBundleListeners.get(context);
    1455                 if (listeners == null) {
    1456                     listeners = new CopyOnWriteIdentityMap<SynchronousBundleListener, SynchronousBundleListener>();
    1457                     allSyncBundleListeners.put(context, listeners);
    1458                 }
    1459                 listeners.put((SynchronousBundleListener) listener, (SynchronousBundleListener) listener);
    1460             }
    1461         } else {
    1462             synchronized (allBundleListeners) {
    1463                 CopyOnWriteIdentityMap<BundleListener, BundleListener> listeners = allBundleListeners.get(context);
    1464                 if (listeners == null) {
    1465                     listeners = new CopyOnWriteIdentityMap<BundleListener, BundleListener>();
    1466                     allBundleListeners.put(context, listeners);
    1467                 }
    1468                 listeners.put(listener, listener);
    1469             }
    1470         }
    1471     }
    1472 
    1473     void removeBundleListener(BundleListener listener, BundleContextImpl context) {
    1474         if (listener instanceof SynchronousBundleListener) {
    1475             checkAdminPermission(context.getBundle(), AdminPermission.LISTENER);
    1476             synchronized (allSyncBundleListeners) {
    1477                 CopyOnWriteIdentityMap<SynchronousBundleListener, SynchronousBundleListener> listeners = allSyncBundleListeners.get(context);
    1478                 if (listeners != null)
    1479                     listeners.remove(listener);
    1480             }
    1481         } else {
    1482             synchronized (allBundleListeners) {
    1483                 CopyOnWriteIdentityMap<BundleListener, BundleListener> listeners = allBundleListeners.get(context);
    1484                 if (listeners != null)
    1485                     listeners.remove(listener);
    1486             }
    1487         }
    1488     }
    1489 
    1490     /**
    1491      * Deliver a BundleEvent to SynchronousBundleListeners (synchronous). and
    1492      * BundleListeners (asynchronous).
    1493      * 
    1494      * @param type
    1495      *            BundleEvent type.
    1496      * @param bundle
    1497      *            Affected bundle or null.
    1498      */
    1499     public void publishBundleEvent(int type, Bundle bundle) {
    1500         publishBundleEvent(new BundleEvent(type, bundle));
    1501     }
    1502 
    1503     private void publishBundleEvent(final BundleEvent event) {
    1504         if (System.getSecurityManager() == null) {
    1505             publishBundleEventPrivileged(event);
    1506         } else {
    1507             AccessController.doPrivileged(new PrivilegedAction<Object>() {
    1508                 public Object run() {
    1509                     publishBundleEventPrivileged(event);
    1510                     return null;
    1511                 }
    1512             });
    1513         }
    1514     }
    1515 
    1516     public void publishBundleEventPrivileged(BundleEvent event) {
    1517         /*
    1518          * We must collect the snapshots of the sync and async listeners
    1519          * BEFORE we dispatch the event.
    1520          */
    1521         /* Collect snapshot of SynchronousBundleListeners */
    1522         /* Build the listener snapshot */
    1523         Map<BundleContextImpl, Set<Map.Entry<SynchronousBundleListener, SynchronousBundleListener>>> listenersSync;
    1524         synchronized (allSyncBundleListeners) {
    1525             listenersSync = new HashMap<BundleContextImpl, Set<Map.Entry<SynchronousBundleListener, SynchronousBundleListener>>>(allSyncBundleListeners.size());
    1526             for (Map.Entry<BundleContextImpl, CopyOnWriteIdentityMap<SynchronousBundleListener, SynchronousBundleListener>> entry : allSyncBundleListeners.entrySet()) {
    1527                 CopyOnWriteIdentityMap<SynchronousBundleListener, SynchronousBundleListener> listeners = entry.getValue();
    1528                 if (!listeners.isEmpty()) {
    1529                     listenersSync.put(entry.getKey(), listeners.entrySet());
    1530                 }
    1531             }
    1532         }
    1533         /* Collect snapshot of BundleListeners; only if the event is NOT STARTING or STOPPING or LAZY_ACTIVATION */
    1534         Map<BundleContextImpl, Set<Map.Entry<BundleListener, BundleListener>>> listenersAsync = null;
    1535         if ((event.getType() & (BundleEvent.STARTING | BundleEvent.STOPPING | BundleEvent.LAZY_ACTIVATION)) == 0) {
    1536             synchronized (allBundleListeners) {
    1537                 listenersAsync = new HashMap<BundleContextImpl, Set<Map.Entry<BundleListener, BundleListener>>>(allBundleListeners.size());
    1538                 for (Map.Entry<BundleContextImpl, CopyOnWriteIdentityMap<BundleListener, BundleListener>> entry : allBundleListeners.entrySet()) {
    1539                     CopyOnWriteIdentityMap<BundleListener, BundleListener> listeners = entry.getValue();
    1540                     if (!listeners.isEmpty()) {
    1541                         listenersAsync.put(entry.getKey(), listeners.entrySet());
    1542                     }
    1543                 }
    1544             }
    1545         }
    1546 
    1547         /* shrink the snapshot.
    1548          * keySet returns a Collection which cannot be added to and
    1549          * removals from that collection will result in removals of the
    1550          * entry from the snapshot.
    1551          */
    1552         Collection<BundleContext> shrinkable;
    1553         if (listenersAsync == null) {
    1554             shrinkable = asBundleContexts(listenersSync.keySet());
    1555         } else {
    1556             shrinkable = new ShrinkableCollection<BundleContext>(asBundleContexts(listenersSync.keySet()), asBundleContexts(listenersAsync.keySet()));
    1557         }
    1558         notifyEventHooksPrivileged(event, shrinkable);
    1559 
    1560         /* Dispatch the event to the snapshot for sync listeners */
    1561         if (!listenersSync.isEmpty()) {
    1562             ListenerQueue<SynchronousBundleListener, SynchronousBundleListener, BundleEvent> queue = newListenerQueue();
    1563             for (Map.Entry<BundleContextImpl, Set<Map.Entry<SynchronousBundleListener, SynchronousBundleListener>>> entry : listenersSync.entrySet()) {
    1564                 @SuppressWarnings({"rawtypes", "unchecked"})
    1565                 EventDispatcher<SynchronousBundleListener, SynchronousBundleListener, BundleEvent> dispatcher = (EventDispatcher) entry.getKey();
    1566                 Set<Map.Entry<SynchronousBundleListener, SynchronousBundleListener>> listeners = entry.getValue();
    1567                 queue.queueListeners(listeners, dispatcher);
    1568             }
    1569             queue.dispatchEventSynchronous(BUNDLEEVENTSYNC, event);
    1570         }
    1571 
    1572         /* Dispatch the event to the snapshot for async listeners */
    1573         if ((listenersAsync != null) && !listenersAsync.isEmpty()) {
    1574             ListenerQueue<BundleListener, BundleListener, BundleEvent> queue = newListenerQueue();
    1575             for (Map.Entry<BundleContextImpl, Set<Map.Entry<BundleListener, BundleListener>>> entry : listenersAsync.entrySet()) {
    1576                 @SuppressWarnings({"rawtypes", "unchecked"})
    1577                 EventDispatcher<BundleListener, BundleListener, BundleEvent> dispatcher = (EventDispatcher) entry.getKey();
    1578                 Set<Map.Entry<BundleListener, BundleListener>> listeners = entry.getValue();
    1579                 queue.queueListeners(listeners, dispatcher);
    1580             }
    1581             queue.dispatchEventAsynchronous(BUNDLEEVENT, event);
    1582         }
    1583     }
    1584 
    1585     /**
    1586      * Coerce the generic type of a collection from Collection<BundleContextImpl>
    1587      * to Collection<BundleContext>
    1588      * @param c Collection to be coerced.
    1589      * @return c coerced to Collection<BundleContext>
    1590      */
    1591     @SuppressWarnings("unchecked")
    1592     public static Collection<BundleContext> asBundleContexts(Collection<? extends BundleContext> c) {
    1593         return (Collection<BundleContext>) c;
    1594     }
    1595 
    1596     private void notifyEventHooksPrivileged(final BundleEvent event, final Collection<BundleContext> result) {
    1597         if (event.getType() == Framework.BATCHEVENT_BEGIN || event.getType() == Framework.BATCHEVENT_END)
    1598             return; // we don't need to send this event; it is used to book case special listeners
    1599         if (Debug.DEBUG_HOOKS) {
    1600             Debug.println("notifyBundleEventHooks(" + event.getType() + ":" + event.getBundle() + ", " + result + " )"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$  
    1601         }
    1602 
    1603         getServiceRegistry().notifyHooksPrivileged(new HookContext() {
    1604             public void call(Object hook, ServiceRegistration<?> hookRegistration) throws Exception {
    1605                 if (hook instanceof EventHook) {
    1606                     ((EventHook) hook).event(event, result);
    1607                 }
    1608             }
    1609 
    1610             public String getHookClassName() {
    1611                 return eventHookName;
    1612             }
    1613 
    1614             public String getHookMethodName() {
    1615                 return "event"; //$NON-NLS-1$
    1616             }
    1617         });
    1618     }
    1619 
    1620     public <K, V, E> ListenerQueue<K, V, E> newListenerQueue() {
    1621         return new ListenerQueue<K, V, E>(eventManager);
    1622     }
    1623 
    1624     private void initializeContextFinder() {
    1625         Thread current = Thread.currentThread();
    1626         try {
    1627             ClassLoader parent = null;
    1628             // check property for specified parent
    1629             String type = FrameworkProperties.getProperty(PROP_CONTEXTCLASSLOADER_PARENT);
    1630             if (CONTEXTCLASSLOADER_PARENT_APP.equals(type))
    1631                 parent = ClassLoader.getSystemClassLoader();
    1632             else if (CONTEXTCLASSLOADER_PARENT_BOOT.equals(type))
    1633                 parent = null;
    1634             else if (CONTEXTCLASSLOADER_PARENT_FWK.equals(type))
    1635                 parent = Framework.class.getClassLoader();
    1636             else if (CONTEXTCLASSLOADER_PARENT_EXT.equals(type)) {
    1637                 ClassLoader appCL = ClassLoader.getSystemClassLoader();
    1638                 if (appCL != null)
    1639                     parent = appCL.getParent();
    1640             } else { // default is ccl (null or any other value will use ccl)
    1641                 parent = current.getContextClassLoader();
    1642             }
    1643             contextFinder = new ContextFinder(parent);
    1644             current.setContextClassLoader(contextFinder);
    1645             return;
    1646         } catch (Exception e) {
    1647             FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.INFO, 0, NLS.bind(Msg.CANNOT_SET_CONTEXTFINDER, null), 0, e, null);
    1648             adaptor.getFrameworkLog().log(entry);
    1649         }
    1650 
    1651     }
    1652 
    1653     public static Field getField(Class<?> clazz, Class<?> type, boolean instance) {
    1654         Field[] fields = clazz.getDeclaredFields();
    1655         for (int i = 0; i < fields.length; i++) {
    1656             boolean isStatic = Modifier.isStatic(fields[i].getModifiers());
    1657             if (instance != isStatic && fields[i].getType().equals(type)) {
    1658                 fields[i].setAccessible(true);
    1659                 return fields[i];
    1660             }
    1661         }
    1662         return null;
    1663     }
    1664 
    1665     private void installContentHandlerFactory(BundleContext context, FrameworkAdaptor frameworkAdaptor) {
    1666         ContentHandlerFactory chf = new ContentHandlerFactory(context, frameworkAdaptor);
    1667         try {
    1668             // first try the standard way
    1669             URLConnection.setContentHandlerFactory(chf);
    1670         } catch (Error err) {
    1671             // ok we failed now use more drastic means to set the factory
    1672             try {
    1673                 forceContentHandlerFactory(chf);
    1674             } catch (Exception ex) {
    1675                 // this is unexpected, log the exception and throw the original error
    1676                 adaptor.getFrameworkLog().log(new FrameworkEvent(FrameworkEvent.ERROR, context.getBundle(), ex));
    1677                 throw err;
    1678             }
    1679         }
    1680         contentHandlerFactory = chf;
    1681     }
    1682 
    1683     private static void forceContentHandlerFactory(ContentHandlerFactory chf) throws Exception {
    1684         Field factoryField = getField(URLConnection.class, java.net.ContentHandlerFactory.class, false);
    1685         if (factoryField == null)
    1686             throw new Exception("Could not find ContentHandlerFactory field"); //$NON-NLS-1$
    1687         synchronized (URLConnection.class) {
    1688             java.net.ContentHandlerFactory factory = (java.net.ContentHandlerFactory) factoryField.get(null);
    1689             // doing a null check here just in case, but it would be really strange if it was null, 
    1690             // because we failed to set the factory normally!!
    1691 
    1692             if (factory != null) {
    1693                 try {
    1694                     factory.getClass().getMethod("isMultiplexing", (Class[]) null); //$NON-NLS-1$
    1695                     Method register = factory.getClass().getMethod("register", new Class[] {Object.class}); //$NON-NLS-1$
    1696                     register.invoke(factory, new Object[] {chf});
    1697                 } catch (NoSuchMethodException e) {
    1698                     // current factory does not support multiplexing, ok we'll wrap it
    1699                     chf.setParentFactory(factory);
    1700                     factory = chf;
    1701                 }
    1702             }
    1703             // null out the field so that we can successfully call setContentHandlerFactory            
    1704             factoryField.set(null, null);
    1705             // always attempt to clear the handlers cache
    1706             // This allows an optomization for the single framework use-case
    1707             resetContentHandlers();
    1708             URLConnection.setContentHandlerFactory(factory);
    1709         }
    1710     }
    1711 
    1712     private void uninstallContentHandlerFactory() {
    1713         try {
    1714             Field factoryField = getField(URLConnection.class, java.net.ContentHandlerFactory.class, false);
    1715             if (factoryField == null)
    1716                 return; // oh well, we tried.
    1717             synchronized (URLConnection.class) {
    1718                 java.net.ContentHandlerFactory factory = (java.net.ContentHandlerFactory) factoryField.get(null);
    1719 
    1720                 if (factory == contentHandlerFactory) {
    1721                     factory = (java.net.ContentHandlerFactory) contentHandlerFactory.designateSuccessor();
    1722                 } else {
    1723                     Method unregister = factory.getClass().getMethod("unregister", new Class[] {Object.class}); //$NON-NLS-1$
    1724                     unregister.invoke(factory, new Object[] {contentHandlerFactory});
    1725                 }
    1726                 // null out the field so that we can successfully call setContentHandlerFactory                                    
    1727                 factoryField.set(null, null);
    1728                 // always attempt to clear the handlers cache
    1729                 // This allows an optomization for the single framework use-case
    1730                 // Note that the call to setContentHandlerFactory below may clear this cache
    1731                 // but we want to be sure to clear it here just incase the parent is null.
    1732                 // In this case the call below would not occur.
    1733                 // Also it appears most java libraries actually do not clear the cache
    1734                 // when setContentHandlerFactory is called, go figure!!
    1735                 resetContentHandlers();
    1736                 if (factory != null)
    1737                     URLConnection.setContentHandlerFactory(factory);
    1738             }
    1739         } catch (Exception e) {
    1740             // ignore and continue closing the framework
    1741         }
    1742     }
    1743 
    1744     private static void resetContentHandlers() throws IllegalAccessException {
    1745         Field handlersField = getField(URLConnection.class, Hashtable.class, false);
    1746         if (handlersField != null) {
    1747             @SuppressWarnings("rawtypes")
    1748             Hashtable<?, ?> handlers = (Hashtable) handlersField.get(null);
    1749             if (handlers != null)
    1750                 handlers.clear();
    1751         }
    1752     }
    1753 
    1754     private void installURLStreamHandlerFactory(BundleContext context, FrameworkAdaptor frameworkAdaptor) {
    1755         StreamHandlerFactory shf = new StreamHandlerFactory(context, frameworkAdaptor);
    1756         try {
    1757             // first try the standard way
    1758             URL.setURLStreamHandlerFactory(shf);
    1759         } catch (Error err) {
    1760             try {
    1761                 // ok we failed now use more drastic means to set the factory
    1762                 forceURLStreamHandlerFactory(shf);
    1763             } catch (Exception ex) {
    1764                 adaptor.getFrameworkLog().log(new FrameworkEvent(FrameworkEvent.ERROR, context.getBundle(), ex));
    1765                 throw err;
    1766             }
    1767         }
    1768         streamHandlerFactory = shf;
    1769     }
    1770 
    1771     private static void forceURLStreamHandlerFactory(StreamHandlerFactory shf) throws Exception {
    1772         Field factoryField = getField(URL.class, URLStreamHandlerFactory.class, false);
    1773         if (factoryField == null)
    1774             throw new Exception("Could not find URLStreamHandlerFactory field"); //$NON-NLS-1$
    1775         // look for a lock to synchronize on
    1776         Object lock = getURLStreamHandlerFactoryLock();
    1777         synchronized (lock) {
    1778             URLStreamHandlerFactory factory = (URLStreamHandlerFactory) factoryField.get(null);
    1779             // doing a null check here just in case, but it would be really strange if it was null, 
    1780             // because we failed to set the factory normally!!
    1781             if (factory != null) {
    1782                 try {
    1783                     factory.getClass().getMethod("isMultiplexing", (Class[]) null); //$NON-NLS-1$
    1784                     Method register = factory.getClass().getMethod("register", new Class[] {Object.class}); //$NON-NLS-1$
    1785                     register.invoke(factory, new Object[] {shf});
    1786                 } catch (NoSuchMethodException e) {
    1787                     // current factory does not support multiplexing, ok we'll wrap it
    1788                     shf.setParentFactory(factory);
    1789                     factory = shf;
    1790                 }
    1791             }
    1792             factoryField.set(null, null);
    1793             // always attempt to clear the handlers cache
    1794             // This allows an optomization for the single framework use-case
    1795             resetURLStreamHandlers();
    1796             URL.setURLStreamHandlerFactory(factory);
    1797         }
    1798     }
    1799 
    1800     private void uninstallURLStreamHandlerFactory() {
    1801         try {
    1802             Field factoryField = getField(URL.class, URLStreamHandlerFactory.class, false);
    1803             if (factoryField == null)
    1804                 return; // oh well, we tried
    1805             Object lock = getURLStreamHandlerFactoryLock();
    1806             synchronized (lock) {
    1807                 URLStreamHandlerFactory factory = (URLStreamHandlerFactory) factoryField.get(null);
    1808                 if (factory == streamHandlerFactory) {
    1809                     factory = (URLStreamHandlerFactory) streamHandlerFactory.designateSuccessor();
    1810                 } else {
    1811                     Method unregister = factory.getClass().getMethod("unregister", new Class[] {Object.class}); //$NON-NLS-1$
    1812                     unregister.invoke(factory, new Object[] {streamHandlerFactory});
    1813                 }
    1814                 factoryField.set(null, null);
    1815                 // always attempt to clear the handlers cache
    1816                 // This allows an optomization for the single framework use-case
    1817                 // Note that the call to setURLStreamHandlerFactory below may clear this cache
    1818                 // but we want to be sure to clear it here just in case the parent is null.
    1819                 // In this case the call below would not occur.
    1820                 resetURLStreamHandlers();
    1821                 if (factory != null)
    1822                     URL.setURLStreamHandlerFactory(factory);
    1823             }
    1824         } catch (Exception e) {
    1825             // ignore and continue closing the framework
    1826         }
    1827     }
    1828 
    1829     private static Object getURLStreamHandlerFactoryLock() throws IllegalAccessException {
    1830         Object lock;
    1831         try {
    1832             Field streamHandlerLockField = URL.class.getDeclaredField("streamHandlerLock"); //$NON-NLS-1$
    1833             streamHandlerLockField.setAccessible(true);
    1834             lock = streamHandlerLockField.get(null);
    1835         } catch (NoSuchFieldException noField) {
    1836             // could not find the lock, lets sync on the class object
    1837             lock = URL.class;
    1838         }
    1839         return lock;
    1840     }
    1841 
    1842     private static void resetURLStreamHandlers() throws IllegalAccessException {
    1843         Field handlersField = getField(URL.class, Hashtable.class, false);
    1844         if (handlersField != null) {
    1845             @SuppressWarnings("rawtypes")
    1846             Hashtable<?, ?> handlers = (Hashtable) handlersField.get(null);
    1847             if (handlers != null)
    1848                 handlers.clear();
    1849         }
    1850     }
    1851 
    1852     /*
    1853      * (non-Javadoc)
    1854      * @see java.lang.Runnable#run()
    1855      * This thread monitors the framework active status and terminates when the framework is
    1856      * shutdown.  This is needed to ensure the VM does not exist because of the lack of a
    1857      * non-daemon thread (bug 215730)
    1858      */
    1859     public void run() {
    1860         synchronized (this) {
    1861             while (active)
    1862                 try {
    1863                     this.wait(1000);
    1864                 } catch (InterruptedException e) {
    1865                     // do nothing
    1866                 }
    1867         }
    1868     }
    1869 
    1870     void setForcedRestart(boolean forcedRestart) {
    1871         this.forcedRestart = forcedRestart;
    1872     }
    1873 
    1874     boolean isForcedRestart() {
    1875         return forcedRestart;
    1876     }
    1877 
    1878     public FrameworkEvent waitForStop(long timeout) throws InterruptedException {
    1879         boolean waitForEver = timeout == 0;
    1880         long start = System.currentTimeMillis();
    1881         long timeLeft = timeout;
    1882         synchronized (this) {
    1883             FrameworkEvent[] event = shutdownEvent;
    1884             while (event != null && event[0] == null) {
    1885                 this.wait(timeLeft);
    1886                 if (!waitForEver) {
    1887                     timeLeft = start + timeout - System.currentTimeMillis();
    1888                     // break if we are passed the timeout
    1889                     if (timeLeft <= 0)
    1890                         break;
    1891                 }
    1892             }
    1893             if (event == null || event[0] == null)
    1894                 return new FrameworkEvent(FrameworkEvent.WAIT_TIMEDOUT, systemBundle, null);
    1895             return event[0];
    1896         }
    1897     }
    1898 
    1899     /**
    1900      * Used by ServiceReferenceImpl for isAssignableTo
    1901      * @param registrant Bundle registering service
    1902      * @param client Bundle desiring to use service
    1903      * @param className class name to use
    1904      * @param serviceClass class of original service object
    1905      * @return true if assignable given package wiring
    1906      */
    1907     public boolean isServiceAssignableTo(Bundle registrant, Bundle client, String className, Class<?> serviceClass) {
    1908         // always return false for fragments
    1909         AbstractBundle consumer = (AbstractBundle) client;
    1910         if (consumer.isFragment())
    1911             return false;
    1912         // 1) if the registrant == consumer always return true
    1913         AbstractBundle producer = (AbstractBundle) registrant;
    1914         if (consumer == producer)
    1915             return true;
    1916         // 2) get the package name from the specified className
    1917         String pkgName = BundleLoader.getPackageName(className);
    1918         if (pkgName.startsWith("java.")) //$NON-NLS-1$
    1919             return true;
    1920         BundleLoader producerBL = producer.getBundleLoader();
    1921         if (producerBL == null)
    1922             return false;
    1923         BundleLoader consumerBL = consumer.getBundleLoader();
    1924         if (consumerBL == null)
    1925             return false;
    1926         // 3) for the specified bundle, find the wiring for the package.  If no wiring is found return true
    1927         PackageSource consumerSource = consumerBL.getPackageSource(pkgName);
    1928         if (consumerSource == null)
    1929             return true;
    1930         // work around the issue when the package is in the EE and we delegate to boot for that package
    1931         if (isBootDelegationPackage(pkgName)) {
    1932             SystemBundleLoader systemLoader = (SystemBundleLoader) systemBundle.getBundleLoader();
    1933             if (systemLoader.isEEPackage(pkgName))
    1934                 return true; // in this case we have a common source from the EE
    1935         }
    1936         // 4) For the registrant bundle, find the wiring for the package.
    1937         PackageSource producerSource = producerBL.getPackageSource(pkgName);
    1938         if (producerSource == null) {
    1939             if (serviceClass != null && ServiceFactory.class.isAssignableFrom(serviceClass)) {
    1940                 Bundle bundle = packageAdmin.getBundle(serviceClass);
    1941                 if (bundle != null && bundle != registrant)
    1942                     // in this case we have a wacky ServiceFactory that is doing something we cannot 
    1943                     // verify if it is correct.  Instead of failing we allow the assignment and hope for the best
    1944                     // bug 326918
    1945                     return true;
    1946             }
    1947             // 5) If no wiring is found for the registrant bundle then find the wiring for the classloader of the service object.  If no wiring is found return false.
    1948             producerSource = getPackageSource(serviceClass, pkgName);
    1949             if (producerSource == null)
    1950                 return false;
    1951         }
    1952         // 6) If the two wirings found are equal then return true; otherwise return false.
    1953         return producerSource.hasCommonSource(consumerSource);
    1954     }
    1955 
    1956     private PackageSource getPackageSource(Class<?> serviceClass, String pkgName) {
    1957         if (serviceClass == null)
    1958             return null;
    1959         AbstractBundle serviceBundle = (AbstractBundle) packageAdmin.getBundle(serviceClass);
    1960         if (serviceBundle == null)
    1961             return null;
    1962         BundleLoader producerBL = serviceBundle.getBundleLoader();
    1963         if (producerBL == null)
    1964             return null;
    1965         PackageSource producerSource = producerBL.getPackageSource(pkgName);
    1966         if (producerSource != null)
    1967             return producerSource;
    1968         // try the interfaces
    1969         Class<?>[] interfaces = serviceClass.getInterfaces();
    1970         // note that getInterfaces never returns null
    1971         for (int i = 0; i < interfaces.length; i++) {
    1972             producerSource = getPackageSource(interfaces[i], pkgName);
    1973             if (producerSource != null)
    1974                 return producerSource;
    1975         }
    1976         // try super class
    1977         return getPackageSource(serviceClass.getSuperclass(), pkgName);
    1978     }
    1979 
    1980     public boolean isBootDelegationPackage(String name) {
    1981         if (bootDelegateAll)
    1982             return true;
    1983         if (bootDelegation != null)
    1984             for (int i = 0; i < bootDelegation.length; i++)
    1985                 if (name.equals(bootDelegation[i]))
    1986                     return true;
    1987         if (bootDelegationStems != null)
    1988             for (int i = 0; i < bootDelegationStems.length; i++)
    1989                 if (name.startsWith(bootDelegationStems[i]))
    1990                     return true;
    1991         return false;
    1992     }
    1993 
    1994     SignedContentFactory getSignedContentFactory() {
    1995         ServiceTracker<SignedContentFactory, SignedContentFactory> currentTracker = signedContentFactory;
    1996         return (currentTracker == null ? null : currentTracker.getService());
    1997     }
    1998 
    1999     ContextFinder getContextFinder() {
    2000         return contextFinder;
    2001     }
    2002 
    2003     public boolean isRefreshDuplicateBSNAllowed() {
    2004         return allowRefreshDuplicateBSN;
    2005     }
    2006 
    2007 }
    Framework
     1     public Framework(FrameworkAdaptor adaptor) {
     2         if (Profile.PROFILE && Profile.STARTUP)
     3             Profile.logEnter("Framework.initialze()", null); //$NON-NLS-1$
     4         String bsnVersion = FrameworkProperties.getProperty(Constants.FRAMEWORK_BSNVERSION);
     5         if (Constants.FRAMEWORK_BSNVERSION_SINGLE.equals(bsnVersion)) {
     6             BSN_VERSION = BSN_VERSION_SINGLE;
     7         } else if (Constants.FRAMEWORK_BSNVERSION_MULTIPLE.equals(bsnVersion)) {
     8             BSN_VERSION = BSN_VERSION_MULTIPLE;
     9         } else {
    10             BSN_VERSION = BSN_VERSION_MANAGED;
    11         }
    12         long start = System.currentTimeMillis();
    13         this.adaptor = adaptor;
    14         delegateHooks = adaptor instanceof BaseAdaptor ? ((BaseAdaptor) adaptor).getHookRegistry().getClassLoaderDelegateHooks() : null;
    15         active = false;
    16         installSecurityManager();
    17         if (Debug.DEBUG_SECURITY) {
    18             Debug.println("SecurityManager: " + System.getSecurityManager()); //$NON-NLS-1$
    19             Debug.println("ProtectionDomain of Framework.class: \n" + this.getClass().getProtectionDomain()); //$NON-NLS-1$
    20         }
    21         setNLSFrameworkLog();
    22         // initialize ContextFinder
    23         initializeContextFinder();
    24         /* initialize the adaptor */
    25         adaptor.initialize(this);
    26         if (Profile.PROFILE && Profile.STARTUP)
    27             Profile.logTime("Framework.initialze()", "adapter initialized"); //$NON-NLS-1$//$NON-NLS-2$
    28         try {
    29             adaptor.initializeStorage();
    30         } catch (IOException e) /* fatal error */{
    31             throw new RuntimeException(e.getMessage(), e);
    32         }
    33         if (Profile.PROFILE && Profile.STARTUP)
    34             Profile.logTime("Framework.initialze()", "adapter storage initialized"); //$NON-NLS-1$//$NON-NLS-2$
    35         /*
    36          * This must be done before calling any of the framework getProperty
    37          * methods.
    38          */
    39         initializeProperties(adaptor.getProperties());
    40         /* initialize admin objects */
    41         packageAdmin = new PackageAdminImpl(this);
    42         try {
    43             // always create security admin even with security off
    44             securityAdmin = new SecurityAdmin(null, this, adaptor.getPermissionStorage());
    45         } catch (IOException e) /* fatal error */{
    46             e.printStackTrace();
    47             throw new RuntimeException(e.getMessage(), e);
    48         }
    49         if (Profile.PROFILE && Profile.STARTUP)
    50             Profile.logTime("Framework.initialze()", "done init props & new PermissionAdminImpl"); //$NON-NLS-1$//$NON-NLS-2$
    51         startLevelManager = new StartLevelManager(this);
    52         /* create the event manager and top level event dispatchers */
    53         eventManager = new EventManager("Framework Event Dispatcher"); //$NON-NLS-1$
    54         if (Profile.PROFILE && Profile.STARTUP)
    55             Profile.logTime("Framework.initialze()", "done new EventManager"); //$NON-NLS-1$ //$NON-NLS-2$
    56         /* create the service registry */
    57         serviceRegistry = new ServiceRegistry(this);
    58         // Initialize the installLock; there is no way of knowing 
    59         // what the initial size should be, at most it will be the number
    60         // of threads trying to install a bundle (probably a very low number).
    61         installLock = new HashMap<String, Thread>(10);
    62         /* create the system bundle */
    63         createSystemBundle();
    64loadVMProfile(); // load VM profile after the system bundle has been created
    65         setBootDelegation(); //set boot delegation property after system exports have been set
    66         if (Profile.PROFILE && Profile.STARTUP)
    67             Profile.logTime("Framework.initialze()", "done createSystemBundle"); //$NON-NLS-1$ //$NON-NLS-2$
    68         /* install URLStreamHandlerFactory */
    69         installURLStreamHandlerFactory(systemBundle.context, adaptor);
    70         /* install ContentHandlerFactory for OSGi URLStreamHandler support */
    71         installContentHandlerFactory(systemBundle.context, adaptor);
    72         if (Profile.PROFILE && Profile.STARTUP)
    73             Profile.logTime("Framework.initialze()", "done new URLStream/Content HandlerFactory"); //$NON-NLS-1$//$NON-NLS-2$
    74         /* create bundle objects for all installed bundles. */
    75         BundleData[] bundleDatas = adaptor.getInstalledBundles();
    76         bundles = new BundleRepository(bundleDatas == null ? 10 : bundleDatas.length + 1);
    77         /* add the system bundle to the Bundle Repository */
    78         bundles.add(systemBundle);
    79         if (bundleDatas != null) {
    80             for (int i = 0; i < bundleDatas.length; i++) {
    81                 try {
    82                     AbstractBundle bundle = AbstractBundle.createBundle(bundleDatas[i], this, true);
    83                     bundles.add(bundle);
    84                 } catch (BundleException be) {
    85                     // This is not a fatal error. Publish the framework event.
    86                     publishFrameworkEvent(FrameworkEvent.ERROR, systemBundle, be);
    87                 }
    88             }
    89         }
    90         if (Debug.DEBUG_GENERAL)
    91             System.out.println("Initialize the framework: " + (System.currentTimeMillis() - start)); //$NON-NLS-1$
    92         if (Profile.PROFILE && Profile.STARTUP)
    93             Profile.logExit("Framework.initialize()"); //$NON-NLS-1$
    94     }

framework.luanch()

 1 public synchronized void launch() {
 2         /* Return if framework already started */
 3         if (active) {
 4             return;
 5         }
 6         /* mark framework as started */
 7         active = true;
 8         shutdownEvent = new FrameworkEvent[1];
 9         if (THREAD_NORMAL.equals(FrameworkProperties.getProperty(PROP_FRAMEWORK_THREAD, THREAD_NORMAL))) {
10             Thread fwkThread = new Thread(this, "Framework Active Thread"); //$NON-NLS-1$
11             fwkThread.setDaemon(false);
12             fwkThread.start();
13         }
14         /* Resume systembundle */
15         if (Debug.DEBUG_GENERAL) {
16             Debug.println("Trying to launch framework"); //$NON-NLS-1$
17         }
18         systemBundle.resume();
19         signedContentFactory = new ServiceTracker<SignedContentFactory, SignedContentFactory>(systemBundle.getBundleContext(), SignedContentFactory.class.getName(), null);
20         signedContentFactory.open();
21     }

 

 1     /*
 2      * (non-Javadoc)
 3      * @see java.lang.Runnable#run()
 4      * This thread monitors the framework active status and terminates when the framework is
 5      * shutdown.  This is needed to ensure the VM does not exist because of the lack of a
 6      * non-daemon thread (bug 215730)
 7      */
 8     public void run() {
 9         synchronized (this) {
10             while (active)
11                 try {
12                     this.wait(1000);
13                 } catch (InterruptedException e) {
14                     // do nothing
15                 }
16         }
17     }

 

  • load basic bundles
  • 1 Bundle[] startBundles = loadBasicBundles();

     

  •  1 private static Bundle[] loadBasicBundles() {
     2         long startTime = System.currentTimeMillis();
     3         String osgiBundles = FrameworkProperties.getProperty(PROP_BUNDLES);
     4         String osgiExtensions = FrameworkProperties.getProperty(PROP_EXTENSIONS);
     5         if (osgiExtensions != null && osgiExtensions.length() > 0) {
     6             osgiBundles = osgiExtensions + ',' + osgiBundles;
     7             FrameworkProperties.setProperty(PROP_BUNDLES, osgiBundles);
     8         }
     9         String[] installEntries = getArrayFromList(osgiBundles, ","); //$NON-NLS-1$
    10         // get the initial bundle list from the installEntries
    11         InitialBundle[] initialBundles = getInitialBundles(installEntries);
    12         // get the list of currently installed initial bundles from the framework
    13         Bundle[] curInitBundles = getCurrentBundles(true);
    14 
    15         // list of bundles to be refreshed
    16         List<Bundle> toRefresh = new ArrayList<Bundle>(curInitBundles.length);
    17         // uninstall any of the currently installed bundles that do not exist in the 
    18         // initial bundle list from installEntries.
    19         uninstallBundles(curInitBundles, initialBundles, toRefresh);
    20 
    21         // install the initialBundles that are not already installed.
    22         List<Bundle> startBundles = new ArrayList<Bundle>(installEntries.length);
    23         List<Bundle> lazyActivationBundles = new ArrayList<Bundle>(installEntries.length);
    24         installBundles(initialBundles, curInitBundles, startBundles, lazyActivationBundles, toRefresh);
    25 
    26         // If we installed/uninstalled something, force a refresh of all installed/uninstalled bundles
    27         if (!toRefresh.isEmpty() && refreshPackages(toRefresh.toArray(new Bundle[toRefresh.size()])))
    28             return null; // cannot continue; refreshPackages shutdown the framework
    29 
    30         // schedule all basic bundles to be started
    31         Bundle[] startInitBundles = startBundles.toArray(new Bundle[startBundles.size()]);
    32         Bundle[] lazyInitBundles = lazyActivationBundles.toArray(new Bundle[lazyActivationBundles.size()]);
    33         startBundles(startInitBundles, lazyInitBundles);
    34 
    35         if (debug)
    36             System.out.println("Time to load bundles: " + (System.currentTimeMillis() - startTime)); //$NON-NLS-1$
    37         return startInitBundles;
    38     }

     startBundles() in which our Activator' s start method will be executed.

  •  1     private static void startBundles(Bundle[] startBundles, Bundle[] lazyBundles) {
     2         for (int i = 0; i < startBundles.length; i++)
     3             startBundle(startBundles[i], 0);
     4         for (int i = 0; i < lazyBundles.length; i++)
     5             startBundle(lazyBundles[i], Bundle.START_ACTIVATION_POLICY);
     6     }
     7 
     8     private static void startBundle(Bundle bundle, int options) {
     9         try {
    10             bundle.start(options);
    11         } catch (BundleException e) {
    12             if ((bundle.getState() & Bundle.RESOLVED) != 0) {
    13                 // only log errors if the bundle is resolved
    14                 FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_FAILED_START, bundle.getLocation()), 0, e, null);
    15                 log.log(entry);
    16             }
    17         }
    18     }

     config.ini

  •  1 #This configuration file was written by: org.eclipse.equinox.internal.frameworkadmin.equinox.EquinoxFwConfigFileParser
     2 #Thu Sep 05 17:05:01 CST 2013
     3 org.eclipse.update.reconcile=false
     4 eclipse.p2.profile=SDKProfile
     5 osgi.instance.area.default=@user.home/workspace
     6 osgi.framework=file\:plugins/org.eclipse.osgi_3.8.0.v20120529-1548.jar
     7 equinox.use.ds=true
     8 eclipse.buildId=I20120608-1400
     9 osgi.bundles=reference\:file\:org.eclipse.equinox.simpleconfigurator_1.0.300.v20110815-1744.jar@1\:start
    10 org.eclipse.equinox.simpleconfigurator.configUrl=file\:org.eclipse.equinox.simpleconfigurator/bundles.info
    11 eclipse.product=org.eclipse.sdk.ide
    12 osgi.splashPath=platform\:/base/plugins/org.eclipse.platform
    13 osgi.framework.extensions=
    14 osgi.bundles.defaultStartLevel=4
    15 eclipse.p2.data.area=@config.dir/../p2/
    16 eclipse.application=org.eclipse.ui.ide.workbench 
  • When clicking eclipse.exe which is a windows program, it will execute to startup JVM and  set some enviroment variables, read elipse.ini
  • Eclipse Launcher
    
    Description
    Eclipse contains a native executable launcher that is used to start Eclipse.  There is more to the launcher than just the eclipse executable in the root of the install.
    
    
    The launcher and its shared library
    The launcher executable comes in 2 pieces: the executable (eclipse.exe), and a shared library (eclipse_1017.dll). The executable lives in the root of the eclipse install. The shared library is in a platform specific fragment, org.eclipse.equinox.launcher.[config], in the plugins directory. 
    
    Having the majority of the launcher code in a shared library that lives in a fragment means that that portion of the launch code can now be updated from an update site. Also, when starting from java, the shared library can be loaded via JNI in order to display the splash screen. 
    
    The launcher bundle
    Previous versions of Eclipse had a startup.jar JAR file in the root of the install.  In 3.3, this code has been moved to a plug-in org.eclipse.equinox.launcher in the plugins directory. Eclipse can still be started directly with java using, for example: 
    
    java -jar plugins/org.eclipse.equinox.launcher_1.0.0.v20070606.jar
    Launching Eclipse involves 3 main pieces: the native executable, the launcher platform specific fragment and the launcher jar. In the example below, notice that the launcher fragment is in folder form, this is necessary so that the native eclipse.exe can load the shared library: 
    
    eclipse/     eclipse.exe    plugins/        org.eclipse.equinox.launcher_1.0.0.v20070606.jar        org.eclipse.equinox.launcher.win32.win32.x86_1.0.0.v20070523/            eclipse_1017a.dll
    The version numbers above are for illustration purposes only (e.g. 1.0.0.v20070606). The actual version numbers may vary depending on the version of Eclipse you are using. 
    
    Finding a VM and using the JNI Invocation API
    The Eclipse launcher is capable of loading the Java VM in the eclipse process using the Java Native Interface Invocation API.  The launcher is still capable of starting the Java VM in a separate process the same as previous version of Eclipse did.  Which method is used depends on how the VM was found.
    
    
    No -vm specified
    When no -vm is specified, the launcher looks for a virtual machine first in a jre directory in the root of eclipse and then on the search path. If java is found in either location, then the launcher looks for a jvm shared library (jvm.dll on Windows, libjvm.so on *nix platforms) relative to that java executable. 
    
    If a jvm shared library is found the launcher loads it and uses the JNI invocation API to start the vm. 
    If no jvm shared library is found, the launcher executes the java launcher to start the vm in a new process. 
    -vm specified on the command line or in eclipse.ini
    Eclipse can be started with "-vm <location>" to indicate a virtual machine to use. There are several possibilities for the value of <location>: 
    
    directory:  <location> is a directory. We look in that directory for: (1) a java launcher or (2) the jvm shared library. If we find the jvm shared library, we use JNI invocation. If we find a launcher, we attempt to find a jvm library in known locations relative to the launcher. If we find one, we use JNI invocation. If no jvm library is found, we exec java in a new process.
    
    java.exe/javaw.exe: <location> is a path to a java launcher. We exec that java launcher to start the vm in a new process. 
    jvm dll or so: <location> is a path to a jvm shared library. We attempt to load that library and use the JNI Invocation API to start the vm in the current process. 
    Exceptions
    linux.ppc, linux.x86_64, aix.ppc:  The launcher is not able to load some older vms using the JNI invocation API.  By default on these platforms the launcher will prefer to execute java in a separate process.  To force the launcher to load the vm using JNI, specify a -vm option pointing directly to the vm's shared library (libjvm.so). 
    MacOSX:  The launcher uses the system JavaVM framework and will always load the vm in-process using the JNI invocation API.
    Eclipse Launcher
  •  1 -startup
     2 plugins/org.eclipse.equinox.launcher_1.3.0.v20120522-1813.jar
     3 --launcher.library
     4 plugins/org.eclipse.equinox.launcher.win32.win32.x86_1.1.200.v20120522-1813
     5 -showsplash
     6 org.eclipse.platform
     7 --launcher.XXMaxPermSize
     8 256m
     9 --launcher.defaultAction
    10 openFile
    11 -vmargs
    12 -Xms40m
    13 -Xmx512m
     1 org.eclipse.equinox.launcher.Main.main(Main.java:1414)
     2 org.eclipse.equinox.launcher.Main.run(Main.java:1438)
     3 org.eclipse.equinox.launcher.Main.basicRun(Main.java:584)
     4 org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:629)
     5 java.lang.reflect.Method.invoke(Unknown Source)
     6 sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
     7 sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
     8 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     9 org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:180)
    10 org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:353)
  • run()
  •  1 public static Object run(Object argument) throws Exception {
     2         if (Profile.PROFILE && Profile.STARTUP)
     3             Profile.logEnter("EclipseStarter.run(Object)()", null); //$NON-NLS-1$
     4         if (!running)
     5             throw new IllegalStateException(EclipseAdaptorMsg.ECLIPSE_STARTUP_NOT_RUNNING);
     6         // if we are just initializing, do not run the application just return.
     7         if (initialize)
     8             return new Integer(0);
     9         try {
    10             if (appLauncher == null) {
    11                 boolean launchDefault = Boolean.valueOf(FrameworkProperties.getProperty(PROP_APPLICATION_LAUNCHDEFAULT, "true")).booleanValue(); //$NON-NLS-1$
    12                 // create the ApplicationLauncher and register it as a service
    13                 appLauncher = new EclipseAppLauncher(context, Boolean.valueOf(FrameworkProperties.getProperty(PROP_ALLOW_APPRELAUNCH)).booleanValue(), launchDefault, log);
    14                 appLauncherRegistration = context.registerService(ApplicationLauncher.class.getName(), appLauncher, null);
    15                 // must start the launcher AFTER service restration because this method 
    16                 // blocks and runs the application on the current thread.  This method 
    17                 // will return only after the application has stopped.
    18                 return appLauncher.start(argument);
    19             }
    20             return appLauncher.reStart(argument);
    21         } catch (Exception e) {
    22             if (log != null && context != null) // context can be null if OSGi failed to launch (bug 151413)
    23                 logUnresolvedBundles(context.getBundles());
    24             throw e;
    25         }
    26     }
  • EclipseAppLauncher
  •   1 /*******************************************************************************
      2  * Copyright (c) 2005, 2010 IBM Corporation and others.
      3  * All rights reserved. This program and the accompanying materials
      4  * are made available under the terms of the Eclipse Public License v1.0
      5  * which accompanies this distribution, and is available at
      6  * http://www.eclipse.org/legal/epl-v10.html
      7  * 
      8  * Contributors:
      9  *     IBM Corporation - initial API and implementation
     10  *******************************************************************************/
     11 
     12 package org.eclipse.core.runtime.internal.adaptor;
     13 
     14 import java.lang.reflect.Method;
     15 import java.util.Map;
     16 import org.eclipse.core.runtime.adaptor.EclipseStarter;
     17 import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor;
     18 import org.eclipse.osgi.framework.internal.core.Constants;
     19 import org.eclipse.osgi.framework.internal.core.FrameworkProperties;
     20 import org.eclipse.osgi.framework.log.FrameworkLog;
     21 import org.eclipse.osgi.framework.log.FrameworkLogEntry;
     22 import org.eclipse.osgi.internal.profile.Profile;
     23 import org.eclipse.osgi.service.runnable.*;
     24 import org.osgi.framework.*;
     25 
     26 public class EclipseAppLauncher implements ApplicationLauncher {
     27     volatile private ParameterizedRunnable runnable = null;
     28     private Object appContext = null;
     29     private Semaphore runningLock = new Semaphore(1);
     30     private Semaphore waitForAppLock = new Semaphore(0);
     31     private BundleContext context;
     32     private boolean relaunch = false;
     33     private boolean failOnNoDefault = false;
     34     private FrameworkLog log;
     35 
     36     public EclipseAppLauncher(BundleContext context, boolean relaunch, boolean failOnNoDefault, FrameworkLog log) {
     37         this.context = context;
     38         this.relaunch = relaunch;
     39         this.failOnNoDefault = failOnNoDefault;
     40         this.log = log;
     41         findRunnableService();
     42     }
     43 
     44     /*
     45      * Used for backwards compatibility with < 3.2 runtime
     46      */
     47     private void findRunnableService() {
     48         // look for a ParameterizedRunnable registered as a service by runtimes (3.0, 3.1)
     49         String appClass = ParameterizedRunnable.class.getName();
     50         ServiceReference<?>[] runRefs = null;
     51         try {
     52             runRefs = context.getServiceReferences(ParameterizedRunnable.class.getName(), "(&(objectClass=" + appClass + ")(eclipse.application=*))"); //$NON-NLS-1$//$NON-NLS-2$
     53         } catch (InvalidSyntaxException e) {
     54             // ignore this.  It should never happen as we have tested the above format.
     55         }
     56         if (runRefs != null && runRefs.length > 0) {
     57             // found the service use it as the application.
     58             runnable = (ParameterizedRunnable) context.getService(runRefs[0]);
     59             // we will never be able to relaunch with a pre 3.2 runtime
     60             relaunch = false;
     61             waitForAppLock.release();
     62         }
     63     }
     64 
     65     /*
     66      * Starts this application launcher on the current thread.  This method
     67      * should be called by the main thread to ensure that applications are 
     68      * launched in the main thread.
     69      */
     70     public Object start(Object defaultContext) throws Exception {
     71         // here we assume that launch has been called by runtime before we started
     72         // TODO this may be a bad assumption but it works for now because we register the app launcher as a service and runtime synchronously calls launch on the service
     73         if (failOnNoDefault && runnable == null)
     74             throw new IllegalStateException(EclipseAdaptorMsg.ECLIPSE_STARTUP_ERROR_NO_APPLICATION);
     75         Object result = null;
     76         boolean doRelaunch;
     77         do {
     78             try {
     79                 result = runApplication(defaultContext);
     80             } catch (Exception e) {
     81                 if (!relaunch || (context.getBundle().getState() & Bundle.ACTIVE) == 0)
     82                     throw e;
     83                 if (log != null)
     84                     log.log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, EclipseAdaptorMsg.ECLIPSE_STARTUP_APP_ERROR, 1, e, null));
     85             }
     86             doRelaunch = (relaunch && (context.getBundle().getState() & Bundle.ACTIVE) != 0) || FrameworkProperties.getProperty(Constants.PROP_OSGI_RELAUNCH) != null;
     87         } while (doRelaunch);
     88         return result;
     89     }
     90 
     91     /*
     92      * Waits for an application to be launched and the runs the application on the
     93      * current thread (main).
     94      */
     95     private Object runApplication(Object defaultContext) throws Exception {
     96         // wait for an application to be launched.
     97         waitForAppLock.acquire();
     98         // an application is ready; acquire the running lock.
     99         // this must happen after we have acquired an application (by acquiring waitForAppLock above).
    100         runningLock.acquire();
    101         if (EclipseStarter.debug) {
    102             String timeString = FrameworkProperties.getProperty("eclipse.startTime"); //$NON-NLS-1$ 
    103             long time = timeString == null ? 0L : Long.parseLong(timeString);
    104             System.out.println("Starting application: " + (System.currentTimeMillis() - time)); //$NON-NLS-1$ 
    105         }
    106         if (Profile.PROFILE && (Profile.STARTUP || Profile.BENCHMARK))
    107             Profile.logTime("EclipseStarter.run(Object)()", "framework initialized! starting application..."); //$NON-NLS-1$ //$NON-NLS-2$
    108         try {
    109             // run the actual application on the current thread (main).
    110             return runnable.run(appContext != null ? appContext : defaultContext);
    111         } finally {
    112             if (Profile.PROFILE && Profile.STARTUP)
    113                 Profile.logExit("EclipseStarter.run(Object)()"); //$NON-NLS-1$
    114             // free the runnable application and release the lock to allow another app to be launched.
    115             runnable = null;
    116             appContext = null;
    117             runningLock.release();
    118         }
    119     }
    120 
    121     public void launch(ParameterizedRunnable app, Object applicationContext) {
    122         waitForAppLock.acquire(-1); // clear out any pending apps notifications
    123         if (!runningLock.acquire(-1)) // check to see if an application is currently running
    124             throw new IllegalStateException("An application is aready running."); //$NON-NLS-1$
    125         this.runnable = app;
    126         this.appContext = applicationContext;
    127         waitForAppLock.release(); // notify the main thread to launch an application.
    128         runningLock.release(); // release the running lock
    129     }
    130 
    131     public void shutdown() {
    132         // this method will aquire and keep the runningLock to prevent
    133         // all future application launches.
    134         if (runningLock.acquire(-1))
    135             return; // no application is currently running.
    136         ParameterizedRunnable currentRunnable = runnable;
    137         if (currentRunnable instanceof ApplicationRunnable) {
    138             ((ApplicationRunnable) currentRunnable).stop();
    139             runningLock.acquire(60000); // timeout after 1 minute.
    140         }
    141     }
    142 
    143     /*
    144      * Similar to the start method this method will restart the default method on current thread.
    145      * This method assumes that the default application was launched at least once and that an ApplicationDescriptor 
    146      * exists that can be used to relaunch the default application.
    147      */
    148     public Object reStart(Object argument) throws Exception {
    149         ServiceReference<?> ref[] = null;
    150         ref = context.getServiceReferences("org.osgi.service.application.ApplicationDescriptor", "(eclipse.application.default=true)"); //$NON-NLS-1$//$NON-NLS-2$
    151         if (ref != null && ref.length > 0) {
    152             Object defaultApp = context.getService(ref[0]);
    153             Method launch = defaultApp.getClass().getMethod("launch", new Class[] {Map.class}); //$NON-NLS-1$
    154             launch.invoke(defaultApp, new Object[] {null});
    155             return start(argument);
    156         }
    157         throw new IllegalStateException(EclipseAdaptorMsg.ECLIPSE_STARTUP_ERROR_NO_APPLICATION);
    158     }
    159 }
    EclipseAppLaunch

     

  •  1 at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
     2 at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
     3 at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)
     4 at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:124)
     5 at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
     6 at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:540)
     7 at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:585)
     8 at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:86)
     9 at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:916)
    10 at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)    
    11 at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$9.run(PartRenderingEngine.java:1022)
    12 at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3756)
    13 at org.eclipse.swt.internal.win32.OS.DispatchMessage(OS.java:2546)
    14 at org.eclipse.swt.internal.win32.OS.DispatchMessageW(Native Method)
    15 at org.eclipse.swt.widgets.Display.windowProc(Display.java:4976)
    16 at org.eclipse.swt.widgets.Control.windowProc(Control.java:4528)
    17 at org.eclipse.swt.widgets.Control.WM_CHAR(Control.java:4640)
    18 at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1062)
    19 at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1077)
    20 at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1052)
    21 at org.eclipse.swt.widgets.Widget.wmChar(Widget.java:1521)
    22 at org.eclipse.swt.widgets.Widget.sendKeyEvent(Widget.java:1100)
    23 at org.eclipse.swt.widgets.Widget.sendKeyEvent(Widget.java:1104)
    24 at org.eclipse.swt.widgets.Display.filterEvent(Display.java:1262)
    25 at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)

     

posted @ 2013-09-06 11:23  iDragon  阅读(1342)  评论(0)    收藏  举报