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

Fri, 11 Jun 2010 17:24:23 -0700

author
jjg
date
Fri, 11 Jun 2010 17:24:23 -0700
changeset 584
d1ea43cb71c1
parent 554
9d9f26857129
child 798
4868a36f6fd8
permissions
-rw-r--r--

6958836: javadoc should support -Xmaxerrs and -Xmaxwarns
Reviewed-by: darcy

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

mercurial