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

Thu, 02 Oct 2008 19:58:40 -0700

author
xdono
date
Thu, 02 Oct 2008 19:58:40 -0700
changeset 117
24a47c3062fe
parent 115
829dea15ff99
child 129
944790f83b57
permissions
-rw-r--r--

6754988: Update copyright year
Summary: Update for files that have been modified starting July 2008
Reviewed-by: ohair, tbell

duke@1 1 /*
xdono@117 2 * Copyright 1998-2008 Sun Microsystems, Inc. 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
duke@1 7 * published by the Free Software Foundation. Sun designates this
duke@1 8 * particular file as subject to the "Classpath" exception as provided
duke@1 9 * by Sun 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 *
duke@1 21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
duke@1 22 * CA 95054 USA or visit www.sun.com if you need additional information or
duke@1 23 * have any 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
duke@1 34 import java.net.*;
duke@1 35 import java.lang.OutOfMemoryError;
duke@1 36 import java.lang.reflect.Method;
duke@1 37 import java.lang.reflect.Modifier;
duke@1 38 import java.lang.reflect.InvocationTargetException;
duke@1 39
duke@1 40 import java.io.File;
duke@1 41 import java.io.IOException;
duke@1 42 import java.util.StringTokenizer;
duke@1 43
duke@1 44 /**
duke@1 45 * Class creates, controls and invokes doclets.
duke@1 46 * @author Neal Gafter (rewrite)
duke@1 47 */
duke@1 48 public class DocletInvoker {
duke@1 49
jjg@74 50 private final Class<?> docletClass;
duke@1 51
duke@1 52 private final String docletClassName;
duke@1 53
duke@1 54 private final ClassLoader appClassLoader;
duke@1 55
duke@1 56 private final Messager messager;
duke@1 57
duke@1 58 private static class DocletInvokeException extends Exception {
duke@1 59 private static final long serialVersionUID = 0;
duke@1 60 }
duke@1 61
duke@1 62 private String appendPath(String path1, String path2) {
duke@1 63 if (path1 == null || path1.length() == 0) {
duke@1 64 return path2 == null ? "." : path2;
duke@1 65 } else if (path2 == null || path2.length() == 0) {
duke@1 66 return path1;
duke@1 67 } else {
duke@1 68 return path1 + File.pathSeparator + path2;
duke@1 69 }
duke@1 70 }
duke@1 71
duke@1 72 public DocletInvoker(Messager messager,
duke@1 73 String docletClassName, String docletPath) {
duke@1 74 this.messager = messager;
duke@1 75 this.docletClassName = docletClassName;
duke@1 76
duke@1 77 // construct class loader
duke@1 78 String cpString = null; // make sure env.class.path defaults to dot
duke@1 79
duke@1 80 // do prepends to get correct ordering
duke@1 81 cpString = appendPath(System.getProperty("env.class.path"), cpString);
duke@1 82 cpString = appendPath(System.getProperty("java.class.path"), cpString);
duke@1 83 cpString = appendPath(docletPath, cpString);
duke@1 84 URL[] urls = pathToURLs(cpString);
duke@1 85 appClassLoader = new URLClassLoader(urls);
duke@1 86
duke@1 87 // attempt to find doclet
duke@1 88 Class dc = null;
duke@1 89 try {
duke@1 90 dc = appClassLoader.loadClass(docletClassName);
duke@1 91 } catch (ClassNotFoundException exc) {
duke@1 92 messager.error(null, "main.doclet_class_not_found", docletClassName);
duke@1 93 messager.exit();
duke@1 94 }
duke@1 95 docletClass = dc;
duke@1 96 }
duke@1 97
duke@1 98 /**
duke@1 99 * Generate documentation here. Return true on success.
duke@1 100 */
duke@1 101 public boolean start(RootDoc root) {
duke@1 102 Object retVal;
duke@1 103 String methodName = "start";
duke@1 104 Class[] paramTypes = new Class[1];
duke@1 105 Object[] params = new Object[1];
duke@1 106 paramTypes[0] = RootDoc.class;
duke@1 107 params[0] = root;
duke@1 108 try {
duke@1 109 retVal = invoke(methodName, null, paramTypes, params);
duke@1 110 } catch (DocletInvokeException exc) {
duke@1 111 return false;
duke@1 112 }
duke@1 113 if (retVal instanceof Boolean) {
duke@1 114 return ((Boolean)retVal).booleanValue();
duke@1 115 } else {
duke@1 116 messager.error(null, "main.must_return_boolean",
duke@1 117 docletClassName, methodName);
duke@1 118 return false;
duke@1 119 }
duke@1 120 }
duke@1 121
duke@1 122 /**
duke@1 123 * Check for doclet added options here. Zero return means
duke@1 124 * option not known. Positive value indicates number of
duke@1 125 * arguments to option. Negative value means error occurred.
duke@1 126 */
duke@1 127 public int optionLength(String option) {
duke@1 128 Object retVal;
duke@1 129 String methodName = "optionLength";
duke@1 130 Class[] paramTypes = new Class[1];
duke@1 131 Object[] params = new Object[1];
duke@1 132 paramTypes[0] = option.getClass();
duke@1 133 params[0] = option;
duke@1 134 try {
duke@1 135 retVal = invoke(methodName, new Integer(0), paramTypes, params);
duke@1 136 } catch (DocletInvokeException exc) {
duke@1 137 return -1;
duke@1 138 }
duke@1 139 if (retVal instanceof Integer) {
duke@1 140 return ((Integer)retVal).intValue();
duke@1 141 } else {
duke@1 142 messager.error(null, "main.must_return_int",
duke@1 143 docletClassName, methodName);
duke@1 144 return -1;
duke@1 145 }
duke@1 146 }
duke@1 147
duke@1 148 /**
duke@1 149 * Let doclet check that all options are OK. Returning true means
duke@1 150 * options are OK. If method does not exist, assume true.
duke@1 151 */
duke@1 152 public boolean validOptions(List<String[]> optlist) {
duke@1 153 Object retVal;
duke@1 154 String options[][] = optlist.toArray(new String[optlist.length()][]);
duke@1 155 String methodName = "validOptions";
duke@1 156 DocErrorReporter reporter = messager;
duke@1 157 Class[] paramTypes = new Class[2];
duke@1 158 Object[] params = new Object[2];
duke@1 159 paramTypes[0] = options.getClass();
duke@1 160 paramTypes[1] = DocErrorReporter.class;
duke@1 161 params[0] = options;
duke@1 162 params[1] = reporter;
duke@1 163 try {
duke@1 164 retVal = invoke(methodName, Boolean.TRUE, paramTypes, params);
duke@1 165 } catch (DocletInvokeException exc) {
duke@1 166 return false;
duke@1 167 }
duke@1 168 if (retVal instanceof Boolean) {
duke@1 169 return ((Boolean)retVal).booleanValue();
duke@1 170 } else {
duke@1 171 messager.error(null, "main.must_return_boolean",
duke@1 172 docletClassName, methodName);
duke@1 173 return false;
duke@1 174 }
duke@1 175 }
duke@1 176
duke@1 177 /**
duke@1 178 * Return the language version supported by this doclet.
duke@1 179 * If the method does not exist in the doclet, assume version 1.1.
duke@1 180 */
duke@1 181 public LanguageVersion languageVersion() {
duke@1 182 try {
duke@1 183 Object retVal;
duke@1 184 String methodName = "languageVersion";
duke@1 185 Class[] paramTypes = new Class[0];
duke@1 186 Object[] params = new Object[0];
duke@1 187 try {
duke@1 188 retVal = invoke(methodName, JAVA_1_1, paramTypes, params);
duke@1 189 } catch (DocletInvokeException exc) {
duke@1 190 return JAVA_1_1;
duke@1 191 }
duke@1 192 if (retVal instanceof LanguageVersion) {
duke@1 193 return (LanguageVersion)retVal;
duke@1 194 } else {
duke@1 195 messager.error(null, "main.must_return_languageversion",
duke@1 196 docletClassName, methodName);
duke@1 197 return JAVA_1_1;
duke@1 198 }
duke@1 199 } catch (NoClassDefFoundError ex) { // for boostrapping, no Enum class.
duke@1 200 return null;
duke@1 201 }
duke@1 202 }
duke@1 203
duke@1 204 /**
duke@1 205 * Utility method for calling doclet functionality
duke@1 206 */
duke@1 207 private Object invoke(String methodName, Object returnValueIfNonExistent,
duke@1 208 Class[] paramTypes, Object[] params)
duke@1 209 throws DocletInvokeException {
duke@1 210 Method meth;
duke@1 211 try {
duke@1 212 meth = docletClass.getMethod(methodName, paramTypes);
duke@1 213 } catch (NoSuchMethodException exc) {
duke@1 214 if (returnValueIfNonExistent == null) {
duke@1 215 messager.error(null, "main.doclet_method_not_found",
duke@1 216 docletClassName, methodName);
duke@1 217 throw new DocletInvokeException();
duke@1 218 } else {
duke@1 219 return returnValueIfNonExistent;
duke@1 220 }
duke@1 221 } catch (SecurityException exc) {
duke@1 222 messager.error(null, "main.doclet_method_not_accessible",
duke@1 223 docletClassName, methodName);
duke@1 224 throw new DocletInvokeException();
duke@1 225 }
duke@1 226 if (!Modifier.isStatic(meth.getModifiers())) {
duke@1 227 messager.error(null, "main.doclet_method_must_be_static",
duke@1 228 docletClassName, methodName);
duke@1 229 throw new DocletInvokeException();
duke@1 230 }
duke@1 231 try {
duke@1 232 Thread.currentThread().setContextClassLoader(appClassLoader);
duke@1 233 return meth.invoke(null , params);
duke@1 234 } catch (IllegalArgumentException exc) {
duke@1 235 messager.error(null, "main.internal_error_exception_thrown",
duke@1 236 docletClassName, methodName, exc.toString());
duke@1 237 throw new DocletInvokeException();
duke@1 238 } catch (IllegalAccessException exc) {
duke@1 239 messager.error(null, "main.doclet_method_not_accessible",
duke@1 240 docletClassName, methodName);
duke@1 241 throw new DocletInvokeException();
duke@1 242 } catch (NullPointerException exc) {
duke@1 243 messager.error(null, "main.internal_error_exception_thrown",
duke@1 244 docletClassName, methodName, exc.toString());
duke@1 245 throw new DocletInvokeException();
duke@1 246 } catch (InvocationTargetException exc) {
duke@1 247 Throwable err = exc.getTargetException();
duke@1 248 if (err instanceof java.lang.OutOfMemoryError) {
duke@1 249 messager.error(null, "main.out.of.memory");
duke@1 250 } else {
duke@1 251 messager.error(null, "main.exception_thrown",
duke@1 252 docletClassName, methodName, exc.toString());
duke@1 253 exc.getTargetException().printStackTrace();
duke@1 254 }
duke@1 255 throw new DocletInvokeException();
duke@1 256 }
duke@1 257 }
duke@1 258
duke@1 259 /**
duke@1 260 * Utility method for converting a search path string to an array
duke@1 261 * of directory and JAR file URLs.
duke@1 262 *
duke@1 263 * @param path the search path string
duke@1 264 * @return the resulting array of directory and JAR file URLs
duke@1 265 */
duke@1 266 static URL[] pathToURLs(String path) {
duke@1 267 StringTokenizer st = new StringTokenizer(path, File.pathSeparator);
duke@1 268 URL[] urls = new URL[st.countTokens()];
duke@1 269 int count = 0;
duke@1 270 while (st.hasMoreTokens()) {
duke@1 271 URL url = fileToURL(new File(st.nextToken()));
duke@1 272 if (url != null) {
duke@1 273 urls[count++] = url;
duke@1 274 }
duke@1 275 }
duke@1 276 if (urls.length != count) {
duke@1 277 URL[] tmp = new URL[count];
duke@1 278 System.arraycopy(urls, 0, tmp, 0, count);
duke@1 279 urls = tmp;
duke@1 280 }
duke@1 281 return urls;
duke@1 282 }
duke@1 283
duke@1 284 /**
duke@1 285 * Returns the directory or JAR file URL corresponding to the specified
duke@1 286 * local file name.
duke@1 287 *
duke@1 288 * @param file the File object
duke@1 289 * @return the resulting directory or JAR file URL, or null if unknown
duke@1 290 */
duke@1 291 static URL fileToURL(File file) {
duke@1 292 String name;
duke@1 293 try {
duke@1 294 name = file.getCanonicalPath();
duke@1 295 } catch (IOException e) {
duke@1 296 name = file.getAbsolutePath();
duke@1 297 }
duke@1 298 name = name.replace(File.separatorChar, '/');
duke@1 299 if (!name.startsWith("/")) {
duke@1 300 name = "/" + name;
duke@1 301 }
duke@1 302 // If the file does not exist, then assume that it's a directory
duke@1 303 if (!file.isFile()) {
duke@1 304 name = name + "/";
duke@1 305 }
duke@1 306 try {
duke@1 307 return new URL("file", "", name);
duke@1 308 } catch (MalformedURLException e) {
duke@1 309 throw new IllegalArgumentException("file");
duke@1 310 }
duke@1 311 }
duke@1 312 }

mercurial