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