src/share/classes/com/sun/tools/javadoc/DocletInvoker.java

Fri, 04 Mar 2011 19:59:04 -0800

author
jjg
date
Fri, 04 Mar 2011 19:59:04 -0800
changeset 912
5e6c661891da
parent 798
4868a36f6fd8
child 1116
d830d28fc72e
permissions
-rw-r--r--

6964914: javadoc does not output number of warnings using user written doclet
Reviewed-by: bpatel

     1 /*
     2  * Copyright (c) 1998, 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.javadoc;
    28 import com.sun.javadoc.*;
    30 import static com.sun.javadoc.LanguageVersion.*;
    32 import com.sun.tools.javac.util.List;
    34 import java.io.File;
    35 import java.lang.reflect.Method;
    36 import java.lang.reflect.Modifier;
    37 import java.lang.reflect.InvocationTargetException;
    38 import java.net.URL;
    39 import java.net.URLClassLoader;
    42 /**
    43  * Class creates, controls and invokes doclets.
    44  * @author Neal Gafter (rewrite)
    45  */
    46 public class DocletInvoker {
    48     private final Class<?> docletClass;
    50     private final String docletClassName;
    52     private final ClassLoader appClassLoader;
    54     private final Messager messager;
    56     private static class DocletInvokeException extends Exception {
    57         private static final long serialVersionUID = 0;
    58     }
    60     private String appendPath(String path1, String path2) {
    61         if (path1 == null || path1.length() == 0) {
    62             return path2 == null ? "." : path2;
    63         } else if (path2 == null || path2.length() == 0) {
    64             return path1;
    65         } else {
    66             return path1  + File.pathSeparator + path2;
    67         }
    68     }
    70     public DocletInvoker(Messager messager,
    71                          String docletClassName, String docletPath,
    72                          ClassLoader docletParentClassLoader) {
    73         this.messager = messager;
    74         this.docletClassName = docletClassName;
    76         // construct class loader
    77         String cpString = null;   // make sure env.class.path defaults to dot
    79         // do prepends to get correct ordering
    80         cpString = appendPath(System.getProperty("env.class.path"), cpString);
    81         cpString = appendPath(System.getProperty("java.class.path"), cpString);
    82         cpString = appendPath(docletPath, cpString);
    83         URL[] urls = com.sun.tools.javac.file.Paths.pathToURLs(cpString);
    84         if (docletParentClassLoader == null)
    85             appClassLoader = new URLClassLoader(urls, getDelegationClassLoader(docletClassName));
    86         else
    87             appClassLoader = new URLClassLoader(urls, docletParentClassLoader);
    89         // attempt to find doclet
    90         Class<?> dc = null;
    91         try {
    92             dc = appClassLoader.loadClass(docletClassName);
    93         } catch (ClassNotFoundException exc) {
    94             messager.error(null, "main.doclet_class_not_found", docletClassName);
    95             messager.exit();
    96         }
    97         docletClass = dc;
    98     }
   100     /*
   101      * Returns the delegation class loader to use when creating
   102      * appClassLoader (used to load the doclet).  The context class
   103      * loader is the best choice, but legacy behavior was to use the
   104      * default delegation class loader (aka system class loader).
   105      *
   106      * Here we favor using the context class loader.  To ensure
   107      * compatibility with existing apps, we revert to legacy
   108      * behavior if either or both of the following conditions hold:
   109      *
   110      * 1) the doclet is loadable from the system class loader but not
   111      *    from the context class loader,
   112      *
   113      * 2) this.getClass() is loadable from the system class loader but not
   114      *    from the context class loader.
   115      */
   116     private ClassLoader getDelegationClassLoader(String docletClassName) {
   117         ClassLoader ctxCL = Thread.currentThread().getContextClassLoader();
   118         ClassLoader sysCL = ClassLoader.getSystemClassLoader();
   119         if (sysCL == null)
   120             return ctxCL;
   121         if (ctxCL == null)
   122             return sysCL;
   124         // Condition 1.
   125         try {
   126             sysCL.loadClass(docletClassName);
   127             try {
   128                 ctxCL.loadClass(docletClassName);
   129             } catch (ClassNotFoundException e) {
   130                 return sysCL;
   131             }
   132         } catch (ClassNotFoundException e) {
   133         }
   135         // Condition 2.
   136         try {
   137             if (getClass() == sysCL.loadClass(getClass().getName())) {
   138                 try {
   139                     if (getClass() != ctxCL.loadClass(getClass().getName()))
   140                         return sysCL;
   141                 } catch (ClassNotFoundException e) {
   142                     return sysCL;
   143                 }
   144             }
   145         } catch (ClassNotFoundException e) {
   146         }
   148         return ctxCL;
   149     }
   151     /**
   152      * Generate documentation here.  Return true on success.
   153      */
   154     public boolean start(RootDoc root) {
   155         Object retVal;
   156         String methodName = "start";
   157         Class<?>[] paramTypes = { RootDoc.class };
   158         Object[] params = { root };
   159         try {
   160             retVal = invoke(methodName, null, paramTypes, params);
   161         } catch (DocletInvokeException exc) {
   162             return false;
   163         }
   164         if (retVal instanceof Boolean) {
   165             return ((Boolean)retVal).booleanValue();
   166         } else {
   167             messager.error(null, "main.must_return_boolean",
   168                            docletClassName, methodName);
   169             return false;
   170         }
   171     }
   173     /**
   174      * Check for doclet added options here. Zero return means
   175      * option not known.  Positive value indicates number of
   176      * arguments to option.  Negative value means error occurred.
   177      */
   178     public int optionLength(String option) {
   179         Object retVal;
   180         String methodName = "optionLength";
   181         Class<?>[] paramTypes = { String.class };
   182         Object[] params = { option };
   183         try {
   184             retVal = invoke(methodName, new Integer(0), paramTypes, params);
   185         } catch (DocletInvokeException exc) {
   186             return -1;
   187         }
   188         if (retVal instanceof Integer) {
   189             return ((Integer)retVal).intValue();
   190         } else {
   191             messager.error(null, "main.must_return_int",
   192                            docletClassName, methodName);
   193             return -1;
   194         }
   195     }
   197     /**
   198      * Let doclet check that all options are OK. Returning true means
   199      * options are OK.  If method does not exist, assume true.
   200      */
   201     public boolean validOptions(List<String[]> optlist) {
   202         Object retVal;
   203         String options[][] = optlist.toArray(new String[optlist.length()][]);
   204         String methodName = "validOptions";
   205         DocErrorReporter reporter = messager;
   206         Class<?>[] paramTypes = { String[][].class, DocErrorReporter.class };
   207         Object[] params = { options, reporter };
   208         try {
   209             retVal = invoke(methodName, Boolean.TRUE, paramTypes, params);
   210         } catch (DocletInvokeException exc) {
   211             return false;
   212         }
   213         if (retVal instanceof Boolean) {
   214             return ((Boolean)retVal).booleanValue();
   215         } else {
   216             messager.error(null, "main.must_return_boolean",
   217                            docletClassName, methodName);
   218             return false;
   219         }
   220     }
   222     /**
   223      * Return the language version supported by this doclet.
   224      * If the method does not exist in the doclet, assume version 1.1.
   225      */
   226     public LanguageVersion languageVersion() {
   227         try {
   228             Object retVal;
   229             String methodName = "languageVersion";
   230             Class<?>[] paramTypes = new Class<?>[0];
   231             Object[] params = new Object[0];
   232             try {
   233                 retVal = invoke(methodName, JAVA_1_1, paramTypes, params);
   234             } catch (DocletInvokeException exc) {
   235                 return JAVA_1_1;
   236             }
   237             if (retVal instanceof LanguageVersion) {
   238                 return (LanguageVersion)retVal;
   239             } else {
   240                 messager.error(null, "main.must_return_languageversion",
   241                                docletClassName, methodName);
   242                 return JAVA_1_1;
   243             }
   244         } catch (NoClassDefFoundError ex) { // for boostrapping, no Enum class.
   245             return null;
   246         }
   247     }
   249     /**
   250      * Utility method for calling doclet functionality
   251      */
   252     private Object invoke(String methodName, Object returnValueIfNonExistent,
   253                           Class<?>[] paramTypes, Object[] params)
   254         throws DocletInvokeException {
   255             Method meth;
   256             try {
   257                 meth = docletClass.getMethod(methodName, paramTypes);
   258             } catch (NoSuchMethodException exc) {
   259                 if (returnValueIfNonExistent == null) {
   260                     messager.error(null, "main.doclet_method_not_found",
   261                                    docletClassName, methodName);
   262                     throw new DocletInvokeException();
   263                 } else {
   264                     return returnValueIfNonExistent;
   265                 }
   266             } catch (SecurityException exc) {
   267                 messager.error(null, "main.doclet_method_not_accessible",
   268                                docletClassName, methodName);
   269                 throw new DocletInvokeException();
   270             }
   271             if (!Modifier.isStatic(meth.getModifiers())) {
   272                 messager.error(null, "main.doclet_method_must_be_static",
   273                                docletClassName, methodName);
   274                 throw new DocletInvokeException();
   275             }
   276             ClassLoader savedCCL =
   277                 Thread.currentThread().getContextClassLoader();
   278             try {
   279                 Thread.currentThread().setContextClassLoader(appClassLoader);
   280                 return meth.invoke(null , params);
   281             } catch (IllegalArgumentException exc) {
   282                 messager.error(null, "main.internal_error_exception_thrown",
   283                                docletClassName, methodName, exc.toString());
   284                 throw new DocletInvokeException();
   285             } catch (IllegalAccessException exc) {
   286                 messager.error(null, "main.doclet_method_not_accessible",
   287                                docletClassName, methodName);
   288                 throw new DocletInvokeException();
   289             } catch (NullPointerException exc) {
   290                 messager.error(null, "main.internal_error_exception_thrown",
   291                                docletClassName, methodName, exc.toString());
   292                 throw new DocletInvokeException();
   293             } catch (InvocationTargetException exc) {
   294                 Throwable err = exc.getTargetException();
   295                 if (err instanceof java.lang.OutOfMemoryError) {
   296                     messager.error(null, "main.out.of.memory");
   297                 } else {
   298                 messager.error(null, "main.exception_thrown",
   299                                docletClassName, methodName, exc.toString());
   300                     exc.getTargetException().printStackTrace();
   301                 }
   302                 throw new DocletInvokeException();
   303             } finally {
   304                 Thread.currentThread().setContextClassLoader(savedCCL);
   305             }
   306     }
   307 }

mercurial