KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > internal > registry > ExtensionsParser


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11
12 package org.eclipse.core.internal.registry;
13
14 import java.io.IOException JavaDoc;
15 import java.util.*;
16 import javax.xml.parsers.ParserConfigurationException JavaDoc;
17 import javax.xml.parsers.SAXParserFactory JavaDoc;
18 import org.eclipse.core.runtime.*;
19 import org.eclipse.osgi.util.NLS;
20 import org.xml.sax.*;
21 import org.xml.sax.helpers.DefaultHandler JavaDoc;
22
23 public class ExtensionsParser extends DefaultHandler JavaDoc {
24     // Introduced for backward compatibility
25
private final static String JavaDoc NO_EXTENSION_MUNGING = "eclipse.noExtensionMunging"; //$NON-NLS-1$ //System property
26
private static final String JavaDoc VERSION_3_0 = "3.0"; //$NON-NLS-1$
27
private static final String JavaDoc VERSION_3_2 = "3.2"; //$NON-NLS-1$
28
private static Map extensionPointMap;
29
30     static {
31         initializeExtensionPointMap();
32     }
33
34     /**
35      * Initialize the list of renamed extension point ids
36      */

37     private static void initializeExtensionPointMap() {
38         Map map = new HashMap(13);
39         map.put("org.eclipse.ui.markerImageProvider", "org.eclipse.ui.ide.markerImageProvider"); //$NON-NLS-1$ //$NON-NLS-2$
40
map.put("org.eclipse.ui.markerHelp", "org.eclipse.ui.ide.markerHelp"); //$NON-NLS-1$ //$NON-NLS-2$
41
map.put("org.eclipse.ui.markerImageProviders", "org.eclipse.ui.ide.markerImageProviders"); //$NON-NLS-1$ //$NON-NLS-2$
42
map.put("org.eclipse.ui.markerResolution", "org.eclipse.ui.ide.markerResolution"); //$NON-NLS-1$ //$NON-NLS-2$
43
map.put("org.eclipse.ui.projectNatureImages", "org.eclipse.ui.ide.projectNatureImages"); //$NON-NLS-1$ //$NON-NLS-2$
44
map.put("org.eclipse.ui.resourceFilters", "org.eclipse.ui.ide.resourceFilters"); //$NON-NLS-1$ //$NON-NLS-2$
45
map.put("org.eclipse.ui.markerUpdaters", "org.eclipse.ui.editors.markerUpdaters"); //$NON-NLS-1$ //$NON-NLS-2$
46
map.put("org.eclipse.ui.documentProviders", "org.eclipse.ui.editors.documentProviders"); //$NON-NLS-1$ //$NON-NLS-2$
47
map.put("org.eclipse.ui.workbench.texteditor.markerAnnotationSpecification", "org.eclipse.ui.editors.markerAnnotationSpecification"); //$NON-NLS-1$ //$NON-NLS-2$
48
map.put("org.eclipse.help.browser", "org.eclipse.help.base.browser"); //$NON-NLS-1$ //$NON-NLS-2$
49
map.put("org.eclipse.help.luceneAnalyzer", "org.eclipse.help.base.luceneAnalyzer"); //$NON-NLS-1$ //$NON-NLS-2$
50
map.put("org.eclipse.help.webapp", "org.eclipse.help.base.webapp"); //$NON-NLS-1$ //$NON-NLS-2$
51
map.put("org.eclipse.help.support", "org.eclipse.ui.helpSupport"); //$NON-NLS-1$ //$NON-NLS-2$
52
extensionPointMap = map;
53     }
54
55     private static long cumulativeTime = 0;
56
57     // is in compatibility mode
58
private boolean compatibilityMode;
59
60     // File name for this extension manifest
61
// This to help with error reporting
62
private String JavaDoc locationName = null;
63
64     // Current State Information
65
private Stack stateStack = new Stack();
66
67     // Current object stack (used to hold the current object we are
68
// populating in this plugin descriptor
69
private Stack objectStack = new Stack();
70
71     private String JavaDoc schemaVersion = null;
72
73     // A status for holding results.
74
private MultiStatus status;
75
76     // Owning extension registry
77
private ExtensionRegistry registry;
78
79     // Resource bundle used to translate the content of the plugin.xml
80
protected ResourceBundle resources;
81
82     // Keep track of the object encountered.
83
private RegistryObjectManager objectManager;
84
85     private Contribution contribution;
86
87     //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.
88
private String JavaDoc configurationElementValue;
89
90     /**
91      * Status code constant (value 1) indicating a problem in a bundle extensions
92      * manifest (<code>extensions.xml</code>) file.
93      */

94     public static final int PARSE_PROBLEM = 1;
95
96     public static final String JavaDoc PLUGIN = "plugin"; //$NON-NLS-1$
97
public static final String JavaDoc PLUGIN_ID = "id"; //$NON-NLS-1$
98
public static final String JavaDoc PLUGIN_NAME = "name"; //$NON-NLS-1$
99
public static final String JavaDoc FRAGMENT = "fragment"; //$NON-NLS-1$
100
public static final String JavaDoc BUNDLE_UID = "id"; //$NON-NLS-1$
101

102     public static final String JavaDoc EXTENSION_POINT = "extension-point"; //$NON-NLS-1$
103
public static final String JavaDoc EXTENSION_POINT_NAME = "name"; //$NON-NLS-1$
104
public static final String JavaDoc EXTENSION_POINT_ID = "id"; //$NON-NLS-1$
105
public static final String JavaDoc EXTENSION_POINT_SCHEMA = "schema"; //$NON-NLS-1$
106

107     public static final String JavaDoc EXTENSION = "extension"; //$NON-NLS-1$
108
public static final String JavaDoc EXTENSION_NAME = "name"; //$NON-NLS-1$
109
public static final String JavaDoc EXTENSION_ID = "id"; //$NON-NLS-1$
110
public static final String JavaDoc EXTENSION_TARGET = "point"; //$NON-NLS-1$
111

112     public static final String JavaDoc ELEMENT = "element"; //$NON-NLS-1$
113
public static final String JavaDoc ELEMENT_NAME = "name"; //$NON-NLS-1$
114
public static final String JavaDoc ELEMENT_VALUE = "value"; //$NON-NLS-1$
115

116     public static final String JavaDoc PROPERTY = "property"; //$NON-NLS-1$
117
public static final String JavaDoc PROPERTY_NAME = "name"; //$NON-NLS-1$
118
public static final String JavaDoc PROPERTY_VALUE = "value"; //$NON-NLS-1$
119

120     // Valid States
121
private static final int IGNORED_ELEMENT_STATE = 0;
122     private static final int INITIAL_STATE = 1;
123     private static final int BUNDLE_STATE = 2;
124     private static final int BUNDLE_EXTENSION_POINT_STATE = 5;
125     private static final int BUNDLE_EXTENSION_STATE = 6;
126     private static final int CONFIGURATION_ELEMENT_STATE = 10;
127
128     // Keep a group of vectors as a temporary scratch space. These
129
// vectors will be used to populate arrays in the bundle model
130
// once processing of the XML file is complete.
131
private static final int EXTENSION_POINT_INDEX = 0;
132     private static final int EXTENSION_INDEX = 1;
133     private static final int LAST_INDEX = 1;
134
135     private ArrayList scratchVectors[] = new ArrayList[LAST_INDEX + 1];
136
137     private Locator locator = null;
138
139     // Cache the behavior toggle (true: attempt to extract namespace from qualified IDs)
140
private boolean extractNamespaces = false;
141
142     private ArrayList processedExtensionIds = null;
143
144     public ExtensionsParser(MultiStatus status, ExtensionRegistry registry) {
145         super();
146         this.status = status;
147         this.registry = registry;
148     }
149
150     /* (non-Javadoc)
151      * @see org.xml.sax.helpers.DefaultHandler#setDocumentLocator(org.xml.sax.Locator)
152      */

153     public void setDocumentLocator(Locator locator) {
154         this.locator = locator;
155     }
156
157     /* (non-Javadoc)
158      * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
159      */

160     public void characters(char[] ch, int start, int length) {
161         int state = ((Integer JavaDoc) stateStack.peek()).intValue();
162         if (state != CONFIGURATION_ELEMENT_STATE)
163             return;
164         if (state == CONFIGURATION_ELEMENT_STATE) {
165             // Accept character data within an element, is when it is
166
// part of a configuration element (i.e. an element within an EXTENSION element
167
ConfigurationElement currentConfigElement = (ConfigurationElement) objectStack.peek();
168             String JavaDoc value = new String JavaDoc(ch, start, length);
169             if (configurationElementValue == null) {
170                 if (value.trim().length() != 0) {
171                     configurationElementValue = value;
172                 }
173             } else {
174                 configurationElementValue = configurationElementValue + value;
175             }
176             if (configurationElementValue != null)
177                 currentConfigElement.setValue(translate(configurationElementValue));
178         }
179     }
180
181     /* (non-Javadoc)
182      * @see org.xml.sax.helpers.DefaultHandler#endDocument()
183      */

184     public void endDocument() {
185         // do nothing
186
}
187
188     /* (non-Javadoc)
189      * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
190      */

191     public void endElement(String JavaDoc uri, String JavaDoc elementName, String JavaDoc qName) {
192         switch (((Integer JavaDoc) stateStack.peek()).intValue()) {
193             case IGNORED_ELEMENT_STATE :
194                 stateStack.pop();
195                 break;
196             case INITIAL_STATE :
197                 // shouldn't get here
198
internalError(NLS.bind(RegistryMessages.parse_internalStack, elementName));
199                 break;
200             case BUNDLE_STATE :
201                 stateStack.pop();
202
203                 ArrayList extensionPoints = scratchVectors[EXTENSION_POINT_INDEX];
204                 ArrayList extensions = scratchVectors[EXTENSION_INDEX];
205                 int[] namespaceChildren = new int[2 + extensionPoints.size() + extensions.size()];
206                 int position = 2;
207                 // Put the extension points into this namespace
208
if (extensionPoints.size() > 0) {
209                     namespaceChildren[Contribution.EXTENSION_POINT] = extensionPoints.size();
210                     for (Iterator iter = extensionPoints.iterator(); iter.hasNext();) {
211                         namespaceChildren[position++] = ((RegistryObject) iter.next()).getObjectId();
212                     }
213                     extensionPoints.clear();
214                 }
215
216                 // Put the extensions into this namespace too
217
if (extensions.size() > 0) {
218                     Extension[] renamedExtensions = fixRenamedExtensionPoints((Extension[]) extensions.toArray(new Extension[extensions.size()]));
219                     namespaceChildren[Contribution.EXTENSION] = renamedExtensions.length;
220                     for (int i = 0; i < renamedExtensions.length; i++) {
221                         namespaceChildren[position++] = renamedExtensions[i].getObjectId();
222                     }
223                     extensions.clear();
224                 }
225                 contribution.setRawChildren(namespaceChildren);
226                 break;
227             case BUNDLE_EXTENSION_POINT_STATE :
228                 if (elementName.equals(EXTENSION_POINT)) {
229                     stateStack.pop();
230                 }
231                 break;
232             case BUNDLE_EXTENSION_STATE :
233                 if (elementName.equals(EXTENSION)) {
234                     stateStack.pop();
235                     // Finish up extension object
236
Extension currentExtension = (Extension) objectStack.pop();
237                     if (currentExtension.getNamespaceIdentifier() == null)
238                         currentExtension.setNamespaceIdentifier(contribution.getDefaultNamespace());
239                     currentExtension.setContributorId(contribution.getContributorId());
240                     scratchVectors[EXTENSION_INDEX].add(currentExtension);
241                 }
242                 break;
243             case CONFIGURATION_ELEMENT_STATE :
244                 // We don't care what the element name was
245
stateStack.pop();
246                 // Now finish up the configuration element object
247
configurationElementValue = null;
248                 ConfigurationElement currentConfigElement = (ConfigurationElement) objectStack.pop();
249
250                 String JavaDoc value = currentConfigElement.getValueAsIs();
251                 if (value != null) {
252                     currentConfigElement.setValue(value.trim());
253                 }
254
255                 RegistryObject parent = (RegistryObject) objectStack.peek();
256                 // Want to add this configuration element to the subelements of an extension
257
int[] oldValues = parent.getRawChildren();
258                 int size = oldValues.length;
259                 int[] newValues = new int[size + 1];
260                 for (int i = 0; i < size; i++) {
261                     newValues[i] = oldValues[i];
262                 }
263                 newValues[size] = currentConfigElement.getObjectId();
264                 parent.setRawChildren(newValues);
265                 currentConfigElement.setParentId(parent.getObjectId());
266                 currentConfigElement.setParentType(parent instanceof ConfigurationElement ? RegistryObjectManager.CONFIGURATION_ELEMENT : RegistryObjectManager.EXTENSION);
267                 break;
268         }
269     }
270
271     /* (non-Javadoc)
272      * @see org.xml.sax.helpers.DefaultHandler#error(org.xml.sax.SAXParseException)
273      */

274     public void error(SAXParseException ex) {
275         logStatus(ex);
276     }
277
278     /* (non-Javadoc)
279      * @see org.xml.sax.helpers.DefaultHandler#fatalError(org.xml.sax.SAXParseException)
280      */

281     public void fatalError(SAXParseException ex) throws SAXException {
282         logStatus(ex);
283         throw ex;
284     }
285
286     private void handleExtensionPointState(String JavaDoc elementName) {
287         // We ignore all elements under extension points (if there are any)
288
stateStack.push(new Integer JavaDoc(IGNORED_ELEMENT_STATE));
289         unknownElement(EXTENSION_POINT, elementName);
290     }
291
292     private void handleExtensionState(String JavaDoc elementName, Attributes attributes) {
293         // You need to change the state here even though we will be executing the same
294
// code for ExtensionState and ConfigurationElementState. We ignore the name
295
// of the element for ConfigurationElements. When we are wrapping up, we will
296
// want to add each configuration element object to the subElements vector of
297
// its parent configuration element object. However, the first configuration
298
// element object we created (the last one we pop off the stack) will need to
299
// be added to a vector in the extension object called _configuration.
300
stateStack.push(new Integer JavaDoc(CONFIGURATION_ELEMENT_STATE));
301
302         configurationElementValue = null;
303
304         // create a new Configuration Element and push it onto the object stack
305
ConfigurationElement currentConfigurationElement = registry.getElementFactory().createConfigurationElement(contribution.shouldPersist());
306         currentConfigurationElement.setContributorId(contribution.getContributorId());
307         objectStack.push(currentConfigurationElement);
308         currentConfigurationElement.setName(elementName);
309
310         // Processing the attributes of a configuration element involves creating
311
// a new configuration property for each attribute and populating the configuration
312
// property with the name/value pair of the attribute. Note there will be one
313
// configuration property for each attribute
314
parseConfigurationElementAttributes(attributes);
315         objectManager.add(currentConfigurationElement, true);
316     }
317
318     private void handleInitialState(String JavaDoc elementName, Attributes attributes) {
319         // new manifests should have the plugin (or fragment) element empty
320
// in compatibility mode, any extraneous elements will be silently ignored
321
compatibilityMode = attributes.getLength() > 0;
322         stateStack.push(new Integer JavaDoc(BUNDLE_STATE));
323         objectStack.push(contribution);
324     }
325
326     private void handleBundleState(String JavaDoc elementName, Attributes attributes) {
327         if (elementName.equals(EXTENSION_POINT)) {
328             stateStack.push(new Integer JavaDoc(BUNDLE_EXTENSION_POINT_STATE));
329             parseExtensionPointAttributes(attributes);
330             return;
331         }
332         if (elementName.equals(EXTENSION)) {
333             stateStack.push(new Integer JavaDoc(BUNDLE_EXTENSION_STATE));
334             parseExtensionAttributes(attributes);
335             return;
336         }
337
338         // If we get to this point, the element name is one we don't currently accept.
339
// Set the state to indicate that this element will be ignored
340
stateStack.push(new Integer JavaDoc(IGNORED_ELEMENT_STATE));
341         if (!compatibilityMode)
342             unknownElement(PLUGIN, elementName);
343     }
344
345     private void logStatus(SAXParseException ex) {
346         String JavaDoc name = ex.getSystemId();
347         if (name == null)
348             name = locationName;
349         if (name == null)
350             name = ""; //$NON-NLS-1$
351
else
352             name = name.substring(1 + name.lastIndexOf("/")); //$NON-NLS-1$
353

354         String JavaDoc msg;
355         if (name.equals("")) //$NON-NLS-1$
356
msg = NLS.bind(RegistryMessages.parse_error, ex.getMessage());
357         else
358             msg = NLS.bind(RegistryMessages.parse_errorNameLineColumn, (new Object JavaDoc[] {name, Integer.toString(ex.getLineNumber()), Integer.toString(ex.getColumnNumber()), ex.getMessage()}));
359         error(new Status(IStatus.WARNING, RegistryMessages.OWNER_NAME, PARSE_PROBLEM, msg, ex));
360     }
361
362     public Contribution parseManifest(SAXParserFactory JavaDoc factory, InputSource in, String JavaDoc manifestName, RegistryObjectManager registryObjects, Contribution currentNamespace, ResourceBundle bundle) throws ParserConfigurationException JavaDoc, SAXException, IOException JavaDoc {
363         long start = 0;
364         this.resources = bundle;
365         this.objectManager = registryObjects;
366         //initialize the parser with this object
367
this.contribution = currentNamespace;
368         if (registry.debug())
369             start = System.currentTimeMillis();
370
371         if (factory == null)
372             throw new SAXException(RegistryMessages.parse_xmlParserNotAvailable);
373
374         try {
375             locationName = in.getSystemId();
376             if (locationName == null)
377                 locationName = manifestName;
378             factory.setNamespaceAware(true);
379             try {
380                 factory.setFeature("http://xml.org/sax/features/string-interning", true); //$NON-NLS-1$
381
} catch (SAXException se) {
382                 // ignore; we can still operate without string-interning
383
}
384             factory.setValidating(false);
385             factory.newSAXParser().parse(in, this);
386             return (Contribution) objectStack.pop();
387         } finally {
388             if (registry.debug()) {
389                 cumulativeTime = cumulativeTime + (System.currentTimeMillis() - start);
390                 System.out.println("Cumulative parse time so far : " + cumulativeTime); //$NON-NLS-1$
391
}
392         }
393     }
394
395     private void parseConfigurationElementAttributes(Attributes attributes) {
396         ConfigurationElement parentConfigurationElement = (ConfigurationElement) objectStack.peek();
397
398         // process attributes
399
int len = (attributes != null) ? attributes.getLength() : 0;
400         if (len == 0) {
401             parentConfigurationElement.setProperties(RegistryObjectManager.EMPTY_STRING_ARRAY);
402             return;
403         }
404         String JavaDoc[] properties = new String JavaDoc[len * 2];
405         for (int i = 0; i < len; i++) {
406             properties[i * 2] = attributes.getLocalName(i);
407             properties[i * 2 + 1] = translate(attributes.getValue(i));
408         }
409         parentConfigurationElement.setProperties(properties);
410         properties = null;
411     }
412
413     private void parseExtensionAttributes(Attributes attributes) {
414         Extension currentExtension = registry.getElementFactory().createExtension(contribution.shouldPersist());
415         objectStack.push(currentExtension);
416
417         String JavaDoc simpleId = null;
418         String JavaDoc namespaceName = null;
419         // Process Attributes
420
int len = (attributes != null) ? attributes.getLength() : 0;
421         for (int i = 0; i < len; i++) {
422             String JavaDoc attrName = attributes.getLocalName(i);
423             String JavaDoc attrValue = attributes.getValue(i).trim();
424
425             if (attrName.equals(EXTENSION_NAME))
426                 currentExtension.setLabel(translate(attrValue));
427             else if (attrName.equals(EXTENSION_ID)) {
428                 int simpleIdStart = attrValue.lastIndexOf('.');
429                 if ((simpleIdStart != -1) && extractNamespaces) {
430                     simpleId = attrValue.substring(simpleIdStart + 1);
431                     namespaceName = attrValue.substring(0, simpleIdStart);
432                 } else {
433                     simpleId = attrValue;
434                     namespaceName = contribution.getDefaultNamespace();
435                 }
436                 currentExtension.setSimpleIdentifier(simpleId);
437                 currentExtension.setNamespaceIdentifier(namespaceName);
438             } else if (attrName.equals(EXTENSION_TARGET)) {
439                 // check if point is specified as a simple or qualified name
440
String JavaDoc targetName;
441                 if (attrValue.lastIndexOf('.') == -1) {
442                     String JavaDoc baseId = contribution.getDefaultNamespace();
443                     targetName = baseId + '.' + attrValue;
444                 } else
445                     targetName = attrValue;
446                 currentExtension.setExtensionPointIdentifier(targetName);
447             } else
448                 unknownAttribute(EXTENSION, attrName);
449         }
450         if (currentExtension.getExtensionPointIdentifier() == null) {
451             missingAttribute(EXTENSION_TARGET, EXTENSION);
452             stateStack.pop();
453             stateStack.push(new Integer JavaDoc(IGNORED_ELEMENT_STATE));
454             objectStack.pop();
455             return;
456         }
457         // if we have an Id specified, check for duplicates. Only issue warning (not error) if duplicate found
458
// as it might still work fine - depending on the access pattern.
459
if (simpleId != null && registry.debug()) {
460             String JavaDoc uniqueId = namespaceName + '.' + simpleId;
461             IExtension existingExtension = registry.getExtension(uniqueId);
462             if (existingExtension != null) {
463                 String JavaDoc currentSupplier = contribution.getDefaultNamespace();
464                 String JavaDoc existingSupplier = existingExtension.getContributor().getName();
465                 String JavaDoc msg = NLS.bind(RegistryMessages.parse_duplicateExtension, new String JavaDoc[] {currentSupplier, existingSupplier, uniqueId});
466                 registry.log(new Status(IStatus.WARNING, RegistryMessages.OWNER_NAME, 0, msg, null));
467             } else if (processedExtensionIds != null) { // check elements in this contribution
468
for (Iterator i = processedExtensionIds.iterator(); i.hasNext();) {
469                     if (uniqueId.equals(i.next())) {
470                         String JavaDoc currentSupplier = contribution.getDefaultNamespace();
471                         String JavaDoc existingSupplier = currentSupplier;
472                         String JavaDoc msg = NLS.bind(RegistryMessages.parse_duplicateExtension, new String JavaDoc[] {currentSupplier, existingSupplier, uniqueId});
473                         registry.log(new Status(IStatus.WARNING, RegistryMessages.OWNER_NAME, 0, msg, null));
474                         break;
475                     }
476                 }
477             }
478             if (processedExtensionIds == null)
479                 processedExtensionIds = new ArrayList(10);
480             processedExtensionIds.add(uniqueId);
481         }
482
483         objectManager.add(currentExtension, true);
484     }
485
486     //todo: Are all three methods needed??
487
private void missingAttribute(String JavaDoc attribute, String JavaDoc element) {
488         if (locator == null)
489             internalError(NLS.bind(RegistryMessages.parse_missingAttribute, attribute, element));
490         else
491             internalError(NLS.bind(RegistryMessages.parse_missingAttributeLine, (new String JavaDoc[] {attribute, element, Integer.toString(locator.getLineNumber())})));
492     }
493
494     private void unknownAttribute(String JavaDoc attribute, String JavaDoc element) {
495         if (locator == null)
496             internalError(NLS.bind(RegistryMessages.parse_unknownAttribute, attribute, element));
497         else
498             internalError(NLS.bind(RegistryMessages.parse_unknownAttributeLine, (new String JavaDoc[] {attribute, element, Integer.toString(locator.getLineNumber())})));
499     }
500
501     private void unknownElement(String JavaDoc parent, String JavaDoc element) {
502         if (locator == null)
503             internalError(NLS.bind(RegistryMessages.parse_unknownElement, element, parent));
504         else
505             internalError(NLS.bind(RegistryMessages.parse_unknownElementLine, (new String JavaDoc[] {element, parent, Integer.toString(locator.getLineNumber())})));
506     }
507
508     private void parseExtensionPointAttributes(Attributes attributes) {
509         ExtensionPoint currentExtPoint = registry.getElementFactory().createExtensionPoint(contribution.shouldPersist());
510
511         // Process Attributes
512
int len = (attributes != null) ? attributes.getLength() : 0;
513         for (int i = 0; i < len; i++) {
514             String JavaDoc attrName = attributes.getLocalName(i);
515             String JavaDoc attrValue = attributes.getValue(i).trim();
516
517             if (attrName.equals(EXTENSION_POINT_NAME))
518                 currentExtPoint.setLabel(translate(attrValue));
519             else if (attrName.equals(EXTENSION_POINT_ID)) {
520                 String JavaDoc uniqueId;
521                 String JavaDoc namespaceName;
522                 int simpleIdStart = attrValue.lastIndexOf('.');
523                 if (simpleIdStart != -1 && extractNamespaces) {
524                     namespaceName = attrValue.substring(0, simpleIdStart);
525                     uniqueId = attrValue;
526                 } else {
527                     namespaceName = contribution.getDefaultNamespace();
528                     uniqueId = namespaceName + '.' + attrValue;
529                 }
530                 currentExtPoint.setUniqueIdentifier(uniqueId);
531                 currentExtPoint.setNamespace(namespaceName);
532
533             } else if (attrName.equals(EXTENSION_POINT_SCHEMA))
534                 currentExtPoint.setSchema(attrValue);
535             else
536                 unknownAttribute(EXTENSION_POINT, attrName);
537         }
538         if (currentExtPoint.getSimpleIdentifier() == null || currentExtPoint.getLabel() == null) {
539             String JavaDoc attribute = currentExtPoint.getSimpleIdentifier() == null ? EXTENSION_POINT_ID : EXTENSION_POINT_NAME;
540             missingAttribute(attribute, EXTENSION_POINT);
541             stateStack.pop();
542             stateStack.push(new Integer JavaDoc(IGNORED_ELEMENT_STATE));
543             return;
544         }
545         if (!objectManager.addExtensionPoint(currentExtPoint, true)) {
546             // avoid adding extension point second time as it might cause
547
// extensions associated with the existing extension point to
548
// become inaccessible.
549
if (registry.debug()) {
550                 String JavaDoc msg = NLS.bind(RegistryMessages.parse_duplicateExtensionPoint, currentExtPoint.getUniqueIdentifier(), contribution.getDefaultNamespace());
551                 registry.log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, 0, msg, null));
552             }
553             stateStack.pop();
554             stateStack.push(new Integer JavaDoc(IGNORED_ELEMENT_STATE));
555             return;
556         }
557         if (currentExtPoint.getNamespace() == null)
558             currentExtPoint.setNamespace(contribution.getDefaultNamespace());
559         currentExtPoint.setContributorId(contribution.getContributorId());
560
561         // Now populate the the vector just below us on the objectStack with this extension point
562
scratchVectors[EXTENSION_POINT_INDEX].add(currentExtPoint);
563     }
564
565     /* (non-Javadoc)
566      * @see org.xml.sax.helpers.DefaultHandler#startDocument()
567      */

568     public void startDocument() {
569         stateStack.push(new Integer JavaDoc(INITIAL_STATE));
570         for (int i = 0; i <= LAST_INDEX; i++) {
571             scratchVectors[i] = new ArrayList();
572         }
573     }
574
575     /* (non-Javadoc)
576      * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
577      */

578     public void startElement(String JavaDoc uri, String JavaDoc elementName, String JavaDoc qName, Attributes attributes) {
579         switch (((Integer JavaDoc) stateStack.peek()).intValue()) {
580             case INITIAL_STATE :
581                 handleInitialState(elementName, attributes);
582                 break;
583             case BUNDLE_STATE :
584                 handleBundleState(elementName, attributes);
585                 break;
586             case BUNDLE_EXTENSION_POINT_STATE :
587                 handleExtensionPointState(elementName);
588                 break;
589             case BUNDLE_EXTENSION_STATE :
590             case CONFIGURATION_ELEMENT_STATE :
591                 handleExtensionState(elementName, attributes);
592                 break;
593             default :
594                 stateStack.push(new Integer JavaDoc(IGNORED_ELEMENT_STATE));
595                 if (!compatibilityMode)
596                     internalError(NLS.bind(RegistryMessages.parse_unknownTopElement, elementName));
597         }
598     }
599
600     /* (non-Javadoc)
601      * @see org.xml.sax.helpers.DefaultHandler#warning(org.xml.sax.SAXParseException)
602      */

603     public void warning(SAXParseException ex) {
604         logStatus(ex);
605     }
606
607     private void internalError(String JavaDoc message) {
608         error(new Status(IStatus.WARNING, RegistryMessages.OWNER_NAME, PARSE_PROBLEM, message, null));
609     }
610
611     /* (non-Javadoc)
612      * @see org.xml.sax.ContentHandler#processingInstruction
613      * @since 3.0
614      */

615     public void processingInstruction(String JavaDoc target, String JavaDoc data) throws SAXException {
616         // Since 3.0, a processing instruction of the form <?eclipse version="3.0"?> at
617
// the start of the manifest file is used to indicate the plug-in manifest
618
// schema version in effect. Pre-3.0 (i.e., 2.1) plug-in manifest files do not
619
// have one of these, and this is how we can distinguish the manifest of a
620
// pre-3.0 plug-in from a post-3.0 one (for compatibility transformations).
621
if (target.equalsIgnoreCase("eclipse")) { //$NON-NLS-1$
622
// just the presence of this processing instruction indicates that this
623
// plug-in is at least 3.0
624
schemaVersion = VERSION_3_0;
625             StringTokenizer tokenizer = new StringTokenizer(data, "=\""); //$NON-NLS-1$
626
while (tokenizer.hasMoreTokens()) {
627                 String JavaDoc token = tokenizer.nextToken();
628                 if (token.equalsIgnoreCase("version")) { //$NON-NLS-1$
629
if (!tokenizer.hasMoreTokens()) {
630                         break;
631                     }
632                     schemaVersion = tokenizer.nextToken();
633                     break;
634                 }
635             }
636             initializeExtractNamespace();
637         }
638     }
639
640     /**
641      * Handles an error state specified by the status. The collection of all logged status
642      * objects can be accessed using <code>getStatus()</code>.
643      *
644      * @param error a status detailing the error condition
645      */

646     public void error(IStatus error) {
647         status.add(error);
648     }
649
650     protected String JavaDoc translate(String JavaDoc key) {
651         return registry.translate(key, resources);
652     }
653
654     /**
655      * Fixes up the extension declarations in the given pre-3.0 plug-in or fragment to compensate
656      * for extension points that were renamed between release 2.1 and 3.0.
657      */

658     private Extension[] fixRenamedExtensionPoints(Extension[] extensions) {
659         if (extensions == null || versionAtLeast(VERSION_3_0) || RegistryProperties.getProperty(NO_EXTENSION_MUNGING) != null)
660             return extensions;
661         for (int i = 0; i < extensions.length; i++) {
662             Extension extension = extensions[i];
663             String JavaDoc oldPointId = extension.getExtensionPointIdentifier();
664             String JavaDoc newPointId = (String JavaDoc) extensionPointMap.get(oldPointId);
665             if (newPointId != null) {
666                 extension.setExtensionPointIdentifier(newPointId);
667             }
668         }
669         return extensions;
670     }
671
672     /**
673      * To preserve backward compatibility, we will only attempt to extract namespace form the name
674      * if Eclipse version specified in the plugin.xml (<?eclipse version="3.2"?>) is at least 3.2.
675      */

676     private void initializeExtractNamespace() {
677         extractNamespaces = new Boolean JavaDoc(versionAtLeast(VERSION_3_2)).booleanValue();
678     }
679
680     /**
681      * Makes sense only for plugin.xml versions >= 3.0 (Eclipse version was introduced in 3.0).
682      * Assumes that version is stored as "X1.X2.....XN" where X1 is a major version; X2 is a minor version
683      * and so on.
684      */

685     private boolean versionAtLeast(String JavaDoc testVersion) {
686         if (schemaVersion == null)
687             return false;
688
689         StringTokenizer testVersionTokenizer = new StringTokenizer(testVersion, "."); //$NON-NLS-1$
690
StringTokenizer schemaVersionTokenizer = new StringTokenizer(schemaVersion, "."); //$NON-NLS-1$
691
while (testVersionTokenizer.hasMoreTokens() && schemaVersionTokenizer.hasMoreTokens()) {
692             try {
693                 if (Integer.parseInt(schemaVersionTokenizer.nextToken()) < Integer.parseInt(testVersionTokenizer.nextToken()))
694                     return false;
695             } catch (NumberFormatException JavaDoc e) {
696                 return false;
697             }
698         }
699         return true;
700     }
701 }
702
Popular Tags