Copyright (c) 2007, 2018 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) 2007, 2018 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 org.eclipse.osgi.framework.log.FrameworkLogEntry; import org.eclipse.osgi.service.runnable.ApplicationRunnable; import org.eclipse.osgi.util.NLS; import org.osgi.framework.ServiceReference; import org.osgi.service.application.ApplicationHandle; import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer;
Listens for the default ApplicationHandle which run on any thread to be destroyed. This is used to force the main thread to wait while a default application runs on another thread. A main threaded application may be launched using this class to launch the main threaded application.
/** * Listens for the default ApplicationHandle which run on any thread to be destroyed. This is used to force the main * thread to wait while a default application runs on another thread. * * A main threaded application may be launched using this class to launch the main threaded application. */
public class DefaultApplicationListener implements ApplicationRunnable, ServiceTrackerCustomizer { private boolean running = true; // indicates the default application is running private EclipseAppHandle launchMainApp; // a handle to a main threaded application private final ServiceTracker handleTracker; // tracks the default application handle private Object result; // holds the result from the default application public DefaultApplicationListener(EclipseAppHandle defaultApp) { ServiceReference defaultRef = defaultApp.getServiceReference(); if (defaultRef == null) { // service has been unregistered; application has ended already, // save the result for latter result = defaultApp.waitForResult(100); handleTracker = null; return; } ServiceTracker defaultAppTracker = new ServiceTracker(Activator.getContext(), defaultRef, this); defaultAppTracker.open(); EclipseAppHandle trackedApp = (EclipseAppHandle) defaultAppTracker.getService(); if (trackedApp == null) { // close tracker since we do not care about tracking the app (bug 215764) defaultAppTracker.close(); // service has been unregistered; application has ended aready, // save the result for latter result = defaultApp.waitForResult(100); handleTracker = null; } else { handleTracker = defaultAppTracker; } } @Override public Object run(Object context) { if (handleTracker == null) return getResult(); // app has ended, return the result EclipseAppHandle anyThreadedDefaultApp = (EclipseAppHandle) handleTracker.getService(); if (anyThreadedDefaultApp != null) // We now need to actual launch the application; this will run the application on another thread. AnyThreadAppLauncher.launchEclipseApplication(anyThreadedDefaultApp); try { while (waitOnRunning()) { EclipseAppHandle mainHandle = getMainHandle(); if (mainHandle != null) { // while we were waiting for the default application to end someone asked for a main threaded app to launch // note that we cannot hold the this lock while launching a main threaded application try { mainHandle.run(null); } catch (Throwable e) { String message = NLS.bind(Messages.application_error_starting, mainHandle.getInstanceId()); Activator.log(new FrameworkLogEntry(Activator.PI_APP, FrameworkLogEntry.WARNING, 0, message, 0, e, null)); } unsetMainHandle(mainHandle); } } } finally { handleTracker.close(); } return getResult(); } private synchronized EclipseAppHandle getMainHandle() { return launchMainApp; } private synchronized void unsetMainHandle(EclipseAppHandle mainHandle) { if (launchMainApp == mainHandle) launchMainApp = null; } private synchronized boolean waitOnRunning() { if (!running) return false; try { wait(100); } catch (InterruptedException e) { // do nothing } return running; } @Override public void stop() { if (handleTracker == null) return; // force the default application to quit ApplicationHandle handle = (ApplicationHandle) handleTracker.getService(); if (handle != null) { try { 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)); } } } @Override public Object addingService(ServiceReference reference) { return Activator.getContext().getService(reference); } @Override public void modifiedService(ServiceReference reference, Object service) { // do nothing } @Override synchronized public void removedService(ServiceReference reference, Object service) { running = false; // only wait for 5 seconds; this may timeout if forcing an application to quit takes too long // this should never timeout if the application exited normally. result = ((EclipseAppHandle) service).waitForResult(5000); EclipseAppHandle mainHandle = getMainHandle(); if (mainHandle != null) // default application has quit; now force the main threaded application to quit try { mainHandle.destroy(); } catch (Throwable t) { String message = NLS.bind(Messages.application_error_stopping, mainHandle.getInstanceId()); Activator.log(new FrameworkLogEntry(Activator.PI_APP, FrameworkLogEntry.WARNING, 0, message, 0, t, null)); } this.notify(); } synchronized void launch(EclipseAppHandle app) { launchMainApp = app; this.notify(); } private synchronized Object getResult() { return result; } }