View Javadoc
1   /*
2    * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package com.sun.tools.javadoc;
27  
28  import java.io.DataInputStream;
29  import java.io.IOException;
30  import java.io.InputStream;
31  import java.text.CollationKey;
32  import java.util.regex.Matcher;
33  import java.util.regex.Pattern;
34  
35  import javax.tools.FileObject;
36  
37  import com.sun.javadoc.*;
38  import com.sun.source.util.TreePath;
39  import com.sun.tools.javac.tree.JCTree;
40  import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
41  import com.sun.tools.javac.util.Position;
42  
43  /**
44   * abstract base class of all Doc classes.  Doc item's are representations
45   * of java language constructs (class, package, method,...) which have
46   * comments and have been processed by this run of javadoc.  All Doc items
47   * are unique, that is, they are == comparable.
48   *
49   *  <p><b>This is NOT part of any supported API.
50   *  If you write code that depends on this, you do so at your own risk.
51   *  This code and its internal interfaces are subject to change or
52   *  deletion without notice.</b>
53   *
54   * @since 1.2
55   * @author Robert Field
56   * @author Atul M Dambalkar
57   * @author Neal Gafter (rewrite)
58   */
59  public abstract class DocImpl implements Doc, Comparable<Object> {
60  
61      /**
62       * Doc environment
63       */
64      protected final DocEnv env;   //### Rename this everywhere to 'docenv' ?
65  
66      /**
67       * Back pointer to the tree node for this doc item.
68       * May be null if there is no associated tree.
69       */
70      protected TreePath treePath;
71  
72      /**
73       *  The complex comment object, lazily initialized.
74       */
75      private Comment comment;
76  
77      /**
78       * The cached sort key, to take care of Natural Language Text sorting.
79       */
80      private CollationKey collationkey = null;
81  
82      /**
83       *  Raw documentation string.
84       */
85      protected String documentation;  // Accessed in PackageDocImpl, RootDocImpl
86  
87      /**
88       * Cached first sentence.
89       */
90      private Tag[] firstSentence;
91  
92      /**
93       * Cached inline tags.
94       */
95      private Tag[] inlineTags;
96  
97      /**
98       * Constructor.
99       */
100     DocImpl(DocEnv env, TreePath treePath) {
101         this.treePath = treePath;
102         this.documentation = getCommentText(treePath);
103         this.env = env;
104     }
105 
106     private static String getCommentText(TreePath p) {
107         if (p == null)
108             return null;
109 
110         JCCompilationUnit topLevel = (JCCompilationUnit) p.getCompilationUnit();
111         JCTree tree = (JCTree) p.getLeaf();
112         return topLevel.docComments.getCommentText(tree);
113     }
114 
115     /**
116      * So subclasses have the option to do lazy initialization of
117      * "documentation" string.
118      */
119     protected String documentation() {
120         if (documentation == null) documentation = "";
121         return documentation;
122     }
123 
124     /**
125      * For lazy initialization of comment.
126      */
127     Comment comment() {
128         if (comment == null) {
129             String d = documentation();
130             if (env.doclint != null
131                     && treePath != null
132                     && d.equals(getCommentText(treePath))) {
133                 env.doclint.scan(treePath);
134             }
135             comment = new Comment(this, d);
136         }
137         return comment;
138     }
139 
140     /**
141      * Return the text of the comment for this doc item.
142      * TagImpls have been removed.
143      */
144     public String commentText() {
145         return comment().commentText();
146     }
147 
148     /**
149      * Return all tags in this Doc item.
150      *
151      * @return an array of TagImpl containing all tags on this Doc item.
152      */
153     public Tag[] tags() {
154         return comment().tags();
155     }
156 
157     /**
158      * Return tags of the specified kind in this Doc item.
159      *
160      * @param tagname name of the tag kind to search for.
161      * @return an array of TagImpl containing all tags whose 'kind()'
162      * matches 'tagname'.
163      */
164     public Tag[] tags(String tagname) {
165         return comment().tags(tagname);
166     }
167 
168     /**
169      * Return the see also tags in this Doc item.
170      *
171      * @return an array of SeeTag containing all &#64;see tags.
172      */
173     public SeeTag[] seeTags() {
174         return comment().seeTags();
175     }
176 
177     public Tag[] inlineTags() {
178         if (inlineTags == null) {
179             inlineTags = Comment.getInlineTags(this, commentText());
180         }
181         return inlineTags;
182     }
183 
184     public Tag[] firstSentenceTags() {
185         if (firstSentence == null) {
186             //Parse all sentences first to avoid duplicate warnings.
187             inlineTags();
188             try {
189                 env.setSilent(true);
190                 firstSentence = Comment.firstSentenceTags(this, commentText());
191             } finally {
192                 env.setSilent(false);
193             }
194         }
195         return firstSentence;
196     }
197 
198     /**
199      * Utility for subclasses which read HTML documentation files.
200      */
201     String readHTMLDocumentation(InputStream input, FileObject filename) throws IOException {
202         byte[] filecontents = new byte[input.available()];
203         try {
204             DataInputStream dataIn = new DataInputStream(input);
205             dataIn.readFully(filecontents);
206         } finally {
207             input.close();
208         }
209         String encoding = env.getEncoding();
210         String rawDoc = (encoding!=null)
211             ? new String(filecontents, encoding)
212             : new String(filecontents);
213         Pattern bodyPat = Pattern.compile("(?is).*<body\\b[^>]*>(.*)</body\\b.*");
214         Matcher m = bodyPat.matcher(rawDoc);
215         if (m.matches()) {
216             return m.group(1);
217         } else {
218             String key = rawDoc.matches("(?is).*<body\\b.*")
219                     ? "javadoc.End_body_missing_from_html_file"
220                     : "javadoc.Body_missing_from_html_file";
221             env.error(SourcePositionImpl.make(filename, Position.NOPOS, null), key);
222             return "";
223         }
224     }
225 
226     /**
227      * Return the full unprocessed text of the comment.  Tags
228      * are included as text.  Used mainly for store and retrieve
229      * operations like internalization.
230      */
231     public String getRawCommentText() {
232         return documentation();
233     }
234 
235     /**
236      * Set the full unprocessed text of the comment.  Tags
237      * are included as text.  Used mainly for store and retrieve
238      * operations like internalization.
239      */
240     public void setRawCommentText(String rawDocumentation) {
241         treePath = null;
242         documentation = rawDocumentation;
243         comment = null;
244     }
245 
246     /**
247      * Set the full unprocessed text of the comment and tree path.
248      */
249     void setTreePath(TreePath treePath) {
250         this.treePath = treePath;
251         documentation = getCommentText(treePath);
252         comment = null;
253     }
254 
255     /**
256      * return a key for sorting.
257      */
258     CollationKey key() {
259         if (collationkey == null) {
260             collationkey = generateKey();
261         }
262         return collationkey;
263     }
264 
265     /**
266      * Generate a key for sorting.
267      * <p>
268      * Default is name().
269      */
270     CollationKey generateKey() {
271         String k = name();
272         // System.out.println("COLLATION KEY FOR " + this + " is \"" + k + "\"");
273         return env.doclocale.collator.getCollationKey(k);
274     }
275 
276     /**
277      * Returns a string representation of this Doc item.
278      */
279     @Override
280     public String toString() {
281         return qualifiedName();
282     }
283 
284     /**
285      * Returns the name of this Doc item.
286      *
287      * @return  the name
288      */
289     public abstract String name();
290 
291     /**
292      * Returns the qualified name of this Doc item.
293      *
294      * @return  the name
295      */
296     public abstract String qualifiedName();
297 
298     /**
299      * Compares this Object with the specified Object for order.  Returns a
300      * negative integer, zero, or a positive integer as this Object is less
301      * than, equal to, or greater than the given Object.
302      * <p>
303      * Included so that Doc item are java.lang.Comparable.
304      *
305      * @param   obj the {@code Object} to be compared.
306      * @return  a negative integer, zero, or a positive integer as this Object
307      *          is less than, equal to, or greater than the given Object.
308      * @exception ClassCastException the specified Object's type prevents it
309      *            from being compared to this Object.
310      */
311     public int compareTo(Object obj) {
312         // System.out.println("COMPARE \"" + this + "\" to \"" + obj + "\" = " + key().compareTo(((DocImpl)obj).key()));
313         return key().compareTo(((DocImpl)obj).key());
314     }
315 
316     /**
317      * Is this Doc item a field?  False until overridden.
318      *
319      * @return true if it represents a field
320      */
321     public boolean isField() {
322         return false;
323     }
324 
325     /**
326      * Is this Doc item an enum constant?  False until overridden.
327      *
328      * @return true if it represents an enum constant
329      */
330     public boolean isEnumConstant() {
331         return false;
332     }
333 
334     /**
335      * Is this Doc item a constructor?  False until overridden.
336      *
337      * @return true if it represents a constructor
338      */
339     public boolean isConstructor() {
340         return false;
341     }
342 
343     /**
344      * Is this Doc item a method (but not a constructor or annotation
345      * type element)?
346      * False until overridden.
347      *
348      * @return true if it represents a method
349      */
350     public boolean isMethod() {
351         return false;
352     }
353 
354     /**
355      * Is this Doc item an annotation type element?
356      * False until overridden.
357      *
358      * @return true if it represents an annotation type element
359      */
360     public boolean isAnnotationTypeElement() {
361         return false;
362     }
363 
364     /**
365      * Is this Doc item a interface (but not an annotation type)?
366      * False until overridden.
367      *
368      * @return true if it represents a interface
369      */
370     public boolean isInterface() {
371         return false;
372     }
373 
374     /**
375      * Is this Doc item a exception class?  False until overridden.
376      *
377      * @return true if it represents a exception
378      */
379     public boolean isException() {
380         return false;
381     }
382 
383     /**
384      * Is this Doc item a error class?  False until overridden.
385      *
386      * @return true if it represents a error
387      */
388     public boolean isError() {
389         return false;
390     }
391 
392     /**
393      * Is this Doc item an enum type?  False until overridden.
394      *
395      * @return true if it represents an enum type
396      */
397     public boolean isEnum() {
398         return false;
399     }
400 
401     /**
402      * Is this Doc item an annotation type?  False until overridden.
403      *
404      * @return true if it represents an annotation type
405      */
406     public boolean isAnnotationType() {
407         return false;
408     }
409 
410     /**
411      * Is this Doc item an ordinary class (i.e. not an interface,
412      * annotation type, enumeration, exception, or error)?
413      * False until overridden.
414      *
415      * @return true if it represents an ordinary class
416      */
417     public boolean isOrdinaryClass() {
418         return false;
419     }
420 
421     /**
422      * Is this Doc item a class
423      * (and not an interface or annotation type)?
424      * This includes ordinary classes, enums, errors and exceptions.
425      * False until overridden.
426      *
427      * @return true if it represents a class
428      */
429     public boolean isClass() {
430         return false;
431     }
432 
433     /**
434      * return true if this Doc is include in the active set.
435      */
436     public abstract boolean isIncluded();
437 
438     /**
439      * Return the source position of the entity, or null if
440      * no position is available.
441      */
442     public SourcePosition position() { return null; }
443 }