| /******************************************************************************* |
| * Copyright (c) 2000, 2005 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.core.internal.registry; |
| |
| import java.util.Hashtable; |
| import org.eclipse.core.internal.runtime.InternalPlatform; |
| import org.eclipse.core.internal.runtime.Messages; |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.osgi.util.NLS; |
| import org.osgi.framework.Bundle; |
| |
| /** |
| * An object which represents the user-defined contents of an extension |
| * in a plug-in manifest. |
| */ |
| public class ConfigurationElement extends RegistryObject { |
| static final ConfigurationElement[] EMPTY_ARRAY = new ConfigurationElement[0]; |
| static final int PLUGIN_ERROR = 1; |
| |
| //The id of the parent element. It can be a configuration element or an extension |
| int parentId; |
| byte parentType; //This value is only interesting when running from cache. |
| |
| //Store the properties and the value of the configuration element. |
| //The format is the following: |
| // [p1, v1, p2, v2, configurationElementValue] |
| //If the array size is even, there is no "configurationElementValue (ie getValue returns null)". |
| //The properties and their values are alternated (v1 is the value of p1). |
| private String[] propertiesAndValue; |
| |
| //The name of the configuration element |
| private String name; |
| |
| //The bundle from which classes will be loaded. It is never a fragment |
| //This value can be null when the element is loaded from disk and the bundle has been uninstalled. |
| //This happens when the configuration is obtained from a delta containing removed extension. |
| private Bundle contributingBundle; |
| |
| ConfigurationElement() { |
| //Nothing to do |
| } |
| |
| ConfigurationElement(int self, Bundle bundle, String name, String[] propertiesAndValue, int[] children, int extraDataOffset, int parent, byte parentType) { |
| setObjectId(self); |
| contributingBundle = bundle; |
| this.name = name; |
| this.propertiesAndValue = propertiesAndValue; |
| setRawChildren(children); |
| this.extraDataOffset = extraDataOffset; |
| parentId = parent; |
| this.parentType = parentType; |
| } |
| |
| Object createExecutableExtension(String attributeName, boolean instantiate) throws CoreException { |
| String prop = null; |
| String executable; |
| String pluginName = null; |
| String className = null; |
| Object initData = null; |
| int i; |
| |
| if (attributeName != null) |
| prop = getAttribute(attributeName); |
| else { |
| // property not specified, try as element value |
| prop = getValue(); |
| if (prop != null) { |
| prop = prop.trim(); |
| if (prop.equals("")) //$NON-NLS-1$ |
| prop = null; |
| } |
| } |
| |
| if (prop == null) { |
| // property not defined, try as a child element |
| ConfigurationElement[] exec; |
| ConfigurationElement[] parms; |
| ConfigurationElement element; |
| Hashtable initParms; |
| String pname; |
| |
| exec = getChildren(attributeName); |
| if (exec.length != 0) { |
| element = exec[0]; // assumes single definition |
| pluginName = element.getAttribute("plugin"); //$NON-NLS-1$ |
| className = element.getAttribute("class"); //$NON-NLS-1$ |
| parms = element.getChildren("parameter"); //$NON-NLS-1$ |
| if (parms.length != 0) { |
| initParms = new Hashtable(parms.length + 1); |
| for (i = 0; i < parms.length; i++) { |
| pname = parms[i].getAttribute("name"); //$NON-NLS-1$ |
| if (pname != null) |
| initParms.put(pname, parms[i].getAttribute("value")); //$NON-NLS-1$ |
| } |
| if (!initParms.isEmpty()) |
| initData = initParms; |
| } |
| } |
| |
| // specified name is not a simple attribute nor child element |
| else { |
| String message = NLS.bind(Messages.plugin_extDefNotFound, attributeName); |
| IStatus status = new Status(IStatus.ERROR, Platform.PI_RUNTIME, PLUGIN_ERROR, message, null); |
| InternalPlatform.getDefault().getLog(InternalPlatform.getDefault().getBundleContext().getBundle()).log(status); |
| throw new CoreException(status); |
| } |
| } else { |
| // simple property or element value, parse it into its components |
| i = prop.indexOf(':'); |
| if (i != -1) { |
| executable = prop.substring(0, i).trim(); |
| initData = prop.substring(i + 1).trim(); |
| } else |
| executable = prop; |
| |
| i = executable.indexOf('/'); |
| if (i != -1) { |
| pluginName = executable.substring(0, i).trim(); |
| className = executable.substring(i + 1).trim(); |
| } else |
| className = executable; |
| } |
| |
| if (className == null || className.equals("")) { //$NON-NLS-1$ |
| String message = NLS.bind(Messages.plugin_extDefNoClass, attributeName); |
| IStatus status = new Status(IStatus.ERROR, Platform.PI_RUNTIME, PLUGIN_ERROR, message, null); |
| InternalPlatform.getDefault().getLog(InternalPlatform.getDefault().getBundleContext().getBundle()).log(status); |
| throw new CoreException(status); |
| } |
| |
| return createExecutableExtension(pluginName, className, initData, this, attributeName, instantiate); |
| } |
| |
| private Object createExecutableExtension(String pluginName, String className, Object initData, ConfigurationElement cfig, String propertyName, boolean instantiate) throws CoreException { |
| if(contributingBundle==null) { |
| throwException(NLS.bind(Messages.plugin_loadClassError, "UNKNOWN BUNDLE", className), new InvalidRegistryObjectException()); //$NON-NLS-1$ |
| } |
| String id = contributingBundle.getSymbolicName(); // this plugin id check if we need to delegate to some other plugin |
| if (pluginName != null && !pluginName.equals("") && !pluginName.equals(id)) { //$NON-NLS-1$ |
| Bundle otherBundle = null; |
| otherBundle = InternalPlatform.getDefault().getBundle(pluginName); |
| return createExecutableExtension(otherBundle, className, initData, cfig, propertyName, instantiate); |
| } |
| return createExecutableExtension(contributingBundle, className, initData, cfig, propertyName, instantiate); |
| } |
| |
| private Object createExecutableExtension(Bundle bundle, String className, Object initData, ConfigurationElement cfig, String propertyName, boolean instantiate) throws CoreException { |
| if(contributingBundle==null) { |
| throwException(NLS.bind(Messages.plugin_loadClassError, "UNKNOWN BUNDLE", className), new InvalidRegistryObjectException()); //$NON-NLS-1$ |
| } |
| // load the requested class from this plugin |
| Class classInstance = null; |
| try { |
| classInstance = bundle.loadClass(className); |
| } catch (Exception e1) { |
| throwException(NLS.bind(Messages.plugin_loadClassError, bundle.getSymbolicName(), className), e1); |
| } catch (LinkageError e) { |
| throwException(NLS.bind(Messages.plugin_loadClassError, bundle.getSymbolicName(), className), e); |
| } |
| |
| if (instantiate == false) |
| return classInstance; |
| |
| // create a new instance |
| Object result = null; |
| try { |
| result = classInstance.newInstance(); |
| } catch (Exception e) { |
| throwException(NLS.bind(Messages.plugin_instantiateClassError, bundle.getSymbolicName(), className), e); |
| } |
| |
| // check if we have extension adapter and initialize |
| if (result instanceof IExecutableExtension) { |
| try { |
| // make the call even if the initialization string is null |
| //TODO Need to change here the access to the registry manager |
| ((IExecutableExtension) result).setInitializationData(new ConfigurationElementHandle(((ExtensionRegistry)InternalPlatform.getDefault().getRegistry()).getObjectManager(),cfig.getObjectId()), propertyName, initData); |
| } catch (CoreException ce) { |
| // user code threw exception |
| InternalPlatform.getDefault().getLog(InternalPlatform.getDefault().getBundleContext().getBundle()).log(ce.getStatus()); |
| throw new CoreException(ce.getStatus()); |
| } catch (Exception te) { |
| // user code caused exception |
| throwException(NLS.bind(Messages.plugin_initObjectError, bundle.getSymbolicName(), className), te); |
| } |
| } |
| return result; |
| } |
| |
| Class loadExtensionClass(String propertyName) throws CoreException { |
| return (Class) createExecutableExtension(propertyName, false); |
| } |
| |
| private void throwException(String message, Throwable exception) throws CoreException { |
| IStatus status = new Status(IStatus.ERROR, Platform.PI_RUNTIME, PLUGIN_ERROR, message, exception); |
| InternalPlatform.getDefault().getLog(InternalPlatform.getDefault().getBundleContext().getBundle()).log(status); |
| throw new CoreException(status); |
| } |
| |
| String getValue() { |
| return getValueAsIs(); |
| } |
| |
| String getValueAsIs() { |
| if (propertiesAndValue.length != 0 && propertiesAndValue.length % 2 == 1) |
| return propertiesAndValue[propertiesAndValue.length - 1]; |
| return null; |
| } |
| |
| String getAttribute(String attrName) { |
| return getAttributeAsIs(attrName); |
| } |
| |
| String getAttributeAsIs(String attrName) { |
| if (propertiesAndValue.length <= 1) |
| return null; |
| int size = propertiesAndValue.length - (propertiesAndValue.length % 2); |
| for (int i = 0; i < size; i += 2) { |
| if (propertiesAndValue[i].equals(attrName)) |
| return propertiesAndValue[i + 1]; |
| } |
| return null; |
| } |
| |
| String[] getAttributeNames() { |
| if (propertiesAndValue.length <= 1) |
| return RegistryObjectManager.EMPTY_STRING_ARRAY; |
| |
| int size = propertiesAndValue.length / 2; |
| String[] result = new String[size]; |
| for (int i = 0; i < size; i++) { |
| result[i] = propertiesAndValue[i * 2]; |
| } |
| return result; |
| } |
| |
| void setProperties(String[] value) { |
| propertiesAndValue = value; |
| } |
| |
| String[] getPropertiesAndValue() { |
| return propertiesAndValue; |
| } |
| |
| void setValue(String value) { |
| if (propertiesAndValue.length == 0) { |
| propertiesAndValue = new String[] {value}; |
| return; |
| } |
| if (propertiesAndValue.length % 2 == 1) { |
| propertiesAndValue[propertiesAndValue.length - 1] = value; |
| return; |
| } |
| String[] newPropertiesAndValue = new String[propertiesAndValue.length + 1]; |
| System.arraycopy(propertiesAndValue, 0, newPropertiesAndValue, 0, propertiesAndValue.length); |
| newPropertiesAndValue[propertiesAndValue.length] = value; |
| propertiesAndValue = newPropertiesAndValue; |
| } |
| |
| void setContributingBundle(Bundle b) { |
| contributingBundle = b; |
| } |
| |
| Bundle getContributingBundle() { |
| return contributingBundle; |
| } |
| |
| ConfigurationElement[] getChildren(String childrenName) { |
| if (getRawChildren().length == 0) |
| return ConfigurationElement.EMPTY_ARRAY; |
| |
| ConfigurationElement[] result = new ConfigurationElement[1]; //Most of the time there is only one match |
| int idx = 0; |
| RegistryObjectManager objectManager = ((ExtensionRegistry)InternalPlatform.getDefault().getRegistry()).getObjectManager(); //TODO To change |
| for (int i = 0; i < children.length; i++) { |
| ConfigurationElement toTest = (ConfigurationElement) objectManager.getObject(children[i], extraDataOffset == -1 ? RegistryObjectManager.CONFIGURATION_ELEMENT : RegistryObjectManager.THIRDLEVEL_CONFIGURATION_ELEMENT); |
| if (toTest.name.equals(childrenName)) { |
| if (idx != 0) { |
| ConfigurationElement[] copy = new ConfigurationElement[result.length + 1]; |
| System.arraycopy(result, 0, copy, 0, result.length); |
| result = copy; |
| } |
| result[idx++] = toTest; |
| } |
| } |
| if (idx == 0) |
| result = ConfigurationElement.EMPTY_ARRAY; |
| return result; |
| } |
| |
| void setParentId(int objectId) { |
| parentId = objectId; |
| } |
| |
| String getName() { |
| return name; |
| } |
| |
| void setName(String name) { |
| this.name = name; |
| } |
| |
| void setParentType(byte type) { |
| parentType = type; |
| } |
| |
| String getNamespace() { |
| return contributingBundle == null ? null : contributingBundle.getSymbolicName(); |
| } |
| } |