1 11 12 package org.eclipse.core.internal.registry; 13 14 import java.io.IOException ; 15 import java.util.*; 16 import javax.xml.parsers.ParserConfigurationException ; 17 import javax.xml.parsers.SAXParserFactory ; 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 ; 22 23 public class ExtensionsParser extends DefaultHandler { 24 private final static String NO_EXTENSION_MUNGING = "eclipse.noExtensionMunging"; private static final String VERSION_3_0 = "3.0"; private static final String VERSION_3_2 = "3.2"; private static Map extensionPointMap; 29 30 static { 31 initializeExtensionPointMap(); 32 } 33 34 37 private static void initializeExtensionPointMap() { 38 Map map = new HashMap(13); 39 map.put("org.eclipse.ui.markerImageProvider", "org.eclipse.ui.ide.markerImageProvider"); map.put("org.eclipse.ui.markerHelp", "org.eclipse.ui.ide.markerHelp"); map.put("org.eclipse.ui.markerImageProviders", "org.eclipse.ui.ide.markerImageProviders"); map.put("org.eclipse.ui.markerResolution", "org.eclipse.ui.ide.markerResolution"); map.put("org.eclipse.ui.projectNatureImages", "org.eclipse.ui.ide.projectNatureImages"); map.put("org.eclipse.ui.resourceFilters", "org.eclipse.ui.ide.resourceFilters"); map.put("org.eclipse.ui.markerUpdaters", "org.eclipse.ui.editors.markerUpdaters"); map.put("org.eclipse.ui.documentProviders", "org.eclipse.ui.editors.documentProviders"); map.put("org.eclipse.ui.workbench.texteditor.markerAnnotationSpecification", "org.eclipse.ui.editors.markerAnnotationSpecification"); map.put("org.eclipse.help.browser", "org.eclipse.help.base.browser"); map.put("org.eclipse.help.luceneAnalyzer", "org.eclipse.help.base.luceneAnalyzer"); map.put("org.eclipse.help.webapp", "org.eclipse.help.base.webapp"); map.put("org.eclipse.help.support", "org.eclipse.ui.helpSupport"); extensionPointMap = map; 53 } 54 55 private static long cumulativeTime = 0; 56 57 private boolean compatibilityMode; 59 60 private String locationName = null; 63 64 private Stack stateStack = new Stack(); 66 67 private Stack objectStack = new Stack(); 70 71 private String schemaVersion = null; 72 73 private MultiStatus status; 75 76 private ExtensionRegistry registry; 78 79 protected ResourceBundle resources; 81 82 private RegistryObjectManager objectManager; 84 85 private Contribution contribution; 86 87 private String configurationElementValue; 89 90 94 public static final int PARSE_PROBLEM = 1; 95 96 public static final String PLUGIN = "plugin"; public static final String PLUGIN_ID = "id"; public static final String PLUGIN_NAME = "name"; public static final String FRAGMENT = "fragment"; public static final String BUNDLE_UID = "id"; 102 public static final String EXTENSION_POINT = "extension-point"; public static final String EXTENSION_POINT_NAME = "name"; public static final String EXTENSION_POINT_ID = "id"; public static final String EXTENSION_POINT_SCHEMA = "schema"; 107 public static final String EXTENSION = "extension"; public static final String EXTENSION_NAME = "name"; public static final String EXTENSION_ID = "id"; public static final String EXTENSION_TARGET = "point"; 112 public static final String ELEMENT = "element"; public static final String ELEMENT_NAME = "name"; public static final String ELEMENT_VALUE = "value"; 116 public static final String PROPERTY = "property"; public static final String PROPERTY_NAME = "name"; public static final String PROPERTY_VALUE = "value"; 120 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 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 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 153 public void setDocumentLocator(Locator locator) { 154 this.locator = locator; 155 } 156 157 160 public void characters(char[] ch, int start, int length) { 161 int state = ((Integer ) stateStack.peek()).intValue(); 162 if (state != CONFIGURATION_ELEMENT_STATE) 163 return; 164 if (state == CONFIGURATION_ELEMENT_STATE) { 165 ConfigurationElement currentConfigElement = (ConfigurationElement) objectStack.peek(); 168 String value = new String (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 184 public void endDocument() { 185 } 187 188 191 public void endElement(String uri, String elementName, String qName) { 192 switch (((Integer ) stateStack.peek()).intValue()) { 193 case IGNORED_ELEMENT_STATE : 194 stateStack.pop(); 195 break; 196 case INITIAL_STATE : 197 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 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 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 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 stateStack.pop(); 246 configurationElementValue = null; 248 ConfigurationElement currentConfigElement = (ConfigurationElement) objectStack.pop(); 249 250 String value = currentConfigElement.getValueAsIs(); 251 if (value != null) { 252 currentConfigElement.setValue(value.trim()); 253 } 254 255 RegistryObject parent = (RegistryObject) objectStack.peek(); 256 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 274 public void error(SAXParseException ex) { 275 logStatus(ex); 276 } 277 278 281 public void fatalError(SAXParseException ex) throws SAXException { 282 logStatus(ex); 283 throw ex; 284 } 285 286 private void handleExtensionPointState(String elementName) { 287 stateStack.push(new Integer (IGNORED_ELEMENT_STATE)); 289 unknownElement(EXTENSION_POINT, elementName); 290 } 291 292 private void handleExtensionState(String elementName, Attributes attributes) { 293 stateStack.push(new Integer (CONFIGURATION_ELEMENT_STATE)); 301 302 configurationElementValue = null; 303 304 ConfigurationElement currentConfigurationElement = registry.getElementFactory().createConfigurationElement(contribution.shouldPersist()); 306 currentConfigurationElement.setContributorId(contribution.getContributorId()); 307 objectStack.push(currentConfigurationElement); 308 currentConfigurationElement.setName(elementName); 309 310 parseConfigurationElementAttributes(attributes); 315 objectManager.add(currentConfigurationElement, true); 316 } 317 318 private void handleInitialState(String elementName, Attributes attributes) { 319 compatibilityMode = attributes.getLength() > 0; 322 stateStack.push(new Integer (BUNDLE_STATE)); 323 objectStack.push(contribution); 324 } 325 326 private void handleBundleState(String elementName, Attributes attributes) { 327 if (elementName.equals(EXTENSION_POINT)) { 328 stateStack.push(new Integer (BUNDLE_EXTENSION_POINT_STATE)); 329 parseExtensionPointAttributes(attributes); 330 return; 331 } 332 if (elementName.equals(EXTENSION)) { 333 stateStack.push(new Integer (BUNDLE_EXTENSION_STATE)); 334 parseExtensionAttributes(attributes); 335 return; 336 } 337 338 stateStack.push(new Integer (IGNORED_ELEMENT_STATE)); 341 if (!compatibilityMode) 342 unknownElement(PLUGIN, elementName); 343 } 344 345 private void logStatus(SAXParseException ex) { 346 String name = ex.getSystemId(); 347 if (name == null) 348 name = locationName; 349 if (name == null) 350 name = ""; else 352 name = name.substring(1 + name.lastIndexOf("/")); 354 String msg; 355 if (name.equals("")) msg = NLS.bind(RegistryMessages.parse_error, ex.getMessage()); 357 else 358 msg = NLS.bind(RegistryMessages.parse_errorNameLineColumn, (new Object [] {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 factory, InputSource in, String manifestName, RegistryObjectManager registryObjects, Contribution currentNamespace, ResourceBundle bundle) throws ParserConfigurationException , SAXException, IOException { 363 long start = 0; 364 this.resources = bundle; 365 this.objectManager = registryObjects; 366 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); } catch (SAXException se) { 382 } 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); } 392 } 393 } 394 395 private void parseConfigurationElementAttributes(Attributes attributes) { 396 ConfigurationElement parentConfigurationElement = (ConfigurationElement) objectStack.peek(); 397 398 int len = (attributes != null) ? attributes.getLength() : 0; 400 if (len == 0) { 401 parentConfigurationElement.setProperties(RegistryObjectManager.EMPTY_STRING_ARRAY); 402 return; 403 } 404 String [] properties = new String [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 simpleId = null; 418 String namespaceName = null; 419 int len = (attributes != null) ? attributes.getLength() : 0; 421 for (int i = 0; i < len; i++) { 422 String attrName = attributes.getLocalName(i); 423 String 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 String targetName; 441 if (attrValue.lastIndexOf('.') == -1) { 442 String 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 (IGNORED_ELEMENT_STATE)); 454 objectStack.pop(); 455 return; 456 } 457 if (simpleId != null && registry.debug()) { 460 String uniqueId = namespaceName + '.' + simpleId; 461 IExtension existingExtension = registry.getExtension(uniqueId); 462 if (existingExtension != null) { 463 String currentSupplier = contribution.getDefaultNamespace(); 464 String existingSupplier = existingExtension.getContributor().getName(); 465 String msg = NLS.bind(RegistryMessages.parse_duplicateExtension, new String [] {currentSupplier, existingSupplier, uniqueId}); 466 registry.log(new Status(IStatus.WARNING, RegistryMessages.OWNER_NAME, 0, msg, null)); 467 } else if (processedExtensionIds != null) { for (Iterator i = processedExtensionIds.iterator(); i.hasNext();) { 469 if (uniqueId.equals(i.next())) { 470 String currentSupplier = contribution.getDefaultNamespace(); 471 String existingSupplier = currentSupplier; 472 String msg = NLS.bind(RegistryMessages.parse_duplicateExtension, new String [] {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 private void missingAttribute(String attribute, String 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 [] {attribute, element, Integer.toString(locator.getLineNumber())}))); 492 } 493 494 private void unknownAttribute(String attribute, String 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 [] {attribute, element, Integer.toString(locator.getLineNumber())}))); 499 } 500 501 private void unknownElement(String parent, String 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 [] {element, parent, Integer.toString(locator.getLineNumber())}))); 506 } 507 508 private void parseExtensionPointAttributes(Attributes attributes) { 509 ExtensionPoint currentExtPoint = registry.getElementFactory().createExtensionPoint(contribution.shouldPersist()); 510 511 int len = (attributes != null) ? attributes.getLength() : 0; 513 for (int i = 0; i < len; i++) { 514 String attrName = attributes.getLocalName(i); 515 String 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 uniqueId; 521 String 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 attribute = currentExtPoint.getSimpleIdentifier() == null ? EXTENSION_POINT_ID : EXTENSION_POINT_NAME; 540 missingAttribute(attribute, EXTENSION_POINT); 541 stateStack.pop(); 542 stateStack.push(new Integer (IGNORED_ELEMENT_STATE)); 543 return; 544 } 545 if (!objectManager.addExtensionPoint(currentExtPoint, true)) { 546 if (registry.debug()) { 550 String 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 (IGNORED_ELEMENT_STATE)); 555 return; 556 } 557 if (currentExtPoint.getNamespace() == null) 558 currentExtPoint.setNamespace(contribution.getDefaultNamespace()); 559 currentExtPoint.setContributorId(contribution.getContributorId()); 560 561 scratchVectors[EXTENSION_POINT_INDEX].add(currentExtPoint); 563 } 564 565 568 public void startDocument() { 569 stateStack.push(new Integer (INITIAL_STATE)); 570 for (int i = 0; i <= LAST_INDEX; i++) { 571 scratchVectors[i] = new ArrayList(); 572 } 573 } 574 575 578 public void startElement(String uri, String elementName, String qName, Attributes attributes) { 579 switch (((Integer ) 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 (IGNORED_ELEMENT_STATE)); 595 if (!compatibilityMode) 596 internalError(NLS.bind(RegistryMessages.parse_unknownTopElement, elementName)); 597 } 598 } 599 600 603 public void warning(SAXParseException ex) { 604 logStatus(ex); 605 } 606 607 private void internalError(String message) { 608 error(new Status(IStatus.WARNING, RegistryMessages.OWNER_NAME, PARSE_PROBLEM, message, null)); 609 } 610 611 615 public void processingInstruction(String target, String data) throws SAXException { 616 if (target.equalsIgnoreCase("eclipse")) { schemaVersion = VERSION_3_0; 625 StringTokenizer tokenizer = new StringTokenizer(data, "=\""); while (tokenizer.hasMoreTokens()) { 627 String token = tokenizer.nextToken(); 628 if (token.equalsIgnoreCase("version")) { if (!tokenizer.hasMoreTokens()) { 630 break; 631 } 632 schemaVersion = tokenizer.nextToken(); 633 break; 634 } 635 } 636 initializeExtractNamespace(); 637 } 638 } 639 640 646 public void error(IStatus error) { 647 status.add(error); 648 } 649 650 protected String translate(String key) { 651 return registry.translate(key, resources); 652 } 653 654 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 oldPointId = extension.getExtensionPointIdentifier(); 664 String newPointId = (String ) extensionPointMap.get(oldPointId); 665 if (newPointId != null) { 666 extension.setExtensionPointIdentifier(newPointId); 667 } 668 } 669 return extensions; 670 } 671 672 676 private void initializeExtractNamespace() { 677 extractNamespaces = new Boolean (versionAtLeast(VERSION_3_2)).booleanValue(); 678 } 679 680 685 private boolean versionAtLeast(String testVersion) { 686 if (schemaVersion == null) 687 return false; 688 689 StringTokenizer testVersionTokenizer = new StringTokenizer(testVersion, "."); StringTokenizer schemaVersionTokenizer = new StringTokenizer(schemaVersion, "."); while (testVersionTokenizer.hasMoreTokens() && schemaVersionTokenizer.hasMoreTokens()) { 692 try { 693 if (Integer.parseInt(schemaVersionTokenizer.nextToken()) < Integer.parseInt(testVersionTokenizer.nextToken())) 694 return false; 695 } catch (NumberFormatException e) { 696 return false; 697 } 698 } 699 return true; 700 } 701 } 702 | Popular Tags |