blob: ecc0983865ad397fdddff54315b7e8d7877ef89e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2007 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.equinox.internal.app;
import java.net.URL;
import java.security.AccessController;
import java.util.*;
import org.eclipse.equinox.app.IApplicationContext;
import org.osgi.framework.Bundle;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.application.*;
import org.osgi.service.condpermadmin.BundleSignerCondition;
import org.osgi.service.condpermadmin.ConditionInfo;
/*
* An ApplicationDescriptor for an eclipse application.
*/
public class EclipseAppDescriptor extends ApplicationDescriptor {
static final String APP_TYPE = "eclipse.application.type"; //$NON-NLS-1$
static final String APP_DEFAULT = "eclipse.application.default"; //$NON-NLS-1$
static final String APP_TYPE_MAIN_THREAD = "main.thread"; //$NON-NLS-1$
static final String APP_TYPE_ANY_THREAD = "any.thread"; //$NON-NLS-1$
static final int FLAG_VISIBLE = 0x01;
static final int FLAG_CARD_SINGLETON_GLOGAL = 0x02;
static final int FLAG_CARD_SINGLETON_SCOPED = 0x04;
static final int FLAG_CARD_UNLIMITED = 0x08;
static final int FLAG_CARD_LIMITED = 0x10;
static final int FLAG_TYPE_MAIN_THREAD = 0x20;
static final int FLAG_TYPE_ANY_THREAD = 0x40;
static final int FLAG_DEFAULT_APP = 0x80;
private long instanceID = 0;
private ServiceRegistration sr;
private Boolean locked = Boolean.FALSE;
private final EclipseAppContainer appContainer;
private final Bundle contributor;
private final int flags;
private final int cardinality;
private final String name;
private final URL iconURL;
private final boolean[] registrationLock = new boolean[] {true};
protected EclipseAppDescriptor(Bundle contributor, String pid, String name, String iconPath, int flags, int cardinality, EclipseAppContainer appContainer) {
super(pid);
this.name = name;
this.contributor = contributor;
this.appContainer = appContainer;
this.locked = AppPersistence.isLocked(this) ? Boolean.TRUE : Boolean.FALSE;
this.flags = flags;
this.cardinality = cardinality;
URL iconResult = null;
// this bit of code is complex because we want to search fragments;
// that can only be done by using the Bundle.findEntries method which
// requires the path to be split up between the base and the file name!!
if (iconPath != null && iconPath.length() > 0) {
if (iconPath.charAt(0) == '/')
iconPath = iconPath.substring(1);
String baseIconDir = "/"; //$NON-NLS-1$
String iconFile = iconPath;
int lastSlash = iconPath.lastIndexOf('/');
if (lastSlash > 0 && lastSlash < iconPath.length() - 1) {
baseIconDir = iconPath.substring(0, lastSlash);
iconFile = iconPath.substring(lastSlash + 1);
}
Enumeration urls = contributor.findEntries(baseIconDir, iconFile, false);
if (urls != null && urls.hasMoreElements())
iconResult = (URL) urls.nextElement();
}
this.iconURL = iconResult;
}
protected Map getPropertiesSpecific(String locale) {
// just use the service properties; for now we do not localize any properties
return getServiceProperties();
}
protected ApplicationHandle launchSpecific(Map arguments) throws Exception {
// if this application is locked throw an exception.
if (getLocked().booleanValue())
throw new IllegalStateException("Cannot launch a locked application."); //$NON-NLS-1$
// initialize the appHandle
EclipseAppHandle appHandle = createAppHandle(arguments);
try {
// use the appContainer to launch the application on the main thread.
appContainer.launch(appHandle);
} catch (Throwable t) {
// be sure to destroy the appHandle if an error occurs
try {
appHandle.destroy();
} catch (Throwable destroyError) {
// ignore and clean up
}
if (t instanceof Exception)
throw (Exception) t;
throw (Error) t;
}
return appHandle;
}
protected synchronized void lockSpecific() {
locked = Boolean.TRUE;
// make sure the service properties are updated with the latest lock info
refreshProperties();
}
protected synchronized void unlockSpecific() {
locked = Boolean.FALSE;
// make sure the service properties are updated with the latest lock info
refreshProperties();
}
void refreshProperties() {
ServiceRegistration reg = getServiceRegistration();
if (reg != null)
try {
reg.setProperties(getServiceProperties());
} catch (IllegalStateException e) {
// this must mean the service was unregistered
// just ignore
}
}
void setServiceRegistration(ServiceRegistration sr) {
synchronized (registrationLock) {
this.sr = sr;
registrationLock[0] = sr != null;
registrationLock.notifyAll();
}
}
private ServiceRegistration getServiceRegistration() {
synchronized (registrationLock) {
if (sr == null && registrationLock[0])
try {
registrationLock.wait(1000); // timeout after 1 second
} catch (InterruptedException e) {
// nothing
}
return sr;
}
}
private synchronized Boolean getLocked() {
return locked;
}
/*
* Gets a snapshot of the current service properties.
*/
Hashtable getServiceProperties() {
Hashtable props = new Hashtable(10);
props.put(ApplicationDescriptor.APPLICATION_PID, getApplicationId());
if (name != null)
props.put(ApplicationDescriptor.APPLICATION_NAME, name);
props.put(ApplicationDescriptor.APPLICATION_CONTAINER, Activator.PI_APP);
props.put(ApplicationDescriptor.APPLICATION_LOCATION, getLocation());
Boolean launchable = appContainer.isLocked(this) == 0 ? Boolean.TRUE : Boolean.FALSE;
props.put(ApplicationDescriptor.APPLICATION_LAUNCHABLE, launchable);
props.put(ApplicationDescriptor.APPLICATION_LOCKED, getLocked());
Boolean visible = (flags & FLAG_VISIBLE) != 0 ? Boolean.TRUE : Boolean.FALSE;
props.put(ApplicationDescriptor.APPLICATION_VISIBLE, visible);
props.put(APP_TYPE, getThreadTypeString());
if ((flags & FLAG_DEFAULT_APP) != 0)
props.put(APP_DEFAULT, Boolean.TRUE);
if (iconURL != null)
props.put(ApplicationDescriptor.APPLICATION_ICON, iconURL);
return props;
}
private String getLocation() {
if (contributor == null)
return ""; //$NON-NLS-1$
return Activator.getLocation(contributor);
}
/*
* Returns the appHandle. If it does not exist then one is created.
*/
private EclipseAppHandle createAppHandle(Map arguments) throws ApplicationException {
EclipseAppHandle newAppHandle = new EclipseAppHandle(getInstanceID(), arguments, this);
appContainer.lock(newAppHandle);
ServiceRegistration appHandleReg = (ServiceRegistration) AccessController.doPrivileged(appContainer.getRegServiceAction(new String[] {ApplicationHandle.class.getName(), IApplicationContext.class.getName()}, newAppHandle, newAppHandle.getServiceProperties()));
newAppHandle.setServiceRegistration(appHandleReg);
return newAppHandle;
}
EclipseAppContainer getContainerManager() {
return appContainer;
}
public boolean matchDNChain(String pattern) {
if (contributor == null)
return false;
return BundleSignerCondition.getCondition(contributor, new ConditionInfo(BundleSignerCondition.class.getName(), new String[] {pattern})).isSatisfied();
}
protected boolean isLaunchableSpecific() {
return true;
}
public void unregister() {
ServiceRegistration temp = getServiceRegistration();
if (temp != null) {
setServiceRegistration(null);
temp.unregister();
}
}
String getThreadTypeString() {
if ((flags & FLAG_TYPE_ANY_THREAD) != 0)
return APP_TYPE_ANY_THREAD;
return APP_TYPE_MAIN_THREAD;
}
int getThreadType() {
return flags & (FLAG_TYPE_ANY_THREAD | FLAG_TYPE_MAIN_THREAD);
}
int getCardinalityType() {
return flags & (FLAG_CARD_SINGLETON_GLOGAL | FLAG_CARD_SINGLETON_SCOPED | FLAG_CARD_LIMITED | FLAG_CARD_UNLIMITED);
}
int getCardinality() {
return cardinality;
}
private synchronized String getInstanceID() {
// make sure the instanceID has not reached the max
if (instanceID == Long.MAX_VALUE)
instanceID = 0;
// create a unique instance id
return getApplicationId() + "." + instanceID++; //$NON-NLS-1$
}
}