org.eclipse.core.internal.registry.ExtensionsParser 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
AspectJ tools most notably contains the AspectJ compiler (AJC). AJC applies aspects to Java classes during
compilation, fully replacing Javac for plain Java classes and also compiling native AspectJ or annotation-based
@AspectJ syntax. Furthermore, AJC can weave aspects into existing class files in a post-compile binary weaving step.
This library is a superset of AspectJ weaver and hence also of AspectJ runtime.
/*******************************************************************************
* Copyright (c) 2000, 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
*******************************************************************************/
package org.eclipse.core.internal.registry;
import java.io.IOException;
import java.util.*;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import org.eclipse.core.runtime.*;
import org.eclipse.osgi.util.NLS;
import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;
public class ExtensionsParser extends DefaultHandler {
// Introduced for backward compatibility
private final static String NO_EXTENSION_MUNGING = "eclipse.noExtensionMunging"; //$NON-NLS-1$ //System property
private static final String VERSION_3_0 = "3.0"; //$NON-NLS-1$
private static final String VERSION_3_2 = "3.2"; //$NON-NLS-1$
private static Map extensionPointMap;
static {
initializeExtensionPointMap();
}
/**
* Initialize the list of renamed extension point ids
*/
private static void initializeExtensionPointMap() {
Map map = new HashMap<>(13);
map.put("org.eclipse.ui.markerImageProvider", "org.eclipse.ui.ide.markerImageProvider"); //$NON-NLS-1$ //$NON-NLS-2$
map.put("org.eclipse.ui.markerHelp", "org.eclipse.ui.ide.markerHelp"); //$NON-NLS-1$ //$NON-NLS-2$
map.put("org.eclipse.ui.markerImageProviders", "org.eclipse.ui.ide.markerImageProviders"); //$NON-NLS-1$ //$NON-NLS-2$
map.put("org.eclipse.ui.markerResolution", "org.eclipse.ui.ide.markerResolution"); //$NON-NLS-1$ //$NON-NLS-2$
map.put("org.eclipse.ui.projectNatureImages", "org.eclipse.ui.ide.projectNatureImages"); //$NON-NLS-1$ //$NON-NLS-2$
map.put("org.eclipse.ui.resourceFilters", "org.eclipse.ui.ide.resourceFilters"); //$NON-NLS-1$ //$NON-NLS-2$
map.put("org.eclipse.ui.markerUpdaters", "org.eclipse.ui.editors.markerUpdaters"); //$NON-NLS-1$ //$NON-NLS-2$
map.put("org.eclipse.ui.documentProviders", "org.eclipse.ui.editors.documentProviders"); //$NON-NLS-1$ //$NON-NLS-2$
map.put("org.eclipse.ui.workbench.texteditor.markerAnnotationSpecification", "org.eclipse.ui.editors.markerAnnotationSpecification"); //$NON-NLS-1$ //$NON-NLS-2$
map.put("org.eclipse.help.browser", "org.eclipse.help.base.browser"); //$NON-NLS-1$ //$NON-NLS-2$
map.put("org.eclipse.help.luceneAnalyzer", "org.eclipse.help.base.luceneAnalyzer"); //$NON-NLS-1$ //$NON-NLS-2$
map.put("org.eclipse.help.webapp", "org.eclipse.help.base.webapp"); //$NON-NLS-1$ //$NON-NLS-2$
map.put("org.eclipse.help.support", "org.eclipse.ui.helpSupport"); //$NON-NLS-1$ //$NON-NLS-2$
extensionPointMap = map;
}
private static long cumulativeTime = 0;
// is in compatibility mode
private boolean compatibilityMode;
// File name for this extension manifest
// This to help with error reporting
private String locationName = null;
// Current State Information
private final Stack stateStack = new Stack<>();
// Current object stack (used to hold the current object we are
// populating in this plugin descriptor
private final Stack objectStack = new Stack<>();
private String schemaVersion = null;
// A status for holding results.
private final MultiStatus status;
// Owning extension registry
private final ExtensionRegistry registry;
// Resource bundle used to translate the content of the plugin.xml
protected ResourceBundle resources;
// Keep track of the object encountered.
private RegistryObjectManager objectManager;
private Contribution contribution;
//This keeps tracks of the value of the configuration element in case the value comes in several pieces (see characters()). See as well bug 75592.
private String configurationElementValue;
/**
* Status code constant (value 1) indicating a problem in a bundle extensions
* manifest (extensions.xml
) file.
*/
public static final int PARSE_PROBLEM = 1;
public static final String PLUGIN = "plugin"; //$NON-NLS-1$
public static final String PLUGIN_ID = "id"; //$NON-NLS-1$
public static final String PLUGIN_NAME = "name"; //$NON-NLS-1$
public static final String FRAGMENT = "fragment"; //$NON-NLS-1$
public static final String BUNDLE_UID = "id"; //$NON-NLS-1$
public static final String EXTENSION_POINT = "extension-point"; //$NON-NLS-1$
public static final String EXTENSION_POINT_NAME = "name"; //$NON-NLS-1$
public static final String EXTENSION_POINT_ID = "id"; //$NON-NLS-1$
public static final String EXTENSION_POINT_SCHEMA = "schema"; //$NON-NLS-1$
public static final String EXTENSION = "extension"; //$NON-NLS-1$
public static final String EXTENSION_NAME = "name"; //$NON-NLS-1$
public static final String EXTENSION_ID = "id"; //$NON-NLS-1$
public static final String EXTENSION_TARGET = "point"; //$NON-NLS-1$
public static final String ELEMENT = "element"; //$NON-NLS-1$
public static final String ELEMENT_NAME = "name"; //$NON-NLS-1$
public static final String ELEMENT_VALUE = "value"; //$NON-NLS-1$
public static final String PROPERTY = "property"; //$NON-NLS-1$
public static final String PROPERTY_NAME = "name"; //$NON-NLS-1$
public static final String PROPERTY_VALUE = "value"; //$NON-NLS-1$
// Valid States
private static final int IGNORED_ELEMENT_STATE = 0;
private static final int INITIAL_STATE = 1;
private static final int BUNDLE_STATE = 2;
private static final int BUNDLE_EXTENSION_POINT_STATE = 5;
private static final int BUNDLE_EXTENSION_STATE = 6;
private static final int CONFIGURATION_ELEMENT_STATE = 10;
// Keep a group of vectors as a temporary scratch space. These
// vectors will be used to populate arrays in the bundle model
// once processing of the XML file is complete.
private static final int EXTENSION_POINT_INDEX = 0;
private static final int EXTENSION_INDEX = 1;
private static final int LAST_INDEX = 1;
@SuppressWarnings("unchecked")
private final ArrayList scratchVectors[] = new ArrayList[LAST_INDEX + 1];
private Locator locator = null;
// Cache the behavior toggle (true: attempt to extract namespace from qualified IDs)
private boolean extractNamespaces = false;
private ArrayList processedExtensionIds = null;
// Keep track of elements added into the registry manager in case we encounter a error
// and need to rollback
private final ArrayList addedRegistryObjects = new ArrayList<>(5);
public ExtensionsParser(MultiStatus status, ExtensionRegistry registry) {
super();
this.status = status;
this.registry = registry;
}
/* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#setDocumentLocator(org.xml.sax.Locator)
*/
@Override
public void setDocumentLocator(Locator locator) {
this.locator = locator;
}
/* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
*/
@Override
public void characters(char[] ch, int start, int length) {
int state = stateStack.peek().intValue();
if (state != CONFIGURATION_ELEMENT_STATE)
return;
if (state == CONFIGURATION_ELEMENT_STATE) {
// Accept character data within an element, is when it is
// part of a configuration element (i.e. an element within an EXTENSION element
ConfigurationElement currentConfigElement = (ConfigurationElement) objectStack.peek();
String value = new String(ch, start, length);
if (configurationElementValue == null) {
if (value.trim().length() != 0) {
configurationElementValue = value;
}
} else {
configurationElementValue = configurationElementValue + value;
}
if (configurationElementValue != null)
currentConfigElement.setValue(configurationElementValue);
}
}
/* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#endDocument()
*/
@Override
public void endDocument() {
// do nothing
}
/* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
*/
@Override
public void endElement(String uri, String elementName, String qName) {
switch (stateStack.peek().intValue()) {
case IGNORED_ELEMENT_STATE :
stateStack.pop();
break;
case INITIAL_STATE :
// shouldn't get here
internalError(NLS.bind(RegistryMessages.parse_internalStack, elementName));
break;
case BUNDLE_STATE :
stateStack.pop();
ArrayList extensionPoints = scratchVectors[EXTENSION_POINT_INDEX];
ArrayList extensions = scratchVectors[EXTENSION_INDEX];
int[] namespaceChildren = new int[2 + extensionPoints.size() + extensions.size()];
int position = 2;
// Put the extension points into this namespace
if (extensionPoints.size() > 0) {
namespaceChildren[Contribution.EXTENSION_POINT] = extensionPoints.size();
for (Object extPoint : extensionPoints) {
namespaceChildren[position++] = ((RegistryObject) extPoint).getObjectId();
}
extensionPoints.clear();
}
// Put the extensions into this namespace too
if (extensions.size() > 0) {
Extension[] renamedExtensions = fixRenamedExtensionPoints(extensions.toArray(new Extension[extensions.size()]));
namespaceChildren[Contribution.EXTENSION] = renamedExtensions.length;
for (Extension renamedExtension : renamedExtensions) {
namespaceChildren[position++] = renamedExtension.getObjectId();
}
extensions.clear();
}
contribution.setRawChildren(namespaceChildren);
break;
case BUNDLE_EXTENSION_POINT_STATE :
if (elementName.equals(EXTENSION_POINT)) {
stateStack.pop();
}
break;
case BUNDLE_EXTENSION_STATE :
if (elementName.equals(EXTENSION)) {
stateStack.pop();
// Finish up extension object
Extension currentExtension = (Extension) objectStack.pop();
if (currentExtension.getNamespaceIdentifier() == null)
currentExtension.setNamespaceIdentifier(contribution.getDefaultNamespace());
currentExtension.setContributorId(contribution.getContributorId());
scratchVectors[EXTENSION_INDEX].add(currentExtension);
}
break;
case CONFIGURATION_ELEMENT_STATE :
// We don't care what the element name was
stateStack.pop();
// Now finish up the configuration element object
configurationElementValue = null;
ConfigurationElement currentConfigElement = (ConfigurationElement) objectStack.pop();
String value = currentConfigElement.getValueAsIs();
if (value != null) {
currentConfigElement.setValue(translate(value).trim());
}
RegistryObject parent = (RegistryObject) objectStack.peek();
// Want to add this configuration element to the subelements of an extension
int[] oldValues = parent.getRawChildren();
int size = oldValues.length;
int[] newValues = new int[size + 1];
for (int i = 0; i < size; i++) {
newValues[i] = oldValues[i];
}
newValues[size] = currentConfigElement.getObjectId();
parent.setRawChildren(newValues);
currentConfigElement.setParentId(parent.getObjectId());
currentConfigElement.setParentType(parent instanceof ConfigurationElement ? RegistryObjectManager.CONFIGURATION_ELEMENT : RegistryObjectManager.EXTENSION);
break;
}
}
/* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#error(org.xml.sax.SAXParseException)
*/
@Override
public void error(SAXParseException ex) {
logStatus(ex);
}
/* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#fatalError(org.xml.sax.SAXParseException)
*/
@Override
public void fatalError(SAXParseException ex) throws SAXException {
cleanup();
logStatus(ex);
throw ex;
}
/**
* Remove all elements that we have added so far into registry manager
*/
private void cleanup() {
for (RegistryObject object : addedRegistryObjects) {
if (object instanceof ExtensionPoint) {
String id = ((ExtensionPoint) object).getUniqueIdentifier();
objectManager.removeExtensionPoint(id);
} else
objectManager.remove(object.getObjectId(), true);
}
}
private void handleExtensionPointState(String elementName) {
// We ignore all elements under extension points (if there are any)
stateStack.push(Integer.valueOf(IGNORED_ELEMENT_STATE));
unknownElement(EXTENSION_POINT, elementName);
}
private void handleExtensionState(String elementName, Attributes attributes) {
// You need to change the state here even though we will be executing the same
// code for ExtensionState and ConfigurationElementState. We ignore the name
// of the element for ConfigurationElements. When we are wrapping up, we will
// want to add each configuration element object to the subElements vector of
// its parent configuration element object. However, the first configuration
// element object we created (the last one we pop off the stack) will need to
// be added to a vector in the extension object called _configuration.
stateStack.push(Integer.valueOf(CONFIGURATION_ELEMENT_STATE));
configurationElementValue = null;
// create a new Configuration Element and push it onto the object stack
ConfigurationElement currentConfigurationElement = registry.getElementFactory().createConfigurationElement(contribution.shouldPersist());
currentConfigurationElement.setContributorId(contribution.getContributorId());
objectStack.push(currentConfigurationElement);
currentConfigurationElement.setName(elementName);
// Processing the attributes of a configuration element involves creating
// a new configuration property for each attribute and populating the configuration
// property with the name/value pair of the attribute. Note there will be one
// configuration property for each attribute
parseConfigurationElementAttributes(attributes);
objectManager.add(currentConfigurationElement, true);
addedRegistryObjects.add(currentConfigurationElement);
}
private void handleInitialState(String elementName, Attributes attributes) {
// new manifests should have the plugin (or fragment) element empty
// in compatibility mode, any extraneous elements will be silently ignored
compatibilityMode = attributes.getLength() > 0;
stateStack.push(Integer.valueOf(BUNDLE_STATE));
objectStack.push(contribution);
}
private void handleBundleState(String elementName, Attributes attributes) {
if (elementName.equals(EXTENSION_POINT)) {
stateStack.push(Integer.valueOf(BUNDLE_EXTENSION_POINT_STATE));
parseExtensionPointAttributes(attributes);
return;
}
if (elementName.equals(EXTENSION)) {
stateStack.push(Integer.valueOf(BUNDLE_EXTENSION_STATE));
parseExtensionAttributes(attributes);
return;
}
// If we get to this point, the element name is one we don't currently accept.
// Set the state to indicate that this element will be ignored
stateStack.push(Integer.valueOf(IGNORED_ELEMENT_STATE));
if (!compatibilityMode)
unknownElement(PLUGIN, elementName);
}
private void logStatus(SAXParseException ex) {
String name = ex.getSystemId();
if (name == null)
name = locationName;
if (name == null)
name = ""; //$NON-NLS-1$
else
name = name.substring(1 + name.lastIndexOf("/")); //$NON-NLS-1$
String msg;
if (name.equals("")) //$NON-NLS-1$
msg = NLS.bind(RegistryMessages.parse_error, ex.getMessage());
else
msg = NLS.bind(RegistryMessages.parse_errorNameLineColumn, (new Object[] {name, Integer.toString(ex.getLineNumber()), Integer.toString(ex.getColumnNumber()), ex.getMessage()}));
error(new Status(IStatus.WARNING, RegistryMessages.OWNER_NAME, PARSE_PROBLEM, msg, ex));
}
public Contribution parseManifest(SAXParserFactory factory, InputSource in, String manifestName, RegistryObjectManager registryObjects, Contribution currentNamespace, ResourceBundle bundle) throws ParserConfigurationException, SAXException, IOException {
long start = 0;
this.resources = bundle;
this.objectManager = registryObjects;
//initialize the parser with this object
this.contribution = currentNamespace;
if (registry.debug())
start = System.currentTimeMillis();
if (factory == null)
throw new SAXException(RegistryMessages.parse_xmlParserNotAvailable);
try {
locationName = in.getSystemId();
if (locationName == null)
locationName = manifestName;
factory.setNamespaceAware(true);
try {
factory.setFeature("http://xml.org/sax/features/string-interning", true); //$NON-NLS-1$
} catch (SAXException se) {
// ignore; we can still operate without string-interning
}
factory.setValidating(false);
factory.newSAXParser().parse(in, this);
return (Contribution) objectStack.pop();
} finally {
if (registry.debug()) {
cumulativeTime = cumulativeTime + (System.currentTimeMillis() - start);
System.out.println("Cumulative parse time so far : " + cumulativeTime); //$NON-NLS-1$
}
}
}
private void parseConfigurationElementAttributes(Attributes attributes) {
ConfigurationElement parentConfigurationElement = (ConfigurationElement) objectStack.peek();
// process attributes
int len = (attributes != null) ? attributes.getLength() : 0;
if (len == 0) {
parentConfigurationElement.setProperties(RegistryObjectManager.EMPTY_STRING_ARRAY);
return;
}
String[] properties = new String[len * 2];
for (int i = 0; i < len; i++) {
properties[i * 2] = attributes.getLocalName(i);
properties[i * 2 + 1] = translate(attributes.getValue(i));
}
parentConfigurationElement.setProperties(properties);
properties = null;
}
private void parseExtensionAttributes(Attributes attributes) {
Extension currentExtension = registry.getElementFactory().createExtension(contribution.shouldPersist());
objectStack.push(currentExtension);
String simpleId = null;
String namespaceName = null;
// Process Attributes
int len = (attributes != null) ? attributes.getLength() : 0;
for (int i = 0; i < len; i++) {
String attrName = attributes.getLocalName(i);
String attrValue = attributes.getValue(i).trim();
if (attrName.equals(EXTENSION_NAME))
currentExtension.setLabel(translate(attrValue));
else if (attrName.equals(EXTENSION_ID)) {
int simpleIdStart = attrValue.lastIndexOf('.');
if ((simpleIdStart != -1) && extractNamespaces) {
simpleId = attrValue.substring(simpleIdStart + 1);
namespaceName = attrValue.substring(0, simpleIdStart);
} else {
simpleId = attrValue;
namespaceName = contribution.getDefaultNamespace();
}
currentExtension.setSimpleIdentifier(simpleId);
currentExtension.setNamespaceIdentifier(namespaceName);
} else if (attrName.equals(EXTENSION_TARGET)) {
// check if point is specified as a simple or qualified name
String targetName;
if (attrValue.lastIndexOf('.') == -1) {
String baseId = contribution.getDefaultNamespace();
targetName = baseId + '.' + attrValue;
} else
targetName = attrValue;
currentExtension.setExtensionPointIdentifier(targetName);
} else
unknownAttribute(attrName, EXTENSION);
}
if (currentExtension.getExtensionPointIdentifier() == null) {
missingAttribute(EXTENSION_TARGET, EXTENSION);
stateStack.pop();
stateStack.push(Integer.valueOf(IGNORED_ELEMENT_STATE));
objectStack.pop();
return;
}
// if we have an Id specified, check for duplicates. Only issue warning (not error) if duplicate found
// as it might still work fine - depending on the access pattern.
if (simpleId != null && registry.debug()) {
String uniqueId = namespaceName + '.' + simpleId;
IExtension existingExtension = registry.getExtension(uniqueId);
if (existingExtension != null) {
String currentSupplier = contribution.getDefaultNamespace();
String existingSupplier = existingExtension.getContributor().getName();
String msg = NLS.bind(RegistryMessages.parse_duplicateExtension, new String[] {currentSupplier, existingSupplier, uniqueId});
registry.log(new Status(IStatus.WARNING, RegistryMessages.OWNER_NAME, 0, msg, null));
} else if (processedExtensionIds != null) { // check elements in this contribution
for (String extensionId : processedExtensionIds) {
if (uniqueId.equals(extensionId)) {
String currentSupplier = contribution.getDefaultNamespace();
String existingSupplier = currentSupplier;
String msg = NLS.bind(RegistryMessages.parse_duplicateExtension, new String[] {currentSupplier, existingSupplier, uniqueId});
registry.log(new Status(IStatus.WARNING, RegistryMessages.OWNER_NAME, 0, msg, null));
break;
}
}
}
if (processedExtensionIds == null)
processedExtensionIds = new ArrayList<>(10);
processedExtensionIds.add(uniqueId);
}
objectManager.add(currentExtension, true);
addedRegistryObjects.add(currentExtension);
}
//todo: Are all three methods needed??
private void missingAttribute(String attribute, String element) {
if (locator == null)
internalError(NLS.bind(RegistryMessages.parse_missingAttribute, attribute, element));
else
internalError(NLS.bind(RegistryMessages.parse_missingAttributeLine, (new String[] {attribute, element, Integer.toString(locator.getLineNumber())})));
}
private void unknownAttribute(String attribute, String element) {
if (locator == null)
internalError(NLS.bind(RegistryMessages.parse_unknownAttribute, attribute, element));
else
internalError(NLS.bind(RegistryMessages.parse_unknownAttributeLine, (new String[] {attribute, element, Integer.toString(locator.getLineNumber())})));
}
private void unknownElement(String parent, String element) {
if (locator == null)
internalError(NLS.bind(RegistryMessages.parse_unknownElement, element, parent));
else
internalError(NLS.bind(RegistryMessages.parse_unknownElementLine, (new String[] {element, parent, Integer.toString(locator.getLineNumber())})));
}
private void parseExtensionPointAttributes(Attributes attributes) {
ExtensionPoint currentExtPoint = registry.getElementFactory().createExtensionPoint(contribution.shouldPersist());
// Process Attributes
int len = (attributes != null) ? attributes.getLength() : 0;
for (int i = 0; i < len; i++) {
String attrName = attributes.getLocalName(i);
String attrValue = attributes.getValue(i).trim();
if (attrName.equals(EXTENSION_POINT_NAME))
currentExtPoint.setLabel(translate(attrValue));
else if (attrName.equals(EXTENSION_POINT_ID)) {
String uniqueId;
String namespaceName;
int simpleIdStart = attrValue.lastIndexOf('.');
if (simpleIdStart != -1 && extractNamespaces) {
namespaceName = attrValue.substring(0, simpleIdStart);
uniqueId = attrValue;
} else {
namespaceName = contribution.getDefaultNamespace();
uniqueId = namespaceName + '.' + attrValue;
}
currentExtPoint.setUniqueIdentifier(uniqueId);
currentExtPoint.setNamespace(namespaceName);
} else if (attrName.equals(EXTENSION_POINT_SCHEMA))
currentExtPoint.setSchema(attrValue);
else
unknownAttribute(attrName, EXTENSION_POINT);
}
if (currentExtPoint.getSimpleIdentifier() == null || currentExtPoint.getLabel() == null) {
String attribute = currentExtPoint.getSimpleIdentifier() == null ? EXTENSION_POINT_ID : EXTENSION_POINT_NAME;
missingAttribute(attribute, EXTENSION_POINT);
stateStack.pop();
stateStack.push(Integer.valueOf(IGNORED_ELEMENT_STATE));
return;
}
if (!objectManager.addExtensionPoint(currentExtPoint, true)) {
// avoid adding extension point second time as it might cause
// extensions associated with the existing extension point to
// become inaccessible.
if (registry.debug()) {
String msg = NLS.bind(RegistryMessages.parse_duplicateExtensionPoint, currentExtPoint.getUniqueIdentifier(), contribution.getDefaultNamespace());
registry.log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, 0, msg, null));
}
stateStack.pop();
stateStack.push(Integer.valueOf(IGNORED_ELEMENT_STATE));
return;
}
if (currentExtPoint.getNamespace() == null)
currentExtPoint.setNamespace(contribution.getDefaultNamespace());
currentExtPoint.setContributorId(contribution.getContributorId());
addedRegistryObjects.add(currentExtPoint);
// Now populate the the vector just below us on the objectStack with this extension point
scratchVectors[EXTENSION_POINT_INDEX].add(currentExtPoint);
}
/* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#startDocument()
*/
@Override
public void startDocument() {
stateStack.push(Integer.valueOf(INITIAL_STATE));
for (int i = 0; i <= LAST_INDEX; i++) {
scratchVectors[i] = new ArrayList<>();
}
}
/* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
*/
@Override
public void startElement(String uri, String elementName, String qName, Attributes attributes) {
switch (stateStack.peek().intValue()) {
case INITIAL_STATE :
handleInitialState(elementName, attributes);
break;
case BUNDLE_STATE :
handleBundleState(elementName, attributes);
break;
case BUNDLE_EXTENSION_POINT_STATE :
handleExtensionPointState(elementName);
break;
case BUNDLE_EXTENSION_STATE :
case CONFIGURATION_ELEMENT_STATE :
handleExtensionState(elementName, attributes);
break;
default :
stateStack.push(Integer.valueOf(IGNORED_ELEMENT_STATE));
if (!compatibilityMode)
internalError(NLS.bind(RegistryMessages.parse_unknownTopElement, elementName));
}
}
/* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#warning(org.xml.sax.SAXParseException)
*/
@Override
public void warning(SAXParseException ex) {
logStatus(ex);
}
private void internalError(String message) {
error(new Status(IStatus.WARNING, RegistryMessages.OWNER_NAME, PARSE_PROBLEM, message, null));
}
/* (non-Javadoc)
* @see org.xml.sax.ContentHandler#processingInstruction
* @since 3.0
*/
@Override
public void processingInstruction(String target, String data) {
// Since 3.0, a processing instruction of the form at
// the start of the manifest file is used to indicate the plug-in manifest
// schema version in effect. Pre-3.0 (i.e., 2.1) plug-in manifest files do not
// have one of these, and this is how we can distinguish the manifest of a
// pre-3.0 plug-in from a post-3.0 one (for compatibility transformations).
if (target.equalsIgnoreCase("eclipse")) { //$NON-NLS-1$
// just the presence of this processing instruction indicates that this
// plug-in is at least 3.0
schemaVersion = VERSION_3_0;
StringTokenizer tokenizer = new StringTokenizer(data, "=\""); //$NON-NLS-1$
while (tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken();
if (token.equalsIgnoreCase("version")) { //$NON-NLS-1$
if (!tokenizer.hasMoreTokens()) {
break;
}
schemaVersion = tokenizer.nextToken();
break;
}
}
initializeExtractNamespace();
}
}
/**
* Handles an error state specified by the status. The collection of all logged status
* objects can be accessed using getStatus()
.
*
* @param error a status detailing the error condition
*/
public void error(IStatus error) {
status.add(error);
}
protected String translate(String key) {
return registry.translate(key, resources);
}
/**
* Fixes up the extension declarations in the given pre-3.0 plug-in or fragment to compensate
* for extension points that were renamed between release 2.1 and 3.0.
*/
private Extension[] fixRenamedExtensionPoints(Extension[] extensions) {
if (extensions == null || versionAtLeast(VERSION_3_0) || RegistryProperties.getProperty(NO_EXTENSION_MUNGING) != null)
return extensions;
for (Extension extension : extensions) {
String oldPointId = extension.getExtensionPointIdentifier();
String newPointId = extensionPointMap.get(oldPointId);
if (newPointId != null) {
extension.setExtensionPointIdentifier(newPointId);
}
}
return extensions;
}
/**
* To preserve backward compatibility, we will only attempt to extract namespace form the name
* if Eclipse version specified in the plugin.xml () is at least 3.2.
*/
private void initializeExtractNamespace() {
extractNamespaces = Boolean.valueOf(versionAtLeast(VERSION_3_2)).booleanValue();
}
/**
* Makes sense only for plugin.xml versions >= 3.0 (Eclipse version was introduced in 3.0).
* Assumes that version is stored as "X1.X2.....XN" where X1 is a major version; X2 is a minor version
* and so on.
*/
private boolean versionAtLeast(String testVersion) {
if (schemaVersion == null)
return false;
StringTokenizer testVersionTokenizer = new StringTokenizer(testVersion, "."); //$NON-NLS-1$
StringTokenizer schemaVersionTokenizer = new StringTokenizer(schemaVersion, "."); //$NON-NLS-1$
while (testVersionTokenizer.hasMoreTokens() && schemaVersionTokenizer.hasMoreTokens()) {
try {
if (Integer.parseInt(schemaVersionTokenizer.nextToken()) < Integer.parseInt(testVersionTokenizer.nextToken()))
return false;
} catch (NumberFormatException e) {
return false;
}
}
return true;
}
}