Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/langtools/src/share/classes/com/sun/tools/javadoc/DocletInvoker.java
38899 views
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
*/
25
26
package com.sun.tools.javadoc;
27
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;
34
35
import javax.tools.DocumentationTool;
36
import javax.tools.JavaFileManager;
37
38
import com.sun.javadoc.*;
39
import com.sun.tools.javac.file.Locations;
40
import com.sun.tools.javac.util.ClientCodeException;
41
import com.sun.tools.javac.util.List;
42
import static com.sun.javadoc.LanguageVersion.*;
43
44
45
/**
46
* Class creates, controls and invokes doclets.
47
*
48
* <p><b>This is NOT part of any supported API.
49
* If you write code that depends on this, you do so at your own risk.
50
* This code and its internal interfaces are subject to change or
51
* deletion without notice.</b>
52
*
53
* @author Neal Gafter (rewrite)
54
*/
55
public class DocletInvoker {
56
57
private final Class<?> docletClass;
58
59
private final String docletClassName;
60
61
private final ClassLoader appClassLoader;
62
63
private final Messager messager;
64
65
/**
66
* In API mode, exceptions thrown while calling the doclet are
67
* propagated using ClientCodeException.
68
*/
69
private final boolean apiMode;
70
71
private static class DocletInvokeException extends Exception {
72
private static final long serialVersionUID = 0;
73
}
74
75
private String appendPath(String path1, String path2) {
76
if (path1 == null || path1.length() == 0) {
77
return path2 == null ? "." : path2;
78
} else if (path2 == null || path2.length() == 0) {
79
return path1;
80
} else {
81
return path1 + File.pathSeparator + path2;
82
}
83
}
84
85
public DocletInvoker(Messager messager, Class<?> docletClass, boolean apiMode) {
86
this.messager = messager;
87
this.docletClass = docletClass;
88
docletClassName = docletClass.getName();
89
appClassLoader = null;
90
this.apiMode = apiMode;
91
}
92
93
public DocletInvoker(Messager messager, JavaFileManager fileManager,
94
String docletClassName, String docletPath,
95
ClassLoader docletParentClassLoader,
96
boolean apiMode) {
97
this.messager = messager;
98
this.docletClassName = docletClassName;
99
this.apiMode = apiMode;
100
101
if (fileManager != null && fileManager.hasLocation(DocumentationTool.Location.DOCLET_PATH)) {
102
appClassLoader = fileManager.getClassLoader(DocumentationTool.Location.DOCLET_PATH);
103
} else {
104
// construct class loader
105
String cpString = null; // make sure env.class.path defaults to dot
106
107
// do prepends to get correct ordering
108
cpString = appendPath(System.getProperty("env.class.path"), cpString);
109
cpString = appendPath(System.getProperty("java.class.path"), cpString);
110
cpString = appendPath(docletPath, cpString);
111
URL[] urls = Locations.pathToURLs(cpString);
112
if (docletParentClassLoader == null)
113
appClassLoader = new URLClassLoader(urls, getDelegationClassLoader(docletClassName));
114
else
115
appClassLoader = new URLClassLoader(urls, docletParentClassLoader);
116
}
117
118
// attempt to find doclet
119
Class<?> dc = null;
120
try {
121
dc = appClassLoader.loadClass(docletClassName);
122
} catch (ClassNotFoundException exc) {
123
messager.error(Messager.NOPOS, "main.doclet_class_not_found", docletClassName);
124
messager.exit();
125
}
126
docletClass = dc;
127
}
128
129
/*
130
* Returns the delegation class loader to use when creating
131
* appClassLoader (used to load the doclet). The context class
132
* loader is the best choice, but legacy behavior was to use the
133
* default delegation class loader (aka system class loader).
134
*
135
* Here we favor using the context class loader. To ensure
136
* compatibility with existing apps, we revert to legacy
137
* behavior if either or both of the following conditions hold:
138
*
139
* 1) the doclet is loadable from the system class loader but not
140
* from the context class loader,
141
*
142
* 2) this.getClass() is loadable from the system class loader but not
143
* from the context class loader.
144
*/
145
private ClassLoader getDelegationClassLoader(String docletClassName) {
146
ClassLoader ctxCL = Thread.currentThread().getContextClassLoader();
147
ClassLoader sysCL = ClassLoader.getSystemClassLoader();
148
if (sysCL == null)
149
return ctxCL;
150
if (ctxCL == null)
151
return sysCL;
152
153
// Condition 1.
154
try {
155
sysCL.loadClass(docletClassName);
156
try {
157
ctxCL.loadClass(docletClassName);
158
} catch (ClassNotFoundException e) {
159
return sysCL;
160
}
161
} catch (ClassNotFoundException e) {
162
}
163
164
// Condition 2.
165
try {
166
if (getClass() == sysCL.loadClass(getClass().getName())) {
167
try {
168
if (getClass() != ctxCL.loadClass(getClass().getName()))
169
return sysCL;
170
} catch (ClassNotFoundException e) {
171
return sysCL;
172
}
173
}
174
} catch (ClassNotFoundException e) {
175
}
176
177
return ctxCL;
178
}
179
180
/**
181
* Generate documentation here. Return true on success.
182
*/
183
public boolean start(RootDoc root) {
184
Object retVal;
185
String methodName = "start";
186
Class<?>[] paramTypes = { RootDoc.class };
187
Object[] params = { root };
188
try {
189
retVal = invoke(methodName, null, paramTypes, params);
190
} catch (DocletInvokeException exc) {
191
return false;
192
}
193
if (retVal instanceof Boolean) {
194
return ((Boolean)retVal).booleanValue();
195
} else {
196
messager.error(Messager.NOPOS, "main.must_return_boolean",
197
docletClassName, methodName);
198
return false;
199
}
200
}
201
202
/**
203
* Check for doclet added options here. Zero return means
204
* option not known. Positive value indicates number of
205
* arguments to option. Negative value means error occurred.
206
*/
207
public int optionLength(String option) {
208
Object retVal;
209
String methodName = "optionLength";
210
Class<?>[] paramTypes = { String.class };
211
Object[] params = { option };
212
try {
213
retVal = invoke(methodName, new Integer(0), paramTypes, params);
214
} catch (DocletInvokeException exc) {
215
return -1;
216
}
217
if (retVal instanceof Integer) {
218
return ((Integer)retVal).intValue();
219
} else {
220
messager.error(Messager.NOPOS, "main.must_return_int",
221
docletClassName, methodName);
222
return -1;
223
}
224
}
225
226
/**
227
* Let doclet check that all options are OK. Returning true means
228
* options are OK. If method does not exist, assume true.
229
*/
230
public boolean validOptions(List<String[]> optlist) {
231
Object retVal;
232
String options[][] = optlist.toArray(new String[optlist.length()][]);
233
String methodName = "validOptions";
234
DocErrorReporter reporter = messager;
235
Class<?>[] paramTypes = { String[][].class, DocErrorReporter.class };
236
Object[] params = { options, reporter };
237
try {
238
retVal = invoke(methodName, Boolean.TRUE, paramTypes, params);
239
} catch (DocletInvokeException exc) {
240
return false;
241
}
242
if (retVal instanceof Boolean) {
243
return ((Boolean)retVal).booleanValue();
244
} else {
245
messager.error(Messager.NOPOS, "main.must_return_boolean",
246
docletClassName, methodName);
247
return false;
248
}
249
}
250
251
/**
252
* Return the language version supported by this doclet.
253
* If the method does not exist in the doclet, assume version 1.1.
254
*/
255
public LanguageVersion languageVersion() {
256
try {
257
Object retVal;
258
String methodName = "languageVersion";
259
Class<?>[] paramTypes = new Class<?>[0];
260
Object[] params = new Object[0];
261
try {
262
retVal = invoke(methodName, JAVA_1_1, paramTypes, params);
263
} catch (DocletInvokeException exc) {
264
return JAVA_1_1;
265
}
266
if (retVal instanceof LanguageVersion) {
267
return (LanguageVersion)retVal;
268
} else {
269
messager.error(Messager.NOPOS, "main.must_return_languageversion",
270
docletClassName, methodName);
271
return JAVA_1_1;
272
}
273
} catch (NoClassDefFoundError ex) { // for boostrapping, no Enum class.
274
return null;
275
}
276
}
277
278
/**
279
* Utility method for calling doclet functionality
280
*/
281
private Object invoke(String methodName, Object returnValueIfNonExistent,
282
Class<?>[] paramTypes, Object[] params)
283
throws DocletInvokeException {
284
Method meth;
285
try {
286
meth = docletClass.getMethod(methodName, paramTypes);
287
} catch (NoSuchMethodException exc) {
288
if (returnValueIfNonExistent == null) {
289
messager.error(Messager.NOPOS, "main.doclet_method_not_found",
290
docletClassName, methodName);
291
throw new DocletInvokeException();
292
} else {
293
return returnValueIfNonExistent;
294
}
295
} catch (SecurityException exc) {
296
messager.error(Messager.NOPOS, "main.doclet_method_not_accessible",
297
docletClassName, methodName);
298
throw new DocletInvokeException();
299
}
300
if (!Modifier.isStatic(meth.getModifiers())) {
301
messager.error(Messager.NOPOS, "main.doclet_method_must_be_static",
302
docletClassName, methodName);
303
throw new DocletInvokeException();
304
}
305
ClassLoader savedCCL =
306
Thread.currentThread().getContextClassLoader();
307
try {
308
if (appClassLoader != null) // will be null if doclet class provided via API
309
Thread.currentThread().setContextClassLoader(appClassLoader);
310
return meth.invoke(null , params);
311
} catch (IllegalArgumentException exc) {
312
messager.error(Messager.NOPOS, "main.internal_error_exception_thrown",
313
docletClassName, methodName, exc.toString());
314
throw new DocletInvokeException();
315
} catch (IllegalAccessException exc) {
316
messager.error(Messager.NOPOS, "main.doclet_method_not_accessible",
317
docletClassName, methodName);
318
throw new DocletInvokeException();
319
} catch (NullPointerException exc) {
320
messager.error(Messager.NOPOS, "main.internal_error_exception_thrown",
321
docletClassName, methodName, exc.toString());
322
throw new DocletInvokeException();
323
} catch (InvocationTargetException exc) {
324
Throwable err = exc.getTargetException();
325
if (apiMode)
326
throw new ClientCodeException(err);
327
if (err instanceof java.lang.OutOfMemoryError) {
328
messager.error(Messager.NOPOS, "main.out.of.memory");
329
} else {
330
messager.error(Messager.NOPOS, "main.exception_thrown",
331
docletClassName, methodName, exc.toString());
332
exc.getTargetException().printStackTrace();
333
}
334
throw new DocletInvokeException();
335
} finally {
336
Thread.currentThread().setContextClassLoader(savedCCL);
337
}
338
}
339
}
340
341