1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
|
/* *******************************************************************
* Copyright (c) 1999-2001 Xerox Corporation,
* 2002 Palo Alto Research Center, Incorporated (PARC).
* 2018 Contributors
* All rights reserved.
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License v1.0
* which accompanies this distribution and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Xerox/PARC initial implementation
* ******************************************************************/
package org.aspectj.util;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.security.PrivilegedActionException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
/**
*
*/
public class LangUtil {
public static final String EOL;
public static final String JRT_FS = "jrt-fs.jar";
private static double vmVersion;
/**
* @return the vm version (1.1, 1.2, 1.3, 1.4, etc)
*/
public static String getVmVersionString() {
return Double.toString(vmVersion);
}
public static double getVmVersion() {
return vmVersion;
}
static {
StringWriter buf = new StringWriter();
PrintWriter writer = new PrintWriter(buf);
writer.println("");
String eol = "\n";
try {
buf.close();
StringBuffer sb = buf.getBuffer();
if (sb != null) {
eol = buf.toString();
}
} catch (Throwable t) {
}
EOL = eol;
}
static {
// http://www.oracle.com/technetwork/java/javase/versioning-naming-139433.html
// http://openjdk.java.net/jeps/223 "New Version-String Scheme"
try {
String vm = System.getProperty("java.version"); // JLS 20.18.7
if (vm == null) {
vm = System.getProperty("java.runtime.version");
}
if (vm == null) {
vm = System.getProperty("java.vm.version");
}
if (vm == null) {
new RuntimeException(
"System properties appear damaged, cannot find: java.version/java.runtime.version/java.vm.version")
.printStackTrace(System.err);
vmVersion = 1.5;
} else {
// Version: [1-9][0-9]*((\.0)*\.[1-9][0-9]*)*
// Care about the first set of digits and second set if first digit is 1
try {
List<Integer> numbers = getFirstNumbers(vm);
if (numbers.get(0) == 1) {
// Old school for 1.0 > 1.8
vmVersion = numbers.get(0)+(numbers.get(1)/10d);
} else {
// numbers.get(0) is the major version (9 and above)
// Note here the number will be 9 (or 10), *not* 1.9 or 1.10
vmVersion = numbers.get(0);
}
} catch (Throwable t) {
// Give up
vmVersion = 1.5;
}
}
} catch (Throwable t) {
new RuntimeException(
"System properties appear damaged, cannot find: java.version/java.runtime.version/java.vm.version", t)
.printStackTrace(System.err);
vmVersion = 1.5;
}
}
private static List<Integer> getFirstNumbers(String vm) {
List<Integer> result = new ArrayList<>();
StringTokenizer st = new StringTokenizer(vm,".-_");
try {
result.add(Integer.parseInt(st.nextToken()));
result.add(Integer.parseInt(st.nextToken()));
} catch (Exception e) {
// NoSuchElementException if no more tokens
// NumberFormatException if not a number
}
return result;
}
@Deprecated
public static boolean is1dot3VMOrGreater() {
return 1.3 <= vmVersion;
}
@Deprecated
public static boolean is1dot4VMOrGreater() {
return 1.4 <= vmVersion;
}
@Deprecated
public static boolean is1dot5VMOrGreater() {
return 1.5 <= vmVersion;
}
@Deprecated
public static boolean is1dot6VMOrGreater() {
return 1.6 <= vmVersion;
}
@Deprecated
public static boolean is1dot7VMOrGreater() {
return 1.7 <= vmVersion;
}
public static boolean is1dot8VMOrGreater() {
return 1.8 <= vmVersion;
}
public static boolean is9VMOrGreater() {
return 9 <= vmVersion;
}
public static boolean is10VMOrGreater() {
return 10 <= vmVersion;
}
public static boolean is11VMOrGreater() {
return 11 <= vmVersion;
}
public static boolean is12VMOrGreater() {
return 12 <= vmVersion;
}
public static boolean is13VMOrGreater() {
return 13 <= vmVersion;
}
public static boolean is14VMOrGreater() {
return 14 <= vmVersion;
}
public static boolean is15VMOrGreater() {
return 15 <= vmVersion;
}
/**
* Shorthand for "if null, throw IllegalArgumentException"
*
* @throws IllegalArgumentException "null {name}" if o is null
*/
public static final void throwIaxIfNull(final Object o, final String name) {
if (null == o) {
String message = "null " + (null == name ? "input" : name);
throw new IllegalArgumentException(message);
}
}
/**
* Shorthand for "if not null or not assignable, throw IllegalArgumentException"
*
* @param c the Class to check - use null to ignore type check
* @throws IllegalArgumentException "null {name}" if o is null
*/
public static final void throwIaxIfNotAssignable(final Object ra[], final Class<?> c, final String name) {
throwIaxIfNull(ra, name);
String label = (null == name ? "input" : name);
for (int i = 0; i < ra.length; i++) {
if (null == ra[i]) {
String m = " null " + label + "[" + i + "]";
throw new IllegalArgumentException(m);
} else if (null != c) {
Class<?> actualClass = ra[i].getClass();
if (!c.isAssignableFrom(actualClass)) {
String message = label + " not assignable to " + c.getName();
throw new IllegalArgumentException(message);
}
}
}
}
/**
* Shorthand for "if not null or not assignable, throw IllegalArgumentException"
*
* @throws IllegalArgumentException "null {name}" if o is null
*/
public static final void throwIaxIfNotAssignable(final Object o, final Class<?> c, final String name) {
throwIaxIfNull(o, name);
if (null != c) {
Class<?> actualClass = o.getClass();
if (!c.isAssignableFrom(actualClass)) {
String message = name + " not assignable to " + c.getName();
throw new IllegalArgumentException(message);
}
}
}
// /**
// * Shorthand for
// "if any not null or not assignable, throw IllegalArgumentException"
// * @throws IllegalArgumentException "{name} is not assignable to {c}"
// */
// public static final void throwIaxIfNotAllAssignable(final Collection
// collection,
// final Class c, final String name) {
// throwIaxIfNull(collection, name);
// if (null != c) {
// for (Iterator iter = collection.iterator(); iter.hasNext();) {
// throwIaxIfNotAssignable(iter.next(), c, name);
//
// }
// }
// }
/**
* Shorthand for "if false, throw IllegalArgumentException"
*
* @throws IllegalArgumentException "{message}" if test is false
*/
public static final void throwIaxIfFalse(final boolean test, final String message) {
if (!test) {
throw new IllegalArgumentException(message);
}
}
// /** @return ((null == s) || (0 == s.trim().length())); */
// public static boolean isEmptyTrimmed(String s) {
// return ((null == s) || (0 == s.length())
// || (0 == s.trim().length()));
// }
/** @return ((null == s) || (0 == s.length())); */
public static boolean isEmpty(String s) {
return ((null == s) || (0 == s.length()));
}
/** @return ((null == ra) || (0 == ra.length)) */
public static boolean isEmpty(Object[] ra) {
return ((null == ra) || (0 == ra.length));
}
/** @return ((null == ra) || (0 == ra.length)) */
public static boolean isEmpty(byte[] ra) {
return ((null == ra) || (0 == ra.length));
}
/** @return ((null == collection) || (0 == collection.size())) */
public static boolean isEmpty(Collection<?> collection) {
return ((null == collection) || (0 == collection.size()));
}
/** @return ((null == map) || (0 == map.size())) */
public static boolean isEmpty(Map<?,?> map) {
return ((null == map) || (0 == map.size()));
}
/**
* Splits <code>text</code> at whitespace.
*
* @param text <code>String</code> to split.
*/
public static String[] split(String text) {
return strings(text).toArray(new String[0]);
}
/**
* Splits <code>input</code> at commas, trimming any white space.
*
* @param input <code>String</code> to split.
* @return List of String of elements.
*/
public static List<String> commaSplit(String input) {
return anySplit(input, ",");
}
/**
* Split string as classpath, delimited at File.pathSeparator. Entries are not trimmed, but empty entries are ignored.
*
* @param classpath the String to split - may be null or empty
* @return String[] of classpath entries
*/
public static String[] splitClasspath(String classpath) {
if (LangUtil.isEmpty(classpath)) {
return new String[0];
}
StringTokenizer st = new StringTokenizer(classpath, File.pathSeparator);
ArrayList<String> result = new ArrayList<>(st.countTokens());
while (st.hasMoreTokens()) {
String entry = st.nextToken();
if (!LangUtil.isEmpty(entry)) {
result.add(entry);
}
}
return result.toArray(new String[0]);
}
/**
* Get System property as boolean, but use default value where the system property is not set.
*
* @return true if value is set to true, false otherwise
*/
public static boolean getBoolean(String propertyName, boolean defaultValue) {
if (null != propertyName) {
try {
String value = System.getProperty(propertyName);
if (null != value) {
return Boolean.valueOf(value);
}
} catch (Throwable t) {
// default below
}
}
return defaultValue;
}
/**
* Splits <code>input</code>, removing delimiter and trimming any white space. Returns an empty collection if the input is null.
* If delimiter is null or empty or if the input contains no delimiters, the input itself is returned after trimming white
* space.
*
* @param input <code>String</code> to split.
* @param delim <code>String</code> separators for input.
* @return List of String of elements.
*/
public static List<String> anySplit(String input, String delim) {
if (null == input) {
return Collections.emptyList();
}
List<String> result = new ArrayList<>();
if (LangUtil.isEmpty(delim) || (!input.contains(delim))) {
result.add(input.trim());
} else {
StringTokenizer st = new StringTokenizer(input, delim);
while (st.hasMoreTokens()) {
result.add(st.nextToken().trim());
}
}
return result;
}
/**
* Splits strings into a <code>List</code> using a <code>StringTokenizer</code>.
*
* @param text <code>String</code> to split.
*/
public static List<String> strings(String text) {
if (LangUtil.isEmpty(text)) {
return Collections.emptyList();
}
List<String> strings = new ArrayList<>();
StringTokenizer tok = new StringTokenizer(text);
while (tok.hasMoreTokens()) {
strings.add(tok.nextToken());
}
return strings;
}
/** @return a non-null unmodifiable List */
public static <T> List<T> safeList(List<T> list) {
return (null == list ? Collections.<T>emptyList() : Collections.unmodifiableList(list));
}
// /**
// * Select from input String[] based on suffix-matching
// * @param inputs String[] of input - null ignored
// * @param suffixes String[] of suffix selectors - null ignored
// * @param ignoreCase if true, ignore case
// * @return String[] of input that end with any input
// */
// public static String[] endsWith(String[] inputs, String[] suffixes,
// boolean ignoreCase) {
// if (LangUtil.isEmpty(inputs) || LangUtil.isEmpty(suffixes)) {
// return new String[0];
// }
// if (ignoreCase) {
// String[] temp = new String[suffixes.length];
// for (int i = 0; i < temp.length; i++) {
// String suff = suffixes[i];
// temp[i] = (null == suff ? null : suff.toLowerCase());
// }
// suffixes = temp;
// }
// ArrayList result = new ArrayList();
// for (int i = 0; i < inputs.length; i++) {
// String input = inputs[i];
// if (null == input) {
// continue;
// }
// if (!ignoreCase) {
// input = input.toLowerCase();
// }
// for (int j = 0; j < suffixes.length; j++) {
// String suffix = suffixes[j];
// if (null == suffix) {
// continue;
// }
// if (input.endsWith(suffix)) {
// result.add(input);
// break;
// }
// }
// }
// return (String[]) result.toArray(new String[0]);
// }
//
// /**
// * Select from input String[] if readable directories
// * @param inputs String[] of input - null ignored
// * @param baseDir the base directory of the input
// * @return String[] of input that end with any input
// */
// public static String[] selectDirectories(String[] inputs, File baseDir) {
// if (LangUtil.isEmpty(inputs)) {
// return new String[0];
// }
// ArrayList result = new ArrayList();
// for (int i = 0; i < inputs.length; i++) {
// String input = inputs[i];
// if (null == input) {
// continue;
// }
// File inputFile = new File(baseDir, input);
// if (inputFile.canRead() && inputFile.isDirectory()) {
// result.add(input);
// }
// }
// return (String[]) result.toArray(new String[0]);
// }
/**
* copy non-null two-dimensional String[][]
*
* @see extractOptions(String[], String[][])
*/
public static String[][] copyStrings(String[][] in) {
String[][] out = new String[in.length][];
for (int i = 0; i < out.length; i++) {
out[i] = new String[in[i].length];
System.arraycopy(in[i], 0, out[i], 0, out[i].length);
}
return out;
}
/**
* Extract options and arguments to input option list, returning remainder. The input options will be nullified if not found.
* e.g.,
*
* <pre>
* String[] options = new String[][] { new String[] { "-verbose" }, new String[] { "-classpath", null } };
* String[] args = extractOptions(args, options);
* boolean verbose = null != options[0][0];
* boolean classpath = options[1][1];
* </pre>
*
* @param args the String[] input options
* @param options the String[][]options to find in the input args - not null for each String[] component the first subcomponent
* is the option itself, and there is one String subcomponent for each additional argument.
* @return String[] of args remaining after extracting options to extracted
*/
public static String[] extractOptions(String[] args, String[][] options) {
if (LangUtil.isEmpty(args) || LangUtil.isEmpty(options)) {
return args;
}
BitSet foundSet = new BitSet();
String[] result = new String[args.length];
int resultIndex = 0;
for (int j = 0; j < args.length; j++) {
boolean found = false;
for (int i = 0; !found && (i < options.length); i++) {
String[] option = options[i];
LangUtil.throwIaxIfFalse(!LangUtil.isEmpty(option), "options");
String sought = option[0];
found = sought.equals(args[j]);
if (found) {
foundSet.set(i);
int doMore = option.length - 1;
if (0 < doMore) {
final int MAX = j + doMore;
if (MAX >= args.length) {
String s = "expecting " + doMore + " args after ";
throw new IllegalArgumentException(s + args[j]);
}
for (int k = 1; k < option.length; k++) {
option[k] = args[++j];
}
}
}
}
if (!found) {
result[resultIndex++] = args[j];
}
}
// unset any not found
for (int i = 0; i < options.length; i++) {
if (!foundSet.get(i)) {
options[i][0] = null;
}
}
// fixup remainder
if (resultIndex < args.length) {
String[] temp = new String[resultIndex];
System.arraycopy(result, 0, temp, 0, resultIndex);
args = temp;
}
return args;
}
//
// /**
// * Extract options and arguments to input parameter list, returning
// remainder.
// * @param args the String[] input options
// * @param validOptions the String[] options to find in the input args -
// not null
// * @param optionArgs the int[] number of arguments for each option in
// validOptions
// * (if null, then no arguments for any option)
// * @param extracted the List for the matched options
// * @return String[] of args remaining after extracting options to
// extracted
// */
// public static String[] extractOptions(String[] args, String[]
// validOptions,
// int[] optionArgs, List extracted) {
// if (LangUtil.isEmpty(args)
// || LangUtil.isEmpty(validOptions) ) {
// return args;
// }
// if (null != optionArgs) {
// if (optionArgs.length != validOptions.length) {
// throw new IllegalArgumentException("args must match options");
// }
// }
// String[] result = new String[args.length];
// int resultIndex = 0;
// for (int j = 0; j < args.length; j++) {
// boolean found = false;
// for (int i = 0; !found && (i < validOptions.length); i++) {
// String sought = validOptions[i];
// int doMore = (null == optionArgs ? 0 : optionArgs[i]);
// if (LangUtil.isEmpty(sought)) {
// continue;
// }
// found = sought.equals(args[j]);
// if (found) {
// if (null != extracted) {
// extracted.add(sought);
// }
// if (0 < doMore) {
// final int MAX = j + doMore;
// if (MAX >= args.length) {
// String s = "expecting " + doMore + " args after ";
// throw new IllegalArgumentException(s + args[j]);
// }
// if (null != extracted) {
// while (j < MAX) {
// extracted.add(args[++j]);
// }
// } else {
// j = MAX;
// }
// }
// break;
// }
// }
// if (!found) {
// result[resultIndex++] = args[j];
// }
// }
// if (resultIndex < args.length) {
// String[] temp = new String[resultIndex];
// System.arraycopy(result, 0, temp, 0, resultIndex);
// args = temp;
// }
// return args;
// }
// /** @return String[] of entries in validOptions found in args */
// public static String[] selectOptions(String[] args, String[]
// validOptions) {
// if (LangUtil.isEmpty(args) || LangUtil.isEmpty(validOptions)) {
// return new String[0];
// }
// ArrayList result = new ArrayList();
// for (int i = 0; i < validOptions.length; i++) {
// String sought = validOptions[i];
// if (LangUtil.isEmpty(sought)) {
// continue;
// }
// for (int j = 0; j < args.length; j++) {
// if (sought.equals(args[j])) {
// result.add(sought);
// break;
// }
// }
// }
// return (String[]) result.toArray(new String[0]);
// }
// /** @return String[] of entries in validOptions found in args */
// public static String[] selectOptions(List args, String[] validOptions) {
// if (LangUtil.isEmpty(args) || LangUtil.isEmpty(validOptions)) {
// return new String[0];
// }
// ArrayList result = new ArrayList();
// for (int i = 0; i < validOptions.length; i++) {
// String sought = validOptions[i];
// if (LangUtil.isEmpty(sought)) {
// continue;
// }
// for (Iterator iter = args.iterator(); iter.hasNext();) {
// String arg = (String) iter.next();
// if (sought.equals(arg)) {
// result.add(sought);
// break;
// }
// }
// }
// return (String[]) result.toArray(new String[0]);
// }
// /**
// * Generate variants of String[] options by creating an extra set for
// * each option that ends with "-". If none end with "-", then an
// * array equal to <code>new String[][] { options }</code> is returned;
// * if one ends with "-", then two sets are returned,
// * three causes eight sets, etc.
// * @return String[][] with each option set.
// * @throws IllegalArgumentException if any option is null or empty.
// */
// public static String[][] optionVariants(String[] options) {
// if ((null == options) || (0 == options.length)) {
// return new String[][] { new String[0]};
// }
// // be nice, don't stomp input
// String[] temp = new String[options.length];
// System.arraycopy(options, 0, temp, 0, temp.length);
// options = temp;
// boolean[] dup = new boolean[options.length];
// int numDups = 0;
//
// for (int i = 0; i < options.length; i++) {
// String option = options[i];
// if (LangUtil.isEmpty(option)) {
// throw new IllegalArgumentException("empty option at " + i);
// }
// if (option.endsWith("-")) {
// options[i] = option.substring(0, option.length()-1);
// dup[i] = true;
// numDups++;
// }
// }
// final String[] NONE = new String[0];
// final int variants = exp(2, numDups);
// final String[][] result = new String[variants][];
// // variant is a bitmap wrt doing extra value when dup[k]=true
// for (int variant = 0; variant < variants; variant++) {
// ArrayList next = new ArrayList();
// int nextOption = 0;
// for (int k = 0; k < options.length; k++) {
// if (!dup[k] || (0 != (variant & (1 << (nextOption++))))) {
// next.add(options[k]);
// }
// }
// result[variant] = (String[]) next.toArray(NONE);
// }
// return result;
// }
//
// private static int exp(int base, int power) { // not in Math?
// if (0 > power) {
// throw new IllegalArgumentException("negative power: " + power);
// }
// int result = 1;
// while (0 < power--) {
// result *= base;
// }
// return result;
// }
// /**
// * Make a copy of the array.
// * @return an array with the same component type as source
// * containing same elements, even if null.
// * @throws IllegalArgumentException if source is null
// */
// public static final Object[] copy(Object[] source) {
// LangUtil.throwIaxIfNull(source, "source");
// final Class c = source.getClass().getComponentType();
// Object[] result = (Object[]) Array.newInstance(c, source.length);
// System.arraycopy(source, 0, result, 0, result.length);
// return result;
// }
/**
* Convert arrays safely. The number of elements in the result will be 1 smaller for each element that is null or not
* assignable. This will use sink if it has exactly the right size. The result will always have the same component type as sink.
*
* @return an array with the same component type as sink containing any assignable elements in source (in the same order).
* @throws IllegalArgumentException if either is null
*/
public static Object[] safeCopy(Object[] source, Object[] sink) {
final Class<?> sinkType = (null == sink ? Object.class : sink.getClass().getComponentType());
final int sourceLength = (null == source ? 0 : source.length);
final int sinkLength = (null == sink ? 0 : sink.length);
final int resultSize;
List<Object> result = null;
if (0 == sourceLength) {
resultSize = 0;
} else {
result = new ArrayList<>(sourceLength);
for (int i = 0; i < sourceLength; i++) {
if ((null != source[i]) && (sinkType.isAssignableFrom(source[i].getClass()))) {
result.add(source[i]);
}
}
resultSize = result.size();
}
if (resultSize != sinkLength) {
sink = (Object[]) Array.newInstance(sinkType, result.size());
}
if (0 < resultSize) {
sink = result.toArray(sink);
}
return sink;
}
/**
* @return a String with the unqualified class name of the class (or "null")
*/
public static String unqualifiedClassName(Class<?> c) {
if (null == c) {
return "null";
}
String name = c.getName();
int loc = name.lastIndexOf(".");
if (-1 != loc) {
name = name.substring(1 + loc);
}
return name;
}
/**
* @return a String with the unqualified class name of the object (or "null")
*/
public static String unqualifiedClassName(Object o) {
return LangUtil.unqualifiedClassName(null == o ? null : o.getClass());
}
/** inefficient way to replace all instances of sought with replace */
public static String replace(String in, String sought, String replace) {
if (LangUtil.isEmpty(in) || LangUtil.isEmpty(sought)) {
return in;
}
StringBuffer result = new StringBuffer();
final int len = sought.length();
int start = 0;
int loc;
while (-1 != (loc = in.indexOf(sought, start))) {
result.append(in.substring(start, loc));
if (!LangUtil.isEmpty(replace)) {
result.append(replace);
}
start = loc + len;
}
result.append(in.substring(start));
return result.toString();
}
/** render i right-justified with a given width less than about 40 */
public static String toSizedString(long i, int width) {
String result = "" + i;
int size = result.length();
if (width > size) {
final String pad = " ";
final int padLength = pad.length();
if (width > padLength) {
width = padLength;
}
int topad = width - size;
result = pad.substring(0, topad) + result;
}
return result;
}
// /** clip StringBuffer to maximum number of lines */
// static String clipBuffer(StringBuffer buffer, int maxLines) {
// if ((null == buffer) || (1 > buffer.length())) return "";
// StringBuffer result = new StringBuffer();
// int j = 0;
// final int MAX = maxLines;
// final int N = buffer.length();
// for (int i = 0, srcBegin = 0; i < MAX; srcBegin += j) {
// // todo: replace with String variant if/since getting char?
// char[] chars = new char[128];
// int srcEnd = srcBegin+chars.length;
// if (srcEnd >= N) {
// srcEnd = N-1;
// }
// if (srcBegin == srcEnd) break;
// //log("srcBegin:" + srcBegin + ":srcEnd:" + srcEnd);
// buffer.getChars(srcBegin, srcEnd, chars, 0);
// for (j = 0; j < srcEnd-srcBegin/*chars.length*/; j++) {
// char c = chars[j];
// if (c == '\n') {
// i++;
// j++;
// break;
// }
// }
// try { result.append(chars, 0, j); }
// catch (Throwable t) { }
// }
// return result.toString();
// }
/**
* @return "({UnqualifiedExceptionClass}) {message}"
*/
public static String renderExceptionShort(Throwable e) {
if (null == e) {
return "(Throwable) null";
}
return "(" + LangUtil.unqualifiedClassName(e) + ") " + e.getMessage();
}
/**
* Renders exception <code>t</code> after unwrapping and eliding any test packages.
*
* @param t <code>Throwable</code> to print.
* @see StringChecker#TEST_PACKAGES
*/
public static String renderException(Throwable t) {
return renderException(t, true);
}
/**
* Renders exception <code>t</code>, unwrapping, optionally eliding and limiting total number of lines.
*
* @param t <code>Throwable</code> to print.
* @param elide true to limit to 100 lines and elide test packages
* @see StringChecker#TEST_PACKAGES
*/
public static String renderException(Throwable t, boolean elide) {
if (null == t) {
return "null throwable";
}
t = unwrapException(t);
StringBuffer stack = stackToString(t, false);
if (elide) {
elideEndingLines(StringChecker.TEST_PACKAGES, stack, 100);
}
return stack.toString();
}
/**
* Trim ending lines from a StringBuffer, clipping to maxLines and further removing any number of trailing lines accepted by
* checker.
*
* @param checker returns true if trailing line should be elided.
* @param stack StringBuffer with lines to elide
* @param maxLines int for maximum number of resulting lines
*/
static void elideEndingLines(StringChecker checker, StringBuffer stack, int maxLines) {
if (null == checker || (null == stack) || (0 == stack.length())) {
return;
}
final LinkedList<String> lines = new LinkedList<>();
StringTokenizer st = new StringTokenizer(stack.toString(), "\n\r");
while (st.hasMoreTokens() && (0 < --maxLines)) {
lines.add(st.nextToken());
}
st = null;
String line;
int elided = 0;
while (!lines.isEmpty()) {
line = lines.getLast();
if (!checker.acceptString(line)) {
break;
} else {
elided++;
lines.removeLast();
}
}
if ((elided > 0) || (maxLines < 1)) {
final int EOL_LEN = EOL.length();
int totalLength = 0;
while (!lines.isEmpty()) {
totalLength += EOL_LEN + lines.getFirst().length();
lines.removeFirst();
}
if (stack.length() > totalLength) {
stack.setLength(totalLength);
if (elided > 0) {
stack.append(" (... " + elided + " lines...)");
}
}
}
}
/** Dump message and stack to StringBuffer. */
public static StringBuffer stackToString(Throwable throwable, boolean skipMessage) {
if (null == throwable) {
return new StringBuffer();
}
StringWriter buf = new StringWriter();
PrintWriter writer = new PrintWriter(buf);
if (!skipMessage) {
writer.println(throwable.getMessage());
}
throwable.printStackTrace(writer);
try {
buf.close();
} catch (IOException ioe) {
} // ignored
return buf.getBuffer();
}
/** @return Throwable input or tail of any wrapped exception chain */
public static Throwable unwrapException(Throwable t) {
Throwable current = t;
Throwable next = null;
while (current != null) {
// Java 1.2 exceptions that carry exceptions
if (current instanceof InvocationTargetException) {
next = ((InvocationTargetException) current).getTargetException();
} else if (current instanceof ClassNotFoundException) {
next = ((ClassNotFoundException) current).getException();
} else if (current instanceof ExceptionInInitializerError) {
next = ((ExceptionInInitializerError) current).getException();
} else if (current instanceof PrivilegedActionException) {
next = ((PrivilegedActionException) current).getException();
} else if (current instanceof SQLException) {
next = ((SQLException) current).getNextException();
}
// ...getException():
// javax.naming.event.NamingExceptionEvent
// javax.naming.ldap.UnsolicitedNotification
// javax.xml.parsers.FactoryConfigurationError
// javax.xml.transform.TransformerFactoryConfigurationError
// javax.xml.transform.TransformerException
// org.xml.sax.SAXException
// 1.4: Throwable.getCause
// java.util.logging.LogRecord.getThrown()
if (null == next) {
break;
} else {
current = next;
next = null;
}
}
return current;
}
/**
* Replacement for Arrays.asList(..) which gacks on null and returns a List in which remove is an unsupported operation.
*
* @param array the Object[] to convert (may be null)
* @return the List corresponding to array (never null)
*/
public static <T> List<T> arrayAsList(T[] array) {
if ((null == array) || (1 > array.length)) {
return Collections.emptyList();
}
List<T> list = new ArrayList<>(Arrays.asList(array));
return list;
}
/** check if input contains any packages to elide. */
public static class StringChecker {
static StringChecker TEST_PACKAGES = new StringChecker(new String[] { "org.aspectj.testing",
"org.eclipse.jdt.internal.junit", "junit.framework.",
"org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner" });
String[] infixes;
/** @param infixes adopted */
StringChecker(String[] infixes) {
this.infixes = infixes;
}
/** @return true if input contains infixes */
public boolean acceptString(String input) {
boolean result = false;
if (!LangUtil.isEmpty(input)) {
for (int i = 0; !result && (i < infixes.length); i++) {
result = (input.contains(infixes[i]));
}
}
return result;
}
}
/**
* Gen classpath.
*
* @param bootclasspath
* @param classpath
* @param classesDir
* @param outputJar
* @return String combining classpath elements
*/
public static String makeClasspath( // XXX dumb implementation
String bootclasspath, String classpath, String classesDir, String outputJar) {
StringBuffer sb = new StringBuffer();
addIfNotEmpty(bootclasspath, sb, File.pathSeparator);
addIfNotEmpty(classpath, sb, File.pathSeparator);
if (!addIfNotEmpty(classesDir, sb, File.pathSeparator)) {
addIfNotEmpty(outputJar, sb, File.pathSeparator);
}
return sb.toString();
}
/**
* @param input ignored if null
* @param sink the StringBuffer to add input to - return false if null
* @param delimiter the String to append to input when added - ignored if empty
* @return true if input + delimiter added to sink
*/
private static boolean addIfNotEmpty(String input, StringBuffer sink, String delimiter) {
if (LangUtil.isEmpty(input) || (null == sink)) {
return false;
}
sink.append(input);
if (!LangUtil.isEmpty(delimiter)) {
sink.append(delimiter);
}
return true;
}
/**
* Create or initialize a process controller to run a process in another VM asynchronously.
*
* @param controller the ProcessController to initialize, if not null
* @param classpath
* @param mainClass
* @param args
* @return initialized ProcessController
*/
public static ProcessController makeProcess(ProcessController controller, String classpath, String mainClass, String[] args) {
File java = LangUtil.getJavaExecutable();
ArrayList<String> cmd = new ArrayList<>();
cmd.add(java.getAbsolutePath());
cmd.add("-classpath");
cmd.add(classpath);
cmd.add(mainClass);
if (!LangUtil.isEmpty(args)) {
cmd.addAll(Arrays.asList(args));
}
String[] command = cmd.toArray(new String[0]);
if (null == controller) {
controller = new ProcessController();
}
controller.init(command, mainClass);
return controller;
}
// /**
// * Create a process to run asynchronously.
// * @param controller if not null, initialize this one
// * @param command the String[] command to run
// * @param controller the ProcessControl for streams and results
// */
// public static ProcessController makeProcess( // not needed?
// ProcessController controller,
// String[] command,
// String label) {
// if (null == controller) {
// controller = new ProcessController();
// }
// controller.init(command, label);
// return controller;
// }
/**
* Find java executable File path from java.home system property.
*
* @return File associated with the java command, or null if not found.
*/
public static File getJavaExecutable() {
String javaHome = null;
File result = null;
// java.home
// java.class.path
// java.ext.dirs
try {
javaHome = System.getProperty("java.home");
} catch (Throwable t) {
// ignore
}
if (null != javaHome) {
File binDir = new File(javaHome, "bin");
if (binDir.isDirectory() && binDir.canRead()) {
String[] execs = new String[] { "java", "java.exe" };
for (String exec : execs) {
result = new File(binDir, exec);
if (result.canRead()) {
break;
}
}
}
}
return result;
}
// /**
// * Sleep for a particular period (in milliseconds).
// *
// * @param time the long time in milliseconds to sleep
// * @return true if delay succeeded, false if interrupted 100 times
// */
// public static boolean sleep(long milliseconds) {
// if (milliseconds == 0) {
// return true;
// } else if (milliseconds < 0) {
// throw new IllegalArgumentException("negative: " + milliseconds);
// }
// return sleepUntil(milliseconds + System.currentTimeMillis());
// }
/**
* Sleep until a particular time.
*
* @param time the long time in milliseconds to sleep until
* @return true if delay succeeded, false if interrupted 100 times
*/
public static boolean sleepUntil(long time) {
if (time == 0) {
return true;
} else if (time < 0) {
throw new IllegalArgumentException("negative: " + time);
}
// final Thread thread = Thread.currentThread();
long curTime = System.currentTimeMillis();
for (int i = 0; (i < 100) && (curTime < time); i++) {
try {
Thread.sleep(time - curTime);
} catch (InterruptedException e) {
// ignore
}
curTime = System.currentTimeMillis();
}
return (curTime >= time);
}
/**
* Handle an external process asynchrously. <code>start()</code> launches a main thread to wait for the process and pipes
* streams (in child threads) through to the corresponding streams (e.g., the process System.err to this System.err). This can
* complete normally, by exception, or on demand by a client. Clients can implement <code>doCompleting(..)</code> to get notice
* when the process completes.
* <p>
* The following sample code creates a process with a completion callback starts it, and some time later retries the process.
*
* <pre>
* LangUtil.ProcessController controller = new LangUtil.ProcessController() {
* protected void doCompleting(LangUtil.ProcessController.Thrown thrown, int result) {
* // signal result
* }
* };
* controller.init(new String[] { "java", "-version" }, "java version");
* controller.start();
* // some time later...
* // retry...
* if (!controller.completed()) {
* controller.stop();
* controller.reinit();
* controller.start();
* }
* </pre>
*
* <u>warning</u>: Currently this does not close the input or output streams, since doing so prevents their use later.
*/
public static class ProcessController {
/*
* XXX not verified thread-safe, but should be. Known problems: - user stops (completed = true) then exception thrown from
* destroying process (stop() expects !completed) ...
*/
private String[] command;
private String[] envp;
private String label;
private boolean init;
private boolean started;
private boolean completed;
/** if true, stopped by user when not completed */
private boolean userStopped;
private Process process;
private FileUtil.Pipe errStream;
private FileUtil.Pipe outStream;
private FileUtil.Pipe inStream;
private ByteArrayOutputStream errSnoop;
private ByteArrayOutputStream outSnoop;
private int result;
private Thrown thrown;
public ProcessController() {
}
/**
* Permit re-running using the same command if this is not started or if completed. Can also call this when done with
* results to release references associated with results (e.g., stack traces).
*/
public final void reinit() {
if (!init) {
throw new IllegalStateException("must init(..) before reinit()");
}
if (started && !completed) {
throw new IllegalStateException("not completed - do stop()");
}
// init everything but command and label
started = false;
completed = false;
result = Integer.MIN_VALUE;
thrown = null;
process = null;
errStream = null;
outStream = null;
inStream = null;
}
public final void init(String classpath, String mainClass, String[] args) {
init(LangUtil.getJavaExecutable(), classpath, mainClass, args);
}
public final void init(File java, String classpath, String mainClass, String[] args) {
LangUtil.throwIaxIfNull(java, "java");
LangUtil.throwIaxIfNull(mainClass, "mainClass");
LangUtil.throwIaxIfNull(args, "args");
ArrayList<String> cmd = new ArrayList<>();
cmd.add(java.getAbsolutePath());
cmd.add("-classpath");
cmd.add(classpath);
cmd.add(mainClass);
if (!LangUtil.isEmpty(args)) {
cmd.addAll(Arrays.asList(args));
}
init(cmd.toArray(new String[0]), mainClass);
}
public final void init(String[] command, String label) {
this.command = (String[]) LangUtil.safeCopy(command, new String[0]);
if (1 > this.command.length) {
throw new IllegalArgumentException("empty command");
}
this.label = LangUtil.isEmpty(label) ? command[0] : label;
init = true;
reinit();
}
public final void setEnvp(String[] envp) {
this.envp = (String[]) LangUtil.safeCopy(envp, new String[0]);
if (1 > this.envp.length) {
throw new IllegalArgumentException("empty envp");
}
}
public final void setErrSnoop(ByteArrayOutputStream snoop) {
errSnoop = snoop;
if (null != errStream) {
errStream.setSnoop(errSnoop);
}
}
public final void setOutSnoop(ByteArrayOutputStream snoop) {
outSnoop = snoop;
if (null != outStream) {
outStream.setSnoop(outSnoop);
}
}
/**
* Start running the process and pipes asynchronously.
*
* @return Thread started or null if unable to start thread (results available via <code>getThrown()</code>, etc.)
*/
public final Thread start() {
if (!init) {
throw new IllegalStateException("not initialized");
}
synchronized (this) {
if (started) {
throw new IllegalStateException("already started");
}
started = true;
}
try {
process = Runtime.getRuntime().exec(command);
} catch (IOException e) {
stop(e, Integer.MIN_VALUE);
return null;
}
errStream = new FileUtil.Pipe(process.getErrorStream(), System.err);
if (null != errSnoop) {
errStream.setSnoop(errSnoop);
}
outStream = new FileUtil.Pipe(process.getInputStream(), System.out);
if (null != outSnoop) {
outStream.setSnoop(outSnoop);
}
inStream = new FileUtil.Pipe(System.in, process.getOutputStream());
// start 4 threads, process & pipes for in, err, out
Runnable processRunner = new Runnable() {
@Override
public void run() {
Throwable thrown = null;
int result = Integer.MIN_VALUE;
try {
// pipe threads are children
new Thread(errStream).start();
new Thread(outStream).start();
new Thread(inStream).start();
process.waitFor();
result = process.exitValue();
} catch (Throwable e) {
thrown = e;
} finally {
stop(thrown, result);
}
}
};
Thread result = new Thread(processRunner, label);
result.start();
return result;
}
/**
* Destroy any process, stop any pipes. This waits for the pipes to clear (reading until no more input is available), but
* does not wait for the input stream for the pipe to close (i.e., not waiting for end-of-file on input stream).
*/
public final synchronized void stop() {
if (completed) {
return;
}
userStopped = true;
stop(null, Integer.MIN_VALUE);
}
public final String[] getCommand() {
String[] toCopy = command;
if (LangUtil.isEmpty(toCopy)) {
return new String[0];
}
String[] result = new String[toCopy.length];
System.arraycopy(toCopy, 0, result, 0, result.length);
return result;
}
public final boolean completed() {
return completed;
}
public final boolean started() {
return started;
}
public final boolean userStopped() {
return userStopped;
}
/**
* Get any Throwable thrown. Note that the process can complete normally (with a valid return value), at the same time the
* pipes throw exceptions, and that this may return some exceptions even if the process is not complete.
*
* @return null if not complete or Thrown containing exceptions thrown by the process and streams.
*/
public final Thrown getThrown() { // cache this
return makeThrown(null);
}
public final int getResult() {
return result;
}
/**
* Subclasses implement this to get synchronous notice of completion. All pipes and processes should be complete at this
* time. To get the exceptions thrown for the pipes, use <code>getThrown()</code>. If there is an exception, the process
* completed abruptly (including side-effects of the user halting the process). If <code>userStopped()</code> is true, then
* some client asked that the process be destroyed using <code>stop()</code>. Otherwise, the result code should be the
* result value returned by the process.
*
* @param thrown same as <code>getThrown().fromProcess</code>.
* @param result same as <code>getResult()</code>
* @see getThrown()
* @see getResult()
* @see stop()
*/
protected void doCompleting(Thrown thrown, int result) {
}
/**
* Handle termination (on-demand, abrupt, or normal) by destroying and/or halting process and pipes.
*
* @param thrown ignored if null
* @param result ignored if Integer.MIN_VALUE
*/
private final synchronized void stop(Throwable thrown, int result) {
if (completed) {
throw new IllegalStateException("already completed");
} else if (null != this.thrown) {
throw new IllegalStateException("already set thrown: " + thrown);
}
// assert null == this.thrown
this.thrown = makeThrown(thrown);
if (null != process) {
process.destroy();
}
if (null != inStream) {
inStream.halt(false, true); // this will block if waiting
inStream = null;
}
if (null != outStream) {
outStream.halt(true, true);
outStream = null;
}
if (null != errStream) {
errStream.halt(true, true);
errStream = null;
}
if (Integer.MIN_VALUE != result) {
this.result = result;
}
completed = true;
doCompleting(this.thrown, result);
}
/**
* Create snapshot of Throwable's thrown.
*
* @param thrown ignored if null or if this.thrown is not null
*/
private final synchronized Thrown makeThrown(Throwable processThrown) {
if (null != thrown) {
return thrown;
}
return new Thrown(processThrown, (null == outStream ? null : outStream.getThrown()), (null == errStream ? null
: errStream.getThrown()), (null == inStream ? null : inStream.getThrown()));
}
public static class Thrown {
public final Throwable fromProcess;
public final Throwable fromErrPipe;
public final Throwable fromOutPipe;
public final Throwable fromInPipe;
/** true only if some Throwable is not null */
public final boolean thrown;
private Thrown(Throwable fromProcess, Throwable fromOutPipe, Throwable fromErrPipe, Throwable fromInPipe) {
this.fromProcess = fromProcess;
this.fromErrPipe = fromErrPipe;
this.fromOutPipe = fromOutPipe;
this.fromInPipe = fromInPipe;
thrown = ((null != fromProcess) || (null != fromInPipe) || (null != fromOutPipe) || (null != fromErrPipe));
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
append(sb, fromProcess, "process");
append(sb, fromOutPipe, " stdout");
append(sb, fromErrPipe, " stderr");
append(sb, fromInPipe, " stdin");
if (0 == sb.length()) {
return "Thrown (none)";
} else {
return sb.toString();
}
}
private void append(StringBuffer sb, Throwable thrown, String label) {
if (null != thrown) {
sb.append("from " + label + ": ");
sb.append(LangUtil.renderExceptionShort(thrown));
sb.append(LangUtil.EOL);
}
}
} // class Thrown
}
public static String getJrtFsFilePath() {
return getJavaHome() + File.separator + "lib" + File.separator + JRT_FS;
}
public static String getJavaHome() {
return System.getProperty("java.home");
}
}
|