1 /* gnu.classpath.tools.doclets.AbstractDoclet
2 Copyright (C) 2004 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
;
23 import com
.sun
.javadoc
.ClassDoc
;
24 import com
.sun
.javadoc
.ConstructorDoc
;
25 import com
.sun
.javadoc
.Doc
;
26 import com
.sun
.javadoc
.Doclet
;
27 import com
.sun
.javadoc
.ExecutableMemberDoc
;
28 import com
.sun
.javadoc
.FieldDoc
;
29 import com
.sun
.javadoc
.MethodDoc
;
30 import com
.sun
.javadoc
.PackageDoc
;
31 import com
.sun
.javadoc
.Parameter
;
32 import com
.sun
.javadoc
.RootDoc
;
33 import com
.sun
.javadoc
.Tag
;
34 import com
.sun
.javadoc
.Type
;
36 import com
.sun
.tools
.doclets
.Taglet
;
38 import gnu
.classpath
.tools
.taglets
.GnuExtendedTaglet
;
39 import gnu
.classpath
.tools
.taglets
.AuthorTaglet
;
40 import gnu
.classpath
.tools
.taglets
.CodeTaglet
;
41 import gnu
.classpath
.tools
.taglets
.DeprecatedTaglet
;
42 import gnu
.classpath
.tools
.taglets
.GenericTaglet
;
43 import gnu
.classpath
.tools
.taglets
.SinceTaglet
;
44 import gnu
.classpath
.tools
.taglets
.ValueTaglet
;
45 import gnu
.classpath
.tools
.taglets
.VersionTaglet
;
46 import gnu
.classpath
.tools
.taglets
.TagletContext
;
48 import gnu
.classpath
.tools
.IOToolkit
;
49 import gnu
.classpath
.tools
.FileSystemClassLoader
;
52 import java
.io
.IOException
;
54 import java
.lang
.reflect
.Method
;
55 import java
.lang
.reflect
.Modifier
;
56 import java
.lang
.reflect
.InvocationTargetException
;
58 import java
.text
.MessageFormat
;
60 import java
.util
.ArrayList
;
61 import java
.util
.Arrays
;
62 import java
.util
.Collections
;
63 import java
.util
.Comparator
;
64 import java
.util
.HashMap
;
65 import java
.util
.Iterator
;
66 import java
.util
.LinkedHashMap
;
67 import java
.util
.LinkedHashSet
;
68 import java
.util
.LinkedList
;
69 import java
.util
.List
;
70 import java
.util
.Locale
;
72 import java
.util
.ResourceBundle
;
74 import java
.util
.SortedSet
;
75 import java
.util
.StringTokenizer
;
76 import java
.util
.TreeMap
;
77 import java
.util
.TreeSet
;
80 * An abstract Doclet implementation with helpers for common tasks
81 * performed by Doclets.
83 public abstract class AbstractDoclet
86 * Mapping from tag type to Taglet for user Taglets specified on
89 protected Map tagletMap
= new LinkedHashMap();
92 * Stores the package groups specified in the user
93 * options. Contains objects of type PackageGroup.
95 private List packageGroups
= new LinkedList();
98 * The current classpath for loading taglet classes.
100 private String tagletPath
;
103 * Keeps track of the tags mentioned by the user during option
104 * processiong so that an error can be emitted if a tag is
105 * mentioned more than once.
107 private List mentionedTags
= new LinkedList();
109 public static int optionLength(String option
) {
110 return instance
.getOptionLength(option
);
113 public static boolean validOptions(String
[][] options
) {
117 private static AbstractDoclet instance
;
119 protected static void setInstance(AbstractDoclet instance
)
121 AbstractDoclet
.instance
= instance
;
124 protected abstract void run()
125 throws DocletConfigurationException
, IOException
;
127 public static boolean start(RootDoc rootDoc
)
131 instance
.startInstance(rootDoc
);
134 catch (DocletConfigurationException e
) {
135 instance
.printError(e
.getMessage());
138 catch (Exception e
) {
144 protected RootDoc
getRootDoc()
149 private RootDoc rootDoc
;
151 protected abstract InlineTagRenderer
getInlineTagRenderer();
153 private void startInstance(RootDoc rootDoc
)
154 throws DocletConfigurationException
, IOException
156 this.rootDoc
= rootDoc
;
158 // Set the default Taglet order
160 registerTaglet(new VersionTaglet());
161 registerTaglet(new AuthorTaglet());
162 registerTaglet(new SinceTaglet(getInlineTagRenderer()));
163 registerTaglet(new StandardTaglet("serial"));
164 registerTaglet(new StandardTaglet("deprecated"));
165 registerTaglet(new StandardTaglet("see"));
166 registerTaglet(new StandardTaglet("param"));
167 registerTaglet(new StandardTaglet("return"));
169 registerTaglet(new ValueTaglet());
170 registerTaglet(new CodeTaglet());
172 // Process command line options
174 for (int i
=0, ilim
=rootDoc
.options().length
; i
<ilim
; ++i
) {
176 String
[] optionArr
= rootDoc
.options()[i
];
177 String _optionTag
= optionArr
[0];
179 DocletOption option
= (DocletOption
)nameToOptionMap
.get(_optionTag
.toLowerCase());
181 if (null != option
) {
182 option
.set(optionArr
);
186 // Enable/disable standard taglets based on user input
188 AuthorTaglet
.setTagletEnabled(optionAuthor
.getValue());
189 VersionTaglet
.setTagletEnabled(optionVersion
.getValue());
190 SinceTaglet
.setTagletEnabled(!optionNoSince
.getValue());
191 DeprecatedTaglet
.setTagletEnabled(!optionNoDeprecated
.getValue());
193 if (!getTargetDirectory().exists()) {
194 if (!getTargetDirectory().mkdirs()) {
195 throw new DocletConfigurationException("Cannot create target directory "
196 + getTargetDirectory());
203 public File
getTargetDirectory()
205 return optionTargetDirectory
.getValue();
208 private DocletOptionFile optionTargetDirectory
=
209 new DocletOptionFile("-d",
210 new File(System
.getProperty("user.dir")));
212 private DocletOptionFlag optionNoEmailWarn
=
213 new DocletOptionFlag("-noemailwarn");
215 private DocletOptionFlag optionAuthor
=
216 new DocletOptionFlag("-author");
218 private DocletOptionFlag optionVersion
=
219 new DocletOptionFlag("-version");
221 private DocletOptionFlag optionNoSince
=
222 new DocletOptionFlag("-nosince");
224 private DocletOptionFlag optionNoDeprecated
=
225 new DocletOptionFlag("-nodeprecated");
227 private DocletOptionGroup optionGroup
=
228 new DocletOptionGroup("-group");
230 private DocletOptionPackageWildcard optionNoQualifier
=
231 new DocletOptionPackageWildcard("-noqualifier", true);
233 private DocletOptionFlag optionDocFilesSubDirs
=
234 new DocletOptionFlag("-docfilessubdirs");
236 private DocletOptionColonSeparated optionExcludeDocFilesSubDir
=
237 new DocletOptionColonSeparated("-excludedocfilessubdir");
239 private DocletOptionTagletPath optionTagletPath
=
240 new DocletOptionTagletPath("-tagletpath");
242 private DocletOptionTag optionTaglet
=
243 new DocletOptionTag("-taglet");
245 private DocletOptionTag optionTag
=
246 new DocletOptionTag("-tag");
248 private class DocletOptionTaglet
251 DocletOptionTaglet(String optionName
)
256 public int getLength()
261 public boolean set(String
[] optionArr
)
264 boolean tagletLoaded
= false;
266 String useTagletPath
= AbstractDoclet
.this.tagletPath
;
267 if (null == useTagletPath
) {
268 useTagletPath
= System
.getProperty("java.class.path");
275 = new FileSystemClassLoader(useTagletPath
).loadClass(optionArr
[1]);
277 catch (ClassNotFoundException e
) {
278 // If not found on specified tagletpath, try default classloader
280 = Class
.forName(optionArr
[1]);
282 Method registerTagletMethod
283 = tagletClass
.getDeclaredMethod("register", new Class
[] { java
.util
.Map
.class });
285 if (!registerTagletMethod
.getReturnType().equals(Void
.TYPE
)) {
286 printError("Taglet class '" + optionArr
[1] + "' found, but register method doesn't return void.");
288 else if (registerTagletMethod
.getExceptionTypes().length
> 0) {
289 printError("Taglet class '" + optionArr
[1] + "' found, but register method contains throws clause.");
291 else if ((registerTagletMethod
.getModifiers() & (Modifier
.STATIC
| Modifier
.PUBLIC
| Modifier
.ABSTRACT
)) != (Modifier
.STATIC
| Modifier
.PUBLIC
)) {
292 printError("Taglet class '" + optionArr
[1] + "' found, but register method isn't public static, or is abstract..");
295 Map tempMap
= new HashMap();
296 registerTagletMethod
.invoke(null, new Object
[] { tempMap
});
298 String name
= (String
)tempMap
.keySet().iterator().next();
299 Taglet taglet
= (Taglet
)tempMap
.get(name
);
300 tagletMap
.put(name
, taglet
);
301 mentionedTags
.add(taglet
);
304 catch (NoSuchMethodException e
) {
305 printError("Taglet class '" + optionArr
[1] + "' found, but doesn't contain the register method.");
307 catch (SecurityException e
) {
308 printError("Taglet class '" + optionArr
[1] + "' cannot be loaded: " + e
.getMessage());
310 catch (InvocationTargetException e
) {
311 printError("Taglet class '" + optionArr
[1] + "' found, but register method throws exception: " + e
.toString());
313 catch (IllegalAccessException e
) {
314 printError("Taglet class '" + optionArr
[1] + "' found, but there was a problem when accessing the register method: " + e
.toString());
316 catch (IllegalArgumentException e
) {
317 printError("Taglet class '" + optionArr
[1] + "' found, but there was a problem when accessing the register method: " + e
.toString());
319 catch (ClassNotFoundException e
) {
320 printError("Taglet class '" + optionArr
[1] + "' cannot be found.");
326 private class DocletOptionGroup
329 DocletOptionGroup(String optionName
)
334 public int getLength()
339 public boolean set(String
[] optionArr
)
342 PackageMatcher packageMatcher
= new PackageMatcher();
344 StringTokenizer tokenizer
= new StringTokenizer(optionArr
[2], ":");
345 while (tokenizer
.hasMoreTokens()) {
346 String packageWildcard
= tokenizer
.nextToken();
347 packageMatcher
.addWildcard(packageWildcard
);
350 SortedSet groupPackages
= packageMatcher
.filter(rootDoc
.specifiedPackages());
352 packageGroups
.add(new PackageGroup(optionArr
[1], groupPackages
));
356 catch (InvalidPackageWildcardException e
) {
363 private class DocletOptionTagletPath
366 DocletOptionTagletPath(String optionName
)
371 public int getLength()
376 public boolean set(String
[] optionArr
)
378 AbstractDoclet
.this.tagletPath
= optionArr
[1];
383 private class DocletOptionTag
386 DocletOptionTag(String optionName
)
391 public int getLength()
396 public boolean set(String
[] optionArr
)
398 String tagSpec
= optionArr
[1];
399 boolean validTagSpec
= false;
400 int ndx1
= tagSpec
.indexOf(':');
402 Taglet taglet
= (Taglet
)tagletMap
.get(tagSpec
);
403 if (null == taglet
) {
404 printError("There is no standard tag '" + tagSpec
+ "'.");
407 if (mentionedTags
.contains(taglet
)) {
408 printError("Tag '" + tagSpec
+ "' has been added or moved before.");
411 mentionedTags
.add(taglet
);
414 tagletMap
.remove(tagSpec
);
415 tagletMap
.put(tagSpec
, taglet
);
420 int ndx2
= tagSpec
.indexOf(':', ndx1
+ 1);
421 if (ndx2
> ndx1
&& ndx2
< tagSpec
.length() - 1) {
422 String tagName
= tagSpec
.substring(0, ndx1
);
423 String tagHead
= null;
424 if (tagSpec
.charAt(ndx2
+ 1) == '\"') {
425 if (tagSpec
.charAt(tagSpec
.length() - 1) == '\"') {
426 tagHead
= tagSpec
.substring(ndx2
+ 2, tagSpec
.length() - 1);
431 tagHead
= tagSpec
.substring(ndx2
+ 1);
435 boolean tagScopeOverview
= false;
436 boolean tagScopePackages
= false;
437 boolean tagScopeTypes
= false;
438 boolean tagScopeConstructors
= false;
439 boolean tagScopeMethods
= false;
440 boolean tagScopeFields
= false;
441 boolean tagDisabled
= false;
444 for (int n
=ndx1
+1; n
<ndx2
; ++n
) {
445 switch (tagSpec
.charAt(n
)) {
450 tagScopeOverview
= true;
451 tagScopePackages
= true;
452 tagScopeTypes
= true;
453 tagScopeConstructors
= true;
454 tagScopeMethods
= true;
455 tagScopeFields
= true;
458 tagScopeOverview
= true;
461 tagScopePackages
= true;
464 tagScopeTypes
= true;
467 tagScopeConstructors
= true;
470 tagScopeMethods
= true;
473 tagScopeFields
= true;
476 validTagSpec
= false;
477 break tag_option_loop
;
483 = new GenericTaglet(tagName
,
488 tagScopeConstructors
,
491 taglet
.setTagletEnabled(!tagDisabled
);
492 taglet
.register(tagletMap
);
493 mentionedTags
.add(taglet
);
498 printError("Value for option -tag must be in format \"<tagname>:Xaoptcmf:<taghead>\".");
504 private DocletOption
[] commonOptions
=
506 optionTargetDirectory
,
512 optionDocFilesSubDirs
,
513 optionExcludeDocFilesSubDir
,
519 private void registerOptions()
521 if (!optionsRegistered
) {
522 for (int i
=0; i
<commonOptions
.length
; ++i
) {
523 DocletOption option
= commonOptions
[i
];
524 registerOption(option
);
526 DocletOption
[] docletOptions
= getOptions();
527 for (int i
=0; i
<docletOptions
.length
; ++i
) {
528 DocletOption option
= docletOptions
[i
];
529 registerOption(option
);
531 optionsRegistered
= true;
535 protected abstract DocletOption
[] getOptions();
537 private boolean optionsRegistered
= false;
539 private void registerOption(DocletOption option
)
541 nameToOptionMap
.put(option
.getName(), option
);
544 private Map nameToOptionMap
= new HashMap();
546 private int getOptionLength(String optionName
)
549 DocletOption option
= (DocletOption
)nameToOptionMap
.get(optionName
.toLowerCase());
550 if (null != option
) {
551 return option
.getLength();
558 protected List
getKnownDirectSubclasses(ClassDoc classDoc
)
560 List result
= new LinkedList();
561 if (!"java.lang.Object".equals(classDoc
.qualifiedName())) {
562 ClassDoc
[] classes
= rootDoc
.classes();
563 for (int i
=0; i
<classes
.length
; ++i
) {
564 if (classDoc
== classes
[i
].superclass()) {
565 result
.add(classes
[i
]);
572 protected static class IndexKey
573 implements Comparable
576 private String lowerName
;
578 public IndexKey(String name
)
581 this.lowerName
= name
.toLowerCase();
584 public boolean equals(Object other
)
586 return this.lowerName
.equals(((IndexKey
)other
).lowerName
);
589 public int hashCode()
591 return lowerName
.hashCode();
594 public int compareTo(Object other
)
596 return lowerName
.compareTo(((IndexKey
)other
).lowerName
);
599 public String
getName()
605 private Map categorizedIndex
;
607 protected Map
getCategorizedIndex()
609 if (null == categorizedIndex
) {
610 categorizedIndex
= new LinkedHashMap();
612 Map indexMap
= getIndexByName();
613 LinkedList keys
= new LinkedList(); //indexMap.keySet().size());
614 keys
.addAll(indexMap
.keySet());
615 Collections
.sort(keys
);
616 Iterator it
= keys
.iterator(); //indexMap.keySet().iterator();
617 char previousCategoryLetter
= '\0';
618 Character keyLetter
= null;
619 while (it
.hasNext()) {
620 IndexKey key
= (IndexKey
)it
.next();
621 char firstChar
= Character
.toUpperCase(key
.getName().charAt(0));
622 if (firstChar
!= previousCategoryLetter
) {
623 keyLetter
= new Character(firstChar
);
624 previousCategoryLetter
= firstChar
;
625 categorizedIndex
.put(keyLetter
, new LinkedList());
627 List letterList
= (List
)categorizedIndex
.get(keyLetter
);
628 letterList
.add(indexMap
.get(key
));
632 return categorizedIndex
;
636 private Map indexByName
;
638 protected Map
getIndexByName()
640 if (null == indexByName
) {
645 indexByName
= new HashMap(); //TreeMap();
647 // Add packages to index
649 PackageDoc
[] packages
= rootDoc
.specifiedPackages();
650 for (int i
=0, ilim
=packages
.length
; i
<ilim
; ++i
) {
651 PackageDoc c
= packages
[i
];
652 if (c
.name().length() > 0) {
653 indexByName
.put(new IndexKey(c
.name()), c
);
657 // Add classes, fields and methods to index
659 ClassDoc
[] sumclasses
= rootDoc
.classes();
660 for (int i
=0, ilim
=sumclasses
.length
; i
<ilim
; ++i
) {
661 ClassDoc c
= sumclasses
[i
];
662 if (null == c
.containingClass()) {
663 indexByName
.put(new IndexKey(c
.name() + " " + c
.containingPackage().name()), c
);
666 indexByName
.put(new IndexKey(c
.name().substring(c
.containingClass().name().length() + 1)
667 + " " + c
.containingClass().name() + " " + c
.containingPackage().name()), c
);
669 FieldDoc
[] fields
= c
.fields();
670 for (int j
=0, jlim
=fields
.length
; j
<jlim
; ++j
) {
671 indexByName
.put(new IndexKey(fields
[j
].name() + " " + fields
[j
].containingClass().name() + " " + fields
[j
].containingPackage().name()), fields
[j
]);
673 MethodDoc
[] methods
= c
.methods();
674 for (int j
=0, jlim
=methods
.length
; j
<jlim
; ++j
) {
675 MethodDoc method
= methods
[j
];
676 indexByName
.put(new IndexKey(method
.name() + method
.signature() + " " + method
.containingClass().name() + " " + method
.containingPackage().name()), method
);
678 ConstructorDoc
[] constructors
= c
.constructors();
679 for (int j
=0, jlim
=constructors
.length
; j
<jlim
; ++j
) {
680 ConstructorDoc constructor
= constructors
[j
];
681 indexByName
.put(new IndexKey(constructor
.name() + constructor
.signature() + " " + constructor
.containingClass().name() + " " + constructor
.containingPackage().name()), constructor
);
688 private void registerTaglet(Taglet taglet
)
690 tagletMap
.put(taglet
.getName(), taglet
);
693 protected void printTaglets(Tag
[] tags
, TagletContext context
, TagletPrinter output
, boolean inline
)
695 for (Iterator it
= tagletMap
.keySet().iterator(); it
.hasNext(); ) {
696 String tagName
= (String
)it
.next();
697 Object o
= tagletMap
.get(tagName
);
698 Taglet taglet
= (Taglet
)o
;
699 Doc doc
= context
.getDoc();
700 if (inline
== taglet
.isInlineTag()
702 && taglet
.inOverview())
704 && ((doc
.isConstructor() && taglet
.inConstructor())
705 || (doc
.isField() && taglet
.inField())
706 || (doc
.isMethod() && taglet
.inMethod())
707 || (doc
instanceof PackageDoc
&& taglet
.inPackage())
708 || ((doc
.isClass() || doc
.isInterface()) && taglet
.inType()))))) {
710 List tagsOfThisType
= new LinkedList();
711 for (int i
=0; i
<tags
.length
; ++i
) {
712 if (tags
[i
].name().substring(1).equals(tagName
)) {
713 tagsOfThisType
.add(tags
[i
]);
717 Tag
[] tagletTags
= (Tag
[])tagsOfThisType
.toArray(new Tag
[tagsOfThisType
.size()]);
720 if (taglet
instanceof StandardTaglet
) {
721 tagletString
= renderTag(tagName
, tagletTags
, context
);
723 else if (taglet
instanceof GnuExtendedTaglet
) {
724 tagletString
= ((GnuExtendedTaglet
)taglet
).toString(tagletTags
, context
);
727 tagletString
= taglet
.toString(tagletTags
);
729 if (null != tagletString
) {
730 output
.printTagletString(tagletString
);
736 protected void printInlineTaglet(Tag tag
, TagletContext context
, TagletPrinter output
)
738 Taglet taglet
= (Taglet
)tagletMap
.get(tag
.name().substring(1));
739 if (null != taglet
) {
741 if (taglet
instanceof GnuExtendedTaglet
) {
742 tagletString
= ((GnuExtendedTaglet
)taglet
).toString(tag
, context
);
745 tagletString
= taglet
.toString(tag
);
747 if (null != tagletString
) {
748 output
.printTagletString(tagletString
);
752 printWarning("Unknown tag: " + tag
.name());
756 protected void printMainTaglets(Tag
[] tags
, TagletContext context
, TagletPrinter output
)
758 printTaglets(tags
, context
, output
, false);
762 * @param usedClassToPackagesMap ClassDoc to (PackageDoc to (UsageType to (Set of Doc)))
764 private void addUsedBy(Map usedClassToPackagesMap
,
765 ClassDoc usedClass
, UsageType usageType
, Doc user
, PackageDoc userPackage
)
767 Map packageToUsageTypeMap
= (Map
)usedClassToPackagesMap
.get(usedClass
);
768 if (null == packageToUsageTypeMap
) {
769 packageToUsageTypeMap
= new HashMap();
770 usedClassToPackagesMap
.put(usedClass
, packageToUsageTypeMap
);
773 Map usageTypeToUsersMap
= (Map
)packageToUsageTypeMap
.get(userPackage
);
774 if (null == usageTypeToUsersMap
) {
775 usageTypeToUsersMap
= new TreeMap();
776 packageToUsageTypeMap
.put(userPackage
, usageTypeToUsersMap
);
779 Set userSet
= (Set
)usageTypeToUsersMap
.get(usageType
);
780 if (null == userSet
) {
781 userSet
= new TreeSet(); // FIXME: we need the collator from Main here
782 usageTypeToUsersMap
.put(usageType
, userSet
);
788 * Create the cross reference database.
790 private Map
collectUsage() {
792 Map _usedClassToPackagesMap
= new HashMap();
794 ClassDoc
[] classes
= rootDoc
.classes();
795 for (int i
= 0, ilim
= classes
.length
; i
< ilim
; ++ i
) {
796 ClassDoc clazz
= classes
[i
];
798 if (clazz
.isInterface()) {
799 // classes implementing
800 InterfaceRelation relation
801 = (InterfaceRelation
)getInterfaceRelations().get(clazz
);
802 Iterator it
= relation
.implementingClasses
.iterator();
803 while (it
.hasNext()) {
804 ClassDoc implementor
= (ClassDoc
)it
.next();
805 addUsedBy(_usedClassToPackagesMap
,
806 clazz
, UsageType
.CLASS_IMPLEMENTING
, implementor
, implementor
.containingPackage());
810 // classes derived from
811 for (ClassDoc superclass
= clazz
.superclass(); superclass
!= null;
812 superclass
= superclass
.superclass()) {
813 addUsedBy(_usedClassToPackagesMap
,
814 superclass
, UsageType
.CLASS_DERIVED_FROM
, clazz
, clazz
.containingPackage());
818 FieldDoc
[] fields
= clazz
.fields();
819 for (int j
= 0, jlim
= fields
.length
; j
< jlim
; ++ j
) {
820 FieldDoc field
= fields
[j
];
823 ClassDoc fieldType
= field
.type().asClassDoc();
824 if (null != fieldType
) {
825 addUsedBy(_usedClassToPackagesMap
,
826 fieldType
, UsageType
.FIELD_OF_TYPE
,
827 field
, clazz
.containingPackage());
831 MethodDoc
[] methods
= clazz
.methods();
832 for (int j
= 0, jlim
= methods
.length
; j
< jlim
; ++ j
) {
833 MethodDoc method
= methods
[j
];
835 // methods with return type
837 ClassDoc returnType
= method
.returnType().asClassDoc();
838 if (null != returnType
) {
839 addUsedBy(_usedClassToPackagesMap
,
840 returnType
, UsageType
.METHOD_WITH_RETURN_TYPE
,
841 method
, clazz
.containingPackage());
843 Parameter
[] parameters
= method
.parameters();
844 for (int k
=0; k
<parameters
.length
; ++k
) {
846 // methods with parameter type
848 Parameter parameter
= parameters
[k
];
849 ClassDoc parameterType
= parameter
.type().asClassDoc();
850 if (null != parameterType
) {
851 addUsedBy(_usedClassToPackagesMap
,
852 parameterType
, UsageType
.METHOD_WITH_PARAMETER_TYPE
,
853 method
, clazz
.containingPackage());
857 // methods which throw
859 ClassDoc
[] thrownExceptions
= method
.thrownExceptions();
860 for (int k
= 0, klim
= thrownExceptions
.length
; k
< klim
; ++ k
) {
861 ClassDoc thrownException
= thrownExceptions
[k
];
862 addUsedBy(_usedClassToPackagesMap
,
863 thrownException
, UsageType
.METHOD_WITH_THROWN_TYPE
,
864 method
, clazz
.containingPackage());
868 ConstructorDoc
[] constructors
= clazz
.constructors();
869 for (int j
= 0, jlim
= constructors
.length
; j
< jlim
; ++ j
) {
871 ConstructorDoc constructor
= constructors
[j
];
873 Parameter
[] parameters
= constructor
.parameters();
874 for (int k
= 0, klim
= parameters
.length
; k
< klim
; ++ k
) {
876 // constructors with parameter type
878 Parameter parameter
= parameters
[k
];
879 ClassDoc parameterType
= parameter
.type().asClassDoc();
880 if (null != parameterType
) {
881 addUsedBy(_usedClassToPackagesMap
,
882 parameterType
, UsageType
.CONSTRUCTOR_WITH_PARAMETER_TYPE
,
883 constructor
, clazz
.containingPackage());
887 // constructors which throw
889 ClassDoc
[] thrownExceptions
= constructor
.thrownExceptions();
890 for (int k
= 0, klim
= thrownExceptions
.length
; k
< klim
; ++ k
) {
891 ClassDoc thrownException
= thrownExceptions
[k
];
892 addUsedBy(_usedClassToPackagesMap
,
893 thrownException
, UsageType
.CONSTRUCTOR_WITH_THROWN_TYPE
,
894 constructor
, clazz
.containingPackage());
898 return _usedClassToPackagesMap
;
901 private Map usedClassToPackagesMap
= null;
903 protected Map
getUsageOfClass(ClassDoc classDoc
)
905 if (null == this.usedClassToPackagesMap
) {
906 this.usedClassToPackagesMap
= collectUsage();
908 return (Map
)this.usedClassToPackagesMap
.get(classDoc
);
911 protected static class UsageType
912 implements Comparable
914 public static final UsageType CLASS_DERIVED_FROM
= new UsageType("class-derived-from");
915 public static final UsageType CLASS_IMPLEMENTING
= new UsageType("class-implementing");
916 public static final UsageType FIELD_OF_TYPE
= new UsageType("field-of-type");
917 public static final UsageType METHOD_WITH_RETURN_TYPE
= new UsageType("method-with-return-type");
918 public static final UsageType METHOD_WITH_PARAMETER_TYPE
= new UsageType("method-with-parameter-type");
919 public static final UsageType METHOD_WITH_THROWN_TYPE
= new UsageType("method-with-thrown-type");
920 public static final UsageType CONSTRUCTOR_WITH_PARAMETER_TYPE
= new UsageType("constructor-with-parameter-type");
921 public static final UsageType CONSTRUCTOR_WITH_THROWN_TYPE
= new UsageType("constructor-with-thrown-type");
924 private UsageType(String id
)
929 public int compareTo(Object other
)
931 return this.id
.compareTo(((UsageType
)other
).id
);
934 public String
toString() {
935 return "UsageType{id=" + id
+ "}";
938 public String
getId() {
943 private ResourceBundle resources
;
945 protected String
getString(String key
)
947 if (null == resources
) {
948 Locale currentLocale
= Locale
.getDefault();
951 = ResourceBundle
.getBundle("htmldoclet.HtmlDoclet", currentLocale
);
954 return resources
.getString(key
);
957 protected String
format(String key
, String value1
)
959 return MessageFormat
.format(getString(key
), new Object
[] { value1
});
962 protected List
getPackageGroups()
964 return packageGroups
;
967 protected void copyDocFiles(File sourceDir
, File targetDir
)
970 File sourceDocFiles
= new File(sourceDir
, "doc-files");
971 File targetDocFiles
= new File(targetDir
, "doc-files");
973 if (sourceDocFiles
.exists()) {
974 IOToolkit
.copyDirectory(sourceDocFiles
,
976 optionDocFilesSubDirs
.getValue(),
977 optionExcludeDocFilesSubDir
.getComponents());
981 private Set sourcePaths
;
984 * Try to determine the source directory for the given package by
985 * looking at the path specified by -sourcepath, or the current
986 * directory if -sourcepath hasn't been specified.
988 * @throws IOException if the source directory couldn't be
991 * @return List of File
993 protected List
getPackageSourceDirs(PackageDoc packageDoc
)
996 if (null == sourcePaths
) {
997 for (int i
=0; i
<rootDoc
.options().length
; ++i
) {
998 if ("-sourcepath".equals(rootDoc
.options()[i
][0])
999 || "-s".equals(rootDoc
.options()[i
][0])) {
1000 sourcePaths
= new LinkedHashSet();
1001 String sourcepathString
= rootDoc
.options()[i
][1];
1002 StringTokenizer st
= new StringTokenizer(sourcepathString
, File
.pathSeparator
);
1003 while (st
.hasMoreTokens()) {
1004 sourcePaths
.add(new File(st
.nextToken()));
1008 if (null == sourcePaths
) {
1009 sourcePaths
= new LinkedHashSet();
1010 sourcePaths
.add(new File(System
.getProperty("user.dir")));
1014 String packageSubDir
= packageDoc
.name().replace('.', File
.separatorChar
);
1015 Iterator it
= sourcePaths
.iterator();
1016 List result
= new LinkedList();
1017 while (it
.hasNext()) {
1018 File pathComponent
= (File
)it
.next();
1019 File packageDir
= new File(pathComponent
, packageSubDir
);
1020 if (packageDir
.exists()) {
1021 result
.add(packageDir
);
1024 if (result
.isEmpty()) {
1025 throw new IOException("Couldn't locate source directory for package " + packageDoc
.name());
1032 protected File
getSourceFile(ClassDoc classDoc
)
1035 List packageDirs
= getPackageSourceDirs(classDoc
.containingPackage());
1036 Iterator it
= packageDirs
.iterator();
1037 while (it
.hasNext()) {
1038 File packageDir
= (File
)it
.next();
1039 File sourceFile
= new File(packageDir
, getOuterClassDoc(classDoc
).name() + ".java");
1040 if (sourceFile
.exists()) {
1045 throw new IOException("Couldn't locate source file for class " + classDoc
.qualifiedTypeName());
1048 protected void printError(String error
)
1050 if (null != rootDoc
) {
1051 rootDoc
.printError(error
);
1054 System
.err
.println("ERROR: "+error
);
1058 protected void printWarning(String warning
)
1060 if (null != rootDoc
) {
1061 rootDoc
.printWarning(warning
);
1064 System
.err
.println("WARNING: "+warning
);
1068 protected void printNotice(String notice
)
1070 if (null != rootDoc
) {
1071 rootDoc
.printNotice(notice
);
1074 System
.err
.println(notice
);
1078 protected static ClassDoc
getOuterClassDoc(ClassDoc classDoc
)
1080 while (null != classDoc
.containingClass()) {
1081 classDoc
= classDoc
.containingClass();
1086 private SortedSet allPackages
;
1088 protected Set
getAllPackages()
1090 if (null == this.allPackages
) {
1091 allPackages
= new TreeSet();
1092 PackageDoc
[] specifiedPackages
= rootDoc
.specifiedPackages();
1093 for (int i
=0; i
<specifiedPackages
.length
; ++i
) {
1094 allPackages
.add(specifiedPackages
[i
]);
1096 ClassDoc
[] specifiedClasses
= rootDoc
.specifiedClasses();
1097 for (int i
=0; i
<specifiedClasses
.length
; ++i
) {
1098 allPackages
.add(specifiedClasses
[i
].containingPackage());
1101 return this.allPackages
;
1104 protected boolean omitPackageQualifier(PackageDoc packageDoc
)
1106 if (!optionNoQualifier
.isSpecified()) {
1110 return optionNoQualifier
.match(packageDoc
);
1114 protected String
possiblyQualifiedName(Type type
)
1116 if (null == type
.asClassDoc()
1117 || !omitPackageQualifier(type
.asClassDoc().containingPackage())) {
1118 return type
.qualifiedTypeName();
1121 return type
.typeName();
1125 protected static class InterfaceRelation
1127 public Set superInterfaces
;
1128 public Set subInterfaces
;
1129 public Set implementingClasses
;
1131 public InterfaceRelation()
1133 superInterfaces
= new TreeSet();
1134 subInterfaces
= new TreeSet();
1135 implementingClasses
= new TreeSet();
1139 private void addAllInterfaces(ClassDoc classDoc
, Set allInterfaces
)
1141 ClassDoc
[] interfaces
= classDoc
.interfaces();
1142 for (int i
=0; i
<interfaces
.length
; ++i
) {
1143 allInterfaces
.add(interfaces
[i
]);
1144 addAllInterfaces(interfaces
[i
], allInterfaces
);
1148 private Map allSubClasses
;
1150 protected Map
getAllSubClasses()
1152 if (null == allSubClasses
) {
1153 allSubClasses
= new HashMap();
1155 ClassDoc
[] classDocs
= getRootDoc().classes();
1156 for (int i
=0; i
<classDocs
.length
; ++i
) {
1157 if (!classDocs
[i
].isInterface()) {
1158 for (ClassDoc cd
= classDocs
[i
].superclass();
1160 cd
= cd
.superclass()) {
1162 if (!cd
.qualifiedTypeName().equals("java.lang.Object")) {
1163 List subClasses
= (List
)allSubClasses
.get(cd
);
1164 if (null == subClasses
) {
1165 subClasses
= new LinkedList();
1166 allSubClasses
.put(cd
, subClasses
);
1168 subClasses
.add(classDocs
[i
]);
1174 return allSubClasses
;
1177 private Map interfaceRelations
;
1179 private void addToInterfaces(ClassDoc classDoc
, ClassDoc
[] interfaces
)
1181 for (int i
=0; i
<interfaces
.length
; ++i
) {
1182 InterfaceRelation interfaceRelation
1183 = (InterfaceRelation
)interfaceRelations
.get(interfaces
[i
]);
1184 if (null == interfaceRelation
) {
1185 interfaceRelation
= new InterfaceRelation();
1186 interfaceRelations
.put(interfaces
[i
], interfaceRelation
);
1188 interfaceRelation
.implementingClasses
.add(classDoc
);
1189 addToInterfaces(classDoc
, interfaces
[i
].interfaces());
1193 protected Map
getInterfaceRelations()
1195 if (null == interfaceRelations
) {
1196 interfaceRelations
= new HashMap();
1198 ClassDoc
[] classDocs
= getRootDoc().classes();
1199 for (int i
=0; i
<classDocs
.length
; ++i
) {
1200 if (classDocs
[i
].isInterface()) {
1201 InterfaceRelation relation
= new InterfaceRelation();
1202 addAllInterfaces(classDocs
[i
], relation
.superInterfaces
);
1203 interfaceRelations
.put(classDocs
[i
], relation
);
1207 Iterator it
= interfaceRelations
.keySet().iterator();
1208 while (it
.hasNext()) {
1209 ClassDoc interfaceDoc
= (ClassDoc
)it
.next();
1210 InterfaceRelation relation
1211 = (InterfaceRelation
)interfaceRelations
.get(interfaceDoc
);
1212 Iterator superIt
= relation
.superInterfaces
.iterator();
1213 while (superIt
.hasNext()) {
1214 ClassDoc superInterfaceDoc
= (ClassDoc
)superIt
.next();
1215 InterfaceRelation superRelation
1216 = (InterfaceRelation
)interfaceRelations
.get(superInterfaceDoc
);
1217 if (null != superRelation
) {
1218 superRelation
.subInterfaces
.add(interfaceDoc
);
1223 for (int i
=0; i
<classDocs
.length
; ++i
) {
1224 if (!classDocs
[i
].isInterface()) {
1225 for (ClassDoc cd
= classDocs
[i
]; null != cd
; cd
= cd
.superclass()) {
1226 addToInterfaces(classDocs
[i
], cd
.interfaces());
1232 return interfaceRelations
;
1235 private Map sortedMethodMap
= new HashMap();
1237 protected MethodDoc
[] getSortedMethods(ClassDoc classDoc
)
1239 MethodDoc
[] result
= (MethodDoc
[])sortedMethodMap
.get(classDoc
);
1240 if (null == result
) {
1241 MethodDoc
[] methods
= classDoc
.methods();
1242 result
= (MethodDoc
[])methods
.clone();
1243 Arrays
.sort(result
);
1249 private Map sortedConstructorMap
= new HashMap();
1251 protected ConstructorDoc
[] getSortedConstructors(ClassDoc classDoc
)
1253 ConstructorDoc
[] result
= (ConstructorDoc
[])sortedConstructorMap
.get(classDoc
);
1254 if (null == result
) {
1255 ConstructorDoc
[] constructors
= classDoc
.constructors();
1256 result
= (ConstructorDoc
[])constructors
.clone();
1257 Arrays
.sort(result
);
1263 private Map sortedFieldMap
= new HashMap();
1265 protected FieldDoc
[] getSortedFields(ClassDoc classDoc
)
1267 FieldDoc
[] result
= (FieldDoc
[])sortedFieldMap
.get(classDoc
);
1268 if (null == result
) {
1269 FieldDoc
[] fields
= classDoc
.fields();
1270 result
= (FieldDoc
[])fields
.clone();
1271 Arrays
.sort(result
);
1277 private Map sortedInnerClassMap
= new HashMap();
1279 protected ClassDoc
[] getSortedInnerClasses(ClassDoc classDoc
)
1281 ClassDoc
[] result
= (ClassDoc
[])sortedInnerClassMap
.get(classDoc
);
1282 if (null == result
) {
1283 ClassDoc
[] innerClasses
= classDoc
.innerClasses();
1284 result
= (ClassDoc
[])innerClasses
.clone();
1285 Arrays
.sort(result
);
1291 protected abstract String
renderTag(String tagName
, Tag
[] tags
, TagletContext context
);
1293 protected abstract String
getDocletVersion();
1295 protected SortedSet
getThrownExceptions(ExecutableMemberDoc execMemberDoc
)
1297 SortedSet result
= new TreeSet();
1298 ClassDoc
[] thrownExceptions
= execMemberDoc
.thrownExceptions();
1299 for (int j
=0; j
<thrownExceptions
.length
; ++j
) {
1300 result
.add(thrownExceptions
[j
]);
1305 protected boolean isUncheckedException(ClassDoc classDoc
)
1307 if (classDoc
.isException()) {
1308 while (null != classDoc
) {
1309 if (classDoc
.qualifiedTypeName().equals("java.lang.RuntimeException")) {
1312 classDoc
= classDoc
.superclass();
1321 protected FieldDoc
findField(ClassDoc classDoc
, String fieldName
)
1323 for (ClassDoc cd
= classDoc
; cd
!= null; cd
= cd
.superclass()) {
1324 FieldDoc
[] fields
= cd
.fields(false);
1325 for (int i
=0; i
<fields
.length
; ++i
) {
1326 if (fields
[i
].name().equals(fieldName
)) {
1334 private Map implementedInterfacesCache
= new HashMap();
1336 protected Set
getImplementedInterfaces(ClassDoc classDoc
)
1338 Set result
= (Set
)implementedInterfacesCache
.get(classDoc
);
1339 if (null == result
) {
1340 result
= new TreeSet();
1342 for (ClassDoc cd
= classDoc
; cd
!= null; cd
= cd
.superclass()) {
1343 ClassDoc
[] interfaces
= cd
.interfaces();
1344 for (int i
=0; i
<interfaces
.length
; ++i
) {
1345 result
.add(interfaces
[i
]);
1346 InterfaceRelation relation
1347 = (InterfaceRelation
)getInterfaceRelations().get(interfaces
[i
]);
1348 if (null != relation
) {
1349 result
.addAll(relation
.superInterfaces
);
1354 implementedInterfacesCache
.put(classDoc
, result
);
1360 protected boolean isSinglePackage()
1362 return getAllPackages().size() <= 1;
1365 protected PackageDoc
getSinglePackage()
1367 return (PackageDoc
)getAllPackages().iterator().next();