1 package org.lsst.ccs.bootstrap;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.lang.reflect.InvocationTargetException;
6 import java.lang.reflect.Method;
7 import java.net.MalformedURLException;
8 import java.net.URL;
9 import java.net.URLClassLoader;
10 import java.util.ArrayList;
11 import java.util.Collection;
12 import java.util.HashMap;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.Properties;
16 import java.util.Set;
17 import java.util.StringTokenizer;
18 import java.util.jar.JarFile;
19 import java.util.jar.Manifest;
20 import javax.xml.parsers.DocumentBuilder;
21 import javax.xml.parsers.DocumentBuilderFactory;
22 import javax.xml.parsers.ParserConfigurationException;
23 import org.apache.commons.cli.BasicParser;
24 import org.apache.commons.cli.CommandLine;
25 import org.apache.commons.cli.CommandLineParser;
26 import org.apache.commons.cli.HelpFormatter;
27 import org.apache.commons.cli.Option;
28 import org.apache.commons.cli.OptionBuilder;
29 import org.apache.commons.cli.Options;
30 import org.apache.commons.cli.ParseException;
31 import org.freehep.util.VersionComparator;
32 import org.freehep.util.VersionComparator.Version;
33 import org.lsst.ccs.bootstrap.resources.BootstrapResourceUtils;
34 import org.lsst.ccs.bootstrap.resources.ResourcesUtils;
35 import org.lsst.ccs.bootstrap.util.SystemPropertyMatcher;
36 import org.w3c.dom.Document;
37 import org.w3c.dom.Element;
38 import org.xml.sax.SAXException;
39
40
41
42
43
44
45
46 public class Bootstrap {
47
48
49 private Options bootstrapCommandLineOptions;
50 private List<String> additionalCommandLineArguments = new ArrayList<>(), passedAlongOptions = new ArrayList<>();
51
52 private static String bootstrapApplication = null;
53 static URLClassLoader applicationClassLoader = null;
54 private boolean printHelp = false, listApplications = false, showDistributionInfo = false;
55 private static boolean verbose = false;
56 static final String APPLICATION_OPTION = "application";
57 static final String HELP_OPTION = "help";
58 static final String VERBOSE_OPTION = "verbose";
59 static final String LIST_APPLICATIONS_OPTION = "listApplications";
60 private String showProperties = null;
61 private boolean showClasspath = false;
62 private static final String APPLICATION_ARGS_PROPERTY = "org.lsst.ccs.application.args";
63 private static final String APPLICATION_DESCRIPTION_PROPERTY = "org.lsst.ccs.application.description";
64 private static Properties bootstrapCmdLineProperties = new Properties();
65 private static Map<String, String> additionalClassPathEntriesMap = new HashMap<>();
66 private static List<String> additionalClassPathEntriesList = new ArrayList<>();
67 private static Properties bootstrapApplicationProperties = null;
68 private static final String BOOTSTRAP_ENVIRONMENT_PROPERTY = "org.lsst.ccs.bootstrap.environment";
69 private static String distributionMainJar = null;
70 static boolean quiet = false;
71 private static Class loaderClass = BootstrapUtils.class;
72
73 Bootstrap() {
74 this(false);
75 }
76
77 Bootstrap(boolean quiet) {
78 this.quiet = quiet;
79
80 bootstrapCommandLineOptions = new Options();
81
82 bootstrapCommandLineOptions.addOption("h", HELP_OPTION, false, "Print the help message");
83
84 bootstrapCommandLineOptions.addOption("v", VERBOSE_OPTION, false, "Turns on verbose statements");
85
86 bootstrapCommandLineOptions.addOption("la", LIST_APPLICATIONS_OPTION, false,
87 "List the available CCS applications in this distribution");
88
89 bootstrapCommandLineOptions.addOption("app", APPLICATION_OPTION, true, "The APPLICATION to be launched");
90 getOption(APPLICATION_OPTION).setArgName("APPLICATION");
91
92
93 Option sysProperty = OptionBuilder.withArgName("SystemProperty=Value").hasArgs(2)
94 .withValueSeparator().withDescription("Set the Value of a SystemProperty.")
95 .create("D");
96 bootstrapCommandLineOptions.addOption(sysProperty);
97
98
99 bootstrapCommandLineOptions.addOption("di", "distInfo", false, "Show information on current distribution.");
100
101
102 bootstrapCommandLineOptions.addOption("sp", "showProperties", true, "Show the properties for <FILE_NAME>.");
103 getOption("showProperties").setArgName("FILE_NAME");
104
105
106 bootstrapCommandLineOptions.addOption("scp", "showClasspath", false, "Show the classpath for the given application.");
107 }
108
109 private static void resetBootstrap() {
110 bootstrapCmdLineProperties = new Properties();
111 additionalClassPathEntriesMap = new HashMap<>();
112 additionalClassPathEntriesList = new ArrayList<>();
113 bootstrapApplication = null;
114 BootstrapUtils.reset();
115 }
116
117 public static void initializeBootstrap() {
118 initializeBootstrap(BootstrapUtils.class);
119 }
120
121
122
123
124
125
126 public static void initializeBootstrap(Class theClazz) {
127 resetBootstrap();
128 Bootstrap.loaderClass = theClazz;
129 }
130
131 public static Class getLoaderClass() {
132 return loaderClass;
133 }
134
135
136
137
138
139
140 public synchronized static Properties getBootstrapApplicationProperties() {
141 if (bootstrapApplicationProperties == null) {
142 bootstrapApplicationProperties = BootstrapUtils.getApplicationDefinitionProperties(getBootstrapApplication());
143 }
144 return bootstrapApplicationProperties;
145 }
146
147 protected List<String> getAdditionalCommandLineArguments() {
148 return additionalCommandLineArguments;
149 }
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164 protected CommandLine parseCommandLineArguments(String[] args) throws ParseException {
165
166
167
168
169
170 List<String> argumentsToParse = new ArrayList<>();
171 boolean skipNext = false;
172 for (int i = 0; i < args.length; i++) {
173 if ( skipNext ) {
174 skipNext = false;
175 continue;
176 }
177 String arg = args[i];
178 if (arg.startsWith("-D")) {
179
180 int propertyStrIndex = arg.equals("-D") ? i + 1 : i;
181 String propertyStr = args[propertyStrIndex].replace("-D", "");
182
183 if (!propertyStr.contains("=")
184 args[propertyStrIndex] = args[propertyStrIndex].replace(propertyStr, propertyStr + "=");
185 }
186 if (arg.equals("-D")) {
187 argumentsToParse.add(arg);
188 } else {
189 additionalCommandLineArguments.add(args[i]);
190 }
191 } else {
192 if ( arg.startsWith("-") && ! bootstrapCommandLineOptions.hasOption(arg) ) {
193
194 additionalCommandLineArguments.add(arg);
195
196 if ( i < args.length -1 ) {
197 String tmpArg = args[i+1];
198 if ( ! tmpArg.startsWith("-") ) {
199 additionalCommandLineArguments.add(tmpArg);
200 skipNext = true;
201 }
202 }
203 } else {
204 argumentsToParse.add(arg);
205 }
206
207 }
208 }
209
210
211 String[] newArgs = argumentsToParse.toArray(new String[argumentsToParse.size()]);
212
213 CommandLineParser parser = new BasicParser();
214 CommandLine line = parser.parse(bootstrapCommandLineOptions, newArgs, false);
215
216 if (line.hasOption(APPLICATION_OPTION)) {
217 String tmpApp = line.getOptionValue(APPLICATION_OPTION);
218 if ("true".equals(System.getProperty("org.lsst.ccs.bootstrap.test")) && !BootstrapUtils.getBootstrapListOfApplications().contains(tmpApp)) {
219 throw new IllegalArgumentException("Application name: " + tmpApp + " is not a valid value.");
220 } else {
221 bootstrapApplication = tmpApp;
222 }
223 }
224
225 if (line.hasOption(HELP_OPTION)) {
226 printHelp = true;
227 }
228
229 additionalCommandLineArguments.addAll(line.getArgList());
230
231 showClasspath = line.hasOption("showClasspath");
232
233 if (line.hasOption("showProperties")) {
234 if (showProperties == null) {
235 showProperties = line.getOptionValue("showProperties");
236 }
237 }
238
239 if (line.hasOption(LIST_APPLICATIONS_OPTION)) {
240 listApplications = true;
241 }
242
243 verbose = line.hasOption(VERBOSE_OPTION);
244
245 if (printHelp && !passedAlongOptions.contains("-" + HELP_OPTION)) {
246 passedAlongOptions.add("-" + HELP_OPTION);
247 }
248 if (verbose && !passedAlongOptions.contains("-" + VERBOSE_OPTION)) {
249 passedAlongOptions.add("-" + VERBOSE_OPTION);
250 }
251
252
253 Properties cmdLineProperties = line.getOptionProperties("D");
254
255
256
257
258 Option[] opts = line.getOptions();
259 for (Option opt : opts) {
260 if (opt.getOpt().equals("D")) {
261 boolean wasSet = (opt.getValuesList().size() == 2);
262 if (!wasSet) {
263 cmdLineProperties.setProperty(opt.getValue(), "");
264 }
265 }
266 }
267
268 if (verbose() && !quiet) {
269 if (!cmdLineProperties.isEmpty()) {
270 System.out.println("\n*** Adding the following command line properties to the Properties:");
271 Set keys = cmdLineProperties.keySet();
272 for (Object key : keys) {
273 System.out.println("\t" + key + " = " + cmdLineProperties.getProperty((String) key));
274 }
275 }
276 }
277 if (!cmdLineProperties.isEmpty()) {
278 bootstrapCmdLineProperties.putAll(cmdLineProperties);
279 System.getProperties().putAll(cmdLineProperties);
280 }
281
282 if (line.hasOption("distInfo")) {
283 showDistributionInfo = true;
284 }
285
286
287
288
289 List<String> toBeRemoved = new ArrayList<>();
290 for (String additional : additionalCommandLineArguments) {
291 SystemPropertyMatcher m = SystemPropertyMatcher.matcher(additional);
292 if (m.matches()) {
293 toBeRemoved.add(additional);
294 bootstrapCmdLineProperties.put(m.getProperty(), m.getValue());
295 }
296 }
297 for (String remove : toBeRemoved) {
298 additionalCommandLineArguments.remove(remove);
299 }
300
301
302 return line;
303 }
304
305 public static Properties getCmdLineProperties() {
306 return bootstrapCmdLineProperties;
307 }
308
309
310
311
312
313
314 public static String getBootstrapApplication() {
315
316
317
318 return bootstrapApplication;
319 }
320
321
322
323
324
325
326 public boolean doPrintHelp() {
327 return printHelp;
328 }
329
330
331
332
333
334
335 public static boolean verbose() {
336 return verbose;
337 }
338
339 public static boolean isQuiet() {
340 return quiet;
341 }
342
343
344
345
346
347
348
349 protected Options getBootstrapCommandLineOptions() {
350 return bootstrapCommandLineOptions;
351 }
352
353
354
355
356
357
358 private static void printBootstrapClassLoader() {
359 URL[] urls = getBootstrapApplicationClassLoader().getURLs();
360 System.out.println("*** CLASSPATH");
361 for (URL url : urls) {
362 System.out.println("\t\t" + url);
363 }
364 }
365
366
367
368
369
370
371
372 private Option getOption(String opt) {
373 return getBootstrapCommandLineOptions().getOption(opt);
374 }
375
376
377
378
379
380
381
382
383
384
385 private String[] getApplicationArguments(Properties appProperties) throws ParseException {
386
387 String applicationArgs = appProperties.getProperty(APPLICATION_ARGS_PROPERTY, "").trim();
388 StringTokenizer applicationArgsTokenizer = new StringTokenizer(applicationArgs, " ");
389
390 int nArgs = passedAlongOptions.size() + additionalCommandLineArguments.size() + applicationArgsTokenizer.countTokens();
391
392 String[] mainArgs = new String[nArgs];
393
394 int argCount = 0;
395 while (applicationArgsTokenizer.hasMoreTokens()) {
396 mainArgs[argCount++] = applicationArgsTokenizer.nextToken();
397 }
398 for (String opt : passedAlongOptions) {
399 mainArgs[argCount++] = opt;
400 }
401 for (String cmdArg : additionalCommandLineArguments) {
402 mainArgs[argCount++] = cmdArg;
403 }
404 if (verbose() && !isQuiet()) {
405 System.out.print("*** Command line arguments passed to the mainClass: ");
406 for (String arg : mainArgs) {
407 System.out.print(arg + " ");
408 }
409 System.out.println();
410 }
411
412 return mainArgs;
413 }
414
415
416
417
418
419
420 public static URLClassLoader getBootstrapApplicationClassLoader() {
421 if (applicationClassLoader == null) {
422 buildBootstrapClassLoader();
423 }
424 return applicationClassLoader;
425 }
426
427
428
429
430
431
432
433
434 static void scanPropertiesForClassPathEntries(Properties props) {
435
436 Set<Object> keySet = BootstrapResourceUtils.getAllKeysInProperties(props);
437 for (Object obj : keySet) {
438 String key = (String) obj;
439 if (key.endsWith("additional.classpath.entry")) {
440 String entry = props.getProperty(key);
441 if (additionalClassPathEntriesMap.containsKey(key)) {
442 if (!quiet) {
443 System.out.println("*** [WARNING] ignoring additional classpath entry: " + key + "=" + entry + " it was already added to the CLASSPATH as " + additionalClassPathEntriesMap.get(key));
444 }
445 } else {
446 additionalClassPathEntriesMap.put(key, entry);
447 additionalClassPathEntriesList.add(entry);
448 }
449 }
450 }
451 }
452
453 private synchronized static void buildBootstrapClassLoader() {
454
455
456
457
458 if (applicationClassLoader != null) {
459 throw new RuntimeException("The Bootstrap ClassLoader has already been built. Please report this problem.");
460 }
461
462
463 List<URL> classPathUrlList = new ArrayList<>();
464
465
466 if (bootstrapApplication != null) {
467 scanPropertiesForClassPathEntries(getBootstrapApplicationProperties());
468 }
469
470 try {
471
472 String userProvidedDistributionDirs = BootstrapUtils.getUserProvidedDistributionDirectories();
473 List<String> additionalDistributionJarDirs = BootstrapUtils.extractDirectoriesFromPath(userProvidedDistributionDirs, null, true);
474
475 boolean checkForVersionIncompatibilities = additionalDistributionJarDirs.size() > 0;
476 ClassPathBuilderSupport cpSupport = new ClassPathBuilderSupport();
477
478
479 String applicationMainJar = getDistributionMainJar();
480 File jar = null;
481 if (applicationMainJar != null) {
482 jar = new File(applicationMainJar);
483 classPathUrlList.add(jar.toURI().toURL());
484 }
485
486
487
488 for (String classPathEntry : additionalClassPathEntriesList) {
489 File cpEntryFile = new File(classPathEntry);
490 if (cpEntryFile.isDirectory()) {
491 if (!quiet) {
492 System.out.println("*** [WARNING] Directories cannot be added to the classpath as additional Classpath entries. Skipping " + classPathEntry);
493 }
494 } else {
495 classPathUrlList.add(cpEntryFile.toURI().toURL());
496 }
497 }
498
499 if (checkForVersionIncompatibilities && jar != null) {
500 scanManifestForClassPathElements(jar, cpSupport);
501 }
502
503
504 for (String dir : additionalDistributionJarDirs) {
505 String additionalMainJar = getDistributionMainJar(dir);
506 File mainjar = new File(additionalMainJar);
507 classPathUrlList.add(mainjar.toURI().toURL());
508 if (checkForVersionIncompatibilities) {
509 scanManifestForClassPathElements(mainjar, cpSupport);
510 }
511 }
512
513 } catch (MalformedURLException mue) {
514 throw new RuntimeException("Failed to build URL when building the classpath: " + mue.getMessage());
515 }
516
517
518 URL[] classpathUrls = new URL[classPathUrlList.size()];
519 int count = 0;
520 for (URL classpathURl : classPathUrlList) {
521 classpathUrls[count++] = classpathURl;
522 }
523
524 applicationClassLoader = new URLClassLoader(classpathUrls);
525 }
526
527
528
529
530
531
532
533
534
535 private static String getDistributionMainJar(String distribution) {
536 File distributionDefinitionFile = new File(BootstrapUtils.getDistributionResourcesDirectory(distribution) + "DIST-INF/distribution.xml");
537 if ( !distributionDefinitionFile.exists()) {
538 if ( "true".equals(System.getProperty("org.lsst.ccs.bootstrap.test")) ) {
539 return null;
540 }
541 throw new RuntimeException("FATAL: Cannot run distribution " + distribution + " as it does not contain the distribution definition xml file");
542 }
543
544 try {
545 DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
546 DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
547
548 Document doc;
549 doc = dBuilder.parse(distributionDefinitionFile);
550
551 Element rootEl = doc.getDocumentElement();
552
553 return BootstrapUtils.getDistributionJarFilesDirectory(distribution) + rootEl.getAttribute("mainJar");
554
555 } catch (ParserConfigurationException | SAXException | IOException pce) {
556 throw new RuntimeException(pce);
557 }
558 }
559
560 private static String getDistributionMainJar() {
561 if (distributionMainJar == null) {
562 distributionMainJar = getDistributionMainJar(BootstrapUtils.getCCSDistributionRootDirectory());
563 }
564 return distributionMainJar;
565 }
566
567
568
569
570
571
572 private void launchCCSApplication(String applicationName) {
573
574 Properties applicationProperties = BootstrapUtils.getApplicationDefinitionProperties(applicationName);
575
576 if (doPrintHelp()) {
577 String appDescription = applicationProperties.getProperty(APPLICATION_DESCRIPTION_PROPERTY, "");
578 System.out.println("\n\tCCS Application " + applicationName + " " + appDescription + "\n");
579 }
580
581
582 String applicationMainClassName = applicationProperties.getProperty(BootstrapUtils.APPLICATION_MAINCLASS_PROPERTY);
583
584 if (applicationMainClassName == null) {
585 throw new RuntimeException("*** Application " + applicationName + " must contain define the main Class to lauch. "
586 + "This can be done either in the Manifest of the main jar or by defining the property "
587 + BootstrapUtils.APPLICATION_MAINCLASS_PROPERTY
588 + " in its definition file. ");
589 }
590
591 if (verbose() && isQuiet()) {
592 System.out.println("*** Distribution Root: " + BootstrapUtils.getCCSDistributionRootDirectory());
593 System.out.println("*** Application name: " + applicationName);
594 System.out.println("*** MainClass: " + applicationMainClassName);
595 System.out.println("*** LD_LIBRARY_PATH: " + System.getenv("LD_LIBRARY_PATH"));
596 }
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618 try {
619 Class applicationMainClass = Class.forName(applicationMainClassName);
620 try {
621
622 Method applicationMainMethod = applicationMainClass.getMethod("main",
623 new Class[]{String[].class});
624
625
626 String[] mainArgs = getApplicationArguments(applicationProperties);
627
628
629 if (verbose() && !isQuiet()) {
630 printBootstrapClassLoader();
631 }
632
633 try {
634
635 applicationMainMethod.invoke(null, new Object[]{mainArgs});
636 } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
637 System.out.println("*** Failed to invoke main method in class " + applicationMainClassName + "\n" + e.getMessage());
638 throw new RuntimeException(e);
639 }
640
641 } catch (NoSuchMethodException | SecurityException | ParseException e) {
642 System.out.println("*** Could not access the main method in class " + applicationMainClassName + "\n" + e.getMessage());
643 }
644
645 } catch (ClassNotFoundException cnfe) {
646 System.out.println("*** Could not find class " + applicationMainClassName + " in the following classpath: ");
647 printBootstrapClassLoader();
648 System.out.println("*************************************************************************\n" + cnfe.getMessage());
649 }
650
651 }
652
653 public static void main(String[] args) throws Exception {
654
655 System.setProperty(BOOTSTRAP_ENVIRONMENT_PROPERTY, "true");
656 Bootstrap bootstrap = new Bootstrap();
657 bootstrap.parseCommandLineArguments(args);
658
659 String applicationName = getBootstrapApplication();
660
661 if (bootstrap.showClasspath) {
662 if (getBootstrapApplication() == null) {
663 throw new IllegalArgumentException("To display the content of the classpath you have to provide an application with the --app option");
664 } else {
665 printBootstrapClassLoader();
666 }
667 } else if (bootstrap.showProperties != null) {
668 if (getBootstrapApplication() == null) {
669 throw new IllegalArgumentException("To display the content of a properties file you have to provide an application with the --app option");
670 } else {
671
672 ResourcesUtils.printProperties(BootstrapResourceUtils.getBootstrapProperties(bootstrap.showProperties));
673 }
674 } else if (bootstrap.showDistributionInfo) {
675 printDistributionInfo();
676 } else if (bootstrap.listApplications) {
677
678 List<String> availableApplications = BootstrapUtils.getBootstrapListOfApplications();
679 if (availableApplications.isEmpty()) {
680 System.out.println("No CCS applications are defined in the current distribution.");
681 if (bootstrap.verbose() && !bootstrap.isQuiet()) {
682 System.out.println(BootstrapUtils.getDistributionResourcesDirectory());
683 }
684 } else {
685 System.out.println("Available CCS applications :");
686 if (bootstrap.verbose() && !bootstrap.isQuiet()) {
687 System.out.println(BootstrapUtils.getDistributionResourcesDirectory());
688 }
689 for (String application : availableApplications) {
690 Properties applicationProps = BootstrapUtils.getApplicationDefinitionProperties(application);
691 System.out.println("\t" + application + "\t" + applicationProps.getProperty(APPLICATION_DESCRIPTION_PROPERTY));
692 }
693 }
694
695 } else if (bootstrap.doPrintHelp() && applicationName == null) {
696 printHelp(bootstrap.getBootstrapCommandLineOptions());
697 } else if (applicationName != null) {
698 bootstrap.launchCCSApplication(applicationName);
699 } else {
700 printHelp(bootstrap.getBootstrapCommandLineOptions());
701 }
702
703 }
704
705 private static void printHelp(Options o) {
706 HelpFormatter formatter = new HelpFormatter();
707 formatter.printHelp(100, "CCSbootstrap", "", o, "", true);
708 }
709
710 private static void printDistributionInfo() {
711 System.out.println("\n*** Distribution info");
712 System.out.println("\tDistribution path: " + BootstrapUtils.getCCSDistributionRootDirectory());
713 System.out.println("\tResources ordered search path: ");
714 List<String> distSearchPathList = BootstrapUtils.getOrderedListOfResourceDirectories();
715 String resourcesDirList = "";
716 StringBuffer b = new StringBuffer();
717 for (String dir : distSearchPathList) {
718 b.append("\t\t" + dir + "\n");
719 }
720 resourcesDirList += b.toString();
721 System.out.print(resourcesDirList);
722
723 }
724
725
726
727
728
729
730
731
732 public static boolean isBootstrapEnvironment() {
733 return "true".equals(System.getProperty(BOOTSTRAP_ENVIRONMENT_PROPERTY));
734 }
735
736 private static void scanManifestForClassPathElements(File file, ClassPathBuilderSupport cp) {
737 JarFile jarFile = null;
738 try {
739 jarFile = new JarFile(file);
740 Manifest manifest = jarFile.getManifest();
741 String manifestClassPath = manifest.getMainAttributes().getValue("Class-Path").trim();
742 File parentDir = file.getParentFile();
743 StringTokenizer classPathTokens = new StringTokenizer(manifestClassPath, " ");
744 while (classPathTokens.hasMoreTokens()) {
745 String manifestClassPathJar = classPathTokens.nextToken();
746 cp.addClasspathEntry(parentDir.getAbsolutePath(), manifestClassPathJar);
747 }
748 } catch (IOException ioe) {
749 throw new RuntimeException(ioe);
750 } finally {
751 if (jarFile != null) {
752 try {
753 jarFile.close();
754 } catch (IOException e) {
755 throw new RuntimeException(e);
756 }
757 }
758 }
759
760 }
761
762 private static class ClassPathBuilderSupport {
763
764 private HashMap<String, ClassPathElementWithVersion> classPathEntries = new HashMap<>();
765
766 void addClasspathEntry(String resourceDir, String fileName) {
767
768 String jarName = VersionComparator.stripVersion(fileName);
769
770 ClassPathElementWithVersion existingEntry = classPathEntries.get(jarName);
771 ClassPathElementWithVersion newEntry = new ClassPathElementWithVersion(resourceDir, fileName);
772 if (existingEntry == null) {
773 classPathEntries.put(jarName, newEntry);
774 } else if (!existingEntry.fileName.equals(newEntry.fileName) && !quiet) {
775 System.out.println("WARNING Classpath entry version conflict: ");
776 System.out.println("\t " + newEntry.resourceDir + BootstrapUtils.FILE_SEPARATOR + newEntry.fileName);
777 System.out.println("\t " + existingEntry.resourceDir + BootstrapUtils.FILE_SEPARATOR + existingEntry.fileName);
778 }
779 }
780
781 Collection<ClassPathElementWithVersion> getListOfClasspathElements() {
782 return classPathEntries.values();
783 }
784 }
785
786 private static class ClassPathElementWithVersion {
787
788 private String fileName, resourceDir;
789 private URL elementURL;
790 private Version version;
791
792 public ClassPathElementWithVersion(String resourceDir, String fileName) {
793
794 this.fileName = fileName;
795 this.resourceDir = resourceDir;
796
797 }
798
799 Version getVersion() {
800 if (version == null) {
801 version = VersionComparator.getVersionFromFileName(fileName);
802 }
803 return version;
804 }
805
806 String getFileName() {
807 return fileName;
808 }
809
810 URL getElementUrl() {
811 File element = new File(resourceDir, fileName);
812 if (element.exists()) {
813 try {
814 return element.toURI().toURL();
815 } catch (Exception e) {
816 e.printStackTrace();
817 return null;
818 }
819 } else {
820 System.out.println("The following file does not exist : " + element.getAbsolutePath());
821 System.out.println("Something went wrong with its version in the Bootstrap");
822 return null;
823 }
824 }
825 }
826 }