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

Tue, 09 Oct 2012 19:10:00 -0700

author
jjg
date
Tue, 09 Oct 2012 19:10:00 -0700
changeset 1357
c75be5bc5283
parent 1116
d830d28fc72e
child 1359
25e14ad23cef
permissions
-rw-r--r--

8000663: clean up langtools imports
Reviewed-by: darcy

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

mercurial