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