Copyright (c) 2003, 2016 IBM Corporation and others. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: IBM Corporation - initial API and implementation Alex Blewitt (bug 172969)
/******************************************************************************* * Copyright (c) 2003, 2016 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation * Alex Blewitt (bug 172969) *******************************************************************************/
package org.eclipse.core.runtime.adaptor; import java.io.*; import java.lang.reflect.Method; import java.net.*; import java.security.CodeSource; import java.security.ProtectionDomain; import java.util.*; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import org.eclipse.core.runtime.internal.adaptor.*; import org.eclipse.osgi.container.Module; import org.eclipse.osgi.container.ModuleRevision; import org.eclipse.osgi.container.namespaces.EquinoxModuleDataNamespace; import org.eclipse.osgi.framework.log.FrameworkLog; import org.eclipse.osgi.framework.log.FrameworkLogEntry; import org.eclipse.osgi.framework.util.FilePath; import org.eclipse.osgi.internal.debug.Debug; import org.eclipse.osgi.internal.framework.EquinoxConfiguration; import org.eclipse.osgi.internal.framework.EquinoxContainer; import org.eclipse.osgi.internal.location.EquinoxLocations; import org.eclipse.osgi.internal.location.LocationHelper; import org.eclipse.osgi.internal.messages.Msg; import org.eclipse.osgi.launch.Equinox; import org.eclipse.osgi.report.resolution.ResolutionReport; import org.eclipse.osgi.service.datalocation.Location; import org.eclipse.osgi.service.environment.EnvironmentInfo; import org.eclipse.osgi.service.runnable.ApplicationLauncher; import org.eclipse.osgi.service.runnable.StartupMonitor; import org.eclipse.osgi.storage.url.reference.Handler; import org.eclipse.osgi.util.ManifestElement; import org.eclipse.osgi.util.NLS; import org.osgi.framework.*; import org.osgi.framework.launch.Framework; import org.osgi.framework.startlevel.BundleStartLevel; import org.osgi.framework.startlevel.FrameworkStartLevel; import org.osgi.framework.wiring.FrameworkWiring; import org.osgi.resource.Resource; import org.osgi.util.tracker.ServiceTracker;
Special startup class for the Eclipse Platform. This class cannot be instantiated; all functionality is provided by static methods.

The Eclipse Platform makes heavy use of Java class loaders for loading plug-ins. Even the Eclipse Runtime itself and the OSGi framework need to be loaded by special class loaders. The upshot is that a client program (such as a Java main program, a servlet) cannot reference any part of Eclipse directly. Instead, a client must use this loader class to start the platform, invoking functionality defined in plug-ins, and shutting down the platform when done.

Note that the fields on this class are not API.

Since:3.0
@noextendThis class is not intended to be subclassed by clients.
/** * Special startup class for the Eclipse Platform. This class cannot be * instantiated; all functionality is provided by static methods. * <p> * The Eclipse Platform makes heavy use of Java class loaders for loading * plug-ins. Even the Eclipse Runtime itself and the OSGi framework need * to be loaded by special class loaders. The upshot is that a * client program (such as a Java main program, a servlet) cannot * reference any part of Eclipse directly. Instead, a client must use this * loader class to start the platform, invoking functionality defined * in plug-ins, and shutting down the platform when done. * </p> * <p>Note that the fields on this class are not API. </p> * @since 3.0 * @noextend This class is not intended to be subclassed by clients. */
public class EclipseStarter { private static BundleContext context; private static boolean initialize = false; public static boolean debug = false; private static boolean running = false; private static ServiceRegistration<?> defaultMonitorRegistration = null; private static ServiceRegistration<?> appLauncherRegistration = null; private static ServiceRegistration<?> splashStreamRegistration = null; // command line arguments private static final String CLEAN = "-clean"; //$NON-NLS-1$ private static final String CONSOLE = "-console"; //$NON-NLS-1$ private static final String CONSOLE_LOG = "-consoleLog"; //$NON-NLS-1$ private static final String DEBUG = "-debug"; //$NON-NLS-1$ private static final String INITIALIZE = "-initialize"; //$NON-NLS-1$ private static final String DEV = "-dev"; //$NON-NLS-1$ private static final String WS = "-ws"; //$NON-NLS-1$ private static final String OS = "-os"; //$NON-NLS-1$ private static final String ARCH = "-arch"; //$NON-NLS-1$ private static final String NL = "-nl"; //$NON-NLS-1$ private static final String NL_EXTENSIONS = "-nlExtensions"; //$NON-NLS-1$ private static final String CONFIGURATION = "-configuration"; //$NON-NLS-1$ private static final String USER = "-user"; //$NON-NLS-1$ private static final String NOEXIT = "-noExit"; //$NON-NLS-1$ private static final String LAUNCHER = "-launcher"; //$NON-NLS-1$ // this is more of an Eclipse argument but this OSGi implementation stores its // metadata alongside Eclipse's. private static final String DATA = "-data"; //$NON-NLS-1$ // System properties public static final String PROP_BUNDLES = "osgi.bundles"; //$NON-NLS-1$ public static final String PROP_BUNDLES_STARTLEVEL = "osgi.bundles.defaultStartLevel"; //$NON-NLS-1$ //The start level used to install the bundles public static final String PROP_EXTENSIONS = "osgi.framework.extensions"; //$NON-NLS-1$ public static final String PROP_INITIAL_STARTLEVEL = "osgi.startLevel"; //$NON-NLS-1$ //The start level when the fwl start public static final String PROP_DEBUG = "osgi.debug"; //$NON-NLS-1$ public static final String PROP_DEV = "osgi.dev"; //$NON-NLS-1$ public static final String PROP_CLEAN = "osgi.clean"; //$NON-NLS-1$ public static final String PROP_CONSOLE = "osgi.console"; //$NON-NLS-1$ public static final String PROP_CONSOLE_CLASS = "osgi.consoleClass"; //$NON-NLS-1$ public static final String PROP_CHECK_CONFIG = "osgi.checkConfiguration"; //$NON-NLS-1$ public static final String PROP_OS = "osgi.os"; //$NON-NLS-1$ public static final String PROP_WS = "osgi.ws"; //$NON-NLS-1$ public static final String PROP_NL = "osgi.nl"; //$NON-NLS-1$ private static final String PROP_NL_EXTENSIONS = "osgi.nl.extensions"; //$NON-NLS-1$ public static final String PROP_ARCH = "osgi.arch"; //$NON-NLS-1$ public static final String PROP_ADAPTOR = "osgi.adaptor"; //$NON-NLS-1$ public static final String PROP_SYSPATH = "osgi.syspath"; //$NON-NLS-1$ public static final String PROP_LOGFILE = "osgi.logfile"; //$NON-NLS-1$ public static final String PROP_FRAMEWORK = "osgi.framework"; //$NON-NLS-1$ public static final String PROP_INSTALL_AREA = "osgi.install.area"; //$NON-NLS-1$ public static final String PROP_FRAMEWORK_SHAPE = "osgi.framework.shape"; //$NON-NLS-1$ //the shape of the fwk (jar, or folder) public static final String PROP_NOSHUTDOWN = "osgi.noShutdown"; //$NON-NLS-1$ public static final String PROP_EXITCODE = "eclipse.exitcode"; //$NON-NLS-1$ public static final String PROP_EXITDATA = "eclipse.exitdata"; //$NON-NLS-1$ public static final String PROP_CONSOLE_LOG = "eclipse.consoleLog"; //$NON-NLS-1$ public static final String PROP_IGNOREAPP = "eclipse.ignoreApp"; //$NON-NLS-1$ public static final String PROP_REFRESH_BUNDLES = "eclipse.refreshBundles"; //$NON-NLS-1$ private static final String PROP_ALLOW_APPRELAUNCH = "eclipse.allowAppRelaunch"; //$NON-NLS-1$ private static final String PROP_APPLICATION_LAUNCHDEFAULT = "eclipse.application.launchDefault"; //$NON-NLS-1$ private static final String FILE_SCHEME = "file:"; //$NON-NLS-1$ private static final String REFERENCE_SCHEME = "reference:"; //$NON-NLS-1$ private static final String REFERENCE_PROTOCOL = "reference"; //$NON-NLS-1$ private static final String INITIAL_LOCATION = "initial@"; //$NON-NLS-1$ private static final int DEFAULT_INITIAL_STARTLEVEL = 6; // default value for legacy purposes private static final String DEFAULT_BUNDLES_STARTLEVEL = "4"; //$NON-NLS-1$ private static FrameworkLog log; // directory of serch candidates keyed by directory abs path -> directory listing (bug 122024) private static Map<String, String[]> searchCandidates = new HashMap<>(4); private static EclipseAppLauncher appLauncher; private static List<Runnable> shutdownHandlers; private static ConsoleManager consoleMgr = null; private static Map<String, String> configuration = null; private static Framework framework = null; private static EquinoxConfiguration equinoxConfig; private static String[] allArgs = null; private static String[] frameworkArgs = null; private static String[] appArgs = null; private synchronized static String getProperty(String key) { if (equinoxConfig != null) { return equinoxConfig.getConfiguration(key); } return getConfiguration().get(key); } private synchronized static String getProperty(String key, String dft) { if (equinoxConfig != null) { return equinoxConfig.getConfiguration(key, dft); } String result = getConfiguration().get(key); return result == null ? dft : result; } private synchronized static Object setProperty(String key, String value) { if (equinoxConfig != null) { return equinoxConfig.setProperty(key, value); } if ("true".equals(getConfiguration().get(EquinoxConfiguration.PROP_USE_SYSTEM_PROPERTIES))) { //$NON-NLS-1$ System.setProperty(key, value); } return getConfiguration().put(key, value); } private synchronized static Object clearProperty(String key) { if (equinoxConfig != null) { return equinoxConfig.clearConfiguration(key); } return getConfiguration().remove(key); } private synchronized static Map<String, String> getConfiguration() { if (configuration == null) { configuration = new HashMap<>(); // TODO hack to set these to defaults for EclipseStarter // Note that this hack does not allow this property to be specified in config.ini configuration.put(EquinoxConfiguration.PROP_USE_SYSTEM_PROPERTIES, System.getProperty(EquinoxConfiguration.PROP_USE_SYSTEM_PROPERTIES, "true")); //$NON-NLS-1$ // we handle this compatibility setting special for EclipseStarter String systemCompatibilityBoot = System.getProperty(EquinoxConfiguration.PROP_COMPATIBILITY_BOOTDELEGATION); if (systemCompatibilityBoot != null) { // The system properties have a specific setting; use it configuration.put(EquinoxConfiguration.PROP_COMPATIBILITY_BOOTDELEGATION, systemCompatibilityBoot); } else { // set a default value; but this value can be overriden by the config.ini configuration.put(EquinoxConfiguration.PROP_COMPATIBILITY_BOOTDELEGATION + EquinoxConfiguration.PROP_DEFAULT_SUFFIX, "true"); //$NON-NLS-1$ } String dsDelayedKeepInstances = System.getProperty(EquinoxConfiguration.PROP_DS_DELAYED_KEEPINSTANCES); if (dsDelayedKeepInstances != null) { // The system properties have a specific setting; use it configuration.put(EquinoxConfiguration.PROP_DS_DELAYED_KEEPINSTANCES, dsDelayedKeepInstances); } else { // set a default value; but this value can be overriden by the config.ini configuration.put(EquinoxConfiguration.PROP_DS_DELAYED_KEEPINSTANCES + EquinoxConfiguration.PROP_DEFAULT_SUFFIX, "true"); //$NON-NLS-1$ } } return configuration; }
This is the main to start osgi. It only works when the framework is being jared as a single jar
/** * This is the main to start osgi. * It only works when the framework is being jared as a single jar */
public static void main(String[] args) throws Exception { if (getProperty("eclipse.startTime") == null) //$NON-NLS-1$ setProperty("eclipse.startTime", Long.toString(System.currentTimeMillis())); //$NON-NLS-1$ if (getProperty(PROP_NOSHUTDOWN) == null) setProperty(PROP_NOSHUTDOWN, "true"); //$NON-NLS-1$ // set the compatibility boot delegation flag to false to get "standard" OSGi behavior WRT boot delegation (bug 178477) if (getProperty(EquinoxConfiguration.PROP_COMPATIBILITY_BOOTDELEGATION) == null) setProperty(EquinoxConfiguration.PROP_COMPATIBILITY_BOOTDELEGATION, "false"); //$NON-NLS-1$ Object result = run(args, null); if (result instanceof Integer && !Boolean.valueOf(getProperty(PROP_NOSHUTDOWN)).booleanValue()) System.exit(((Integer) result).intValue()); }
Launches the platform and runs a single application. The application is either identified in the given arguments (e.g., -application <app id>) or in the eclipse.application System property. This convenience method starts up the platform, runs the indicated application, and then shuts down the platform. The platform must not be running already.
Params:
  • args – the command line-style arguments used to configure the platform
  • endSplashHandler – the block of code to run to tear down the splash screen or null if no tear down is required
Throws:
Returns:the result of running the application
/** * Launches the platform and runs a single application. The application is either identified * in the given arguments (e.g., -application &lt;app id&gt;) or in the <code>eclipse.application</code> * System property. This convenience method starts * up the platform, runs the indicated application, and then shuts down the * platform. The platform must not be running already. * * @param args the command line-style arguments used to configure the platform * @param endSplashHandler the block of code to run to tear down the splash * screen or <code>null</code> if no tear down is required * @return the result of running the application * @throws Exception if anything goes wrong */
public static Object run(String[] args, Runnable endSplashHandler) throws Exception { if (running) throw new IllegalStateException(Msg.ECLIPSE_STARTUP_ALREADY_RUNNING); boolean startupFailed = true; try { startup(args, endSplashHandler); startupFailed = false; if (Boolean.valueOf(getProperty(PROP_IGNOREAPP)).booleanValue() || isForcedRestart()) return null; return run(null); } catch (Throwable e) { // ensure the splash screen is down if (endSplashHandler != null) endSplashHandler.run(); // may use startupFailed to understand where the error happened FrameworkLogEntry logEntry = new FrameworkLogEntry(EquinoxContainer.NAME, FrameworkLogEntry.ERROR, 0, startupFailed ? Msg.ECLIPSE_STARTUP_STARTUP_ERROR : Msg.ECLIPSE_STARTUP_APP_ERROR, 1, e, null); if (log != null) log.log(logEntry); else // TODO desperate measure - ideally, we should write this to disk (a la Main.log) e.printStackTrace(); } finally { try { // The application typically sets the exit code however the framework can request that // it be re-started. We need to check for this and potentially override the exit code. if (isForcedRestart()) setProperty(PROP_EXITCODE, "23"); //$NON-NLS-1$ if (!Boolean.valueOf(getProperty(PROP_NOSHUTDOWN)).booleanValue()) shutdown(); } catch (Throwable e) { FrameworkLogEntry logEntry = new FrameworkLogEntry(EquinoxContainer.NAME, FrameworkLogEntry.ERROR, 0, Msg.ECLIPSE_STARTUP_SHUTDOWN_ERROR, 1, e, null); if (log != null) log.log(logEntry); else // TODO desperate measure - ideally, we should write this to disk (a la Main.log) e.printStackTrace(); } } // we only get here if an error happened if (getProperty(PROP_EXITCODE) == null) { setProperty(PROP_EXITCODE, "13"); //$NON-NLS-1$ setProperty(PROP_EXITDATA, NLS.bind(Msg.ECLIPSE_STARTUP_ERROR_CHECK_LOG, log == null ? null : log.getFile().getPath())); } return null; }
Returns true if the platform is already running, false otherwise.
Returns:whether or not the platform is already running
/** * Returns true if the platform is already running, false otherwise. * @return whether or not the platform is already running */
public static boolean isRunning() { return running; }
Starts the platform and sets it up to run a single application. The application is either identified in the given arguments (e.g., -application <app id>) or in the eclipse.application System property. The platform must not be running already.

The given runnable (if not null) is used to tear down the splash screen if required.

Params:
  • args – the arguments passed to the application
Throws:
Returns:BundleContext the context of the system bundle
/** * Starts the platform and sets it up to run a single application. The application is either identified * in the given arguments (e.g., -application &lt;app id&gt;) or in the <code>eclipse.application</code> * System property. The platform must not be running already. * <p> * The given runnable (if not <code>null</code>) is used to tear down the splash screen if required. * </p> * @param args the arguments passed to the application * @return BundleContext the context of the system bundle * @throws Exception if anything goes wrong */
public static BundleContext startup(String[] args, Runnable endSplashHandler) throws Exception { if (running) throw new IllegalStateException(Msg.ECLIPSE_STARTUP_ALREADY_RUNNING); processCommandLine(args); framework = new Equinox(getConfiguration()); framework.init(); context = framework.getBundleContext(); ServiceReference<FrameworkLog> logRef = context.getServiceReference(FrameworkLog.class); log = context.getService(logRef); ServiceReference<EnvironmentInfo> configRef = context.getServiceReference(EnvironmentInfo.class); equinoxConfig = (EquinoxConfiguration) context.getService(configRef); equinoxConfig.setAllArgs(allArgs); equinoxConfig.setFrameworkArgs(frameworkArgs); equinoxConfig.setAppArgs(appArgs); registerFrameworkShutdownHandlers(); publishSplashScreen(endSplashHandler); consoleMgr = ConsoleManager.startConsole(context, equinoxConfig); Bundle[] startBundles = loadBasicBundles(); if (startBundles == null || ("true".equals(getProperty(PROP_REFRESH_BUNDLES)) && refreshPackages(getCurrentBundles(false)))) { //$NON-NLS-1$ waitForShutdown(); return context; // cannot continue; loadBasicBundles caused refreshPackages to shutdown the framework } framework.start(); if (isForcedRestart()) { return context; } // set the framework start level to the ultimate value. This will actually start things // running if they are persistently active. setStartLevel(getStartLevel()); // they should all be active by this time ensureBundlesActive(startBundles); // in the case where the built-in console is disabled we should try to start the console bundle try { consoleMgr.checkForConsoleBundle(); } catch (BundleException e) { FrameworkLogEntry entry = new FrameworkLogEntry(EquinoxContainer.NAME, FrameworkLogEntry.ERROR, 0, e.getMessage(), 0, e, null); log.log(entry); } // TODO should log unresolved bundles if in debug or dev mode running = true; return context; } private static int getStartLevel() { String level = getProperty(PROP_INITIAL_STARTLEVEL); if (level != null) try { return Integer.parseInt(level); } catch (NumberFormatException e) { if (debug) Debug.println("Start level = " + level + " parsed. Using hardcoded default: 6"); //$NON-NLS-1$ //$NON-NLS-2$ } return DEFAULT_INITIAL_STARTLEVEL; }
Runs the application for which the platform was started. The platform must be running.

The given argument is passed to the application being run. If it is null then the command line arguments used in starting the platform, and not consumed by the platform code, are passed to the application as a String[].

Params:
  • argument – the argument passed to the application. May be null
Throws:
Returns:the result of running the application
/** * Runs the application for which the platform was started. The platform * must be running. * <p> * The given argument is passed to the application being run. If it is <code>null</code> * then the command line arguments used in starting the platform, and not consumed * by the platform code, are passed to the application as a <code>String[]</code>. * </p> * @param argument the argument passed to the application. May be <code>null</code> * @return the result of running the application * @throws Exception if anything goes wrong */
public static Object run(Object argument) throws Exception { if (!running) throw new IllegalStateException(Msg.ECLIPSE_STARTUP_NOT_RUNNING); // if we are just initializing, do not run the application just return. if (initialize) return Integer.valueOf(0); try { if (appLauncher == null) { boolean launchDefault = Boolean.parseBoolean(getProperty(PROP_APPLICATION_LAUNCHDEFAULT, "true")); //$NON-NLS-1$ // create the ApplicationLauncher and register it as a service appLauncher = new EclipseAppLauncher(context, Boolean.parseBoolean(getProperty(PROP_ALLOW_APPRELAUNCH)), launchDefault, log, equinoxConfig); appLauncherRegistration = context.registerService(ApplicationLauncher.class.getName(), appLauncher, null); // must start the launcher AFTER service restration because this method // blocks and runs the application on the current thread. This method // will return only after the application has stopped. return appLauncher.start(argument); } return appLauncher.reStart(argument); } catch (Exception e) { if (log != null && context != null) { // context can be null if OSGi failed to launch (bug 151413) ResolutionReport report = context.getBundle().adapt(Module.class).getContainer().resolve(null, false); for (Resource unresolved : report.getEntries().keySet()) { String bsn = ((ModuleRevision) unresolved).getSymbolicName(); FrameworkLogEntry logEntry = new FrameworkLogEntry(bsn != null ? bsn : EquinoxContainer.NAME, FrameworkLogEntry.WARNING, 0, Msg.Module_ResolveError + report.getResolutionReportMessage(unresolved), 1, null, null); log.log(logEntry); } } throw e; } }
Shuts down the Platform. The state of the Platform is not automatically saved before shutting down.

On return, the Platform will no longer be running (but could be re-launched with another call to startup). If relaunching, care must be taken to reinitialize any System properties which the platform uses (e.g., osgi.instance.area) as some policies in the platform do not allow resetting of such properties on subsequent runs.

Any objects handed out by running Platform, including Platform runnables obtained via getRunnable, will be permanently invalid. The effects of attempting to invoke methods on invalid objects is undefined.

Throws:
  • Exception – if anything goes wrong
/** * Shuts down the Platform. The state of the Platform is not automatically * saved before shutting down. * <p> * On return, the Platform will no longer be running (but could be re-launched * with another call to startup). If relaunching, care must be taken to reinitialize * any System properties which the platform uses (e.g., osgi.instance.area) as * some policies in the platform do not allow resetting of such properties on * subsequent runs. * </p><p> * Any objects handed out by running Platform, * including Platform runnables obtained via getRunnable, will be * permanently invalid. The effects of attempting to invoke methods * on invalid objects is undefined. * </p> * @throws Exception if anything goes wrong */
public static void shutdown() throws Exception { if (!running || framework == null) return; if (framework.getState() == Bundle.ACTIVE) { if (appLauncherRegistration != null) appLauncherRegistration.unregister(); if (splashStreamRegistration != null) splashStreamRegistration.unregister(); if (defaultMonitorRegistration != null) defaultMonitorRegistration.unregister(); } if (appLauncher != null) appLauncher.shutdown(); appLauncherRegistration = null; appLauncher = null; splashStreamRegistration = null; defaultMonitorRegistration = null; if (consoleMgr != null) { consoleMgr.stopConsole(); consoleMgr = null; } if (framework.getState() == Bundle.ACTIVE) { framework.stop(); framework.waitForStop(0); framework = null; } configuration = null; equinoxConfig = null; context = null; running = false; } private static void ensureBundlesActive(Bundle[] bundles) { for (Bundle bundle : bundles) { if (bundle.getState() != Bundle.ACTIVE) { if (bundle.getState() == Bundle.INSTALLED) { // Log that the bundle is not resolved log.log(new FrameworkLogEntry(EquinoxContainer.NAME, FrameworkLogEntry.ERROR, 0, NLS.bind(Msg.ECLIPSE_STARTUP_ERROR_BUNDLE_NOT_RESOLVED, bundle.getLocation()), 0, null, null)); continue; } // check that the startlevel allows the bundle to be active (111550) FrameworkStartLevel fwStartLevel = context.getBundle().adapt(FrameworkStartLevel.class); BundleStartLevel bundleStartLevel = bundle.adapt(BundleStartLevel.class); if (fwStartLevel != null && (bundleStartLevel.getStartLevel() <= fwStartLevel.getStartLevel())) { log.log(new FrameworkLogEntry(EquinoxContainer.NAME, FrameworkLogEntry.ERROR, 0, NLS.bind(Msg.ECLIPSE_STARTUP_ERROR_BUNDLE_NOT_ACTIVE, bundle), 0, null, null)); } } } } private static void publishSplashScreen(final Runnable endSplashHandler) { if (endSplashHandler == null) return; // register the output stream to the launcher if it exists try { Method method = endSplashHandler.getClass().getMethod("getOutputStream", new Class[0]); //$NON-NLS-1$ Object outputStream = method.invoke(endSplashHandler, new Object[0]); if (outputStream instanceof OutputStream) { Dictionary<String, Object> osProperties = new Hashtable<>(); osProperties.put("name", "splashstream"); //$NON-NLS-1$//$NON-NLS-2$ splashStreamRegistration = context.registerService(OutputStream.class.getName(), outputStream, osProperties); } } catch (Exception ex) { // ignore } // keep this splash handler as the default startup monitor try { Dictionary<String, Object> monitorProps = new Hashtable<>(); monitorProps.put(Constants.SERVICE_RANKING, Integer.valueOf(Integer.MIN_VALUE)); defaultMonitorRegistration = context.registerService(StartupMonitor.class.getName(), new DefaultStartupMonitor(endSplashHandler, equinoxConfig), monitorProps); } catch (IllegalStateException e) { //splash handler did not provide the necessary methods, ignore it } } @SuppressWarnings("deprecation") private static URL searchForBundle(String name, String parent) throws MalformedURLException { URL url = null; File fileLocation = null; boolean reference = false; try { createURL(name); // quick check to see if the name is a valid URL url = createURL(new File(parent).toURL(), name); } catch (MalformedURLException e) { // TODO this is legacy support for non-URL names. It should be removed eventually. // if name was not a URL then construct one. // Assume it should be a reference and that it is relative. This support need not // be robust as it is temporary.. File child = new File(name); fileLocation = child.isAbsolute() ? child : new File(parent, name); url = createURL(REFERENCE_PROTOCOL, null, fileLocation.toURL().toExternalForm()); reference = true; } // if the name was a URL then see if it is relative. If so, insert syspath. if (!reference) { URL baseURL = url; // if it is a reference URL then strip off the reference: and set base to the file:... if (url.getProtocol().equals(REFERENCE_PROTOCOL)) { reference = true; String baseSpec = url.getPath(); if (baseSpec.startsWith(FILE_SCHEME)) { File child = new File(baseSpec.substring(5)); baseURL = child.isAbsolute() ? child.toURL() : new File(parent, child.getPath()).toURL(); } else baseURL = createURL(baseSpec); } fileLocation = new File(baseURL.getPath()); // if the location is relative, prefix it with the parent if (!fileLocation.isAbsolute()) fileLocation = new File(parent, fileLocation.toString()); } // If the result is a reference then search for the real result and // reconstruct the answer. if (reference) { String result = searchFor(fileLocation.getName(), new File(fileLocation.getParent()).getAbsolutePath()); if (result != null) url = createURL(REFERENCE_PROTOCOL, null, FILE_SCHEME + result); else return null; } // finally we have something worth trying try { URLConnection result = LocationHelper.getConnection(url); result.connect(); return url; } catch (IOException e) { // int i = location.lastIndexOf('_'); // return i == -1? location : location.substring(0, i); return null; } } /* * Ensure all basic bundles are installed, resolved and scheduled to start. Returns an array containing * all basic bundles that are marked to start. * Returns null if the framework has been shutdown as a result of refreshPackages */ private static Bundle[] loadBasicBundles() throws InterruptedException { long startTime = System.currentTimeMillis(); String osgiBundles = getProperty(PROP_BUNDLES); String osgiExtensions = getProperty(PROP_EXTENSIONS); if (osgiExtensions != null && osgiExtensions.length() > 0) { osgiBundles = osgiExtensions + ',' + osgiBundles; setProperty(PROP_BUNDLES, osgiBundles); } String[] installEntries = getArrayFromList(osgiBundles, ","); //$NON-NLS-1$ // get the initial bundle list from the installEntries InitialBundle[] initialBundles = getInitialBundles(installEntries); // get the list of currently installed initial bundles from the framework Bundle[] curInitBundles = getCurrentBundles(true); // list of bundles to be refreshed List<Bundle> toRefresh = new ArrayList<>(curInitBundles.length); // uninstall any of the currently installed bundles that do not exist in the // initial bundle list from installEntries. uninstallBundles(curInitBundles, initialBundles, toRefresh); // install the initialBundles that are not already installed. List<Bundle> startBundles = new ArrayList<>(installEntries.length); List<Bundle> lazyActivationBundles = new ArrayList<>(installEntries.length); installBundles(initialBundles, curInitBundles, startBundles, lazyActivationBundles, toRefresh); // If we installed/uninstalled something, force a refresh of all installed/uninstalled bundles if (!toRefresh.isEmpty() && refreshPackages(toRefresh.toArray(new Bundle[toRefresh.size()]))) return null; // cannot continue; refreshPackages shutdown the framework // schedule all basic bundles to be started Bundle[] startInitBundles = startBundles.toArray(new Bundle[startBundles.size()]); Bundle[] lazyInitBundles = lazyActivationBundles.toArray(new Bundle[lazyActivationBundles.size()]); startBundles(startInitBundles, lazyInitBundles); if (debug) Debug.println("Time to load bundles: " + (System.currentTimeMillis() - startTime)); //$NON-NLS-1$ return startInitBundles; } private static InitialBundle[] getInitialBundles(String[] installEntries) { searchCandidates.clear(); List<InitialBundle> result = new ArrayList<>(installEntries.length); int defaultStartLevel = Integer.parseInt(getProperty(PROP_BUNDLES_STARTLEVEL, DEFAULT_BUNDLES_STARTLEVEL)); String syspath = getSysPath(); // should canonicalize the syspath. try { syspath = new File(syspath).getCanonicalPath(); } catch (IOException ioe) { // do nothing } Collection<ServiceReference<Location>> installLocRef; try { installLocRef = context.getServiceReferences(Location.class, Location.INSTALL_FILTER); } catch (InvalidSyntaxException e) { throw new RuntimeException(e); } Location installLocation = installLocRef == null ? null : context.getService(installLocRef.iterator().next()); if (installLocation == null) { throw new IllegalStateException(Msg.EclipseStarter_InstallLocation); } for (String name : installEntries) { int level = defaultStartLevel; boolean start = false; int index = name.lastIndexOf('@'); if (index >= 0) { String[] attributes = getArrayFromList(name.substring(index + 1, name.length()), ":"); //$NON-NLS-1$ for (String attribute : attributes) { if (attribute.equals("start")) //$NON-NLS-1$ start = true; else { try { level = Integer.parseInt(attribute); } catch (NumberFormatException e) { // bug 188089 index = name.length(); continue; } } } name = name.substring(0, index); } try { URL location = searchForBundle(name, syspath); if (location == null) { FrameworkLogEntry entry = new FrameworkLogEntry(EquinoxContainer.NAME, FrameworkLogEntry.ERROR, 0, NLS.bind(Msg.ECLIPSE_STARTUP_BUNDLE_NOT_FOUND, name), 0, null, null); log.log(entry); // skip this entry continue; } location = makeRelative(installLocation.getURL(), location); String locationString = INITIAL_LOCATION + location.toExternalForm(); result.add(new InitialBundle(locationString, location, level, start)); }catch (IOException e) { log.log(new FrameworkLogEntry(EquinoxContainer.NAME, FrameworkLogEntry.ERROR, 0, e.getMessage(), 0, e, null)); } } return result.toArray(new InitialBundle[result.size()]); } // returns true if the refreshPackages operation caused the framework to shutdown private static boolean refreshPackages(Bundle[] bundles) throws InterruptedException { FrameworkWiring frameworkWiring = context.getBundle().adapt(FrameworkWiring.class); if (frameworkWiring == null) return false; Semaphore semaphore = new Semaphore(0); StartupEventListener listener = new StartupEventListener(semaphore, FrameworkEvent.PACKAGES_REFRESHED); context.addBundleListener(listener); frameworkWiring.refreshBundles(Arrays.asList(bundles), listener); updateSplash(semaphore, listener); return isForcedRestart(); } private static void waitForShutdown() { // wait for the system bundle to stop try { framework.waitForStop(0); } catch (InterruptedException e) { Thread.interrupted(); throw new RuntimeException(e); } } private static void processCommandLine(String[] args) throws Exception { allArgs = args; if (args.length == 0) { frameworkArgs = args; return; } int[] configArgs = new int[args.length]; configArgs[0] = -1; // need to initialize the first element to something that could not be an index. int configArgIndex = 0; for (int i = 0; i < args.length; i++) { boolean found = false; // check for args without parameters (i.e., a flag arg) // check if debug should be enabled for the entire platform // If this is the last arg or there is a following arg (i.e., arg+1 has a leading -), // simply enable debug. Otherwise, assume that that the following arg is // actually the filename of an options file. This will be processed below. if (args[i].equalsIgnoreCase(DEBUG) && ((i + 1 == args.length) || ((i + 1 < args.length) && (args[i + 1].startsWith("-"))))) { //$NON-NLS-1$ setProperty(PROP_DEBUG, ""); //$NON-NLS-1$ debug = true; found = true; } // check if development mode should be enabled for the entire platform // If this is the last arg or there is a following arg (i.e., arg+1 has a leading -), // simply enable development mode. Otherwise, assume that that the following arg is // actually some additional development time class path entries. This will be processed below. if (args[i].equalsIgnoreCase(DEV) && ((i + 1 == args.length) || ((i + 1 < args.length) && (args[i + 1].startsWith("-"))))) { //$NON-NLS-1$ setProperty(PROP_DEV, ""); //$NON-NLS-1$ found = true; } // look for the initialization arg if (args[i].equalsIgnoreCase(INITIALIZE)) { initialize = true; found = true; } // look for the clean flag. if (args[i].equalsIgnoreCase(CLEAN)) { setProperty(PROP_CLEAN, "true"); //$NON-NLS-1$ found = true; } // look for the consoleLog flag if (args[i].equalsIgnoreCase(CONSOLE_LOG)) { setProperty(PROP_CONSOLE_LOG, "true"); //$NON-NLS-1$ found = true; } // look for the console with no port. if (args[i].equalsIgnoreCase(CONSOLE) && ((i + 1 == args.length) || ((i + 1 < args.length) && (args[i + 1].startsWith("-"))))) { //$NON-NLS-1$ setProperty(PROP_CONSOLE, ""); //$NON-NLS-1$ found = true; } if (args[i].equalsIgnoreCase(NOEXIT)) { setProperty(PROP_NOSHUTDOWN, "true"); //$NON-NLS-1$ found = true; } if (found) { configArgs[configArgIndex++] = i; continue; } // check for args with parameters. If we are at the last argument or if the next one // has a '-' as the first character, then we can't have an arg with a parm so continue. if (i == args.length - 1 || args[i + 1].startsWith("-")) { //$NON-NLS-1$ continue; } String arg = args[++i]; // look for the console and port. if (args[i - 1].equalsIgnoreCase(CONSOLE)) { setProperty(PROP_CONSOLE, arg); found = true; } // look for the configuration location . if (args[i - 1].equalsIgnoreCase(CONFIGURATION)) { setProperty(EquinoxLocations.PROP_CONFIG_AREA, arg); found = true; } // look for the data location for this instance. if (args[i - 1].equalsIgnoreCase(DATA)) { setProperty(EquinoxLocations.PROP_INSTANCE_AREA, arg); found = true; } // look for the user location for this instance. if (args[i - 1].equalsIgnoreCase(USER)) { setProperty(EquinoxLocations.PROP_USER_AREA, arg); found = true; } // look for the launcher location if (args[i - 1].equalsIgnoreCase(LAUNCHER)) { setProperty(EquinoxLocations.PROP_LAUNCHER, arg); found = true; } // look for the development mode and class path entries. if (args[i - 1].equalsIgnoreCase(DEV)) { setProperty(PROP_DEV, arg); found = true; } // look for the debug mode and option file location. if (args[i - 1].equalsIgnoreCase(DEBUG)) { setProperty(PROP_DEBUG, arg); debug = true; found = true; } // look for the window system. if (args[i - 1].equalsIgnoreCase(WS)) { setProperty(PROP_WS, arg); found = true; } // look for the operating system if (args[i - 1].equalsIgnoreCase(OS)) { setProperty(PROP_OS, arg); found = true; } // look for the system architecture if (args[i - 1].equalsIgnoreCase(ARCH)) { setProperty(PROP_ARCH, arg); found = true; } // look for the nationality/language if (args[i - 1].equalsIgnoreCase(NL)) { setProperty(PROP_NL, arg); found = true; } // look for the locale extensions if (args[i - 1].equalsIgnoreCase(NL_EXTENSIONS)) { setProperty(PROP_NL_EXTENSIONS, arg); found = true; } // done checking for args. Remember where an arg was found if (found) { configArgs[configArgIndex++] = i - 1; configArgs[configArgIndex++] = i; } } // remove all the arguments consumed by this argument parsing if (configArgIndex == 0) { frameworkArgs = new String[0]; appArgs = args; return; } appArgs = new String[args.length - configArgIndex]; frameworkArgs = new String[configArgIndex]; configArgIndex = 0; int j = 0; int k = 0; for (int i = 0; i < args.length; i++) { if (i == configArgs[configArgIndex]) { frameworkArgs[k++] = args[i]; configArgIndex++; } else appArgs[j++] = args[i]; } return; }
Returns the result of converting a list of comma-separated tokens into an array
Params:
  • prop – the initial comma-separated string
Returns:the array of string tokens
/** * Returns the result of converting a list of comma-separated tokens into an array * * @return the array of string tokens * @param prop the initial comma-separated string */
private static String[] getArrayFromList(String prop, String separator) { return ManifestElement.getArrayFromList(prop, separator); } protected static String getSysPath() { String result = getProperty(PROP_SYSPATH); if (result != null) return result; result = getSysPathFromURL(getProperty(PROP_FRAMEWORK)); if (result == null) result = getSysPathFromCodeSource(); if (result == null) throw new IllegalStateException("Can not find the system path."); //$NON-NLS-1$ if (Character.isUpperCase(result.charAt(0))) { char[] chars = result.toCharArray(); chars[0] = Character.toLowerCase(chars[0]); result = new String(chars); } setProperty(PROP_SYSPATH, result); return result; } private static String getSysPathFromURL(String urlSpec) { if (urlSpec == null) return null; URL url = LocationHelper.buildURL(urlSpec, false); if (url == null) return null; File fwkFile = LocationHelper.decodePath(new File(url.getPath())); fwkFile = new File(fwkFile.getAbsolutePath()); fwkFile = new File(fwkFile.getParent()); return fwkFile.getAbsolutePath(); } private static String getSysPathFromCodeSource() { ProtectionDomain pd = EclipseStarter.class.getProtectionDomain(); if (pd == null) return null; CodeSource cs = pd.getCodeSource(); if (cs == null) return null; URL url = cs.getLocation(); if (url == null) return null; String result = url.getPath(); if (File.separatorChar == '\\') { // in case on windows the \ is used result = result.replace('\\', '/'); } if (result.endsWith(".jar")) { //$NON-NLS-1$ result = result.substring(0, result.lastIndexOf('/')); if ("folder".equals(getProperty(PROP_FRAMEWORK_SHAPE))) //$NON-NLS-1$ result = result.substring(0, result.lastIndexOf('/')); } else { if (result.endsWith("/")) //$NON-NLS-1$ result = result.substring(0, result.length() - 1); result = result.substring(0, result.lastIndexOf('/')); result = result.substring(0, result.lastIndexOf('/')); } return result; } private static Bundle[] getCurrentBundles(boolean includeInitial) { Bundle[] installed = context.getBundles(); List<Bundle> initial = new ArrayList<>(); for (Bundle bundle : installed) { if (bundle.getLocation().startsWith(INITIAL_LOCATION)) { if (includeInitial) initial.add(bundle); } else if (!includeInitial && bundle.getBundleId() != 0) initial.add(bundle); } return initial.toArray(new Bundle[initial.size()]); } private static Bundle getBundleByLocation(String location, Bundle[] bundles) { for (Bundle bundle : bundles) { if (location.equalsIgnoreCase(bundle.getLocation())) return bundle; } return null; } private static void uninstallBundles(Bundle[] curInitBundles, InitialBundle[] newInitBundles, List<Bundle> toRefresh) { for (Bundle curInitBundle : curInitBundles) { boolean found = false; for (InitialBundle newInitBundle : newInitBundles) { if (curInitBundle.getLocation().equalsIgnoreCase(newInitBundle.locationString)) { found = true; break; } } if (!found) { try { curInitBundle.uninstall(); toRefresh.add(curInitBundle); } catch (BundleException e) { FrameworkLogEntry entry = new FrameworkLogEntry(EquinoxContainer.NAME, FrameworkLogEntry.ERROR, 0, NLS.bind(Msg.ECLIPSE_STARTUP_FAILED_UNINSTALL, curInitBundle.getLocation()), 0, e, null); log.log(entry); } } } } private static void installBundles(InitialBundle[] initialBundles, Bundle[] curInitBundles, List<Bundle> startBundles, List<Bundle> lazyActivationBundles, List<Bundle> toRefresh) { for (InitialBundle initialBundle : initialBundles) { Bundle osgiBundle = getBundleByLocation(initialBundle.locationString, curInitBundles); try { // don't need to install if it is already installed if (osgiBundle == null) { InputStream in = LocationHelper.getStream(initialBundle.location); try { osgiBundle = context.installBundle(initialBundle.locationString, in); }catch (BundleException e) { if (e.getType() == BundleException.DUPLICATE_BUNDLE_ERROR) { continue; // TODO should attempt to lookup the existing bundle } throw e; } // only check for lazy activation header if this is a newly installed bundle and is not marked for persistent start if (!initialBundle.start && hasLazyActivationPolicy(osgiBundle)) { lazyActivationBundles.add(osgiBundle); } } // always set the startlevel incase it has changed (bug 111549) // this is a no-op if the level is the same as previous launch. if ((osgiBundle.getState() & Bundle.UNINSTALLED) == 0 && initialBundle.level >= 0) { osgiBundle.adapt(BundleStartLevel.class).setStartLevel(initialBundle.level); } // if this bundle is supposed to be started then add it to the start list if (initialBundle.start) { startBundles.add(osgiBundle); } // include basic bundles in case they were not resolved before if ((osgiBundle.getState() & Bundle.INSTALLED) != 0) toRefresh.add(osgiBundle); } catch (BundleException | IOException e) { FrameworkLogEntry entry = new FrameworkLogEntry(EquinoxContainer.NAME, FrameworkLogEntry.ERROR, 0, NLS.bind(Msg.ECLIPSE_STARTUP_FAILED_INSTALL, initialBundle.location), 0, e, null); log.log(entry); } } } @SuppressWarnings("deprecation") private static boolean hasLazyActivationPolicy(Bundle target) { // check the bundle manifest to see if it defines a lazy activation policy Dictionary<String, String> headers = target.getHeaders(""); //$NON-NLS-1$ // first check to see if this is a fragment bundle String fragmentHost = headers.get(Constants.FRAGMENT_HOST); if (fragmentHost != null) return false; // do not activate fragment bundles // look for the OSGi defined Bundle-ActivationPolicy header String activationPolicy = headers.get(Constants.BUNDLE_ACTIVATIONPOLICY); try { if (activationPolicy != null) { ManifestElement[] elements = ManifestElement.parseHeader(Constants.BUNDLE_ACTIVATIONPOLICY, activationPolicy); if (elements != null && elements.length > 0) { // if the value is "lazy" then it has a lazy activation poliyc if (Constants.ACTIVATION_LAZY.equals(elements[0].getValue())) return true; } } else { // check for Eclipse specific lazy start headers "Eclipse-LazyStart" and "Eclipse-AutoStart" String eclipseLazyStart = headers.get(EquinoxModuleDataNamespace.LAZYSTART_HEADER); if (eclipseLazyStart == null) eclipseLazyStart = headers.get(EquinoxModuleDataNamespace.AUTOSTART_HEADER); ManifestElement[] elements = ManifestElement.parseHeader(EquinoxModuleDataNamespace.AUTOSTART_HEADER, eclipseLazyStart); if (elements != null && elements.length > 0) { // if the value is true then it is lazy activated if ("true".equals(elements[0].getValue())) //$NON-NLS-1$ return true; // otherwise it is only lazy activated if it defines an exceptions directive. else if (elements[0].getDirective("exceptions") != null) //$NON-NLS-1$ return true; } } } catch (BundleException be) { // ignore this } return false; } private static void startBundles(Bundle[] startBundles, Bundle[] lazyBundles) { for (Bundle startBundle : startBundles) { startBundle(startBundle, 0); } for (Bundle lazyBundle : lazyBundles) { startBundle(lazyBundle, Bundle.START_ACTIVATION_POLICY); } } private static void startBundle(Bundle bundle, int options) { try { bundle.start(options); } catch (BundleException e) { if ((bundle.getState() & Bundle.RESOLVED) != 0) { // only log errors if the bundle is resolved FrameworkLogEntry entry = new FrameworkLogEntry(EquinoxContainer.NAME, FrameworkLogEntry.ERROR, 0, NLS.bind(Msg.ECLIPSE_STARTUP_FAILED_START, bundle.getLocation()), 0, e, null); log.log(entry); } } }
Returns a URL which is equivalent to the given URL relative to the specified base URL. Works only for file: URLs
Throws:
  • MalformedURLException –
/** * Returns a URL which is equivalent to the given URL relative to the * specified base URL. Works only for file: URLs * @throws MalformedURLException */
private static URL makeRelative(URL base, URL location) throws MalformedURLException { if (base == null) return location; if (!"file".equals(base.getProtocol())) //$NON-NLS-1$ return location; if (!location.getProtocol().equals(REFERENCE_PROTOCOL)) return location; // we can only make reference urls relative URL nonReferenceLocation = createURL(location.getPath()); // if some URL component does not match, return the original location if (!base.getProtocol().equals(nonReferenceLocation.getProtocol())) return location; File locationPath = new File(nonReferenceLocation.getPath()); // if location is not absolute, return original location if (!locationPath.isAbsolute()) return location; File relativePath = makeRelative(new File(base.getPath()), locationPath); String urlPath = relativePath.getPath(); if (File.separatorChar != '/') urlPath = urlPath.replace(File.separatorChar, '/'); if (nonReferenceLocation.getPath().endsWith("/")) //$NON-NLS-1$ // restore original trailing slash urlPath += '/'; // couldn't use File to create URL here because it prepends the path with user.dir URL relativeURL = createURL(base.getProtocol(), base.getHost(), base.getPort(), urlPath); // now make it back to a reference URL relativeURL = createURL(REFERENCE_SCHEME + relativeURL.toExternalForm()); return relativeURL; } private static URL createURL(String spec) throws MalformedURLException { return createURL(null, spec); } private static URL createURL(URL urlContext, String spec) throws MalformedURLException { if (context != null && spec.startsWith(REFERENCE_SCHEME)) { return new URL(urlContext, spec, new Handler(context.getProperty(EquinoxLocations.PROP_INSTALL_AREA))); } return new URL(urlContext, spec); } private static URL createURL(String protocol, String host, String file) throws MalformedURLException { return createURL(protocol, host, -1, file); } private static URL createURL(String protocol, String host, int port, String file) throws MalformedURLException { if (context != null && REFERENCE_PROTOCOL.equalsIgnoreCase(protocol)) { return new URL(protocol, host, port, file, new Handler(context.getProperty(EquinoxLocations.PROP_INSTALL_AREA))); } return new URL(protocol, host, port, file); } private static File makeRelative(File base, File location) { if (!location.isAbsolute()) return location; File relative = new File(new FilePath(base).makeRelative(new FilePath(location))); return relative; } private static void setStartLevel(final int value) throws InterruptedException { FrameworkStartLevel fwkStartLevel = context.getBundle().adapt(FrameworkStartLevel.class); final Semaphore semaphore = new Semaphore(0); StartupEventListener listener = new StartupEventListener(semaphore, FrameworkEvent.STARTLEVEL_CHANGED); context.addBundleListener(listener); fwkStartLevel.setStartLevel(value, listener); updateSplash(semaphore, listener); } static class StartupEventListener implements SynchronousBundleListener, FrameworkListener { private final Semaphore semaphore; private final int frameworkEventType; public StartupEventListener(Semaphore semaphore, int frameworkEventType) { this.semaphore = semaphore; this.frameworkEventType = frameworkEventType; } @Override public void bundleChanged(BundleEvent event) { if (event.getBundle().getBundleId() == 0 && event.getType() == BundleEvent.STOPPING) semaphore.release(); } @Override public void frameworkEvent(FrameworkEvent event) { if (event.getType() == frameworkEventType) semaphore.release(); } } private static void updateSplash(Semaphore semaphore, StartupEventListener listener) throws InterruptedException { ServiceTracker<StartupMonitor, StartupMonitor> monitorTracker = new ServiceTracker<>(context, StartupMonitor.class.getName(), null); try { monitorTracker.open(); } catch (IllegalStateException e) { // do nothing; this can happen if the framework shutdown return; } try { while (true) { StartupMonitor monitor = monitorTracker.getService(); if (monitor != null) { try { monitor.update(); } catch (Throwable e) { // ignore exceptions thrown by the monitor } } // can we acquire the semaphore yet? if (semaphore.tryAcquire(50, TimeUnit.MILLISECONDS)) break; //done //else still working, spin another update } } finally { if (listener != null) { try { context.removeBundleListener(listener); monitorTracker.close(); } catch (IllegalStateException e) { // do nothing; this can happen if the framework shutdown } } } }
Searches for the given target directory immediately under the given start location. If one is found then this location is returned; otherwise an exception is thrown.
Params:
  • start – the location to begin searching
Returns:the location where target directory was found
/** * Searches for the given target directory immediately under * the given start location. If one is found then this location is returned; * otherwise an exception is thrown. * * @return the location where target directory was found * @param start the location to begin searching */
private static String searchFor(final String target, String start) { String[] candidates = searchCandidates.get(start); if (candidates == null) { File startFile = new File(start); startFile = LocationHelper.decodePath(startFile); candidates = startFile.list(); if (candidates != null) searchCandidates.put(start, candidates); } if (candidates == null) return null; String result = null; Object[] maxVersion = null; boolean resultIsFile = false; for (String candidateName : candidates) { if (!candidateName.startsWith(target)) continue; boolean simpleJar = false; final char versionSep = candidateName.length() > target.length() ? candidateName.charAt(target.length()) : 0; if (candidateName.length() > target.length() && versionSep != '_' && versionSep != '-') { // make sure this is not just a jar with no (_|-)version tacked on the end if (candidateName.length() == 4 + target.length() && candidateName.endsWith(".jar")) //$NON-NLS-1$ simpleJar = true; else // name does not match the target properly with an (_|-) version at the end continue; } // Note: directory with version suffix is always > than directory without version suffix String version = candidateName.length() > target.length() + 1 && (versionSep == '_' || versionSep == '-') ? candidateName.substring(target.length() + 1) : ""; //$NON-NLS-1$ Object[] currentVersion = getVersionElements(version); if (currentVersion != null && compareVersion(maxVersion, currentVersion) < 0) { File candidate = new File(start, candidateName); boolean candidateIsFile = candidate.isFile(); // if simple jar; make sure it is really a file before accepting it if (!simpleJar || candidateIsFile) { result = candidate.getAbsolutePath(); resultIsFile = candidateIsFile; maxVersion = currentVersion; } } } if (result == null) return null; return result.replace(File.separatorChar, '/') + (resultIsFile ? "" : "/"); //$NON-NLS-1$ //$NON-NLS-2$ }
Do a quick parse of version identifier so its elements can be correctly compared. If we are unable to parse the full version, remaining elements are initialized with suitable defaults.
Returns:an array of size 4; first three elements are of type Integer (representing major, minor and service) and the fourth element is of type String (representing qualifier). A value of null is returned if there are no valid Integers. Note, that returning anything else will cause exceptions in the caller.
/** * Do a quick parse of version identifier so its elements can be correctly compared. * If we are unable to parse the full version, remaining elements are initialized * with suitable defaults. * @return an array of size 4; first three elements are of type Integer (representing * major, minor and service) and the fourth element is of type String (representing * qualifier). A value of null is returned if there are no valid Integers. Note, that * returning anything else will cause exceptions in the caller. */
private static Object[] getVersionElements(String version) { Object[] result = {Integer.valueOf(-1), Integer.valueOf(-1), Integer.valueOf(-1), ""}; //$NON-NLS-1$ StringTokenizer t = new StringTokenizer(version, "."); //$NON-NLS-1$ String token; for (int i = 0; t.hasMoreTokens() && i < 4; i++) { token = t.nextToken(); if (i < 3) { // major, minor or service ... numeric values try { result[i] = Integer.valueOf(token); } catch (Exception e) { if (i == 0) return null; // return null if no valid numbers are present // invalid number format - use default numbers (-1) for the rest break; } } else { // qualifier ... string value result[i] = token; } } return result; }
Compares version strings.
Returns:result of comparison, as integer; <0 if left < right; 0 if left == right; >0 if left > right;
/** * Compares version strings. * @return result of comparison, as integer; * <code><0</code> if left < right; * <code>0</code> if left == right; * <code>>0</code> if left > right; */
private static int compareVersion(Object[] left, Object[] right) { if (left == null) return -1; int result = ((Integer) left[0]).compareTo((Integer) right[0]); // compare major if (result != 0) return result; result = ((Integer) left[1]).compareTo((Integer) right[1]); // compare minor if (result != 0) return result; result = ((Integer) left[2]).compareTo((Integer) right[2]); // compare service if (result != 0) return result; return ((String) left[3]).compareTo((String) right[3]); // compare qualifier } private static class InitialBundle { public final String locationString; public final URL location; public final int level; public final boolean start; InitialBundle(String locationString, URL location, int level, boolean start) { this.locationString = locationString; this.location = location; this.level = level; this.start = start; } }
Sets the initial properties for the platform. This method must be called before calling the run(String[], Runnable) or startup(String[], Runnable) methods for the properties to be used in a launched instance of the platform.

If the specified properties contains a null value then the key for that value will be cleared from the properties of the platform.

Params:
  • initialProperties – the initial properties to set for the platform.
Since:3.2
/** * Sets the initial properties for the platform. * This method must be called before calling the {@link #run(String[], Runnable)} or * {@link #startup(String[], Runnable)} methods for the properties to be used in * a launched instance of the platform. * <p> * If the specified properties contains a null value then the key for that value * will be cleared from the properties of the platform. * </p> * @param initialProperties the initial properties to set for the platform. * @since 3.2 */
public static void setInitialProperties(Map<String, String> initialProperties) { if (initialProperties == null || initialProperties.isEmpty()) return; for (Map.Entry<String, String> entry : initialProperties.entrySet()) { if (entry.getValue() != null) setProperty(entry.getKey(), entry.getValue()); else clearProperty(entry.getKey()); } }
Returns the context of the system bundle. A value of null is returned if the platform is not running.
Throws:
  • SecurityException – If the caller does not have the appropriate AdminPermission[system.bundle,CONTEXT], and the Java Runtime Environment supports permissions.
Returns:the context of the system bundle
/** * Returns the context of the system bundle. A value of * <code>null</code> is returned if the platform is not running. * @return the context of the system bundle * @throws java.lang.SecurityException If the caller does not have the * appropriate <code>AdminPermission[system.bundle,CONTEXT]</code>, and * the Java Runtime Environment supports permissions. */
public static BundleContext getSystemBundleContext() { if (context == null || !running) return null; return context.getBundle().getBundleContext(); } private static boolean isForcedRestart() { return Boolean.valueOf(getProperty(EquinoxConfiguration.PROP_FORCED_RESTART)).booleanValue(); } /* * NOTE: This is an internal/experimental method used by launchers that need to react when the framework * is shutdown internally. * * Adds a framework shutdown handler. <p> * A handler implements the {@link Runnable} interface. When the framework is shutdown * the {@link Runnable#run()} method is called for each registered handler. Handlers should * make no assumptions on the thread it is being called from. If a handler object is * registered multiple times it will be called once for each registration. * <p> * At the time a handler is called the framework is shutdown. Handlers must not depend on * a running framework to execute or attempt to load additional classes from bundles * installed in the framework. * @param handler the framework shutdown handler * @throws IllegalStateException if the platform is already running */ static void internalAddFrameworkShutdownHandler(Runnable handler) { if (running) throw new IllegalStateException(Msg.ECLIPSE_STARTUP_ALREADY_RUNNING); if (shutdownHandlers == null) shutdownHandlers = new ArrayList<>(); shutdownHandlers.add(handler); } /* * NOTE: This is an internal/experimental method used by launchers that need to react when the framework * is shutdown internally. * * Removes a framework shutdown handler. <p> * @param handler the framework shutdown handler * @throws IllegalStateException if the platform is already running */ static void internalRemoveFrameworkShutdownHandler(Runnable handler) { if (running) throw new IllegalStateException(Msg.ECLIPSE_STARTUP_ALREADY_RUNNING); if (shutdownHandlers != null) shutdownHandlers.remove(handler); } private static void registerFrameworkShutdownHandlers() { if (shutdownHandlers == null) return; final Bundle systemBundle = context.getBundle(); for (Iterator<Runnable> it = shutdownHandlers.iterator(); it.hasNext();) { final Runnable handler = it.next(); BundleListener listener = new BundleListener() { @Override public void bundleChanged(BundleEvent event) { if (event.getBundle() == systemBundle && event.getType() == BundleEvent.STOPPED) { handler.run(); } } }; context.addBundleListener(listener); } } }