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

duke@1 1 /*
jjg@912 2 * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
duke@1 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@1 4 *
duke@1 5 * This code is free software; you can redistribute it and/or modify it
duke@1 6 * under the terms of the GNU General Public License version 2 only, as
ohair@554 7 * published by the Free Software Foundation. Oracle designates this
duke@1 8 * particular file as subject to the "Classpath" exception as provided
ohair@554 9 * by Oracle in the LICENSE file that accompanied this code.
duke@1 10 *
duke@1 11 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@1 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@1 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@1 14 * version 2 for more details (a copy is included in the LICENSE file that
duke@1 15 * accompanied this code).
duke@1 16 *
duke@1 17 * You should have received a copy of the GNU General Public License version
duke@1 18 * 2 along with this work; if not, write to the Free Software Foundation,
duke@1 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@1 20 *
ohair@554 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@554 22 * or visit www.oracle.com if you need additional information or have any
ohair@554 23 * questions.
duke@1 24 */
duke@1 25
duke@1 26 package com.sun.tools.javadoc;
duke@1 27
duke@1 28 import com.sun.javadoc.*;
duke@1 29
duke@1 30 import static com.sun.javadoc.LanguageVersion.*;
duke@1 31
duke@1 32 import com.sun.tools.javac.util.List;
duke@1 33
jjg@912 34 import java.io.File;
duke@1 35 import java.lang.reflect.Method;
duke@1 36 import java.lang.reflect.Modifier;
duke@1 37 import java.lang.reflect.InvocationTargetException;
jjg@912 38 import java.net.URL;
jjg@912 39 import java.net.URLClassLoader;
duke@1 40
duke@1 41
duke@1 42 /**
duke@1 43 * Class creates, controls and invokes doclets.
duke@1 44 * @author Neal Gafter (rewrite)
duke@1 45 */
duke@1 46 public class DocletInvoker {
duke@1 47
jjg@74 48 private final Class<?> docletClass;
duke@1 49
duke@1 50 private final String docletClassName;
duke@1 51
duke@1 52 private final ClassLoader appClassLoader;
duke@1 53
duke@1 54 private final Messager messager;
duke@1 55
duke@1 56 private static class DocletInvokeException extends Exception {
duke@1 57 private static final long serialVersionUID = 0;
duke@1 58 }
duke@1 59
duke@1 60 private String appendPath(String path1, String path2) {
duke@1 61 if (path1 == null || path1.length() == 0) {
duke@1 62 return path2 == null ? "." : path2;
duke@1 63 } else if (path2 == null || path2.length() == 0) {
duke@1 64 return path1;
duke@1 65 } else {
duke@1 66 return path1 + File.pathSeparator + path2;
duke@1 67 }
duke@1 68 }
duke@1 69
duke@1 70 public DocletInvoker(Messager messager,
jjg@129 71 String docletClassName, String docletPath,
jjg@129 72 ClassLoader docletParentClassLoader) {
duke@1 73 this.messager = messager;
duke@1 74 this.docletClassName = docletClassName;
duke@1 75
duke@1 76 // construct class loader
duke@1 77 String cpString = null; // make sure env.class.path defaults to dot
duke@1 78
duke@1 79 // do prepends to get correct ordering
duke@1 80 cpString = appendPath(System.getProperty("env.class.path"), cpString);
duke@1 81 cpString = appendPath(System.getProperty("java.class.path"), cpString);
duke@1 82 cpString = appendPath(docletPath, cpString);
darcy@497 83 URL[] urls = com.sun.tools.javac.file.Paths.pathToURLs(cpString);
jjg@129 84 if (docletParentClassLoader == null)
jjg@209 85 appClassLoader = new URLClassLoader(urls, getDelegationClassLoader(docletClassName));
jjg@129 86 else
jjg@129 87 appClassLoader = new URLClassLoader(urls, docletParentClassLoader);
duke@1 88
duke@1 89 // attempt to find doclet
mcimadamore@184 90 Class<?> dc = null;
duke@1 91 try {
duke@1 92 dc = appClassLoader.loadClass(docletClassName);
duke@1 93 } catch (ClassNotFoundException exc) {
duke@1 94 messager.error(null, "main.doclet_class_not_found", docletClassName);
duke@1 95 messager.exit();
duke@1 96 }
duke@1 97 docletClass = dc;
duke@1 98 }
duke@1 99
jjg@209 100 /*
jjg@209 101 * Returns the delegation class loader to use when creating
jjg@209 102 * appClassLoader (used to load the doclet). The context class
jjg@209 103 * loader is the best choice, but legacy behavior was to use the
jjg@209 104 * default delegation class loader (aka system class loader).
jjg@209 105 *
jjg@209 106 * Here we favor using the context class loader. To ensure
jjg@209 107 * compatibility with existing apps, we revert to legacy
jjg@209 108 * behavior if either or both of the following conditions hold:
jjg@209 109 *
jjg@209 110 * 1) the doclet is loadable from the system class loader but not
jjg@209 111 * from the context class loader,
jjg@209 112 *
jjg@209 113 * 2) this.getClass() is loadable from the system class loader but not
jjg@209 114 * from the context class loader.
jjg@209 115 */
jjg@209 116 private ClassLoader getDelegationClassLoader(String docletClassName) {
jjg@209 117 ClassLoader ctxCL = Thread.currentThread().getContextClassLoader();
jjg@209 118 ClassLoader sysCL = ClassLoader.getSystemClassLoader();
jjg@209 119 if (sysCL == null)
jjg@209 120 return ctxCL;
jjg@209 121 if (ctxCL == null)
jjg@209 122 return sysCL;
jjg@209 123
jjg@209 124 // Condition 1.
jjg@209 125 try {
jjg@209 126 sysCL.loadClass(docletClassName);
jjg@209 127 try {
jjg@209 128 ctxCL.loadClass(docletClassName);
jjg@209 129 } catch (ClassNotFoundException e) {
jjg@209 130 return sysCL;
jjg@209 131 }
jjg@209 132 } catch (ClassNotFoundException e) {
jjg@209 133 }
jjg@209 134
jjg@209 135 // Condition 2.
jjg@209 136 try {
jjg@209 137 if (getClass() == sysCL.loadClass(getClass().getName())) {
jjg@209 138 try {
jjg@209 139 if (getClass() != ctxCL.loadClass(getClass().getName()))
jjg@209 140 return sysCL;
jjg@209 141 } catch (ClassNotFoundException e) {
jjg@209 142 return sysCL;
jjg@209 143 }
jjg@209 144 }
jjg@209 145 } catch (ClassNotFoundException e) {
jjg@209 146 }
jjg@209 147
jjg@209 148 return ctxCL;
jjg@209 149 }
jjg@209 150
duke@1 151 /**
duke@1 152 * Generate documentation here. Return true on success.
duke@1 153 */
duke@1 154 public boolean start(RootDoc root) {
duke@1 155 Object retVal;
duke@1 156 String methodName = "start";
jjg@584 157 Class<?>[] paramTypes = { RootDoc.class };
jjg@584 158 Object[] params = { root };
duke@1 159 try {
duke@1 160 retVal = invoke(methodName, null, paramTypes, params);
duke@1 161 } catch (DocletInvokeException exc) {
duke@1 162 return false;
duke@1 163 }
duke@1 164 if (retVal instanceof Boolean) {
duke@1 165 return ((Boolean)retVal).booleanValue();
duke@1 166 } else {
duke@1 167 messager.error(null, "main.must_return_boolean",
duke@1 168 docletClassName, methodName);
duke@1 169 return false;
duke@1 170 }
duke@1 171 }
duke@1 172
duke@1 173 /**
duke@1 174 * Check for doclet added options here. Zero return means
duke@1 175 * option not known. Positive value indicates number of
duke@1 176 * arguments to option. Negative value means error occurred.
duke@1 177 */
duke@1 178 public int optionLength(String option) {
duke@1 179 Object retVal;
duke@1 180 String methodName = "optionLength";
jjg@584 181 Class<?>[] paramTypes = { String.class };
jjg@584 182 Object[] params = { option };
duke@1 183 try {
duke@1 184 retVal = invoke(methodName, new Integer(0), paramTypes, params);
duke@1 185 } catch (DocletInvokeException exc) {
duke@1 186 return -1;
duke@1 187 }
duke@1 188 if (retVal instanceof Integer) {
duke@1 189 return ((Integer)retVal).intValue();
duke@1 190 } else {
duke@1 191 messager.error(null, "main.must_return_int",
duke@1 192 docletClassName, methodName);
duke@1 193 return -1;
duke@1 194 }
duke@1 195 }
duke@1 196
duke@1 197 /**
duke@1 198 * Let doclet check that all options are OK. Returning true means
duke@1 199 * options are OK. If method does not exist, assume true.
duke@1 200 */
duke@1 201 public boolean validOptions(List<String[]> optlist) {
duke@1 202 Object retVal;
duke@1 203 String options[][] = optlist.toArray(new String[optlist.length()][]);
duke@1 204 String methodName = "validOptions";
duke@1 205 DocErrorReporter reporter = messager;
jjg@584 206 Class<?>[] paramTypes = { String[][].class, DocErrorReporter.class };
jjg@584 207 Object[] params = { options, reporter };
duke@1 208 try {
duke@1 209 retVal = invoke(methodName, Boolean.TRUE, paramTypes, params);
duke@1 210 } catch (DocletInvokeException exc) {
duke@1 211 return false;
duke@1 212 }
duke@1 213 if (retVal instanceof Boolean) {
duke@1 214 return ((Boolean)retVal).booleanValue();
duke@1 215 } else {
duke@1 216 messager.error(null, "main.must_return_boolean",
duke@1 217 docletClassName, methodName);
duke@1 218 return false;
duke@1 219 }
duke@1 220 }
duke@1 221
duke@1 222 /**
duke@1 223 * Return the language version supported by this doclet.
duke@1 224 * If the method does not exist in the doclet, assume version 1.1.
duke@1 225 */
duke@1 226 public LanguageVersion languageVersion() {
duke@1 227 try {
duke@1 228 Object retVal;
duke@1 229 String methodName = "languageVersion";
mcimadamore@184 230 Class<?>[] paramTypes = new Class<?>[0];
duke@1 231 Object[] params = new Object[0];
duke@1 232 try {
duke@1 233 retVal = invoke(methodName, JAVA_1_1, paramTypes, params);
duke@1 234 } catch (DocletInvokeException exc) {
duke@1 235 return JAVA_1_1;
duke@1 236 }
duke@1 237 if (retVal instanceof LanguageVersion) {
duke@1 238 return (LanguageVersion)retVal;
duke@1 239 } else {
duke@1 240 messager.error(null, "main.must_return_languageversion",
duke@1 241 docletClassName, methodName);
duke@1 242 return JAVA_1_1;
duke@1 243 }
duke@1 244 } catch (NoClassDefFoundError ex) { // for boostrapping, no Enum class.
duke@1 245 return null;
duke@1 246 }
duke@1 247 }
duke@1 248
duke@1 249 /**
duke@1 250 * Utility method for calling doclet functionality
duke@1 251 */
duke@1 252 private Object invoke(String methodName, Object returnValueIfNonExistent,
mcimadamore@184 253 Class<?>[] paramTypes, Object[] params)
duke@1 254 throws DocletInvokeException {
duke@1 255 Method meth;
duke@1 256 try {
duke@1 257 meth = docletClass.getMethod(methodName, paramTypes);
duke@1 258 } catch (NoSuchMethodException exc) {
duke@1 259 if (returnValueIfNonExistent == null) {
duke@1 260 messager.error(null, "main.doclet_method_not_found",
duke@1 261 docletClassName, methodName);
duke@1 262 throw new DocletInvokeException();
duke@1 263 } else {
duke@1 264 return returnValueIfNonExistent;
duke@1 265 }
duke@1 266 } catch (SecurityException exc) {
duke@1 267 messager.error(null, "main.doclet_method_not_accessible",
duke@1 268 docletClassName, methodName);
duke@1 269 throw new DocletInvokeException();
duke@1 270 }
duke@1 271 if (!Modifier.isStatic(meth.getModifiers())) {
duke@1 272 messager.error(null, "main.doclet_method_must_be_static",
duke@1 273 docletClassName, methodName);
duke@1 274 throw new DocletInvokeException();
duke@1 275 }
jjg@209 276 ClassLoader savedCCL =
jjg@209 277 Thread.currentThread().getContextClassLoader();
duke@1 278 try {
duke@1 279 Thread.currentThread().setContextClassLoader(appClassLoader);
duke@1 280 return meth.invoke(null , params);
duke@1 281 } catch (IllegalArgumentException exc) {
duke@1 282 messager.error(null, "main.internal_error_exception_thrown",
duke@1 283 docletClassName, methodName, exc.toString());
duke@1 284 throw new DocletInvokeException();
duke@1 285 } catch (IllegalAccessException exc) {
duke@1 286 messager.error(null, "main.doclet_method_not_accessible",
duke@1 287 docletClassName, methodName);
duke@1 288 throw new DocletInvokeException();
duke@1 289 } catch (NullPointerException exc) {
duke@1 290 messager.error(null, "main.internal_error_exception_thrown",
duke@1 291 docletClassName, methodName, exc.toString());
duke@1 292 throw new DocletInvokeException();
duke@1 293 } catch (InvocationTargetException exc) {
duke@1 294 Throwable err = exc.getTargetException();
duke@1 295 if (err instanceof java.lang.OutOfMemoryError) {
duke@1 296 messager.error(null, "main.out.of.memory");
duke@1 297 } else {
duke@1 298 messager.error(null, "main.exception_thrown",
duke@1 299 docletClassName, methodName, exc.toString());
duke@1 300 exc.getTargetException().printStackTrace();
duke@1 301 }
duke@1 302 throw new DocletInvokeException();
jjg@209 303 } finally {
jjg@209 304 Thread.currentThread().setContextClassLoader(savedCCL);
duke@1 305 }
duke@1 306 }
duke@1 307 }

mercurial