libjava/ChangeLog:
[official-gcc.git] / libjava / classpath / tools / gnu / classpath / tools / doclets / xmldoclet / Driver.java
blob6f90338b2af2b865c066cabb7f6382642806e3a4
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)
9 any later version.
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
19 02111-1307 USA. */
21 package gnu.classpath.tools.doclets.xmldoclet;
23 import com.sun.javadoc.*;
24 import java.io.*;
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;
44 import java.util.Map;
45 import java.util.HashMap;
46 import java.util.Properties;
47 import java.util.Set;
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;
74 /**
75 * A Doclet which retrieves all information presented by the Doclet
76 * API, dumping it to stdout in XML format.
78 * @author Julian Scheid
80 public class Driver {
82 public static final String XMLDOCLET_VERSION = "0.6.1";
84 /**
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
185 * with -workpath.
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.
204 * Set of String.
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
244 * the command line.
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);
279 _rootDoc = null;
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) {
344 println();
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) {
367 println();
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) {
375 println();
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) {
394 println();
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) {
424 println();
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);
450 if (false) {
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;
463 println();
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");
554 currentClass = null;
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);
564 ++ level;
566 outputType(level, "heritage", classDoc, false);
567 return level;
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;
583 if (doc.isClass()) {
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;
601 if (doc.isError()) {
602 printAtomTag(level, "isError");
604 if (doc.isException()) {
605 printAtomTag(level, "isException");
607 if (doc.isField()) {
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]);
626 else {
627 outputType(level, "implemented-by", classes[i]);
629 break;
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());
678 String access;
679 if (programElementDoc.isPublic())
680 access="public";
681 else if (programElementDoc.isProtected())
682 access="protected";
683 else if (programElementDoc.isPrivate())
684 access="private";
685 else if (programElementDoc.isPackagePrivate())
686 access="package";
687 else
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());
714 else {
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());
722 sb.append(' ');
724 sb.append(currentClass.qualifiedName());
725 sb.append('.');
726 sb.append(currentExecMember.name());
727 sb.append('(');
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());
732 sb.append(' ');
733 sb.append(params[j].name());
734 if (j != params.length-1)
735 sb.append(", ");
737 sb.append(')');
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);
750 if (fixHTML) {
751 print(htmlRepairer.getWellformedHTML(tag.text()));
753 else {
754 print("<![CDATA["+cdata(tag.text())+"]]>");
756 //printCloseTag(0 /* don't introduce additional whitespace */, "text");
758 else {
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());
827 else {
828 String tagletString = taglet.toString(tagletTags);
829 if (null != tagletString) {
830 printOpenTag(0, "tag name=\"" + tagName + "\" taglet-generated=\"true\"");
831 if (fixHTML) {
832 print(htmlRepairer.getWellformedHTML(tagletString));
833 print(htmlRepairer.terminateText());
835 else {
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;
852 _rootDoc = null;
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);
872 try {
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"),
881 targetDirectory);
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)) {
898 fixHTML = false;
899 printError("-nofixhtml currently not supported.");
900 return false;
902 else if ("-compress".equals(optionTag)) {
903 compress = true;
905 else if ("-nohtmlwarn".equals(optionTag)) {
906 noHTMLWarn = true;
908 else if ("-noemailwarn".equals(optionTag)) {
909 noEmailWarn = true;
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])),
916 targetDirectory));
918 else if ("-genhtml".equals(optionTag)) {
919 htmlTargetContext.setTargetDirectory(targetDirectory);
920 targets.add(targetContext = htmlTargetContext);
921 xmlOnly = false;
923 else if ("-geninfo".equals(optionTag)) {
924 targetContext
925 = new TargetContext(DocTranslet.fromClasspath("/doctranslets/info/gengj.xsl"),
926 targetDirectory);
927 targets.add(targetContext);
928 if (!fixHTML) {
929 printNotice("NOTE: -geninfo implies -fixhtml.");
930 fixHTML = true;
932 xmlOnly = false;
934 else if ("-gendocbook".equals(optionTag)) {
935 targetContext = new TargetContext(DocTranslet.fromClasspath("/doctranslets/docbook/gengj.xsl"),
936 targetDirectory);
937 targets.add(targetContext);
938 if (!fixHTML) {
939 printNotice("NOTE: -gendocbook implies -fixhtml.");
940 fixHTML = true;
943 else if ("-genpdf".equals(optionTag)) {
944 targetContext
945 = new TargetContext(DocTranslet.fromClasspath("/doctranslets/docbook/gengj.xsl"),
946 targetDirectory);
947 /** "gnu.classpath.tools.doclets.xmldoclet.DocBookPostprocessor") **/
948 targets.add(targetContext);
949 if (!fixHTML) {
950 printNotice("NOTE: -genpdf implies -fixhtml.");
951 fixHTML = true;
954 else if ("-xmlonly".equals(optionTag)) {
955 xmlOnly = true;
957 else if ("-bottomnote".equals(optionTag)) {
959 FileReader reader = new FileReader(option[1]);
960 StringWriter writer = new StringWriter();
961 char[] buf = new char[256];
962 int nread;
963 while ((nread = reader.read(buf)) >= 0) {
964 writer.write(buf, 0, nread);
966 writer.flush();
967 bottomNote = writer.toString();
968 writer.close();
969 reader.close();
971 else if ("-title".equals(optionTag)) {
973 title = option[1];
975 else if ("-workpath".equals(optionTag)) {
977 workingPath = option[1];
979 else if ("-tagletpath".equals(optionTag)) {
981 if (null == tagletPath) {
982 tagletPath = option[1];
984 else {
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");
997 try {
998 Class tagletClass;
999 try {
1000 tagletClass
1001 = new FileSystemClassLoader(useTagletPath).loadClass(option[1]);
1003 catch (ClassNotFoundException e) {
1004 // If not found on specified tagletpath, try default classloader
1005 tagletClass
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..");
1020 else {
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) {
1049 return false;
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);
1078 else {
1079 printError("Invalid value for option '-authortag-email'. Allowed values are:"
1080 + " no-replace, mailto-name, name-mailto-address, name-mangled-address.");
1081 return false;
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]);
1150 return false;
1153 else if ("-tag".equals(optionTag)) {
1154 String tagSpec = option[1];
1155 boolean validTagSpec = false;
1156 int ndx1 = tagSpec.indexOf(':');
1157 if (ndx1 < 0) {
1158 Taglet taglet = (Taglet)tagletMap.get(tagSpec);
1159 if (null == taglet) {
1160 printError("There is no standard tag '" + tagSpec + "'.");
1162 else {
1163 if (mentionedTags.contains(taglet)) {
1164 printError("Tag '" + tagSpec + "' has been added or moved before.");
1166 else {
1167 mentionedTags.add(taglet);
1169 // re-append taglet
1170 tagletMap.remove(tagSpec);
1171 tagletMap.put(tagSpec, taglet);
1175 else {
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;
1186 else {
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;
1199 tag_option_loop:
1200 for (int n=ndx1+1; n<ndx2; ++n) {
1201 switch (tagSpec.charAt(n)) {
1202 case 'X':
1203 tagDisabled = true;
1204 break;
1205 case 'a':
1206 tagScopeOverview = true;
1207 tagScopePackages = true;
1208 tagScopeTypes = true;
1209 tagScopeConstructors = true;
1210 tagScopeMethods = true;
1211 tagScopeFields = true;
1212 break;
1213 case 'o':
1214 tagScopeOverview = true;
1215 break;
1216 case 'p':
1217 tagScopePackages = true;
1218 break;
1219 case 't':
1220 tagScopeTypes = true;
1221 break;
1222 case 'c':
1223 tagScopeConstructors = true;
1224 break;
1225 case 'm':
1226 tagScopeMethods = true;
1227 break;
1228 case 'f':
1229 tagScopeFields = true;
1230 break;
1231 default:
1232 validTagSpec = false;
1233 break tag_option_loop;
1237 if (validTagSpec) {
1238 GenericTaglet taglet
1239 = new GenericTaglet(tagName,
1240 tagHead,
1241 tagScopeOverview,
1242 tagScopePackages,
1243 tagScopeTypes,
1244 tagScopeConstructors,
1245 tagScopeMethods,
1246 tagScopeFields);
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.");
1272 return false;
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
1285 // output formats.
1287 for (Iterator it = targets.iterator(); it.hasNext(); ) {
1288 TargetContext t = (TargetContext)it.next();
1289 t.setTargetDirectory(targetDirectory);
1292 // Create temporary directory if necessary
1294 if (xmlOnly) {
1296 xmlTargetDirectory = targetDirectory;
1298 else {
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"));
1306 return false;
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"));
1313 return false;
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 + "\"");
1327 return false;
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,
1382 false);
1384 collectUsage();
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\">");
1398 println();
1399 printOpenTag(0, "rootdoc xmlns=\"http://www.w3.org/TR/REC-html40\" xmlns:gjdoc=\"http://www.gnu.org/software/cp-tools/gjdocxml\"");
1401 println();
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");
1418 print(bottomNote);
1419 printCloseTag(1, "bottomnote");
1422 if (null != title) {
1423 printOpenTag(1, "title");
1424 println(2, 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
1441 println();
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
1452 println();
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
1462 // command line
1464 println();
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.");
1475 else {
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
1491 println();
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);
1498 packages = null;
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
1506 println();
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);
1513 sumclasses = null;
1515 // Output closing tag, finish output stream
1517 println();
1518 printCloseTag(0, "rootdoc");
1520 closeTargetFile();
1522 createIndexByName();
1526 // Output information on all classes for which documentation
1527 // has been made available via the Doclet API
1529 println();
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];
1536 if (isVerbose()) {
1537 printNotice("Writing XML information for "+c.qualifiedName()+"...");
1539 else {
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\">");
1552 outputClassDoc(c);
1554 closeTargetFile();
1556 classes = null;
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[] {
1565 "gjdoc.dtd",
1566 "gjdoc-alphaindex.dtd",
1567 "dbcentx.mod",
1568 "ent/iso-amsa.ent",
1569 "ent/iso-amsb.ent",
1570 "ent/iso-amsc.ent",
1571 "ent/iso-amsn.ent",
1572 "ent/iso-amso.ent",
1573 "ent/iso-amsr.ent",
1574 "ent/iso-box.ent",
1575 "ent/iso-cyr1.ent",
1576 "ent/iso-cyr2.ent",
1577 "ent/iso-dia.ent",
1578 "ent/iso-grk1.ent",
1579 "ent/iso-grk2.ent",
1580 "ent/iso-grk3.ent",
1581 "ent/iso-grk4.ent",
1582 "ent/iso-lat1.ent",
1583 "ent/iso-lat2.ent",
1584 "ent/iso-num.ent",
1585 "ent/iso-pub.ent",
1586 "ent/iso-tech.ent",
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]));
1599 else {
1600 printError("Cannot create temporary directories for DTD data at " + tempDtdDirectory);
1601 return false;
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;
1624 System.gc();
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(),
1643 rootDoc);
1646 // Done
1648 targets = null;
1650 System.gc();
1651 Runtime.getRuntime().runFinalization();
1653 return true;
1655 catch (Exception e) {
1657 // Something went wrong. Report to stderr and pass error to
1658 // Javadoc Reporter
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();
1672 return false;
1674 finally {
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;
1709 else {
1711 success = file.delete() && success;
1715 return directory.delete() && success;
1719 * Prints a string to stdout and appends a newline. Convenience
1720 * method.
1722 protected void println(String str) {
1723 out.println(str);
1727 * Prints a string to stdout without appending a newline.
1728 * Convenience method.
1730 protected void print(String str) {
1731 out.print(str);
1735 * In standard mode, prints an empty line to stdout.
1736 * In thight mode, nothing happens.
1737 * Convenience method.
1739 protected void println() {
1740 if (!compress) {
1741 out.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) {
1750 if (compress) {
1751 out.print(msg);
1753 else {
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)+">");
1793 else {
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)+">");
1813 else {
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;
1863 else return -1;
1866 public static boolean validOptions(String[][] options) {
1867 return true;
1872 * Workaround for non well-formed comments: fix tag contents
1873 * by replacing <code>&lt;</code> with <code>&amp;lt;</code>,
1874 * <code>&gt;</code> with <code>&amp;gt;</code> and
1875 * <code>&amp;</code> with <code>&amp;amp;</code>.
1877 * @param tagContent String to process
1879 * @return given String with all special characters replaced by
1880 * HTML entities.
1882 private static String replaceCharsInTag(String tagContent) {
1883 return
1884 replaceString(
1885 replaceString(
1886 replaceString(
1887 tagContent,
1888 "<", "&lt;"
1890 ">", "&gt;"
1892 "&", "&amp;"
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);
1906 if (ndx<0)
1907 return haystack;
1908 else
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() {
1921 out.flush();
1922 out.close();
1925 private String cdata(String str) {
1927 if (null==str) {
1928 return 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)) {
1935 rc.append(c);
1937 else {
1938 printWarning("Invalid Unicode character 0x"+Integer.toString(c, 16)+" in javadoc markup has been stripped.");
1939 } // end of else
1942 return rc.toString();
1945 static void copyResourceToFile(String resourceName, File target) throws IOException {
1947 InputStream in = Driver.class.getResourceAsStream(resourceName);
1949 if (null != in) {
1951 FileOutputStream out = new FileOutputStream(target);
1952 int size;
1953 byte[] buffer = new byte[512];
1954 while ((size = in.read(buffer)) >= 0) {
1955 out.write(buffer, 0, size);
1957 out.close();
1959 else {
1961 throw new IOException("Can't find resource named "+resourceName);
1965 private void printError(String error) {
1966 if (null != rootDoc) {
1967 rootDoc.printError(error);
1969 else {
1970 System.err.println("ERROR: "+error);
1974 private void printWarning(String warning) {
1975 if (null != rootDoc) {
1976 rootDoc.printWarning(warning);
1978 else {
1979 System.err.println("WARNING: "+warning);
1983 private void printNotice(String notice) {
1984 if (null != rootDoc) {
1985 rootDoc.printNotice(notice);
1987 else {
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,
2015 boolean recursive,
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);
2031 else {
2032 throw new IOException("Cannot create directory " + targetSubDir);
2036 else {
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);
2050 int nread;
2051 byte[] buf = new byte[512];
2052 while ((nread = in.read(buf)) >= 0) {
2053 out.write(buf, 0, nread);
2055 in.close();
2056 out.close();
2059 private void createIndexByName() throws IOException {
2060 // Create index
2062 // Collect index
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);
2086 else {
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) {
2101 if (k > 0) {
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\">");
2119 println();
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) {
2133 if (categoryOpen) {
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) {
2184 Tag tag = tags[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");
2196 if (categoryOpen) {
2197 printCloseTag(1, "category");
2200 printCloseTag(0, "alphaindex");
2202 closeTargetFile();
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");
2214 private String id;
2216 private UsageType(String id)
2218 this.id = id;
2221 public String toString() {
2222 return "UsageType{id=" + id + "}";
2225 public String getId() {
2226 return id;
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);
2254 userSet.add(user);
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];
2276 // fields of type
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)
2405 try {
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));
2418 return true;
2420 catch (InvalidPackageWildcardException e) {
2421 return false;
2425 private void registerTaglet(Taglet taglet)
2427 tagletMap.put(taglet.getName(), taglet);
2430 private boolean isVerbose()
2432 return false;