001: /*
002: * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.tools.javadoc;
027:
028: import com.sun.javadoc.*;
029:
030: import java.io.File;
031: import java.io.InputStream;
032: import java.io.FileInputStream;
033: import java.io.IOException;
034: import java.util.zip.ZipFile;
035: import java.util.zip.ZipEntry;
036:
037: import com.sun.tools.javac.code.Attribute;
038: import com.sun.tools.javac.code.Scope;
039: import com.sun.tools.javac.code.Symbol.ClassSymbol;
040: import com.sun.tools.javac.code.Symbol.PackageSymbol;
041: import com.sun.tools.javac.comp.AttrContext;
042: import com.sun.tools.javac.comp.Env;
043: import com.sun.tools.javac.tree.JCTree;
044: import com.sun.tools.javac.util.List;
045: import com.sun.tools.javac.util.ListBuffer;
046: import com.sun.tools.javac.util.Name;
047: import com.sun.tools.javac.util.Position;
048:
049: import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
050:
051: /**
052: * Represents a java package. Provides access to information
053: * about the package, the package's comment and tags, and the
054: * classes in the package.
055: *
056: * @since 1.2
057: * @author Kaiyang Liu (original)
058: * @author Robert Field (rewrite)
059: * @author Neal Gafter (rewrite)
060: * @author Scott Seligman (package-info.java)
061: */
062:
063: public class PackageDocImpl extends DocImpl implements PackageDoc {
064:
065: private static final String PACKAGE_HTML_FILE_NAME = "package.html";
066:
067: protected PackageSymbol sym;
068: private JCCompilationUnit tree = null; // for source position
069:
070: public String docPath = null;
071: public String zipDocPath = null;
072: public String zipDocEntry = null;
073: private boolean foundDoc; // found a doc comment in either
074: // package.html or package-info.java
075:
076: boolean isIncluded = false; // Set in RootDocImpl.
077: public boolean setDocPath = false; //Flag to avoid setting doc path multiple times.
078:
079: /**
080: * Constructor
081: */
082: public PackageDocImpl(DocEnv env, PackageSymbol sym) {
083: this (env, sym, null, null);
084: }
085:
086: /**
087: * Constructor
088: */
089: public PackageDocImpl(DocEnv env, PackageSymbol sym,
090: String documentation, JCTree tree) {
091: super (env, documentation);
092: this .sym = sym;
093: this .tree = (JCCompilationUnit) tree;
094: foundDoc = (documentation != null);
095: }
096:
097: void setTree(JCTree tree) {
098: this .tree = (JCCompilationUnit) tree;
099: }
100:
101: public void setRawCommentText(String rawDocumentation) {
102: super .setRawCommentText(rawDocumentation);
103: checkDoc();
104: }
105:
106: /**
107: * Do lazy initialization of "documentation" string.
108: */
109: String documentation() {
110: if (documentation != null)
111: return documentation;
112: if (zipDocPath != null) {
113: try {
114: ZipFile f = new ZipFile(zipDocPath);
115: ZipEntry entry = f.getEntry(zipDocEntry);
116: if (entry != null) {
117: InputStream s = f.getInputStream(entry);
118: return (documentation = readHTMLDocumentation(s,
119: zipDocPath + File.separatorChar
120: + zipDocEntry));
121: }
122: } catch (IOException exc) {
123: documentation = "";
124: env.error(null, "javadoc.File_Read_Error", zipDocPath
125: + File.separatorChar + zipDocEntry);
126: }
127: }
128: if (docPath != null) {
129: // read from file
130: try {
131: InputStream s = new FileInputStream(docPath);
132: documentation = readHTMLDocumentation(s, docPath);
133: } catch (IOException exc) {
134: documentation = "";
135: env.error(null, "javadoc.File_Read_Error", docPath);
136: }
137: } else {
138: // no doc file to be had
139: documentation = "";
140: }
141: return documentation;
142: }
143:
144: /**
145: * Cache of all classes contained in this package, including
146: * member classes of those classes, and their member classes, etc.
147: * Includes only those classes at the specified protection level
148: * and weaker.
149: */
150: private List<ClassDocImpl> allClassesFiltered = null;
151:
152: /**
153: * Cache of all classes contained in this package, including
154: * member classes of those classes, and their member classes, etc.
155: */
156: private List<ClassDocImpl> allClasses = null;
157:
158: /**
159: * Return a list of all classes contained in this package, including
160: * member classes of those classes, and their member classes, etc.
161: */
162: private List<ClassDocImpl> getClasses(boolean filtered) {
163: if (allClasses != null && !filtered) {
164: return allClasses;
165: }
166: if (allClassesFiltered != null && filtered) {
167: return allClassesFiltered;
168: }
169: ListBuffer<ClassDocImpl> classes = new ListBuffer<ClassDocImpl>();
170: for (Scope.Entry e = sym.members().elems; e != null; e = e.sibling) {
171: if (e.sym != null) {
172: ClassSymbol s = (ClassSymbol) e.sym;
173: ClassDocImpl c = env.getClassDoc(s);
174: if (c != null && !c.isSynthetic())
175: c.addAllClasses(classes, filtered);
176: }
177: }
178: if (filtered)
179: return allClassesFiltered = classes.toList();
180: else
181: return allClasses = classes.toList();
182: }
183:
184: /**
185: * Add all included classes (including Exceptions and Errors)
186: * and interfaces.
187: */
188: public void addAllClassesTo(ListBuffer<ClassDocImpl> list) {
189: list.appendList(getClasses(true));
190: }
191:
192: /**
193: * Get all classes (including Exceptions and Errors)
194: * and interfaces.
195: * @since J2SE1.4.
196: *
197: * @return all classes and interfaces in this package, filtered to include
198: * only the included classes if filter==true.
199: */
200: public ClassDoc[] allClasses(boolean filter) {
201: List<ClassDocImpl> classes = getClasses(filter);
202: return classes.toArray(new ClassDocImpl[classes.length()]);
203: }
204:
205: /**
206: * Get all included classes (including Exceptions and Errors)
207: * and interfaces. Same as allClasses(true).
208: *
209: * @return all included classes and interfaces in this package.
210: */
211: public ClassDoc[] allClasses() {
212: return allClasses(true);
213: }
214:
215: /**
216: * Get ordinary classes (that is, exclude exceptions, errors,
217: * enums, interfaces, and annotation types) in this package.
218: *
219: * @return included ordinary classes in this package.
220: */
221: public ClassDoc[] ordinaryClasses() {
222: ListBuffer<ClassDocImpl> ret = new ListBuffer<ClassDocImpl>();
223: for (ClassDocImpl c : getClasses(true)) {
224: if (c.isOrdinaryClass()) {
225: ret.append(c);
226: }
227: }
228: return ret.toArray(new ClassDocImpl[ret.length()]);
229: }
230:
231: /**
232: * Get Exception classes in this package.
233: *
234: * @return included Exceptions in this package.
235: */
236: public ClassDoc[] exceptions() {
237: ListBuffer<ClassDocImpl> ret = new ListBuffer<ClassDocImpl>();
238: for (ClassDocImpl c : getClasses(true)) {
239: if (c.isException()) {
240: ret.append(c);
241: }
242: }
243: return ret.toArray(new ClassDocImpl[ret.length()]);
244: }
245:
246: /**
247: * Get Error classes in this package.
248: *
249: * @return included Errors in this package.
250: */
251: public ClassDoc[] errors() {
252: ListBuffer<ClassDocImpl> ret = new ListBuffer<ClassDocImpl>();
253: for (ClassDocImpl c : getClasses(true)) {
254: if (c.isError()) {
255: ret.append(c);
256: }
257: }
258: return ret.toArray(new ClassDocImpl[ret.length()]);
259: }
260:
261: /**
262: * Get included enum types in this package.
263: *
264: * @return included enum types in this package.
265: */
266: public ClassDoc[] enums() {
267: ListBuffer<ClassDocImpl> ret = new ListBuffer<ClassDocImpl>();
268: for (ClassDocImpl c : getClasses(true)) {
269: if (c.isEnum()) {
270: ret.append(c);
271: }
272: }
273: return ret.toArray(new ClassDocImpl[ret.length()]);
274: }
275:
276: /**
277: * Get included interfaces in this package, omitting annotation types.
278: *
279: * @return included interfaces in this package.
280: */
281: public ClassDoc[] interfaces() {
282: ListBuffer<ClassDocImpl> ret = new ListBuffer<ClassDocImpl>();
283: for (ClassDocImpl c : getClasses(true)) {
284: if (c.isInterface()) {
285: ret.append(c);
286: }
287: }
288: return ret.toArray(new ClassDocImpl[ret.length()]);
289: }
290:
291: /**
292: * Get included annotation types in this package.
293: *
294: * @return included annotation types in this package.
295: */
296: public AnnotationTypeDoc[] annotationTypes() {
297: ListBuffer<AnnotationTypeDocImpl> ret = new ListBuffer<AnnotationTypeDocImpl>();
298: for (ClassDocImpl c : getClasses(true)) {
299: if (c.isAnnotationType()) {
300: ret.append((AnnotationTypeDocImpl) c);
301: }
302: }
303: return ret.toArray(new AnnotationTypeDocImpl[ret.length()]);
304: }
305:
306: /**
307: * Get the annotations of this package.
308: * Return an empty array if there are none.
309: */
310: public AnnotationDesc[] annotations() {
311: AnnotationDesc res[] = new AnnotationDesc[sym
312: .getAnnotationMirrors().length()];
313: int i = 0;
314: for (Attribute.Compound a : sym.getAnnotationMirrors()) {
315: res[i++] = new AnnotationDescImpl(env, a);
316: }
317: return res;
318: }
319:
320: /**
321: * Lookup for a class within this package.
322: *
323: * @return ClassDocImpl of found class, or null if not found.
324: */
325: public ClassDoc findClass(String className) {
326: final boolean filtered = true;
327: for (ClassDocImpl c : getClasses(filtered)) {
328: if (c.name().equals(className)) {
329: return c;
330: }
331: }
332: return null;
333: }
334:
335: /**
336: * Return true if this package is included in the active set.
337: */
338: public boolean isIncluded() {
339: return isIncluded;
340: }
341:
342: /**
343: * Get package name.
344: *
345: * Note that we do not provide a means of obtaining the simple
346: * name of a package -- package names are always returned in their
347: * uniquely qualified form.
348: */
349: public String name() {
350: return qualifiedName();
351: }
352:
353: /**
354: * Get package name.
355: */
356: public String qualifiedName() {
357: Name fullname = sym.getQualifiedName();
358: // Some bogus tests depend on the interned "" being returned.
359: // See 6457276.
360: return fullname.isEmpty() ? "" : fullname.toString();
361: }
362:
363: /**
364: * set doc path for an unzipped directory
365: */
366: public void setDocPath(String path) {
367: setDocPath = true;
368: if (path == null)
369: return;
370: String newDocPath = path + File.separatorChar
371: + PACKAGE_HTML_FILE_NAME;
372: if (!newDocPath.equals(docPath)) {
373: docPath = newDocPath;
374: checkDoc();
375: }
376: }
377:
378: /**
379: * set the doc path for zipped directory
380: */
381: public void setDocPath(String path, String entry) {
382: if (!path.equals(zipDocPath)) {
383: zipDocPath = path;
384: zipDocEntry = entry + PACKAGE_HTML_FILE_NAME;
385: checkDoc();
386: }
387: }
388:
389: // Has checkDoc() sounded off yet?
390: private boolean checkDocWarningEmitted = false;
391:
392: /**
393: * Invoked when a source of package doc comments is located.
394: * Emits a diagnostic if this is the second one.
395: */
396: private void checkDoc() {
397: if (foundDoc) {
398: if (!checkDocWarningEmitted) {
399: env.warning(null, "javadoc.Multiple_package_comments",
400: name());
401: checkDocWarningEmitted = true;
402: }
403: } else {
404: foundDoc = true;
405: }
406: }
407:
408: /**
409: * Return the source position of the entity, or null if
410: * no position is available.
411: */
412: public SourcePosition position() {
413: return (tree != null) ? SourcePositionImpl.make(tree.sourcefile
414: + "", tree.pos, tree.lineMap) : SourcePositionImpl
415: .make(docPath, Position.NOPOS, null);
416: }
417: }
|