KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > javacore > parser > JavaDocParser


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.javacore.parser;
21
22 import java.util.Arrays JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.List JavaDoc;
25 import java.util.ArrayList JavaDoc;
26
27
28 /** JavaDoc Parser.
29  *
30  * @author Vladimir Hudec
31  */

32 public class JavaDocParser {
33
34     private static final String JavaDoc TEXT_TAG_NAME = "@@@@@"; // NOI18N
35

36     protected String JavaDoc rawText;
37     protected JavaDocTag[] tags;
38
39     /**
40      * Native line separator.
41      */

42     private static final String JavaDoc lineSeparator;
43     private static final int lineSeparatorLength;
44
45     static {
46         String JavaDoc sep = System.getProperty("line.separator"); // NOI18N
47
if (sep == null || sep.equals("\n")) { // NOI18N
48
lineSeparator = null;
49             lineSeparatorLength = 0;
50         } else {
51             lineSeparator = sep;
52             lineSeparatorLength = sep.length();
53         }
54     }
55     
56     
57     /** Constructs the JavaDoc object held in memory. Parses the tags from rawText.
58      */

59     
60     public JavaDocParser(String JavaDoc rawText) {
61         this.rawText = rawText;
62         this.tags = null;
63     }
64     
65     /** Constructs the JavaDoc object held in memory. Used for rawText construction.
66      */

67     
68     public JavaDocParser(JavaDocTag[] tags) {
69         this.rawText = null;
70         this.tags = tags;
71     }
72     
73     public JavaDocParser(String JavaDoc text, JavaDocTag[] tags) {
74         this.rawText = null;
75         if (text == null) {
76             this.tags = tags;
77         }
78         else {
79             int newSize = (tags != null) ? tags.length+1 : 1;
80             JavaDocTag[] newTags = new JavaDocTag[newSize];
81             newTags[0] = new JavaDocTag(TEXT_TAG_NAME, text);
82             if (tags != null)
83                 System.arraycopy(tags, 0, newTags, 1, tags.length);
84             this.tags = newTags;
85         }
86     }
87     
88     /** Get the entire text of the comment.
89      * @return the whole text
90      */

91     public String JavaDoc getRawText() {
92         return getRawText(false);
93     }
94     public String JavaDoc getRawText(boolean reorder) {
95         if (rawText != null && !reorder)
96             return rawText;
97         if (rawText != null)
98             tags = getTags();
99         if (reorder)
100             Arrays.sort(tags);
101         String JavaDoc javadocContent = buildComment(tags);
102         //return surroundWithJavaDocStars(javadocContent);
103
return javadocContent;
104     }
105     
106     /** Clears the javadoc from the source.
107      */

108     public void clearJavaDoc() {
109         rawText = null;
110     }
111     
112     /** Test if this javadoc is empty.
113      * @return true if it is not generated to the source.
114      */

115     public boolean isEmpty() {
116         return rawText == null;
117     }
118     
119     /** Gets all tags from comment.
120      */

121     public JavaDocTag[] getTags() {
122         if (tags != null)
123             return tags;
124             
125         if ( rawText == null )
126             return null;
127         
128         List JavaDoc tagList = new ArrayList JavaDoc();
129         int[] textIndexes = removeJavaDocStars(getRawText());
130         parseComment(tagList, getRawText(), textIndexes);
131         
132         JavaDocTag[] tagArray = new JavaDocTag[tagList.size()];
133         tagList.toArray(tagArray);
134         return tagArray;
135     }
136     
137     /** Gets all tags of given name
138      */

139     public JavaDocTag[] getTags(String JavaDoc name) {
140         JavaDocTag[] allTags = getTags();
141         ArrayList JavaDoc resultList = new ArrayList JavaDoc( allTags.length );
142         
143         for( int i = 0; i < allTags.length; i++ ) {
144             if (allTags[i].getName().equals(name))
145                 resultList.add(allTags[i]);
146         }
147         
148         JavaDocTag result[] = new JavaDocTag[resultList.size()];
149         resultList.toArray(result);
150         return result;
151     }
152     
153     // PRIVATE & UTILITY METHODS ----------------------------------------------------------
154

155     /**
156      * Parses the rawText and generates list of tags;
157      */

158     
159     private void parseComment(List JavaDoc tagList, String JavaDoc textWithStars, int[] textIndexes) {
160         final int IN_TEXT = 1;
161         final int TAG_GAP = 2;
162         final int TAG_NAME = 3;
163         final int TAG_TEXT = 4;
164         
165         int state = IN_TEXT;
166         
167         boolean newLine = true;
168         
169         int tagStart = 0;
170         int tagEnd = 0;
171         int textStart = 0;
172         int textEnd = 0;
173         int lastNonWhite = -1;
174         String JavaDoc rawText = rebuildText(textWithStars, textIndexes);
175         //System.out.println("parseComment(): rawText=>"+rawText+"<");
176
//System.out.println("parseComment(): lineSeparator=>"+lineSeparator+"<");
177
int len = rawText.length();
178         
179         for (int i = 0; i < len; ++i) {
180             
181             char ch = rawText.charAt(i);
182             boolean isWhite = Character.isWhitespace(ch);
183             
184             switch (state) {
185                 case IN_TEXT:
186                     if (newLine && ch == '@') {
187                         parseCommentComponent(tagList, rawText, textIndexes, -1, -1, 0, textEnd);
188                         tagStart = i;
189                         state = TAG_NAME;
190                     }
191                     break;
192                 case TAG_NAME:
193                     if (isWhite) {
194                         tagEnd = i;
195                         state = TAG_GAP;
196                     }
197                     break;
198                 case TAG_GAP:
199                     if (isWhite) {
200                         break;
201                     }
202                     textStart = i;
203                     state = TAG_TEXT;
204                     // Fall through (in case of @tagname\n@anothertagname)
205
case TAG_TEXT:
206                     if (newLine && ch == '@') {
207                         parseCommentComponent(tagList, rawText, textIndexes, tagStart, tagEnd, textStart, lastNonWhite + 1);
208                         tagStart = i;
209                         state = TAG_NAME;
210                     }
211                     break;
212             }
213             
214             // more idiot-proof check for newline terminator:
215
if (lineSeparator != null && i + lineSeparatorLength <= len && rawText.regionMatches(i, lineSeparator, 0, lineSeparatorLength)) {
216                 newLine = true;
217                 if (state == IN_TEXT) {
218                     textEnd = i;
219                 }
220                 // advance the scan pointer after the separator string.
221
i += lineSeparatorLength - 1;
222             } else if (ch == '\n') {
223                 newLine = true;
224                 if (state == IN_TEXT) {
225                     textEnd = i;
226                 }
227             } else if (!isWhite) {
228                 lastNonWhite = i;
229                 newLine = false;
230             }
231         }
232         
233         // Finish what's currently being processed
234
switch (state) {
235             case TAG_NAME:
236                 tagEnd = len;
237                 /* fall thru */
238             case TAG_GAP:
239                 textStart = len;
240                 /* fall thru */
241             case TAG_TEXT:
242             case IN_TEXT:
243                 parseCommentComponent(tagList, rawText, textIndexes, tagStart, tagEnd, textStart, lastNonWhite + 1);
244                 break;
245         };
246         
247     }
248     
249     /**
250      * Parses the tag.
251      * Saves away the last parsed item.
252      */

253     private void parseCommentComponent(List JavaDoc tagList, String JavaDoc text, int[] textIndexes, int tagStart, int tagEnd, int textStart, int textEnd) {
254         //System.out.println("parseCommentComponent: "+tagStart+","+tagEnd+","+textStart+","+textEnd);
255
//System.out.println("parseCommentComponent: "+textIndex(textIndexes,tagStart)+","+textIndex(textIndexes,tagEnd)+","+textIndex(textIndexes,textStart)+","+textIndex(textIndexes,textEnd));
256
String JavaDoc tagName = (tagStart < 0 || tagEnd < 0 || tagStart > tagEnd || (tagStart == 0 && tagEnd == 0)) ? TEXT_TAG_NAME : text.substring(tagStart, tagEnd);
257         String JavaDoc tx = (textStart < 0 || textEnd < 0 || textStart > textEnd) ? "" : text.substring(textStart, textEnd);
258         
259         if (TEXT_TAG_NAME.equals(tagName)) {
260             JavaDocTag tag = new JavaDocTag(TEXT_TAG_NAME, tx, -1, -1, (textIndexes!=null)?textIndexes[textStart]:textStart, (textIndexes!=null)?textIndexes[textEnd]:textEnd);
261             tagList.add(tag);
262         }
263         else {
264             JavaDocTag tag = new JavaDocTag(tagName, tx, (textIndexes!=null)?textIndexes[tagStart]:tagStart, (textIndexes!=null)?textIndexes[tagEnd]:tagEnd,
265                                             (textIndexes!=null)?textIndexes[textStart]:textStart, (textIndexes!=null)?textIndexes[textEnd]:textEnd);
266             tagList.add(tag);
267         }
268     }
269     
270     public int[] removeJavaDocStars(String JavaDoc rawText) {
271         final int SPACE_BEFORE=1;
272         final int ASTERIX=2;
273         final int SPACE_AFTER=3;
274         final int TEXT=4;
275         final int LINE_BREAK=5;
276         
277         if (rawText == null || rawText.length() < 4)
278             return null;
279         
280         int len = rawText.length();
281         int text[] = new int[len];
282         int i, j = 0;
283         int state = ASTERIX;
284         
285         int start = rawText.indexOf("/*");
286         int end = rawText.lastIndexOf("*/"); // NOI18N
287
if (start == -1 || end == -1 || (start+2) > end)
288             return null;
289         int linebreak = -1;
290         
291         for (i=start+2; i<end; i++) {
292             char ch = rawText.charAt(i);
293             if (ch=='\n' || ch=='\r')
294                 linebreak = i;
295             else if (ch=='*' && linebreak >= 0)
296                 linebreak = -1;
297             
298             switch (state) {
299                 case SPACE_BEFORE:
300                     if (ch=='*')
301                         state = ASTERIX;
302                     else if (ch=='\n' || ch=='\r')
303                         state = LINE_BREAK;
304                     else if (ch!=' ' && ch!='\t')
305                         state = TEXT;
306                     break;
307                 case SPACE_AFTER:
308                     if (ch=='\n' || ch=='\r')
309                         state = LINE_BREAK;
310                     else if (ch!=' ' && ch!='\t')
311                         state = TEXT;
312                     break;
313                 case ASTERIX:
314                     if (ch=='\n' || ch=='\r')
315                         state = LINE_BREAK;
316                     else if (ch==' ' || ch=='\t')
317                         state = SPACE_AFTER;
318                     else if (ch != '*')
319                         state = TEXT;
320                     break;
321                 case TEXT:
322                     if (ch=='\n' || ch=='\r')
323                         state = LINE_BREAK;
324                     break;
325                 case LINE_BREAK:
326                     if (ch=='*')
327                         state = ASTERIX;
328                     else if (ch==' ' || ch=='\t')
329                         state = SPACE_BEFORE;
330                     else if (ch!='\n' && ch!='\r')
331                         state = TEXT;
332                     break;
333             }
334             
335             if (state==LINE_BREAK || state==SPACE_AFTER) {
336                 text[j++]=i;
337             }
338             else if (state==TEXT) {
339                 if (linebreak != -1) {
340                     for (int k = linebreak+1; k <= i; k++) {
341                         text[j++]=k;
342                     }
343                     linebreak = -1;
344                 }
345                 else {
346                     text[j++]=i;
347                 }
348             }
349         }
350         
351         int result[];
352         if (j < len) {
353             result = new int[j];
354             System.arraycopy(text, 0, result, 0, j);
355         }
356         else
357             result = text;
358         return result;
359     }
360     
361     private String JavaDoc rebuildText(String JavaDoc text, int[] textIndexes) {
362         String JavaDoc rawText = text;
363         if (textIndexes != null) {
364             char[] rawTextChars = new char[textIndexes.length];
365             for (int i = 0; i < textIndexes.length; i++)
366                 rawTextChars[i] = text.charAt(textIndexes[i]);
367             rawText = new String JavaDoc(rawTextChars, 0, rawTextChars.length);
368         }
369         return rawText;
370     }
371     
372     private String JavaDoc buildComment(JavaDocTag[] tags) {
373         if (tags == null)
374             return null;
375         if (tags.length == 0)
376             return "";
377             
378         String JavaDoc separator = (lineSeparator != null) ? lineSeparator : "\n"; // NOI18N
379
String JavaDoc separator2 = separator+separator;
380         
381         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
382         for (int i = 0; i < tags.length; i++) {
383             if (TEXT_TAG_NAME.equals(tags[i].getName())) {
384                 String JavaDoc value = tags[i].getValue();
385                 sb.append(value);
386                 
387                 if (!value.endsWith(separator2)) {
388                     if (!value.endsWith(separator)) {
389                         sb.append('\n');
390                     }
391                     sb.append('\n');
392                 }
393             }
394             else {
395                 String JavaDoc value = tags[i].getValue();
396                 sb.append(tags[i].getName()).append(" ").append(value); // NOI18N
397
if (!value.endsWith(separator)) {
398                     sb.append(separator);
399                 }
400             }
401         }
402         return sb.toString();
403     }
404
405     /**
406      * Creates javaDoc comment from provided parameter.
407      *
408      * @param javadocContent contents
409      * @return javadoc comment created from provided string
410      */

411     public static String JavaDoc surroundWithJavaDocStars(String JavaDoc javadocContent) {
412         if (javadocContent == null)
413             return null;
414         
415         String JavaDoc separator = "\n"; // NOI18N
416

417         StringBuffer JavaDoc sb = new StringBuffer JavaDoc("/**\n *"); // NOI18N
418
String JavaDoc[] tokens = javadocContent.split(separator);
419         for (int i = 0; i < tokens.length; i++) {
420             if (!tokens[i].startsWith(" ")) {
421                 sb.append(' ');
422             }
423             sb.append(tokens[i]);
424             sb.append(separator).append(" *"); // NOI18N
425
}
426         sb.append('/'); // NOI18N
427
return sb.toString();
428     }
429     
430     
431     public static class JavaDocTag implements Comparable JavaDoc {
432         public static final HashMap JavaDoc nameValues = new HashMap JavaDoc();
433         static {
434             nameValues.put(TEXT_TAG_NAME, new Integer JavaDoc(1));
435             nameValues.put("@author", new Integer JavaDoc(2)); // NOI18N
436
nameValues.put("@version", new Integer JavaDoc(3)); // NOI18N
437
nameValues.put("@param", new Integer JavaDoc(4)); // NOI18N
438
nameValues.put("@return", new Integer JavaDoc(5)); // NOI18N
439
nameValues.put("@exception", new Integer JavaDoc(6)); // NOI18N
440
nameValues.put("@see", new Integer JavaDoc(7)); // NOI18N
441
nameValues.put("@since", new Integer JavaDoc(8)); // NOI18N
442
nameValues.put("@serial", new Integer JavaDoc(9)); // NOI18N
443
nameValues.put("@deprecated", new Integer JavaDoc(10)); // NOI18N
444
}
445         
446         String JavaDoc name;
447         String JavaDoc text;
448         
449         /** Holds value of property startName. */
450         private int startName;
451         
452         /** Holds value of property endName. */
453         private int endName;
454         
455         /** Holds value of property startText. */
456         private int startText;
457         
458         /** Holds value of property endText. */
459         private int endText;
460         
461         
462         public JavaDocTag(String JavaDoc name, String JavaDoc text) {
463             this.name = name;
464             this.text = text;
465             startName = endName = startText = endText = -1;
466         }
467         
468         JavaDocTag(String JavaDoc name, String JavaDoc text, int startName, int endName, int startText, int endText) {
469             this.name = name;
470             this.text = text;
471             this.startName = startName;
472             this.endName = endName;
473             this.startText = startText;
474             this.endText = endText;
475         }
476         
477         public String JavaDoc toString() {
478             return name+" "+text; // NOI18N
479
}
480         
481         public String JavaDoc toInfo() {
482             return startName+","+endName+"{"+name+"} "+startText+","+endText+"{"+text+"}"; // NOI18N
483
}
484         
485         /**
486          * Return the name of this tag.
487          */

488         public String JavaDoc getName() {
489             return name;
490         }
491         
492         /**
493          * Return the kind of this tag.
494          */

495         public String JavaDoc getKind() {
496             return name;
497         }
498         
499         public boolean isText() {
500             return TEXT_TAG_NAME.equals(getName());
501         }
502         
503         /**
504          * Return the text of this tag, that is, portion beyond tag name.
505          */

506         public String JavaDoc getValue() {
507             return text;
508         }
509         
510         /** Getter for property startName.
511          * @return Value of property startName.
512          *
513          */

514         public int getStartName() {
515             return startName;
516         }
517         
518         /** Getter for property endName.
519          * @return Value of property endName.
520          *
521          */

522         public int getEndName() {
523             return endName;
524         }
525         
526         /** Getter for property startText.
527          * @return Value of property startText.
528          *
529          */

530         public int getStartText() {
531             return startText;
532         }
533         
534         /** Getter for property endText.
535          * @return Value of property endText.
536          *
537          */

538         public int getEndText() {
539             return endText;
540         }
541         
542         private int getNameValue(String JavaDoc name) {
543             Integer JavaDoc value = (Integer JavaDoc) nameValues.get(name);
544             if (value != null)
545                 return value.intValue();
546             return 0;
547         }
548         
549         public int compareTo(Object JavaDoc o) {
550             if (o == null || !(o instanceof JavaDocTag))
551               return -1;
552             String JavaDoc name1 = getName();
553             String JavaDoc name2 = ((JavaDocTag)o).getName();
554             int value1 = getNameValue(name1);
555             int value2 = getNameValue(name2);
556             
557             if (value1 > 0 && value2 > 0) {
558                 return value1-value2;
559             }
560             else if (value1 >0) {
561                 return -100;
562             }
563             else if (value2 >0) {
564                 return 100;
565             }
566             return name1.compareTo(name2);
567         }
568     }
569
570 }
571
Popular Tags