org.eclipse.equinox.internal.app.EclipseAppHandle Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aspectjtools Show documentation
Show all versions of aspectjtools Show documentation
Tools from the AspectJ project
/*******************************************************************************
* Copyright (c) 2005, 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
* Josh Arnold - Bug 180080 Equinox Application Admin spec violations
*******************************************************************************/
package org.eclipse.equinox.internal.app;
import java.util.*;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.app.IApplicationContext;
import org.eclipse.osgi.service.runnable.ApplicationRunnable;
import org.eclipse.osgi.service.runnable.StartupMonitor;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.*;
import org.osgi.service.application.ApplicationException;
import org.osgi.service.application.ApplicationHandle;
/*
* An ApplicationHandle that represents a single instance of a running eclipse application.
*/
public class EclipseAppHandle extends ApplicationHandle implements ApplicationRunnable, IApplicationContext {
// Indicates the application is starting
private static final int FLAG_STARTING = 0x01;
// Indicates the application is active
private static final int FLAG_ACTIVE = 0x02;
// Indicates the application is stopping
private static final int FLAG_STOPPING = 0x04;
// Indicates the application is stopped
private static final int FLAG_STOPPED = 0x08;
private static final String STARTING = "org.eclipse.equinox.app.starting"; //$NON-NLS-1$
private static final String STOPPED = "org.eclipse.equinox.app.stopped"; //$NON-NLS-1$
private static final String PROP_ECLIPSE_EXITCODE = "eclipse.exitcode"; //$NON-NLS-1$
private static final Object NULL_RESULT = new Object();
private volatile ServiceRegistration handleRegistration;
private int status = EclipseAppHandle.FLAG_STARTING;
private final Map arguments;
private Object application;
private final Boolean defaultAppInstance;
private Object result;
private boolean setResult = false;
private boolean setAsyncResult = false;
private final boolean[] registrationLock = new boolean[] {true};
/*
* Constructs a handle for a single running instance of a eclipse application.
*/
EclipseAppHandle(String instanceId, Map arguments, EclipseAppDescriptor descriptor) {
super(instanceId, descriptor);
defaultAppInstance = arguments == null || arguments.get(EclipseAppDescriptor.APP_DEFAULT) == null ? Boolean.FALSE : (Boolean) arguments.remove(EclipseAppDescriptor.APP_DEFAULT);
if (arguments == null)
this.arguments = new HashMap<>(2);
else
this.arguments = new HashMap<>(arguments);
}
@Override
synchronized public String getState() {
switch (status) {
case FLAG_STARTING :
return STARTING;
case FLAG_ACTIVE :
return ApplicationHandle.RUNNING;
case FLAG_STOPPING :
return ApplicationHandle.STOPPING;
case FLAG_STOPPED :
default :
// must only check this if the status is STOPPED; otherwise we throw exceptions before we have set the registration.
if (getServiceRegistration() == null)
throw new IllegalStateException(NLS.bind(Messages.application_error_state_stopped, getInstanceId()));
return STOPPED;
}
}
@Override
protected void destroySpecific() {
// when this method is called we must force the application to exit.
// first set the status to stopping
setAppStatus(EclipseAppHandle.FLAG_STOPPING);
// now force the application to stop
IApplication app = getApplication();
if (app != null)
app.stop();
// make sure the app status is stopped
setAppStatus(EclipseAppHandle.FLAG_STOPPED);
}
void setServiceRegistration(ServiceRegistration sr) {
synchronized (registrationLock) {
this.handleRegistration = sr;
registrationLock[0] = sr != null;
registrationLock.notifyAll();
}
}
private ServiceRegistration getServiceRegistration() {
synchronized (registrationLock) {
if (handleRegistration == null && registrationLock[0]) {
try {
registrationLock.wait(1000); // timeout after 1 second
} catch (InterruptedException e) {
// nothing
}
}
return handleRegistration;
}
}
ServiceReference getServiceReference() {
ServiceRegistration reg = getServiceRegistration();
if (reg == null)
return null;
try {
return reg.getReference();
} catch (IllegalStateException e) {
return null; // this will happen if the service has been unregistered already
}
}
/*
* Gets a snapshot of the current service properties.
*/
Dictionary getServiceProperties() {
Dictionary props = new Hashtable<>(6);
props.put(ApplicationHandle.APPLICATION_PID, getInstanceId());
props.put(ApplicationHandle.APPLICATION_STATE, getState());
props.put(ApplicationHandle.APPLICATION_DESCRIPTOR, getApplicationDescriptor().getApplicationId());
props.put(EclipseAppDescriptor.APP_TYPE, ((EclipseAppDescriptor) getApplicationDescriptor()).getThreadTypeString());
props.put(ApplicationHandle.APPLICATION_SUPPORTS_EXITVALUE, Boolean.TRUE);
if (defaultAppInstance.booleanValue())
props.put(EclipseAppDescriptor.APP_DEFAULT, defaultAppInstance);
return props;
}
/*
* Changes the status of this handle. This method will properly transition
* the state of this handle and will update the service registration accordingly.
*/
private synchronized void setAppStatus(int status) {
if (this.status == status)
return;
if ((status & EclipseAppHandle.FLAG_STARTING) != 0)
throw new IllegalArgumentException("Cannot set app status to starting"); //$NON-NLS-1$
// if status is stopping and the context is already stopping then return
if ((status & EclipseAppHandle.FLAG_STOPPING) != 0)
if ((this.status & (EclipseAppHandle.FLAG_STOPPING | EclipseAppHandle.FLAG_STOPPED)) != 0)
return;
// change the service properties to reflect the state change.
this.status = status;
ServiceRegistration handleReg = getServiceRegistration();
if (handleReg == null)
return;
handleReg.setProperties(getServiceProperties());
// if the status is stopped then unregister the service
if ((this.status & EclipseAppHandle.FLAG_STOPPED) != 0) {
((EclipseAppDescriptor) getApplicationDescriptor()).getContainerManager().unlock(this);
handleReg.unregister();
setServiceRegistration(null);
}
}
@Override
public Map getArguments() {
return arguments;
}
@Override
public Object run(Object context) throws Exception {
if (context != null) {
// always force the use of the context if it is not null
arguments.put(IApplicationContext.APPLICATION_ARGS, context);
} else {
// get the context from the arguments
context = arguments.get(IApplicationContext.APPLICATION_ARGS);
if (context == null) {
// if context is null then use the args from CommandLineArgs
context = CommandLineArgs.getApplicationArgs();
arguments.put(IApplicationContext.APPLICATION_ARGS, context);
}
}
Object tempResult = null;
try {
Object app;
synchronized (this) {
if ((status & (EclipseAppHandle.FLAG_STARTING | EclipseAppHandle.FLAG_STOPPING)) == 0)
throw new ApplicationException(ApplicationException.APPLICATION_INTERNAL_ERROR, NLS.bind(Messages.application_instance_stopped, getInstanceId()));
application = getConfiguration().createExecutableExtension("run"); //$NON-NLS-1$
app = application;
notifyAll();
}
if (app instanceof IApplication)
tempResult = ((IApplication) app).start(this);
else
tempResult = EclipseAppContainer.callMethodWithException(app, "run", new Class[] {Object.class}, new Object[] {context}); //$NON-NLS-1$
if (tempResult == null)
tempResult = NULL_RESULT;
} finally {
tempResult = setInternalResult(tempResult, false, null);
}
if (Activator.DEBUG)
System.out.println(NLS.bind(Messages.application_returned, (new String[] {getApplicationDescriptor().getApplicationId(), tempResult == null ? "null" : tempResult.toString()}))); //$NON-NLS-1$
return tempResult;
}
private synchronized Object setInternalResult(Object result, boolean isAsync, IApplication tokenApp) {
if (setResult)
throw new IllegalStateException("The result of the application is already set."); //$NON-NLS-1$
if (isAsync) {
if (!setAsyncResult)
throw new IllegalStateException("The application must return IApplicationContext.EXIT_ASYNC_RESULT to set asynchronous results."); //$NON-NLS-1$
if (application != tokenApp)
throw new IllegalArgumentException("The application is not the correct instance for this application context."); //$NON-NLS-1$
} else {
if (result == IApplicationContext.EXIT_ASYNC_RESULT) {
setAsyncResult = true;
return NULL_RESULT; // the result well be set with setResult
}
}
this.result = result;
setResult = true;
application = null;
notifyAll();
// The application exited itself; notify the app context
setAppStatus(EclipseAppHandle.FLAG_STOPPING); // must ensure the STOPPING event is fired
setAppStatus(EclipseAppHandle.FLAG_STOPPED);
// only set the exit code property if this is the default application
// (bug 321386) only set the exit code if the result != null; when result == null we assume an exception was thrown
if (isDefault() && result != null) {
int exitCode = result instanceof Integer ? ((Integer) result).intValue() : 0;
// Use the EnvironmentInfo Service to set properties
Activator.setProperty(PROP_ECLIPSE_EXITCODE, Integer.toString(exitCode));
}
return result;
}
@Override
public void stop() {
try {
destroy();
} catch (IllegalStateException e) {
// Do nothing; we don't care that the application was already stopped
// return with no error
}
}
@Override
public void applicationRunning() {
// first set the application handle status to running
setAppStatus(EclipseAppHandle.FLAG_ACTIVE);
// now run the splash handler
final ServiceReference[] monitors = getStartupMonitors();
if (monitors == null)
return;
SafeRunner.run(new ISafeRunnable() {
@Override
public void handleException(Throwable e) {
// just continue ... the exception has already been logged by
// handleException(ISafeRunnable)
}
@Override
public void run() throws Exception {
for (ServiceReference m : monitors) {
StartupMonitor monitor = (StartupMonitor) Activator.getContext().getService(m);
if (monitor != null) {
monitor.applicationRunning();
Activator.getContext().ungetService(m);
}
}
}
});
}
private ServiceReference[] getStartupMonitors() {
// assumes theStartupMonitor is available as a service
// see EclipseStarter.publishSplashScreen
ServiceReference[] refs = null;
try {
refs = Activator.getContext().getServiceReferences(StartupMonitor.class.getName(), null);
} catch (InvalidSyntaxException e) {
// ignore; this cannot happen
}
if (refs == null || refs.length == 0)
return null;
// Implement our own Comparator to sort services
Arrays.sort(refs, new Comparator() {
@Override
public int compare(ServiceReference ref1, ServiceReference ref2) {
// sort in descending order
// sort based on service ranking first; highest rank wins
Object property = ref1.getProperty(Constants.SERVICE_RANKING);
int rank1 = (property instanceof Integer) ? ((Integer) property).intValue() : 0;
property = ref2.getProperty(Constants.SERVICE_RANKING);
int rank2 = (property instanceof Integer) ? ((Integer) property).intValue() : 0;
if (rank1 != rank2)
return rank1 > rank2 ? -1 : 1;
// rankings are equal; sort by id, lowest id wins
long id1 = ((Long) (ref1.getProperty(Constants.SERVICE_ID))).longValue();
long id2 = ((Long) (ref2.getProperty(Constants.SERVICE_ID))).longValue();
return id2 > id1 ? -1 : 1;
}
});
return refs;
}
private synchronized IApplication getApplication() {
if (handleRegistration != null && application == null)
// the handle has been initialized by the container but the launcher has not
// gotten around to creating the application object and starting it yet.
try {
wait(5000); // timeout after a while in case there was an internal error and there will be no application created
} catch (InterruptedException e) {
// do nothing
}
return (IApplication) ((application instanceof IApplication) ? application : null);
}
private IConfigurationElement getConfiguration() {
IExtension applicationExtension = ((EclipseAppDescriptor) getApplicationDescriptor()).getContainerManager().getAppExtension(getApplicationDescriptor().getApplicationId());
if (applicationExtension == null)
throw new RuntimeException(NLS.bind(Messages.application_notFound, getApplicationDescriptor().getApplicationId(), ((EclipseAppDescriptor) getApplicationDescriptor()).getContainerManager().getAvailableAppsMsg()));
IConfigurationElement[] configs = applicationExtension.getConfigurationElements();
if (configs.length == 0)
throw new RuntimeException(NLS.bind(Messages.application_invalidExtension, getApplicationDescriptor().getApplicationId()));
return configs[0];
}
@Override
public String getBrandingApplication() {
IBranding branding = ((EclipseAppDescriptor) getApplicationDescriptor()).getContainerManager().getBranding();
return branding == null ? null : branding.getApplication();
}
@Override
public Bundle getBrandingBundle() {
IBranding branding = ((EclipseAppDescriptor) getApplicationDescriptor()).getContainerManager().getBranding();
return branding == null ? null : branding.getDefiningBundle();
}
@Override
public String getBrandingDescription() {
IBranding branding = ((EclipseAppDescriptor) getApplicationDescriptor()).getContainerManager().getBranding();
return branding == null ? null : branding.getDescription();
}
@Override
public String getBrandingId() {
IBranding branding = ((EclipseAppDescriptor) getApplicationDescriptor()).getContainerManager().getBranding();
return branding == null ? null : branding.getId();
}
@Override
public String getBrandingName() {
IBranding branding = ((EclipseAppDescriptor) getApplicationDescriptor()).getContainerManager().getBranding();
return branding == null ? null : branding.getName();
}
@Override
public String getBrandingProperty(String key) {
IBranding branding = ((EclipseAppDescriptor) getApplicationDescriptor()).getContainerManager().getBranding();
return branding == null ? null : branding.getProperty(key);
}
boolean isDefault() {
return defaultAppInstance.booleanValue();
}
public synchronized Object waitForResult(int timeout) {
try {
return getExitValue(timeout);
} catch (ApplicationException | InterruptedException e) {
// return null
}
return null;
}
@Override
public synchronized Object getExitValue(long timeout) throws ApplicationException, InterruptedException {
if (handleRegistration == null && application == null)
return result;
long startTime = System.currentTimeMillis();
long delay = timeout;
while (!setResult && (delay > 0 || timeout == 0)) {
wait(delay); // only wait for the specified amount of time
if (timeout > 0)
delay -= (System.currentTimeMillis() - startTime);
}
if (result == null)
throw new ApplicationException(ApplicationException.APPLICATION_EXITVALUE_NOT_AVAILABLE);
if (result == NULL_RESULT)
return null;
return result;
}
@Override
public void setResult(Object result, IApplication application) {
setInternalResult(result == null ? NULL_RESULT : result, true, application);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy