Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/make/src/classes/build/tools/swingbeaninfo/GenDocletBeanInfo.java
32287 views
1
/*
2
* Copyright (c) 1998, 2013, 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 build.tools.swingbeaninfo;
27
28
import com.sun.javadoc.ClassDoc;
29
import com.sun.javadoc.MethodDoc;
30
import com.sun.javadoc.RootDoc;
31
import com.sun.javadoc.Tag;
32
33
import java.beans.Introspector;
34
35
import java.util.Enumeration;
36
import java.util.Hashtable;
37
import java.util.HashMap;
38
import java.util.StringTokenizer;
39
40
/**
41
* Properties supported and tag syntax:
42
*
43
* @beaninfo
44
* bound: flag
45
* constrained: flag
46
* expert: flag
47
* hidden: flag
48
* preferred: flag
49
* description: string
50
* displayname: string
51
* propertyeditorclass: string (with dots: foo.bar.MyPropertyEditor
52
* customizerclass: string (w/dots: foo.bar.MyCustomizer)
53
* attribute: key1 value1
54
* attribute: key2 value2
55
*
56
* TODO: getValue and genDocletInfo needs some cleaning.
57
*
58
* @author Hans Muller
59
* @author Rich Schiavi
60
* @author Mark Davidson
61
*/
62
public class GenDocletBeanInfo {
63
64
static String[] ATTRIBUTE_NAMES = { "bound",
65
"constrained",
66
"expert",
67
"hidden",
68
"preferred",
69
"displayname",
70
"propertyeditorclass",
71
"customizerclass",
72
"displayname",
73
"description",
74
"enum",
75
"attribute" };
76
private static boolean DEBUG = false;
77
78
private static String fileDir = "";
79
private static String templateDir = "";
80
81
public static final String TRUE = "true";
82
public static final String FALSE = "false";
83
84
/**
85
* Method called from the javadoc environment to determint the options length.
86
* Doclet options:
87
* -t template location
88
* -d outputdir
89
* -x true Enable debug output.
90
*/
91
public static int optionLength(String option) {
92
// remind: this needs to be cleaned up
93
if (option.equals("-t"))
94
return 2;
95
if (option.equals("-d"))
96
return 2;
97
if (option.equals("-x"))
98
return 2;
99
return 0;
100
}
101
102
/** @beaninfo
103
* bound:true
104
* constrained:false
105
* expert:true
106
* hidden:true
107
* preferred:false
108
* description: the description of this method can
109
* do all sorts of funky things. if it \n
110
* is indented like this, we have to remove
111
* all char spaces greater than 2 and also any hard-coded \n
112
* newline characters and all newlines
113
* displayname: theString
114
* propertyeditorclass: foo.bar.MyPropertyEditorClass
115
* customizerclass: foo.bar.MyCustomizerClass
116
* attribute:key1 value1
117
* attribute: key2 value2
118
*
119
*/
120
public static boolean start(RootDoc doc) {
121
readOptions(doc.options());
122
123
if (templateDir.length() == 0) {
124
System.err.println("-t option not specified");
125
return false;
126
}
127
if (fileDir.length() == 0) {
128
System.err.println("-d option not specified");
129
return false;
130
}
131
132
GenSwingBeanInfo generator = new GenSwingBeanInfo(fileDir, templateDir, DEBUG);
133
Hashtable dochash = new Hashtable();
134
DocBeanInfo dbi;
135
136
/* "javadoc Foo.java Bar.java" will return:
137
* "Foo Foo.I1 Foo.I2 Bar Bar.I1 Bar.I2"
138
* i.e., with all the innerclasses of classes specified in the command
139
* line. We don't want to generate BeanInfo for any of these inner
140
* classes, so we ignore these by remembering what the last outer
141
* class was. A hack, I admit, but makes the build faster.
142
*/
143
String previousClass = null;
144
145
ClassDoc[] classes = doc.classes();
146
147
for (int cnt = 0; cnt < classes.length; cnt++) {
148
String className = classes[cnt].qualifiedName();
149
if (previousClass != null &&
150
className.startsWith(previousClass) &&
151
className.charAt(previousClass.length()) == '.') {
152
continue;
153
}
154
previousClass = className;
155
156
// XXX - debug
157
System.out.println("\n>>> Generating beaninfo for " + className + "...");
158
159
// Examine the javadoc tags and look for the the @beaninfo tag
160
// This first block looks at the javadoc for the class
161
Tag[] tags = classes[cnt].tags();
162
for (int i = 0; i < tags.length; i++) {
163
if (tags[i].kind().equalsIgnoreCase("@beaninfo")) {
164
if (DEBUG)
165
System.out.println("GenDocletBeanInfo: found @beaninfo tagged Class: " + tags[i].text());
166
dbi = genDocletInfo(tags[i].text(), classes[cnt].name());
167
dochash.put(dbi.name, dbi);
168
break;
169
}
170
}
171
172
// This block looks at the javadoc for the class methods.
173
int startPos = -1;
174
MethodDoc[] methods = classes[cnt].methods();
175
for (int j = 0; j < methods.length; j++) {
176
// actually don't "introspect" - look for all
177
// methods with a @beaninfo tag
178
tags = methods[j].tags();
179
for (int x = 0; x < tags.length; x++){
180
if (tags[x].kind().equalsIgnoreCase("@beaninfo")){
181
if ((methods[j].name().startsWith("get")) ||
182
(methods[j].name().startsWith("set")))
183
startPos = 3;
184
else if (methods[j].name().startsWith("is"))
185
startPos = 2;
186
else
187
startPos = 0;
188
String propDesc =
189
Introspector.decapitalize((methods[j].name()).substring(startPos));
190
if (DEBUG)
191
System.out.println("GenDocletBeanInfo: found @beaninfo tagged Method: " + tags[x].text());
192
dbi = genDocletInfo(tags[x].text(), propDesc);
193
dochash.put(dbi.name, dbi);
194
break;
195
}
196
}
197
}
198
if (DEBUG) {
199
// dump our classes doc beaninfo
200
System.out.println(">>>>DocletBeanInfo for class: " + classes[cnt].name());
201
Enumeration e = dochash.elements();
202
while (e.hasMoreElements()) {
203
DocBeanInfo db = (DocBeanInfo)e.nextElement();
204
System.out.println(db.toString());
205
}
206
}
207
208
// Use the generator to create the beaninfo code for the class.
209
generator.genBeanInfo(classes[cnt].containingPackage().name(),
210
classes[cnt].name(), dochash);
211
// reset the values!
212
dochash.clear();
213
} // end for loop
214
return true;
215
}
216
217
/**
218
* Reads the command line options.
219
* Side Effect, sets class variables templateDir, fileDir and DEBUG
220
*/
221
private static void readOptions(String[][] options) {
222
// Parse the command line args
223
for (int i = 0; i < options.length; i++){
224
if (options[i][0].equals("-t")) {
225
templateDir = options[i][1];
226
} else if (options[i][0].equals("-d")) {
227
fileDir = options[i][1];
228
} else if (options[i][0].equals("-x")){
229
if (options[i][1].equals("true"))
230
DEBUG=true;
231
else
232
DEBUG=false;
233
}
234
}
235
}
236
237
/**
238
* Create a "BeanInfo" data structure from the tag. This is a data structure
239
* which contains all beaninfo data for a method or a class.
240
*
241
* @param text All the text after the @beaninfo tag.
242
* @param name Name of the property i.e., mnemonic for setMnemonic
243
*/
244
private static DocBeanInfo genDocletInfo(String text, String name) {
245
int beanflags = 0;
246
String desc = "null";
247
String displayname = "null";
248
String propertyeditorclass = "null";
249
String customizerclass = "null";
250
String value = "null";
251
HashMap attribs = null;
252
HashMap enums = null;
253
254
int index;
255
256
for (int j = 0; j < ATTRIBUTE_NAMES.length; j++){
257
index = 0;
258
if ((index = text.indexOf(ATTRIBUTE_NAMES[j])) != -1){
259
value = getValue((text).substring(index),ATTRIBUTE_NAMES[j]);
260
261
if (ATTRIBUTE_NAMES[j].equalsIgnoreCase("attribute")) {
262
attribs = getAttributeMap(value, " ");
263
}
264
if (ATTRIBUTE_NAMES[j].equalsIgnoreCase("enum")) {
265
enums = getAttributeMap(value, " \n");
266
}
267
else if (ATTRIBUTE_NAMES[j].equals("displayname")){
268
displayname = value;
269
}
270
else if (ATTRIBUTE_NAMES[j].equalsIgnoreCase("propertyeditorclass")) {
271
propertyeditorclass = value;
272
}
273
else if (ATTRIBUTE_NAMES[j].equalsIgnoreCase("customizerclass")){
274
customizerclass = value;
275
}
276
else if ((ATTRIBUTE_NAMES[j].equalsIgnoreCase("bound"))
277
&& (value.equalsIgnoreCase(TRUE)))
278
beanflags = beanflags | DocBeanInfo.BOUND;
279
else if ((ATTRIBUTE_NAMES[j].equalsIgnoreCase("expert"))
280
&& (value.equalsIgnoreCase(TRUE)))
281
beanflags = beanflags | DocBeanInfo.EXPERT;
282
else if ((ATTRIBUTE_NAMES[j].equalsIgnoreCase("constrained"))
283
&& (value.equalsIgnoreCase(TRUE)))
284
beanflags = beanflags | DocBeanInfo.CONSTRAINED;
285
else if ((ATTRIBUTE_NAMES[j].equalsIgnoreCase("hidden"))
286
&& (value.equalsIgnoreCase(TRUE)))
287
beanflags = beanflags | DocBeanInfo.HIDDEN;
288
else if ((ATTRIBUTE_NAMES[j].equalsIgnoreCase("preferred"))
289
&& (value.equalsIgnoreCase(TRUE)))
290
beanflags = beanflags | DocBeanInfo.PREFERRED;
291
else if (ATTRIBUTE_NAMES[j].equalsIgnoreCase("description")){
292
desc = value;
293
}
294
}
295
}
296
/** here we create our doclet-beaninfo data structure, which we read in
297
* later if it has anything worthwhile
298
*/
299
300
// Construct a new Descriptor class
301
return new DocBeanInfo(name, beanflags, desc,displayname,
302
propertyeditorclass, customizerclass,
303
attribs, enums);
304
}
305
306
/**
307
* Parses the substring and returns the cleaned up value for the attribute.
308
* @param substring Full String of the attrib tag.
309
* i.e., "attribute: visualUpdate true" will return "visualUpdate true";
310
*/
311
private static String getValue(String substring, String prop) {
312
StringTokenizer t;
313
String value = "null";
314
315
try {
316
/** if the ATTRIBUTE_NAMES is NOT the description, then we
317
* parse until newline
318
* if it is the description we read until the next token
319
* and then look for a match in the last MAXMATCH index
320
* and truncate the description
321
* if it is the attribute we wead until no more
322
*/
323
if (prop.equalsIgnoreCase("attribute")){
324
StringBuffer tmp = new StringBuffer();
325
try {
326
t = new StringTokenizer(substring, " :\n");
327
t.nextToken().trim();//the prop
328
// we want to return : key1 value1 key2 value2
329
while (t.hasMoreTokens()){
330
tmp.append(t.nextToken().trim()).append(" ");
331
tmp.append(t.nextToken().trim()).append(" ");
332
String test = t.nextToken().trim();
333
if (!(test.equalsIgnoreCase("attribute")))
334
break;
335
}
336
} catch (Exception e){
337
}
338
value = tmp.toString();
339
}
340
else if (prop.equalsIgnoreCase("enum")){
341
t = new StringTokenizer(substring, ":");
342
t.nextToken().trim(); // the prop we already know
343
StringBuffer tmp = new StringBuffer(t.nextToken().trim());
344
for (int i = 0; i < ATTRIBUTE_NAMES.length; i++){
345
if (tmp.toString().endsWith(ATTRIBUTE_NAMES[i])){
346
int len = ATTRIBUTE_NAMES[i].length();
347
// trim off that
348
tmp.setLength(tmp.length() - len);
349
break;
350
}
351
}
352
value = tmp.toString();
353
}
354
else if (prop.equalsIgnoreCase("description")){
355
t = new StringTokenizer(substring, ":");
356
t.nextToken().trim(); // the prop we already know
357
StringBuffer tmp = new StringBuffer(t.nextToken().trim());
358
for (int i = 0; i < ATTRIBUTE_NAMES.length; i++){
359
if (tmp.toString().endsWith(ATTRIBUTE_NAMES[i])){
360
int len = ATTRIBUTE_NAMES[i].length();
361
// trim off that
362
tmp.setLength(tmp.length() - len);
363
break;
364
}
365
}
366
value = hansalizeIt(tmp.toString());
367
}
368
else {
369
// Single value properties like bound: true
370
t = new StringTokenizer(substring, ":\n");
371
t.nextToken().trim(); // the prop we already know
372
value = t.nextToken().trim();
373
}
374
375
// now we need to look for a match of any of the
376
// property
377
378
return value;
379
}
380
catch (Exception e){
381
return "invalidValue";
382
}
383
}
384
385
/**
386
* Creates a HashMap containing the key value pair for the parsed values
387
* of the "attributes" and "enum" tags.
388
* ie. For attribute value: visualUpdate true
389
* The HashMap will have key: visualUpdate, value: true
390
*/
391
private static HashMap getAttributeMap(String str, String delim) {
392
StringTokenizer t = new StringTokenizer(str, delim);
393
HashMap map = null;
394
String key;
395
String value;
396
397
int num = t.countTokens()/2;
398
if (num > 0) {
399
map = new HashMap();
400
for (int i = 0; i < num; i++) {
401
key = t.nextToken().trim();
402
value = t.nextToken().trim();
403
map.put(key, value);
404
}
405
}
406
return map;
407
}
408
409
// looks for extra spaces, \n hard-coded and invisible,etc
410
private static String hansalizeIt(String from){
411
char [] chars = from.toCharArray();
412
int len = chars.length;
413
int toss = 0;
414
415
// remove double spaces
416
for (int i = 0; i < len; i++){
417
if ((chars[i] == ' ')) {
418
if (i+1 < len) {
419
if ((chars[i+1] == ' ' ) || (chars[i+1] == '\n'))
420
{
421
--len;
422
System.arraycopy(chars,i+1,chars,i,len-i);
423
--i;
424
}
425
}
426
}
427
428
if (chars[i] == '\n'){
429
chars[i] = ' ';
430
i -= 2;
431
}
432
433
if (chars[i] == '\\') {
434
if (i+1 < len) {
435
if (chars[i+1] == 'n'){
436
chars[i+1] = ' ';
437
--len;
438
System.arraycopy(chars,i+1, chars,i, len-i);
439
--i;
440
}
441
}
442
}
443
}
444
return new String(chars,0,len);
445
}
446
447
}
448
449