KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > internal > cheatsheets > data > CheatSheetParser


1 /*******************************************************************************
2  * Copyright (c) 2002, 2007 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 package org.eclipse.ui.internal.cheatsheets.data;
12
13 import java.io.IOException JavaDoc;
14 import java.io.InputStream JavaDoc;
15 import java.io.StringReader JavaDoc;
16 import java.net.URL JavaDoc;
17 import java.util.ArrayList JavaDoc;
18
19 import javax.xml.parsers.DocumentBuilder JavaDoc;
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 JavaDoc;
46 import org.w3c.dom.NamedNodeMap JavaDoc;
47 import org.w3c.dom.Node JavaDoc;
48 import org.w3c.dom.NodeList JavaDoc;
49 import org.xml.sax.InputSource JavaDoc;
50 import org.xml.sax.SAXException JavaDoc;
51 import org.xml.sax.SAXParseException JavaDoc;
52
53 /**
54  * Parser for the cheatsheet content files.
55  *
56  * Construct an intance of the CheatSheetDomParser.
57  * Call <code>parse()</code>.
58  * Then get the content items by calling
59  * <code>getIntroItem()</code> and <code>getItemsList()</code>.
60  * The title of the cheatsheet can be retrieved by calling
61  * <code>getTitle()</code>.
62  *
63  */

64 public class CheatSheetParser implements IStatusContainer {
65
66     private static final String JavaDoc TRUE_STRING = "true"; //$NON-NLS-1$
67

68     private DocumentBuilder JavaDoc documentBuilder;
69     private DocumentProcessor processor;
70     private ArrayList JavaDoc itemExtensionContainerList;
71     
72     // Cheatsheet kinds that can be parsed
73
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     /**
85      * Java constructor comment.
86      */

87     public CheatSheetParser() {
88         super();
89         documentBuilder = CheatSheetPlugin.getPlugin().getDocumentBuilder();
90     }
91     
92     /**
93      * Gets the status of the last call to parse()
94      */

95     public IStatus getStatus() {
96         return status;
97     }
98     
99     public void addStatus(int severity, String JavaDoc message, Throwable JavaDoc exception) {
100         status = ParserStatusUtility.addStatus(status, severity, message, exception);
101     }
102
103     /**
104      * Converts any characters required to escaped by an XML parser to
105      * their escaped counterpart.
106      *
107      * Characters XML escaped counterpart
108      * < -> &lt;
109      * > -> &gt;
110      * & -> &amp;
111      * ' -> &apos;
112      * " -> &quot;
113      *
114      * Tags that will be ignored <b>, </b> and <br/>.
115      *
116      * @param text the string buffer to have its characters escaped
117      * @return string buffer with any of the characters requiring XML escaping escaped
118      */

119     private StringBuffer JavaDoc escapeXMLCharacters(StringBuffer JavaDoc text) {
120         // Set the maximum length of the tags to ignore
121
final int MAXIMUM_TAG_LENGTH = 5;
122         
123         // Keep a local variable for the orignal string's length
124
int length = text.length();
125         
126         // Create the buffer to store the resulting string
127
StringBuffer JavaDoc result = new StringBuffer JavaDoc(length);
128         
129         // Loop for the characters of the original string
130
for(int i=0; i<length; i++) {
131             // Grab the next character and determine how to handle it
132
char c = text.charAt(i);
133             switch (c) {
134                 case '<': {
135                     // We have a less than, grab the maximum tag length of characters
136
// or the remaining characters which follow and determine if it
137
// is the start of a tag to ignore.
138
String JavaDoc 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                         // We have a tag to ignore so just emit the character
146
result.append(c);
147                     } else {
148                         // We have detemined that it is just a less than
149
// so emit the XML escaped counterpart
150
result.append(IParserTags.LESS_THAN);
151                     }
152                     break; }
153                 case '>': {
154                     // We have a greater than, grab the maximum tag length of characters
155
// or the starting characters which come before and determine if it
156
// is the end of a tag to ignore.
157
String JavaDoc 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                         // We have a tag to ignore so just emit the character
165
result.append(c);
166                     } else {
167                         // We have detemined that it is just a greater than
168
// so emit the XML escaped counterpart
169
result.append(IParserTags.GREATER_THAN);
170                     }
171                     break; }
172                 case '&':
173                     // We have an ampersand so emit the XML escaped counterpart
174
result.append(IParserTags.AMPERSAND);
175                     break;
176                 case '\'':
177                     // We have an apostrophe so emit the XML escaped counterpart
178
result.append(IParserTags.APOSTROPHE);
179                     break;
180                 case '"':
181                     // We have a quote so emit the XML escaped counterpart
182
result.append(IParserTags.QUOTE);
183                     break;
184                 case '\t':
185                     // We have a tab, replace with a space
186
result.append(' ');
187                     break;
188                 default:
189                     // We have a character that does not require escaping
190
result.append(c);
191                     break;
192             }
193         }
194         return result;
195     }
196
197     private Node JavaDoc findNode(Node JavaDoc startNode, String JavaDoc nodeName) {
198         if(startNode == null) {
199             return null;
200         }
201
202         if(startNode.getNodeName().equals(nodeName)) {
203             return startNode;
204         }
205
206         NodeList JavaDoc nodes = startNode.getChildNodes();
207         for (int i = 0; i < nodes.getLength(); i++) {
208             Node JavaDoc 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 JavaDoc executableNode, AbstractExecutable executable) throws CheatSheetParserException {
218         Assert.isNotNull(item);
219         Assert.isNotNull(executableNode);
220
221         String JavaDoc[] params = null;
222
223         if (executable instanceof CheatSheetCommand) {
224             commandCount++;
225         }
226         if (executable instanceof Action) {
227             actionCount++;
228         }
229
230         NamedNodeMap JavaDoc attributes = executableNode.getAttributes();
231         if (attributes != null) {
232             for (int x = 0; x < attributes.getLength(); x++) {
233                 Node JavaDoc attribute = attributes.item(x);
234                 String JavaDoc 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                     // Translation hint, no semantic effect
245
} else if (executable.hasParams() && attributeName.startsWith(IParserTags.PARAM)) {
246                     try {
247                         if(params == null) {
248                             params = new String JavaDoc[9];
249                         }
250                         String JavaDoc 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 JavaDoc message = NLS.bind(Messages.ERROR_PARSING_PARAM_INVALIDRANGE, (new Object JavaDoc[] {attributeName, paramNum}));
257                             addStatus(IStatus.ERROR, message, null);
258                         }
259                     } catch(NumberFormatException JavaDoc e) {
260                         String JavaDoc message = Messages.ERROR_PARSING_PARAM_INVALIDNUMBER;
261                         addStatus(IStatus.ERROR, message, e);
262                     }
263                 } else if (!executable.handleAttribute(attribute)) {
264                     String JavaDoc message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ATTRIBUTE, (new Object JavaDoc[] {attributeName, executableNode.getNodeName()}));
265                     addStatus(IStatus.WARNING, message, null);
266                 }
267             }
268             String JavaDoc 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 JavaDoc parentNode) {
279         NodeList JavaDoc nodes = parentNode.getChildNodes();
280         for (int i = 0; i < nodes.getLength(); i++) {
281             Node JavaDoc node = nodes.item(i);
282             if(node.getNodeType() != Node.TEXT_NODE && node.getNodeType() != Node.COMMENT_NODE ) {
283                 String JavaDoc message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ELEMENT, (new Object JavaDoc[] {node.getNodeName(), parentNode.getNodeName()}));
284                 addStatus(IStatus.WARNING, message, null);
285             }
286         }
287     }
288
289     private void handleCheatSheetAttributes(CheatSheet cheatSheet, Node JavaDoc 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 JavaDoc attributes = cheatSheetNode.getAttributes();
297         if (attributes != null) {
298             for (int x = 0; x < attributes.getLength(); x++) {
299                 Node JavaDoc attribute = attributes.item(x);
300                 String JavaDoc 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 JavaDoc message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ATTRIBUTE, (new Object JavaDoc[] {attributeName, cheatSheetNode.getNodeName()}));
309                     addStatus(IStatus.WARNING, message, null);
310                 }
311             }
312         }
313
314         if(!title) {
315             String JavaDoc message = NLS.bind(Messages.ERROR_PARSING_NO_TITLE, (new Object JavaDoc[] {cheatSheetNode.getNodeName()}));
316             throw new CheatSheetParserException(message);
317         }
318     }
319
320     private void handleConditionalSubItem(Item item, Node JavaDoc 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         // Handle attributes
330
NamedNodeMap JavaDoc attributes = conditionalSubItemNode.getAttributes();
331         if (attributes != null) {
332             for (int x = 0; x < attributes.getLength(); x++) {
333                 Node JavaDoc attribute = attributes.item(x);
334                 String JavaDoc 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 JavaDoc message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ATTRIBUTE, (new Object JavaDoc[] {attributeName, conditionalSubItemNode.getNodeName()}));
343                     addStatus(IStatus.WARNING, message, null);
344                 }
345             }
346         }
347
348         if(!condition) {
349             String JavaDoc message = NLS.bind(Messages.ERROR_PARSING_NO_CONDITION, (new Object JavaDoc[] {conditionalSubItemNode.getNodeName()}));
350             throw new CheatSheetParserException(message);
351         }
352
353         boolean subitem = false;
354
355         // Handle nodes
356
NodeList JavaDoc nodes = conditionalSubItemNode.getChildNodes();
357         for (int i = 0; i < nodes.getLength(); i++) {
358             Node JavaDoc 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 JavaDoc message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ELEMENT, (new Object JavaDoc[] {node.getNodeName(), conditionalSubItemNode.getNodeName()}));
366                     addStatus(IStatus.WARNING, message, null);
367                 }
368             }
369         }
370
371         if(!subitem) {
372             String JavaDoc message = NLS.bind(Messages.ERROR_PARSING_NO_SUBITEM, (new Object JavaDoc[] {conditionalSubItemNode.getNodeName()}));
373             throw new CheatSheetParserException(message);
374         }
375
376         item.addSubItem(conditionalSubItem);
377     }
378
379     private void handleDescription(Item item, Node JavaDoc startNode) throws CheatSheetParserException {
380         Assert.isNotNull(item);
381         Assert.isNotNull(startNode);
382
383         Node JavaDoc descriptionNode = findNode(startNode, IParserTags.DESCRIPTION);
384         
385         if(descriptionNode != null) {
386             String JavaDoc text = handleMarkedUpText(descriptionNode, startNode, IParserTags.DESCRIPTION);
387             item.setDescription(text);
388         } else {
389             Node JavaDoc parentNode = startNode;
390             if( startNode.getNodeName().equals(IParserTags.DESCRIPTION) ) {
391                 parentNode = startNode.getParentNode();
392             }
393             String JavaDoc message = NLS.bind(Messages.ERROR_PARSING_NO_DESCRIPTION, (new Object JavaDoc[] {parentNode.getNodeName()}));
394             throw new CheatSheetParserException(message);
395         }
396     }
397
398     private String JavaDoc handleMarkedUpText(Node JavaDoc nodeContainingText, Node JavaDoc startNode, String JavaDoc nodeName ) {
399         NodeList JavaDoc nodes = nodeContainingText.getChildNodes();
400         StringBuffer JavaDoc text = new StringBuffer JavaDoc();
401         
402         boolean containsMarkup = false;
403         
404         // The documentation for the content file specifies
405
// that leading whitespace should be ignored at the
406
// beginning of a description or after a <br/>. This
407
// applies also to <onCompletion> elements.
408
// See Bug 129208 and Bug 131185
409
boolean isLeadingTrimRequired = true;
410
411         for (int i = 0; i < nodes.getLength(); i++) {
412             Node JavaDoc node = nodes.item(i);
413             if(node.getNodeType() == Node.TEXT_NODE) {
414                 String JavaDoc 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                 // handle <b></b> and <br/>
422
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         // Remove the new line, form feed and tab chars
447
return text.toString().trim();
448     }
449
450     // Replace any tabs with spaces
451

452     private void deTab(StringBuffer JavaDoc 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 JavaDoc trimLeadingWhitespace(String JavaDoc 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     /*
473      * Write a warning to the log
474      */

475     private void warnUnknownMarkupElement(Node JavaDoc startNode, String JavaDoc nodeName, Node JavaDoc node) {
476         Node JavaDoc parentNode = startNode;
477         if( startNode.getNodeName().equals(nodeName) ) {
478             parentNode = startNode.getParentNode();
479         }
480         String JavaDoc message;
481         if (IParserTags.DESCRIPTION.equals(nodeName)) {
482             message = NLS.bind(Messages.WARNING_PARSING_DESCRIPTION_UNKNOWN_ELEMENT, (new Object JavaDoc[] {parentNode.getNodeName(), node.getNodeName()}));
483         } else {
484             message = NLS.bind(Messages.WARNING_PARSING_ON_COMPLETION_UNKNOWN_ELEMENT, (new Object JavaDoc[] {parentNode.getNodeName(), node.getNodeName()}));
485         }
486         addStatus(IStatus.WARNING, message, null);
487
488     }
489     
490     private void handleOnCompletion(Item item, Node JavaDoc onCompletionNode) {
491         String JavaDoc text = handleMarkedUpText(onCompletionNode, onCompletionNode, IParserTags.ON_COMPLETION);
492         item.setCompletionMessage(text);
493     }
494     
495     private void handleIntroNode(CheatSheet cheatSheet, Node JavaDoc 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 JavaDoc nodes = introNode.getChildNodes();
505         for (int i = 0; i < nodes.getLength(); i++) {
506             Node JavaDoc node = nodes.item(i);
507
508             if(node.getNodeName().equals(IParserTags.DESCRIPTION)) {
509                 if (hasDescription) {
510                     String JavaDoc message = NLS.bind(Messages.ERROR_PARSING_MULTIPLE_DESCRIPTION, (new Object JavaDoc[] {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 JavaDoc message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ELEMENT, (new Object JavaDoc[] {node.getNodeName(), introNode.getNodeName()}));
519                     addStatus(IStatus.WARNING, message, null);
520                 }
521             }
522         }
523
524         if(!hasDescription) {
525             String JavaDoc message = NLS.bind(Messages.ERROR_PARSING_NO_DESCRIPTION, (new Object JavaDoc[] {introNode.getNodeName()}));
526             addStatus(IStatus.ERROR, message, null);
527         }
528
529         cheatSheet.setIntroItem(introItem);
530     }
531
532     private void handleIntroAttributes(Item item, Node JavaDoc introNode) {
533         Assert.isNotNull(item);
534         Assert.isNotNull(introNode);
535
536         NamedNodeMap JavaDoc attributes = introNode.getAttributes();
537         if (attributes != null) {
538             for (int x = 0; x < attributes.getLength(); x++) {
539                 Node JavaDoc attribute = attributes.item(x);
540                 String JavaDoc 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 JavaDoc message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ATTRIBUTE, (new Object JavaDoc[] {attributeName, introNode.getNodeName()}));
550                     addStatus(IStatus.WARNING, message, null);
551                 }
552             }
553         }
554     }
555
556     private Item handleItem(Node JavaDoc 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 JavaDoc nodes = itemNode.getChildNodes();
567         
568         IncompatibleSiblingChecker checker = new IncompatibleSiblingChecker(this, itemNode);
569         for (int i = 0; i < nodes.getLength(); i++) {
570             Node JavaDoc 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 JavaDoc message = NLS.bind(Messages.ERROR_PARSING_MULTIPLE_DESCRIPTION, (new Object JavaDoc[] {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 JavaDoc message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ELEMENT, (new Object JavaDoc[] {node.getNodeName(), itemNode.getNodeName()}));
597                     addStatus(IStatus.WARNING, message, null);
598                 }
599             }
600         }
601
602         if(!hasDescription) {
603             String JavaDoc message = NLS.bind(Messages.ERROR_PARSING_NO_DESCRIPTION, (new Object JavaDoc[] {itemNode.getNodeName()}));
604             addStatus(IStatus.ERROR, message, null);
605         }
606         
607         return item;
608     }
609
610     private void handleItemAttributes(Item item, Node JavaDoc itemNode) throws CheatSheetParserException {
611         Assert.isNotNull(item);
612         Assert.isNotNull(itemNode);
613
614         ArrayList JavaDoc itemExtensionElements = new ArrayList JavaDoc();
615
616         boolean title = false;
617
618         NamedNodeMap JavaDoc attributes = itemNode.getAttributes();
619         if (attributes != null) {
620             for (int x = 0; x < attributes.getLength(); x++) {
621                 Node JavaDoc attribute = attributes.item(x);
622                 String JavaDoc 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 JavaDoc message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ATTRIBUTE, (new Object JavaDoc[] {attributeName, itemNode.getNodeName()}));
643                         addStatus(IStatus.WARNING, message, null);
644                     }
645                 }
646             }
647         }
648
649         if(!title) {
650             String JavaDoc message = NLS.bind(Messages.ERROR_PARSING_NO_TITLE, (new Object JavaDoc[] {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 JavaDoc 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         // Handle attributes
668
NamedNodeMap JavaDoc attributes = performWhenNode.getAttributes();
669         if (attributes != null) {
670             for (int x = 0; x < attributes.getLength(); x++) {
671                 Node JavaDoc attribute = attributes.item(x);
672                 String JavaDoc 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 JavaDoc message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ATTRIBUTE, (new Object JavaDoc[] {attributeName, performWhenNode.getNodeName()}));
681                     addStatus(IStatus.WARNING,message, null);
682                 }
683             }
684         }
685
686         if(!condition) {
687             String JavaDoc message = NLS.bind(Messages.ERROR_PARSING_NO_CONDITION, (new Object JavaDoc[] {performWhenNode.getNodeName()}));
688             throw new CheatSheetParserException(message);
689         }
690
691         boolean exeutable = false;
692
693         // Handle nodes
694
NodeList JavaDoc nodes = performWhenNode.getChildNodes();
695         for (int i = 0; i < nodes.getLength(); i++) {
696             Node JavaDoc 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 JavaDoc message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ELEMENT, (new Object JavaDoc[] {node.getNodeName(), performWhenNode .getNodeName()}));
706                     addStatus(IStatus.WARNING, message, null);
707                 }
708             }
709         }
710
711         if(!exeutable) {
712             String JavaDoc message = NLS.bind(Messages.ERROR_PARSING_NO_ACTION, (new Object JavaDoc[] {performWhenNode.getNodeName()}));
713             throw new CheatSheetParserException(message);
714         }
715
716         item.setPerformWhen(performWhen);
717     }
718
719     private void handleRepeatedSubItem(Item item, Node JavaDoc 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         // Handle attributes
729
NamedNodeMap JavaDoc attributes = repeatedSubItemNode.getAttributes();
730         if (attributes != null) {
731             for (int x = 0; x < attributes.getLength(); x++) {
732                 Node JavaDoc attribute = attributes.item(x);
733                 String JavaDoc 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 JavaDoc message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ATTRIBUTE, (new Object JavaDoc[] {attributeName, repeatedSubItemNode.getNodeName()}));
742                     addStatus(IStatus.WARNING, message, null);
743                 }
744             }
745         }
746
747         if(!values) {
748             String JavaDoc message = NLS.bind(Messages.ERROR_PARSING_NO_VALUES, (new Object JavaDoc[] {repeatedSubItemNode.getNodeName()}));
749             throw new CheatSheetParserException(message);
750         }
751
752         boolean subitem = false;
753
754         // Handle nodes
755
NodeList JavaDoc nodes = repeatedSubItemNode.getChildNodes();
756         for (int i = 0; i < nodes.getLength(); i++) {
757             Node JavaDoc 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 JavaDoc message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ELEMENT, (new Object JavaDoc[] {node.getNodeName(), repeatedSubItemNode.getNodeName()}));
765                     addStatus(IStatus.WARNING, message, null);
766                 }
767             }
768         }
769
770         if(!subitem) {
771             String JavaDoc message = NLS.bind(Messages.ERROR_PARSING_NO_SUBITEM, (new Object JavaDoc[] {repeatedSubItemNode.getNodeName()}));
772             throw new CheatSheetParserException(message);
773         }
774
775         item.addSubItem(repeatedSubItem);
776     }
777
778     private void handleSubItem(ISubItemItem item, Node JavaDoc 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 JavaDoc nodes = subItemNode.getChildNodes();
790         for (int i = 0; i < nodes.getLength(); i++) {
791             Node JavaDoc 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 JavaDoc message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ELEMENT, (new Object JavaDoc[] {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 JavaDoc subItemNode) throws CheatSheetParserException {
811         Assert.isNotNull(subItem);
812         Assert.isNotNull(subItemNode);
813
814         boolean label = false;
815
816         NamedNodeMap JavaDoc attributes = subItemNode.getAttributes();
817         if (attributes != null) {
818             for (int x = 0; x < attributes.getLength(); x++) {
819                 Node JavaDoc attribute = attributes.item(x);
820                 String JavaDoc 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 JavaDoc message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ATTRIBUTE, (new Object JavaDoc[] {attributeName, subItemNode.getNodeName()}));
833                     addStatus(IStatus.WARNING, message, null);
834                 }
835             }
836         }
837
838         if(!label) {
839             String JavaDoc message = NLS.bind(Messages.ERROR_PARSING_NO_LABEL, (new Object JavaDoc[] {subItemNode.getNodeName()}));
840             throw new CheatSheetParserException(message);
841         }
842     }
843
844     private AbstractItemExtensionElement[] handleUnknownItemAttribute(Node JavaDoc item, Node JavaDoc node) {
845         ArrayList JavaDoc al = new ArrayList JavaDoc();
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 JavaDoc message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ATTRIBUTE, (new Object JavaDoc[] {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 JavaDoc url, String JavaDoc 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 JavaDoc is = null;
881         InputSource JavaDoc inputSource = null;
882         String JavaDoc filename = ""; //$NON-NLS-1$
883
URL JavaDoc url = input.getUrl();
884
885         if (input.getXml() != null) {
886             StringReader JavaDoc reader = new StringReader JavaDoc(input.getXml());
887             inputSource = new InputSource JavaDoc(reader);
888         } else if (input.getUrl() != null){
889             try {
890                 is = url.openStream();
891     
892                 if (is != null) {
893                     inputSource = new InputSource JavaDoc(is);
894                 }
895             } catch (Exception JavaDoc e) {
896                 String JavaDoc message = NLS.bind(Messages.ERROR_OPENING_FILE, (new Object JavaDoc[] {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 JavaDoc 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 JavaDoc e) {
916             String JavaDoc message = NLS.bind(Messages.ERROR_OPENING_FILE_IN_PARSER, (new Object JavaDoc[] {filename}));
917             addStatus(IStatus.ERROR, message, e);
918             return null;
919         } catch (SAXParseException JavaDoc spe) {
920             String JavaDoc message = NLS.bind(Messages.ERROR_SAX_PARSING_WITH_LOCATION, (new Object JavaDoc[] {filename, new Integer JavaDoc(spe.getLineNumber()), new Integer JavaDoc(spe.getColumnNumber())}));
921             addStatus(IStatus.ERROR, message, spe);
922             return null;
923         } catch (SAXException JavaDoc se) {
924             String JavaDoc message = NLS.bind(Messages.ERROR_SAX_PARSING, (new Object JavaDoc[] {filename}));
925             addStatus(IStatus.ERROR, message, se);
926             return null;
927         } finally {
928             try {
929                 is.close();
930             } catch (Exception JavaDoc e) {
931             }
932         }
933
934         // process dynamic content, normalize paths
935
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 JavaDoc 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 JavaDoc document) {
965         if (document != null) {
966             Node JavaDoc rootnode = document.getDocumentElement();
967             // Is the root node compositeCheatsheet?
968
return rootnode.getNodeName().equals(ICompositeCheatsheetTags.COMPOSITE_CHEATSHEET) ;
969         }
970         return false;
971     }
972
973     private CheatSheet parseCheatSheet(Document JavaDoc document) throws CheatSheetParserException {
974         // If the document passed is null return a null tree and update the status
975
if (document != null) {
976             Node JavaDoc rootnode = document.getDocumentElement();
977             
978             // Is the root node really <cheatsheet>?
979
if( !rootnode.getNodeName().equals(IParserTags.CHEATSHEET) ) {
980                 throw new CheatSheetParserException(Messages.ERROR_PARSING_CHEATSHEET_ELEMENT);
981             }
982
983             // Create the cheat sheet model object
984
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 JavaDoc nodes = rootnode.getChildNodes();
995             for (int i = 0; i < nodes.getLength(); i++) {
996                 Node JavaDoc 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 JavaDoc message = NLS.bind(Messages.WARNING_PARSING_UNKNOWN_ELEMENT, (new Object JavaDoc[] {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            //handleIntro(cheatSheet, document);
1025

1026            //handleItems(cheatSheet, document);
1027

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    /*
1039     * Normalizes composite cheat sheet-relative paths to simple cheat sheets into fully
1040     * qualified paths, e.g. for the path "tasks/mySimpleCheatSheet.xml" in composite cheat
1041     * sheet "/my.plugin/cheatsheets/myCompositeCheatSheet.xml", this normalizes to
1042     * "/my.plugin/cheatsheets/tasks/mySimpleCheatSheet.xml".
1043     *
1044     * This is necessary because with dynamic content we are pulling in tasks from other
1045     * plug-ins and those tasks have relative paths. It also only applies for cheat sheets
1046     * located in running plug-ins.
1047     */

1048    private class NormalizeHandler extends ProcessorHandler {
1049        
1050        private static final String JavaDoc ELEMENT_PARAM = "param"; //$NON-NLS-1$
1051
private static final String JavaDoc ATTRIBUTE_NAME = "name"; //$NON-NLS-1$
1052
private static final String JavaDoc ATTRIBUTE_VALUE = "value"; //$NON-NLS-1$
1053
private static final String JavaDoc NAME_PATH = "path"; //$NON-NLS-1$
1054

1055        public short handle(UAElement element, String JavaDoc id) {
1056            if (id != null && ELEMENT_PARAM.equals(element.getElementName())) {
1057                String JavaDoc name = element.getAttribute(ATTRIBUTE_NAME);
1058                if (NAME_PATH.equals(name)) {
1059                    String JavaDoc 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