Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/rmi/rmic/newrmic/Main.java
38923 views
1
/*
2
* Copyright (c) 2003, 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 sun.rmi.rmic.newrmic;
27
28
import com.sun.javadoc.ClassDoc;
29
import com.sun.javadoc.RootDoc;
30
import java.io.File;
31
import java.io.FileNotFoundException;
32
import java.io.IOException;
33
import java.io.OutputStream;
34
import java.io.PrintStream;
35
import java.io.PrintWriter;
36
import java.lang.reflect.Constructor;
37
import java.lang.reflect.InvocationTargetException;
38
import java.util.ArrayList;
39
import java.util.Collections;
40
import java.util.HashMap;
41
import java.util.HashSet;
42
import java.util.List;
43
import java.util.Map;
44
import java.util.Set;
45
import sun.rmi.rmic.newrmic.jrmp.JrmpGenerator;
46
import sun.tools.util.CommandLine;
47
48
/**
49
* The rmic front end. This class contains the "main" method for rmic
50
* command line invocation.
51
*
52
* A Main instance contains the stream to output error messages and
53
* other diagnostics to.
54
*
55
* An rmic compilation batch (for example, one rmic command line
56
* invocation) is executed by invoking the "compile" method of a Main
57
* instance.
58
*
59
* WARNING: The contents of this source file are not part of any
60
* supported API. Code that depends on them does so at its own risk:
61
* they are subject to change or removal without notice.
62
*
63
* NOTE: If and when there is a J2SE API for invoking SDK tools, this
64
* class should be updated to support that API.
65
*
66
* NOTE: This class is the front end for a "new" rmic implementation,
67
* which uses javadoc and the doclet API for reading class files and
68
* javac for compiling generated source files. This implementation is
69
* incomplete: it lacks any CORBA-based back end implementations, and
70
* thus the command line options "-idl", "-iiop", and their related
71
* options are not yet supported. The front end for the "old",
72
* oldjavac-based rmic implementation is sun.rmi.rmic.Main.
73
*
74
* @author Peter Jones
75
**/
76
public class Main {
77
78
/*
79
* Implementation note:
80
*
81
* In order to use the doclet API to read class files, much of
82
* this implementation of rmic executes as a doclet within an
83
* invocation of javadoc. This class is used as the doclet class
84
* for such javadoc invocations, via its static "start" and
85
* "optionLength" methods. There is one javadoc invocation per
86
* rmic compilation batch.
87
*
88
* The only guaranteed way to pass data to a doclet through a
89
* javadoc invocation is through doclet-specific options on the
90
* javadoc "command line". Rather than passing numerous pieces of
91
* individual data in string form as javadoc options, we use a
92
* single doclet-specific option ("-batchID") to pass a numeric
93
* identifier that uniquely identifies the rmic compilation batch
94
* that the javadoc invocation is for, and that identifier can
95
* then be used as a key in a global table to retrieve an object
96
* containing all of batch-specific data (rmic command line
97
* arguments, etc.).
98
*/
99
100
/** guards "batchCount" */
101
private static final Object batchCountLock = new Object();
102
103
/** number of batches run; used to generated batch IDs */
104
private static long batchCount = 0;
105
106
/** maps batch ID to batch data */
107
private static final Map<Long,Batch> batchTable =
108
Collections.synchronizedMap(new HashMap<Long,Batch>());
109
110
/** stream to output error messages and other diagnostics to */
111
private final PrintStream out;
112
113
/** name of this program, to use in error messages */
114
private final String program;
115
116
/**
117
* Command line entry point.
118
**/
119
public static void main(String[] args) {
120
Main rmic = new Main(System.err, "rmic");
121
System.exit(rmic.compile(args) ? 0 : 1);
122
}
123
124
/**
125
* Creates a Main instance that writes output to the specified
126
* stream. The specified program name is used in error messages.
127
**/
128
public Main(OutputStream out, String program) {
129
this.out = out instanceof PrintStream ?
130
(PrintStream) out : new PrintStream(out);
131
this.program = program;
132
}
133
134
/**
135
* Compiles a batch of input classes, as given by the specified
136
* command line arguments. Protocol-specific generators are
137
* determined by the choice options on the command line. Returns
138
* true if successful, or false if an error occurred.
139
*
140
* NOTE: This method is retained for transitional consistency with
141
* previous implementations.
142
**/
143
public boolean compile(String[] args) {
144
long startTime = System.currentTimeMillis();
145
146
long batchID;
147
synchronized (batchCountLock) {
148
batchID = batchCount++; // assign batch ID
149
}
150
151
// process command line
152
Batch batch = parseArgs(args);
153
if (batch == null) {
154
return false; // terminate if error occurred
155
}
156
157
/*
158
* With the batch data retrievable in the global table, run
159
* javadoc to continue the rest of the batch's compliation as
160
* a doclet.
161
*/
162
boolean status;
163
try {
164
batchTable.put(batchID, batch);
165
status = invokeJavadoc(batch, batchID);
166
} finally {
167
batchTable.remove(batchID);
168
}
169
170
if (batch.verbose) {
171
long deltaTime = System.currentTimeMillis() - startTime;
172
output(Resources.getText("rmic.done_in",
173
Long.toString(deltaTime)));
174
}
175
176
return status;
177
}
178
179
/**
180
* Prints the specified string to the output stream of this Main
181
* instance.
182
**/
183
public void output(String msg) {
184
out.println(msg);
185
}
186
187
/**
188
* Prints an error message to the output stream of this Main
189
* instance. The first argument is used as a key in rmic's
190
* resource bundle, and the rest of the arguments are used as
191
* arguments in the formatting of the resource string.
192
**/
193
public void error(String msg, String... args) {
194
output(Resources.getText(msg, args));
195
}
196
197
/**
198
* Prints rmic's usage message to the output stream of this Main
199
* instance.
200
*
201
* This method is public so that it can be used by the "parseArgs"
202
* methods of Generator implementations.
203
**/
204
public void usage() {
205
error("rmic.usage", program);
206
}
207
208
/**
209
* Processes rmic command line arguments. Returns a Batch object
210
* representing the command line arguments if successful, or null
211
* if an error occurred. Processed elements of the args array are
212
* set to null.
213
**/
214
private Batch parseArgs(String[] args) {
215
Batch batch = new Batch();
216
217
/*
218
* Pre-process command line for @file arguments.
219
*/
220
try {
221
args = CommandLine.parse(args);
222
} catch (FileNotFoundException e) {
223
error("rmic.cant.read", e.getMessage());
224
return null;
225
} catch (IOException e) {
226
e.printStackTrace(out);
227
return null;
228
}
229
230
for (int i = 0; i < args.length; i++) {
231
232
if (args[i] == null) {
233
// already processed by a generator
234
continue;
235
236
} else if (args[i].equals("-Xnew")) {
237
// we're already using the "new" implementation
238
args[i] = null;
239
240
} else if (args[i].equals("-show")) {
241
// obselete: fail
242
error("rmic.option.unsupported", args[i]);
243
usage();
244
return null;
245
246
} else if (args[i].equals("-O")) {
247
// obselete: warn but tolerate
248
error("rmic.option.unsupported", args[i]);
249
args[i] = null;
250
251
} else if (args[i].equals("-debug")) {
252
// obselete: warn but tolerate
253
error("rmic.option.unsupported", args[i]);
254
args[i] = null;
255
256
} else if (args[i].equals("-depend")) {
257
// obselete: warn but tolerate
258
// REMIND: should this fail instead?
259
error("rmic.option.unsupported", args[i]);
260
args[i] = null;
261
262
} else if (args[i].equals("-keep") ||
263
args[i].equals("-keepgenerated"))
264
{
265
batch.keepGenerated = true;
266
args[i] = null;
267
268
} else if (args[i].equals("-g")) {
269
batch.debug = true;
270
args[i] = null;
271
272
} else if (args[i].equals("-nowarn")) {
273
batch.noWarn = true;
274
args[i] = null;
275
276
} else if (args[i].equals("-nowrite")) {
277
batch.noWrite = true;
278
args[i] = null;
279
280
} else if (args[i].equals("-verbose")) {
281
batch.verbose = true;
282
args[i] = null;
283
284
} else if (args[i].equals("-Xnocompile")) {
285
batch.noCompile = true;
286
batch.keepGenerated = true;
287
args[i] = null;
288
289
} else if (args[i].equals("-bootclasspath")) {
290
if ((i + 1) >= args.length) {
291
error("rmic.option.requires.argument", args[i]);
292
usage();
293
return null;
294
}
295
if (batch.bootClassPath != null) {
296
error("rmic.option.already.seen", args[i]);
297
usage();
298
return null;
299
}
300
args[i] = null;
301
batch.bootClassPath = args[++i];
302
assert batch.bootClassPath != null;
303
args[i] = null;
304
305
} else if (args[i].equals("-extdirs")) {
306
if ((i + 1) >= args.length) {
307
error("rmic.option.requires.argument", args[i]);
308
usage();
309
return null;
310
}
311
if (batch.extDirs != null) {
312
error("rmic.option.already.seen", args[i]);
313
usage();
314
return null;
315
}
316
args[i] = null;
317
batch.extDirs = args[++i];
318
assert batch.extDirs != null;
319
args[i] = null;
320
321
} else if (args[i].equals("-classpath")) {
322
if ((i + 1) >= args.length) {
323
error("rmic.option.requires.argument", args[i]);
324
usage();
325
return null;
326
}
327
if (batch.classPath != null) {
328
error("rmic.option.already.seen", args[i]);
329
usage();
330
return null;
331
}
332
args[i] = null;
333
batch.classPath = args[++i];
334
assert batch.classPath != null;
335
args[i] = null;
336
337
} else if (args[i].equals("-d")) {
338
if ((i + 1) >= args.length) {
339
error("rmic.option.requires.argument", args[i]);
340
usage();
341
return null;
342
}
343
if (batch.destDir != null) {
344
error("rmic.option.already.seen", args[i]);
345
usage();
346
return null;
347
}
348
args[i] = null;
349
batch.destDir = new File(args[++i]);
350
assert batch.destDir != null;
351
args[i] = null;
352
if (!batch.destDir.exists()) {
353
error("rmic.no.such.directory", batch.destDir.getPath());
354
usage();
355
return null;
356
}
357
358
} else if (args[i].equals("-v1.1") ||
359
args[i].equals("-vcompat") ||
360
args[i].equals("-v1.2"))
361
{
362
Generator gen = new JrmpGenerator();
363
batch.generators.add(gen);
364
// JrmpGenerator only requires base BatchEnvironment class
365
if (!gen.parseArgs(args, this)) {
366
return null;
367
}
368
369
} else if (args[i].equalsIgnoreCase("-iiop")) {
370
error("rmic.option.unimplemented", args[i]);
371
return null;
372
373
// Generator gen = new IiopGenerator();
374
// batch.generators.add(gen);
375
// if (!batch.envClass.isAssignableFrom(gen.envClass())) {
376
// error("rmic.cannot.use.both",
377
// batch.envClass.getName(), gen.envClass().getName());
378
// return null;
379
// }
380
// batch.envClass = gen.envClass();
381
// if (!gen.parseArgs(args, this)) {
382
// return null;
383
// }
384
385
} else if (args[i].equalsIgnoreCase("-idl")) {
386
error("rmic.option.unimplemented", args[i]);
387
return null;
388
389
// see implementation sketch above
390
391
} else if (args[i].equalsIgnoreCase("-xprint")) {
392
error("rmic.option.unimplemented", args[i]);
393
return null;
394
395
// see implementation sketch above
396
}
397
}
398
399
/*
400
* At this point, all that remains non-null in the args
401
* array are input class names or illegal options.
402
*/
403
for (int i = 0; i < args.length; i++) {
404
if (args[i] != null) {
405
if (args[i].startsWith("-")) {
406
error("rmic.no.such.option", args[i]);
407
usage();
408
return null;
409
} else {
410
batch.classes.add(args[i]);
411
}
412
}
413
}
414
if (batch.classes.isEmpty()) {
415
usage();
416
return null;
417
}
418
419
/*
420
* If options did not specify at least one protocol-specific
421
* generator, then JRMP is the default.
422
*/
423
if (batch.generators.isEmpty()) {
424
batch.generators.add(new JrmpGenerator());
425
}
426
return batch;
427
}
428
429
/**
430
* Doclet class entry point.
431
**/
432
public static boolean start(RootDoc rootDoc) {
433
434
/*
435
* Find batch ID among javadoc options, and retrieve
436
* corresponding batch data from global table.
437
*/
438
long batchID = -1;
439
for (String[] option : rootDoc.options()) {
440
if (option[0].equals("-batchID")) {
441
try {
442
batchID = Long.parseLong(option[1]);
443
} catch (NumberFormatException e) {
444
throw new AssertionError(e);
445
}
446
}
447
}
448
Batch batch = batchTable.get(batchID);
449
assert batch != null;
450
451
/*
452
* Construct batch environment using class agreed upon by
453
* generator implementations.
454
*/
455
BatchEnvironment env;
456
try {
457
Constructor<? extends BatchEnvironment> cons =
458
batch.envClass.getConstructor(new Class<?>[] { RootDoc.class });
459
env = cons.newInstance(rootDoc);
460
} catch (NoSuchMethodException e) {
461
throw new AssertionError(e);
462
} catch (IllegalAccessException e) {
463
throw new AssertionError(e);
464
} catch (InstantiationException e) {
465
throw new AssertionError(e);
466
} catch (InvocationTargetException e) {
467
throw new AssertionError(e);
468
}
469
470
env.setVerbose(batch.verbose);
471
472
/*
473
* Determine the destination directory (the top of the package
474
* hierarchy) for the output of this batch; if no destination
475
* directory was specified on the command line, then the
476
* default is the current working directory.
477
*/
478
File destDir = batch.destDir;
479
if (destDir == null) {
480
destDir = new File(System.getProperty("user.dir"));
481
}
482
483
/*
484
* Run each input class through each generator.
485
*/
486
for (String inputClassName : batch.classes) {
487
ClassDoc inputClass = rootDoc.classNamed(inputClassName);
488
try {
489
for (Generator gen : batch.generators) {
490
gen.generate(env, inputClass, destDir);
491
}
492
} catch (NullPointerException e) {
493
/*
494
* We assume that this means that some class that was
495
* needed (perhaps even a bootstrap class) was not
496
* found, and that javadoc has already reported this
497
* as an error. There is nothing for us to do here
498
* but try to continue with the next input class.
499
*
500
* REMIND: More explicit error checking throughout
501
* would be preferable, however.
502
*/
503
}
504
}
505
506
/*
507
* Compile any generated source files, if configured to do so.
508
*/
509
boolean status = true;
510
List<File> generatedFiles = env.generatedFiles();
511
if (!batch.noCompile && !batch.noWrite && !generatedFiles.isEmpty()) {
512
status = batch.enclosingMain().invokeJavac(batch, generatedFiles);
513
}
514
515
/*
516
* Delete any generated source files, if configured to do so.
517
*/
518
if (!batch.keepGenerated) {
519
for (File file : generatedFiles) {
520
file.delete();
521
}
522
}
523
524
return status;
525
}
526
527
/**
528
* Doclet class method that indicates that this doclet class
529
* recognizes (only) the "-batchID" option on the javadoc command
530
* line, and that the "-batchID" option comprises two arguments on
531
* the javadoc command line.
532
**/
533
public static int optionLength(String option) {
534
if (option.equals("-batchID")) {
535
return 2;
536
} else {
537
return 0;
538
}
539
}
540
541
/**
542
* Runs the javadoc tool to invoke this class as a doclet, passing
543
* command line options derived from the specified batch data and
544
* indicating the specified batch ID.
545
*
546
* NOTE: This method currently uses a J2SE-internal API to run
547
* javadoc. If and when there is a J2SE API for invoking SDK
548
* tools, this method should be updated to use that API instead.
549
**/
550
private boolean invokeJavadoc(Batch batch, long batchID) {
551
List<String> javadocArgs = new ArrayList<String>();
552
553
// include all types, regardless of language-level access
554
javadocArgs.add("-private");
555
556
// inputs are class names, not source files
557
javadocArgs.add("-Xclasses");
558
559
// reproduce relevant options from rmic invocation
560
if (batch.verbose) {
561
javadocArgs.add("-verbose");
562
}
563
if (batch.bootClassPath != null) {
564
javadocArgs.add("-bootclasspath");
565
javadocArgs.add(batch.bootClassPath);
566
}
567
if (batch.extDirs != null) {
568
javadocArgs.add("-extdirs");
569
javadocArgs.add(batch.extDirs);
570
}
571
if (batch.classPath != null) {
572
javadocArgs.add("-classpath");
573
javadocArgs.add(batch.classPath);
574
}
575
576
// specify batch ID
577
javadocArgs.add("-batchID");
578
javadocArgs.add(Long.toString(batchID));
579
580
/*
581
* Run javadoc on union of rmic input classes and all
582
* generators' bootstrap classes, so that they will all be
583
* available to the doclet code.
584
*/
585
Set<String> classNames = new HashSet<String>();
586
for (Generator gen : batch.generators) {
587
classNames.addAll(gen.bootstrapClassNames());
588
}
589
classNames.addAll(batch.classes);
590
for (String s : classNames) {
591
javadocArgs.add(s);
592
}
593
594
// run javadoc with our program name and output stream
595
int status = com.sun.tools.javadoc.Main.execute(
596
program,
597
new PrintWriter(out, true),
598
new PrintWriter(out, true),
599
new PrintWriter(out, true),
600
this.getClass().getName(), // doclet class is this class
601
javadocArgs.toArray(new String[javadocArgs.size()]));
602
return status == 0;
603
}
604
605
/**
606
* Runs the javac tool to compile the specified source files,
607
* passing command line options derived from the specified batch
608
* data.
609
*
610
* NOTE: This method currently uses a J2SE-internal API to run
611
* javac. If and when there is a J2SE API for invoking SDK tools,
612
* this method should be updated to use that API instead.
613
**/
614
private boolean invokeJavac(Batch batch, List<File> files) {
615
List<String> javacArgs = new ArrayList<String>();
616
617
// rmic never wants to display javac warnings
618
javacArgs.add("-nowarn");
619
620
// reproduce relevant options from rmic invocation
621
if (batch.debug) {
622
javacArgs.add("-g");
623
}
624
if (batch.verbose) {
625
javacArgs.add("-verbose");
626
}
627
if (batch.bootClassPath != null) {
628
javacArgs.add("-bootclasspath");
629
javacArgs.add(batch.bootClassPath);
630
}
631
if (batch.extDirs != null) {
632
javacArgs.add("-extdirs");
633
javacArgs.add(batch.extDirs);
634
}
635
if (batch.classPath != null) {
636
javacArgs.add("-classpath");
637
javacArgs.add(batch.classPath);
638
}
639
640
/*
641
* For now, rmic still always produces class files that have a
642
* class file format version compatible with JDK 1.1.
643
*/
644
javacArgs.add("-source");
645
javacArgs.add("1.3");
646
javacArgs.add("-target");
647
javacArgs.add("1.1");
648
649
// add source files to compile
650
for (File file : files) {
651
javacArgs.add(file.getPath());
652
}
653
654
// run javac with our output stream
655
int status = com.sun.tools.javac.Main.compile(
656
javacArgs.toArray(new String[javacArgs.size()]),
657
new PrintWriter(out, true));
658
return status == 0;
659
}
660
661
/**
662
* The data for an rmic compliation batch: the processed command
663
* line arguments.
664
**/
665
private class Batch {
666
boolean keepGenerated = false; // -keep or -keepgenerated
667
boolean debug = false; // -g
668
boolean noWarn = false; // -nowarn
669
boolean noWrite = false; // -nowrite
670
boolean verbose = false; // -verbose
671
boolean noCompile = false; // -Xnocompile
672
String bootClassPath = null; // -bootclasspath
673
String extDirs = null; // -extdirs
674
String classPath = null; // -classpath
675
File destDir = null; // -d
676
List<Generator> generators = new ArrayList<Generator>();
677
Class<? extends BatchEnvironment> envClass = BatchEnvironment.class;
678
List<String> classes = new ArrayList<String>();
679
680
Batch() { }
681
682
/**
683
* Returns the Main instance for this batch.
684
**/
685
Main enclosingMain() {
686
return Main.this;
687
}
688
}
689
}
690
691