1 package org.lcsim.job;
2
3 import hep.aida.ref.BatchAnalysisFactory;
4
5 import java.io.BufferedReader;
6 import java.io.File;
7 import java.io.FileInputStream;
8 import java.io.FileNotFoundException;
9 import java.io.FileOutputStream;
10 import java.io.FileReader;
11 import java.io.IOException;
12 import java.io.InputStream;
13 import java.lang.reflect.Method;
14 import java.net.MalformedURLException;
15 import java.net.URL;
16 import java.net.URLClassLoader;
17 import java.util.ArrayList;
18 import java.util.Date;
19 import java.util.HashMap;
20 import java.util.Iterator;
21 import java.util.LinkedHashMap;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Map.Entry;
25 import java.util.Properties;
26 import java.util.logging.Level;
27 import java.util.logging.Logger;
28 import java.util.regex.Matcher;
29 import java.util.regex.Pattern;
30
31 import org.apache.commons.cli.CommandLine;
32 import org.apache.commons.cli.CommandLineParser;
33 import org.apache.commons.cli.HelpFormatter;
34 import org.apache.commons.cli.Option;
35 import org.apache.commons.cli.Options;
36 import org.apache.commons.cli.ParseException;
37 import org.apache.commons.cli.PosixParser;
38 import org.freehep.record.loop.RecordEvent;
39 import org.jdom.Attribute;
40 import org.jdom.Document;
41 import org.jdom.Element;
42 import org.jdom.Text;
43 import org.jdom.input.SAXBuilder;
44 import org.jdom.output.Format;
45 import org.jdom.output.XMLOutputter;
46 import org.lcsim.conditions.ConditionsManager;
47 import org.lcsim.conditions.ConditionsManager.ConditionsNotFoundException;
48 import org.lcsim.event.EventHeader;
49 import org.lcsim.units.Constants;
50 import org.lcsim.util.Driver;
51 import org.lcsim.util.DriverAdapter;
52 import org.lcsim.util.cache.FileCache;
53 import org.lcsim.util.loop.LCIOEventSource;
54 import org.lcsim.util.loop.LCSimConditionsManagerImplementation;
55 import org.lcsim.util.loop.LCSimLoop;
56 import org.lcsim.util.xml.ClasspathEntityResolver;
57 import org.lcsim.util.xml.JDOMExpressionFactory;
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79 @SuppressWarnings({"unchecked", "rawtypes"})
80 public class JobControlManager {
81
82
83
84
85 protected static final Logger LOGGER = Logger.getLogger(JobControlManager.class.getPackage().getName());
86
87
88
89
90 private static final Options OPTIONS = createCommandLineOptions();
91
92
93
94
95 private static final Pattern VARIABLE_PATTERN = Pattern.compile("[$][{][a-zA-Z_-]*[}]");
96
97
98
99
100
101
102 private static Options createCommandLineOptions() {
103 final Options options = new Options();
104 options.addOption(new Option("h", "help", false, "Print help and exit"));
105 options.addOption(new Option("p", "properties", true, "Load a properties file containing variable definitions"));
106 options.addOption(new Option("D", "define", true, "Define a variable with form [name]=[value]"));
107 options.addOption(new Option("w", "rewrite", true, "Rewrite the XML file with variables resolved"));
108 options.addOption(new Option("s", "skip", true, "Set the number of events to skip"));
109 options.addOption(new Option("n", "nevents", true, "Set the max number of events to process"));
110 options.addOption(new Option("x", "dry-run", false, "Perform a dry run which does not process events"));
111 options.addOption(new Option("i", "input-file", true, "Add an LCIO input file to process"));
112 options.addOption(new Option("r", "resource", false, "Use a steering resource rather than a file"));
113 options.addOption(new Option("b", "batch", false, "Run in batch mode in which plots will not be shown."));
114 options.addOption(new Option("e", "event-print", true, "Event print interval"));
115 options.addOption(new Option("d", "detector", true, "user supplied detector name (careful!)"));
116 options.addOption(new Option("R", "run", true, "user supplied run number (careful!)"));
117 return options;
118 }
119
120
121
122
123
124
125
126 private static Class getPrimitiveType(final String name) {
127 if (name.equals("byte")) {
128 return byte.class;
129 }
130 if (name.equals("short")) {
131 return short.class;
132 }
133 if (name.equals("int")) {
134 return int.class;
135 }
136 if (name.equals("long")) {
137 return long.class;
138 }
139 if (name.equals("char")) {
140 return char.class;
141 }
142 if (name.equals("float")) {
143 return float.class;
144 }
145 if (name.equals("double")) {
146 return double.class;
147 }
148 if (name.equals("boolean")) {
149 return boolean.class;
150 }
151 if (name.equals("String")) {
152 return String.class;
153 }
154 return null;
155 }
156
157
158
159
160
161
162
163
164 public static void main(final String args[]) {
165 final JobControlManager mgr = new JobControlManager();
166 mgr.parse(args);
167 mgr.run();
168 }
169
170
171
172
173 private static void printHelp() {
174 LOGGER.info("java " + JobControlManager.class.getCanonicalName() + " [options] steeringFile.xml");
175 final HelpFormatter help = new HelpFormatter();
176 help.printHelp(" ", OPTIONS);
177 System.exit(1);
178 }
179
180
181
182
183 private File cacheDirectory;
184
185
186
187
188 private ClassLoader classLoader;
189
190
191
192
193 CommandLine commandLine = null;
194
195
196
197
198 private final Map<String, Double> constantsMap = new HashMap<String, Double>();
199
200
201
202
203 private String detectorName = null;
204
205
206
207
208 private DriverAdapter driverAdapter = null;
209
210
211
212
213 private final List<Driver> driverExec = new ArrayList<Driver>();
214
215
216
217
218 private final Map<String, Driver> driverMap = new LinkedHashMap<String, Driver>();
219
220
221
222
223 private boolean dryRun;
224
225
226
227
228 private boolean dummyDetector;
229
230
231
232
233 private Long eventPrintInterval = null;
234
235
236
237
238 private final JDOMExpressionFactory factory = new JDOMExpressionFactory();
239
240
241
242
243 private FileCache fileCache;
244
245
246
247
248 private final List<File> inputFiles = new ArrayList<File>();
249
250
251
252
253 private boolean isSetup;
254
255
256
257
258 private long jobEnd = 0;
259
260
261
262
263 private long jobStart = 0;
264
265
266
267
268 private LCSimLoop loop;
269
270
271
272
273 private int numberOfEvents = -1;
274
275
276
277
278 private final ParameterConverters paramConverter = new ParameterConverters(factory);
279
280
281
282
283 private boolean printDriverStatistics;
284
285
286
287
288 private File rewriteFile;
289
290
291
292
293 private boolean rewriteSteering;
294
295
296
297
298 private Element root;
299
300
301
302
303 private Integer runNumber = null;
304
305
306
307
308 private int skipEvents = -1;
309
310
311
312
313 private boolean useSteeringResource;
314
315
316
317
318 private final Map<String, String> variableMap = new HashMap<String, String>();
319
320
321
322
323 public JobControlManager() {
324
325 try {
326 fileCache = new FileCache();
327 } catch (final IOException x) {
328 throw new RuntimeException(x);
329 }
330
331
332 LCSimConditionsManagerImplementation.register();
333 }
334
335
336
337
338
339
340
341 private void addDriver(final String name, final Driver driver) {
342 if (driverMap.containsKey(name)) {
343 throw new RuntimeException("Duplicate driver name: " + name);
344 }
345 driverMap.put(name, driver);
346 }
347
348
349
350
351
352
353 public void addInputFile(final File inputFile) {
354 if (isSetup) {
355 throw new RuntimeException("Input files cannot be added when manager has already been setup.");
356 }
357 inputFiles.add(inputFile);
358 }
359
360
361
362
363
364
365
366
367 public void addVariableDefinition(final String key, final String value) {
368 LOGGER.config(key + " = " + value);
369 if (!this.variableMap.containsKey(key)) {
370 variableMap.put(key, value);
371 } else {
372 throw new RuntimeException("Duplicate variable definition: " + key);
373 }
374 }
375
376
377
378
379 public void configure() {
380 this.getDriverAdapter().start(null);
381 }
382
383
384
385
386 private void createDriverAdapter() {
387 if (this.isSetup == false) {
388 throw new IllegalStateException("The job manager was never setup.");
389 }
390 final Driver topDriver = new Driver();
391 for (final Driver driver : this.getDriverExecList()) {
392 topDriver.add(driver);
393 }
394 driverAdapter = new DriverAdapter(topDriver);
395 }
396
397
398
399
400 private void createDriverExecList() {
401
402 final List<Element> exec = root.getChild("execute").getChildren("driver");
403 for (final Element execDriver : exec) {
404 final String driverName = execDriver.getAttributeValue("name");
405 final Driver driverFind = driverMap.get(driverName);
406 if (driverFind != null) {
407 driverExec.add(driverFind);
408 } else {
409 throw new RuntimeException("A Driver called " + driverName + " was not found.");
410 }
411 }
412
413
414 for (final Driver driver : driverExec) {
415 loop.add(driver);
416 }
417 }
418
419
420
421
422
423 public void enableHeadlessMode() {
424 System.setProperty("hep.aida.IAnalysisFactory", BatchAnalysisFactory.class.getName());
425 }
426
427
428
429
430 public void finish() {
431 this.getDriverAdapter().finish(null);
432 }
433
434
435
436
437
438
439 public DriverAdapter getDriverAdapter() {
440 if (driverAdapter == null) {
441
442 this.createDriverAdapter();
443 }
444 return driverAdapter;
445 }
446
447
448
449
450
451
452
453 public List<Driver> getDriverExecList() {
454 return this.driverExec;
455 }
456
457
458
459
460
461
462 public LCSimLoop getLCSimLoop() {
463 return loop;
464 }
465
466
467
468
469
470
471
472 private List<Method> getSetterMethods(final Class klass) {
473 final List<Method> methods = new ArrayList<Method>();
474 Class currentClass = klass;
475 while (currentClass != null) {
476 for (final Method method : currentClass.getMethods()) {
477 if (method.getName().startsWith("set") && !methods.contains(method)) {
478 methods.add(method);
479 }
480 }
481 currentClass = currentClass.getSuperclass();
482 }
483 return methods;
484 }
485
486
487
488
489 private void initializeLoop() {
490 LOGGER.config("initializing LCSim loop");
491 loop = new LCSimLoop();
492 if (this.eventPrintInterval != null) {
493 loop.addRecordListener(new EventPrintLoopAdapter(this.eventPrintInterval));
494 LOGGER.config("enabled event marker printing with interval " + eventPrintInterval);
495 } else {
496 LOGGER.config("no event printing enabled");
497 }
498 }
499
500
501
502
503
504
505
506
507 public void parse(final String args[]) {
508
509 LOGGER.config("parsing command line arguments");
510
511
512 final CommandLineParser parser = new PosixParser();
513
514
515 try {
516 commandLine = parser.parse(OPTIONS, args);
517 } catch (final ParseException x) {
518 throw new RuntimeException("Problem parsing command line options.", x);
519 }
520
521
522 if (args.length == 0 || commandLine.hasOption("h")) {
523 printHelp();
524 }
525
526
527 if (commandLine.hasOption("p")) {
528 final String[] propValues = commandLine.getOptionValues("p");
529 for (final String propFileName : propValues) {
530 InputStream in = null;
531 try {
532 in = new FileInputStream(propFileName);
533 } catch (final FileNotFoundException e) {
534 throw new RuntimeException(e);
535 }
536 final Properties props = new Properties();
537 try {
538 props.load(in);
539 } catch (final IOException e) {
540 throw new RuntimeException(e);
541 }
542 for (final Entry<Object, Object> entry : props.entrySet()) {
543 final String key = (String) entry.getKey();
544 final String value = (String) entry.getValue();
545 this.addVariableDefinition(key, value);
546 }
547 LOGGER.config("loaded variable definitions from " + propFileName);
548 }
549 }
550
551
552 if (commandLine.hasOption("D")) {
553 final String[] defValues = commandLine.getOptionValues("D");
554 for (final String def : defValues) {
555 final String[] s = def.split("=");
556 if (s.length != 2) {
557 throw new RuntimeException("Bad variable format: " + def);
558 }
559 final String key = s[0];
560 final String value = s[1];
561 this.addVariableDefinition(key, value);
562 LOGGER.config("defined " + key + " = " + value);
563 }
564 }
565
566
567 if (commandLine.hasOption("w")) {
568 this.rewriteSteering = true;
569 final String rewritePath = commandLine.getOptionValue("w");
570 this.rewriteFile = new File(rewritePath);
571 if (this.rewriteFile.exists()) {
572 throw new RuntimeException("Rewrite file already exists: " + rewritePath);
573 }
574 LOGGER.config("XML will be rewritten to " + this.rewriteFile.getPath());
575 }
576
577
578 if (commandLine.hasOption("n")) {
579 this.numberOfEvents = Integer.valueOf(commandLine.getOptionValue("n"));
580 LOGGER.config("max number of events set to " + this.numberOfEvents);
581 }
582
583
584 if (commandLine.hasOption("s")) {
585 this.skipEvents = Integer.valueOf(commandLine.getOptionValue("s"));
586 LOGGER.config("skip events set to " + this.skipEvents);
587 }
588
589
590 if (commandLine.hasOption("x")) {
591 this.dryRun = true;
592 LOGGER.config("dry run is enabled");
593 }
594
595
596 if (commandLine.hasOption("r")) {
597 this.useSteeringResource = true;
598 LOGGER.config("steering resource enabled");
599 }
600
601
602 if (commandLine.getArgList().size() == 0) {
603 throw new RuntimeException("Missing LCSim XML file argument.");
604 } else if (commandLine.getArgList().size() > 1) {
605 throw new RuntimeException("Too many extra arguments.");
606 }
607
608
609 if (commandLine.hasOption("i")) {
610 final String[] files = commandLine.getOptionValues("i");
611 for (final String fileName : files) {
612 final File file = new File(fileName);
613 if (!file.exists()) {
614 throw new RuntimeException("File given as command line option does not exist: " + fileName);
615 }
616 inputFiles.add(new File(fileName));
617 LOGGER.config("added input file " + fileName);
618 }
619 }
620
621
622 if (commandLine.hasOption("b")) {
623 this.enableHeadlessMode();
624 LOGGER.config("headless mode enabled");
625 }
626
627
628 final String steering = (String) commandLine.getArgList().get(0);
629
630 if (commandLine.hasOption("e")) {
631 this.eventPrintInterval = Long.parseLong(commandLine.getOptionValue("e"));
632 LOGGER.config("eventPrintInterval: " + this.eventPrintInterval);
633 if (this.eventPrintInterval <= 0) {
634 throw new IllegalArgumentException("The event print interval must be > 0.");
635 }
636 }
637
638 if (commandLine.hasOption("d")) {
639 this.detectorName = commandLine.getOptionValue("d");
640 LOGGER.config("detector: " + this.detectorName);
641 }
642
643 if (commandLine.hasOption("R")) {
644 this.runNumber = Integer.parseInt(commandLine.getOptionValue("R"));
645 LOGGER.config("runNumber: " + this.runNumber);
646 }
647
648 if (this.detectorName != null && this.runNumber == null ||
649 this.runNumber != null && this.detectorName == null) {
650 throw new IllegalArgumentException("The detector name and run number must be given together.");
651 }
652
653
654 if (this.useSteeringResource) {
655
656 LOGGER.config("initializing from steering resource " + steering);
657 this.setup(steering);
658 } else {
659
660 final File xmlRunControlFile = new File(steering);
661 if (!xmlRunControlFile.exists()) {
662 throw new RuntimeException("The steering file " + args[0] + " does not exist!");
663 }
664 LOGGER.config("initializing from steering file " + xmlRunControlFile.getPath());
665 this.setup(xmlRunControlFile);
666 }
667 }
668
669
670
671
672 private void printInputFileList() {
673 final StringBuffer sb = new StringBuffer();
674 sb.append('\n');
675 sb.append("--- Input Files ---");
676 for (final File file : inputFiles) {
677 sb.append(file.getAbsolutePath());
678 sb.append('\n');
679 }
680 LOGGER.config(sb.toString());
681 }
682
683
684
685
686 private void printUserClasspath() {
687 final StringBuffer sb = new StringBuffer();
688 final URL[] urls = ((URLClassLoader) classLoader).getURLs();
689 if (urls.length > 0) {
690 for (final URL url : ((URLClassLoader) classLoader).getURLs()) {
691 sb.append(url + " ");
692 }
693 sb.append('\n');
694 LOGGER.config("Extra classpath URLs:" + sb.toString());
695 }
696 }
697
698
699
700
701 private void processConstants() {
702 final Element define = root.getChild("define");
703 if (define != null) {
704 for (final Object o : define.getChildren()) {
705 final Element e = (Element) o;
706 final Text txt = (Text) e.getContent().get(0);
707 final double dval = factory.computeDouble(txt.getValue());
708 this.constantsMap.put(e.getName(), dval);
709 factory.addConstant(e.getName(), dval);
710 }
711 }
712 }
713
714
715
716
717
718
719
720
721 private void processDriverParameters(final Class driverClass, final Driver newDriver, final List<Element> parameters) {
722
723 for (final Element parameterElement : parameters) {
724
725
726 Method setter = null;
727
728
729 Class propertyType = null;
730
731
732 final String pname = parameterElement.getName();
733
734
735 final List<Method> methods = this.getSetterMethods(driverClass);
736 final List<Method> methodCandidates = new ArrayList<Method>();
737 for (final Method method : methods) {
738 String propHack = method.getName().replaceFirst("set", "");
739 propHack = propHack.substring(0, 1).toLowerCase() + propHack.substring(1);
740 if (propHack.equals(pname)) {
741 methodCandidates.add(method);
742 }
743 }
744 if (methodCandidates.size() == 1) {
745
746 setter = methodCandidates.get(0);
747 if (setter.getParameterTypes().length > 1) {
748 throw new RuntimeException("The set method has too many arguments for parameter: " + pname);
749 }
750 propertyType = setter.getParameterTypes()[0];
751 } else if (methodCandidates.size() > 1) {
752
753 if (parameterElement.getAttribute("type") == null) {
754 throw new RuntimeException("Parameter " + pname + " in Driver " + driverClass.getCanonicalName()
755 + " is overloaded, but a type field is missing from the parameter's XML element.");
756 }
757 try {
758
759 propertyType = getPrimitiveType(parameterElement.getAttribute("type").getValue());
760
761
762
763 if (propertyType == null) {
764 propertyType = Class.forName(parameterElement.getAttribute("type").getValue());
765 }
766 } catch (final ClassNotFoundException x) {
767 throw new RuntimeException("Bad type " + parameterElement.getAttribute("type").getValue()
768 + " given for parameter " + pname + ".");
769 }
770
771 for (final Method candidateMethod : methodCandidates) {
772 if (candidateMethod.getParameterTypes().length == 1
773 && candidateMethod.getParameterTypes()[0].equals(propertyType)) {
774 setter = candidateMethod;
775 break;
776 }
777 }
778 } else if (methodCandidates.size() == 0) {
779
780 throw new RuntimeException("Set method for Driver parameter " + pname + " was not found.");
781 }
782
783
784 if (setter == null) {
785 throw new RuntimeException("Unable to find set method for parameter " + pname + ".");
786 }
787
788
789 final IParameterConverter converter = paramConverter.getConverterForType(propertyType);
790 if (converter == null) {
791 throw new RuntimeException("No converter found for parameter " + parameterElement.getName()
792 + " with type " + propertyType.getName() + ".");
793 }
794 final Object nextParameter = converter.convert(factory, parameterElement);
795
796
797 final Object pargs[] = new Object[1];
798 pargs[0] = nextParameter;
799 try {
800
801 setter.invoke(newDriver, pargs);
802
803
804 LOGGER.fine(" " + pname + " = " + parameterElement.getText().trim());
805
806 } catch (final Exception x) {
807 throw new RuntimeException("Problem processing parameter " + parameterElement.getName() + ".", x);
808 }
809 }
810 }
811
812
813
814
815
816
817 public void processEvent(final EventHeader event) {
818 this.getDriverAdapter().recordSupplied(new RecordEvent(loop, event));
819 }
820
821
822
823
824
825
826
827
828 private File processFileElement(final Element fileElement, final List<File> fileList) {
829
830 final String fileLoc = this.processPath(fileElement.getText().trim());
831 File file = null;
832
833
834 try {
835 final URL fileURL = new URL(fileLoc);
836
837
838 if (fileLoc.startsWith("file:")) {
839 file = new File(fileURL.getPath());
840 } else {
841
842 try {
843 file = this.fileCache.getCachedFile(fileURL);
844 } catch (final IOException x) {
845 throw new RuntimeException("Unable to fetch file " + fileLoc + " to the cache directory.", x);
846 }
847 }
848 } catch (final MalformedURLException x) {
849
850 file = new File(fileLoc);
851 }
852
853
854 if (fileList != null) {
855 fileList.add(file);
856 }
857
858 return file;
859 }
860
861
862
863
864
865
866
867
868 private File processFileText(final String fileText, final List<File> fileList) {
869 final Element fileElement = new Element("file");
870 fileElement.setText(fileText.trim());
871 return this.processFileElement(fileElement, fileList);
872 }
873
874
875
876
877
878
879
880
881 private String processPath(final String path) {
882 if (path.startsWith("~")) {
883 return path.replaceFirst("~", System.getProperty("user.home"));
884 } else {
885 return path;
886 }
887 }
888
889
890
891
892
893
894
895 private void rewriteXMLSteering(final Document doc) {
896 LOGGER.info("Rewriting XML to " + this.rewriteFile);
897 final XMLOutputter outputter = new XMLOutputter();
898 outputter.setFormat(Format.getPrettyFormat());
899 try {
900 final FileOutputStream out = new FileOutputStream(this.rewriteFile);
901 outputter.output(doc, out);
902 out.close();
903 } catch (final Exception e) {
904 throw new RuntimeException(e);
905 }
906 }
907
908
909
910
911 public boolean run() {
912
913
914 if (!isSetup) {
915 LOGGER.info("Aborting job! Setup was never called.");
916 return false;
917 }
918
919
920 if (dryRun) {
921 LOGGER.info("Executed dry run. No events processed!");
922 return false;
923 }
924
925 boolean okay = true;
926
927 try {
928
929 loop.setLCIORecordSource(new LCIOEventSource(this.getClass().getSimpleName(), inputFiles));
930
931
932 initializeConditions();
933
934
935 if (dummyDetector) {
936 LOGGER.info("Using dummy detector for conditions system!");
937 loop.setDummyDetector("dummy");
938 }
939
940 this.jobStart = System.currentTimeMillis();
941
942 LOGGER.info("Job started: " + new Date(jobStart));
943
944 if (this.skipEvents > 0) {
945 LOGGER.info("Skipping " + skipEvents + " events.");
946 loop.skip(skipEvents);
947 }
948
949
950 final long processedEvents = loop.loop(numberOfEvents, this.printDriverStatistics ? System.out : null);
951 if (numberOfEvents != -1 && processedEvents != numberOfEvents) {
952 LOGGER.info("End of file was reached.");
953 }
954 LOGGER.info("Job processed " + processedEvents + " events.");
955 this.jobEnd = System.currentTimeMillis();
956
957 LOGGER.info("Job ended: " + new Date(this.jobEnd));
958 final long elapsed = this.jobStart - this.jobEnd;
959 LOGGER.info("Job took " + elapsed + " which is " + elapsed / processedEvents + " ms/event.");
960
961 } catch (final Exception e) {
962 LOGGER.log(Level.SEVERE, "A fatal error occurred during the job.", e);
963 okay = false;
964 } finally {
965 try {
966
967 loop.dispose();
968 } catch (final Exception e) {
969 LOGGER.log(Level.WARNING, "An error occurred during job cleanup.", e);
970 okay = false;
971 }
972 }
973
974
975 return okay;
976 }
977
978
979
980
981
982
983 public void setDryRun(final boolean dryRun) {
984 this.dryRun = dryRun;
985 }
986
987
988
989
990
991 public void setNumberOfEvents(final int numberOfEvents) {
992 this.numberOfEvents = numberOfEvents;
993 }
994
995
996
997
998
999
1000
1001
1002
1003 private void setup(final Document xmlDocument) {
1004
1005
1006 if (isSetup) {
1007 throw new IllegalStateException("The job manager was already setup.");
1008 }
1009
1010
1011 root = xmlDocument.getRootElement();
1012
1013
1014 this.substituteVariables(xmlDocument);
1015
1016
1017 if (this.rewriteSteering) {
1018 this.rewriteXMLSteering(xmlDocument);
1019 }
1020
1021
1022 this.setupJobControlParameters();
1023
1024
1025 this.setupClassLoader();
1026
1027
1028 this.setupUnits();
1029
1030
1031 this.processConstants();
1032
1033
1034 this.initializeLoop();
1035
1036
1037 this.setupDrivers();
1038
1039
1040 this.setupFileCache();
1041
1042
1043 this.setupInputFiles();
1044
1045
1046 if (inputFiles.size() == 0 && !this.dryRun) {
1047 LOGGER.severe("No input files provided and dry run is not enabled.");
1048 throw new IllegalStateException("No input files to process.");
1049 }
1050
1051
1052 isSetup = true;
1053 }
1054
1055
1056
1057
1058
1059
1060 public void setup(final File file) {
1061 try {
1062 this.setup(new FileInputStream(file));
1063 } catch (final FileNotFoundException x) {
1064 throw new RuntimeException(x);
1065 }
1066 }
1067
1068
1069
1070
1071
1072
1073 public void setup(final InputStream in) {
1074
1075
1076 final SAXBuilder builder = new SAXBuilder();
1077
1078
1079 builder.setEntityResolver(new ClasspathEntityResolver());
1080 builder.setValidation(true);
1081 builder.setFeature("http://apache.org/xml/features/validation/schema", true);
1082
1083
1084 builder.setFactory(factory);
1085
1086
1087 Document doc = null;
1088 try {
1089 doc = builder.build(in);
1090 } catch (final Exception x) {
1091 throw new RuntimeException(x);
1092 }
1093
1094
1095 this.setup(doc);
1096 }
1097
1098
1099
1100
1101 public void setup(final String resourceURL) {
1102 this.setup(this.getClass().getResourceAsStream(resourceURL));
1103 }
1104
1105
1106
1107
1108 private void setupClassLoader() {
1109
1110 if (classLoader != null) {
1111 LOGGER.info("The ClassLoader was already set externally, so custom classpaths will be ignored!");
1112 return;
1113 }
1114
1115 final Element classpath = root.getChild("classpath");
1116 final List<URL> urlList = new ArrayList<URL>();
1117 if (classpath != null) {
1118 for (final Object jarObject : classpath.getChildren("jar")) {
1119 final Element jarElement = (Element) jarObject;
1120 try {
1121 urlList.add(new File(this.processPath(jarElement.getText())).toURI().toURL());
1122 } catch (final Exception x) {
1123 throw new RuntimeException("Bad jar location: " + jarElement.getText(), x);
1124 }
1125 }
1126 for (final Object jarUrlObject : classpath.getChildren("jarUrl")) {
1127 final Element jarUrlElement = (Element) jarUrlObject;
1128 try {
1129 urlList.add(new URL(jarUrlElement.getText()));
1130 } catch (final Exception x) {
1131 throw new RuntimeException("Bad jar URL: " + jarUrlElement.getText(), x);
1132 }
1133 }
1134 for (final Object cpDirObject : classpath.getChildren("directory")) {
1135 final Element cpDirElement = (Element) cpDirObject;
1136 try {
1137 final File cpFile = new File(this.processPath(cpDirElement.getText()));
1138 if (!cpFile.isDirectory()) {
1139 throw new RuntimeException("The classpath component " + cpFile.getPath()
1140 + " is not a valid directory!");
1141 }
1142 urlList.add(cpFile.toURI().toURL());
1143 } catch (final Exception x) {
1144 throw new RuntimeException("Bad classpath directory: " + cpDirElement.getText(), x);
1145 }
1146 }
1147 }
1148 final URL[] urls = urlList.toArray(new URL[] {});
1149
1150 classLoader = new LCSimClassLoader(urls);
1151
1152
1153 this.printUserClasspath();
1154 }
1155
1156
1157
1158
1159 private void setupDrivers() {
1160
1161
1162 final List<Element> drivers = root.getChild("drivers").getChildren("driver");
1163 for (final Element driver : drivers) {
1164
1165
1166 final String name = driver.getAttributeValue("name");
1167
1168
1169 final String type = driver.getAttributeValue("type");
1170
1171
1172 Class driverClass;
1173 try {
1174 driverClass = classLoader.loadClass(type);
1175 } catch (final ClassNotFoundException x) {
1176 throw new RuntimeException("The Driver class " + type + " was not found.", x);
1177 }
1178
1179 LOGGER.fine("adding driver " + driverClass.getCanonicalName());
1180
1181
1182 Driver newDriver;
1183 try {
1184 newDriver = (Driver) driverClass.newInstance();
1185 } catch (final InstantiationException x) {
1186 throw new RuntimeException("Failed to create a Driver of class " + type + ".", x);
1187 } catch (final IllegalAccessException x) {
1188 throw new RuntimeException("Cannot access Driver type " + type + ".", x);
1189 }
1190
1191
1192 final List<Element> parameters = driver.getChildren();
1193
1194
1195 this.processDriverParameters(driverClass, newDriver, parameters);
1196
1197
1198 this.addDriver(name, newDriver);
1199
1200 }
1201
1202
1203 this.createDriverExecList();
1204 }
1205
1206
1207
1208
1209 private void setupFileCache() {
1210 if (cacheDirectory != null) {
1211 try {
1212 fileCache = new FileCache();
1213 fileCache.setCacheDirectory(cacheDirectory);
1214 fileCache.setPrintStream(null);
1215 LOGGER.config("File cache created at " + cacheDirectory);
1216 } catch (final IOException x) {
1217 throw new RuntimeException(x);
1218 }
1219 }
1220 }
1221
1222
1223
1224
1225 private void setupInputFiles() {
1226
1227 if (root.getChild("inputFiles") == null) {
1228
1229 LOGGER.config("No input files in XML file.");
1230 return;
1231 }
1232
1233
1234 final List<Element> files = root.getChild("inputFiles").getChildren("file");
1235 for (final Element fileElem : files) {
1236 this.processFileElement(fileElem, this.inputFiles);
1237 }
1238
1239
1240 final List<Element> fileLists = root.getChild("inputFiles").getChildren("fileList");
1241 for (final Element fileList : fileLists) {
1242 final String filePath = fileList.getText();
1243 BufferedReader input;
1244 try {
1245 input = new BufferedReader(new FileReader(new File(filePath)));
1246 } catch (final FileNotFoundException x) {
1247 throw new RuntimeException("File not found: " + filePath, x);
1248 }
1249 String line = null;
1250 try {
1251
1252
1253 while ((line = input.readLine()) != null) {
1254 this.processFileText(line.trim(), inputFiles);
1255 }
1256 } catch (final IOException x) {
1257 throw new RuntimeException(x);
1258 } finally {
1259 if (input != null) {
1260 try {
1261 input.close();
1262 } catch (final IOException e) {
1263 e.printStackTrace();
1264 }
1265 }
1266 }
1267 }
1268
1269
1270 final List<Element> fileSets = root.getChild("inputFiles").getChildren("fileSet");
1271 for (final Element fileSet : fileSets) {
1272 final Attribute basedirAttrib = fileSet.getAttribute("baseDir");
1273 String basedir = "";
1274 if (basedirAttrib != null) {
1275 basedir = basedirAttrib.getValue();
1276 }
1277 final List<Element> fsFiles = fileSet.getChildren("file");
1278 for (final Element file : fsFiles) {
1279 final String filePath = basedir + File.separator + file.getText().trim();
1280 this.processFileText(filePath, inputFiles);
1281 }
1282 }
1283
1284
1285 final List<Element> fileRegExps = root.getChild("inputFiles").getChildren("fileRegExp");
1286 for (final Element fileRegExp : fileRegExps) {
1287 final Pattern pattern = Pattern.compile(fileRegExp.getText());
1288 final String basedir = fileRegExp.getAttributeValue("baseDir");
1289 final File dir = new File(basedir);
1290 if (!dir.isDirectory()) {
1291 throw new RuntimeException(basedir + " is not a valid directory!");
1292 }
1293 final String dirlist[] = dir.list();
1294 for (final String file : dirlist) {
1295 if (file.endsWith(".slcio")) {
1296 final Matcher matcher = pattern.matcher(file);
1297 if (matcher.matches()) {
1298 this.processFileText(basedir + File.separator + file, inputFiles);
1299 LOGGER.fine("Matched file <" + file.toString() + "> to pattern <" + pattern.toString() + ">");
1300 } else {
1301 LOGGER.fine("Did NOT match file <" + file.toString() + "> to pattern <" + pattern.toString()
1302 + ">");
1303 }
1304 }
1305 }
1306 }
1307
1308
1309 if (!dryRun) {
1310 for (final File file : inputFiles) {
1311 if (!file.exists()) {
1312 LOGGER.info("The input file " + file.getAbsolutePath() + " does not exist.");
1313 throw new RuntimeException("The input file " + file.getAbsolutePath() + " does not exist!");
1314 }
1315 }
1316 }
1317
1318
1319 this.printInputFileList();
1320
1321 if (inputFiles.size() == 0) {
1322 LOGGER.info("No input files were provided by the steering file or command line options. Dry run will be enabled.");
1323 this.dryRun = true;
1324 }
1325 }
1326
1327
1328
1329
1330 private void setupJobControlParameters() {
1331
1332 final Element control = root.getChild("control");
1333
1334 if (control == null) {
1335
1336 return;
1337 }
1338
1339
1340 LOGGER.config(this.getClass().getCanonicalName() + " is initialized.");
1341
1342
1343 final Element controlElement = control.getChild("numberOfEvents");
1344 if (controlElement != null) {
1345 numberOfEvents = Integer.valueOf(controlElement.getText());
1346 LOGGER.config("numberOfEvents: " + numberOfEvents);
1347 }
1348
1349 final Element skipElement = control.getChild("skipEvents");
1350 if (skipElement != null) {
1351 skipEvents = Integer.valueOf(skipElement.getText());
1352 LOGGER.config("skipEvents: " + skipEvents);
1353 }
1354
1355 final Element dryRunElement = control.getChild("dryRun");
1356 if (dryRunElement != null) {
1357 dryRun = Boolean.valueOf(dryRunElement.getText());
1358 LOGGER.config("dryRun: " + dryRun);
1359 }
1360
1361
1362 final Element cacheDirElement = control.getChild("cacheDirectory");
1363 if (cacheDirElement != null) {
1364 cacheDirectory = new File(cacheDirElement.getText());
1365 if (!cacheDirectory.exists()) {
1366 throw new RuntimeException("cacheDirectory does not exist at location: " + cacheDirElement.getText());
1367 }
1368 } else {
1369
1370 cacheDirectory = new File(System.getProperties().get("user.dir").toString());
1371 }
1372
1373 LOGGER.config("cacheDirectory: " + cacheDirectory);
1374
1375 final Element printStatisticsElement = control.getChild("printDriverStatistics");
1376 if (printStatisticsElement != null) {
1377 printDriverStatistics = Boolean.valueOf(printStatisticsElement.getText());
1378 LOGGER.config("printDriverStatistics: " + printDriverStatistics);
1379 }
1380
1381 final Element dummyDetectorElement = control.getChild("dummyDetector");
1382 if (dummyDetectorElement != null) {
1383 dummyDetector = Boolean.valueOf(dummyDetectorElement.getText());
1384 LOGGER.config("dummyDetector: " + dummyDetector);
1385 }
1386 }
1387
1388
1389
1390
1391 private void setupUnits() {
1392 final Constants constants = Constants.getInstance();
1393 for (final Entry<String, Double> unit : constants.entrySet()) {
1394 factory.addConstant(unit.getKey(), unit.getValue());
1395 LOGGER.finest(unit.getKey() + " = " + unit.getValue());
1396 }
1397 }
1398
1399
1400
1401
1402
1403
1404 private void substituteVariables(final Document doc) {
1405 this.substituteVariables(doc.getRootElement());
1406 }
1407
1408
1409
1410
1411
1412
1413
1414 private void substituteVariables(final Element element) {
1415
1416 final String text = element.getTextNormalize();
1417
1418 if (text.length() != 0) {
1419
1420
1421 final Matcher match = VARIABLE_PATTERN.matcher(text);
1422
1423
1424 if (!match.find()) {
1425 return;
1426 }
1427
1428
1429 String newText = new String(text);
1430
1431
1432 match.reset();
1433
1434
1435 while (match.find()) {
1436
1437
1438 final String var = match.group();
1439
1440
1441 final String varName = var.substring(2, var.length() - 1);
1442
1443
1444 final String varValue = variableMap.get(varName);
1445
1446
1447 if (varValue == null) {
1448 throw new RuntimeException("Required variable was not defined: " + varName);
1449 }
1450
1451
1452 newText = newText.replace(var, varValue);
1453 }
1454
1455
1456 element.setText(newText);
1457 }
1458
1459
1460 for (final Iterator it = element.getChildren().iterator(); it.hasNext();) {
1461 this.substituteVariables((Element) it.next());
1462 }
1463 }
1464
1465
1466
1467
1468
1469
1470
1471
1472 protected void initializeConditions() throws ConditionsNotFoundException {
1473
1474 if (this.detectorName != null) {
1475 LOGGER.config("initializing conditions system with detector " + this.detectorName + " and run " + this.runNumber);
1476 ConditionsManager.defaultInstance().setDetector(this.detectorName, this.runNumber);
1477 }
1478 }
1479
1480
1481
1482
1483
1484 protected Integer getRunNumber() {
1485 return this.runNumber;
1486 }
1487
1488
1489
1490
1491
1492 protected String getDetectorName() {
1493 return this.detectorName;
1494 }
1495 }