Copyright (c) 2005, 2010 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
/******************************************************************************* * Copyright (c) 2005, 2010 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 *******************************************************************************/
package org.eclipse.equinox.internal.app; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.*; import org.eclipse.core.runtime.*; import org.eclipse.equinox.app.IApplicationContext; import org.eclipse.osgi.framework.log.FrameworkLogEntry; import org.eclipse.osgi.service.runnable.ApplicationLauncher; import org.eclipse.osgi.service.runnable.ParameterizedRunnable; import org.eclipse.osgi.util.NLS; import org.osgi.framework.*; import org.osgi.service.application.*; import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer; /* * A MEG application container that understands eclipse applications. This * container will discover installed eclipse applications and register the * appropriate ApplicatoinDescriptor service with the service registry. */ public class EclipseAppContainer implements IRegistryEventListener, SynchronousBundleListener, ServiceTrackerCustomizer { private static final String PI_RUNTIME = "org.eclipse.core.runtime"; //$NON-NLS-1$ private static final String PT_APPLICATIONS = "applications"; //$NON-NLS-1$ private static final String PT_APP_VISIBLE = "visible"; //$NON-NLS-1$ private static final String PT_APP_THREAD = "thread"; //$NON-NLS-1$ private static final String PT_APP_THREAD_ANY = "any"; //$NON-NLS-1$ private static final String PT_APP_CARDINALITY = "cardinality"; //$NON-NLS-1$ private static final String PT_APP_CARDINALITY_SINGLETON_GLOBAL = "singleton-global"; //$NON-NLS-1$ private static final String PT_APP_CARDINALITY_SINGLETON_SCOPED = "singleton-scoped"; //$NON-NLS-1$ private static final String PT_APP_CARDINALITY_UNLIMITED = "*"; //$NON-NLS-1$ private static final String PT_APP_ICON = "icon"; //$NON-NLS-1$ private static final String PT_PRODUCTS = "products"; //$NON-NLS-1$ private static final String EXT_ERROR_APP = "org.eclipse.equinox.app.error"; //$NON-NLS-1$ static final String PROP_PRODUCT = "eclipse.product"; //$NON-NLS-1$ static final String PROP_ECLIPSE_APPLICATION = "eclipse.application"; //$NON-NLS-1$ private static final String PROP_ECLIPSE_APPLICATION_LAUNCH_DEFAULT = "eclipse.application.launchDefault"; //$NON-NLS-1$ static final int NOT_LOCKED = 0; static final int LOCKED_SINGLETON_GLOBAL_RUNNING = 1; static final int LOCKED_SINGLETON_GLOBAL_APPS_RUNNING = 2; static final int LOCKED_SINGLETON_SCOPED_RUNNING = 3; static final int LOCKED_SINGLETON_LIMITED_RUNNING = 4; static final int LOCKED_MAIN_THREAD_RUNNING = 5; final BundleContext context; private final Object lock = new Object(); // A map of ApplicationDescriptors keyed by eclipse application ID /* @GuardedBy(lock) */ final private HashMap<String, EclipseAppDescriptor> apps = new HashMap<>(); final private IExtensionRegistry extensionRegistry; final private ServiceTracker launcherTracker; private IBranding branding; private boolean missingProductReported; /* @GuardedBy(lock) */ final private Collection<EclipseAppHandle> activeHandles = new ArrayList<>(); // the currently active application handles /* @GuardedBy(lock) */ private EclipseAppHandle activeMain; // the handle currently running on the main thread /* @GuardedBy(lock) */ private EclipseAppHandle activeGlobalSingleton; // the current global singleton handle /* @GuardedBy(lock) */ private EclipseAppHandle activeScopedSingleton; // the current scoped singleton handle /* @GuardedBy(lock) */ private HashMap<String, ArrayList<EclipseAppHandle>> activeLimited; // Map of handles that have cardinality limits private String defaultAppId; private DefaultApplicationListener defaultAppListener; private ParameterizedRunnable defaultMainThreadAppHandle; // holds the default app handle to be run on the main thread private volatile boolean missingApp = false; private MainApplicationLauncher missingAppLauncher; public EclipseAppContainer(BundleContext context, IExtensionRegistry extensionRegistry) { this.context = context; this.extensionRegistry = extensionRegistry; launcherTracker = new ServiceTracker(context, ApplicationLauncher.class.getName(), this); } void start() { launcherTracker.open(); extensionRegistry.addListener(this, PI_RUNTIME + '.' + PT_APPLICATIONS); // need to listen for system bundle stopping context.addBundleListener(this); // register all the descriptors registerAppDescriptors(); String startDefaultProp = context.getProperty(EclipseAppContainer.PROP_ECLIPSE_APPLICATION_LAUNCH_DEFAULT); if (startDefaultProp == null || "true".equalsIgnoreCase(startDefaultProp)) { //$NON-NLS-1$ // Start the default application try { startDefaultApp(true); } catch (ApplicationException e) { Activator.log(new FrameworkLogEntry(Activator.PI_APP, FrameworkLogEntry.ERROR, 0, Messages.application_errorStartDefault, 0, e, null)); } } } void stop() { // stop all applications stopAllApps(); context.removeBundleListener(this); extensionRegistry.removeListener(this); // flush the apps apps.clear(); branding = null; missingProductReported = false; launcherTracker.close(); } /* * Only used to find the default application */ private EclipseAppDescriptor getAppDescriptor(String applicationId) { EclipseAppDescriptor result = null; synchronized (lock) { result = apps.get(applicationId); } if (result == null) { registerAppDescriptor(applicationId); // try again just in case we are waiting for an event synchronized (lock) { result = apps.get(applicationId); } } return result; } private EclipseAppDescriptor createAppDescriptor(IExtension appExtension) { if (Activator.DEBUG) System.out.println("Creating application descriptor: " + appExtension.getUniqueIdentifier()); //$NON-NLS-1$ String iconPath = null; synchronized (lock) { EclipseAppDescriptor appDescriptor = apps.get(appExtension.getUniqueIdentifier()); if (appDescriptor != null) return appDescriptor; // the appDescriptor does not exist for the app ID; create it IConfigurationElement[] configs = appExtension.getConfigurationElements(); int flags = EclipseAppDescriptor.FLAG_CARD_SINGLETON_GLOGAL | EclipseAppDescriptor.FLAG_VISIBLE | EclipseAppDescriptor.FLAG_TYPE_MAIN_THREAD; int cardinality = 0; if (configs.length > 0) { String sVisible = configs[0].getAttribute(PT_APP_VISIBLE); if (sVisible != null && !Boolean.valueOf(sVisible).booleanValue()) flags &= ~(EclipseAppDescriptor.FLAG_VISIBLE); String sThread = configs[0].getAttribute(PT_APP_THREAD); if (PT_APP_THREAD_ANY.equals(sThread)) { flags |= EclipseAppDescriptor.FLAG_TYPE_ANY_THREAD; flags &= ~(EclipseAppDescriptor.FLAG_TYPE_MAIN_THREAD); } String sCardinality = configs[0].getAttribute(PT_APP_CARDINALITY); if (sCardinality != null) { flags &= ~(EclipseAppDescriptor.FLAG_CARD_SINGLETON_GLOGAL); // clear the global bit if (PT_APP_CARDINALITY_SINGLETON_SCOPED.equals(sCardinality)) flags |= EclipseAppDescriptor.FLAG_CARD_SINGLETON_SCOPED; else if (PT_APP_CARDINALITY_UNLIMITED.equals(sCardinality)) flags |= EclipseAppDescriptor.FLAG_CARD_UNLIMITED; else if (PT_APP_CARDINALITY_SINGLETON_GLOBAL.equals(sCardinality)) flags |= EclipseAppDescriptor.FLAG_CARD_SINGLETON_GLOGAL; else { try { cardinality = Integer.parseInt(sCardinality); flags |= EclipseAppDescriptor.FLAG_CARD_LIMITED; } catch (NumberFormatException e) { // TODO should we log this? // just fall back to the default flags |= EclipseAppDescriptor.FLAG_CARD_SINGLETON_GLOGAL; } } } String defaultApp = getDefaultAppId(); if (defaultApp != null && defaultApp.equals(appExtension.getUniqueIdentifier())) flags |= EclipseAppDescriptor.FLAG_DEFAULT_APP; iconPath = configs[0].getAttribute(PT_APP_ICON); } appDescriptor = new EclipseAppDescriptor(Activator.getBundle(appExtension.getContributor()), appExtension.getUniqueIdentifier(), appExtension.getLabel(), iconPath, flags, cardinality, this); // register the appDescriptor as a service ServiceRegistration sr = (ServiceRegistration) AccessController.doPrivileged(new RegisterService(new String[] {ApplicationDescriptor.class.getName()}, appDescriptor, appDescriptor.getServiceProperties())); appDescriptor.setServiceRegistration(sr); // save the app descriptor in the cache apps.put(appExtension.getUniqueIdentifier(), appDescriptor); return appDescriptor; } } private EclipseAppDescriptor removeAppDescriptor(String applicationId) { if (Activator.DEBUG) System.out.println("Removing application descriptor: " + applicationId); //$NON-NLS-1$ synchronized (lock) { EclipseAppDescriptor appDescriptor = apps.remove(applicationId); if (appDescriptor == null) return null; appDescriptor.unregister(); return appDescriptor; } } /* * Gives access to the RegisterService privileged action. */ PrivilegedAction getRegServiceAction(String[] serviceClasses, Object serviceObject, Dictionary<String, ?> serviceProps) { return new RegisterService(serviceClasses, serviceObject, serviceProps); } /* * PrivilegedAction used to register ApplicationDescriptor and ApplicationHandle services */ private class RegisterService implements PrivilegedAction { String[] serviceClasses; Object serviceObject; Dictionary<String, ?> serviceProps; RegisterService(String[] serviceClasses, Object serviceObject, Dictionary<String, ?> serviceProps) { this.serviceClasses = serviceClasses; this.serviceObject = serviceObject; this.serviceProps = serviceProps; } @Override public Object run() { return context.registerService(serviceClasses, serviceObject, serviceProps); } } void startDefaultApp(boolean delayError) throws ApplicationException { // find the default application String applicationId = getDefaultAppId(); EclipseAppDescriptor defaultDesc = null; Map<String, Object> args = new HashMap<>(2); args.put(EclipseAppDescriptor.APP_DEFAULT, Boolean.TRUE); if (applicationId == null && !delayError) { // the application id is not set; use a descriptor that will throw an exception args.put(ErrorApplication.ERROR_EXCEPTION, new RuntimeException(Messages.application_noIdFound)); defaultDesc = getAppDescriptor(EXT_ERROR_APP); } else { defaultDesc = getAppDescriptor(applicationId); if (defaultDesc == null && !delayError) { // the application id is not available in the registry; use a descriptor that will throw an exception args.put(ErrorApplication.ERROR_EXCEPTION, new RuntimeException(NLS.bind(Messages.application_notFound, applicationId, getAvailableAppsMsg()))); defaultDesc = getAppDescriptor(EXT_ERROR_APP); } } if (delayError && defaultDesc == null) { // could not find the application; but we want to delay the error. // another bundle may get installed that provides the application // before we actually try to launch it. missingApp = true; return; } if (defaultDesc != null) defaultDesc.launch(args); else throw new ApplicationException(ApplicationException.APPLICATION_INTERNAL_ERROR, Messages.application_noIdFound); } /* * Registers an ApplicationDescriptor service for each eclipse application * available in the extension registry. */ private void registerAppDescriptors() { IExtension[] availableApps = getAvailableAppExtensions(); for (IExtension availableApp : availableApps) { createAppDescriptor(availableApp); } } private void registerAppDescriptor(String applicationId) { IExtension appExtension = getAppExtension(applicationId); if (appExtension != null) createAppDescriptor(appExtension); } /* * Returns a list of all the available application IDs which are available * in the extension registry. */ private IExtension[] getAvailableAppExtensions() { IExtensionPoint point = extensionRegistry.getExtensionPoint(PI_RUNTIME + '.' + PT_APPLICATIONS); if (point == null) return new IExtension[0]; return point.getExtensions(); } String getAvailableAppsMsg() { IExtension[] availableApps = getAvailableAppExtensions(); String availableAppsMsg = "<NONE>"; //$NON-NLS-1$ if (availableApps.length != 0) { availableAppsMsg = availableApps[0].getUniqueIdentifier(); for (int i = 1; i < availableApps.length; i++) availableAppsMsg = availableAppsMsg + ", " + availableApps[i].getUniqueIdentifier(); //$NON-NLS-1$ } return availableAppsMsg; } /* * Returns the application extension for the specified applicaiton ID. * A RuntimeException is thrown if the extension does not exist for the * given application ID. */ IExtension getAppExtension(String applicationId) { return extensionRegistry.getExtension(PI_RUNTIME, PT_APPLICATIONS, applicationId); } void launch(EclipseAppHandle appHandle) throws Exception { boolean isDefault = appHandle.isDefault(); if (((EclipseAppDescriptor) appHandle.getApplicationDescriptor()).getThreadType() == EclipseAppDescriptor.FLAG_TYPE_MAIN_THREAD) { // use the ApplicationLauncher provided by the framework to ensure it is launched on the main thread DefaultApplicationListener curDefaultApplicationListener = null; MainApplicationLauncher curMissingAppLauncher = null; ApplicationLauncher appLauncher = null; synchronized (this) { appLauncher = (ApplicationLauncher) launcherTracker.getService(); if (appLauncher == null) { if (isDefault) { // we need to wait to allow the ApplicationLauncher to get registered; // save the handle to be launched as soon as the ApplicationLauncher is available defaultMainThreadAppHandle = appHandle; return; } throw new ApplicationException(ApplicationException.APPLICATION_INTERNAL_ERROR, NLS.bind(Messages.application_error_noMainThread, appHandle.getInstanceId())); } curDefaultApplicationListener = defaultAppListener; curMissingAppLauncher = missingAppLauncher; } if (curDefaultApplicationListener != null) curDefaultApplicationListener.launch(appHandle); else if (curMissingAppLauncher != null) curMissingAppLauncher.launch(appHandle); else appLauncher.launch(appHandle, appHandle.getArguments().get(IApplicationContext.APPLICATION_ARGS)); } else { if (isDefault) { DefaultApplicationListener curDefaultApplicationListener = null; MainApplicationLauncher curMissingAppLauncher = null; ApplicationLauncher appLauncher = null; synchronized (this) { appLauncher = (ApplicationLauncher) launcherTracker.getService(); if (defaultAppListener == null) defaultAppListener = new DefaultApplicationListener(appHandle); curDefaultApplicationListener = defaultAppListener; if (appLauncher == null) { // we need to wait to allow the ApplicationLauncher to get registered; // save the default app listener to be launched as soon as the ApplicationLauncher is available defaultMainThreadAppHandle = curDefaultApplicationListener; return; } curMissingAppLauncher = missingAppLauncher; } if (curMissingAppLauncher != null) curMissingAppLauncher.launch(curDefaultApplicationListener); else appLauncher.launch(curDefaultApplicationListener, null); } else { AnyThreadAppLauncher.launchEclipseApplication(appHandle); } } } @Override public void bundleChanged(BundleEvent event) { // if this is not the system bundle stopping then ignore the event if ((BundleEvent.STOPPING & event.getType()) == 0 || event.getBundle().getBundleId() != 0) return; // The system bundle is stopping; better stop all applications and containers now stopAllApps(); } private void stopAllApps() { // get a stapshot of running applications try { ServiceReference[] runningRefs = context.getServiceReferences(ApplicationHandle.class.getName(), "(!(application.state=STOPPING))"); //$NON-NLS-1$ if (runningRefs != null) for (ServiceReference runningRef : runningRefs) { ApplicationHandle handle = (ApplicationHandle) context.getService(runningRef); try { if (handle != null) handle.destroy(); } catch (Throwable t) { String message = NLS.bind(Messages.application_error_stopping, handle.getInstanceId()); Activator.log(new FrameworkLogEntry(Activator.PI_APP, FrameworkLogEntry.WARNING, 0, message, 0, t, null)); } finally { if (handle != null) { context.ungetService(runningRef); } } } } catch (InvalidSyntaxException e) { // do nothing; we already tested the filter string above } } private String getDefaultAppId() { if (defaultAppId != null) return defaultAppId; // try commandLineProperties defaultAppId = CommandLineArgs.getApplication(); if (defaultAppId != null) return defaultAppId; // try bundleContext properties defaultAppId = context.getProperty(EclipseAppContainer.PROP_ECLIPSE_APPLICATION); if (defaultAppId != null) return defaultAppId; //Derive the application from the product information defaultAppId = getBranding() == null ? null : getBranding().getApplication(); return defaultAppId; } public IBranding getBranding() { if (branding != null) return branding; // try commandLineProperties String productId = CommandLineArgs.getProduct(); if (productId == null) { // try bundleContext properties if (context == null) return null; productId = context.getProperty(PROP_PRODUCT); if (productId == null) return null; } IConfigurationElement[] entries = extensionRegistry.getConfigurationElementsFor(PI_RUNTIME, PT_PRODUCTS, productId); if (entries.length > 0) { // There should only be one product with the given id so just take the first element branding = new ProductExtensionBranding(productId, entries[0]); return branding; } IConfigurationElement[] elements = extensionRegistry.getConfigurationElementsFor(PI_RUNTIME, PT_PRODUCTS); List<FrameworkLogEntry> logEntries = null; for (IConfigurationElement element : elements) { if (element.getName().equalsIgnoreCase("provider")) { //$NON-NLS-1$ try { Object provider = element.createExecutableExtension("run"); //$NON-NLS-1$ Object[] products = (Object[]) EclipseAppContainer.callMethod(provider, "getProducts", null, null); //$NON-NLS-1$ if (products != null) for (Object product : products) { if (productId.equalsIgnoreCase((String) EclipseAppContainer.callMethod(product, "getId", null, null))) { //$NON-NLS-1$ branding = new ProviderExtensionBranding(product); return branding; } } } catch (CoreException e) { if (logEntries == null) logEntries = new ArrayList<>(3); logEntries.add(new FrameworkLogEntry(Activator.PI_APP, NLS.bind(Messages.provider_invalid, element.getParent().toString()), 0, e, null)); } } } if (logEntries != null) Activator.log(new FrameworkLogEntry(Activator.PI_APP, Messages.provider_invalid_general, 0, null, logEntries.toArray(new FrameworkLogEntry[logEntries.size()]))); if (!missingProductReported) { Activator.log(new FrameworkLogEntry(Activator.PI_APP, NLS.bind(Messages.product_notFound, productId), 0, null, null)); missingProductReported = true; } return null; } private void refreshAppDescriptors() { synchronized (lock) { for (Iterator<EclipseAppDescriptor> allApps = apps.values().iterator(); allApps.hasNext();) allApps.next().refreshProperties(); } } void lock(EclipseAppHandle appHandle) throws ApplicationException { EclipseAppDescriptor eclipseApp = (EclipseAppDescriptor) appHandle.getApplicationDescriptor(); synchronized (lock) { switch (isLocked(eclipseApp)) { case NOT_LOCKED : break; case LOCKED_SINGLETON_GLOBAL_RUNNING : throw new ApplicationException(ApplicationException.APPLICATION_NOT_LAUNCHABLE, NLS.bind(Messages.singleton_running, activeGlobalSingleton.getInstanceId())); case LOCKED_SINGLETON_GLOBAL_APPS_RUNNING : throw new ApplicationException(ApplicationException.APPLICATION_NOT_LAUNCHABLE, Messages.apps_running); case LOCKED_SINGLETON_SCOPED_RUNNING : throw new ApplicationException(ApplicationException.APPLICATION_NOT_LAUNCHABLE, NLS.bind(Messages.singleton_running, activeScopedSingleton.getInstanceId())); case LOCKED_SINGLETON_LIMITED_RUNNING : throw new ApplicationException(ApplicationException.APPLICATION_NOT_LAUNCHABLE, NLS.bind(Messages.max_running, eclipseApp.getApplicationId())); case LOCKED_MAIN_THREAD_RUNNING : throw new ApplicationException(ApplicationException.APPLICATION_NOT_LAUNCHABLE, NLS.bind(Messages.main_running, activeMain.getInstanceId())); default : break; } // ok we can now successfully lock the container switch (eclipseApp.getCardinalityType()) { case EclipseAppDescriptor.FLAG_CARD_SINGLETON_GLOGAL : activeGlobalSingleton = appHandle; break; case EclipseAppDescriptor.FLAG_CARD_SINGLETON_SCOPED : activeScopedSingleton = appHandle; break; case EclipseAppDescriptor.FLAG_CARD_LIMITED : if (activeLimited == null) activeLimited = new HashMap<>(3); ArrayList<EclipseAppHandle> limited = activeLimited.get(eclipseApp.getApplicationId()); if (limited == null) { limited = new ArrayList<>(eclipseApp.getCardinality()); activeLimited.put(eclipseApp.getApplicationId(), limited); } limited.add(appHandle); break; case EclipseAppDescriptor.FLAG_CARD_UNLIMITED : break; default : break; } if (eclipseApp.getThreadType() == EclipseAppDescriptor.FLAG_TYPE_MAIN_THREAD) activeMain = appHandle; activeHandles.add(appHandle); refreshAppDescriptors(); } } void unlock(EclipseAppHandle appHandle) { synchronized (lock) { if (activeGlobalSingleton == appHandle) activeGlobalSingleton = null; else if (activeScopedSingleton == appHandle) activeScopedSingleton = null; else if (((EclipseAppDescriptor) appHandle.getApplicationDescriptor()).getCardinalityType() == EclipseAppDescriptor.FLAG_CARD_LIMITED) { if (activeLimited != null) { ArrayList<EclipseAppHandle> limited = activeLimited.get(((EclipseAppDescriptor) appHandle.getApplicationDescriptor()).getApplicationId()); if (limited != null) limited.remove(appHandle); } } if (activeMain == appHandle) activeMain = null; if (activeHandles.remove(appHandle)) refreshAppDescriptors(); // only refresh descriptors if we really unlocked something } } int isLocked(EclipseAppDescriptor eclipseApp) { synchronized (lock) { if (activeGlobalSingleton != null) return LOCKED_SINGLETON_GLOBAL_RUNNING; switch (eclipseApp.getCardinalityType()) { case EclipseAppDescriptor.FLAG_CARD_SINGLETON_GLOGAL : if (activeHandles.size() > 0) return LOCKED_SINGLETON_GLOBAL_APPS_RUNNING; break; case EclipseAppDescriptor.FLAG_CARD_SINGLETON_SCOPED : if (activeScopedSingleton != null) return LOCKED_SINGLETON_SCOPED_RUNNING; break; case EclipseAppDescriptor.FLAG_CARD_LIMITED : if (activeLimited != null) { ArrayList<EclipseAppHandle> limited = activeLimited.get(eclipseApp.getApplicationId()); if (limited != null && limited.size() >= eclipseApp.getCardinality()) return LOCKED_SINGLETON_LIMITED_RUNNING; } break; case EclipseAppDescriptor.FLAG_CARD_UNLIMITED : break; default : break; } if (eclipseApp.getThreadType() == EclipseAppDescriptor.FLAG_TYPE_MAIN_THREAD && activeMain != null) return LOCKED_MAIN_THREAD_RUNNING; return NOT_LOCKED; } } static Object callMethod(Object obj, String methodName, Class<?>[] argTypes, Object[] args) { try { return callMethodWithException(obj, methodName, argTypes, args); } catch (Throwable t) { Activator.log(new FrameworkLogEntry(Activator.PI_APP, FrameworkLogEntry.ERROR, 0, "Error in invoking method.", 0, t, null)); //$NON-NLS-1$ } return null; } static Object callMethodWithException(Object obj, String methodName, Class<?>[] argTypes, Object[] args) throws Exception { try { Method method = obj.getClass().getMethod(methodName, argTypes); return method.invoke(obj, args); } catch (InvocationTargetException e) { if (e.getTargetException() instanceof Error) throw (Error) e.getTargetException(); if (e.getTargetException() instanceof Exception) throw (Exception) e.getTargetException(); throw e; } } @Override public Object addingService(ServiceReference reference) { ApplicationLauncher appLauncher; ParameterizedRunnable appRunnable; synchronized (this) { appLauncher = (ApplicationLauncher) context.getService(reference); // see if there is a default main threaded application waiting to run appRunnable = defaultMainThreadAppHandle; // null out so we do not attempt to start this handle again defaultMainThreadAppHandle = null; if (appRunnable == null && missingApp) { missingAppLauncher = new MainApplicationLauncher(this); appRunnable = missingAppLauncher; missingApp = false; } } if (appRunnable != null) // found a main threaded app; start it now that the app launcher is available appLauncher.launch(appRunnable, appRunnable instanceof EclipseAppHandle ? ((EclipseAppHandle) appRunnable).getArguments().get(IApplicationContext.APPLICATION_ARGS) : null); return appLauncher; } @Override public void modifiedService(ServiceReference reference, Object service) { // Do nothing } @Override public void removedService(ServiceReference reference, Object service) { // Do nothing } @Override public void added(IExtension[] extensions) { for (IExtension extension : extensions) { createAppDescriptor(extension); } } @Override public void added(IExtensionPoint[] extensionPoints) { // nothing } @Override public void removed(IExtension[] extensions) { for (IExtension extension : extensions) { removeAppDescriptor(extension.getUniqueIdentifier()); } } @Override public void removed(IExtensionPoint[] extensionPoints) { // nothing } }