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

Mon, 15 Oct 2012 17:07:55 -0700

author
jjg
date
Mon, 15 Oct 2012 17:07:55 -0700
changeset 1364
8db45b13526e
parent 1360
560d4a5d14e6
child 1372
78962d89f283
permissions
-rw-r--r--

8000666: javadoc should write directly to Writer instead of composing strings
Reviewed-by: bpatel

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

mercurial