1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.eclipse.jetty.start;
18
19 import java.io.BufferedReader;
20 import java.io.File;
21 import java.io.FileFilter;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.InputStreamReader;
25 import java.io.Reader;
26 import java.io.StringReader;
27 import java.lang.reflect.Constructor;
28 import java.lang.reflect.InvocationTargetException;
29 import java.net.URL;
30 import java.security.Policy;
31 import java.text.CollationKey;
32 import java.text.Collator;
33 import java.util.ArrayList;
34 import java.util.Arrays;
35 import java.util.Collection;
36 import java.util.Collections;
37 import java.util.Comparator;
38 import java.util.Enumeration;
39 import java.util.HashMap;
40 import java.util.Iterator;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.Properties;
44 import java.util.Set;
45 import java.util.StringTokenizer;
46 import java.util.TreeSet;
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 public class Config
147 {
148 public static final String DEFAULT_SECTION = "";
149 static
150 {
151 Package pkg = Config.class.getPackage();
152 if (pkg != null &&
153 "Eclipse.org - Jetty".equals(pkg.getImplementationVendor()) &&
154 (pkg.getImplementationVersion() != null))
155 _version = pkg.getImplementationVersion();
156 else
157 _version = System.getProperty("jetty.version","Unknown");
158 }
159
160
161
162
163 private final Comparator<String> keySorter = new Comparator<String>()
164 {
165 private final Collator collator = Collator.getInstance();
166
167 public int compare(String o1, String o2)
168 {
169 CollationKey key1 = collator.getCollationKey(o1);
170 CollationKey key2 = collator.getCollationKey(o2);
171 return key1.compareTo(key2);
172 }
173 };
174
175 private static final String _version;
176 private static boolean DEBUG = false;
177 private static final Map<String, String> __properties = new HashMap<String, String>();
178 private final Map<String, Classpath> _classpaths = new HashMap<String, Classpath>();
179 private final List<String> _xml = new ArrayList<String>();
180 private String _policyDirectory = null;
181 private String _classname = null;
182
183 private int argCount = 0;
184
185 private final Set<String> _activeOptions = new TreeSet<String>(new Comparator<String>()
186 {
187
188 public int compare(String o1, String o2)
189 {
190 if ("*".equals(o1))
191 {
192 return 1;
193 }
194 if ("*".equals(o2))
195 {
196 return -1;
197 }
198 return o1.compareTo(o2);
199 }
200 });
201
202 private boolean addClasspathComponent(List<String> sections, String component)
203 {
204 for (String section : sections)
205 {
206 Classpath cp = _classpaths.get(section);
207 if (cp == null)
208 cp = new Classpath();
209
210 boolean added = cp.addComponent(component);
211 _classpaths.put(section,cp);
212
213 if (!added)
214 {
215
216 return false;
217 }
218 }
219
220 return true;
221 }
222
223 private boolean addClasspathPath(List<String> sections, String path)
224 {
225 for (String section : sections)
226 {
227 Classpath cp = _classpaths.get(section);
228 if (cp == null)
229 {
230 cp = new Classpath();
231 }
232 if (!cp.addClasspath(path))
233 {
234
235 return false;
236 }
237 _classpaths.put(section,cp);
238 }
239
240 return true;
241 }
242
243 private void addJars(List<String> sections, File dir, boolean recurse) throws IOException
244 {
245 List<File> entries = new ArrayList<File>();
246 File[] files = dir.listFiles();
247 if (files == null)
248 {
249
250 return;
251 }
252 entries.addAll(Arrays.asList(files));
253 Collections.sort(entries,FilenameComparator.INSTANCE);
254
255 for (File entry : entries)
256 {
257 if (entry.isDirectory())
258 {
259 if (recurse)
260 addJars(sections,entry,recurse);
261 }
262 else
263 {
264 String name = entry.getName().toLowerCase();
265 if (name.endsWith(".jar") || name.endsWith(".zip"))
266 {
267 String jar = entry.getCanonicalPath();
268 boolean added = addClasspathComponent(sections,jar);
269 debug((added?" CLASSPATH+=":" !") + jar);
270 }
271 }
272 }
273 }
274
275 private void close(InputStream stream)
276 {
277 if (stream == null)
278 return;
279
280 try
281 {
282 stream.close();
283 }
284 catch (IOException ignore)
285 {
286
287 }
288 }
289
290 private void close(Reader reader)
291 {
292 if (reader == null)
293 return;
294
295 try
296 {
297 reader.close();
298 }
299 catch (IOException ignore)
300 {
301
302 }
303 }
304
305 public static boolean isDebug()
306 {
307 return DEBUG;
308 }
309
310 public static void debug(String msg)
311 {
312 if (DEBUG)
313 {
314 System.err.println(msg);
315 }
316 }
317
318 public static void debug(Throwable t)
319 {
320 if (DEBUG)
321 {
322 t.printStackTrace(System.err);
323 }
324 }
325
326 private String expand(String s)
327 {
328 int i1 = 0;
329 int i2 = 0;
330 while (s != null)
331 {
332 i1 = s.indexOf("$(",i2);
333 if (i1 < 0)
334 break;
335 i2 = s.indexOf(")",i1 + 2);
336 if (i2 < 0)
337 break;
338 String name = s.substring(i1 + 2,i2);
339 String property = getProperty(name);
340 s = s.substring(0,i1) + property + s.substring(i2 + 1);
341 }
342
343 i1 = 0;
344 i2 = 0;
345 while (s != null)
346 {
347 i1 = s.indexOf("${",i2);
348 if (i1 < 0)
349 break;
350 i2 = s.indexOf("}",i1 + 2);
351 if (i2 < 0)
352 break;
353 String name = s.substring(i1 + 2,i2);
354 String property = getProperty(name);
355 s = s.substring(0,i1) + property + s.substring(i2 + 1);
356 }
357
358 return s;
359 }
360
361
362
363
364
365
366 public Classpath getClasspath()
367 {
368 return _classpaths.get(DEFAULT_SECTION);
369 }
370
371
372
373
374
375
376
377 public Classpath getActiveClasspath()
378 {
379 return getCombinedClasspath(_activeOptions);
380 }
381
382
383
384
385
386
387
388
389
390
391
392 public Classpath getCombinedClasspath(Collection<String> optionIds)
393 {
394 Classpath cp = new Classpath();
395
396 cp.overlay(_classpaths.get(DEFAULT_SECTION));
397 for (String optionId : optionIds)
398 {
399 Classpath otherCp = _classpaths.get(optionId);
400 if (otherCp == null)
401 {
402 throw new IllegalArgumentException("No such OPTIONS: " + optionId);
403 }
404 cp.overlay(otherCp);
405 }
406 cp.overlay(_classpaths.get("*"));
407 return cp;
408 }
409
410 public String getMainClassname()
411 {
412 return _classname;
413 }
414
415 public static void clearProperties()
416 {
417 __properties.clear();
418 }
419
420 public static Properties getProperties()
421 {
422 Properties properties = new Properties();
423
424 Enumeration<?> ensysprop = System.getProperties().propertyNames();
425 while(ensysprop.hasMoreElements()) {
426 String name = (String)ensysprop.nextElement();
427 properties.put(name, System.getProperty(name));
428 }
429
430 for (String key : __properties.keySet()) {
431 properties.put(key,__properties.get(key));
432 }
433 return properties;
434 }
435
436 public static String getProperty(String name)
437 {
438 if ("version".equalsIgnoreCase(name)) {
439 return _version;
440 }
441
442 if (__properties.containsKey(name)) {
443 return __properties.get(name);
444 }
445
446 return System.getProperty(name);
447 }
448
449 public static String getProperty(String name, String defaultValue)
450 {
451
452 if (__properties.containsKey(name))
453 return __properties.get(name);
454
455 return System.getProperty(name, defaultValue);
456 }
457
458
459
460
461
462
463
464 public Classpath getSectionClasspath(String sectionId)
465 {
466 return _classpaths.get(sectionId);
467 }
468
469
470
471
472
473
474 public Set<String> getSectionIds()
475 {
476 Set<String> ids = new TreeSet<String>(keySorter);
477 ids.addAll(_classpaths.keySet());
478 return ids;
479 }
480
481 public List<String> getXmlConfigs()
482 {
483 return _xml;
484 }
485
486 private boolean isAvailable(List<String> options, String classname)
487 {
488
489 try
490 {
491 Class.forName(classname);
492 return true;
493 }
494 catch (NoClassDefFoundError e)
495 {
496 debug(e);
497 }
498 catch (ClassNotFoundException e)
499 {
500 debug("ClassNotFoundException (parent class loader): " + classname);
501 }
502
503
504 ClassLoader loader;
505 Classpath classpath;
506 for (String optionId : options)
507 {
508 classpath = _classpaths.get(optionId);
509 if (classpath == null)
510 {
511
512 continue;
513 }
514
515 loader = classpath.getClassLoader();
516
517 try
518 {
519 loader.loadClass(classname);
520 return true;
521 }
522 catch (NoClassDefFoundError e)
523 {
524 debug(e);
525 }
526 catch (ClassNotFoundException e)
527 {
528 debug("ClassNotFoundException (section class loader: " + optionId + "): " + classname);
529 }
530 }
531 return false;
532 }
533
534
535
536
537
538
539
540 public void parse(CharSequence buf) throws IOException
541 {
542 parse(new StringReader(buf.toString()));
543 }
544
545
546
547
548
549
550
551 public void parse(InputStream stream) throws IOException
552 {
553 InputStreamReader reader = null;
554 try
555 {
556 reader = new InputStreamReader(stream);
557 parse(reader);
558 }
559 finally
560 {
561 close(reader);
562 }
563 }
564
565
566
567 public void parse(Reader reader) throws IOException
568 {
569 BufferedReader buf = null;
570
571 try
572 {
573 buf = new BufferedReader(reader);
574
575 List<String> options = new ArrayList<String>();
576 options.add(DEFAULT_SECTION);
577 _classpaths.put(DEFAULT_SECTION,new Classpath());
578 Version java_version = new Version(System.getProperty("java.version"));
579 Version ver = new Version();
580
581 String line = null;
582 while ((line = buf.readLine()) != null)
583 {
584 String trim = line.trim();
585 if (trim.length() == 0)
586 continue;
587
588 if (trim.startsWith("#"))
589 continue;
590
591
592 if (trim.startsWith("[") && trim.endsWith("]"))
593 {
594 String identifier = trim.substring(1,trim.length() - 1);
595
596
597 options = Arrays.asList(identifier.split(","));
598 List<String> option_ids=new ArrayList<String>();
599
600
601 for (String optionId : options)
602 {
603 if (optionId.charAt(0) == '=')
604 continue;
605
606 if (!_classpaths.containsKey(optionId))
607 _classpaths.put(optionId,new Classpath());
608
609 if (!option_ids.contains(optionId))
610 option_ids.add(optionId);
611 }
612
613
614
615 for (String optionId : options)
616 {
617 if (optionId.charAt(0) != '=')
618 continue;
619
620 option_ids = processDynamicSectionIdentifier(optionId.substring(1),option_ids);
621 }
622
623 options = option_ids;
624
625 continue;
626 }
627
628 try
629 {
630 StringTokenizer st = new StringTokenizer(line);
631 String subject = st.nextToken();
632 boolean expression = true;
633 boolean not = false;
634 String condition = null;
635
636 while (st.hasMoreTokens())
637 {
638 condition = st.nextToken();
639 if (condition.equalsIgnoreCase("!"))
640 {
641 not = true;
642 continue;
643 }
644 if (condition.equalsIgnoreCase("OR"))
645 {
646 if (expression)
647 break;
648 expression = true;
649 continue;
650 }
651 if (condition.equalsIgnoreCase("AND"))
652 {
653 if (!expression)
654 break;
655 continue;
656 }
657 boolean eval = true;
658 if (condition.equals("true") || condition.equals("always"))
659 {
660 eval = true;
661 }
662 else if (condition.equals("false") || condition.equals("never"))
663 {
664 eval = false;
665 }
666 else if (condition.equals("available"))
667 {
668 String class_to_check = st.nextToken();
669 eval = isAvailable(options,class_to_check);
670 }
671 else if (condition.equals("exists"))
672 {
673 try
674 {
675 eval = false;
676 File file = new File(expand(st.nextToken()));
677 eval = file.exists();
678 }
679 catch (Exception e)
680 {
681 debug(e);
682 }
683 }
684 else if (condition.equals("property"))
685 {
686 String property = getProperty(st.nextToken());
687 eval = property != null && property.length() > 0;
688 }
689 else if (condition.equals("system"))
690 {
691 String property = System.getProperty(st.nextToken());
692 eval = property != null && property.length() > 0;
693 }
694 else if (condition.equals("java"))
695 {
696 String operator = st.nextToken();
697 String version = st.nextToken();
698 ver.parse(version);
699 eval = (operator.equals("<") && java_version.compare(ver) < 0) || (operator.equals(">") && java_version.compare(ver) > 0)
700 || (operator.equals("<=") && java_version.compare(ver) <= 0) || (operator.equals("=<") && java_version.compare(ver) <= 0)
701 || (operator.equals("=>") && java_version.compare(ver) >= 0) || (operator.equals(">=") && java_version.compare(ver) >= 0)
702 || (operator.equals("==") && java_version.compare(ver) == 0) || (operator.equals("!=") && java_version.compare(ver) != 0);
703 }
704 else if (condition.equals("nargs"))
705 {
706 String operator = st.nextToken();
707 int number = Integer.parseInt(st.nextToken());
708 eval = (operator.equals("<") && argCount < number) || (operator.equals(">") && argCount > number)
709 || (operator.equals("<=") && argCount <= number) || (operator.equals("=<") && argCount <= number)
710 || (operator.equals("=>") && argCount >= number) || (operator.equals(">=") && argCount >= number)
711 || (operator.equals("==") && argCount == number) || (operator.equals("!=") && argCount != number);
712 }
713 else
714 {
715 System.err.println("ERROR: Unknown condition: " + condition);
716 eval = false;
717 }
718 expression &= not?!eval:eval;
719 not = false;
720 }
721
722 String file = expand(subject);
723 debug((expression?"T ":"F ") + line);
724 if (!expression)
725 continue;
726
727
728 if (subject.indexOf("~=") > 0)
729 {
730 int i = file.indexOf("~=");
731 String property = file.substring(0,i);
732 String value = fixPath(file.substring(i + 2));
733 debug(" " + property + "~=" + value);
734 setProperty(property,value);
735 continue;
736 }
737
738
739 if (subject.indexOf("/=") > 0)
740 {
741 int i = file.indexOf("/=");
742 String property = file.substring(0,i);
743 String value = fixPath(file.substring(i + 2));
744 String canonical = new File(value).getCanonicalPath();
745 debug(" " + property + "/=" + value + "==" + canonical);
746 setProperty(property,canonical);
747 continue;
748 }
749
750
751 if (subject.indexOf("=") > 0)
752 {
753 int i = file.indexOf("=");
754 String property = file.substring(0,i);
755 String value = fixPath(file.substring(i + 1));
756 debug(" " + property + "=" + value);
757 System.setProperty(property,value);
758 continue;
759 }
760
761
762 if (subject.endsWith("/*"))
763 {
764
765 File dir = new File(fixPath(file.substring(0,file.length() - 1)));
766 addJars(options,dir,false);
767 continue;
768 }
769
770
771 if (subject.endsWith("/**"))
772 {
773
774 File dir = new File(fixPath(file.substring(0,file.length() - 2)));
775 addJars(options,dir,true);
776 continue;
777 }
778
779
780 if (subject.endsWith("/"))
781 {
782
783 File cd = new File(fixPath(file));
784 String d = cd.getCanonicalPath();
785 boolean added = addClasspathComponent(options,d);
786 debug((added?" CLASSPATH+=":" !") + d);
787 continue;
788 }
789
790
791 if (subject.toLowerCase().endsWith(".xml"))
792 {
793
794 File f = new File(fixPath(file));
795 if (f.exists())
796 _xml.add(f.getCanonicalPath());
797 debug(" ARGS+=" + f);
798 continue;
799 }
800
801
802 if (subject.toLowerCase().endsWith(".class"))
803 {
804
805 String cn = expand(subject.substring(0,subject.length() - 6));
806 if (cn != null && cn.length() > 0)
807 {
808 debug(" CLASS=" + cn);
809 _classname = cn;
810 }
811 continue;
812 }
813
814
815 if (subject.toLowerCase().endsWith(".path"))
816 {
817
818 String cn = expand(subject.substring(0,subject.length() - 5));
819 if (cn != null && cn.length() > 0)
820 {
821 debug(" PATH=" + cn);
822 addClasspathPath(options,cn);
823 }
824 continue;
825 }
826
827
828 File f = new File(fixPath(file));
829 if (f.exists())
830 {
831 String d = f.getCanonicalPath();
832 boolean added = addClasspathComponent(options,d);
833 if (!added)
834 {
835 added = addClasspathPath(options,expand(subject));
836 }
837 debug((added?" CLASSPATH+=":" !") + d);
838 }
839 }
840 catch (Exception e)
841 {
842 System.err.println("on line: '" + line + "'");
843 e.printStackTrace();
844 }
845 }
846 }
847 finally
848 {
849 close(buf);
850 }
851 }
852
853 private List<String> processDynamicSectionIdentifier(String dynamicPathId,List<String> sections) throws IOException
854 {
855 String rawPath;
856 boolean deep;
857
858 if (dynamicPathId.endsWith("/*"))
859 {
860 deep=false;
861 rawPath = fixPath(dynamicPathId.substring(0,dynamicPathId.length() - 1));
862 }
863 else if (dynamicPathId.endsWith("/**"))
864 {
865 deep=true;
866 rawPath = fixPath(dynamicPathId.substring(0,dynamicPathId.length() - 2));
867 }
868 else
869 {
870 String msg = "Illegal dynamic path [" + dynamicPathId + "]";
871 throw new IOException(msg);
872 }
873
874 File parentDir = new File(expand(rawPath));
875 if (!parentDir.exists())
876 return sections;
877 debug("dynamic: " + parentDir);
878
879 File dirs[] = parentDir.listFiles(new FileFilter()
880 {
881 public boolean accept(File path)
882 {
883 return path.isDirectory();
884 }
885 });
886
887 List<String> dyn_sections = new ArrayList<String>();
888 List<String> super_sections = new ArrayList<String>();
889 if (sections!=null)
890 super_sections.addAll(sections);
891
892 for (File dir : dirs)
893 {
894 String id = dir.getName();
895 if (!_classpaths.keySet().contains(id))
896 _classpaths.put(id, new Classpath());
897
898 dyn_sections.clear();
899 if (sections!=null)
900 dyn_sections.addAll(sections);
901 dyn_sections.add(id);
902 super_sections.add(id);
903 debug("dynamic: " + dyn_sections);
904 addJars(dyn_sections,dir,deep);
905 }
906
907 return super_sections;
908 }
909
910 private String fixPath(String path)
911 {
912 return path.replace('/',File.separatorChar);
913 }
914
915 public void parse(URL url) throws IOException
916 {
917 InputStream stream = null;
918 InputStreamReader reader = null;
919 try
920 {
921 stream = url.openStream();
922 reader = new InputStreamReader(stream);
923 parse(reader);
924 }
925 finally
926 {
927 close(reader);
928 close(stream);
929 }
930 }
931
932 public void setArgCount(int argCount)
933 {
934 this.argCount = argCount;
935 }
936
937 public void setProperty(String name, String value)
938 {
939 if (name.equals("DEBUG"))
940 {
941 DEBUG = Boolean.parseBoolean(value);
942 if (DEBUG)
943 {
944 System.setProperty("org.eclipse.jetty.util.log.stderr.DEBUG","true");
945 System.setProperty("org.eclipse.jetty.start.DEBUG","true");
946 }
947 }
948 if (name.equals("OPTIONS"))
949 {
950 _activeOptions.clear();
951 String ids[] = value.split(",");
952 for (String id : ids)
953 {
954 addActiveOption(id);
955 }
956 }
957 __properties.put(name,value);
958 }
959
960 public void addActiveOption(String option)
961 {
962 _activeOptions.add(option);
963 __properties.put("OPTIONS",join(_activeOptions,","));
964 }
965
966 public Set<String> getActiveOptions()
967 {
968 return _activeOptions;
969 }
970
971 public void removeActiveOption(String option)
972 {
973 _activeOptions.remove(option);
974 __properties.put("OPTIONS",join(_activeOptions,","));
975 }
976
977 private String join(Collection<?> coll, String delim)
978 {
979 StringBuffer buf = new StringBuffer();
980 Iterator<?> i = coll.iterator();
981 boolean hasNext = i.hasNext();
982 while (hasNext)
983 {
984 buf.append(String.valueOf(i.next()));
985 hasNext = i.hasNext();
986 if (hasNext)
987 buf.append(delim);
988 }
989
990 return buf.toString();
991 }
992
993 }