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