Tue, 20 Jan 2009 15:17:45 -0800
6794582: javadoc should read files using a FileManager
Reviewed-by: darcy, bpatel
1 /*
2 * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
26 package com.sun.tools.doclets.internal.toolkit.util;
28 import java.io.*;
29 import java.util.*;
31 import com.sun.javadoc.*;
32 import com.sun.tools.doclets.internal.toolkit.*;
34 /**
35 * Utilities Class for Doclets.
36 *
37 * This code is not part of an API.
38 * It is implementation that is subject to change.
39 * Do not use it as an API
40 *
41 * @author Atul M Dambalkar
42 * @author Jamie Ho
43 */
44 public class Util {
46 /**
47 * A mapping between characters and their
48 * corresponding HTML escape character.
49 */
50 public static final String[][] HTML_ESCAPE_CHARS =
51 {{"&", "&"}, {"<", "<"}, {">", ">"}};
53 /**
54 * Return array of class members whose documentation is to be generated.
55 * If the member is deprecated do not include such a member in the
56 * returned array.
57 *
58 * @param members Array of members to choose from.
59 * @return ProgramElementDoc[] Array of eligible members for whom
60 * documentation is getting generated.
61 */
62 public static ProgramElementDoc[] excludeDeprecatedMembers(
63 ProgramElementDoc[] members) {
64 return
65 toProgramElementDocArray(excludeDeprecatedMembersAsList(members));
66 }
68 /**
69 * Return array of class members whose documentation is to be generated.
70 * If the member is deprecated do not include such a member in the
71 * returned array.
72 *
73 * @param members Array of members to choose from.
74 * @return List List of eligible members for whom
75 * documentation is getting generated.
76 */
77 public static List<ProgramElementDoc> excludeDeprecatedMembersAsList(
78 ProgramElementDoc[] members) {
79 List<ProgramElementDoc> list = new ArrayList<ProgramElementDoc>();
80 for (int i = 0; i < members.length; i++) {
81 if (members[i].tags("deprecated").length == 0) {
82 list.add(members[i]);
83 }
84 }
85 Collections.sort(list);
86 return list;
87 }
89 /**
90 * Return the list of ProgramElementDoc objects as Array.
91 */
92 public static ProgramElementDoc[] toProgramElementDocArray(List<ProgramElementDoc> list) {
93 ProgramElementDoc[] pgmarr = new ProgramElementDoc[list.size()];
94 for (int i = 0; i < list.size(); i++) {
95 pgmarr[i] = list.get(i);
96 }
97 return pgmarr;
98 }
100 /**
101 * Return true if a non-public member found in the given array.
102 *
103 * @param members Array of members to look into.
104 * @return boolean True if non-public member found, false otherwise.
105 */
106 public static boolean nonPublicMemberFound(ProgramElementDoc[] members) {
107 for (int i = 0; i < members.length; i++) {
108 if (!members[i].isPublic()) {
109 return true;
110 }
111 }
112 return false;
113 }
115 /**
116 * Search for the given method in the given class.
117 *
118 * @param cd Class to search into.
119 * @param method Method to be searched.
120 * @return MethodDoc Method found, null otherwise.
121 */
122 public static MethodDoc findMethod(ClassDoc cd, MethodDoc method) {
123 MethodDoc[] methods = cd.methods();
124 for (int i = 0; i < methods.length; i++) {
125 if (executableMembersEqual(method, methods[i])) {
126 return methods[i];
128 }
129 }
130 return null;
131 }
133 /**
134 * @param member1 the first method to compare.
135 * @param member2 the second method to compare.
136 * @return true if member1 overrides/hides or is overriden/hidden by member2.
137 */
138 public static boolean executableMembersEqual(ExecutableMemberDoc member1,
139 ExecutableMemberDoc member2) {
140 if (! (member1 instanceof MethodDoc && member2 instanceof MethodDoc))
141 return false;
143 MethodDoc method1 = (MethodDoc) member1;
144 MethodDoc method2 = (MethodDoc) member2;
145 if (method1.isStatic() && method2.isStatic()) {
146 Parameter[] targetParams = method1.parameters();
147 Parameter[] currentParams;
148 if (method1.name().equals(method2.name()) &&
149 (currentParams = method2.parameters()).length ==
150 targetParams.length) {
151 int j;
152 for (j = 0; j < targetParams.length; j++) {
153 if (! (targetParams[j].typeName().equals(
154 currentParams[j].typeName()) ||
155 currentParams[j].type() instanceof TypeVariable ||
156 targetParams[j].type() instanceof TypeVariable)) {
157 break;
158 }
159 }
160 if (j == targetParams.length) {
161 return true;
162 }
163 }
164 return false;
165 } else {
166 return method1.overrides(method2) ||
167 method2.overrides(method1) ||
168 member1 == member2;
169 }
170 }
172 /**
173 * According to the Java Language Specifications, all the outer classes
174 * and static inner classes are core classes.
175 */
176 public static boolean isCoreClass(ClassDoc cd) {
177 return cd.containingClass() == null || cd.isStatic();
178 }
180 public static boolean matches(ProgramElementDoc doc1,
181 ProgramElementDoc doc2) {
182 if (doc1 instanceof ExecutableMemberDoc &&
183 doc2 instanceof ExecutableMemberDoc) {
184 ExecutableMemberDoc ed1 = (ExecutableMemberDoc)doc1;
185 ExecutableMemberDoc ed2 = (ExecutableMemberDoc)doc2;
186 return executableMembersEqual(ed1, ed2);
187 } else {
188 return doc1.name().equals(doc2.name());
189 }
190 }
192 /**
193 * Copy source file to destination file.
194 *
195 * @throws SecurityException
196 * @throws IOException
197 */
198 public static void copyFile(File destfile, File srcfile)
199 throws IOException {
200 byte[] bytearr = new byte[512];
201 int len = 0;
202 FileInputStream input = new FileInputStream(srcfile);
203 File destDir = destfile.getParentFile();
204 destDir.mkdirs();
205 FileOutputStream output = new FileOutputStream(destfile);
206 try {
207 while ((len = input.read(bytearr)) != -1) {
208 output.write(bytearr, 0, len);
209 }
210 } catch (FileNotFoundException exc) {
211 } catch (SecurityException exc) {
212 } finally {
213 input.close();
214 output.close();
215 }
216 }
218 /**
219 * Copy the given directory contents from the source package directory
220 * to the generated documentation directory. For example for a package
221 * java.lang this method find out the source location of the package using
222 * {@link SourcePath} and if given directory is found in the source
223 * directory structure, copy the entire directory, to the generated
224 * documentation hierarchy.
225 *
226 * @param configuration The configuration of the current doclet.
227 * @param path The relative path to the directory to be copied.
228 * @param dir The original directory name to copy from.
229 * @param overwrite Overwrite files if true.
230 */
231 public static void copyDocFiles(Configuration configuration,
232 String path, String dir, boolean overwrite) {
233 if (checkCopyDocFilesErrors(configuration, path, dir)) {
234 return;
235 }
236 String destname = configuration.docFileDestDirName;
237 File srcdir = new File(path + dir);
238 if (destname.length() > 0 && !destname.endsWith(
239 DirectoryManager.URL_FILE_SEPERATOR)) {
240 destname += DirectoryManager.URL_FILE_SEPERATOR;
241 }
242 String dest = destname + dir;
243 try {
244 File destdir = new File(dest);
245 DirectoryManager.createDirectory(configuration, dest);
246 String[] files = srcdir.list();
247 for (int i = 0; i < files.length; i++) {
248 File srcfile = new File(srcdir, files[i]);
249 File destfile = new File(destdir, files[i]);
250 if (srcfile.isFile()) {
251 if(destfile.exists() && ! overwrite) {
252 configuration.message.warning((SourcePosition) null,
253 "doclet.Copy_Overwrite_warning",
254 srcfile.toString(), destdir.toString());
255 } else {
256 configuration.message.notice(
257 "doclet.Copying_File_0_To_Dir_1",
258 srcfile.toString(), destdir.toString());
259 Util.copyFile(destfile, srcfile);
260 }
261 } else if(srcfile.isDirectory()) {
262 if(configuration.copydocfilesubdirs
263 && ! configuration.shouldExcludeDocFileDir(
264 srcfile.getName())){
265 copyDocFiles(configuration, path, dir +
266 DirectoryManager.URL_FILE_SEPERATOR + srcfile.getName(),
267 overwrite);
268 }
269 }
270 }
271 } catch (SecurityException exc) {
272 throw new DocletAbortException();
273 } catch (IOException exc) {
274 throw new DocletAbortException();
275 }
276 }
278 /**
279 * Given the parameters for copying doc-files, check for errors.
280 *
281 * @param configuration The configuration of the current doclet.
282 * @param path The relative path to the directory to be copied.
283 * @param dirName The original directory name to copy from.
284 */
285 private static boolean checkCopyDocFilesErrors (Configuration configuration,
286 String path, String dirName) {
287 if ((configuration.sourcepath == null || configuration.sourcepath.length() == 0) &&
288 (configuration.destDirName == null || configuration.destDirName.length() == 0)) {
289 //The destination path and source path are definitely equal.
290 return true;
291 }
292 File sourcePath, destPath = new File(configuration.destDirName);
293 StringTokenizer pathTokens = new StringTokenizer(
294 configuration.sourcepath == null ? "" : configuration.sourcepath,
295 File.pathSeparator);
296 //Check if the destination path is equal to the source path. If yes,
297 //do not copy doc-file directories.
298 while(pathTokens.hasMoreTokens()){
299 sourcePath = new File(pathTokens.nextToken());
300 if(destPath.equals(sourcePath)){
301 return true;
302 }
303 }
304 //Make sure the doc-file being copied exists.
305 File srcdir = new File(path + dirName);
306 if (! srcdir.exists()) {
307 return true;
308 }
309 return false;
310 }
312 /**
313 * Copy a file in the resources directory to the destination
314 * directory (if it is not there already). If
315 * <code>overwrite</code> is true and the destination file
316 * already exists, overwrite it.
317 *
318 * @param configuration Holds the destination directory and error message
319 * @param resourcefile The name of the resource file to copy
320 * @param overwrite A flag to indicate whether the file in the
321 * destination directory will be overwritten if
322 * it already exists.
323 */
324 public static void copyResourceFile(Configuration configuration,
325 String resourcefile,
326 boolean overwrite) {
327 String destdir = configuration.destDirName;
328 String destresourcesdir = destdir + "resources";
329 DirectoryManager.createDirectory(configuration, destresourcesdir);
330 File destfile = new File(destresourcesdir, resourcefile);
331 if(destfile.exists() && (! overwrite)) return;
332 try {
334 InputStream in = Configuration.class.getResourceAsStream(
335 "resources/" + resourcefile);
337 if(in==null) return;
339 OutputStream out = new FileOutputStream(destfile);
340 byte[] buf = new byte[2048];
341 int n;
342 while((n = in.read(buf))>0) out.write(buf,0,n);
344 in.close();
345 out.close();
346 } catch(Throwable t) {}
347 }
349 /**
350 * Given a PackageDoc, return the source path for that package.
351 * @param configuration The Configuration for the current Doclet.
352 * @param pkgDoc The package to seach the path for.
353 * @return A string representing the path to the given package.
354 */
355 public static String getPackageSourcePath(Configuration configuration,
356 PackageDoc pkgDoc){
357 try{
358 String pkgPath = DirectoryManager.getDirectoryPath(pkgDoc);
359 String completePath = new SourcePath(configuration.sourcepath).
360 getDirectory(pkgPath) + DirectoryManager.URL_FILE_SEPERATOR;
361 //Make sure that both paths are using the same seperators.
362 completePath = Util.replaceText(completePath, File.separator,
363 DirectoryManager.URL_FILE_SEPERATOR);
364 pkgPath = Util.replaceText(pkgPath, File.separator,
365 DirectoryManager.URL_FILE_SEPERATOR);
366 return completePath.substring(0, completePath.indexOf(pkgPath));
367 } catch (Exception e){
368 return "";
369 }
370 }
372 /**
373 * We want the list of types in alphabetical order. However, types are not
374 * comparable. We need a comparator for now.
375 */
376 private static class TypeComparator implements Comparator<Type> {
377 public int compare(Type type1, Type type2) {
378 return type1.qualifiedTypeName().toLowerCase().compareTo(
379 type2.qualifiedTypeName().toLowerCase());
380 }
381 }
383 /**
384 * For the class return all implemented interfaces including the
385 * superinterfaces of the implementing interfaces, also iterate over for
386 * all the superclasses. For interface return all the extended interfaces
387 * as well as superinterfaces for those extended interfaces.
388 *
389 * @param type type whose implemented or
390 * super interfaces are sought.
391 * @param configuration the current configuration of the doclet.
392 * @param sort if true, return list of interfaces sorted alphabetically.
393 * @return List of all the required interfaces.
394 */
395 public static List<Type> getAllInterfaces(Type type,
396 Configuration configuration, boolean sort) {
397 Map<ClassDoc,Type> results = sort ? new TreeMap<ClassDoc,Type>() : new LinkedHashMap<ClassDoc,Type>();
398 Type[] interfaceTypes = null;
399 Type superType = null;
400 if (type instanceof ParameterizedType) {
401 interfaceTypes = ((ParameterizedType) type).interfaceTypes();
402 superType = ((ParameterizedType) type).superclassType();
403 } else if (type instanceof ClassDoc) {
404 interfaceTypes = ((ClassDoc) type).interfaceTypes();
405 superType = ((ClassDoc) type).superclassType();
406 } else {
407 interfaceTypes = type.asClassDoc().interfaceTypes();
408 superType = type.asClassDoc().superclassType();
409 }
411 for (int i = 0; i < interfaceTypes.length; i++) {
412 Type interfaceType = interfaceTypes[i];
413 ClassDoc interfaceClassDoc = interfaceType.asClassDoc();
414 if (! (interfaceClassDoc.isPublic() ||
415 (configuration == null ||
416 isLinkable(interfaceClassDoc, configuration)))) {
417 continue;
418 }
419 results.put(interfaceClassDoc, interfaceType);
420 List<Type> superInterfaces = getAllInterfaces(interfaceType, configuration, sort);
421 for (Iterator<Type> iter = superInterfaces.iterator(); iter.hasNext(); ) {
422 Type t = iter.next();
423 results.put(t.asClassDoc(), t);
424 }
425 }
426 if (superType == null)
427 return new ArrayList<Type>(results.values());
428 //Try walking the tree.
429 addAllInterfaceTypes(results,
430 superType,
431 superType instanceof ClassDoc ?
432 ((ClassDoc) superType).interfaceTypes() :
433 ((ParameterizedType) superType).interfaceTypes(),
434 false, configuration);
435 List<Type> resultsList = new ArrayList<Type>(results.values());
436 if (sort) {
437 Collections.sort(resultsList, new TypeComparator());
438 }
439 return resultsList;
440 }
442 public static List<Type> getAllInterfaces(Type type, Configuration configuration) {
443 return getAllInterfaces(type, configuration, true);
444 }
446 private static void findAllInterfaceTypes(Map<ClassDoc,Type> results, ClassDoc c, boolean raw,
447 Configuration configuration) {
448 Type superType = c.superclassType();
449 if (superType == null)
450 return;
451 addAllInterfaceTypes(results, superType,
452 superType instanceof ClassDoc ?
453 ((ClassDoc) superType).interfaceTypes() :
454 ((ParameterizedType) superType).interfaceTypes(),
455 raw, configuration);
456 }
458 private static void findAllInterfaceTypes(Map<ClassDoc,Type> results, ParameterizedType p,
459 Configuration configuration) {
460 Type superType = p.superclassType();
461 if (superType == null)
462 return;
463 addAllInterfaceTypes(results, superType,
464 superType instanceof ClassDoc ?
465 ((ClassDoc) superType).interfaceTypes() :
466 ((ParameterizedType) superType).interfaceTypes(),
467 false, configuration);
468 }
470 private static void addAllInterfaceTypes(Map<ClassDoc,Type> results, Type type,
471 Type[] interfaceTypes, boolean raw,
472 Configuration configuration) {
473 for (int i = 0; i < interfaceTypes.length; i++) {
474 Type interfaceType = interfaceTypes[i];
475 ClassDoc interfaceClassDoc = interfaceType.asClassDoc();
476 if (! (interfaceClassDoc.isPublic() ||
477 (configuration != null &&
478 isLinkable(interfaceClassDoc, configuration)))) {
479 continue;
480 }
481 if (raw)
482 interfaceType = interfaceType.asClassDoc();
483 results.put(interfaceClassDoc, interfaceType);
484 List<Type> superInterfaces = getAllInterfaces(interfaceType, configuration);
485 for (Iterator<Type> iter = superInterfaces.iterator(); iter.hasNext(); ) {
486 Type superInterface = iter.next();
487 results.put(superInterface.asClassDoc(), superInterface);
488 }
489 }
490 if (type instanceof ParameterizedType)
491 findAllInterfaceTypes(results, (ParameterizedType) type, configuration);
492 else if (((ClassDoc) type).typeParameters().length == 0)
493 findAllInterfaceTypes(results, (ClassDoc) type, raw, configuration);
494 else
495 findAllInterfaceTypes(results, (ClassDoc) type, true, configuration);
496 }
499 public static <T extends ProgramElementDoc> List<T> asList(T[] members) {
500 List<T> list = new ArrayList<T>();
501 for (int i = 0; i < members.length; i++) {
502 list.add(members[i]);
503 }
504 return list;
505 }
507 /**
508 * Enclose in quotes, used for paths and filenames that contains spaces
509 */
510 public static String quote(String filepath) {
511 return ("\"" + filepath + "\"");
512 }
514 /**
515 * Given a package, return it's name.
516 * @param packageDoc the package to check.
517 * @return the name of the given package.
518 */
519 public static String getPackageName(PackageDoc packageDoc) {
520 return packageDoc == null || packageDoc.name().length() == 0 ?
521 DocletConstants.DEFAULT_PACKAGE_NAME : packageDoc.name();
522 }
524 /**
525 * Given a package, return it's file name without the extension.
526 * @param packageDoc the package to check.
527 * @return the file name of the given package.
528 */
529 public static String getPackageFileHeadName(PackageDoc packageDoc) {
530 return packageDoc == null || packageDoc.name().length() == 0 ?
531 DocletConstants.DEFAULT_PACKAGE_FILE_NAME : packageDoc.name();
532 }
534 /**
535 * Given a string, replace all occurraces of 'newStr' with 'oldStr'.
536 * @param originalStr the string to modify.
537 * @param oldStr the string to replace.
538 * @param newStr the string to insert in place of the old string.
539 */
540 public static String replaceText(String originalStr, String oldStr,
541 String newStr) {
542 if (oldStr == null || newStr == null || oldStr.equals(newStr)) {
543 return originalStr;
544 }
545 StringBuffer result = new StringBuffer(originalStr);
546 int startIndex = 0;
547 while ((startIndex = result.indexOf(oldStr, startIndex)) != -1) {
548 result = result.replace(startIndex, startIndex + oldStr.length(),
549 newStr);
550 startIndex += newStr.length();
551 }
552 return result.toString();
553 }
555 /**
556 * Given a string, escape all special html characters and
557 * return the result.
558 *
559 * @param s The string to check.
560 * @return the original string with all of the HTML characters
561 * escaped.
562 *
563 * @see #HTML_ESCAPE_CHARS
564 */
565 public static String escapeHtmlChars(String s) {
566 String result = s;
567 for (int i = 0; i < HTML_ESCAPE_CHARS.length; i++) {
568 result = Util.replaceText(result,
569 HTML_ESCAPE_CHARS[i][0], HTML_ESCAPE_CHARS[i][1]);
570 }
571 return result;
572 }
574 /**
575 * Create the directory path for the file to be generated, construct
576 * FileOutputStream and OutputStreamWriter depending upon docencoding.
577 *
578 * @param path The directory path to be created for this file.
579 * @param filename File Name to which the PrintWriter will do the Output.
580 * @param docencoding Encoding to be used for this file.
581 * @exception IOException Exception raised by the FileWriter is passed on
582 * to next level.
583 * @exception UnsupportedEncodingException Exception raised by the
584 * OutputStreamWriter is passed on to next level.
585 * @return Writer Writer for the file getting generated.
586 * @see java.io.FileOutputStream
587 * @see java.io.OutputStreamWriter
588 */
589 public static Writer genWriter(Configuration configuration,
590 String path, String filename,
591 String docencoding)
592 throws IOException, UnsupportedEncodingException {
593 FileOutputStream fos;
594 if (path != null) {
595 DirectoryManager.createDirectory(configuration, path);
596 fos = new FileOutputStream(((path.length() > 0)?
597 path + File.separator: "") + filename);
598 } else {
599 fos = new FileOutputStream(filename);
600 }
601 if (docencoding == null) {
602 return new OutputStreamWriter(fos);
603 } else {
604 return new OutputStreamWriter(fos, docencoding);
605 }
606 }
608 /**
609 * Given an annotation, return true if it should be documented and false
610 * otherwise.
611 *
612 * @param annotationDoc the annotation to check.
613 *
614 * @return true return true if it should be documented and false otherwise.
615 */
616 public static boolean isDocumentedAnnotation(AnnotationTypeDoc annotationDoc) {
617 AnnotationDesc[] annotationDescList = annotationDoc.annotations();
618 for (int i = 0; i < annotationDescList.length; i++) {
619 if (annotationDescList[i].annotationType().qualifiedName().equals(
620 java.lang.annotation.Documented.class.getName())){
621 return true;
622 }
623 }
624 return false;
625 }
627 /**
628 * Given a string, return an array of tokens. The separator can be escaped
629 * with the '\' character. The '\' character may also be escaped by the
630 * '\' character.
631 *
632 * @param s the string to tokenize.
633 * @param separator the separator char.
634 * @param maxTokens the maxmimum number of tokens returned. If the
635 * max is reached, the remaining part of s is appended
636 * to the end of the last token.
637 *
638 * @return an array of tokens.
639 */
640 public static String[] tokenize(String s, char separator, int maxTokens) {
641 List<String> tokens = new ArrayList<String>();
642 StringBuilder token = new StringBuilder ();
643 boolean prevIsEscapeChar = false;
644 for (int i = 0; i < s.length(); i += Character.charCount(i)) {
645 int currentChar = s.codePointAt(i);
646 if (prevIsEscapeChar) {
647 // Case 1: escaped character
648 token.appendCodePoint(currentChar);
649 prevIsEscapeChar = false;
650 } else if (currentChar == separator && tokens.size() < maxTokens-1) {
651 // Case 2: separator
652 tokens.add(token.toString());
653 token = new StringBuilder();
654 } else if (currentChar == '\\') {
655 // Case 3: escape character
656 prevIsEscapeChar = true;
657 } else {
658 // Case 4: regular character
659 token.appendCodePoint(currentChar);
660 }
661 }
662 if (token.length() > 0) {
663 tokens.add(token.toString());
664 }
665 return tokens.toArray(new String[] {});
666 }
668 /**
669 * Return true if this class is linkable and false if we can't link to the
670 * desired class.
671 * <br>
672 * <b>NOTE:</b> You can only link to external classes if they are public or
673 * protected.
674 *
675 * @param classDoc the class to check.
676 * @param configuration the current configuration of the doclet.
677 *
678 * @return true if this class is linkable and false if we can't link to the
679 * desired class.
680 */
681 public static boolean isLinkable(ClassDoc classDoc,
682 Configuration configuration) {
683 return
684 ((classDoc.isIncluded() && configuration.isGeneratedDoc(classDoc))) ||
685 (configuration.extern.isExternal(classDoc) &&
686 (classDoc.isPublic() || classDoc.isProtected()));
687 }
689 /**
690 * Given a class, return the closest visible super class.
691 *
692 * @param classDoc the class we are searching the parent for.
693 * @param configuration the current configuration of the doclet.
694 * @return the closest visible super class. Return null if it cannot
695 * be found (i.e. classDoc is java.lang.Object).
696 */
697 public static Type getFirstVisibleSuperClass(ClassDoc classDoc,
698 Configuration configuration) {
699 if (classDoc == null) {
700 return null;
701 }
702 Type sup = classDoc.superclassType();
703 ClassDoc supClassDoc = classDoc.superclass();
704 while (sup != null &&
705 (! (supClassDoc.isPublic() ||
706 isLinkable(supClassDoc, configuration))) ) {
707 if (supClassDoc.superclass().qualifiedName().equals(supClassDoc.qualifiedName()))
708 break;
709 sup = supClassDoc.superclassType();
710 supClassDoc = supClassDoc.superclass();
711 }
712 if (classDoc.equals(supClassDoc)) {
713 return null;
714 }
715 return sup;
716 }
718 /**
719 * Given a class, return the closest visible super class.
720 *
721 * @param classDoc the class we are searching the parent for.
722 * @param configuration the current configuration of the doclet.
723 * @return the closest visible super class. Return null if it cannot
724 * be found (i.e. classDoc is java.lang.Object).
725 */
726 public static ClassDoc getFirstVisibleSuperClassCD(ClassDoc classDoc,
727 Configuration configuration) {
728 if (classDoc == null) {
729 return null;
730 }
731 ClassDoc supClassDoc = classDoc.superclass();
732 while (supClassDoc != null &&
733 (! (supClassDoc.isPublic() ||
734 isLinkable(supClassDoc, configuration))) ) {
735 supClassDoc = supClassDoc.superclass();
736 }
737 if (classDoc.equals(supClassDoc)) {
738 return null;
739 }
740 return supClassDoc;
741 }
743 /**
744 * Given a ClassDoc, return the name of its type (Class, Interface, etc.).
745 *
746 * @param cd the ClassDoc to check.
747 * @param lowerCaseOnly true if you want the name returned in lower case.
748 * If false, the first letter of the name is capatilized.
749 * @return
750 */
751 public static String getTypeName(Configuration config,
752 ClassDoc cd, boolean lowerCaseOnly) {
753 String typeName = "";
754 if (cd.isOrdinaryClass()) {
755 typeName = "doclet.Class";
756 } else if (cd.isInterface()) {
757 typeName = "doclet.Interface";
758 } else if (cd.isException()) {
759 typeName = "doclet.Exception";
760 } else if (cd.isError()) {
761 typeName = "doclet.Error";
762 } else if (cd.isAnnotationType()) {
763 typeName = "doclet.AnnotationType";
764 } else if (cd.isEnum()) {
765 typeName = "doclet.Enum";
766 }
767 return config.getText(
768 lowerCaseOnly ? typeName.toLowerCase() : typeName);
769 }
771 /**
772 * Given a string, replace all tabs with the appropriate
773 * number of spaces.
774 * @param tabLength the length of each tab.
775 * @param s the String to scan.
776 */
777 public static void replaceTabs(int tabLength, StringBuffer s) {
778 int index, col;
779 StringBuffer whitespace;
780 while ((index = s.indexOf("\t")) != -1) {
781 whitespace = new StringBuffer();
782 col = index;
783 do {
784 whitespace.append(" ");
785 col++;
786 } while ((col%tabLength) != 0);
787 s.replace(index, index+1, whitespace.toString());
788 }
789 }
791 /**
792 * The documentation for values() and valueOf() in Enums are set by the
793 * doclet.
794 */
795 public static void setEnumDocumentation(Configuration configuration,
796 ClassDoc classDoc) {
797 MethodDoc[] methods = classDoc.methods();
798 for (int j = 0; j < methods.length; j++) {
799 MethodDoc currentMethod = methods[j];
800 if (currentMethod.name().equals("values") &&
801 currentMethod.parameters().length == 0) {
802 currentMethod.setRawCommentText(
803 configuration.getText("doclet.enum_values_doc", classDoc.name()));
804 } else if (currentMethod.name().equals("valueOf") &&
805 currentMethod.parameters().length == 1) {
806 Type paramType = currentMethod.parameters()[0].type();
807 if (paramType != null &&
808 paramType.qualifiedTypeName().equals(String.class.getName())) {
809 currentMethod.setRawCommentText(
810 configuration.getText("doclet.enum_valueof_doc"));
811 }
812 }
813 }
814 }
816 /**
817 * Return true if the given Doc is deprecated.
818 *
819 * @param doc the Doc to check.
820 * @return true if the given Doc is deprecated.
821 */
822 public static boolean isDeprecated(ProgramElementDoc doc) {
823 if (doc.tags("deprecated").length > 0) {
824 return true;
825 }
826 AnnotationDesc[] annotationDescList = doc.annotations();
827 for (int i = 0; i < annotationDescList.length; i++) {
828 if (annotationDescList[i].annotationType().qualifiedName().equals(
829 java.lang.Deprecated.class.getName())){
830 return true;
831 }
832 }
833 return false;
834 }
835 }