1 /* gnu.classpath.tools.doclets.xmldoclet.Driver
2 Copyright (C) 2001 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 package gnu
.classpath
.tools
.doclets
.xmldoclet
;
23 import com
.sun
.javadoc
.*;
26 import com
.sun
.tools
.doclets
.Taglet
;
28 import java
.lang
.reflect
.InvocationTargetException
;
29 import java
.lang
.reflect
.Method
;
30 import java
.lang
.reflect
.Modifier
;
32 import java
.text
.DateFormat
;
34 import java
.util
.ArrayList
;
35 import java
.util
.Arrays
;
36 import java
.util
.Comparator
;
37 import java
.util
.HashSet
;
38 import java
.util
.TreeSet
;
39 import java
.util
.Iterator
;
40 import java
.util
.LinkedHashMap
;
41 import java
.util
.LinkedList
;
42 import java
.util
.List
;
43 import java
.util
.Locale
;
45 import java
.util
.HashMap
;
46 import java
.util
.Properties
;
48 import java
.util
.SortedSet
;
49 import java
.util
.StringTokenizer
;
50 import java
.util
.TreeMap
;
52 import gnu
.classpath
.tools
.gjdoc
.TemporaryStore
;
53 import gnu
.classpath
.tools
.gjdoc
.GjdocPackageDoc
;
55 import gnu
.classpath
.tools
.doclets
.PackageGroup
;
56 import gnu
.classpath
.tools
.doclets
.PackageMatcher
;
57 import gnu
.classpath
.tools
.doclets
.InvalidPackageWildcardException
;
59 import gnu
.classpath
.tools
.doclets
.xmldoclet
.doctranslet
.DocTranslet
;
60 import gnu
.classpath
.tools
.doclets
.xmldoclet
.doctranslet
.DocTransletOptions
;
62 import gnu
.classpath
.tools
.taglets
.AuthorTaglet
;
63 import gnu
.classpath
.tools
.taglets
.VersionTaglet
;
64 import gnu
.classpath
.tools
.taglets
.SinceTaglet
;
65 import gnu
.classpath
.tools
.taglets
.DeprecatedTaglet
;
66 import gnu
.classpath
.tools
.taglets
.GenericTaglet
;
67 import gnu
.classpath
.tools
.doclets
.StandardTaglet
;
69 import gnu
.classpath
.tools
.java2xhtml
.Java2xhtml
;
71 import gnu
.classpath
.tools
.IOToolkit
;
72 import gnu
.classpath
.tools
.FileSystemClassLoader
;
75 * A Doclet which retrieves all information presented by the Doclet
76 * API, dumping it to stdout in XML format.
78 * @author Julian Scheid
82 public static final String XMLDOCLET_VERSION
= "0.6.1";
85 * Used for redirecting error messages to <code>/dev/null</code>.
87 private static class NullErrorReporter
implements DocErrorReporter
{
88 public void printError(String ignore
) {}
89 public void printWarning(String ignore
) {}
90 public void printNotice(String ignore
) {}
94 * Taglet context constants.
96 private static final int CONTEXT_CONSTRUCTOR
= 1;
97 private static final int CONTEXT_FIELD
= 2;
98 private static final int CONTEXT_METHOD
= 3;
99 private static final int CONTEXT_OVERVIEW
= 4;
100 private static final int CONTEXT_PACKAGE
= 5;
101 private static final int CONTEXT_TYPE
= 6;
104 * All XML output will go to this stream.
106 private PrintWriter out
;
109 * How many spaces to indent each XML node level,
110 * i.e. Tab size for output.
112 private static int indentStep
= 1;
115 * Won't output superfluous spaces if set to true.
116 * If set to false, output will be more legible.
118 private boolean compress
= false;
121 * Won't output warning messages while fixing
122 * HTML code if set to true.
124 private boolean noHTMLWarn
= false;
127 * Won't output warning messages when encountering tags
128 * that look like an email address if set to true.
130 private boolean noEmailWarn
= false;
133 * Will fix HTML if necessary so that each comment
134 * contains valid XML code if set to true. If set
135 * to false, HTML code will not be modified and
136 * instead encapsulated in a CDATA section.
138 private boolean fixHTML
= true;
141 * User-specified name of the directory where the final version of
142 * the generated files will be written to.
144 * If no XSLT sheet is given, the XML output will go directly into
145 * this directory. Otherwise, XML output will go to a temporary
146 * directory and XSLT output will go to this directory.
148 private File targetDirectory
= null;
151 * Directory where XML output will be written to. If no XSLT
152 * sheet was given, this is the target directory specified
153 * by the user. Otherwise, this is a temporary directory.
155 private File xmlTargetDirectory
;
158 * Contains a number of TargetContexts which describe which XSLT
159 * sheet to apply to the output of this doclet, to what directory
160 * the XSLT output is written, and which postprocess driver to use
161 * to process XSLT output.
163 private List targets
= new ArrayList();
166 * XML text to include at the end of every generated page. Read
167 * from the file specified on the command line using -bottomnote.
168 * If present, this will be written to the main output file
169 * (index.xml) in node /gjdoc:rootDoc/gjdoc:bottomnote.
171 private String bottomNote
;
174 * Brief description of the package set. Can be specified on the
175 * command line using -title. This will be written to the main
176 * output file (index.xml) in node
177 * /gjdoc:rootDoc/gjdoc:title. The HTML generating XSLT sheet
178 * uses this for example in window titles.
180 private String title
;
183 * Path to the directory where temporary files should be stored.
184 * Defaults to system tempdir, but can be overridden by user
187 private String workingPath
= System
.getProperty("java.io.tmpdir");
190 * Temporary directory created by this doclet where all
191 * temporary files will be stored in. If no temporary
192 * files are needed (i.e. no XSLT postprocessing stage
193 * specified by user), this is <code>null</code>.
195 private File workingDirectory
;
198 * Whether to deep-copy the doc-files subdirectory.
200 private boolean docFilesSubdirsEnabled
= false;
203 * Which direct subdirectories of the doc-files directories to exclude.
206 private Set excludeDocFilesSubDirs
= new HashSet();
209 * Stores the Doclet API RootDoc we are operating on.
211 private RootDoc rootDoc
;
214 * XML namespace prefix used for all tags, except for HTML
215 * tags copied from Javadoc comments. Excluding colon.
217 public static final String tagPrefix
= "gjdoc";
220 * Classpath for loading Taglet classes.
222 private String tagletPath
= null;
225 * The current class that is being processed.
226 * Set in outputClassDoc().
228 private ClassDoc currentClass
;
231 * The current member that is being processed.
232 * Set in outputMemberDoc().
234 private MemberDoc currentMember
;
237 * The current constructor/method that is being processed.
238 * Set in outputExecutableMemberDoc().
240 private ExecutableMemberDoc currentExecMember
;
243 * Mapping from tag type to Taglet for user Taglets specified on
246 private Map tagletMap
= new LinkedHashMap();
249 * Keeps track of the tags mentioned by the user during option
250 * processiong so that an error can be emitted if a tag is
251 * mentioned more than once.
253 private List mentionedTags
= new LinkedList();
256 * Stores options to be passed to the DocTranslet.
258 private DocTransletOptions docTransletOptions
= new DocTransletOptions();
261 * Stores the package groups specified in the user
262 * options. Contains objects of type PackageGroup.
264 private List packageGroups
= new LinkedList();
266 private HtmlRepairer htmlRepairer
;
268 public static boolean start(TemporaryStore _rootDocWrapper
) {
269 return new Driver().instanceStart((RootDoc
)_rootDocWrapper
.getAndClear());
273 * Official Doclet entry point.
275 public static boolean start(RootDoc _rootDoc
) {
277 // Create a new XmlDoclet instance and delegate control.
278 TemporaryStore tstore
= new TemporaryStore(_rootDoc
);
280 return new Driver().instanceStart((RootDoc
)tstore
.getAndClear());
284 * Output an XML tag describing a com.sun.javadoc.Type object.
285 * Assumes that the tag does not have subtags.
287 * @param level Level of indentation. Will be multiplied by
288 * <code>indentStep</code> to yield actual amount
289 * of whitespace inserted at start of line.
290 * @param tag Identifier for the XML tag being output.
291 * @param type The Javadoc Type to be output.
293 protected void outputType(int level
, String tag
, Type type
) {
294 outputType(level
, tag
, type
, true);
297 protected void outputType(int level
, String tag
, Type type
, boolean atomic
) {
299 boolean isIncluded
= false;
300 ClassDoc typeAsClassDoc
= type
.asClassDoc();
301 String packageName
= null;
302 if (null != typeAsClassDoc
) {
303 isIncluded
= typeAsClassDoc
.isIncluded();
304 packageName
= typeAsClassDoc
.containingPackage().name();
306 println(level
, "<"+tagPrefix
+":"+tag
+ " typename=\""+type
.typeName()+"\""+
307 " qualifiedtypename=\""+type
.qualifiedTypeName()+"\""
308 +(type
.dimension().length()==0?
"":" dimension=\""+type
.dimension()+"\"")
309 +(isIncluded?
" isIncluded=\"true\"" : "")
310 +((null != packageName
)?
" package=\"" + packageName
+ "\"" : "")
311 +(atomic?
"/":"")+">");
314 protected void outputExecutableMemberDocBody(int level
, ExecutableMemberDoc memberDoc
) {
316 currentExecMember
= memberDoc
;
318 outputMemberDocBody(level
, memberDoc
);
320 Parameter
[] parameters
= memberDoc
.parameters();
321 for (int i
=0, ilim
=parameters
.length
; i
<ilim
; ++i
) {
322 Parameter parameter
= parameters
[i
];
323 outputType(level
, "parameter name=\""+parameter
.name()+"\"", parameter
.type());
326 ClassDoc
[] exceptions
= memberDoc
.thrownExceptions();
327 for (int i
=0, ilim
=exceptions
.length
; i
<ilim
; ++i
) {
328 ClassDoc exception
= exceptions
[i
];
329 outputType(level
, "thrownException", exception
);
332 printAtomTag(level
, "signature full=\""+memberDoc
.signature()+"\" flat=\""+memberDoc
.flatSignature()+"\"");
334 if (memberDoc
.isNative()) {
335 printAtomTag(level
, "isNative");
338 if (memberDoc
.isSynchronized()) {
339 printAtomTag(level
, "isSynchronized");
343 protected void outputMethodDoc(int level
, MethodDoc methodDoc
) {
345 printOpenTag(level
, "methoddoc name=\""+methodDoc
.name()+"\"");
346 outputExecutableMemberDocBody(level
+1, methodDoc
);
347 outputType(level
+1, "returns", methodDoc
.returnType());
348 printCloseTag(level
, "methoddoc");
351 protected void outputMemberDocBody(int level
, MemberDoc memberDoc
) {
352 currentMember
= memberDoc
;
353 outputProgramElementDocBody(level
, memberDoc
);
356 protected void outputFieldDocBody(int level
, FieldDoc fieldDoc
) {
357 outputType(level
, "type", fieldDoc
.type());
358 if (fieldDoc
.isTransient()) {
359 printAtomTag(level
, "isTransient");
361 if (fieldDoc
.isVolatile()) {
362 printAtomTag(level
, "isVolatile");
366 private void outputFieldDoc(int level
, FieldDoc fieldDoc
) {
368 printOpenTag(level
, "fielddoc name=\""+fieldDoc
.name()+"\"");
369 outputMemberDocBody(level
+1, fieldDoc
);
370 outputFieldDocBody(level
+1, fieldDoc
);
371 printCloseTag(level
, "fielddoc");
374 protected void outputConstructorDoc(int level
, ConstructorDoc constructorDoc
) {
376 printOpenTag(level
, "constructordoc name=\""+constructorDoc
.name()+"\"");
377 outputExecutableMemberDocBody(level
+1, constructorDoc
);
378 printCloseTag(level
, "constructordoc");
381 protected void outputSuperInterfacesRec(int level
, ClassDoc classDoc
) {
382 if (null!=classDoc
) {
383 ClassDoc
[] interfaces
= classDoc
.interfaces();
384 if (null != interfaces
) {
385 for (int i
=0, ilim
=interfaces
.length
; i
<ilim
; ++i
) {
386 outputType(level
, "superimplements", interfaces
[i
]);
389 outputSuperInterfacesRec(level
, classDoc
.superclass());
393 protected void outputClassDocSummary(ClassDoc classDoc
) {
395 printOpenTag(1, "classdoc name=\""+classDoc
.name()+"\" qualifiedtypename=\""+classDoc
.qualifiedName()+"\" isIncluded=\"true\"");
396 if (null!=classDoc
.superclass()) {
397 outputType(2, "superclass", classDoc
.superclass());
400 ClassDoc
[] interfaces
= classDoc
.interfaces();
401 for (int i
=0, ilim
=interfaces
.length
; i
<ilim
; ++i
) {
402 outputType(2, "implements", interfaces
[i
]);
404 outputSuperInterfacesRec(2, classDoc
.superclass());
406 printAtomTag(2, "containingPackage name=\""+classDoc
.containingPackage().name()+"\"");
407 if (classDoc
.isError()) {
408 printAtomTag(2, "isError");
410 if (classDoc
.isException()) {
411 printAtomTag(2, "isException");
413 if (classDoc
.isInterface()) {
414 printAtomTag(2, "isInterface");
416 if (classDoc
.isOrdinaryClass()) {
417 printAtomTag(2, "isOrdinaryClass");
420 printCloseTag(1, "classdoc");
423 protected void outputPackageDoc(PackageDoc packageDoc
) {
425 printOpenTag(1, "packagedoc name=\""+packageDoc
.name()+"\"");
426 if (packageDoc
.firstSentenceTags().length
> 0) {
427 printOpenTag(2, "firstSentenceTags", false);
428 outputTags(3, packageDoc
.firstSentenceTags(), true, CONTEXT_PACKAGE
);
429 printCloseTag(0, "firstSentenceTags");
430 printOpenTag(2, "inlineTags", false);
431 outputTags(3, packageDoc
.inlineTags(), true, CONTEXT_PACKAGE
);
432 printCloseTag(0, "inlineTags");
435 if (packageDoc
.tags().length
> 0) {
436 printOpenTag(2, "tags");
437 outputTags(3, packageDoc
.tags(), true, CONTEXT_PACKAGE
);
438 printCloseTag(2, "tags");
441 if (packageDoc
.seeTags().length
> 0) {
442 printOpenTag(2, "seeTags");
443 outputTags(3, packageDoc
.seeTags(), true, CONTEXT_PACKAGE
);
444 printCloseTag(2, "seeTags");
447 ClassDoc
[] allClasses
= (ClassDoc
[]) packageDoc
.allClasses().clone();
448 Arrays
.sort(allClasses
);
451 for (int i
= 0, ilim
= allClasses
.length
; i
< ilim
; ++ i
) {
452 printAtomTag(2, "containsClass qualifiedtypename=\""+allClasses
[i
].qualifiedTypeName()+"\"");
456 printCloseTag(1, "packagedoc");
459 protected void outputClassDoc(ClassDoc classDoc
) throws IOException
{
461 currentClass
= classDoc
;
464 printOpenTag(1, "classdoc xmlns=\"http://www.w3.org/TR/REC-html40\" xmlns:"+tagPrefix
+"=\"http://www.gnu.org/software/cp-tools/gjdocxml\" name=\""+classDoc
.name()+"\" qualifiedtypename=\""+classDoc
.qualifiedName()+"\"");
466 ClassDoc
[] interfaces
= classDoc
.interfaces();
467 for (int i
=0, ilim
=interfaces
.length
; i
<ilim
; ++i
) {
468 outputType(2, "implements", interfaces
[i
]);
470 outputSuperInterfacesRec(2, classDoc
.superclass());
472 outputProgramElementDocBody(2, classDoc
);
473 if (classDoc
.isAbstract())
474 printAtomTag(2, "isAbstract");
475 if (classDoc
.isSerializable())
476 printAtomTag(2, "isSerializable");
477 if (classDoc
.isExternalizable())
478 printAtomTag(2, "isExternalizable");
479 if (classDoc
.definesSerializableFields()) {
480 printAtomTag(2, "definesSerializableFields");
483 ConstructorDoc
[] constructors
= classDoc
.constructors();
484 for (int i
=0, ilim
=constructors
.length
; i
<ilim
; ++i
) {
485 outputConstructorDoc(2, constructors
[i
]);
488 MethodDoc
[] methods
= classDoc
.methods();
489 for (int i
=0, ilim
=methods
.length
; i
<ilim
; ++i
) {
490 outputMethodDoc(2, methods
[i
]);
493 FieldDoc
[] fields
= classDoc
.fields();
494 for (int i
=0, ilim
=fields
.length
; i
<ilim
; ++i
) {
495 outputFieldDoc(2, fields
[i
]);
498 if (classDoc
.serializableFields().length
> 0) {
499 printOpenTag(2, "serializableFields");
501 FieldDoc
[] sfields
= classDoc
.serializableFields();
502 for (int i
=0, ilim
=sfields
.length
; i
<ilim
; ++i
) {
503 outputFieldDoc(2, sfields
[i
]);
505 printCloseTag(2, "serializableFields");
508 Java2xhtml java2xhtml
= new Java2xhtml();
509 Properties properties
= new Properties();
510 properties
.setProperty("isCodeSnippet", "true");
511 properties
.setProperty("hasLineNumbers", "true");
512 java2xhtml
.setProperties(properties
);
514 if (null == classDoc
.containingClass() && docTransletOptions
.linksource
) {
515 printOpenTag(2, "source");
516 StringWriter sourceBuffer
= new StringWriter();
517 File sourceFile
= new File(((GjdocPackageDoc
)classDoc
.containingPackage()).packageDirectory(),
518 classDoc
.name() + ".java");
519 FileReader sourceReader
= new FileReader(sourceFile
);
520 IOToolkit
.copyStream(sourceReader
, sourceBuffer
);
521 print(java2xhtml
.makeHTML(sourceBuffer
.getBuffer(), sourceFile
.getName()));
522 printCloseTag(2, "source");
525 ClassDoc superclassDoc
= classDoc
.superclass();
526 while (superclassDoc
!= null) {
527 outputType(2, "superclass", superclassDoc
, false);
529 // FIXME: remove the following after adjusting the XSLT sheets:
530 printAtomTag(3, "containingPackage name=\"" + superclassDoc
.containingPackage().name() + "\"");
532 MethodDoc
[] superMethods
= superclassDoc
.methods();
533 if (null != superMethods
) {
534 for (int i
=0, ilim
=superMethods
.length
; i
<ilim
; ++i
) {
535 printAtomTag(3, "methoddoc name=\"" + superMethods
[i
].name() + "\" signature=\"" + superMethods
[i
].signature() + "\"");
539 FieldDoc
[] superFields
= superclassDoc
.fields();
540 if (null != superFields
) {
541 for (int i
=0, ilim
=superFields
.length
; i
<ilim
; ++i
) {
542 printAtomTag(3, "fielddoc name=\"" + superFields
[i
].name() + "\"");
545 printCloseTag(2, "superclass");
547 superclassDoc
= superclassDoc
.superclass();
550 outputUsage(classDoc
, 2);
552 printCloseTag(1, "classdoc");
555 currentMember
= null;
556 currentExecMember
= null;
559 protected int outputHeritageOpen(int level
, ClassDoc classDoc
) {
561 ClassDoc superClassDoc
= classDoc
.superclass();
562 if (null != superClassDoc
) {
563 level
= outputHeritageOpen(level
, superClassDoc
);
566 outputType(level
, "heritage", classDoc
, false);
570 protected void outputHeritageClose(int level
, ClassDoc classDoc
) {
572 ClassDoc superClassDoc
= classDoc
.superclass();
573 if (null != superClassDoc
) {
574 outputHeritageClose(level
+ 1, superClassDoc
);
576 printCloseTag(level
, "heritage");
579 protected void outputDocBody(int level
, Doc doc
) {
581 int context
= CONTEXT_TYPE
;
584 printAtomTag(level
, "isClass");
586 ClassDoc classDoc
= (ClassDoc
)doc
;
587 ClassDoc
[] classes
= rootDoc
.classes();
588 for (int i
=0, ilim
=classes
.length
; i
<ilim
; ++i
) {
589 if (classes
[i
].superclass() == classDoc
) {
590 outputType(level
, "extended-by", classes
[i
]);
594 outputHeritageOpen(level
, classDoc
);
595 outputHeritageClose(level
, classDoc
);
597 if (doc
.isConstructor()) {
598 printAtomTag(level
, "isConstructor");
599 context
= CONTEXT_CONSTRUCTOR
;
602 printAtomTag(level
, "isError");
604 if (doc
.isException()) {
605 printAtomTag(level
, "isException");
608 printAtomTag(level
, "isField");
609 context
= CONTEXT_FIELD
;
611 if (doc
.isIncluded()) {
612 printAtomTag(level
, "isIncluded");
614 if (doc
.isInterface()) {
615 printAtomTag(level
, "isInterface");
617 ClassDoc classDoc
= (ClassDoc
)doc
;
618 ClassDoc
[] classes
= rootDoc
.classes();
619 for (int i
=0, ilim
=classes
.length
; i
<ilim
; ++i
) {
620 ClassDoc
[] implementedInterfaces
= classes
[i
].interfaces();
621 for (int j
=0; j
<implementedInterfaces
.length
; ++j
) {
622 if (implementedInterfaces
[j
] == classDoc
) {
623 if (classDoc
.isInterface()) {
624 outputType(level
, "subinterface", classes
[i
]);
627 outputType(level
, "implemented-by", classes
[i
]);
634 if (doc
.isMethod()) {
635 printAtomTag(level
, "isMethod");
636 context
= CONTEXT_METHOD
;
638 if (doc
.isOrdinaryClass()) {
639 printAtomTag(level
, "isOrdinaryClass");
642 if (doc
.inlineTags().length
> 0) {
643 printOpenTag(level
, "inlineTags", false);
644 outputTags(level
+1, doc
.inlineTags(), true, context
);
645 printCloseTag(0, "inlineTags");
648 if (doc
.firstSentenceTags().length
> 0) {
649 printOpenTag(level
, "firstSentenceTags", false);
650 outputTags(level
+1, doc
.firstSentenceTags(), true, context
);
651 printCloseTag(0, "firstSentenceTags");
654 if (doc
.tags().length
> 0) {
655 printOpenTag(level
, "tags");
656 outputTaglets(level
+1, doc
.tags(), true, context
);
657 printCloseTag(level
, "tags");
660 if (doc
.seeTags().length
> 0) {
661 printOpenTag(level
, "seeTags");
662 outputTags(level
+1, doc
.seeTags(), true, context
);
663 printCloseTag(level
, "seeTags");
666 SourcePosition position
= doc
.position();
667 if (null != position
) {
668 printAtomTag(level
, "position file=\"" + position
.file().getAbsolutePath() + "\" line=\"" + position
.line() + "\" column=\"" + position
.column() + "\"");
672 protected void outputProgramElementDocBody(int level
, ProgramElementDoc programElementDoc
) {
673 outputDocBody(level
, programElementDoc
);
674 printAtomTag(level
, "containingPackage name=\""+programElementDoc
.containingPackage().name()+"\"");
675 if (null!=programElementDoc
.containingClass()) {
676 outputType(level
, "containingClass", programElementDoc
.containingClass());
679 if (programElementDoc
.isPublic())
681 else if (programElementDoc
.isProtected())
683 else if (programElementDoc
.isPrivate())
685 else if (programElementDoc
.isPackagePrivate())
688 throw new RuntimeException("Huh? "+programElementDoc
+" is neither public, protected, private nor package protected.");
689 printAtomTag(level
, "access scope=\""+access
+"\"");
690 if (programElementDoc
.isFinal())
691 printAtomTag(level
, "isFinal");
692 if (programElementDoc
.isStatic())
693 printAtomTag(level
, "isStatic");
696 protected void outputTags(int level
, Tag
[] tags
, boolean descend
, int context
) {
698 for (int i
=0; i
<tags
.length
; ++i
) {
699 outputTag(tags
[i
], level
, descend
, context
, i
== tags
.length
-1);
703 protected void outputTag(Tag tag
, int level
, boolean descend
, int context
, boolean lastTag
) {
705 if (!"Text".equals(tag
.name())) {
706 printOpenTag(0 /* don't introduce additional whitespace */,
707 "tag kind=\""+tag
.kind()+"\" name=\""+tag
.name()+"\"", false);
709 if (tag
instanceof ThrowsTag
) {
710 ThrowsTag throwsTag
= (ThrowsTag
)tag
;
711 if (null!=throwsTag
.exception()) {
712 outputType(level
+1, "exception", throwsTag
.exception());
715 StringBuffer sb
= new StringBuffer("Exception ");
716 sb
.append(throwsTag
.exceptionName());
717 sb
.append(" not found in ");
718 if (currentExecMember
instanceof MethodDoc
) {
719 MethodDoc m
= (MethodDoc
)currentExecMember
;
720 sb
.append(m
.returnType().typeName());
721 sb
.append(m
.returnType().dimension());
724 sb
.append(currentClass
.qualifiedName());
726 sb
.append(currentExecMember
.name());
728 Parameter
[] params
= currentExecMember
.parameters();
729 for (int j
=0; j
< params
.length
; j
++) {
730 sb
.append(params
[j
].type().typeName());
731 sb
.append(params
[j
].type().dimension());
733 sb
.append(params
[j
].name());
734 if (j
!= params
.length
-1)
738 printWarning(sb
.toString());
740 printAtomTag(level
+1, "exception typename=\""+throwsTag
.exceptionName()+"\"");
743 else if (tag
instanceof ParamTag
) {
744 ParamTag paramTag
= (ParamTag
)tag
;
745 printAtomTag(level
+1, "parameter name=\""+paramTag
.parameterName()+"\"");
748 if (null != tag
.text()) {
749 //printOpenTag(level+1, "text", false);
751 print(htmlRepairer
.getWellformedHTML(tag
.text()));
754 print("<![CDATA["+cdata(tag
.text())+"]]>");
756 //printCloseTag(0 /* don't introduce additional whitespace */, "text");
759 printWarning("Tag got null text: "+tag
);
762 if ((descend
&& ("@throws".equals(tag
.name()) || "@param".equals(tag
.name()))) || "@deprecated".equals(tag
.name())) {
763 if (tag
.firstSentenceTags().length
>0) {
764 printOpenTag(level
+1, "firstSentenceTags", false);
765 outputTags(level
+2, tag
.firstSentenceTags(), false, context
);
766 printCloseTag(0, "firstSentenceTags");
769 if (tag
.inlineTags().length
>0) {
770 printOpenTag(level
+1, "inlineTags", false);
771 outputTags(level
+2, tag
.firstSentenceTags(), false, context
);
772 printCloseTag(0, "inlineTags");
776 if (fixHTML
&& lastTag
) {
777 String terminateText
= htmlRepairer
.terminateText();
778 if (null != terminateText
&& terminateText
.length() > 0) {
779 print(terminateText
);
783 if (!"Text".equals(tag
.name())) {
785 Taglet inlineTaglet
= (Taglet
)tagletMap
.get(tag
.name().substring(1));
786 if (null != inlineTaglet
&& inlineTaglet
.isInlineTag()) {
787 printOpenTag(0, "inlineTagletText", false);
788 print(inlineTaglet
.toString(tag
));
789 printCloseTag(0, "inlineTagletText");
792 printCloseTag(0, "tag", false);
796 void outputTaglets(int level
, Tag
[] tags
, boolean descend
, int context
)
798 for (Iterator it
= tagletMap
.keySet().iterator(); it
.hasNext(); ) {
799 String tagName
= (String
)it
.next();
800 Object o
= tagletMap
.get(tagName
);
801 Taglet taglet
= (Taglet
)o
;
803 if (!taglet
.isInlineTag()
804 && ((context
!= CONTEXT_CONSTRUCTOR
|| taglet
.inConstructor())
805 || (context
!= CONTEXT_FIELD
|| taglet
.inField())
806 || (context
!= CONTEXT_METHOD
|| taglet
.inMethod())
807 || (context
!= CONTEXT_OVERVIEW
|| taglet
.inOverview())
808 || (context
!= CONTEXT_PACKAGE
|| taglet
.inPackage())
809 || (context
!= CONTEXT_TYPE
|| taglet
.inType()))) {
811 List tagsOfThisType
= new ArrayList();
812 for (int i
=0, ilim
=tags
.length
; i
<ilim
; ++i
) {
813 if (tags
[i
].name().substring(1).equals(tagName
)) {
814 tagsOfThisType
.add(tags
[i
]);
818 if (!tagsOfThisType
.isEmpty()) {
819 Tag
[] tagletTags
= (Tag
[])tagsOfThisType
.toArray(new Tag
[tagsOfThisType
.size()]);
820 if (taglet
instanceof StandardTaglet
) {
821 Iterator tagIterator
= tagsOfThisType
.iterator();
822 while (tagIterator
.hasNext()) {
823 Tag tag
= (Tag
)tagIterator
.next();
824 outputTag(tag
, level
, descend
, context
, !tagIterator
.hasNext());
828 String tagletString
= taglet
.toString(tagletTags
);
829 if (null != tagletString
) {
830 printOpenTag(0, "tag name=\"" + tagName
+ "\" taglet-generated=\"true\"");
832 print(htmlRepairer
.getWellformedHTML(tagletString
));
833 print(htmlRepairer
.terminateText());
836 print("<![CDATA["+cdata(tagletString
)+"]]>");
838 printCloseTag(0, "tag", false);
847 * Inofficial entry point. We got an instance here.
849 protected boolean instanceStart(RootDoc _rootDoc
) {
851 this.rootDoc
= _rootDoc
;
854 boolean xmlOnly
= true;
856 // Set the default Taglet order
858 registerTaglet(new VersionTaglet());
859 registerTaglet(new AuthorTaglet());
860 //registerTaglet(new SinceTaglet());
861 registerTaglet(new StandardTaglet("deprecated"));
862 registerTaglet(new StandardTaglet("see"));
863 registerTaglet(new StandardTaglet("param"));
865 // Set the built-in Taglet filter
867 AuthorTaglet
.setTagletEnabled(false);
868 VersionTaglet
.setTagletEnabled(false);
869 SinceTaglet
.setTagletEnabled(true);
870 DeprecatedTaglet
.setTagletEnabled(true);
875 // Process command line options passed through to this doclet
877 TargetContext targetContext
= null;
879 TargetContext htmlTargetContext
880 = new TargetContext(DocTranslet
.fromClasspath("/doctranslets/html/gjdoc.xsl"),
883 for (int i
=0, ilim
=rootDoc
.options().length
; i
<ilim
; ++i
) {
885 String
[] option
= rootDoc
.options()[i
];
886 String optionTag
= option
[0];
888 if ("-d".equals(optionTag
)) {
889 if (null == targetDirectory
) {
890 targetDirectory
= new File(option
[1]);
892 if (null != targetContext
) {
893 targetContext
.setTargetDirectory(targetDirectory
);
897 else if ("-nofixhtml".equals(optionTag
)) {
899 printError("-nofixhtml currently not supported.");
902 else if ("-compress".equals(optionTag
)) {
905 else if ("-nohtmlwarn".equals(optionTag
)) {
908 else if ("-noemailwarn".equals(optionTag
)) {
911 else if ("-indentstep".equals(optionTag
)) {
912 indentStep
= Integer
.parseInt(option
[1]);
914 else if ("-doctranslet".equals(optionTag
)) {
915 targets
.add(targetContext
= new TargetContext(DocTranslet
.fromJarFile(new File(option
[1])),
918 else if ("-genhtml".equals(optionTag
)) {
919 htmlTargetContext
.setTargetDirectory(targetDirectory
);
920 targets
.add(targetContext
= htmlTargetContext
);
923 else if ("-geninfo".equals(optionTag
)) {
925 = new TargetContext(DocTranslet
.fromClasspath("/doctranslets/info/gengj.xsl"),
927 targets
.add(targetContext
);
929 printNotice("NOTE: -geninfo implies -fixhtml.");
934 else if ("-gendocbook".equals(optionTag
)) {
935 targetContext
= new TargetContext(DocTranslet
.fromClasspath("/doctranslets/docbook/gengj.xsl"),
937 targets
.add(targetContext
);
939 printNotice("NOTE: -gendocbook implies -fixhtml.");
943 else if ("-genpdf".equals(optionTag
)) {
945 = new TargetContext(DocTranslet
.fromClasspath("/doctranslets/docbook/gengj.xsl"),
947 /** "gnu.classpath.tools.doclets.xmldoclet.DocBookPostprocessor") **/
948 targets
.add(targetContext
);
950 printNotice("NOTE: -genpdf implies -fixhtml.");
954 else if ("-xmlonly".equals(optionTag
)) {
957 else if ("-bottomnote".equals(optionTag
)) {
959 FileReader reader
= new FileReader(option
[1]);
960 StringWriter writer
= new StringWriter();
961 char[] buf
= new char[256];
963 while ((nread
= reader
.read(buf
)) >= 0) {
964 writer
.write(buf
, 0, nread
);
967 bottomNote
= writer
.toString();
971 else if ("-title".equals(optionTag
)) {
975 else if ("-workpath".equals(optionTag
)) {
977 workingPath
= option
[1];
979 else if ("-tagletpath".equals(optionTag
)) {
981 if (null == tagletPath
) {
982 tagletPath
= option
[1];
985 tagletPath
= tagletPath
+ File
.pathSeparator
+ option
[1];
988 else if ("-taglet".equals(optionTag
)) {
990 boolean tagletLoaded
= false;
992 String useTagletPath
= this.tagletPath
;
993 if (null == useTagletPath
) {
994 useTagletPath
= System
.getProperty("java.class.path");
1001 = new FileSystemClassLoader(useTagletPath
).loadClass(option
[1]);
1003 catch (ClassNotFoundException e
) {
1004 // If not found on specified tagletpath, try default classloader
1006 = Class
.forName(option
[1]);
1008 Method registerTagletMethod
1009 = tagletClass
.getDeclaredMethod("register", new Class
[] { java
.util
.Map
.class });
1011 if (!registerTagletMethod
.getReturnType().equals(Void
.TYPE
)) {
1012 printError("Taglet class '" + option
[1] + "' found, but register method doesn't return void.");
1014 else if (registerTagletMethod
.getExceptionTypes().length
> 0) {
1015 printError("Taglet class '" + option
[1] + "' found, but register method contains throws clause.");
1017 else if ((registerTagletMethod
.getModifiers() & (Modifier
.STATIC
| Modifier
.PUBLIC
| Modifier
.ABSTRACT
)) != (Modifier
.STATIC
| Modifier
.PUBLIC
)) {
1018 printError("Taglet class '" + option
[1] + "' found, but register method isn't public static, or is abstract..");
1021 Map tempMap
= new HashMap();
1022 registerTagletMethod
.invoke(null, new Object
[] { tempMap
});
1023 tagletLoaded
= true;
1024 String name
= (String
)tempMap
.keySet().iterator().next();
1025 Taglet taglet
= (Taglet
)tempMap
.get(name
);
1026 tagletMap
.put(name
, taglet
);
1027 mentionedTags
.add(taglet
);
1030 catch (NoSuchMethodException e
) {
1031 printError("Taglet class '" + option
[1] + "' found, but doesn't contain the register method.");
1033 catch (SecurityException e
) {
1034 printError("Taglet class '" + option
[1] + "' cannot be loaded: " + e
.getMessage());
1036 catch (InvocationTargetException e
) {
1037 printError("Taglet class '" + option
[1] + "' found, but register method throws exception: " + e
.toString());
1039 catch (IllegalAccessException e
) {
1040 printError("Taglet class '" + option
[1] + "' found, but there was a problem when accessing the register method: " + e
.toString());
1042 catch (IllegalArgumentException e
) {
1043 printError("Taglet class '" + option
[1] + "' found, but there was a problem when accessing the register method: " + e
.toString());
1045 catch (ClassNotFoundException e
) {
1046 printError("Taglet class '" + option
[1] + "' cannot be found.");
1048 if (!tagletLoaded
) {
1052 else if ("-author".equals(optionTag
)) {
1053 AuthorTaglet
.setTagletEnabled(true);
1055 else if ("-version".equals(optionTag
)) {
1056 VersionTaglet
.setTagletEnabled(true);
1058 else if ("-nosince".equals(optionTag
)) {
1059 SinceTaglet
.setTagletEnabled(false);
1061 else if ("-nodeprecated".equals(optionTag
)) {
1062 DeprecatedTaglet
.setTagletEnabled(false);
1064 else if ("-authormail".equals(optionTag
)) {
1066 if ("no-replace".equalsIgnoreCase(option
[1])) {
1067 AuthorTaglet
.setEmailReplacementType(AuthorTaglet
.EmailReplacement
.NO_REPLACEMENT
);
1069 else if ("mailto-name".equalsIgnoreCase(option
[1])) {
1070 AuthorTaglet
.setEmailReplacementType(AuthorTaglet
.EmailReplacement
.MAILTO_NAME
);
1072 else if ("name-mailto-address".equalsIgnoreCase(option
[1])) {
1073 AuthorTaglet
.setEmailReplacementType(AuthorTaglet
.EmailReplacement
.NAME_MAILTO_ADDRESS
);
1075 else if ("name-mangled-address".equalsIgnoreCase(option
[1])) {
1076 AuthorTaglet
.setEmailReplacementType(AuthorTaglet
.EmailReplacement
.NAME_MANGLED_ADDRESS
);
1079 printError("Invalid value for option '-authortag-email'. Allowed values are:"
1080 + " no-replace, mailto-name, name-mailto-address, name-mangled-address.");
1084 else if ("-mailmangledot".equals(optionTag
)) {
1085 AuthorTaglet
.setDotReplacement(option
[1]);
1087 else if ("-mailmangleat".equals(optionTag
)) {
1088 AuthorTaglet
.setAtReplacement(option
[1]);
1090 else if ("-docfilessubdirs".equals(optionTag
)) {
1091 docFilesSubdirsEnabled
= true;
1093 else if ("-excludedocfilessubdir".equals(optionTag
)) {
1094 StringTokenizer st
= new StringTokenizer(option
[1]);
1095 while (st
.hasMoreTokens()) {
1096 excludeDocFilesSubDirs
.add(st
.nextToken());
1099 else if ("-nonavbar".equals(optionTag
)) {
1100 docTransletOptions
.nonavbar
= true;
1102 else if ("-noindex".equals(optionTag
)) {
1103 docTransletOptions
.noindex
= true;
1105 else if ("-notree".equals(optionTag
)) {
1106 docTransletOptions
.notree
= true;
1108 else if ("-nocomment".equals(optionTag
)) {
1109 docTransletOptions
.nocomment
= true;
1111 else if ("-nohelp".equals(optionTag
)) {
1112 docTransletOptions
.nohelp
= true;
1114 else if ("-splitindex".equals(optionTag
)) {
1115 docTransletOptions
.splitindex
= true;
1117 else if ("-linksource".equals(optionTag
)) {
1118 docTransletOptions
.linksource
= true;
1120 else if ("-windowtitle".equals(optionTag
)) {
1121 docTransletOptions
.windowtitle
= option
[1];
1123 else if ("-helpfile".equals(optionTag
)) {
1124 docTransletOptions
.helpfile
= new File(option
[1]).toURL().toString();
1126 else if ("-stylesheetfile".equals(optionTag
)) {
1127 docTransletOptions
.stylesheetfile
= new File(option
[1]).toURL().toString();
1129 else if ("-header".equals(optionTag
)) {
1130 docTransletOptions
.header
= option
[1];
1132 else if ("-footer".equals(optionTag
)) {
1133 docTransletOptions
.footer
= option
[1];
1135 else if ("-bottom".equals(optionTag
)) {
1136 docTransletOptions
.bottom
= option
[1];
1138 else if ("-doctitle".equals(optionTag
)) {
1139 docTransletOptions
.doctitle
= option
[1];
1141 else if ("-nodeprecatedlist".equals(optionTag
)) {
1142 docTransletOptions
.nodeprecatedlist
= true;
1144 else if ("-uses".equals(optionTag
)) {
1145 docTransletOptions
.uses
= true;
1147 else if ("-group".equals(optionTag
)) {
1148 if (!processGroupOption(option
[1], option
[2])) {
1149 printError("Invalid package wildcard list in -group option \"" + option
[1] + "\" " + option
[2]);
1153 else if ("-tag".equals(optionTag
)) {
1154 String tagSpec
= option
[1];
1155 boolean validTagSpec
= false;
1156 int ndx1
= tagSpec
.indexOf(':');
1158 Taglet taglet
= (Taglet
)tagletMap
.get(tagSpec
);
1159 if (null == taglet
) {
1160 printError("There is no standard tag '" + tagSpec
+ "'.");
1163 if (mentionedTags
.contains(taglet
)) {
1164 printError("Tag '" + tagSpec
+ "' has been added or moved before.");
1167 mentionedTags
.add(taglet
);
1170 tagletMap
.remove(tagSpec
);
1171 tagletMap
.put(tagSpec
, taglet
);
1176 int ndx2
= tagSpec
.indexOf(':', ndx1
+ 1);
1177 if (ndx2
> ndx1
&& ndx2
< tagSpec
.length() - 1) {
1178 String tagName
= tagSpec
.substring(0, ndx1
);
1179 String tagHead
= null;
1180 if (tagSpec
.charAt(ndx2
+ 1) == '\"') {
1181 if (tagSpec
.charAt(tagSpec
.length() - 1) == '\"') {
1182 tagHead
= tagSpec
.substring(ndx2
+ 2, tagSpec
.length() - 1);
1183 validTagSpec
= true;
1187 tagHead
= tagSpec
.substring(ndx2
+ 1);
1188 validTagSpec
= true;
1191 boolean tagScopeOverview
= false;
1192 boolean tagScopePackages
= false;
1193 boolean tagScopeTypes
= false;
1194 boolean tagScopeConstructors
= false;
1195 boolean tagScopeMethods
= false;
1196 boolean tagScopeFields
= false;
1197 boolean tagDisabled
= false;
1200 for (int n
=ndx1
+1; n
<ndx2
; ++n
) {
1201 switch (tagSpec
.charAt(n
)) {
1206 tagScopeOverview
= true;
1207 tagScopePackages
= true;
1208 tagScopeTypes
= true;
1209 tagScopeConstructors
= true;
1210 tagScopeMethods
= true;
1211 tagScopeFields
= true;
1214 tagScopeOverview
= true;
1217 tagScopePackages
= true;
1220 tagScopeTypes
= true;
1223 tagScopeConstructors
= true;
1226 tagScopeMethods
= true;
1229 tagScopeFields
= true;
1232 validTagSpec
= false;
1233 break tag_option_loop
;
1238 GenericTaglet taglet
1239 = new GenericTaglet(tagName
,
1244 tagScopeConstructors
,
1247 taglet
.setTagletEnabled(!tagDisabled
);
1248 taglet
.register(tagletMap
);
1249 mentionedTags
.add(taglet
);
1253 if (!validTagSpec
) {
1254 printError("Value for option -tag must be in format \"<tagname>:Xaoptcmf:<taghead>\".");
1259 // Use current directory if target directory hasn't been set.
1260 if (null == targetDirectory
) {
1261 targetDirectory
= new File(System
.getProperty("user.dir"));
1263 if (null != targetContext
) {
1264 targetContext
.setTargetDirectory(targetDirectory
);
1267 // It is illegal to specify targets AND -xmlonly.
1269 if (xmlOnly
&& targets
.size() > 0) {
1271 printError("You can only specify one of -xmlonly and a target format.");
1275 // If no target was specified and XML only was not
1276 // requested, use HTML as default target.
1278 if (!xmlOnly
&& targets
.size() == 0) {
1279 targets
.add(targetContext
= htmlTargetContext
);
1282 // Set the same target directory for all output.
1284 // FIXME: Allow separate target directories for different
1287 for (Iterator it
= targets
.iterator(); it
.hasNext(); ) {
1288 TargetContext t
= (TargetContext
)it
.next();
1289 t
.setTargetDirectory(targetDirectory
);
1292 // Create temporary directory if necessary
1296 xmlTargetDirectory
= targetDirectory
;
1300 File workingTopDirectory
= new File(workingPath
);
1302 workingDirectory
= new File(workingTopDirectory
, "gjdoc.tmp."+System
.currentTimeMillis());
1304 if (!workingDirectory
.mkdir()) {
1305 printError("Cannot create temporary directory at "+System
.getProperty("java.io.tmpdir"));
1309 File xmlTempDirectory
= new File(workingDirectory
, "xmloutput");
1311 if (!xmlTempDirectory
.mkdir()) {
1312 printError("Cannot create temporary directory for XML output at "+System
.getProperty("java.io.tmpdir"));
1316 xmlTargetDirectory
= xmlTempDirectory
;
1319 // Create target directory if necessary
1321 if (!targetDirectory
.exists()) {
1322 printNotice("Creating destination directory: \""
1323 + targetDirectory
+ "\"");
1324 if (!targetDirectory
.mkdirs()) {
1325 printError("Failed to create destination directory \""
1326 + targetDirectory
+ "\"");
1331 // Check for deprecation
1333 boolean hasDeprecatedClasses
= false;
1334 boolean hasDeprecatedInterfaces
= false;
1335 boolean hasDeprecatedExceptions
= false;
1336 boolean hasDeprecatedErrors
= false;
1337 boolean hasDeprecatedMethods
= false;
1338 boolean hasDeprecatedFields
= false;
1341 ClassDoc
[] classes
= rootDoc
.classes();
1342 for (int i
= 0, ilim
= classes
.length
; i
< ilim
; ++ i
) {
1343 ClassDoc c
= classes
[i
];
1344 Tag
[] deprecatedTags
= c
.tags("deprecated");
1345 if (null != deprecatedTags
&& 0 != deprecatedTags
.length
) {
1346 if (c
.isInterface()) {
1347 hasDeprecatedInterfaces
= true;
1349 else if (c
.isException()) {
1350 hasDeprecatedExceptions
= true;
1352 else if (c
.isError()) {
1353 hasDeprecatedErrors
= true;
1355 else /*if (c.isOrdinaryClass())*/ {
1356 hasDeprecatedClasses
= true;
1360 MethodDoc
[] methods
= c
.methods();
1361 for (int j
= 0, jlim
= methods
.length
; j
< jlim
; ++ j
) {
1362 MethodDoc m
= methods
[j
];
1363 deprecatedTags
= m
.tags("deprecated");
1364 if (null != deprecatedTags
&& 0 != deprecatedTags
.length
) {
1365 hasDeprecatedMethods
= true;
1369 FieldDoc
[] fields
= c
.fields();
1370 for (int j
= 0, jlim
= fields
.length
; j
< jlim
; ++ j
) {
1371 FieldDoc f
= fields
[j
];
1372 deprecatedTags
= f
.tags("deprecated");
1373 if (null != deprecatedTags
&& 0 != deprecatedTags
.length
) {
1374 hasDeprecatedFields
= true;
1380 htmlRepairer
= new HtmlRepairer(rootDoc
, noHTMLWarn
, noEmailWarn
,
1381 currentClass
, currentMember
,
1386 // Begin XML generation
1388 printNotice("Writing XML Index file...");
1390 // Assign output stream
1392 setTargetFile("index.xml");
1394 // Output XML document header
1396 println(0, "<?xml version=\"1.0\"?>");
1397 println("<!DOCTYPE gjdoc SYSTEM \"dtd/gjdoc.dtd\">");
1399 printOpenTag(0, "rootdoc xmlns=\"http://www.w3.org/TR/REC-html40\" xmlns:gjdoc=\"http://www.gnu.org/software/cp-tools/gjdocxml\"");
1402 println(1, "<!-- Tags from overview page, if available -->");
1404 if (rootDoc
.firstSentenceTags().length
> 0) {
1405 printOpenTag(2, "firstSentenceTags", false);
1406 outputTags(3, rootDoc
.firstSentenceTags(), true, CONTEXT_PACKAGE
);
1407 printCloseTag(0, "firstSentenceTags");
1410 if (rootDoc
.inlineTags().length
> 0) {
1411 printOpenTag(2, "inlineTags");
1412 outputTags(3, rootDoc
.inlineTags(), true, CONTEXT_PACKAGE
);
1413 printCloseTag(2, "inlineTags");
1416 if (null != bottomNote
) {
1417 printOpenTag(1, "bottomnote");
1419 printCloseTag(1, "bottomnote");
1422 if (null != title
) {
1423 printOpenTag(1, "title");
1425 printCloseTag(1, "title");
1428 printOpenTag(1, "created");
1429 println(2, DateFormat
.getDateInstance(DateFormat
.LONG
, Locale
.US
).format(new java
.util
.Date()));
1430 printCloseTag(1, "created");
1432 if (hasDeprecatedClasses
) printAtomTag(1, "hasDeprecatedClasses");
1433 if (hasDeprecatedInterfaces
) printAtomTag(1, "hasDeprecatedInterfaces");
1434 if (hasDeprecatedExceptions
) printAtomTag(1, "hasDeprecatedExceptions");
1435 if (hasDeprecatedErrors
) printAtomTag(1, "hasDeprecatedErrors");
1436 if (hasDeprecatedMethods
) printAtomTag(1, "hasDeprecatedMethods");
1437 if (hasDeprecatedFields
) printAtomTag(1, "hasDeprecatedFields");
1439 // Output summary of all classes specified on command line
1442 println(1, "<!-- Classes specified by user on command line -->");
1443 ClassDoc
[] specifiedClasses
= rootDoc
.specifiedClasses();
1444 for (int i
=0, ilim
=specifiedClasses
.length
; i
<ilim
; ++i
) {
1445 ClassDoc sc
= specifiedClasses
[i
];
1446 printAtomTag(1, "specifiedclass fqname=\""+sc
.qualifiedName()+"\" name=\""+sc
.name()+"\"");
1448 specifiedClasses
= null;
1450 // Output summary of all packages specified on command line
1453 println(1, "<!-- Packages specified by user on command line -->");
1454 PackageDoc
[] specifiedPackages
= rootDoc
.specifiedPackages();
1455 for (int i
=0, ilim
=specifiedPackages
.length
; i
<ilim
; ++i
) {
1456 PackageDoc sp
= specifiedPackages
[i
];
1457 printAtomTag(1, "specifiedpackage name=\""+sp
.name()+"\"");
1459 specifiedPackages
= null;
1461 // Output package group information specified on the
1465 println(1, "<!-- Package groups specified by user on command line -->");
1467 Iterator packageGroupIt
= packageGroups
.iterator();
1468 while (packageGroupIt
.hasNext()) {
1469 PackageGroup packageGroup
= (PackageGroup
)packageGroupIt
.next();
1470 SortedSet groupedPackages
= packageGroup
.getPackages();
1471 if (groupedPackages
.isEmpty()) {
1472 printWarning("Package group named '"
1473 + packageGroup
.getName() + "' didn't match any packages.");
1476 printOpenTag(1, "packagegroup name=\"" + packageGroup
.getName() + "\"");
1477 Iterator groupedPackageIt
= groupedPackages
.iterator();
1478 while (groupedPackageIt
.hasNext()) {
1479 PackageDoc groupedPackageDoc
= (PackageDoc
)groupedPackageIt
.next();
1480 printAtomTag(2, "package name=\"" + groupedPackageDoc
.name() + "\"");
1482 printCloseTag(1, "packagegroup");
1485 packageGroups
= null;
1488 // Output information on all packages for which documentation
1489 // has been made available via the Doclet API
1492 println(1, "<!-- Documentation for all packages -->");
1493 PackageDoc
[] packages
= rootDoc
.specifiedPackages();
1494 for (int i
=0, ilim
=packages
.length
; i
<ilim
; ++i
) {
1495 PackageDoc c
= packages
[i
];
1496 outputPackageDoc(c
);
1500 // Output brief summary on all classes for which documentation
1501 // has been made available via the Doclet API.
1503 // While this is redundant, it can speed up XSLT
1504 // processing by orders of magnitude
1507 println(1, "<!-- Brief summary for all classes -->");
1508 ClassDoc
[] sumclasses
= rootDoc
.classes();
1509 for (int i
=0, ilim
=sumclasses
.length
; i
<ilim
; ++i
) {
1510 ClassDoc c
= sumclasses
[i
];
1511 outputClassDocSummary(c
);
1515 // Output closing tag, finish output stream
1518 printCloseTag(0, "rootdoc");
1522 createIndexByName();
1526 // Output information on all classes for which documentation
1527 // has been made available via the Doclet API
1530 println(1, "<!-- Documentation for all classes -->");
1531 ClassDoc
[] classes
= rootDoc
.classes();
1532 String prevPackageName
= null;
1533 for (int i
= 0, ilim
= classes
.length
; i
< ilim
; ++ i
) {
1534 ClassDoc c
= classes
[i
];
1537 printNotice("Writing XML information for "+c
.qualifiedName()+"...");
1540 String packageName
= c
.containingPackage().name();
1541 if (null == prevPackageName
|| !packageName
.equals(prevPackageName
)) {
1542 printNotice("Writing XML information for "+packageName
+"...");
1543 prevPackageName
= packageName
;
1547 setTargetFile(c
.qualifiedName().replace('/','.')+".xml");
1549 println("<?xml version=\"1.0\"?>");
1550 println("<!DOCTYPE gjdoc SYSTEM \"dtd/gjdoc.dtd\">");
1559 // Copy DTD files to temporary directory
1561 // FIXME: try to solve this via jar: URLs. but this will
1562 // probably break libxmlj compatibility (?)
1564 String
[] resources
= new String
[] {
1566 "gjdoc-alphaindex.dtd",
1589 File tempDtdDirectory
= new File(xmlTargetDirectory
, "dtd");
1590 File tempDtdEntDirectory
= new File(tempDtdDirectory
, "ent");
1592 if ((tempDtdDirectory
.exists() || tempDtdDirectory
.mkdir())
1593 && (tempDtdEntDirectory
.exists() || tempDtdEntDirectory
.mkdir())) {
1594 for (int i
= 0; i
< resources
.length
; ++ i
) {
1595 copyResourceToFile("/dtd/" + resources
[i
],
1596 new File(tempDtdDirectory
, resources
[i
]));
1600 printError("Cannot create temporary directories for DTD data at " + tempDtdDirectory
);
1604 // Copy package data-dir directory
1607 PackageDoc
[] packages
= rootDoc
.specifiedPackages();
1608 for (int i
=0, ilim
=packages
.length
; i
<ilim
; ++i
) {
1609 PackageDoc c
= packages
[i
];
1610 if (c
instanceof GjdocPackageDoc
) {
1611 copyPackageDataDir((GjdocPackageDoc
)c
);
1616 // All information has been output. Apply stylesheet if given.
1618 gnu
.classpath
.tools
.gjdoc
.Main
.releaseRootDoc();
1620 this.currentClass
= null;
1621 this.currentMember
= null;
1622 this.currentExecMember
= null;
1626 // From this point we are only operating on files, so we don't
1627 // need this anymore and can free up some memory
1629 for (Iterator it
= targets
.iterator(); it
.hasNext(); ) {
1631 TargetContext target
= (TargetContext
)it
.next();
1633 // We have XSLT postprocessing, run DocTranslet.
1635 //DocTranslet docTranslet = DocTranslet.fromClasspath("/doctranslets/html/gjdoc.xsl");
1637 //docTranslet.setOptions(docTransletOptions);
1639 target
.getDocTranslet().setOptions(docTransletOptions
);
1641 target
.getDocTranslet().apply(xmlTargetDirectory
,
1642 target
.getTargetDirectory(),
1651 Runtime
.getRuntime().runFinalization();
1655 catch (Exception e
) {
1657 // Something went wrong. Report to stderr and pass error to
1660 e
.printStackTrace();
1661 printError(e
.toString());
1663 Throwable rootCause
= e
.getCause();
1664 if (null != rootCause
) {
1665 while (null != rootCause
.getCause()) {
1666 rootCause
= rootCause
.getCause();
1668 System
.err
.println("Root cause:");
1669 rootCause
.printStackTrace();
1676 // In any case, delete the working directory if we created one
1678 if (null != workingDirectory
) {
1680 if (!deleteRecursive(workingDirectory
)) {
1681 printWarning("Could not delete temporary directory at "+workingDirectory
);
1685 printNotice("Done.");
1690 * Recursively delete the specified directory and its contents,
1691 * like <code>rm -Rf directory</code>
1693 * @return <code>true</code> on success
1695 private static boolean deleteRecursive(File directory
) {
1697 boolean success
= true;
1699 File
[] files
= directory
.listFiles();
1701 for (int i
=0, ilim
=files
.length
; i
<ilim
; ++i
) {
1703 File file
= files
[i
];
1705 if (file
.isDirectory()) {
1707 success
= deleteRecursive(file
) && success
;
1711 success
= file
.delete() && success
;
1715 return directory
.delete() && success
;
1719 * Prints a string to stdout and appends a newline. Convenience
1722 protected void println(String str
) {
1727 * Prints a string to stdout without appending a newline.
1728 * Convenience method.
1730 protected void print(String str
) {
1735 * In standard mode, prints an empty line to stdout.
1736 * In thight mode, nothing happens.
1737 * Convenience method.
1739 protected void println() {
1746 * In standard mode, prints the given text indented to stdout and appends newline.
1747 * In tight mode, doesn't print indentation or newlines.
1749 protected void print(int indentLevel
, String msg
) {
1754 StringBuffer indentation
= new StringBuffer();
1755 for (int i
=0; i
<indentLevel
*indentStep
; ++i
) {
1756 indentation
.append(' ');
1758 out
.print(indentation
+msg
);
1763 * In tight mode, prints a message at a given indentation level.
1764 * In standard mode, appends a newline in addition.
1766 protected void println(int indentLevel
, String msg
) {
1767 print(indentLevel
, msg
);
1768 if (!compress
) out
.println();
1772 * Prints an atom tag at the given indentation level.
1774 protected void printAtomTag(int level
, String tag
) {
1775 println(level
, "<"+tagPrefix
+":"+replaceCharsInTag(tag
)+"/>");
1779 * Prints an open tag at the given indentation level.
1781 protected void printOpenTag(int level
, String tag
) {
1782 printOpenTag(level
, replaceCharsInTag(tag
), true);
1786 * Prints an open tag at the given indentation level and
1787 * conditionally appends a newline (if not in tight mode).
1789 protected void printOpenTag(int level
, String tag
, boolean appendNewline
) {
1790 if (appendNewline
&& !compress
) {
1791 println(level
, "<"+tagPrefix
+":"+replaceCharsInTag(tag
)+">");
1794 print(level
, "<"+tagPrefix
+":"+replaceCharsInTag(tag
)+">");
1799 * Prints a close tag at the given indentation level.
1801 protected void printCloseTag(int level
, String tag
) {
1802 printCloseTag(level
, tag
, true);
1806 * Prints a close tag at the given indentation level and
1807 * conditionally appends a newline (if not in tight mode).
1809 protected void printCloseTag(int level
, String tag
, boolean appendNewline
) {
1810 if (appendNewline
&& !compress
) {
1811 println(level
, "</"+tagPrefix
+":"+replaceCharsInTag(tag
)+">");
1814 print(level
, "</"+tagPrefix
+":"+replaceCharsInTag(tag
)+">");
1818 public static int optionLength(String option
) {
1819 if ("-d".equals(option
)) return 2;
1820 else if ("-fixhtml".equals(option
)) return 1;
1821 else if ("-compress".equals(option
)) return 1;
1822 else if ("-nohtmlwarn".equals(option
)) return 1;
1823 else if ("-noemailwarn".equals(option
)) return 1;
1824 else if ("-indentstep".equals(option
)) return 2;
1825 else if ("-xslsheet".equals(option
)) return 2;
1826 else if ("-xsltdriver".equals(option
)) return 2;
1827 else if ("-postprocess".equals(option
)) return 2;
1828 else if ("-genhtml".equals(option
)) return 1;
1829 else if ("-geninfo".equals(option
)) return 1;
1830 else if ("-gendocbook".equals(option
)) return 1;
1831 else if ("-xmlonly".equals(option
)) return 1;
1832 else if ("-bottomnote".equals(option
)) return 2;
1833 else if ("-workpath".equals(option
)) return 2;
1834 else if ("-title".equals(option
)) return 2;
1835 else if ("-tagletpath".equals(option
)) return 2;
1836 else if ("-taglet".equals(option
)) return 2;
1837 else if ("-authormail".equals(option
)) return 2;
1838 else if ("-mailmangledot".equals(option
)) return 2;
1839 else if ("-mailmangleat".equals(option
)) return 2;
1840 else if ("-noindex".equals(option
)) return 1;
1841 else if ("-nocomment".equals(option
)) return 1;
1842 else if ("-notree".equals(option
)) return 1;
1843 else if ("-nohelp".equals(option
)) return 1;
1844 else if ("-nonavbar".equals(option
)) return 1;
1845 else if ("-splitindex".equals(option
)) return 1;
1846 else if ("-author".equals(option
)) return 1;
1847 else if ("-version".equals(option
)) return 1;
1848 else if ("-nosince".equals(option
)) return 1;
1849 else if ("-nodeprecated".equals(option
)) return 1;
1850 else if ("-linksource".equals(option
)) return 1;
1851 else if ("-windowtitle".equals(option
)) return 2;
1852 else if ("-helpfile".equals(option
)) return 2;
1853 else if ("-stylesheetfile".equals(option
)) return 2;
1854 else if ("-tag".equals(option
)) return 2;
1855 else if ("-header".equals(option
)) return 2;
1856 else if ("-footer".equals(option
)) return 2;
1857 else if ("-bottom".equals(option
)) return 2;
1858 else if ("-doctitle".equals(option
)) return 2;
1859 else if ("-nodeprecatedlist".equals(option
)) return 1;
1860 else if ("-uses".equals(option
)) return 1;
1861 else if ("-group".equals(option
)) return 3;
1866 public static boolean validOptions(String
[][] options
) {
1872 * Workaround for non well-formed comments: fix tag contents
1873 * by replacing <code><</code> with <code>&lt;</code>,
1874 * <code>></code> with <code>&gt;</code> and
1875 * <code>&</code> with <code>&amp;</code>.
1877 * @param tagContent String to process
1879 * @return given String with all special characters replaced by
1882 private static String
replaceCharsInTag(String tagContent
) {
1897 * Replaces all occurences of string <code>needle</code> within string
1898 * <code>haystack</code> by string <code>replacement</code>.
1900 * @param haystack The string to search and replace in.
1901 * @param needle The string which is searched for.
1902 * @param replacement The string by which every occurence of <code>needle</code> is replaced.
1904 private static String
replaceString(String haystack
, String needle
, String replacement
) {
1905 int ndx
= haystack
.indexOf(needle
);
1909 return haystack
.substring(0, ndx
) + replacement
1910 + replaceString(haystack
.substring(ndx
+needle
.length()), needle
, replacement
);
1913 protected void setTargetFile(String filename
) throws IOException
{
1915 OutputStream fileOut
= new FileOutputStream(new File(xmlTargetDirectory
, filename
));
1916 out
= new PrintWriter(new BufferedWriter(new OutputStreamWriter(fileOut
, "UTF8")));;
1919 protected void closeTargetFile() {
1925 private String
cdata(String str
) {
1929 } // end of if ((null==str)
1931 StringBuffer rc
= new StringBuffer();
1932 for (int i
=0; i
<str
.length(); ++i
) {
1933 char c
= str
.charAt(i
);
1934 if (c
==0x09 || c
==0x0a || c
==0x0d || (c
>=0x20 && c
<=0xd7ff) || (c
>=0xe000 && c
<=0xfffd) || (c
>=0x10000 && c
<=0x10ffff)) {
1938 printWarning("Invalid Unicode character 0x"+Integer
.toString(c
, 16)+" in javadoc markup has been stripped.");
1942 return rc
.toString();
1945 static void copyResourceToFile(String resourceName
, File target
) throws IOException
{
1947 InputStream in
= Driver
.class.getResourceAsStream(resourceName
);
1951 FileOutputStream out
= new FileOutputStream(target
);
1953 byte[] buffer
= new byte[512];
1954 while ((size
= in
.read(buffer
)) >= 0) {
1955 out
.write(buffer
, 0, size
);
1961 throw new IOException("Can't find resource named "+resourceName
);
1965 private void printError(String error
) {
1966 if (null != rootDoc
) {
1967 rootDoc
.printError(error
);
1970 System
.err
.println("ERROR: "+error
);
1974 private void printWarning(String warning
) {
1975 if (null != rootDoc
) {
1976 rootDoc
.printWarning(warning
);
1979 System
.err
.println("WARNING: "+warning
);
1983 private void printNotice(String notice
) {
1984 if (null != rootDoc
) {
1985 rootDoc
.printNotice(notice
);
1988 System
.err
.println(notice
);
1993 * Copy the contents of the input directory to the output
1994 * directory. The output directory must exist.
1996 private void copyPackageDataDir(GjdocPackageDoc packageDoc
) throws IOException
{
1997 File docFilesSourceDirectory
1998 = new File(packageDoc
.packageDirectory(), "doc-files");
1999 File docFilesTargetDirectory
2000 = new File(this.targetDirectory
,
2001 packageDoc
.name().replace('.', File
.separatorChar
));
2002 if (docFilesSourceDirectory
.exists()) {
2003 printNotice("Copying files from " + docFilesSourceDirectory
);
2004 copyDirectory(docFilesSourceDirectory
, docFilesTargetDirectory
,
2005 docFilesSubdirsEnabled
,
2006 excludeDocFilesSubDirs
);
2011 * Recursively copy the contents of the input directory to the
2012 * output directory. The output directory must exist.
2014 private static void copyDirectory(File sourceDir
, File targetDir
,
2016 Set excludeDirs
) throws IOException
{
2017 if (!targetDir
.exists() && !targetDir
.mkdirs()) {
2018 throw new IOException("Cannot create directory " + targetDir
);
2021 File
[] sourceFiles
= sourceDir
.listFiles();
2022 for (int i
=0; i
<sourceFiles
.length
; ++i
) {
2023 if (sourceFiles
[i
].isDirectory()) {
2024 if (recursive
&& (null == excludeDirs
2025 || !excludeDirs
.contains(sourceFiles
[i
].getName()))) {
2026 File targetSubDir
= new File(targetDir
,
2027 sourceFiles
[i
].getName());
2028 if (targetSubDir
.exists() || targetSubDir
.mkdir()) {
2029 copyDirectory(sourceFiles
[i
], targetSubDir
, recursive
, null);
2032 throw new IOException("Cannot create directory " + targetSubDir
);
2037 copyFile(sourceFiles
[i
], new File(targetDir
, sourceFiles
[i
].getName()));
2043 * Copy the contents of the input file to the output file. The
2044 * output file's parent directory must exist.
2046 private static void copyFile(File sourceFile
, File targetFile
) throws IOException
{
2048 InputStream in
= new FileInputStream(sourceFile
);
2049 OutputStream out
= new FileOutputStream(targetFile
);
2051 byte[] buf
= new byte[512];
2052 while ((nread
= in
.read(buf
)) >= 0) {
2053 out
.write(buf
, 0, nread
);
2059 private void createIndexByName() throws IOException
{
2064 Map indexMap
= new TreeMap(new Comparator() {
2065 public int compare(Object o1
, Object o2
) {
2066 return o1
.toString().toLowerCase().compareTo(o2
.toString().toLowerCase());
2070 // Add packages to index
2072 PackageDoc
[] packages
= rootDoc
.specifiedPackages();
2073 for (int i
=0, ilim
=packages
.length
; i
<ilim
; ++i
) {
2074 PackageDoc c
= packages
[i
];
2075 indexMap
.put(c
.name(), c
);
2078 // Add classes, fields and methods to index
2080 ClassDoc
[] sumclasses
= rootDoc
.classes();
2081 for (int i
=0, ilim
=sumclasses
.length
; i
<ilim
; ++i
) {
2082 ClassDoc c
= sumclasses
[i
];
2083 if (null == c
.containingClass()) {
2084 indexMap
.put(c
.name(), c
);
2087 indexMap
.put(c
.name().substring(c
.containingClass().name().length() + 1), c
);
2089 FieldDoc
[] fields
= c
.fields();
2090 for (int j
=0, jlim
=fields
.length
; j
<jlim
; ++j
) {
2091 indexMap
.put(fields
[j
].name(), fields
[j
]);
2093 MethodDoc
[] methods
= c
.methods();
2094 for (int j
=0, jlim
=methods
.length
; j
<jlim
; ++j
) {
2095 MethodDoc method
= methods
[j
];
2096 StringBuffer signature
= new StringBuffer();
2097 signature
.append(method
.name());
2098 signature
.append('(');
2099 Parameter
[] parameters
= method
.parameters();
2100 for (int k
=0, klim
=parameters
.length
; k
<klim
; ++k
) {
2102 signature
.append(", ");
2104 signature
.append(parameters
[k
].typeName());
2106 signature
.append(')');
2107 indexMap
.put(signature
.toString(), method
);
2111 // Assign output stream
2113 setTargetFile("alphaindex.xml");
2115 // Output XML document header
2117 println(0, "<?xml version=\"1.0\"?>");
2118 println("<!DOCTYPE gjdoc SYSTEM \"dtd/gjdoc-alphaindex.dtd\">");
2120 printOpenTag(0, "alphaindex xmlns=\"http://www.w3.org/TR/REC-html40\" xmlns:gjdoc=\"http://www.gnu.org/software/cp-tools/gjdocxml\"");
2122 Iterator it
= indexMap
.keySet().iterator();
2124 char previousCategoryLetter
= '\0';
2125 boolean categoryOpen
= false;
2127 while (it
.hasNext()) {
2128 String key
= (String
)it
.next();
2129 Doc entry
= (Doc
)indexMap
.get(key
);
2131 char firstChar
= Character
.toUpperCase(key
.charAt(0));
2132 if (firstChar
!= previousCategoryLetter
) {
2134 printCloseTag(1, "category");
2136 printOpenTag(1, "category letter=\"" + firstChar
+ "\"");
2137 categoryOpen
= true;
2138 previousCategoryLetter
= firstChar
;
2141 printOpenTag(2, "entry name=\"" + key
+ "\"");
2142 if (entry
instanceof PackageDoc
) {
2143 printAtomTag(3, "isPackage");
2145 else if (entry
instanceof ClassDoc
) {
2146 printAtomTag(3, "isClass");
2147 ClassDoc centry
= (ClassDoc
)entry
;
2148 currentClass
= centry
;
2149 printAtomTag(3, "containingPackage name=\"" + centry
.containingPackage().name() + "\"");
2150 if (null != centry
.containingClass()) {
2151 printAtomTag(3, "containingClass name=\"" + centry
.containingClass().name() + "\"");
2153 if (centry
.isInterface()) {
2154 printAtomTag(3, "isInterface");
2156 if (centry
.isException()) {
2157 printAtomTag(3, "isException");
2159 if (centry
.isError()) {
2160 printAtomTag(3, "isError");
2162 if (centry
.isOrdinaryClass()) {
2163 printAtomTag(3, "isOrdinaryClass");
2166 else if (entry
instanceof ProgramElementDoc
) {
2167 ProgramElementDoc pentry
= (ProgramElementDoc
)entry
;
2168 currentClass
= pentry
.containingClass();
2169 printAtomTag(3, "containingPackage name=\"" + pentry
.containingPackage().name() + "\"");
2170 printAtomTag(3, "containingClass name=\"" + pentry
.containingClass().name() + "\"");
2171 if (pentry
.isMethod()) {
2172 printAtomTag(3, "isMethod");
2173 ExecutableMemberDoc mentry
= (ExecutableMemberDoc
)pentry
;
2174 printAtomTag(3, "signature full=\""+mentry
.signature()+"\" flat=\""+mentry
.flatSignature()+"\"");
2175 printAtomTag(3, "method name=\"" + mentry
.name() + "\"");
2177 if (pentry
.isField()) {
2178 printAtomTag(3, "isField");
2182 Tag
[] tags
= entry
.firstSentenceTags();
2183 for (int i
=0, ilim
=tags
.length
; i
<ilim
; ++i
) {
2185 if (tag
.firstSentenceTags().length
>0) {
2186 printOpenTag(3, "firstSentenceTags", false);
2187 outputTags(4, tag
.firstSentenceTags(), false, CONTEXT_TYPE
);
2188 printCloseTag(3, "firstSentenceTags");
2193 printCloseTag(2, "entry");
2197 printCloseTag(1, "category");
2200 printCloseTag(0, "alphaindex");
2205 private static class UsageType
2207 public static final UsageType CLASS_DERIVED_FROM
= new UsageType("class-derived-from");
2208 public static final UsageType FIELD_OF_TYPE
= new UsageType("field-of-type");
2209 public static final UsageType METHOD_WITH_RETURN_TYPE
= new UsageType("method-with-return-type");
2210 public static final UsageType METHOD_WITH_PARAMETER_TYPE
= new UsageType("method-with-parameter-type");
2211 public static final UsageType METHOD_WITH_THROWN_TYPE
= new UsageType("method-with-thrown-type");
2212 public static final UsageType CONSTRUCTOR_WITH_PARAMETER_TYPE
= new UsageType("constructor-with-parameter-type");
2213 public static final UsageType CONSTRUCTOR_WITH_THROWN_TYPE
= new UsageType("constructor-with-thrown-type");
2216 private UsageType(String id
)
2221 public String
toString() {
2222 return "UsageType{id=" + id
+ "}";
2225 public String
getId() {
2231 * ClassDoc -> (PackageDoc -> (UsageType -> (Set of Doc)))
2233 private Map usedClassToPackagesMap
= new HashMap();
2235 private void addUsedBy(ClassDoc usedClass
, UsageType usageType
, Doc user
, PackageDoc userPackage
)
2237 Map packageToUsageTypeMap
= (Map
)usedClassToPackagesMap
.get(usedClass
);
2238 if (null == packageToUsageTypeMap
) {
2239 packageToUsageTypeMap
= new HashMap();
2240 usedClassToPackagesMap
.put(usedClass
, packageToUsageTypeMap
);
2243 Map usageTypeToUsersMap
= (Map
)packageToUsageTypeMap
.get(userPackage
);
2244 if (null == usageTypeToUsersMap
) {
2245 usageTypeToUsersMap
= new HashMap();
2246 packageToUsageTypeMap
.put(userPackage
, usageTypeToUsersMap
);
2249 Set userSet
= (Set
)usageTypeToUsersMap
.get(usageType
);
2250 if (null == userSet
) {
2251 userSet
= new TreeSet(); // FIXME: we need the collator from Main here
2252 usageTypeToUsersMap
.put(usageType
, userSet
);
2258 * Create the cross reference database.
2260 private void collectUsage() {
2262 ClassDoc
[] classes
= rootDoc
.classes();
2263 for (int i
= 0, ilim
= classes
.length
; i
< ilim
; ++ i
) {
2264 ClassDoc clazz
= classes
[i
];
2266 // classes derived from
2267 for (ClassDoc superclass
= clazz
.superclass(); superclass
!= null;
2268 superclass
= superclass
.superclass()) {
2269 addUsedBy(superclass
, UsageType
.CLASS_DERIVED_FROM
, clazz
, clazz
.containingPackage());
2272 FieldDoc
[] fields
= clazz
.fields();
2273 for (int j
= 0, jlim
= fields
.length
; j
< jlim
; ++ j
) {
2274 FieldDoc field
= fields
[j
];
2277 ClassDoc fieldType
= field
.type().asClassDoc();
2278 if (null != fieldType
) {
2279 addUsedBy(fieldType
, UsageType
.FIELD_OF_TYPE
,
2280 field
, clazz
.containingPackage());
2284 MethodDoc
[] methods
= clazz
.methods();
2285 for (int j
= 0, jlim
= methods
.length
; j
< jlim
; ++ j
) {
2286 MethodDoc method
= methods
[j
];
2288 // methods with return type
2290 ClassDoc returnType
= method
.returnType().asClassDoc();
2291 if (null != returnType
) {
2292 addUsedBy(returnType
, UsageType
.METHOD_WITH_RETURN_TYPE
,
2293 method
, clazz
.containingPackage());
2295 Parameter
[] parameters
= method
.parameters();
2296 for (int k
=0; k
<parameters
.length
; ++k
) {
2298 // methods with parameter type
2300 Parameter parameter
= parameters
[k
];
2301 ClassDoc parameterType
= parameter
.type().asClassDoc();
2302 if (null != parameterType
) {
2303 addUsedBy(parameterType
, UsageType
.METHOD_WITH_PARAMETER_TYPE
,
2304 method
, clazz
.containingPackage());
2308 // methods which throw
2310 ClassDoc
[] thrownExceptions
= method
.thrownExceptions();
2311 for (int k
= 0, klim
= thrownExceptions
.length
; k
< klim
; ++ k
) {
2312 ClassDoc thrownException
= thrownExceptions
[k
];
2313 addUsedBy(thrownException
, UsageType
.METHOD_WITH_THROWN_TYPE
,
2314 method
, clazz
.containingPackage());
2318 ConstructorDoc
[] constructors
= clazz
.constructors();
2319 for (int j
= 0, jlim
= constructors
.length
; j
< jlim
; ++ j
) {
2321 ConstructorDoc constructor
= constructors
[j
];
2323 Parameter
[] parameters
= constructor
.parameters();
2324 for (int k
= 0, klim
= parameters
.length
; k
< klim
; ++ k
) {
2326 // constructors with parameter type
2328 Parameter parameter
= parameters
[k
];
2329 ClassDoc parameterType
= parameter
.type().asClassDoc();
2330 if (null != parameterType
) {
2331 addUsedBy(parameterType
, UsageType
.CONSTRUCTOR_WITH_PARAMETER_TYPE
,
2332 constructor
, clazz
.containingPackage());
2336 // constructors which throw
2338 ClassDoc
[] thrownExceptions
= constructor
.thrownExceptions();
2339 for (int k
= 0, klim
= thrownExceptions
.length
; k
< klim
; ++ k
) {
2340 ClassDoc thrownException
= thrownExceptions
[k
];
2341 addUsedBy(thrownException
, UsageType
.CONSTRUCTOR_WITH_THROWN_TYPE
,
2342 constructor
, clazz
.containingPackage());
2348 private void outputUsage(ClassDoc clazz
, int level
) {
2350 Map packageToUsageTypeMap
= (Map
)usedClassToPackagesMap
.get(clazz
);
2351 if (null != packageToUsageTypeMap
) {
2352 printOpenTag(level
, "references");
2354 Iterator packagesIterator
= packageToUsageTypeMap
.keySet().iterator();
2356 while (packagesIterator
.hasNext()) {
2357 PackageDoc packageDoc
= (PackageDoc
)packagesIterator
.next();
2358 printOpenTag(level
+ 1, "referencing-package name=\"" + packageDoc
.name() + "\"");
2359 Map usageTypeToUsersMap
= (Map
)packageToUsageTypeMap
.get(packageDoc
);
2360 Iterator usageTypeIterator
= usageTypeToUsersMap
.keySet().iterator();
2361 while (usageTypeIterator
.hasNext()) {
2362 UsageType usageType
= (UsageType
)usageTypeIterator
.next();
2363 printOpenTag(level
+ 2, "usage-type id=\"" + usageType
.getId() + "\"");
2364 Set users
= (Set
)usageTypeToUsersMap
.get(usageType
);
2365 Iterator userIterator
= users
.iterator();
2366 while (userIterator
.hasNext()) {
2367 Doc user
= (Doc
)userIterator
.next();
2368 if (user
instanceof ClassDoc
) {
2369 printAtomTag(level
+ 3, "user"
2370 + " class=\"" + ((ClassDoc
)user
).name() + "\"");
2372 else if (user
instanceof FieldDoc
) {
2373 FieldDoc fieldDoc
= (FieldDoc
)user
;
2374 printAtomTag(level
+ 3, "user"
2375 + " class=\"" + fieldDoc
.containingClass().name() + "\""
2376 + " field=\"" + fieldDoc
.name() + "\"");
2378 else if (user
instanceof MethodDoc
) {
2379 MethodDoc methodDoc
= (MethodDoc
)user
;
2380 printAtomTag(level
+ 3, "user"
2381 + " class=\"" + methodDoc
.containingClass().name() + "\""
2382 + " method=\"" + methodDoc
.name() + "\""
2383 + " signature=\"" + methodDoc
.signature() + "\""
2384 + " flatSignature=\"" + methodDoc
.flatSignature() + "\"");
2386 else if (user
instanceof ConstructorDoc
) {
2387 ConstructorDoc constructorDoc
= (ConstructorDoc
)user
;
2388 printAtomTag(level
+ 3, "user"
2389 + " class=\"" + constructorDoc
.containingClass().name() + "\""
2390 + " signature=\"" + constructorDoc
.signature() + "\""
2391 + " flatSignature=\"" + constructorDoc
.flatSignature() + "\"");
2394 printCloseTag(level
+2, "usage-type");
2396 printCloseTag(level
+ 1, "referencing-package");
2399 printCloseTag(level
, "references");
2403 private boolean processGroupOption(String groupName
, String colonSeparatedPackageList
)
2406 PackageMatcher packageMatcher
= new PackageMatcher();
2408 StringTokenizer tokenizer
= new StringTokenizer(colonSeparatedPackageList
, ":");
2409 while (tokenizer
.hasMoreTokens()) {
2410 String packageWildcard
= tokenizer
.nextToken();
2411 packageMatcher
.addWildcard(packageWildcard
);
2414 SortedSet groupPackages
= packageMatcher
.filter(rootDoc
.specifiedPackages());
2416 packageGroups
.add(new PackageGroup(groupName
, groupPackages
));
2420 catch (InvalidPackageWildcardException e
) {
2425 private void registerTaglet(Taglet taglet
)
2427 tagletMap
.put(taglet
.getName(), taglet
);
2430 private boolean isVerbose()