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