/******************************************************************************* * 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$ } }