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