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();