src/share/classes/com/sun/tools/doclets/internal/toolkit/util/Util.java

Fri, 04 Mar 2011 19:53:03 -0800

author
jjg
date
Fri, 04 Mar 2011 19:53:03 -0800
changeset 910
ebf7c13df6c0
parent 798
4868a36f6fd8
child 972
694ff82ca68e
permissions
-rw-r--r--

6866185: Util.getPackageSourcePath should use lastIndexOf not indexOf and related cleanup
Reviewed-by: bpatel

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

mercurial