| /******************************************************************************* |
| * Copyright (c) 2004 Composent, Inc. 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: Composent, Inc. - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.ecf.internal.core; |
| |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.MissingResourceException; |
| import java.util.Properties; |
| import java.util.ResourceBundle; |
| import java.util.WeakHashMap; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.core.runtime.IExtension; |
| import org.eclipse.core.runtime.IExtensionDelta; |
| import org.eclipse.core.runtime.IExtensionPoint; |
| import org.eclipse.core.runtime.IExtensionRegistry; |
| import org.eclipse.core.runtime.ILog; |
| import org.eclipse.core.runtime.IRegistryChangeEvent; |
| import org.eclipse.core.runtime.IRegistryChangeListener; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.core.runtime.Plugin; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.ecf.core.ContainerFactory; |
| import org.eclipse.ecf.core.ContainerTypeDescription; |
| import org.eclipse.ecf.core.IContainerFactory; |
| import org.eclipse.ecf.core.provider.IContainerInstantiator; |
| import org.eclipse.ecf.core.start.ECFStartJob; |
| import org.eclipse.ecf.core.start.IECFStart; |
| import org.eclipse.ecf.core.util.Trace; |
| import org.osgi.framework.BundleContext; |
| |
| public class ECFPlugin extends Plugin { |
| |
| public static final String PLUGIN_ID = "org.eclipse.ecf"; |
| |
| private static final String ECFNAMESPACE = PLUGIN_ID; |
| |
| private static final String CONTAINER_FACTORY_NAME = "containerFactory"; |
| |
| private static final String CONTAINER_FACTORY_EPOINT = ECFNAMESPACE |
| + "." + CONTAINER_FACTORY_NAME; |
| |
| private static final String STARTUP_NAME = "startup"; |
| |
| public static final String START_EPOINT = ECFNAMESPACE + "." + STARTUP_NAME; |
| |
| public static final String PLUGIN_RESOURCE_BUNDLE = ECFNAMESPACE |
| + ".ECFPluginResources"; |
| |
| public static final String CLASS_ATTRIBUTE = "class"; |
| |
| public static final String NAME_ATTRIBUTE = "name"; |
| |
| public static final String DESCRIPTION_ATTRIBUTE = "description"; |
| |
| public static final String ARG_ELEMENT_NAME = "defaultargument"; |
| |
| public static final String VALUE_ATTRIBUTE = "value"; |
| |
| public static final String PROPERTY_ELEMENT_NAME = "property"; |
| |
| public static final int FACTORY_DOES_NOT_IMPLEMENT_ERRORCODE = 10; |
| |
| public static final int FACTORY_NAME_COLLISION_ERRORCODE = 20; |
| |
| public static final int INSTANTIATOR_DOES_NOT_IMPLEMENT_ERRORCODE = 30; |
| |
| public static final int INSTANTIATOR_NAME_COLLISION_ERRORCODE = 50; |
| |
| public static final int INSTANTIATOR_NAMESPACE_LOAD_ERRORCODE = 60; |
| |
| public static final int START_ERRORCODE = 70; |
| |
| protected static final int REMOVE_NAMESPACE_ERRORCODE = 80; |
| |
| // The shared instance. |
| private static ECFPlugin plugin; |
| |
| // Resource bundle. |
| private ResourceBundle resourceBundle; |
| |
| BundleContext bundlecontext = null; |
| |
| private Map disposables = new WeakHashMap(); |
| |
| private IRegistryChangeListener registryManager = null; |
| |
| public ECFPlugin() { |
| super(); |
| plugin = this; |
| try { |
| resourceBundle = ResourceBundle.getBundle(PLUGIN_RESOURCE_BUNDLE); |
| } catch (MissingResourceException x) { |
| resourceBundle = null; |
| } |
| } |
| |
| public void addDisposable(IDisposable disposable) { |
| disposables.put(disposable, null); |
| } |
| |
| public void removeDisposable(IDisposable disposable) { |
| disposables.remove(disposable); |
| } |
| |
| protected void fireDisposables() { |
| for (Iterator i = disposables.keySet().iterator(); i.hasNext();) { |
| IDisposable d = (IDisposable) i.next(); |
| if (d != null) |
| d.dispose(); |
| } |
| } |
| |
| public static void log(IStatus status) { |
| if (status == null) |
| return; |
| ILog log = plugin.getLog(); |
| if (log != null) |
| log.log(status); |
| else |
| System.err.println("No log output. Status Message: " |
| + status.getMessage()); |
| } |
| |
| protected String[] getDefaultArgs(IConfigurationElement[] argElements) { |
| String[] argDefaults = new String[0]; |
| if (argElements != null) { |
| if (argElements.length > 0) { |
| argDefaults = new String[argElements.length]; |
| for (int i = 0; i < argElements.length; i++) |
| argDefaults[i] = argElements[i] |
| .getAttribute(VALUE_ATTRIBUTE); |
| } |
| } |
| return argDefaults; |
| } |
| |
| protected Map getProperties(IConfigurationElement[] propertyElements) { |
| Properties props = new Properties(); |
| if (propertyElements != null) { |
| if (propertyElements.length > 0) { |
| for (int i = 0; i < propertyElements.length; i++) { |
| String name = propertyElements[i] |
| .getAttribute(NAME_ATTRIBUTE); |
| String value = propertyElements[i] |
| .getAttribute(VALUE_ATTRIBUTE); |
| if (name != null && !name.equals("") && value != null |
| && !value.equals("")) { |
| props.setProperty(name, value); |
| } |
| } |
| } |
| } |
| return props; |
| } |
| |
| protected void logException(IStatus status, String method, |
| Throwable exception) { |
| log(status); |
| Trace.catching(ECFPlugin.getDefault(), |
| ECFDebugOptions.EXCEPTIONS_CATCHING, ECFPlugin.class, method, |
| exception); |
| } |
| |
| /** |
| * Remove extensions for container factory extension point |
| * |
| * @param members |
| * the members to remove |
| */ |
| protected void removeContainerFactoryExtensions( |
| IConfigurationElement[] members) { |
| String method = "removeContainerFactoryExtensions"; |
| Trace.entering(ECFPlugin.getDefault(), |
| ECFDebugOptions.METHODS_ENTERING, ECFPlugin.class, method, |
| members); |
| // For each configuration element |
| for (int m = 0; m < members.length; m++) { |
| IConfigurationElement member = members[m]; |
| // Get the label of the extender plugin and the ID of the extension. |
| IExtension extension = member.getDeclaringExtension(); |
| String name = null; |
| try { |
| // Get name and get version, if available |
| name = member.getAttribute(NAME_ATTRIBUTE); |
| if (name == null) { |
| name = member.getAttribute(CLASS_ATTRIBUTE); |
| } |
| IContainerFactory factory = ContainerFactory.getDefault(); |
| ContainerTypeDescription cd = factory |
| .getDescriptionByName(name); |
| if (cd == null || !factory.containsDescription(cd)) { |
| continue; |
| } |
| // remove |
| factory.removeDescription(cd); |
| Trace.trace(ECFPlugin.getDefault(), ECFDebugOptions.DEBUG, |
| method + ".removed " + cd + " from factory"); |
| } catch (Exception e) { |
| logException( |
| new Status( |
| Status.ERROR, |
| getDefault().getBundle().getSymbolicName(), |
| FACTORY_NAME_COLLISION_ERRORCODE, |
| getResourceString("ExtPointError.ContainerNameCollisionPrefix") |
| + name |
| + getResourceString("ExtPointError.ContainerNameCollisionSuffix") |
| + extension |
| .getExtensionPointUniqueIdentifier(), |
| null), method, e); |
| } |
| } |
| } |
| |
| /** |
| * Add container factory extension point extensions |
| * |
| * @param members |
| * to add |
| */ |
| protected void addContainerFactoryExtensions(IConfigurationElement[] members) { |
| String method = "addContainerFactoryExtensions"; |
| Trace.entering(ECFPlugin.getDefault(), |
| ECFDebugOptions.METHODS_ENTERING, ECFPlugin.class, method, |
| members); |
| // For each configuration element |
| for (int m = 0; m < members.length; m++) { |
| IConfigurationElement member = members[m]; |
| // Get the label of the extender plugin and the ID of the extension. |
| IExtension extension = member.getDeclaringExtension(); |
| Object exten = null; |
| String name = null; |
| try { |
| // The only required attribute is "class" |
| exten = member.createExecutableExtension(CLASS_ATTRIBUTE); |
| String clazz = exten.getClass().getName(); |
| // Get name and get version, if available |
| name = member.getAttribute(NAME_ATTRIBUTE); |
| if (name == null) { |
| name = clazz; |
| } |
| // Get description, if present |
| String description = member.getAttribute(DESCRIPTION_ATTRIBUTE); |
| if (description == null) { |
| description = ""; |
| } |
| // Get any arguments |
| String[] defaults = getDefaultArgs(member |
| .getChildren(ARG_ELEMENT_NAME)); |
| // Get any property elements |
| Map properties = getProperties(member |
| .getChildren(PROPERTY_ELEMENT_NAME)); |
| // Now make description instance |
| ContainerTypeDescription scd = new ContainerTypeDescription( |
| name, (IContainerInstantiator) exten, description, |
| defaults, properties); |
| IContainerFactory factory = ContainerFactory.getDefault(); |
| if (factory.containsDescription(scd)) { |
| throw new CoreException( |
| new Status( |
| Status.ERROR, |
| getDefault().getBundle().getSymbolicName(), |
| FACTORY_NAME_COLLISION_ERRORCODE, |
| getResourceString("ExtPointError.ContainerNameCollisionPrefix") |
| + name |
| + getResourceString("ExtPointError.ContainerNameCollisionSuffix") |
| + extension |
| .getExtensionPointUniqueIdentifier(), |
| null)); |
| } |
| // Now add the description and we're ready to go. |
| factory.addDescription(scd); |
| Trace.trace(ECFPlugin.getDefault(), ECFDebugOptions.DEBUG, |
| method + ".added " + scd + " to factory " + factory); |
| } catch (CoreException e) { |
| logException(e.getStatus(), method, e); |
| } catch (Exception e) { |
| logException( |
| new Status( |
| Status.ERROR, |
| getDefault().getBundle().getSymbolicName(), |
| FACTORY_NAME_COLLISION_ERRORCODE, |
| getResourceString("ExtPointError.ContainerNameCollisionPrefix") |
| + name |
| + getResourceString("ExtPointError.ContainerNameCollisionSuffix") |
| + extension |
| .getExtensionPointUniqueIdentifier(), |
| null), method, e); |
| } |
| } |
| } |
| |
| /** |
| * Setup container factory extension point |
| * |
| * @param context |
| * the BundleContext for this bundle |
| */ |
| protected void setupContainerFactoryExtensionPoint(BundleContext bc) { |
| IExtensionRegistry reg = Platform.getExtensionRegistry(); |
| IExtensionPoint extensionPoint = reg |
| .getExtensionPoint(CONTAINER_FACTORY_EPOINT); |
| if (extensionPoint == null) { |
| return; |
| } |
| addContainerFactoryExtensions(extensionPoint.getConfigurationElements()); |
| } |
| |
| /** |
| * Setup start extension point |
| * |
| * @param bc |
| * the BundleContext fro this bundle |
| */ |
| protected void setupStartExtensionPoint(BundleContext bc) { |
| IExtensionRegistry reg = Platform.getExtensionRegistry(); |
| IExtensionPoint extensionPoint = reg.getExtensionPoint(START_EPOINT); |
| if (extensionPoint == null) { |
| return; |
| } |
| runStartExtensions(extensionPoint.getConfigurationElements()); |
| } |
| |
| protected void runStartExtensions( |
| IConfigurationElement[] configurationElements) { |
| String method = "runStartExtensions"; |
| // For each configuration element |
| for (int m = 0; m < configurationElements.length; m++) { |
| IConfigurationElement member = configurationElements[m]; |
| IECFStart exten = null; |
| String name = null; |
| try { |
| // The only required attribute is "class" |
| exten = (IECFStart) member |
| .createExecutableExtension(CLASS_ATTRIBUTE); |
| // Get name and get version, if available |
| name = member.getAttribute(NAME_ATTRIBUTE); |
| if (name == null) |
| name = exten.getClass().getName(); |
| startExtension(name, exten); |
| } catch (CoreException e) { |
| logException(e.getStatus(), method, e); |
| } catch (Exception e) { |
| logException(new Status(Status.ERROR, getDefault().getBundle() |
| .getSymbolicName(), START_ERRORCODE, |
| "Unknown start exception", e), method, e); |
| } |
| } |
| } |
| |
| private void startExtension(String name, IECFStart exten) { |
| // Create job to do start, and schedule |
| ECFStartJob job = new ECFStartJob(name, exten); |
| job.schedule(); |
| } |
| |
| /** |
| * This method is called upon plug-in activation |
| */ |
| public void start(BundleContext context) throws Exception { |
| super.start(context); |
| this.bundlecontext = context; |
| this.registryManager = new ECFRegistryManager(); |
| Platform.getExtensionRegistry().addRegistryChangeListener( |
| registryManager); |
| setupContainerFactoryExtensionPoint(context); |
| setupStartExtensionPoint(context); |
| } |
| |
| protected class ECFRegistryManager implements IRegistryChangeListener { |
| public void registryChanged(IRegistryChangeEvent event) { |
| IExtensionDelta delta[] = event.getExtensionDeltas(ECFNAMESPACE, |
| CONTAINER_FACTORY_NAME); |
| for (int i = 0; i < delta.length; i++) { |
| switch (delta[i].getKind()) { |
| case IExtensionDelta.ADDED: |
| addContainerFactoryExtensions(delta[i].getExtension() |
| .getConfigurationElements()); |
| break; |
| case IExtensionDelta.REMOVED: |
| removeContainerFactoryExtensions(delta[i].getExtension() |
| .getConfigurationElements()); |
| break; |
| } |
| } |
| } |
| } |
| |
| /** |
| * This method is called when the plug-in is stopped |
| */ |
| public void stop(BundleContext context) throws Exception { |
| super.stop(context); |
| fireDisposables(); |
| this.disposables = null; |
| this.bundlecontext = null; |
| Platform.getExtensionRegistry().removeRegistryChangeListener( |
| registryManager); |
| this.registryManager = null; |
| } |
| |
| /** |
| * Returns the shared instance. |
| */ |
| public static ECFPlugin getDefault() { |
| return plugin; |
| } |
| |
| /** |
| * Returns the string from the plugin's resource bundle, or 'key' if not |
| * found. |
| */ |
| public static String getResourceString(String key) { |
| ResourceBundle bundle = ECFPlugin.getDefault().getResourceBundle(); |
| try { |
| return (bundle != null) ? bundle.getString(key) : "!" + key + "!"; |
| } catch (MissingResourceException e) { |
| return "!" + key + "!"; |
| } |
| } |
| |
| /** |
| * Returns the plugin's resource bundle, |
| */ |
| public ResourceBundle getResourceBundle() { |
| return resourceBundle; |
| } |
| } |