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/launcher/LauncherHelper.java
38829 views
1
/*
2
* Copyright (c) 2007, 2018, 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.launcher;
27
28
/*
29
*
30
* <p><b>This is NOT part of any API supported by Sun Microsystems.
31
* If you write code that depends on this, you do so at your own
32
* risk. This code and its internal interfaces are subject to change
33
* or deletion without notice.</b>
34
*
35
*/
36
37
/**
38
* A utility package for the java(1), javaw(1) launchers.
39
* The following are helper methods that the native launcher uses
40
* to perform checks etc. using JNI, see src/share/bin/java.c
41
*/
42
import java.io.File;
43
import java.io.IOException;
44
import java.io.PrintStream;
45
import java.io.UnsupportedEncodingException;
46
import java.lang.reflect.Method;
47
import java.lang.reflect.Modifier;
48
import java.math.BigDecimal;
49
import java.math.RoundingMode;
50
import java.nio.charset.Charset;
51
import java.nio.file.DirectoryStream;
52
import java.nio.file.Files;
53
import java.nio.file.Path;
54
import java.text.Normalizer;
55
import java.util.ResourceBundle;
56
import java.text.MessageFormat;
57
import java.util.ArrayList;
58
import java.util.Collections;
59
import java.util.Iterator;
60
import java.util.List;
61
import java.util.Locale;
62
import java.util.Locale.Category;
63
import java.util.Properties;
64
import java.util.Set;
65
import java.util.TreeSet;
66
import java.util.jar.Attributes;
67
import java.util.jar.JarFile;
68
import java.util.jar.Manifest;
69
import jdk.internal.platform.Container;
70
import jdk.internal.platform.Metrics;
71
72
public enum LauncherHelper {
73
INSTANCE;
74
private static final String MAIN_CLASS = "Main-Class";
75
76
private static StringBuilder outBuf = new StringBuilder();
77
78
private static final String INDENT = " ";
79
private static final String VM_SETTINGS = "VM settings:";
80
private static final String PROP_SETTINGS = "Property settings:";
81
private static final String LOCALE_SETTINGS = "Locale settings:";
82
83
// sync with java.c and sun.misc.VM
84
private static final String diagprop = "sun.java.launcher.diag";
85
final static boolean trace = sun.misc.VM.getSavedProperty(diagprop) != null;
86
87
private static final String defaultBundleName =
88
"sun.launcher.resources.launcher";
89
private static class ResourceBundleHolder {
90
private static final ResourceBundle RB =
91
ResourceBundle.getBundle(defaultBundleName);
92
}
93
private static PrintStream ostream;
94
private static final ClassLoader scloader = ClassLoader.getSystemClassLoader();
95
private static Class<?> appClass; // application class, for GUI/reporting purposes
96
97
/*
98
* A method called by the launcher to print out the standard settings,
99
* by default -XshowSettings is equivalent to -XshowSettings:all,
100
* Specific information may be gotten by using suboptions with possible
101
* values vm, properties and locale.
102
*
103
* printToStderr: choose between stdout and stderr
104
*
105
* optionFlag: specifies which options to print default is all other
106
* possible values are vm, properties, locale.
107
*
108
* initialHeapSize: in bytes, as set by the launcher, a zero-value indicates
109
* this code should determine this value, using a suitable method or
110
* the line could be omitted.
111
*
112
* maxHeapSize: in bytes, as set by the launcher, a zero-value indicates
113
* this code should determine this value, using a suitable method.
114
*
115
* stackSize: in bytes, as set by the launcher, a zero-value indicates
116
* this code determine this value, using a suitable method or omit the
117
* line entirely.
118
*/
119
@SuppressWarnings("fallthrough")
120
static void showSettings(boolean printToStderr, String optionFlag,
121
long initialHeapSize, long maxHeapSize, long stackSize,
122
boolean isServer) {
123
124
initOutput(printToStderr);
125
String opts[] = optionFlag.split(":");
126
String optStr = (opts.length > 1 && opts[1] != null)
127
? opts[1].trim()
128
: "all";
129
switch (optStr) {
130
case "vm":
131
printVmSettings(initialHeapSize, maxHeapSize,
132
stackSize, isServer);
133
break;
134
case "properties":
135
printProperties();
136
break;
137
case "locale":
138
printLocale();
139
break;
140
case "system":
141
if (System.getProperty("os.name").contains("Linux")) {
142
printSystemMetrics();
143
break;
144
}
145
default:
146
printVmSettings(initialHeapSize, maxHeapSize, stackSize,
147
isServer);
148
printProperties();
149
printLocale();
150
if (System.getProperty("os.name").contains("Linux")) {
151
printSystemMetrics();
152
}
153
break;
154
}
155
}
156
157
/*
158
* prints the main vm settings subopt/section
159
*/
160
private static void printVmSettings(
161
long initialHeapSize, long maxHeapSize,
162
long stackSize, boolean isServer) {
163
164
ostream.println(VM_SETTINGS);
165
if (stackSize != 0L) {
166
ostream.println(INDENT + "Stack Size: " +
167
SizePrefix.scaleValue(stackSize));
168
}
169
if (initialHeapSize != 0L) {
170
ostream.println(INDENT + "Min. Heap Size: " +
171
SizePrefix.scaleValue(initialHeapSize));
172
}
173
if (maxHeapSize != 0L) {
174
ostream.println(INDENT + "Max. Heap Size: " +
175
SizePrefix.scaleValue(maxHeapSize));
176
} else {
177
ostream.println(INDENT + "Max. Heap Size (Estimated): "
178
+ SizePrefix.scaleValue(Runtime.getRuntime().maxMemory()));
179
}
180
ostream.println(INDENT + "Ergonomics Machine Class: "
181
+ ((isServer) ? "server" : "client"));
182
ostream.println(INDENT + "Using VM: "
183
+ System.getProperty("java.vm.name"));
184
ostream.println();
185
}
186
187
/*
188
* prints the properties subopt/section
189
*/
190
private static void printProperties() {
191
Properties p = System.getProperties();
192
ostream.println(PROP_SETTINGS);
193
List<String> sortedPropertyKeys = new ArrayList<>();
194
sortedPropertyKeys.addAll(p.stringPropertyNames());
195
Collections.sort(sortedPropertyKeys);
196
for (String x : sortedPropertyKeys) {
197
printPropertyValue(x, p.getProperty(x));
198
}
199
ostream.println();
200
}
201
202
private static boolean isPath(String key) {
203
return key.endsWith(".dirs") || key.endsWith(".path");
204
}
205
206
private static void printPropertyValue(String key, String value) {
207
ostream.print(INDENT + key + " = ");
208
if (key.equals("line.separator")) {
209
for (byte b : value.getBytes()) {
210
switch (b) {
211
case 0xd:
212
ostream.print("\\r ");
213
break;
214
case 0xa:
215
ostream.print("\\n ");
216
break;
217
default:
218
// print any bizzare line separators in hex, but really
219
// shouldn't happen.
220
ostream.printf("0x%02X", b & 0xff);
221
break;
222
}
223
}
224
ostream.println();
225
return;
226
}
227
if (!isPath(key)) {
228
ostream.println(value);
229
return;
230
}
231
String[] values = value.split(System.getProperty("path.separator"));
232
boolean first = true;
233
for (String s : values) {
234
if (first) { // first line treated specially
235
ostream.println(s);
236
first = false;
237
} else { // following lines prefix with indents
238
ostream.println(INDENT + INDENT + s);
239
}
240
}
241
}
242
243
/*
244
* prints the locale subopt/section
245
*/
246
private static void printLocale() {
247
Locale locale = Locale.getDefault();
248
ostream.println(LOCALE_SETTINGS);
249
ostream.println(INDENT + "default locale = " +
250
locale.getDisplayLanguage());
251
ostream.println(INDENT + "default display locale = " +
252
Locale.getDefault(Category.DISPLAY).getDisplayName());
253
ostream.println(INDENT + "default format locale = " +
254
Locale.getDefault(Category.FORMAT).getDisplayName());
255
printLocales();
256
ostream.println();
257
}
258
259
private static void printLocales() {
260
Locale[] tlocales = Locale.getAvailableLocales();
261
final int len = tlocales == null ? 0 : tlocales.length;
262
if (len < 1 ) {
263
return;
264
}
265
// Locale does not implement Comparable so we convert it to String
266
// and sort it for pretty printing.
267
Set<String> sortedSet = new TreeSet<>();
268
for (Locale l : tlocales) {
269
sortedSet.add(l.toString());
270
}
271
272
ostream.print(INDENT + "available locales = ");
273
Iterator<String> iter = sortedSet.iterator();
274
final int last = len - 1;
275
for (int i = 0 ; iter.hasNext() ; i++) {
276
String s = iter.next();
277
ostream.print(s);
278
if (i != last) {
279
ostream.print(", ");
280
}
281
// print columns of 8
282
if ((i + 1) % 8 == 0) {
283
ostream.println();
284
ostream.print(INDENT + INDENT);
285
}
286
}
287
}
288
289
public static void printSystemMetrics() {
290
Metrics c = Container.metrics();
291
292
ostream.println("Operating System Metrics:");
293
294
if (c == null) {
295
ostream.println(INDENT + "No metrics available for this platform");
296
return;
297
}
298
299
ostream.println(INDENT + "Provider: " + c.getProvider());
300
ostream.println(INDENT + "Effective CPU Count: " + c.getEffectiveCpuCount());
301
ostream.println(INDENT + "CPU Period: " + c.getCpuPeriod() +
302
(c.getCpuPeriod() == -1 ? "" : "us"));
303
ostream.println(INDENT + "CPU Quota: " + c.getCpuQuota() +
304
(c.getCpuQuota() == -1 ? "" : "us"));
305
ostream.println(INDENT + "CPU Shares: " + c.getCpuShares());
306
307
int cpus[] = c.getCpuSetCpus();
308
ostream.println(INDENT + "List of Processors, "
309
+ cpus.length + " total: ");
310
311
ostream.print(INDENT);
312
for (int i = 0; i < cpus.length; i++) {
313
ostream.print(cpus[i] + " ");
314
}
315
if (cpus.length > 0) {
316
ostream.println("");
317
}
318
319
cpus = c.getEffectiveCpuSetCpus();
320
ostream.println(INDENT + "List of Effective Processors, "
321
+ cpus.length + " total: ");
322
323
ostream.print(INDENT);
324
for (int i = 0; i < cpus.length; i++) {
325
ostream.print(cpus[i] + " ");
326
}
327
if (cpus.length > 0) {
328
ostream.println("");
329
}
330
331
int mems[] = c.getCpuSetMems();
332
ostream.println(INDENT + "List of Memory Nodes, "
333
+ mems.length + " total: ");
334
335
ostream.print(INDENT);
336
for (int i = 0; i < mems.length; i++) {
337
ostream.print(mems[i] + " ");
338
}
339
if (mems.length > 0) {
340
ostream.println("");
341
}
342
343
mems = c.getEffectiveCpuSetMems();
344
ostream.println(INDENT + "List of Available Memory Nodes, "
345
+ mems.length + " total: ");
346
347
ostream.print(INDENT);
348
for (int i = 0; i < mems.length; i++) {
349
ostream.print(mems[i] + " ");
350
}
351
if (mems.length > 0) {
352
ostream.println("");
353
}
354
355
ostream.println(INDENT + "CPUSet Memory Pressure Enabled: "
356
+ c.isCpuSetMemoryPressureEnabled());
357
358
long limit = c.getMemoryLimit();
359
ostream.println(INDENT + "Memory Limit: " +
360
((limit >= 0) ? SizePrefix.scaleValue(limit) : "Unlimited"));
361
362
limit = c.getMemorySoftLimit();
363
ostream.println(INDENT + "Memory Soft Limit: " +
364
((limit >= 0) ? SizePrefix.scaleValue(limit) : "Unlimited"));
365
366
limit = c.getMemoryAndSwapLimit();
367
ostream.println(INDENT + "Memory & Swap Limit: " +
368
((limit >= 0) ? SizePrefix.scaleValue(limit) : "Unlimited"));
369
370
limit = c.getKernelMemoryLimit();
371
ostream.println(INDENT + "Kernel Memory Limit: " +
372
((limit >= 0) ? SizePrefix.scaleValue(limit) : "Unlimited"));
373
374
limit = c.getTcpMemoryLimit();
375
ostream.println(INDENT + "TCP Memory Limit: " +
376
((limit >= 0) ? SizePrefix.scaleValue(limit) : "Unlimited"));
377
378
ostream.println(INDENT + "Out Of Memory Killer Enabled: "
379
+ c.isMemoryOOMKillEnabled());
380
381
ostream.println("");
382
}
383
384
private enum SizePrefix {
385
386
KILO(1024, "K"),
387
MEGA(1024 * 1024, "M"),
388
GIGA(1024 * 1024 * 1024, "G"),
389
TERA(1024L * 1024L * 1024L * 1024L, "T");
390
long size;
391
String abbrev;
392
393
SizePrefix(long size, String abbrev) {
394
this.size = size;
395
this.abbrev = abbrev;
396
}
397
398
private static String scale(long v, SizePrefix prefix) {
399
return BigDecimal.valueOf(v).divide(BigDecimal.valueOf(prefix.size),
400
2, RoundingMode.HALF_EVEN).toPlainString() + prefix.abbrev;
401
}
402
/*
403
* scale the incoming values to a human readable form, represented as
404
* K, M, G and T, see java.c parse_size for the scaled values and
405
* suffixes. The lowest possible scaled value is Kilo.
406
*/
407
static String scaleValue(long v) {
408
if (v < MEGA.size) {
409
return scale(v, KILO);
410
} else if (v < GIGA.size) {
411
return scale(v, MEGA);
412
} else if (v < TERA.size) {
413
return scale(v, GIGA);
414
} else {
415
return scale(v, TERA);
416
}
417
}
418
}
419
420
/**
421
* A private helper method to get a localized message and also
422
* apply any arguments that we might pass.
423
*/
424
private static String getLocalizedMessage(String key, Object... args) {
425
String msg = ResourceBundleHolder.RB.getString(key);
426
return (args != null) ? MessageFormat.format(msg, args) : msg;
427
}
428
429
/**
430
* The java -help message is split into 3 parts, an invariant, followed
431
* by a set of platform dependent variant messages, finally an invariant
432
* set of lines.
433
* This method initializes the help message for the first time, and also
434
* assembles the invariant header part of the message.
435
*/
436
static void initHelpMessage(String progname) {
437
outBuf = outBuf.append(getLocalizedMessage("java.launcher.opt.header",
438
(progname == null) ? "java" : progname ));
439
outBuf = outBuf.append(getLocalizedMessage("java.launcher.opt.datamodel",
440
32));
441
outBuf = outBuf.append(getLocalizedMessage("java.launcher.opt.datamodel",
442
64));
443
}
444
445
/**
446
* Appends the vm selection messages to the header, already created.
447
* initHelpSystem must already be called.
448
*/
449
static void appendVmSelectMessage(String vm1, String vm2) {
450
outBuf = outBuf.append(getLocalizedMessage("java.launcher.opt.vmselect",
451
vm1, vm2));
452
}
453
454
/**
455
* Appends the vm synoym message to the header, already created.
456
* initHelpSystem must be called before using this method.
457
*/
458
static void appendVmSynonymMessage(String vm1, String vm2) {
459
outBuf = outBuf.append(getLocalizedMessage("java.launcher.opt.hotspot",
460
vm1, vm2));
461
}
462
463
/**
464
* Appends the vm Ergo message to the header, already created.
465
* initHelpSystem must be called before using this method.
466
*/
467
static void appendVmErgoMessage(boolean isServerClass, String vm) {
468
outBuf = outBuf.append(getLocalizedMessage("java.launcher.ergo.message1",
469
vm));
470
outBuf = (isServerClass)
471
? outBuf.append(",\n" +
472
getLocalizedMessage("java.launcher.ergo.message2") + "\n\n")
473
: outBuf.append(".\n\n");
474
}
475
476
/**
477
* Appends the last invariant part to the previously created messages,
478
* and finishes up the printing to the desired output stream.
479
* initHelpSystem must be called before using this method.
480
*/
481
static void printHelpMessage(boolean printToStderr) {
482
initOutput(printToStderr);
483
outBuf = outBuf.append(getLocalizedMessage("java.launcher.opt.footer",
484
File.pathSeparator));
485
ostream.println(outBuf.toString());
486
}
487
488
/**
489
* Prints the Xusage text to the desired output stream.
490
*/
491
static void printXUsageMessage(boolean printToStderr) {
492
initOutput(printToStderr);
493
ostream.println(getLocalizedMessage("java.launcher.X.usage",
494
File.pathSeparator));
495
if (System.getProperty("os.name").contains("OS X")) {
496
ostream.println(getLocalizedMessage("java.launcher.X.macosx.usage",
497
File.pathSeparator));
498
}
499
}
500
501
static void initOutput(boolean printToStderr) {
502
ostream = (printToStderr) ? System.err : System.out;
503
}
504
505
static String getMainClassFromJar(String jarname) {
506
String mainValue = null;
507
try (JarFile jarFile = new JarFile(jarname)) {
508
Manifest manifest = jarFile.getManifest();
509
if (manifest == null) {
510
abort(null, "java.launcher.jar.error2", jarname);
511
}
512
Attributes mainAttrs = manifest.getMainAttributes();
513
if (mainAttrs == null) {
514
abort(null, "java.launcher.jar.error3", jarname);
515
}
516
mainValue = mainAttrs.getValue(MAIN_CLASS);
517
if (mainValue == null) {
518
abort(null, "java.launcher.jar.error3", jarname);
519
}
520
521
/*
522
* Hand off to FXHelper if it detects a JavaFX application
523
* This must be done after ensuring a Main-Class entry
524
* exists to enforce compliance with the jar specification
525
*/
526
if (mainAttrs.containsKey(
527
new Attributes.Name(FXHelper.JAVAFX_APPLICATION_MARKER))) {
528
return FXHelper.class.getName();
529
}
530
531
return mainValue.trim();
532
} catch (IOException ioe) {
533
abort(ioe, "java.launcher.jar.error1", jarname);
534
}
535
return null;
536
}
537
538
// From src/share/bin/java.c:
539
// enum LaunchMode { LM_UNKNOWN = 0, LM_CLASS, LM_JAR };
540
541
private static final int LM_UNKNOWN = 0;
542
private static final int LM_CLASS = 1;
543
private static final int LM_JAR = 2;
544
545
static void abort(Throwable t, String msgKey, Object... args) {
546
if (msgKey != null) {
547
ostream.println(getLocalizedMessage(msgKey, args));
548
}
549
if (trace) {
550
if (t != null) {
551
t.printStackTrace();
552
} else {
553
Thread.dumpStack();
554
}
555
}
556
System.exit(1);
557
}
558
559
/**
560
* This method does the following:
561
* 1. gets the classname from a Jar's manifest, if necessary
562
* 2. loads the class using the System ClassLoader
563
* 3. ensures the availability and accessibility of the main method,
564
* using signatureDiagnostic method.
565
* a. does the class exist
566
* b. is there a main
567
* c. is the main public
568
* d. is the main static
569
* e. does the main take a String array for args
570
* 4. if no main method and if the class extends FX Application, then call
571
* on FXHelper to determine the main class to launch
572
* 5. and off we go......
573
*
574
* @param printToStderr if set, all output will be routed to stderr
575
* @param mode LaunchMode as determined by the arguments passed on the
576
* command line
577
* @param what either the jar file to launch or the main class when using
578
* LM_CLASS mode
579
* @return the application's main class
580
*/
581
public static Class<?> checkAndLoadMain(boolean printToStderr,
582
int mode,
583
String what) {
584
initOutput(printToStderr);
585
// get the class name
586
String cn = null;
587
switch (mode) {
588
case LM_CLASS:
589
cn = what;
590
break;
591
case LM_JAR:
592
cn = getMainClassFromJar(what);
593
break;
594
default:
595
// should never happen
596
throw new InternalError("" + mode + ": Unknown launch mode");
597
}
598
cn = cn.replace('/', '.');
599
Class<?> mainClass = null;
600
try {
601
mainClass = scloader.loadClass(cn);
602
} catch (NoClassDefFoundError | ClassNotFoundException cnfe) {
603
if (System.getProperty("os.name", "").contains("OS X")
604
&& Normalizer.isNormalized(cn, Normalizer.Form.NFD)) {
605
try {
606
// On Mac OS X since all names with diacretic symbols are given as decomposed it
607
// is possible that main class name comes incorrectly from the command line
608
// and we have to re-compose it
609
mainClass = scloader.loadClass(Normalizer.normalize(cn, Normalizer.Form.NFC));
610
} catch (NoClassDefFoundError | ClassNotFoundException cnfe1) {
611
abort(cnfe, "java.launcher.cls.error1", cn);
612
}
613
} else {
614
abort(cnfe, "java.launcher.cls.error1", cn);
615
}
616
}
617
// set to mainClass
618
appClass = mainClass;
619
620
/*
621
* Check if FXHelper can launch it using the FX launcher. In an FX app,
622
* the main class may or may not have a main method, so do this before
623
* validating the main class.
624
*/
625
if (mainClass.equals(FXHelper.class) ||
626
FXHelper.doesExtendFXApplication(mainClass)) {
627
// Will abort() if there are problems with the FX runtime
628
FXHelper.setFXLaunchParameters(what, mode);
629
return FXHelper.class;
630
}
631
632
validateMainClass(mainClass);
633
return mainClass;
634
}
635
636
/*
637
* Accessor method called by the launcher after getting the main class via
638
* checkAndLoadMain(). The "application class" is the class that is finally
639
* executed to start the application and in this case is used to report
640
* the correct application name, typically for UI purposes.
641
*/
642
public static Class<?> getApplicationClass() {
643
return appClass;
644
}
645
646
// Check the existence and signature of main and abort if incorrect
647
static void validateMainClass(Class<?> mainClass) {
648
Method mainMethod;
649
try {
650
mainMethod = mainClass.getMethod("main", String[].class);
651
} catch (NoSuchMethodException nsme) {
652
// invalid main or not FX application, abort with an error
653
abort(null, "java.launcher.cls.error4", mainClass.getName(),
654
FXHelper.JAVAFX_APPLICATION_CLASS_NAME);
655
return; // Avoid compiler issues
656
}
657
658
/*
659
* getMethod (above) will choose the correct method, based
660
* on its name and parameter type, however, we still have to
661
* ensure that the method is static and returns a void.
662
*/
663
int mod = mainMethod.getModifiers();
664
if (!Modifier.isStatic(mod)) {
665
abort(null, "java.launcher.cls.error2", "static",
666
mainMethod.getDeclaringClass().getName());
667
}
668
if (mainMethod.getReturnType() != java.lang.Void.TYPE) {
669
abort(null, "java.launcher.cls.error3",
670
mainMethod.getDeclaringClass().getName());
671
}
672
}
673
674
private static final String encprop = "sun.jnu.encoding";
675
private static String encoding = null;
676
private static boolean isCharsetSupported = false;
677
678
/*
679
* converts a c or a byte array to a platform specific string,
680
* previously implemented as a native method in the launcher.
681
*/
682
static String makePlatformString(boolean printToStderr, byte[] inArray) {
683
initOutput(printToStderr);
684
if (encoding == null) {
685
encoding = System.getProperty(encprop);
686
isCharsetSupported = Charset.isSupported(encoding);
687
}
688
try {
689
String out = isCharsetSupported
690
? new String(inArray, encoding)
691
: new String(inArray);
692
return out;
693
} catch (UnsupportedEncodingException uee) {
694
abort(uee, null);
695
}
696
return null; // keep the compiler happy
697
}
698
699
static String[] expandArgs(String[] argArray) {
700
List<StdArg> aList = new ArrayList<>();
701
for (String x : argArray) {
702
aList.add(new StdArg(x));
703
}
704
return expandArgs(aList);
705
}
706
707
static String[] expandArgs(List<StdArg> argList) {
708
ArrayList<String> out = new ArrayList<>();
709
if (trace) {
710
System.err.println("Incoming arguments:");
711
}
712
for (StdArg a : argList) {
713
if (trace) {
714
System.err.println(a);
715
}
716
if (a.needsExpansion) {
717
File x = new File(a.arg);
718
File parent = x.getParentFile();
719
String glob = x.getName();
720
if (parent == null) {
721
parent = new File(".");
722
}
723
try (DirectoryStream<Path> dstream =
724
Files.newDirectoryStream(parent.toPath(), glob)) {
725
int entries = 0;
726
for (Path p : dstream) {
727
out.add(p.normalize().toString());
728
entries++;
729
}
730
if (entries == 0) {
731
out.add(a.arg);
732
}
733
} catch (Exception e) {
734
out.add(a.arg);
735
if (trace) {
736
System.err.println("Warning: passing argument as-is " + a);
737
System.err.print(e);
738
}
739
}
740
} else {
741
out.add(a.arg);
742
}
743
}
744
String[] oarray = new String[out.size()];
745
out.toArray(oarray);
746
747
if (trace) {
748
System.err.println("Expanded arguments:");
749
for (String x : oarray) {
750
System.err.println(x);
751
}
752
}
753
return oarray;
754
}
755
756
/* duplicate of the native StdArg struct */
757
private static class StdArg {
758
final String arg;
759
final boolean needsExpansion;
760
StdArg(String arg, boolean expand) {
761
this.arg = arg;
762
this.needsExpansion = expand;
763
}
764
// protocol: first char indicates whether expansion is required
765
// 'T' = true ; needs expansion
766
// 'F' = false; needs no expansion
767
StdArg(String in) {
768
this.arg = in.substring(1);
769
needsExpansion = in.charAt(0) == 'T';
770
}
771
public String toString() {
772
return "StdArg{" + "arg=" + arg + ", needsExpansion=" + needsExpansion + '}';
773
}
774
}
775
776
static final class FXHelper {
777
// Marker entry in jar manifest that designates a JavaFX application jar
778
private static final String JAVAFX_APPLICATION_MARKER =
779
"JavaFX-Application-Class";
780
private static final String JAVAFX_APPLICATION_CLASS_NAME =
781
"javafx.application.Application";
782
private static final String JAVAFX_LAUNCHER_CLASS_NAME =
783
"com.sun.javafx.application.LauncherImpl";
784
785
/*
786
* The launch method used to invoke the JavaFX launcher. These must
787
* match the strings used in the launchApplication method.
788
*
789
* Command line JavaFX-App-Class Launch mode FX Launch mode
790
* java -cp fxapp.jar FXClass N/A LM_CLASS "LM_CLASS"
791
* java -cp somedir FXClass N/A LM_CLASS "LM_CLASS"
792
* java -jar fxapp.jar Present LM_JAR "LM_JAR"
793
* java -jar fxapp.jar Not Present LM_JAR "LM_JAR"
794
*/
795
private static final String JAVAFX_LAUNCH_MODE_CLASS = "LM_CLASS";
796
private static final String JAVAFX_LAUNCH_MODE_JAR = "LM_JAR";
797
798
/*
799
* FX application launcher and launch method, so we can launch
800
* applications with no main method.
801
*/
802
private static String fxLaunchName = null;
803
private static String fxLaunchMode = null;
804
805
private static Class<?> fxLauncherClass = null;
806
private static Method fxLauncherMethod = null;
807
808
/*
809
* Set the launch params according to what was passed to LauncherHelper
810
* so we can use the same launch mode for FX. Abort if there is any
811
* issue with loading the FX runtime or with the launcher method.
812
*/
813
private static void setFXLaunchParameters(String what, int mode) {
814
// Check for the FX launcher classes
815
try {
816
fxLauncherClass = scloader.loadClass(JAVAFX_LAUNCHER_CLASS_NAME);
817
/*
818
* signature must be:
819
* public static void launchApplication(String launchName,
820
* String launchMode, String[] args);
821
*/
822
fxLauncherMethod = fxLauncherClass.getMethod("launchApplication",
823
String.class, String.class, String[].class);
824
825
// verify launcher signature as we do when validating the main method
826
int mod = fxLauncherMethod.getModifiers();
827
if (!Modifier.isStatic(mod)) {
828
abort(null, "java.launcher.javafx.error1");
829
}
830
if (fxLauncherMethod.getReturnType() != java.lang.Void.TYPE) {
831
abort(null, "java.launcher.javafx.error1");
832
}
833
} catch (ClassNotFoundException | NoSuchMethodException ex) {
834
abort(ex, "java.launcher.cls.error5", ex);
835
}
836
837
fxLaunchName = what;
838
switch (mode) {
839
case LM_CLASS:
840
fxLaunchMode = JAVAFX_LAUNCH_MODE_CLASS;
841
break;
842
case LM_JAR:
843
fxLaunchMode = JAVAFX_LAUNCH_MODE_JAR;
844
break;
845
default:
846
// should not have gotten this far...
847
throw new InternalError(mode + ": Unknown launch mode");
848
}
849
}
850
851
/*
852
* Check if the given class is a JavaFX Application class. This is done
853
* in a way that does not cause the Application class to load or throw
854
* ClassNotFoundException if the JavaFX runtime is not available.
855
*/
856
private static boolean doesExtendFXApplication(Class<?> mainClass) {
857
for (Class<?> sc = mainClass.getSuperclass(); sc != null;
858
sc = sc.getSuperclass()) {
859
if (sc.getName().equals(JAVAFX_APPLICATION_CLASS_NAME)) {
860
return true;
861
}
862
}
863
return false;
864
}
865
866
public static void main(String... args) throws Exception {
867
if (fxLauncherMethod == null
868
|| fxLaunchMode == null
869
|| fxLaunchName == null) {
870
throw new RuntimeException("Invalid JavaFX launch parameters");
871
}
872
// launch appClass via fxLauncherMethod
873
fxLauncherMethod.invoke(null,
874
new Object[] {fxLaunchName, fxLaunchMode, args});
875
}
876
}
877
}
878
879