Import GNU Classpath (20121202).
[official-gcc.git] / libjava / classpath / tools / gnu / classpath / tools / doclets / AbstractDoclet.java
blob9e1fac62ead791e2ebf7ea5d11307115479223ab
1 /* gnu.classpath.tools.doclets.AbstractDoclet
2 Copyright (C) 2004, 2012 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 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
38 package gnu.classpath.tools.doclets;
40 import com.sun.javadoc.ClassDoc;
41 import com.sun.javadoc.ConstructorDoc;
42 import com.sun.javadoc.Doc;
43 import com.sun.javadoc.Doclet;
44 import com.sun.javadoc.ExecutableMemberDoc;
45 import com.sun.javadoc.FieldDoc;
46 import com.sun.javadoc.MethodDoc;
47 import com.sun.javadoc.PackageDoc;
48 import com.sun.javadoc.Parameter;
49 import com.sun.javadoc.RootDoc;
50 import com.sun.javadoc.Tag;
51 import com.sun.javadoc.Type;
53 import com.sun.tools.doclets.Taglet;
55 import gnu.classpath.tools.taglets.GnuExtendedTaglet;
56 import gnu.classpath.tools.taglets.AuthorTaglet;
57 import gnu.classpath.tools.taglets.CodeTaglet;
58 import gnu.classpath.tools.taglets.DeprecatedTaglet;
59 import gnu.classpath.tools.taglets.GenericTaglet;
60 import gnu.classpath.tools.taglets.SinceTaglet;
61 import gnu.classpath.tools.taglets.ValueTaglet;
62 import gnu.classpath.tools.taglets.VersionTaglet;
63 import gnu.classpath.tools.taglets.TagletContext;
65 import gnu.classpath.tools.IOToolkit;
66 import gnu.classpath.tools.FileSystemClassLoader;
68 import java.io.File;
69 import java.io.IOException;
71 import java.lang.reflect.Method;
72 import java.lang.reflect.Modifier;
73 import java.lang.reflect.InvocationTargetException;
75 import java.text.MessageFormat;
77 import java.util.ArrayList;
78 import java.util.Arrays;
79 import java.util.Collections;
80 import java.util.Comparator;
81 import java.util.HashMap;
82 import java.util.Iterator;
83 import java.util.LinkedHashMap;
84 import java.util.LinkedHashSet;
85 import java.util.LinkedList;
86 import java.util.List;
87 import java.util.Locale;
88 import java.util.Map;
89 import java.util.ResourceBundle;
90 import java.util.Set;
91 import java.util.SortedSet;
92 import java.util.StringTokenizer;
93 import java.util.TreeMap;
94 import java.util.TreeSet;
96 /**
97 * An abstract Doclet implementation with helpers for common tasks
98 * performed by Doclets.
100 public abstract class AbstractDoclet
103 * Mapping from tag type to Taglet for user Taglets specified on
104 * the command line.
106 protected Map<String,Taglet> tagletMap = new LinkedHashMap<String,Taglet>();
109 * Stores the package groups specified in the user
110 * options. Contains objects of type PackageGroup.
112 private List<PackageGroup> packageGroups = new LinkedList<PackageGroup>();
115 * Keeps track of the tags mentioned by the user during option
116 * processiong so that an error can be emitted if a tag is
117 * mentioned more than once.
119 private List<Taglet> mentionedTags = new LinkedList<Taglet>();
121 public static int optionLength(String option) {
122 return instance.getOptionLength(option);
125 public static boolean validOptions(String[][] options) {
126 return true;
129 private static AbstractDoclet instance;
131 protected static void setInstance(AbstractDoclet instance)
133 AbstractDoclet.instance = instance;
136 protected abstract void run()
137 throws DocletConfigurationException, IOException;
139 public static boolean start(RootDoc rootDoc)
141 try {
143 instance.startInstance(rootDoc);
144 return true;
146 catch (DocletConfigurationException e) {
147 instance.printError(e.getMessage());
148 return false;
150 catch (Exception e) {
151 e.printStackTrace();
152 return false;
156 protected RootDoc getRootDoc()
158 return this.rootDoc;
161 private RootDoc rootDoc;
163 protected abstract InlineTagRenderer getInlineTagRenderer();
165 private void startInstance(RootDoc rootDoc)
166 throws DocletConfigurationException, IOException
168 this.rootDoc = rootDoc;
170 // Set the default Taglet order
172 registerTaglet(new VersionTaglet());
173 registerTaglet(new AuthorTaglet());
174 registerTaglet(new SinceTaglet(getInlineTagRenderer()));
175 registerTaglet(new StandardTaglet("serial"));
176 registerTaglet(new StandardTaglet("deprecated"));
177 registerTaglet(new StandardTaglet("see"));
178 registerTaglet(new StandardTaglet("param"));
179 registerTaglet(new StandardTaglet("return"));
181 registerTaglet(new ValueTaglet());
182 registerTaglet(new CodeTaglet());
184 // Process command line options
186 for (int i=0, ilim=rootDoc.options().length; i<ilim; ++i) {
188 String[] optionArr = rootDoc.options()[i];
189 String _optionTag = optionArr[0];
191 DocletOption option = (DocletOption)nameToOptionMap.get(_optionTag.toLowerCase());
193 if (null != option) {
194 option.set(optionArr);
198 // Enable/disable standard taglets based on user input
200 AuthorTaglet.setTagletEnabled(optionAuthor.getValue());
201 VersionTaglet.setTagletEnabled(optionVersion.getValue());
202 SinceTaglet.setTagletEnabled(!optionNoSince.getValue());
203 DeprecatedTaglet.setTagletEnabled(!optionNoDeprecated.getValue());
205 if (!getTargetDirectory().exists()) {
206 if (!getTargetDirectory().mkdirs()) {
207 throw new DocletConfigurationException("Cannot create target directory "
208 + getTargetDirectory());
212 run();
215 public File getTargetDirectory()
217 return optionTargetDirectory.getValue();
220 private DocletOptionFile optionTargetDirectory =
221 new DocletOptionFile("-d",
222 new File(System.getProperty("user.dir")));
224 private DocletOptionFlag optionAuthor =
225 new DocletOptionFlag("-author");
227 private DocletOptionFlag optionVersion =
228 new DocletOptionFlag("-version");
230 private DocletOptionFlag optionNoSince =
231 new DocletOptionFlag("-nosince");
233 private DocletOptionFlag optionNoDeprecated =
234 new DocletOptionFlag("-nodeprecated");
236 private DocletOptionGroup optionGroup =
237 new DocletOptionGroup("-group");
239 private DocletOptionPackageWildcard optionNoQualifier =
240 new DocletOptionPackageWildcard("-noqualifier", true);
242 private DocletOptionFlag optionDocFilesSubDirs =
243 new DocletOptionFlag("-docfilessubdirs");
245 private DocletOptionColonSeparated optionExcludeDocFilesSubDir =
246 new DocletOptionColonSeparated("-excludedocfilessubdir");
248 private DocletOptionTag optionTaglet =
249 new DocletOptionTag("-taglet");
251 private DocletOptionTag optionTag =
252 new DocletOptionTag("-tag");
254 private class DocletOptionGroup
255 extends DocletOption
257 DocletOptionGroup(String optionName)
259 super(optionName);
262 public int getLength()
264 return 3;
267 public boolean set(String[] optionArr)
269 try {
270 PackageMatcher packageMatcher = new PackageMatcher();
272 StringTokenizer tokenizer = new StringTokenizer(optionArr[2], ":");
273 while (tokenizer.hasMoreTokens()) {
274 String packageWildcard = tokenizer.nextToken();
275 packageMatcher.addWildcard(packageWildcard);
278 SortedSet<PackageDoc> groupPackages = packageMatcher.filter(rootDoc.specifiedPackages());
280 packageGroups.add(new PackageGroup(optionArr[1], groupPackages));
282 return true;
284 catch (InvalidPackageWildcardException e) {
285 return false;
290 private class DocletOptionTag
291 extends DocletOption
293 DocletOptionTag(String optionName)
295 super(optionName);
298 public int getLength()
300 return 2;
303 public boolean set(String[] optionArr)
305 String tagSpec = optionArr[1];
306 boolean validTagSpec = false;
307 int ndx1 = tagSpec.indexOf(':');
308 if (ndx1 < 0) {
309 Taglet taglet = (Taglet)tagletMap.get(tagSpec);
310 if (null == taglet) {
311 printError("There is no standard tag '" + tagSpec + "'.");
313 else {
314 if (mentionedTags.contains(taglet)) {
315 printError("Tag '" + tagSpec + "' has been added or moved before.");
317 else {
318 mentionedTags.add(taglet);
320 // re-append taglet
321 tagletMap.remove(tagSpec);
322 tagletMap.put(tagSpec, taglet);
326 else {
327 int ndx2 = tagSpec.indexOf(':', ndx1 + 1);
328 if (ndx2 > ndx1 && ndx2 < tagSpec.length() - 1) {
329 String tagName = tagSpec.substring(0, ndx1);
330 String tagHead = null;
331 if (tagSpec.charAt(ndx2 + 1) == '\"') {
332 if (tagSpec.charAt(tagSpec.length() - 1) == '\"') {
333 tagHead = tagSpec.substring(ndx2 + 2, tagSpec.length() - 1);
334 validTagSpec = true;
337 else {
338 tagHead = tagSpec.substring(ndx2 + 1);
339 validTagSpec = true;
342 boolean tagScopeOverview = false;
343 boolean tagScopePackages = false;
344 boolean tagScopeTypes = false;
345 boolean tagScopeConstructors = false;
346 boolean tagScopeMethods = false;
347 boolean tagScopeFields = false;
348 boolean tagDisabled = false;
350 tag_option_loop:
351 for (int n=ndx1+1; n<ndx2; ++n) {
352 switch (tagSpec.charAt(n)) {
353 case 'X':
354 tagDisabled = true;
355 break;
356 case 'a':
357 tagScopeOverview = true;
358 tagScopePackages = true;
359 tagScopeTypes = true;
360 tagScopeConstructors = true;
361 tagScopeMethods = true;
362 tagScopeFields = true;
363 break;
364 case 'o':
365 tagScopeOverview = true;
366 break;
367 case 'p':
368 tagScopePackages = true;
369 break;
370 case 't':
371 tagScopeTypes = true;
372 break;
373 case 'c':
374 tagScopeConstructors = true;
375 break;
376 case 'm':
377 tagScopeMethods = true;
378 break;
379 case 'f':
380 tagScopeFields = true;
381 break;
382 default:
383 validTagSpec = false;
384 break tag_option_loop;
388 if (validTagSpec) {
389 GenericTaglet taglet
390 = new GenericTaglet(tagName,
391 tagHead,
392 tagScopeOverview,
393 tagScopePackages,
394 tagScopeTypes,
395 tagScopeConstructors,
396 tagScopeMethods,
397 tagScopeFields);
398 taglet.setTagletEnabled(!tagDisabled);
399 taglet.register(tagletMap);
400 mentionedTags.add(taglet);
404 if (!validTagSpec) {
405 printError("Value for option -tag must be in format \"<tagname>:Xaoptcmf:<taghead>\".");
407 return validTagSpec;
411 private DocletOption[] commonOptions =
413 optionTargetDirectory,
414 optionAuthor,
415 optionVersion,
416 optionNoSince,
417 optionNoDeprecated,
418 optionGroup,
419 optionDocFilesSubDirs,
420 optionExcludeDocFilesSubDir,
421 optionTaglet,
422 optionTag,
425 private void registerOptions()
427 if (!optionsRegistered) {
428 for (int i=0; i<commonOptions.length; ++i) {
429 DocletOption option = commonOptions[i];
430 registerOption(option);
432 DocletOption[] docletOptions = getOptions();
433 for (int i=0; i<docletOptions.length; ++i) {
434 DocletOption option = docletOptions[i];
435 registerOption(option);
437 optionsRegistered = true;
441 protected abstract DocletOption[] getOptions();
443 private boolean optionsRegistered = false;
445 private void registerOption(DocletOption option)
447 nameToOptionMap.put(option.getName(), option);
450 private Map<String,DocletOption> nameToOptionMap = new HashMap<String,DocletOption>();
452 private int getOptionLength(String optionName)
454 registerOptions();
455 DocletOption option = nameToOptionMap.get(optionName.toLowerCase());
456 if (null != option) {
457 return option.getLength();
459 else {
460 return -1;
464 protected List<ClassDoc> getKnownDirectSubclasses(ClassDoc classDoc)
466 List<ClassDoc> result = new LinkedList<ClassDoc>();
467 if (!"java.lang.Object".equals(classDoc.qualifiedName())) {
468 ClassDoc[] classes = rootDoc.classes();
469 for (int i=0; i<classes.length; ++i) {
470 if (classDoc == classes[i].superclass()) {
471 result.add(classes[i]);
475 return result;
478 protected static class IndexKey
479 implements Comparable<IndexKey>
481 private String name;
482 private String lowerName;
484 public IndexKey(String name)
486 this.name = name;
487 this.lowerName = name.toLowerCase();
490 public boolean equals(Object other)
492 return this.lowerName.equals(((IndexKey)other).lowerName);
495 public int hashCode()
497 return lowerName.hashCode();
500 public int compareTo(IndexKey ik)
502 return lowerName.compareTo(ik.lowerName);
505 public String getName()
507 return name;
511 private Map<Character,List<Doc>> categorizedIndex;
513 protected Map<Character,List<Doc>> getCategorizedIndex()
515 if (null == categorizedIndex) {
516 categorizedIndex = new LinkedHashMap<Character,List<Doc>>();
518 Map<IndexKey,Doc> indexMap = getIndexByName();
519 LinkedList<IndexKey> keys = new LinkedList<IndexKey>(); //indexMap.keySet().size());
520 keys.addAll(indexMap.keySet());
521 Collections.sort(keys);
522 Iterator<IndexKey> it = keys.iterator(); //indexMap.keySet().iterator();
523 char previousCategoryLetter = '\0';
524 Character keyLetter = null;
525 while (it.hasNext()) {
526 IndexKey key = it.next();
527 char firstChar = Character.toUpperCase(key.getName().charAt(0));
528 if (firstChar != previousCategoryLetter) {
529 keyLetter = new Character(firstChar);
530 previousCategoryLetter = firstChar;
531 categorizedIndex.put(keyLetter, new LinkedList<Doc>());
533 List<Doc> letterList = categorizedIndex.get(keyLetter);
534 letterList.add(indexMap.get(key));
538 return categorizedIndex;
542 private Map<IndexKey,Doc> indexByName;
544 protected Map<IndexKey,Doc> getIndexByName()
546 if (null == indexByName) {
547 // Create index
549 // Collect index
551 indexByName = new HashMap<IndexKey,Doc>(); //TreeMap();
553 // Add packages to index
555 PackageDoc[] packages = rootDoc.specifiedPackages();
556 for (int i=0, ilim=packages.length; i<ilim; ++i) {
557 PackageDoc c = packages[i];
558 if (c.name().length() > 0) {
559 indexByName.put(new IndexKey(c.name()), c);
563 // Add classes, fields and methods to index
565 ClassDoc[] sumclasses = rootDoc.classes();
566 for (int i=0, ilim=sumclasses.length; i<ilim; ++i) {
567 ClassDoc c = sumclasses[i];
568 if (null == c.containingClass()) {
569 indexByName.put(new IndexKey(c.name() + " " + c.containingPackage().name()), c);
571 else {
572 indexByName.put(new IndexKey(c.name().substring(c.containingClass().name().length() + 1)
573 + " " + c.containingClass().name() + " " + c.containingPackage().name()), c);
575 FieldDoc[] fields = c.fields();
576 for (int j=0, jlim=fields.length; j<jlim; ++j) {
577 indexByName.put(new IndexKey(fields[j].name() + " " + fields[j].containingClass().name() + " " + fields[j].containingPackage().name()), fields[j]);
579 MethodDoc[] methods = c.methods();
580 for (int j=0, jlim=methods.length; j<jlim; ++j) {
581 MethodDoc method = methods[j];
582 indexByName.put(new IndexKey(method.name() + method.signature() + " " + method.containingClass().name() + " " + method.containingPackage().name()), method);
584 ConstructorDoc[] constructors = c.constructors();
585 for (int j=0, jlim=constructors.length; j<jlim; ++j) {
586 ConstructorDoc constructor = constructors[j];
587 indexByName.put(new IndexKey(constructor.name() + constructor.signature() + " " + constructor.containingClass().name() + " " + constructor.containingPackage().name()), constructor);
591 return indexByName;
594 private void registerTaglet(Taglet taglet)
596 tagletMap.put(taglet.getName(), taglet);
599 protected void printTaglets(Tag[] tags, TagletContext context, TagletPrinter output, boolean inline)
601 for (Iterator<String> it = tagletMap.keySet().iterator(); it.hasNext(); ) {
602 String tagName = it.next();
603 Taglet taglet = tagletMap.get(tagName);
604 Doc doc = context.getDoc();
605 if (inline == taglet.isInlineTag()
606 && ((doc == null
607 && taglet.inOverview())
608 || (doc != null
609 && ((doc.isConstructor() && taglet.inConstructor())
610 || (doc.isField() && taglet.inField())
611 || (doc.isMethod() && taglet.inMethod())
612 || (doc instanceof PackageDoc && taglet.inPackage())
613 || ((doc.isClass() || doc.isInterface()) && taglet.inType()))))) {
615 List<Tag> tagsOfThisType = new LinkedList<Tag>();
616 for (int i=0; i<tags.length; ++i) {
617 if (tags[i].name().substring(1).equals(tagName)) {
618 tagsOfThisType.add(tags[i]);
622 Tag[] tagletTags = tagsOfThisType.toArray(new Tag[tagsOfThisType.size()]);
624 String tagletString;
625 if (taglet instanceof StandardTaglet) {
626 tagletString = renderTag(tagName, tagletTags, context);
628 else if (taglet instanceof GnuExtendedTaglet) {
629 tagletString = ((GnuExtendedTaglet)taglet).toString(tagletTags, context);
631 else {
632 tagletString = taglet.toString(tagletTags);
634 if (null != tagletString) {
635 output.printTagletString(tagletString);
641 protected void printInlineTaglet(Tag tag, TagletContext context, TagletPrinter output)
643 Taglet taglet = (Taglet)tagletMap.get(tag.name().substring(1));
644 if (null != taglet) {
645 String tagletString;
646 if (taglet instanceof GnuExtendedTaglet) {
647 tagletString = ((GnuExtendedTaglet)taglet).toString(tag, context);
649 else {
650 tagletString = taglet.toString(tag);
652 if (null != tagletString) {
653 output.printTagletString(tagletString);
656 else {
657 printWarning("Unknown tag: " + tag.name());
661 protected void printMainTaglets(Tag[] tags, TagletContext context, TagletPrinter output)
663 printTaglets(tags, context, output, false);
667 * @param usedClassToPackagesMap ClassDoc to (PackageDoc to (UsageType to (Set of Doc)))
669 private void addUsedBy(Map<ClassDoc,Map<PackageDoc,Map<UsageType,Set<Doc>>>> usedClassToPackagesMap,
670 ClassDoc usedClass, UsageType usageType, Doc user, PackageDoc userPackage)
672 Map<PackageDoc,Map<UsageType,Set<Doc>>> packageToUsageTypeMap = usedClassToPackagesMap.get(usedClass);
673 if (null == packageToUsageTypeMap) {
674 packageToUsageTypeMap = new HashMap<PackageDoc,Map<UsageType,Set<Doc>>>();
675 usedClassToPackagesMap.put(usedClass, packageToUsageTypeMap);
678 Map<UsageType,Set<Doc>> usageTypeToUsersMap = packageToUsageTypeMap.get(userPackage);
679 if (null == usageTypeToUsersMap) {
680 usageTypeToUsersMap = new TreeMap<UsageType,Set<Doc>>();
681 packageToUsageTypeMap.put(userPackage, usageTypeToUsersMap);
684 Set<Doc> userSet = usageTypeToUsersMap.get(usageType);
685 if (null == userSet) {
686 userSet = new TreeSet<Doc>(); // FIXME: we need the collator from Main here
687 usageTypeToUsersMap.put(usageType, userSet);
689 userSet.add(user);
693 * Create the cross reference database.
695 private Map collectUsage() {
697 Map<ClassDoc,Map<PackageDoc,Map<UsageType,Set<Doc>>>> _usedClassToPackagesMap =
698 new HashMap<ClassDoc,Map<PackageDoc,Map<UsageType,Set<Doc>>>>();
700 ClassDoc[] classes = rootDoc.classes();
701 for (int i = 0, ilim = classes.length; i < ilim; ++ i) {
702 ClassDoc clazz = classes[i];
704 if (clazz.isInterface()) {
705 // classes implementing
706 InterfaceRelation relation
707 = (InterfaceRelation)getInterfaceRelations().get(clazz);
708 Iterator<ClassDoc> it = relation.implementingClasses.iterator();
709 while (it.hasNext()) {
710 ClassDoc implementor = it.next();
711 addUsedBy(_usedClassToPackagesMap,
712 clazz, UsageType.CLASS_IMPLEMENTING, implementor, implementor.containingPackage());
715 else {
716 // classes derived from
717 for (ClassDoc superclass = clazz.superclass(); superclass != null;
718 superclass = superclass.superclass()) {
719 addUsedBy(_usedClassToPackagesMap,
720 superclass, UsageType.CLASS_DERIVED_FROM, clazz, clazz.containingPackage());
724 FieldDoc[] fields = clazz.fields();
725 for (int j = 0, jlim = fields.length; j < jlim; ++ j) {
726 FieldDoc field = fields[j];
728 // fields of type
729 ClassDoc fieldType = field.type().asClassDoc();
730 if (null != fieldType) {
731 addUsedBy(_usedClassToPackagesMap,
732 fieldType, UsageType.FIELD_OF_TYPE,
733 field, clazz.containingPackage());
737 MethodDoc[] methods = clazz.methods();
738 for (int j = 0, jlim = methods.length; j < jlim; ++ j) {
739 MethodDoc method = methods[j];
741 // methods with return type
743 ClassDoc returnType = method.returnType().asClassDoc();
744 if (null != returnType) {
745 addUsedBy(_usedClassToPackagesMap,
746 returnType, UsageType.METHOD_WITH_RETURN_TYPE,
747 method, clazz.containingPackage());
749 Parameter[] parameters = method.parameters();
750 for (int k=0; k<parameters.length; ++k) {
752 // methods with parameter type
754 Parameter parameter = parameters[k];
755 ClassDoc parameterType = parameter.type().asClassDoc();
756 if (null != parameterType) {
757 addUsedBy(_usedClassToPackagesMap,
758 parameterType, UsageType.METHOD_WITH_PARAMETER_TYPE,
759 method, clazz.containingPackage());
763 // methods which throw
765 ClassDoc[] thrownExceptions = method.thrownExceptions();
766 for (int k = 0, klim = thrownExceptions.length; k < klim; ++ k) {
767 ClassDoc thrownException = thrownExceptions[k];
768 addUsedBy(_usedClassToPackagesMap,
769 thrownException, UsageType.METHOD_WITH_THROWN_TYPE,
770 method, clazz.containingPackage());
774 ConstructorDoc[] constructors = clazz.constructors();
775 for (int j = 0, jlim = constructors.length; j < jlim; ++ j) {
777 ConstructorDoc constructor = constructors[j];
779 Parameter[] parameters = constructor.parameters();
780 for (int k = 0, klim = parameters.length; k < klim; ++ k) {
782 // constructors with parameter type
784 Parameter parameter = parameters[k];
785 ClassDoc parameterType = parameter.type().asClassDoc();
786 if (null != parameterType) {
787 addUsedBy(_usedClassToPackagesMap,
788 parameterType, UsageType.CONSTRUCTOR_WITH_PARAMETER_TYPE,
789 constructor, clazz.containingPackage());
793 // constructors which throw
795 ClassDoc[] thrownExceptions = constructor.thrownExceptions();
796 for (int k = 0, klim = thrownExceptions.length; k < klim; ++ k) {
797 ClassDoc thrownException = thrownExceptions[k];
798 addUsedBy(_usedClassToPackagesMap,
799 thrownException, UsageType.CONSTRUCTOR_WITH_THROWN_TYPE,
800 constructor, clazz.containingPackage());
804 return _usedClassToPackagesMap;
807 private Map<ClassDoc,Map<PackageDoc,Map<UsageType,Set<Doc>>>> usedClassToPackagesMap = null;
809 protected Map<PackageDoc,Map<UsageType,Set<Doc>>> getUsageOfClass(ClassDoc classDoc)
811 if (null == this.usedClassToPackagesMap) {
812 this.usedClassToPackagesMap = collectUsage();
814 return this.usedClassToPackagesMap.get(classDoc);
817 protected static class UsageType
818 implements Comparable<UsageType>
820 public static final UsageType CLASS_DERIVED_FROM = new UsageType("class-derived-from");
821 public static final UsageType CLASS_IMPLEMENTING = new UsageType("class-implementing");
822 public static final UsageType FIELD_OF_TYPE = new UsageType("field-of-type");
823 public static final UsageType METHOD_WITH_RETURN_TYPE = new UsageType("method-with-return-type");
824 public static final UsageType METHOD_WITH_PARAMETER_TYPE = new UsageType("method-with-parameter-type");
825 public static final UsageType METHOD_WITH_THROWN_TYPE = new UsageType("method-with-thrown-type");
826 public static final UsageType CONSTRUCTOR_WITH_PARAMETER_TYPE = new UsageType("constructor-with-parameter-type");
827 public static final UsageType CONSTRUCTOR_WITH_THROWN_TYPE = new UsageType("constructor-with-thrown-type");
828 private String id;
830 private UsageType(String id)
832 this.id = id;
835 public int compareTo(UsageType ut)
837 return this.id.compareTo(ut.id);
840 public String toString() {
841 return "UsageType{id=" + id + "}";
844 public String getId() {
845 return id;
849 private ResourceBundle resources;
851 protected String getString(String key)
853 if (null == resources) {
854 Locale currentLocale = Locale.getDefault();
856 resources
857 = ResourceBundle.getBundle("htmldoclet.HtmlDoclet", currentLocale);
860 return resources.getString(key);
863 protected String format(String key, String value1)
865 return MessageFormat.format(getString(key), new Object[] { value1 });
868 protected List<PackageGroup> getPackageGroups()
870 return packageGroups;
873 protected void copyDocFiles(File sourceDir, File targetDir)
874 throws IOException
876 File sourceDocFiles = new File(sourceDir, "doc-files");
877 File targetDocFiles = new File(targetDir, "doc-files");
879 if (sourceDocFiles.exists()) {
880 IOToolkit.copyDirectory(sourceDocFiles,
881 targetDocFiles,
882 optionDocFilesSubDirs.getValue(),
883 optionExcludeDocFilesSubDir.getComponents());
887 private Set sourcePaths;
890 * Try to determine the source directory for the given package by
891 * looking at the path specified by -sourcepath, or the current
892 * directory if -sourcepath hasn't been specified.
894 * @throws IOException if the source directory couldn't be
895 * located.
897 * @return List of File
899 protected List getPackageSourceDirs(PackageDoc packageDoc)
900 throws IOException
902 if (null == sourcePaths) {
903 for (int i=0; i<rootDoc.options().length; ++i) {
904 if ("-sourcepath".equals(rootDoc.options()[i][0])
905 || "-s".equals(rootDoc.options()[i][0])) {
906 sourcePaths = new LinkedHashSet();
907 String sourcepathString = rootDoc.options()[i][1];
908 StringTokenizer st = new StringTokenizer(sourcepathString, File.pathSeparator);
909 while (st.hasMoreTokens()) {
910 sourcePaths.add(new File(st.nextToken()));
914 if (null == sourcePaths) {
915 sourcePaths = new LinkedHashSet();
916 sourcePaths.add(new File(System.getProperty("user.dir")));
920 String packageSubDir = packageDoc.name().replace('.', File.separatorChar);
921 Iterator it = sourcePaths.iterator();
922 List result = new LinkedList();
923 while (it.hasNext()) {
924 File pathComponent = (File)it.next();
925 File packageDir = new File(pathComponent, packageSubDir);
926 if (packageDir.exists()) {
927 result.add(packageDir);
930 if (result.isEmpty()) {
931 throw new IOException("Couldn't locate source directory for package " + packageDoc.name());
933 else {
934 return result;
938 protected File getSourceFile(ClassDoc classDoc)
939 throws IOException
941 List packageDirs = getPackageSourceDirs(classDoc.containingPackage());
942 Iterator it = packageDirs.iterator();
943 while (it.hasNext()) {
944 File packageDir = (File)it.next();
945 File sourceFile = new File(packageDir, getOuterClassDoc(classDoc).name() + ".java");
946 if (sourceFile.exists()) {
947 return sourceFile;
951 throw new IOException("Couldn't locate source file for class " + classDoc.qualifiedTypeName());
954 protected void printError(String error)
956 if (null != rootDoc) {
957 rootDoc.printError(error);
959 else {
960 System.err.println("ERROR: "+error);
964 protected void printWarning(String warning)
966 if (null != rootDoc) {
967 rootDoc.printWarning(warning);
969 else {
970 System.err.println("WARNING: "+warning);
974 protected void printNotice(String notice)
976 if (null != rootDoc) {
977 rootDoc.printNotice(notice);
979 else {
980 System.err.println(notice);
984 protected static ClassDoc getOuterClassDoc(ClassDoc classDoc)
986 while (null != classDoc.containingClass()) {
987 classDoc = classDoc.containingClass();
989 return classDoc;
992 private SortedSet allPackages;
994 protected Set getAllPackages()
996 if (null == this.allPackages) {
997 allPackages = new TreeSet();
998 PackageDoc[] specifiedPackages = rootDoc.specifiedPackages();
999 for (int i=0; i<specifiedPackages.length; ++i) {
1000 allPackages.add(specifiedPackages[i]);
1002 ClassDoc[] specifiedClasses = rootDoc.specifiedClasses();
1003 for (int i=0; i<specifiedClasses.length; ++i) {
1004 allPackages.add(specifiedClasses[i].containingPackage());
1007 return this.allPackages;
1010 protected boolean omitPackageQualifier(PackageDoc packageDoc)
1012 if (!optionNoQualifier.isSpecified()) {
1013 return false;
1015 else {
1016 return optionNoQualifier.match(packageDoc);
1020 protected String possiblyQualifiedName(Type type)
1022 if (null == type.asClassDoc()
1023 || !omitPackageQualifier(type.asClassDoc().containingPackage())) {
1024 return type.qualifiedTypeName();
1026 else {
1027 return type.typeName();
1031 protected static class InterfaceRelation
1033 public Set superInterfaces;
1034 public Set subInterfaces;
1035 public Set implementingClasses;
1037 public InterfaceRelation()
1039 superInterfaces = new TreeSet();
1040 subInterfaces = new TreeSet();
1041 implementingClasses = new TreeSet();
1045 private void addAllInterfaces(ClassDoc classDoc, Set allInterfaces)
1047 ClassDoc[] interfaces = classDoc.interfaces();
1048 for (int i=0; i<interfaces.length; ++i) {
1049 allInterfaces.add(interfaces[i]);
1050 addAllInterfaces(interfaces[i], allInterfaces);
1054 private Map allSubClasses;
1056 protected Map getAllSubClasses()
1058 if (null == allSubClasses) {
1059 allSubClasses = new HashMap();
1061 ClassDoc[] classDocs = getRootDoc().classes();
1062 for (int i=0; i<classDocs.length; ++i) {
1063 if (!classDocs[i].isInterface()) {
1064 for (ClassDoc cd = classDocs[i].superclass();
1065 null != cd;
1066 cd = cd.superclass()) {
1068 if (!cd.qualifiedTypeName().equals("java.lang.Object")) {
1069 List subClasses = (List)allSubClasses.get(cd);
1070 if (null == subClasses) {
1071 subClasses = new LinkedList();
1072 allSubClasses.put(cd, subClasses);
1074 subClasses.add(classDocs[i]);
1080 return allSubClasses;
1083 private Map interfaceRelations;
1085 private void addToInterfaces(ClassDoc classDoc, ClassDoc[] interfaces)
1087 for (int i=0; i<interfaces.length; ++i) {
1088 InterfaceRelation interfaceRelation
1089 = (InterfaceRelation)interfaceRelations.get(interfaces[i]);
1090 if (null == interfaceRelation) {
1091 interfaceRelation = new InterfaceRelation();
1092 interfaceRelations.put(interfaces[i], interfaceRelation);
1094 interfaceRelation.implementingClasses.add(classDoc);
1095 addToInterfaces(classDoc, interfaces[i].interfaces());
1099 protected Map getInterfaceRelations()
1101 if (null == interfaceRelations) {
1102 interfaceRelations = new HashMap();
1104 ClassDoc[] classDocs = getRootDoc().classes();
1105 for (int i=0; i<classDocs.length; ++i) {
1106 if (classDocs[i].isInterface()) {
1107 InterfaceRelation relation = new InterfaceRelation();
1108 addAllInterfaces(classDocs[i], relation.superInterfaces);
1109 interfaceRelations.put(classDocs[i], relation);
1113 Iterator it = interfaceRelations.keySet().iterator();
1114 while (it.hasNext()) {
1115 ClassDoc interfaceDoc = (ClassDoc)it.next();
1116 InterfaceRelation relation
1117 = (InterfaceRelation)interfaceRelations.get(interfaceDoc);
1118 Iterator superIt = relation.superInterfaces.iterator();
1119 while (superIt.hasNext()) {
1120 ClassDoc superInterfaceDoc = (ClassDoc)superIt.next();
1121 InterfaceRelation superRelation
1122 = (InterfaceRelation)interfaceRelations.get(superInterfaceDoc);
1123 if (null != superRelation) {
1124 superRelation.subInterfaces.add(interfaceDoc);
1129 for (int i=0; i<classDocs.length; ++i) {
1130 if (!classDocs[i].isInterface()) {
1131 for (ClassDoc cd = classDocs[i]; null != cd; cd = cd.superclass()) {
1132 addToInterfaces(classDocs[i], cd.interfaces());
1138 return interfaceRelations;
1141 private Map sortedMethodMap = new HashMap();
1143 protected MethodDoc[] getSortedMethods(ClassDoc classDoc)
1145 MethodDoc[] result = (MethodDoc[])sortedMethodMap.get(classDoc);
1146 if (null == result) {
1147 MethodDoc[] methods = classDoc.methods();
1148 result = (MethodDoc[])methods.clone();
1149 Arrays.sort(result);
1150 return result;
1152 return result;
1155 private Map sortedConstructorMap = new HashMap();
1157 protected ConstructorDoc[] getSortedConstructors(ClassDoc classDoc)
1159 ConstructorDoc[] result = (ConstructorDoc[])sortedConstructorMap.get(classDoc);
1160 if (null == result) {
1161 ConstructorDoc[] constructors = classDoc.constructors();
1162 result = (ConstructorDoc[])constructors.clone();
1163 Arrays.sort(result);
1164 return result;
1166 return result;
1169 private Map sortedFieldMap = new HashMap();
1171 protected FieldDoc[] getSortedFields(ClassDoc classDoc)
1173 FieldDoc[] result = (FieldDoc[])sortedFieldMap.get(classDoc);
1174 if (null == result) {
1175 FieldDoc[] fields = classDoc.fields();
1176 result = (FieldDoc[])fields.clone();
1177 Arrays.sort(result);
1178 return result;
1180 return result;
1183 private Map sortedInnerClassMap = new HashMap();
1185 protected ClassDoc[] getSortedInnerClasses(ClassDoc classDoc)
1187 ClassDoc[] result = (ClassDoc[])sortedInnerClassMap.get(classDoc);
1188 if (null == result) {
1189 ClassDoc[] innerClasses = classDoc.innerClasses();
1190 result = (ClassDoc[])innerClasses.clone();
1191 Arrays.sort(result);
1192 return result;
1194 return result;
1197 protected abstract String renderTag(String tagName, Tag[] tags, TagletContext context);
1199 protected abstract String getDocletVersion();
1201 protected SortedSet getThrownExceptions(ExecutableMemberDoc execMemberDoc)
1203 SortedSet result = new TreeSet();
1204 ClassDoc[] thrownExceptions = execMemberDoc.thrownExceptions();
1205 for (int j=0; j<thrownExceptions.length; ++j) {
1206 result.add(thrownExceptions[j]);
1208 return result;
1211 protected boolean isUncheckedException(ClassDoc classDoc)
1213 if (classDoc.isException()) {
1214 while (null != classDoc) {
1215 if (classDoc.qualifiedTypeName().equals("java.lang.RuntimeException")) {
1216 return true;
1218 classDoc = classDoc.superclass();
1220 return false;
1222 else {
1223 return false;
1227 protected FieldDoc findField(ClassDoc classDoc, String fieldName)
1229 for (ClassDoc cd = classDoc; cd != null; cd = cd.superclass()) {
1230 FieldDoc[] fields = cd.fields(false);
1231 for (int i=0; i<fields.length; ++i) {
1232 if (fields[i].name().equals(fieldName)) {
1233 return fields[i];
1237 return null;
1240 private Map implementedInterfacesCache = new HashMap();
1242 protected Set getImplementedInterfaces(ClassDoc classDoc)
1244 Set result = (Set)implementedInterfacesCache.get(classDoc);
1245 if (null == result) {
1246 result = new TreeSet();
1248 for (ClassDoc cd = classDoc; cd != null; cd = cd.superclass()) {
1249 ClassDoc[] interfaces = cd.interfaces();
1250 for (int i=0; i<interfaces.length; ++i) {
1251 result.add(interfaces[i]);
1252 InterfaceRelation relation
1253 = (InterfaceRelation)getInterfaceRelations().get(interfaces[i]);
1254 if (null != relation) {
1255 result.addAll(relation.superInterfaces);
1260 implementedInterfacesCache.put(classDoc, result);
1263 return result;
1266 protected boolean isSinglePackage()
1268 return getAllPackages().size() <= 1;
1271 protected PackageDoc getSinglePackage()
1273 return (PackageDoc)getAllPackages().iterator().next();