1 11 package org.eclipse.ui.internal.cheatsheets.data; 12 13 import java.io.IOException ; 14 import java.io.InputStream ; 15 import java.io.StringReader ; 16 import java.net.URL ; 17 import java.util.ArrayList ; 18 19 import javax.xml.parsers.DocumentBuilder ; 20 21 import org.eclipse.core.runtime.Assert; 22 import org.eclipse.core.runtime.IStatus; 23 import org.eclipse.core.runtime.Platform; 24 import org.eclipse.core.runtime.Status; 25 import org.eclipse.help.internal.UAElement; 26 import org.eclipse.help.internal.UAElementFactory; 27 import org.eclipse.help.internal.dynamic.DocumentProcessor; 28 import org.eclipse.help.internal.dynamic.DocumentReader; 29 import org.eclipse.help.internal.dynamic.ExtensionHandler; 30 import org.eclipse.help.internal.dynamic.FilterHandler; 31 import org.eclipse.help.internal.dynamic.IncludeHandler; 32 import org.eclipse.help.internal.dynamic.ProcessorHandler; 33 import org.eclipse.osgi.util.NLS; 34 import org.eclipse.ui.cheatsheets.AbstractItemExtensionElement; 35 import org.eclipse.ui.internal.cheatsheets.CheatSheetEvaluationContext; 36 import org.eclipse.ui.internal.cheatsheets.CheatSheetPlugin; 37 import org.eclipse.ui.internal.cheatsheets.ICheatSheetResource; 38 import org.eclipse.ui.internal.cheatsheets.Messages; 39 import org.eclipse.ui.internal.cheatsheets.composite.model.CompositeCheatSheetModel; 40 import org.eclipse.ui.internal.cheatsheets.composite.parser.CompositeCheatSheetParser; 41 import org.eclipse.ui.internal.cheatsheets.composite.parser.ICompositeCheatsheetTags; 42 import org.eclipse.ui.internal.cheatsheets.composite.parser.IStatusContainer; 43 import org.eclipse.ui.internal.cheatsheets.registry.CheatSheetItemExtensionElement; 44 import org.eclipse.ui.internal.cheatsheets.registry.CheatSheetRegistryReader; 45 import org.w3c.dom.Document ; 46 import org.w3c.dom.NamedNodeMap ; 47 import org.w3c.dom.Node ; 48 import org.w3c.dom.NodeList ; 49 import org.xml.sax.InputSource ; 50 import org.xml.sax.SAXException ; 51 import org.xml.sax.SAXParseException ; 52 53 64 public class CheatSheetParser implements IStatusContainer { 65 66 private static final String TRUE_STRING = "true"; 68 private DocumentBuilder documentBuilder; 69 private DocumentProcessor processor; 70 private ArrayList itemExtensionContainerList; 71 72 public static final int COMPOSITE_ONLY = 1; 74 public static final int SIMPLE_ONLY = 2; 75 public static final int ANY = 3; 76 77 private IStatus status; 78 79 private int commandCount; 80 81 private int actionCount; 82 83 84 87 public CheatSheetParser() { 88 super(); 89 documentBuilder = CheatSheetPlugin.getPlugin().getDocumentBuilder(); 90 } 91 92 95 public IStatus getStatus() { 96 return status; 97 } 98 99 public void addStatus(int severity, String message, Throwable exception) { 100 status = ParserStatusUtility.addStatus(status, severity, message, exception); 101 } 102 103 119 private StringBuffer escapeXMLCharacters(StringBuffer text) { 120 final int MAXIMUM_TAG_LENGTH = 5; 122 123 int length = text.length(); 125 126 StringBuffer result = new StringBuffer (length); 128 129 for(int i=0; i<length; i++) { 131 char c = text.charAt(i); 133 switch (c) { 134 case '<': { 135 String tmp = ICheatSheetResource.EMPTY_STRING; 139 if(i+MAXIMUM_TAG_LENGTH < length) 140 tmp = text.substring(i, i+MAXIMUM_TAG_LENGTH).toLowerCase(); 141 else { 142 tmp = text.substring(i, length).toLowerCase(); 143 } 144 if(tmp.startsWith(IParserTags.BOLD_START_TAG) || tmp.startsWith(IParserTags.BOLD_END_TAG) || tmp.startsWith(IParserTags.BREAK_TAG)) { 145 result.append(c); 147 } else { 148 result.append(IParserTags.LESS_THAN); 151 } 152 break; } 153 case '>': { 154 String tmp = ICheatSheetResource.EMPTY_STRING; 158 if(i>=MAXIMUM_TAG_LENGTH) { 159 tmp = text.substring(i-MAXIMUM_TAG_LENGTH, i+1).toLowerCase(); 160 } else { 161 tmp = text.substring(0, i+1).toLowerCase(); 162 } 163 if(tmp.endsWith(IParserTags.BOLD_START_TAG) || tmp.endsWith(IParserTags.BOLD_END_TAG) || tmp.endsWith(IParserTags.BREAK_TAG)) { 164 result.append(c); 166 } else { 167 result.append(IParserTags.GREATER_THAN); 170 } 171 break; } 172 case '&': 173 result.append(IParserTags.AMPERSAND); 175 break; 176 case '\'': 177 result.append(IParserTags.APOSTROPHE); 179 break; 180 case '"': 181 result.append(IParserTags.QUOTE); 183 break; 184 case '\t': 185 result.append(' '); 187 break; 188 default: 189 result.append(c); 191 break; 192 } 193 } 194 return result; 195 } 196 197 private Node findNode(Node startNode, String nodeName) { 198 if(startNode == null) { 199 return null; 200 } 201 202 if(startNode.getNodeName().equals(nodeName)) { 203 return startNode; 204 } 205 206 NodeList nodes = startNode.getChildNodes(); 207 for (int i = 0; i < nodes.getLength(); i++) { 208 Node node = nodes.item(i); 209 if(node.getNodeName().equals(nodeName)) { 210 return node; 211 } 212 } 213 214 return null; 215 } 216 217 private void handleExecutable(IExecutableItem item, Node executableNode, AbstractExecutable executable) throws CheatSheetParserException { 218 Assert.isNotNull(item); 219 Assert.isNotNull(executableNode); 220 221 String [] params = null; 222 223 if (executable instanceof CheatSheetCommand) { 224 commandCount++; 225 } 226 if (executable instanceof Action) { 227 actionCount++; 228 } 229 230 NamedNodeMap attributes = executableNode.getAttributes(); 231 if (attributes != null) { 232 for (int x = 0; x < attributes.getLength(); x++) { 233 Node attribute = attributes.item(x); 234 String attributeName = attribute.getNodeName(); 235 if (attribute == null || attributeName == null) 236 continue; 237 if (attributeName.equals(IParserTags.CONFIRM)) { 238 executable.setConfirm(attribute.getNodeValue().equals(TRUE_STRING));} 239 else if (attributeName.equals(IParserTags.WHEN)) { 240 executable.setWhen(attribute.getNodeValue()); 241 } else if (attributeName.equals(IParserTags.REQUIRED)) { 242 executable.setRequired(attribute.getNodeValue().equals(TRUE_STRING)); 243 } else if (attributeName.equals(IParserTags.TRANSLATE)) { 244 } else if (executable.hasParams() && attributeName.startsWith(IParserTags.PARAM)) { 246 try { 247 if(params == null) { 248 params = new String [9]; 249 } 250 String paramNum = attributeName.substring(IParserTags.PARAM.length()); 251 int num = Integer.parseInt(paramNum)-1; 252 253 if(num>-1 && num<9){ 254 params[num] = attribute.getNodeValue(); 255 } else { 256 String message = NLS.bind(Messages.ERROR_PARSING_PARAM_INVALIDRANGE, (new Object [] {attributeName, paramNum})); 257 addStatus(IStatus.ERROR, message, null); 258 } 259 } catch(NumberFormatException e) { 260 String message = Messages.ERROR_PARSING_PARAM_INVALIDNUMBER; 261 addStatus(IStatus.ERROR, message, e); 262 } 263 } else if (!executable.handleAttribute(attribute)) { 264 String message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ATTRIBUTE, (new Object [] {attributeName, executableNode.getNodeName()})); 265 addStatus(IStatus.WARNING, message, null); 266 } 267 } 268 String errorMessage = executable.checkAttributes(executableNode); 269 if (errorMessage != null) { 270 throw new CheatSheetParserException(errorMessage); 271 } 272 } 273 checkForNoChildren(executableNode); 274 executable.setParams(params); 275 item.setExecutable(executable); 276 } 277 278 private void checkForNoChildren(Node parentNode) { 279 NodeList nodes = parentNode.getChildNodes(); 280 for (int i = 0; i < nodes.getLength(); i++) { 281 Node node = nodes.item(i); 282 if(node.getNodeType() != Node.TEXT_NODE && node.getNodeType() != Node.COMMENT_NODE ) { 283 String message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ELEMENT, (new Object [] {node.getNodeName(), parentNode.getNodeName()})); 284 addStatus(IStatus.WARNING, message, null); 285 } 286 } 287 } 288 289 private void handleCheatSheetAttributes(CheatSheet cheatSheet, Node cheatSheetNode) throws CheatSheetParserException { 290 Assert.isNotNull(cheatSheet); 291 Assert.isNotNull(cheatSheetNode); 292 Assert.isTrue(cheatSheetNode.getNodeName().equals(IParserTags.CHEATSHEET)); 293 294 boolean title = false; 295 296 NamedNodeMap attributes = cheatSheetNode.getAttributes(); 297 if (attributes != null) { 298 for (int x = 0; x < attributes.getLength(); x++) { 299 Node attribute = attributes.item(x); 300 String attributeName = attribute.getNodeName(); 301 if (attribute == null || attributeName == null) 302 continue; 303 304 if (attributeName.equals(IParserTags.TITLE)) { 305 title = true; 306 cheatSheet.setTitle(attribute.getNodeValue()); 307 } else { 308 String message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ATTRIBUTE, (new Object [] {attributeName, cheatSheetNode.getNodeName()})); 309 addStatus(IStatus.WARNING, message, null); 310 } 311 } 312 } 313 314 if(!title) { 315 String message = NLS.bind(Messages.ERROR_PARSING_NO_TITLE, (new Object [] {cheatSheetNode.getNodeName()})); 316 throw new CheatSheetParserException(message); 317 } 318 } 319 320 private void handleConditionalSubItem(Item item, Node conditionalSubItemNode) throws CheatSheetParserException { 321 Assert.isNotNull(item); 322 Assert.isNotNull(conditionalSubItemNode); 323 Assert.isTrue(conditionalSubItemNode.getNodeName().equals(IParserTags.CONDITIONALSUBITEM)); 324 325 ConditionalSubItem conditionalSubItem = new ConditionalSubItem(); 326 327 boolean condition = false; 328 329 NamedNodeMap attributes = conditionalSubItemNode.getAttributes(); 331 if (attributes != null) { 332 for (int x = 0; x < attributes.getLength(); x++) { 333 Node attribute = attributes.item(x); 334 String attributeName = attribute.getNodeName(); 335 if (attribute == null || attributeName == null) 336 continue; 337 338 if (attributeName.equals(IParserTags.CONDITION)) { 339 condition = true; 340 conditionalSubItem.setCondition(attribute.getNodeValue()); 341 } else { 342 String message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ATTRIBUTE, (new Object [] {attributeName, conditionalSubItemNode.getNodeName()})); 343 addStatus(IStatus.WARNING, message, null); 344 } 345 } 346 } 347 348 if(!condition) { 349 String message = NLS.bind(Messages.ERROR_PARSING_NO_CONDITION, (new Object [] {conditionalSubItemNode.getNodeName()})); 350 throw new CheatSheetParserException(message); 351 } 352 353 boolean subitem = false; 354 355 NodeList nodes = conditionalSubItemNode.getChildNodes(); 357 for (int i = 0; i < nodes.getLength(); i++) { 358 Node node = nodes.item(i); 359 360 if(node.getNodeName().equals(IParserTags.SUBITEM)) { 361 subitem = true; 362 handleSubItem(conditionalSubItem, node); 363 } else { 364 if(node.getNodeType() != Node.TEXT_NODE && node.getNodeType() != Node.COMMENT_NODE ) { 365 String message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ELEMENT, (new Object [] {node.getNodeName(), conditionalSubItemNode.getNodeName()})); 366 addStatus(IStatus.WARNING, message, null); 367 } 368 } 369 } 370 371 if(!subitem) { 372 String message = NLS.bind(Messages.ERROR_PARSING_NO_SUBITEM, (new Object [] {conditionalSubItemNode.getNodeName()})); 373 throw new CheatSheetParserException(message); 374 } 375 376 item.addSubItem(conditionalSubItem); 377 } 378 379 private void handleDescription(Item item, Node startNode) throws CheatSheetParserException { 380 Assert.isNotNull(item); 381 Assert.isNotNull(startNode); 382 383 Node descriptionNode = findNode(startNode, IParserTags.DESCRIPTION); 384 385 if(descriptionNode != null) { 386 String text = handleMarkedUpText(descriptionNode, startNode, IParserTags.DESCRIPTION); 387 item.setDescription(text); 388 } else { 389 Node parentNode = startNode; 390 if( startNode.getNodeName().equals(IParserTags.DESCRIPTION) ) { 391 parentNode = startNode.getParentNode(); 392 } 393 String message = NLS.bind(Messages.ERROR_PARSING_NO_DESCRIPTION, (new Object [] {parentNode.getNodeName()})); 394 throw new CheatSheetParserException(message); 395 } 396 } 397 398 private String handleMarkedUpText(Node nodeContainingText, Node startNode, String nodeName ) { 399 NodeList nodes = nodeContainingText.getChildNodes(); 400 StringBuffer text = new StringBuffer (); 401 402 boolean containsMarkup = false; 403 404 boolean isLeadingTrimRequired = true; 410 411 for (int i = 0; i < nodes.getLength(); i++) { 412 Node node = nodes.item(i); 413 if(node.getNodeType() == Node.TEXT_NODE) { 414 String nodeValue = node.getNodeValue(); 415 if (isLeadingTrimRequired) { 416 nodeValue = trimLeadingWhitespace(nodeValue); 417 } 418 text.append(nodeValue); 419 isLeadingTrimRequired = false; 420 } else if(node.getNodeType() == Node.ELEMENT_NODE) { 421 if(node.getNodeName().equals(IParserTags.BOLD)) { 423 containsMarkup = true; 424 text.append(IParserTags.BOLD_START_TAG); 425 text.append(node.getFirstChild().getNodeValue()); 426 text.append(IParserTags.BOLD_END_TAG); 427 isLeadingTrimRequired = false; 428 } else if(node.getNodeName().equals(IParserTags.BREAK)) { 429 containsMarkup = true; 430 text.append(IParserTags.BREAK_TAG); 431 isLeadingTrimRequired = true; 432 } else { 433 warnUnknownMarkupElement(startNode, nodeName, node); 434 } 435 } 436 } 437 438 if(containsMarkup) { 439 text = escapeXMLCharacters(text); 440 text.insert(0, IParserTags.FORM_START_TAG); 441 text.append(IParserTags.FORM_END_TAG); 442 } else { 443 deTab(text); 444 } 445 446 return text.toString().trim(); 448 } 449 450 452 private void deTab(StringBuffer text) { 453 for (int i = 0; i < text.length(); i++) { 454 if (text.charAt(i) == '\t') { 455 text.setCharAt(i, ' '); 456 } 457 } 458 } 459 460 private String trimLeadingWhitespace(String nodeValue) { 461 int firstNonWhitespaceIndex = 0; 462 while (firstNonWhitespaceIndex < nodeValue.length() && 463 Character.isWhitespace(nodeValue.charAt(firstNonWhitespaceIndex))) { 464 firstNonWhitespaceIndex++; 465 } 466 if (firstNonWhitespaceIndex > 0) { 467 return nodeValue.substring(firstNonWhitespaceIndex, nodeValue.length()); 468 } 469 return nodeValue; 470 } 471 472 475 private void warnUnknownMarkupElement(Node startNode, String nodeName, Node node) { 476 Node parentNode = startNode; 477 if( startNode.getNodeName().equals(nodeName) ) { 478 parentNode = startNode.getParentNode(); 479 } 480 String message; 481 if (IParserTags.DESCRIPTION.equals(nodeName)) { 482 message = NLS.bind(Messages.WARNING_PARSING_DESCRIPTION_UNKNOWN_ELEMENT, (new Object [] {parentNode.getNodeName(), node.getNodeName()})); 483 } else { 484 message = NLS.bind(Messages.WARNING_PARSING_ON_COMPLETION_UNKNOWN_ELEMENT, (new Object [] {parentNode.getNodeName(), node.getNodeName()})); 485 } 486 addStatus(IStatus.WARNING, message, null); 487 488 } 489 490 private void handleOnCompletion(Item item, Node onCompletionNode) { 491 String text = handleMarkedUpText(onCompletionNode, onCompletionNode, IParserTags.ON_COMPLETION); 492 item.setCompletionMessage(text); 493 } 494 495 private void handleIntroNode(CheatSheet cheatSheet, Node introNode) 496 throws CheatSheetParserException { 497 Item introItem = new Item(); 498 introItem.setTitle(Messages.CHEAT_SHEET_INTRO_TITLE); 499 500 handleIntroAttributes(introItem, introNode); 501 502 boolean hasDescription = false; 503 504 NodeList nodes = introNode.getChildNodes(); 505 for (int i = 0; i < nodes.getLength(); i++) { 506 Node node = nodes.item(i); 507 508 if(node.getNodeName().equals(IParserTags.DESCRIPTION)) { 509 if (hasDescription) { 510 String message = NLS.bind(Messages.ERROR_PARSING_MULTIPLE_DESCRIPTION, (new Object [] {introNode.getNodeName()})); 511 addStatus(IStatus.ERROR, message, null); 512 } else { 513 hasDescription = true; 514 handleDescription(introItem, node); 515 } 516 } else { 517 if(node.getNodeType() != Node.TEXT_NODE && node.getNodeType() != Node.COMMENT_NODE ) { 518 String message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ELEMENT, (new Object [] {node.getNodeName(), introNode.getNodeName()})); 519 addStatus(IStatus.WARNING, message, null); 520 } 521 } 522 } 523 524 if(!hasDescription) { 525 String message = NLS.bind(Messages.ERROR_PARSING_NO_DESCRIPTION, (new Object [] {introNode.getNodeName()})); 526 addStatus(IStatus.ERROR, message, null); 527 } 528 529 cheatSheet.setIntroItem(introItem); 530 } 531 532 private void handleIntroAttributes(Item item, Node introNode) { 533 Assert.isNotNull(item); 534 Assert.isNotNull(introNode); 535 536 NamedNodeMap attributes = introNode.getAttributes(); 537 if (attributes != null) { 538 for (int x = 0; x < attributes.getLength(); x++) { 539 Node attribute = attributes.item(x); 540 String attributeName = attribute.getNodeName(); 541 if (attribute == null || attributeName == null) 542 continue; 543 544 if (attributeName.equals(IParserTags.CONTEXTID)) { 545 item.setContextId(attribute.getNodeValue()); 546 } else if (attributeName.equals(IParserTags.HREF)) { 547 item.setHref(attribute.getNodeValue()); 548 } else { 549 String message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ATTRIBUTE, (new Object [] {attributeName, introNode.getNodeName()})); 550 addStatus(IStatus.WARNING, message, null); 551 } 552 } 553 } 554 } 555 556 private Item handleItem(Node itemNode) throws CheatSheetParserException { 557 Assert.isNotNull(itemNode); 558 Assert.isTrue(itemNode.getNodeName().equals(IParserTags.ITEM)); 559 560 Item item = new Item(); 561 562 handleItemAttributes(item, itemNode); 563 564 boolean hasDescription = false; 565 566 NodeList nodes = itemNode.getChildNodes(); 567 568 IncompatibleSiblingChecker checker = new IncompatibleSiblingChecker(this, itemNode); 569 for (int i = 0; i < nodes.getLength(); i++) { 570 Node node = nodes.item(i); 571 checker.checkElement(node.getNodeName()); 572 if(node.getNodeName().equals(IParserTags.ACTION)) { 573 handleExecutable(item, node, new Action()); 574 } else if(node.getNodeName().equals(IParserTags.COMMAND)) { 575 handleExecutable(item, node, new CheatSheetCommand()); 576 } else if(node.getNodeName().equals(IParserTags.DESCRIPTION)) { 577 if (hasDescription) { 578 String message = NLS.bind(Messages.ERROR_PARSING_MULTIPLE_DESCRIPTION, (new Object [] {itemNode.getNodeName()})); 579 addStatus(IStatus.ERROR, message, null); 580 } else { 581 hasDescription = true; 582 handleDescription(item, node); 583 } 584 } else if(node.getNodeName().equals(IParserTags.ON_COMPLETION)) { 585 handleOnCompletion(item, node); 586 } else if(node.getNodeName().equals(IParserTags.SUBITEM)) { 587 handleSubItem(item, node); 588 } else if(node.getNodeName().equals(IParserTags.CONDITIONALSUBITEM)) { 589 handleConditionalSubItem(item, node); 590 } else if(node.getNodeName().equals(IParserTags.REPEATEDSUBITM)) { 591 handleRepeatedSubItem(item, node); 592 } else if(node.getNodeName().equals(IParserTags.PERFORMWHEN)) { 593 handlePerformWhen(item, node); 594 } else { 595 if(node.getNodeType() != Node.TEXT_NODE && node.getNodeType() != Node.COMMENT_NODE ) { 596 String message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ELEMENT, (new Object [] {node.getNodeName(), itemNode.getNodeName()})); 597 addStatus(IStatus.WARNING, message, null); 598 } 599 } 600 } 601 602 if(!hasDescription) { 603 String message = NLS.bind(Messages.ERROR_PARSING_NO_DESCRIPTION, (new Object [] {itemNode.getNodeName()})); 604 addStatus(IStatus.ERROR, message, null); 605 } 606 607 return item; 608 } 609 610 private void handleItemAttributes(Item item, Node itemNode) throws CheatSheetParserException { 611 Assert.isNotNull(item); 612 Assert.isNotNull(itemNode); 613 614 ArrayList itemExtensionElements = new ArrayList (); 615 616 boolean title = false; 617 618 NamedNodeMap attributes = itemNode.getAttributes(); 619 if (attributes != null) { 620 for (int x = 0; x < attributes.getLength(); x++) { 621 Node attribute = attributes.item(x); 622 String attributeName = attribute.getNodeName(); 623 if (attribute == null || attributeName == null) 624 continue; 625 626 if (attributeName.equals(IParserTags.TITLE)) { 627 title = true; 628 item.setTitle(attribute.getNodeValue()); 629 } else if (attributeName.equals(IParserTags.CONTEXTID)) { 630 item.setContextId(attribute.getNodeValue()); 631 } else if (attributeName.equals(IParserTags.HREF)) { 632 item.setHref(attribute.getNodeValue()); 633 } else if (attributeName.equals(IParserTags.SKIP)) { 634 item.setSkip(attribute.getNodeValue().equals(TRUE_STRING)); 635 } else if (attributeName.equals(IParserTags.DIALOG)) { 636 item.setDialog(attribute.getNodeValue().equals(TRUE_STRING)); 637 } else { 638 AbstractItemExtensionElement[] ie = handleUnknownItemAttribute(attribute, itemNode); 639 if (ie != null) { 640 itemExtensionElements.add(ie); 641 } else { 642 String message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ATTRIBUTE, (new Object [] {attributeName, itemNode.getNodeName()})); 643 addStatus(IStatus.WARNING, message, null); 644 } 645 } 646 } 647 } 648 649 if(!title) { 650 String message = NLS.bind(Messages.ERROR_PARSING_NO_TITLE, (new Object [] {itemNode.getNodeName()})); 651 throw new CheatSheetParserException(message); 652 } 653 654 if (itemExtensionElements != null) 655 item.setItemExtensions(itemExtensionElements); 656 } 657 658 private void handlePerformWhen(IPerformWhenItem item, Node performWhenNode) throws CheatSheetParserException { 659 Assert.isNotNull(item); 660 Assert.isNotNull(performWhenNode); 661 Assert.isTrue(performWhenNode.getNodeName().equals(IParserTags.PERFORMWHEN)); 662 663 PerformWhen performWhen = new PerformWhen(); 664 665 boolean condition = false; 666 667 NamedNodeMap attributes = performWhenNode.getAttributes(); 669 if (attributes != null) { 670 for (int x = 0; x < attributes.getLength(); x++) { 671 Node attribute = attributes.item(x); 672 String attributeName = attribute.getNodeName(); 673 if (attribute == null || attributeName == null) 674 continue; 675 676 if (attributeName.equals(IParserTags.CONDITION)) { 677 condition = true; 678 performWhen.setCondition(attribute.getNodeValue()); 679 } else { 680 String message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ATTRIBUTE, (new Object [] {attributeName, performWhenNode.getNodeName()})); 681 addStatus(IStatus.WARNING,message, null); 682 } 683 } 684 } 685 686 if(!condition) { 687 String message = NLS.bind(Messages.ERROR_PARSING_NO_CONDITION, (new Object [] {performWhenNode.getNodeName()})); 688 throw new CheatSheetParserException(message); 689 } 690 691 boolean exeutable = false; 692 693 NodeList nodes = performWhenNode.getChildNodes(); 695 for (int i = 0; i < nodes.getLength(); i++) { 696 Node node = nodes.item(i); 697 if(node.getNodeName().equals(IParserTags.ACTION)) { 698 exeutable = true; 699 handleExecutable(performWhen, node, new Action()); 700 } else if(node.getNodeName().equals(IParserTags.COMMAND)) { 701 exeutable = true; 702 handleExecutable(performWhen, node, new CheatSheetCommand()); 703 } else { 704 if(node.getNodeType() != Node.TEXT_NODE && node.getNodeType() != Node.COMMENT_NODE ) { 705 String message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ELEMENT, (new Object [] {node.getNodeName(), performWhenNode .getNodeName()})); 706 addStatus(IStatus.WARNING, message, null); 707 } 708 } 709 } 710 711 if(!exeutable) { 712 String message = NLS.bind(Messages.ERROR_PARSING_NO_ACTION, (new Object [] {performWhenNode.getNodeName()})); 713 throw new CheatSheetParserException(message); 714 } 715 716 item.setPerformWhen(performWhen); 717 } 718 719 private void handleRepeatedSubItem(Item item, Node repeatedSubItemNode) throws CheatSheetParserException { 720 Assert.isNotNull(item); 721 Assert.isNotNull(repeatedSubItemNode); 722 Assert.isTrue(repeatedSubItemNode.getNodeName().equals(IParserTags.REPEATEDSUBITM)); 723 724 RepeatedSubItem repeatedSubItem = new RepeatedSubItem(); 725 726 boolean values = false; 727 728 NamedNodeMap attributes = repeatedSubItemNode.getAttributes(); 730 if (attributes != null) { 731 for (int x = 0; x < attributes.getLength(); x++) { 732 Node attribute = attributes.item(x); 733 String attributeName = attribute.getNodeName(); 734 if (attribute == null || attributeName == null) 735 continue; 736 737 if (attributeName.equals(IParserTags.VALUES)) { 738 values = true; 739 repeatedSubItem.setValues(attribute.getNodeValue()); 740 } else { 741 String message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ATTRIBUTE, (new Object [] {attributeName, repeatedSubItemNode.getNodeName()})); 742 addStatus(IStatus.WARNING, message, null); 743 } 744 } 745 } 746 747 if(!values) { 748 String message = NLS.bind(Messages.ERROR_PARSING_NO_VALUES, (new Object [] {repeatedSubItemNode.getNodeName()})); 749 throw new CheatSheetParserException(message); 750 } 751 752 boolean subitem = false; 753 754 NodeList nodes = repeatedSubItemNode.getChildNodes(); 756 for (int i = 0; i < nodes.getLength(); i++) { 757 Node node = nodes.item(i); 758 759 if(node.getNodeName().equals(IParserTags.SUBITEM)) { 760 subitem = true; 761 handleSubItem(repeatedSubItem, node); 762 } else { 763 if(node.getNodeType() != Node.TEXT_NODE && node.getNodeType() != Node.COMMENT_NODE ) { 764 String message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ELEMENT, (new Object [] {node.getNodeName(), repeatedSubItemNode.getNodeName()})); 765 addStatus(IStatus.WARNING, message, null); 766 } 767 } 768 } 769 770 if(!subitem) { 771 String message = NLS.bind(Messages.ERROR_PARSING_NO_SUBITEM, (new Object [] {repeatedSubItemNode.getNodeName()})); 772 throw new CheatSheetParserException(message); 773 } 774 775 item.addSubItem(repeatedSubItem); 776 } 777 778 private void handleSubItem(ISubItemItem item, Node subItemNode) throws CheatSheetParserException { 779 Assert.isNotNull(item); 780 Assert.isNotNull(subItemNode); 781 Assert.isTrue(subItemNode.getNodeName().equals(IParserTags.SUBITEM)); 782 783 SubItem subItem = new SubItem(); 784 785 handleSubItemAttributes(subItem, subItemNode); 786 787 IncompatibleSiblingChecker checker = new IncompatibleSiblingChecker(this, subItemNode); 788 789 NodeList nodes = subItemNode.getChildNodes(); 790 for (int i = 0; i < nodes.getLength(); i++) { 791 Node node = nodes.item(i); 792 checker.checkElement(node.getNodeName()); 793 794 if(node.getNodeName().equals(IParserTags.ACTION)) { 795 handleExecutable(subItem, node, new Action()); 796 } else if(node.getNodeName().equals(IParserTags.COMMAND)) { 797 handleExecutable(subItem, node, new CheatSheetCommand()); 798 } else if(node.getNodeName().equals(IParserTags.PERFORMWHEN)) { 799 handlePerformWhen(subItem, node); 800 } else { 801 if(node.getNodeType() != Node.TEXT_NODE && node.getNodeType() != Node.COMMENT_NODE ) { 802 String message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ELEMENT, (new Object [] {node.getNodeName(), subItemNode.getNodeName()})); 803 addStatus(IStatus.WARNING, message, null); 804 } 805 } 806 } 807 item.addSubItem(subItem); 808 } 809 810 private void handleSubItemAttributes(SubItem subItem, Node subItemNode) throws CheatSheetParserException { 811 Assert.isNotNull(subItem); 812 Assert.isNotNull(subItemNode); 813 814 boolean label = false; 815 816 NamedNodeMap attributes = subItemNode.getAttributes(); 817 if (attributes != null) { 818 for (int x = 0; x < attributes.getLength(); x++) { 819 Node attribute = attributes.item(x); 820 String attributeName = attribute.getNodeName(); 821 if (attribute == null || attributeName == null) 822 continue; 823 824 if (attributeName.equals(IParserTags.LABEL)) { 825 label = true; 826 subItem.setLabel(attribute.getNodeValue()); 827 } else if (attributeName.equals(IParserTags.SKIP)) { 828 subItem.setSkip(attribute.getNodeValue().equals(TRUE_STRING)); 829 } else if (attributeName.equals(IParserTags.WHEN)) { 830 subItem.setWhen(attribute.getNodeValue()); 831 } else { 832 String message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ATTRIBUTE, (new Object [] {attributeName, subItemNode.getNodeName()})); 833 addStatus(IStatus.WARNING, message, null); 834 } 835 } 836 } 837 838 if(!label) { 839 String message = NLS.bind(Messages.ERROR_PARSING_NO_LABEL, (new Object [] {subItemNode.getNodeName()})); 840 throw new CheatSheetParserException(message); 841 } 842 } 843 844 private AbstractItemExtensionElement[] handleUnknownItemAttribute(Node item, Node node) { 845 ArrayList al = new ArrayList (); 846 if (itemExtensionContainerList == null) 847 return null; 848 849 for (int i = 0; i < itemExtensionContainerList.size(); i++) { 850 CheatSheetItemExtensionElement itemExtensionElement = (CheatSheetItemExtensionElement) itemExtensionContainerList.get(i); 851 852 if (itemExtensionElement.getItemAttribute().equals(item.getNodeName())) { 853 AbstractItemExtensionElement itemElement = itemExtensionElement.createInstance(); 854 if(itemElement != null) { 855 itemElement.handleAttribute(item.getNodeValue()); 856 al.add(itemElement); 857 } 858 } 859 } 860 861 if(al.size() == 0) { 862 String message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ATTRIBUTE, (new Object [] {item.getNodeName(), node.getNodeName()})); 863 addStatus(IStatus.WARNING, message, null); 864 } 865 return (AbstractItemExtensionElement[])al.toArray(new AbstractItemExtensionElement[al.size()]); 866 } 867 868 public ICheatSheet parse(URL url, String pluginId, int cheatSheetKind) { 869 return parse(new ParserInput(url, pluginId), cheatSheetKind); 870 } 871 872 public ICheatSheet parse(ParserInput input, int cheatSheetKind) { 873 status = Status.OK_STATUS; 874 commandCount = 0; 875 actionCount = 0; 876 if(input == null) { 877 return null; 878 } 879 880 InputStream is = null; 881 InputSource inputSource = null; 882 String filename = ""; URL url = input.getUrl(); 884 885 if (input.getXml() != null) { 886 StringReader reader = new StringReader (input.getXml()); 887 inputSource = new InputSource (reader); 888 } else if (input.getUrl() != null){ 889 try { 890 is = url.openStream(); 891 892 if (is != null) { 893 inputSource = new InputSource (is); 894 } 895 } catch (Exception e) { 896 String message = NLS.bind(Messages.ERROR_OPENING_FILE, (new Object [] {url.getFile()})); 897 addStatus(IStatus.ERROR, message, e); 898 return null; 899 } 900 } else { 901 return null; 902 } 903 904 if (input.getUrl() != null){ 905 filename = url.getFile(); 906 } 907 908 Document document; 909 try { 910 if(documentBuilder == null) { 911 addStatus(IStatus.ERROR, Messages.ERROR_DOCUMENT_BUILDER_NOT_INIT, null); 912 return null; 913 } 914 document = documentBuilder.parse(inputSource); 915 } catch (IOException e) { 916 String message = NLS.bind(Messages.ERROR_OPENING_FILE_IN_PARSER, (new Object [] {filename})); 917 addStatus(IStatus.ERROR, message, e); 918 return null; 919 } catch (SAXParseException spe) { 920 String message = NLS.bind(Messages.ERROR_SAX_PARSING_WITH_LOCATION, (new Object [] {filename, new Integer (spe.getLineNumber()), new Integer (spe.getColumnNumber())})); 921 addStatus(IStatus.ERROR, message, spe); 922 return null; 923 } catch (SAXException se) { 924 String message = NLS.bind(Messages.ERROR_SAX_PARSING, (new Object [] {filename})); 925 addStatus(IStatus.ERROR, message, se); 926 return null; 927 } finally { 928 try { 929 is.close(); 930 } catch (Exception e) { 931 } 932 } 933 934 if (processor == null) { 936 DocumentReader reader = new DocumentReader(); 937 processor = new DocumentProcessor(new ProcessorHandler[] { 938 new FilterHandler(CheatSheetEvaluationContext.getContext()), 939 new NormalizeHandler(), 940 new IncludeHandler(reader, Platform.getNL()), 941 new ExtensionHandler(reader, Platform.getNL()) 942 }); 943 } 944 String documentPath = null; 945 if (input.getPluginId() != null) { 946 documentPath = '/' + input.getPluginId() + input.getUrl().getPath(); 947 } 948 processor.process(UAElementFactory.newElement(document.getDocumentElement()), documentPath); 949 950 if ( cheatSheetKind == COMPOSITE_ONLY || (cheatSheetKind == ANY && isComposite(document))) { 951 CompositeCheatSheetParser compositeParser = new CompositeCheatSheetParser(); 952 CompositeCheatSheetModel result = compositeParser.parseCompositeCheatSheet(document, input.getUrl()); 953 status = compositeParser.getStatus(); 954 return result; 955 } 956 try { 957 return parseCheatSheet(document); 958 } catch(CheatSheetParserException e) { 959 addStatus(IStatus.ERROR, e.getMessage(), e); 960 } 961 return null; 962 } 963 964 private boolean isComposite(Document document) { 965 if (document != null) { 966 Node rootnode = document.getDocumentElement(); 967 return rootnode.getNodeName().equals(ICompositeCheatsheetTags.COMPOSITE_CHEATSHEET) ; 969 } 970 return false; 971 } 972 973 private CheatSheet parseCheatSheet(Document document) throws CheatSheetParserException { 974 if (document != null) { 976 Node rootnode = document.getDocumentElement(); 977 978 if( !rootnode.getNodeName().equals(IParserTags.CHEATSHEET) ) { 980 throw new CheatSheetParserException(Messages.ERROR_PARSING_CHEATSHEET_ELEMENT); 981 } 982 983 CheatSheet cheatSheet = new CheatSheet(); 985 986 handleCheatSheetAttributes(cheatSheet, rootnode); 987 988 boolean hasItem = false; 989 boolean hasIntro = false; 990 991 CheatSheetRegistryReader reader = CheatSheetRegistryReader.getInstance(); 992 itemExtensionContainerList = reader.readItemExtensions(); 993 994 NodeList nodes = rootnode.getChildNodes(); 995 for (int i = 0; i < nodes.getLength(); i++) { 996 Node node = nodes.item(i); 997 998 if(node.getNodeName().equals(IParserTags.ITEM)) { 999 hasItem = true; 1000 Item item = handleItem(node); 1001 cheatSheet.addItem(item); 1002 } else if(node.getNodeName().equals(IParserTags.INTRO)) { 1003 if (hasIntro) { 1004 addStatus(IStatus.ERROR, Messages.ERROR_PARSING_MORE_THAN_ONE_INTRO, null); 1005 } else { 1006 hasIntro = true; 1007 handleIntroNode(cheatSheet, node); 1008 } 1009 } else { 1010 if(node.getNodeType() != Node.TEXT_NODE && node.getNodeType() != Node.COMMENT_NODE ) { 1011 String message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ELEMENT, (new Object [] {node.getNodeName(), rootnode.getNodeName()})); 1012 addStatus(IStatus.WARNING, message, null); 1013 } 1014 } 1015 } 1016 1017 if(!hasIntro) { 1018 addStatus(IStatus.ERROR, Messages.ERROR_PARSING_NO_INTRO, null); 1019 } 1020 if(!hasItem) { 1021 addStatus(IStatus.ERROR, Messages.ERROR_PARSING_NO_ITEM, null); 1022 } 1023 1024 1026 1028 if (status.getSeverity() == IStatus.ERROR) { 1029 return null; 1030 } 1031 1032 cheatSheet.setContainsCommandOrAction(actionCount != 0 || commandCount != 0); 1033 return cheatSheet; 1034 } 1035 throw new CheatSheetParserException(Messages.ERROR_PARSING_CHEATSHEET_CONTENTS); 1036 } 1037 1038 1048 private class NormalizeHandler extends ProcessorHandler { 1049 1050 private static final String ELEMENT_PARAM = "param"; private static final String ATTRIBUTE_NAME = "name"; private static final String ATTRIBUTE_VALUE = "value"; private static final String NAME_PATH = "path"; 1055 public short handle(UAElement element, String id) { 1056 if (id != null && ELEMENT_PARAM.equals(element.getElementName())) { 1057 String name = element.getAttribute(ATTRIBUTE_NAME); 1058 if (NAME_PATH.equals(name)) { 1059 String value = element.getAttribute(ATTRIBUTE_VALUE); 1060 if (value != null) { 1061 int index = id.lastIndexOf('/'); 1062 element.setAttribute(ATTRIBUTE_VALUE, id.substring(0, index + 1) + value); 1063 } 1064 } 1065 return HANDLED_CONTINUE; 1066 } 1067 return UNHANDLED; 1068 } 1069 } 1070} 1071 | Popular Tags |