1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.xml;
20
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.StringReader;
24 import java.lang.reflect.Array;
25 import java.lang.reflect.Constructor;
26 import java.lang.reflect.Field;
27 import java.lang.reflect.InvocationTargetException;
28 import java.lang.reflect.Method;
29 import java.lang.reflect.Modifier;
30 import java.net.InetAddress;
31 import java.net.MalformedURLException;
32 import java.net.URL;
33 import java.net.UnknownHostException;
34 import java.security.AccessController;
35 import java.security.PrivilegedAction;
36 import java.util.ArrayList;
37 import java.util.Collection;
38 import java.util.HashMap;
39 import java.util.HashSet;
40 import java.util.LinkedList;
41 import java.util.List;
42 import java.util.Locale;
43 import java.util.Map;
44 import java.util.Properties;
45 import java.util.Queue;
46 import java.util.ServiceLoader;
47 import java.util.Set;
48 import java.util.concurrent.atomic.AtomicReference;
49
50 import org.eclipse.jetty.util.ArrayQueue;
51 import org.eclipse.jetty.util.LazyList;
52 import org.eclipse.jetty.util.Loader;
53 import org.eclipse.jetty.util.StringUtil;
54 import org.eclipse.jetty.util.TypeUtil;
55 import org.eclipse.jetty.util.component.LifeCycle;
56 import org.eclipse.jetty.util.log.Log;
57 import org.eclipse.jetty.util.log.Logger;
58 import org.eclipse.jetty.util.resource.Resource;
59 import org.xml.sax.InputSource;
60 import org.xml.sax.SAXException;
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79 public class XmlConfiguration
80 {
81 private static final Logger LOG = Log.getLogger(XmlConfiguration.class);
82 private static final Class<?>[] __primitives =
83 {Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE, Void.TYPE};
84 private static final Class<?>[] __boxedPrimitives =
85 {Boolean.class, Character.class, Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, Void.class};
86 private static final Class<?>[] __supportedCollections =
87 {ArrayList.class, ArrayQueue.class, HashSet.class, Queue.class, List.class, Set.class, Collection.class};
88 private static final Iterable<ConfigurationProcessorFactory> __factoryLoader = ServiceLoader.load(ConfigurationProcessorFactory.class);
89 private static final XmlParser __parser = initParser();
90 private static XmlParser initParser()
91 {
92 XmlParser parser = new XmlParser();
93 URL config60 = Loader.getResource(XmlConfiguration.class, "org/eclipse/jetty/xml/configure_6_0.dtd");
94 URL config76 = Loader.getResource(XmlConfiguration.class,"org/eclipse/jetty/xml/configure_7_6.dtd");
95 URL config90 = Loader.getResource(XmlConfiguration.class,"org/eclipse/jetty/xml/configure_9_0.dtd");
96 URL config93 = Loader.getResource(XmlConfiguration.class,"org/eclipse/jetty/xml/configure_9_3.dtd");
97 parser.redirectEntity("configure.dtd",config90);
98 parser.redirectEntity("configure_1_0.dtd",config60);
99 parser.redirectEntity("configure_1_1.dtd",config60);
100 parser.redirectEntity("configure_1_2.dtd",config60);
101 parser.redirectEntity("configure_1_3.dtd",config60);
102 parser.redirectEntity("configure_6_0.dtd",config60);
103 parser.redirectEntity("configure_7_6.dtd",config76);
104 parser.redirectEntity("configure_9_0.dtd",config90);
105 parser.redirectEntity("configure_9_3.dtd",config93);
106
107 parser.redirectEntity("http://jetty.mortbay.org/configure.dtd",config93);
108 parser.redirectEntity("http://jetty.eclipse.org/configure.dtd",config93);
109 parser.redirectEntity("http://www.eclipse.org/jetty/configure.dtd",config93);
110
111 parser.redirectEntity("-//Mort Bay Consulting//DTD Configure//EN",config93);
112 parser.redirectEntity("-//Jetty//Configure//EN",config93);
113
114 return parser;
115 }
116
117 private final Map<String, Object> _idMap = new HashMap<>();
118 private final Map<String, String> _propertyMap = new HashMap<>();
119 private final URL _url;
120 private final String _dtd;
121 private ConfigurationProcessor _processor;
122
123
124
125
126
127
128
129
130 public XmlConfiguration(URL configuration) throws SAXException, IOException
131 {
132 synchronized (__parser)
133 {
134 _url=configuration;
135 setConfig(__parser.parse(configuration.toString()));
136 _dtd=__parser.getDTD();
137 }
138 }
139
140
141
142
143
144
145
146
147
148 public XmlConfiguration(String configuration) throws SAXException, IOException
149 {
150 configuration = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE Configure PUBLIC \"-//Jetty//Configure//EN\" \"http://eclipse.org/jetty/configure.dtd\">"
151 + configuration;
152 InputSource source = new InputSource(new StringReader(configuration));
153 synchronized (__parser)
154 {
155 _url=null;
156 setConfig( __parser.parse(source));
157 _dtd=__parser.getDTD();
158 }
159 }
160
161
162
163
164
165
166
167
168 public XmlConfiguration(InputStream configuration) throws SAXException, IOException
169 {
170 InputSource source = new InputSource(configuration);
171 synchronized (__parser)
172 {
173 _url=null;
174 setConfig(__parser.parse(source));
175 _dtd=__parser.getDTD();
176 }
177 }
178
179 private void setConfig(XmlParser.Node config)
180 {
181 if ("Configure".equals(config.getTag()))
182 {
183 _processor=new JettyXmlConfiguration();
184 }
185 else if (__factoryLoader!=null)
186 {
187 for (ConfigurationProcessorFactory factory : __factoryLoader)
188 {
189 _processor = factory.getConfigurationProcessor(_dtd, config.getTag());
190 if (_processor!=null)
191 break;
192 }
193
194 if (_processor==null)
195 throw new IllegalStateException("Unknown configuration type: "+config.getTag()+" in "+this);
196 }
197 else
198 {
199 throw new IllegalArgumentException("Unknown XML tag:"+config.getTag());
200 }
201 _processor.init(_url,config,this);
202 }
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219 public Map<String, Object> getIdMap()
220 {
221 return _idMap;
222 }
223
224
225
226
227
228
229
230 public Map<String, String> getProperties()
231 {
232 return _propertyMap;
233 }
234
235
236
237
238
239
240
241
242
243 public Object configure(Object obj) throws Exception
244 {
245 return _processor.configure(obj);
246 }
247
248
249
250
251
252
253
254
255
256
257 public Object configure() throws Exception
258 {
259 return _processor.configure();
260 }
261
262
263
264
265
266
267
268
269 public void initializeDefaults(Object object)
270 {
271 }
272
273
274 private static class JettyXmlConfiguration implements ConfigurationProcessor
275 {
276
277 private String _url;
278 XmlParser.Node _root;
279 XmlConfiguration _configuration;
280
281 public void init(URL url, XmlParser.Node root, XmlConfiguration configuration)
282 {
283 _url=url==null?null:url.toString();
284 _root=root;
285 _configuration=configuration;
286 }
287
288 public Object configure(Object obj) throws Exception
289 {
290
291 Class<?> oClass = nodeClass(_root);
292 if (oClass != null && !oClass.isInstance(obj))
293 {
294 String loaders = (oClass.getClassLoader()==obj.getClass().getClassLoader())?"":"Object Class and type Class are from different loaders.";
295 throw new IllegalArgumentException("Object of class '"+obj.getClass().getCanonicalName()+"' is not of type '" + oClass.getCanonicalName()+"'. "+loaders+" in "+_url);
296 }
297 String id=_root.getAttribute("id");
298 if (id!=null)
299 _configuration.getIdMap().put(id,obj);
300 configure(obj,_root,0);
301 return obj;
302 }
303
304 public Object configure() throws Exception
305 {
306 Class<?> oClass = nodeClass(_root);
307
308 String id = _root.getAttribute("id");
309 Object obj = id == null?null:_configuration.getIdMap().get(id);
310
311 int index = 0;
312 if (obj == null && oClass != null)
313 {
314 index = _root.size();
315 Map<String, Object> namedArgMap = new HashMap<>();
316
317 List<Object> arguments = new LinkedList<>();
318 for (int i = 0; i < _root.size(); i++)
319 {
320 Object o = _root.get(i);
321 if (o instanceof String)
322 {
323 continue;
324 }
325 XmlParser.Node node = (XmlParser.Node)o;
326
327 if (!(node.getTag().equals("Arg")))
328 {
329 index = i;
330 break;
331 }
332 else
333 {
334 String namedAttribute = node.getAttribute("name");
335 Object value=value(obj,(XmlParser.Node)o);
336 if (namedAttribute != null)
337 namedArgMap.put(namedAttribute,value);
338 arguments.add(value);
339 }
340 }
341
342 try
343 {
344 if (namedArgMap.size() > 0)
345 obj = TypeUtil.construct(oClass, arguments.toArray(), namedArgMap);
346 else
347 obj = TypeUtil.construct(oClass, arguments.toArray());
348 }
349 catch (NoSuchMethodException x)
350 {
351 throw new IllegalStateException(String.format("No constructor %s(%s,%s) in %s",oClass,arguments,namedArgMap,_url));
352 }
353 }
354 if (id!=null)
355 _configuration.getIdMap().put(id,obj);
356
357 _configuration.initializeDefaults(obj);
358 configure(obj, _root, index);
359 return obj;
360 }
361
362 private static Class<?> nodeClass(XmlParser.Node node) throws ClassNotFoundException
363 {
364 String className = node.getAttribute("class");
365 if (className == null)
366 return null;
367
368 return Loader.loadClass(XmlConfiguration.class,className);
369 }
370
371
372
373
374
375
376
377
378
379
380 public void configure(Object obj, XmlParser.Node cfg, int i) throws Exception
381 {
382
383 for (; i < cfg.size(); i++)
384 {
385 Object o = cfg.get(i);
386 if (o instanceof String)
387 continue;
388 XmlParser.Node node = (XmlParser.Node)o;
389 if ("Arg".equals(node.getTag()))
390 {
391 LOG.warn("Ignored arg: "+node);
392 continue;
393 }
394 break;
395 }
396
397
398 for (; i < cfg.size(); i++)
399 {
400 Object o = cfg.get(i);
401 if (o instanceof String)
402 continue;
403 XmlParser.Node node = (XmlParser.Node)o;
404
405 try
406 {
407 String tag = node.getTag();
408 switch (tag)
409 {
410 case "Set":
411 set(obj, node);
412 break;
413 case "Put":
414 put(obj, node);
415 break;
416 case "Call":
417 call(obj, node);
418 break;
419 case "Get":
420 get(obj, node);
421 break;
422 case "New":
423 newObj(obj, node);
424 break;
425 case "Array":
426 newArray(obj, node);
427 break;
428 case "Map":
429 newMap(obj,node);
430 break;
431 case "Ref":
432 refObj(obj, node);
433 break;
434 case "Property":
435 propertyObj(node);
436 break;
437 case "SystemProperty":
438 systemPropertyObj(node);
439 break;
440 case "Env":
441 envObj(node);
442 break;
443 default:
444 throw new IllegalStateException("Unknown tag: " + tag + " in " + _url);
445 }
446 }
447 catch (Exception e)
448 {
449 LOG.warn("Config error at " + node,e.toString()+" in "+_url);
450 throw e;
451 }
452 }
453 }
454
455
456
457
458
459
460
461
462 private void set(Object obj, XmlParser.Node node) throws Exception
463 {
464 String attr = node.getAttribute("name");
465 String name = "set" + attr.substring(0,1).toUpperCase(Locale.ENGLISH) + attr.substring(1);
466 Object value = value(obj,node);
467 Object[] arg =
468 { value };
469
470 Class<?> oClass = nodeClass(node);
471 if (oClass != null)
472 obj = null;
473 else
474 oClass = obj.getClass();
475
476 Class<?>[] vClass =
477 { Object.class };
478 if (value != null)
479 vClass[0] = value.getClass();
480
481 if (LOG.isDebugEnabled())
482 LOG.debug("XML " + (obj != null?obj.toString():oClass.getName()) + "." + name + "(" + value + ")");
483
484
485 try
486 {
487 Method set = oClass.getMethod(name,vClass);
488 set.invoke(obj,arg);
489 return;
490 }
491 catch (IllegalArgumentException | IllegalAccessException | NoSuchMethodException e)
492 {
493 LOG.ignore(e);
494 }
495
496
497 try
498 {
499 Field type = vClass[0].getField("TYPE");
500 vClass[0] = (Class<?>)type.get(null);
501 Method set = oClass.getMethod(name,vClass);
502 set.invoke(obj,arg);
503 return;
504 }
505 catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException | NoSuchMethodException e)
506 {
507 LOG.ignore(e);
508 }
509
510
511 try
512 {
513 Field field = oClass.getField(attr);
514 if (Modifier.isPublic(field.getModifiers()))
515 {
516 field.set(obj,value);
517 return;
518 }
519 }
520 catch (NoSuchFieldException e)
521 {
522 LOG.ignore(e);
523 }
524
525
526 Method[] sets = oClass.getMethods();
527 Method set = null;
528 for (int s = 0; sets != null && s < sets.length; s++)
529 {
530 Class<?>[] paramTypes = sets[s].getParameterTypes();
531 if (name.equals(sets[s].getName()) && paramTypes.length == 1)
532 {
533
534 try
535 {
536 set = sets[s];
537 sets[s].invoke(obj,arg);
538 return;
539 }
540 catch (IllegalArgumentException | IllegalAccessException e)
541 {
542 LOG.ignore(e);
543 }
544
545 try
546 {
547 for (Class<?> c : __supportedCollections)
548 if (paramTypes[0].isAssignableFrom(c))
549 {
550 sets[s].invoke(obj,convertArrayToCollection(value,c));
551 return;
552 }
553 }
554 catch (IllegalAccessException e)
555 {
556 LOG.ignore(e);
557 }
558 }
559 }
560
561
562 if (set != null)
563 {
564 try
565 {
566 Class<?> sClass = set.getParameterTypes()[0];
567 if (sClass.isPrimitive())
568 {
569 for (int t = 0; t < __primitives.length; t++)
570 {
571 if (sClass.equals(__primitives[t]))
572 {
573 sClass = __boxedPrimitives[t];
574 break;
575 }
576 }
577 }
578 Constructor<?> cons = sClass.getConstructor(vClass);
579 arg[0] = cons.newInstance(arg);
580 _configuration.initializeDefaults(arg[0]);
581 set.invoke(obj,arg);
582 return;
583 }
584 catch (NoSuchMethodException | IllegalAccessException | InstantiationException e)
585 {
586 LOG.ignore(e);
587 }
588 }
589
590
591 throw new NoSuchMethodException(oClass + "." + name + "(" + vClass[0] + ")");
592 }
593
594
595
596
597
598
599 private static Collection<?> convertArrayToCollection(Object array, Class<?> collectionType)
600 {
601 Collection<?> collection = null;
602 if (array.getClass().isArray())
603 {
604 if (collectionType.isAssignableFrom(ArrayList.class))
605 collection = convertArrayToArrayList(array);
606 else if (collectionType.isAssignableFrom(HashSet.class))
607 collection = new HashSet<>(convertArrayToArrayList(array));
608 else if (collectionType.isAssignableFrom(ArrayQueue.class))
609 {
610 ArrayQueue<Object> q= new ArrayQueue<>();
611 q.addAll(convertArrayToArrayList(array));
612 collection=q;
613 }
614 }
615 if (collection==null)
616 throw new IllegalArgumentException("Can't convert \"" + array.getClass() + "\" to " + collectionType);
617 return collection;
618 }
619
620 private static ArrayList<Object> convertArrayToArrayList(Object array)
621 {
622 int length = Array.getLength(array);
623 ArrayList<Object> list = new ArrayList<>(length);
624 for (int i = 0; i < length; i++)
625 list.add(Array.get(array,i));
626 return list;
627 }
628
629
630
631
632
633
634 private void put(Object obj, XmlParser.Node node) throws Exception
635 {
636 if (!(obj instanceof Map))
637 throw new IllegalArgumentException("Object for put is not a Map: " + obj);
638 @SuppressWarnings("unchecked")
639 Map<Object, Object> map = (Map<Object, Object>)obj;
640
641 String name = node.getAttribute("name");
642 Object value = value(obj, node);
643 map.put(name,value);
644 if (LOG.isDebugEnabled())
645 LOG.debug("XML " + obj + ".put(" + name + "," + value + ")");
646 }
647
648
649
650
651
652
653 private Object get(Object obj, XmlParser.Node node) throws Exception
654 {
655 Class<?> oClass = nodeClass(node);
656 if (oClass != null)
657 obj = null;
658 else
659 oClass = obj.getClass();
660
661 String name = node.getAttribute("name");
662 String id = node.getAttribute("id");
663 if (LOG.isDebugEnabled())
664 LOG.debug("XML get " + name);
665
666 try
667 {
668
669 Method method = oClass.getMethod("get" + name.substring(0,1).toUpperCase(Locale.ENGLISH) + name.substring(1),(java.lang.Class[])null);
670 obj = method.invoke(obj,(java.lang.Object[])null);
671 if (id!=null)
672 _configuration.getIdMap().put(id,obj);
673 configure(obj,node,0);
674 }
675 catch (NoSuchMethodException nsme)
676 {
677 try
678 {
679 Field field = oClass.getField(name);
680 obj = field.get(obj);
681 configure(obj,node,0);
682 }
683 catch (NoSuchFieldException nsfe)
684 {
685 throw nsme;
686 }
687 }
688 return obj;
689 }
690
691
692
693
694
695
696
697
698 private Object call(Object obj, XmlParser.Node node) throws Exception
699 {
700 AttrOrElementNode aoeNode=new AttrOrElementNode(obj,node,"Id","Name","Class","Arg");
701 String id = aoeNode.getString("Id");
702 String name = aoeNode.getString("Name");
703 String clazz = aoeNode.getString("Class");
704 List<Object> args = aoeNode.getList("Arg");
705
706
707 Class<?> oClass;
708 if (clazz!=null)
709 {
710
711 oClass=Loader.loadClass(XmlConfiguration.class,clazz);
712 obj=null;
713 }
714 else if (obj!=null)
715 {
716 oClass = obj.getClass();
717 }
718 else
719 throw new IllegalArgumentException(node.toString());
720
721 if (LOG.isDebugEnabled())
722 LOG.debug("XML call " + name);
723
724 try
725 {
726 Object nobj= TypeUtil.call(oClass,name,obj,args.toArray(new Object[args.size()]));
727 if (id != null)
728 _configuration.getIdMap().put(id,nobj);
729 configure(nobj,node,aoeNode.getNext());
730 return nobj;
731 }
732 catch (NoSuchMethodException e)
733 {
734 IllegalStateException ise = new IllegalStateException("No Method: " + node + " on " + oClass);
735 ise.initCause(e);
736 throw ise;
737 }
738 }
739
740
741
742
743
744
745
746
747
748 private Object newObj(Object obj, XmlParser.Node node) throws Exception
749 {
750 AttrOrElementNode aoeNode=new AttrOrElementNode(obj,node,"Id","Class","Arg");
751 String id = aoeNode.getString("Id");
752 String clazz = aoeNode.getString("Class");
753 List<XmlParser.Node> argNodes = aoeNode.getNodes("Arg");
754
755 if (LOG.isDebugEnabled())
756 LOG.debug("XML new " + clazz);
757
758 Class<?> oClass = Loader.loadClass(XmlConfiguration.class,clazz);
759
760
761 Map<String, Object> namedArgMap = new HashMap<>();
762 List<Object> arguments = new LinkedList<>();
763 for (XmlParser.Node child : argNodes)
764 {
765 String namedAttribute = child.getAttribute("name");
766 Object value=value(obj,child);
767 if (namedAttribute != null)
768 {
769
770 namedArgMap.put(namedAttribute,value);
771 }
772
773 arguments.add(value);
774 }
775
776 Object nobj;
777 try
778 {
779 if (namedArgMap.size() > 0)
780 {
781 LOG.debug("using named mapping");
782 nobj = TypeUtil.construct(oClass, arguments.toArray(), namedArgMap);
783 }
784 else
785 {
786 LOG.debug("using normal mapping");
787 nobj = TypeUtil.construct(oClass, arguments.toArray());
788 }
789 }
790 catch (NoSuchMethodException e)
791 {
792 throw new IllegalStateException("No suitable constructor: " + node + " on " + obj);
793 }
794
795 if (id != null)
796 _configuration.getIdMap().put(id, nobj);
797
798 _configuration.initializeDefaults(nobj);
799 configure(nobj,node,aoeNode.getNext());
800 return nobj;
801 }
802
803
804
805
806
807
808 private Object refObj(Object obj, XmlParser.Node node) throws Exception
809 {
810 String refid = node.getAttribute("refid");
811 if (refid==null)
812 refid = node.getAttribute("id");
813 obj = _configuration.getIdMap().get(refid);
814 if (obj == null && node.size()>0)
815 throw new IllegalStateException("No object for refid=" + refid);
816 configure(obj,node,0);
817 return obj;
818 }
819
820
821
822
823 private Object newArray(Object obj, XmlParser.Node node) throws Exception
824 {
825 AttrOrElementNode aoeNode=new AttrOrElementNode(obj,node,"Id","Type","Item");
826 String id = aoeNode.getString("Id");
827 String type = aoeNode.getString("Type");
828 List<XmlParser.Node> items = aoeNode.getNodes("Item");
829
830
831 Class<?> aClass = java.lang.Object.class;
832 if (type != null)
833 {
834 aClass = TypeUtil.fromName(type);
835 if (aClass == null)
836 {
837 switch (type)
838 {
839 case "String":
840 aClass = String.class;
841 break;
842 case "URL":
843 aClass = URL.class;
844 break;
845 case "InetAddress":
846 aClass = InetAddress.class;
847 break;
848 default:
849 aClass = Loader.loadClass(XmlConfiguration.class, type);
850 break;
851 }
852 }
853 }
854
855 Object al = null;
856
857 for (XmlParser.Node item : items)
858 {
859 String nid = item.getAttribute("id");
860 Object v = value(obj,item);
861 al = LazyList.add(al,(v == null && aClass.isPrimitive())?0:v);
862 if (nid != null)
863 _configuration.getIdMap().put(nid,v);
864 }
865
866 Object array = LazyList.toArray(al,aClass);
867 if (id != null)
868 _configuration.getIdMap().put(id,array);
869 return array;
870 }
871
872
873
874
875 private Object newMap(Object obj, XmlParser.Node node) throws Exception
876 {
877 AttrOrElementNode aoeNode=new AttrOrElementNode(node,"Id","Entry");
878 String id = aoeNode.getString("Id");
879 List<XmlParser.Node> entries = aoeNode.getNodes("Entry");
880
881 Map<Object, Object> map = new HashMap<>();
882 if (id != null)
883 _configuration.getIdMap().put(id, map);
884
885 for (XmlParser.Node entry : entries)
886 {
887 if (!entry.getTag().equals("Entry"))
888 throw new IllegalStateException("Not an Entry");
889
890 XmlParser.Node key = null;
891 XmlParser.Node value = null;
892
893 for (Object object : entry)
894 {
895 if (object instanceof String)
896 continue;
897 XmlParser.Node item = (XmlParser.Node)object;
898 if (!item.getTag().equals("Item"))
899 throw new IllegalStateException("Not an Item");
900 if (key == null)
901 key = item;
902 else
903 value = item;
904 }
905
906 if (key == null || value == null)
907 throw new IllegalStateException("Missing Item in Entry");
908 String kid = key.getAttribute("id");
909 String vid = value.getAttribute("id");
910
911 Object k = value(obj,key);
912 Object v = value(obj,value);
913 map.put(k,v);
914
915 if (kid != null)
916 _configuration.getIdMap().put(kid,k);
917 if (vid != null)
918 _configuration.getIdMap().put(vid,v);
919 }
920
921 return map;
922 }
923
924
925
926
927
928
929
930
931 private Object propertyObj(XmlParser.Node node) throws Exception
932 {
933 AttrOrElementNode aoeNode=new AttrOrElementNode(node,"Id","Name","Deprecated","Default");
934 String id = aoeNode.getString("Id");
935 String name = aoeNode.getString("Name",true);
936 List<Object> deprecated = aoeNode.getList("Deprecated");
937 String dftValue = aoeNode.getString("Default");
938
939
940 Map<String,String> properties = _configuration.getProperties();
941 String value = properties.get(name);
942
943
944
945 String alternate=null;
946 if (!deprecated.isEmpty())
947 {
948 for (Object d : deprecated)
949 {
950 String v = properties.get(StringUtil.valueOf(d));
951 if (v!=null)
952 {
953 if (value==null)
954 LOG.warn("Property '{}' is deprecated, use '{}' instead", d, name);
955 else
956 LOG.warn("Property '{}' is deprecated, value from '{}' used", d, name);
957 }
958 if (alternate==null)
959 alternate=v;;
960 }
961 }
962
963
964 if (value==null)
965 value=alternate;
966
967
968 if (value==null)
969 value=dftValue;
970
971
972 if (id != null)
973 _configuration.getIdMap().put(id, value);
974 return value;
975 }
976
977
978
979
980
981
982
983
984 private Object systemPropertyObj(XmlParser.Node node) throws Exception
985 {
986 AttrOrElementNode aoeNode=new AttrOrElementNode(node,"Id","Name","Deprecated","Default");
987 String id = aoeNode.getString("Id");
988 String name = aoeNode.getString("Name",true);
989 List<Object> deprecated = aoeNode.getList("Deprecated");
990 String dftValue = aoeNode.getString("Default");
991
992
993 String value = System.getProperty(name);
994
995
996 String alternate=null;
997 if (!deprecated.isEmpty())
998 {
999 for (Object d : deprecated)
1000 {
1001 String v = System.getProperty(StringUtil.valueOf(d));
1002 if (v!=null)
1003 {
1004 if (value==null)
1005 LOG.warn("SystemProperty '{}' is deprecated, use '{}' instead", d, name);
1006 else
1007 LOG.warn("SystemProperty '{}' is deprecated, value from '{}' used", d, name);
1008 }
1009 if (alternate==null)
1010 alternate=v;;
1011 }
1012 }
1013
1014
1015 if (value==null)
1016 value=alternate;
1017
1018
1019 if (value==null)
1020 value=dftValue;
1021
1022
1023 if (id != null)
1024 _configuration.getIdMap().put(id, value);
1025
1026 return value;
1027 }
1028
1029
1030
1031
1032
1033
1034
1035
1036 private Object envObj(XmlParser.Node node) throws Exception
1037 {
1038 AttrOrElementNode aoeNode=new AttrOrElementNode(node,"Id","Name","Deprecated","Default");
1039 String id = aoeNode.getString("Id");
1040 String name = aoeNode.getString("Name",true);
1041 List<Object> deprecated = aoeNode.getList("Deprecated");
1042 String dftValue = aoeNode.getString("Default");
1043
1044
1045 String value = System.getenv(name);
1046
1047
1048 if (value==null && !deprecated.isEmpty())
1049 {
1050 for (Object d : deprecated)
1051 {
1052 value = System.getenv(StringUtil.valueOf(d));
1053 if (value!=null)
1054 {
1055 LOG.warn("Property '{}' is deprecated, use '{}' instead", d, name);
1056 break;
1057 }
1058 }
1059 }
1060
1061
1062 if (value==null)
1063 value=dftValue;
1064
1065
1066 if (id != null)
1067 _configuration.getIdMap().put(id, value);
1068
1069 return value;
1070 }
1071
1072
1073
1074
1075
1076 private Object value(Object obj, XmlParser.Node node) throws Exception
1077 {
1078 Object value;
1079
1080
1081 String type = node.getAttribute("type");
1082
1083
1084 String ref = node.getAttribute("ref");
1085 if (ref != null)
1086 {
1087 value = _configuration.getIdMap().get(ref);
1088 }
1089 else
1090 {
1091
1092 if (node.size() == 0)
1093 {
1094 if ("String".equals(type))
1095 return "";
1096 return null;
1097 }
1098
1099
1100 int first = 0;
1101 int last = node.size() - 1;
1102
1103
1104 if (type == null || !"String".equals(type))
1105 {
1106
1107 Object item;
1108 while (first <= last)
1109 {
1110 item = node.get(first);
1111 if (!(item instanceof String))
1112 break;
1113 item = ((String)item).trim();
1114 if (((String)item).length() > 0)
1115 break;
1116 first++;
1117 }
1118
1119
1120 while (first < last)
1121 {
1122 item = node.get(last);
1123 if (!(item instanceof String))
1124 break;
1125 item = ((String)item).trim();
1126 if (((String)item).length() > 0)
1127 break;
1128 last--;
1129 }
1130
1131
1132 if (first > last)
1133 return null;
1134 }
1135
1136 if (first == last)
1137
1138 value = itemValue(obj,node.get(first));
1139 else
1140 {
1141
1142 StringBuilder buf = new StringBuilder();
1143 for (int i = first; i <= last; i++)
1144 {
1145 Object item = node.get(i);
1146 buf.append(itemValue(obj,item));
1147 }
1148 value = buf.toString();
1149 }
1150 }
1151
1152
1153 if (value == null)
1154 {
1155 if ("String".equals(type))
1156 return "";
1157 return null;
1158 }
1159
1160
1161 if (type == null)
1162 {
1163 if (value instanceof String)
1164 return ((String)value).trim();
1165 return value;
1166 }
1167
1168 if (isTypeMatchingClass(type,String.class))
1169 return value.toString();
1170
1171 Class<?> pClass = TypeUtil.fromName(type);
1172 if (pClass != null)
1173 return TypeUtil.valueOf(pClass,value.toString());
1174
1175 if (isTypeMatchingClass(type,URL.class))
1176 {
1177 if (value instanceof URL)
1178 return value;
1179 try
1180 {
1181 return new URL(value.toString());
1182 }
1183 catch (MalformedURLException e)
1184 {
1185 throw new InvocationTargetException(e);
1186 }
1187 }
1188
1189 if (isTypeMatchingClass(type,InetAddress.class))
1190 {
1191 if (value instanceof InetAddress)
1192 return value;
1193 try
1194 {
1195 return InetAddress.getByName(value.toString());
1196 }
1197 catch (UnknownHostException e)
1198 {
1199 throw new InvocationTargetException(e);
1200 }
1201 }
1202
1203 for (Class<?> collectionClass : __supportedCollections)
1204 {
1205 if (isTypeMatchingClass(type,collectionClass))
1206 return convertArrayToCollection(value,collectionClass);
1207 }
1208
1209 throw new IllegalStateException("Unknown type " + type);
1210 }
1211
1212 private static boolean isTypeMatchingClass(String type, Class<?> classToMatch)
1213 {
1214 return classToMatch.getSimpleName().equalsIgnoreCase(type) || classToMatch.getName().equals(type);
1215 }
1216
1217
1218
1219
1220 private Object itemValue(Object obj, Object item) throws Exception
1221 {
1222
1223 if (item instanceof String)
1224 return item;
1225
1226 XmlParser.Node node = (XmlParser.Node)item;
1227 String tag = node.getTag();
1228 if ("Call".equals(tag))
1229 return call(obj,node);
1230 if ("Get".equals(tag))
1231 return get(obj,node);
1232 if ("New".equals(tag))
1233 return newObj(obj,node);
1234 if ("Ref".equals(tag))
1235 return refObj(obj,node);
1236 if ("Array".equals(tag))
1237 return newArray(obj,node);
1238 if ("Map".equals(tag))
1239 return newMap(obj,node);
1240 if ("Property".equals(tag))
1241 return propertyObj(node);
1242 if ("SystemProperty".equals(tag))
1243 return systemPropertyObj(node);
1244 if ("Env".equals(tag))
1245 return envObj(node);
1246
1247 LOG.warn("Unknown value tag: " + node,new Throwable());
1248 return null;
1249 }
1250
1251
1252 private class AttrOrElementNode
1253 {
1254 final Object _obj;
1255 final XmlParser.Node _node;
1256 final Set<String> _elements = new HashSet<>();
1257 final int _next;
1258
1259 AttrOrElementNode(XmlParser.Node node,String... elements )
1260 {
1261 this(null,node,elements);
1262 }
1263
1264 AttrOrElementNode(Object obj, XmlParser.Node node,String... elements )
1265 {
1266 _obj=obj;
1267 _node=node;
1268 for (String e:elements)
1269 _elements.add(e);
1270
1271 int next=0;
1272 for (Object o: _node)
1273 {
1274 if (o instanceof String)
1275 {
1276 if (((String)o).trim().length()==0)
1277 {
1278 next++;
1279 continue;
1280 }
1281 break;
1282 }
1283
1284 if (!(o instanceof XmlParser.Node))
1285 break;
1286
1287 XmlParser.Node n = (XmlParser.Node)o;
1288 if (!_elements.contains(n.getTag()))
1289 break;
1290
1291 next++;
1292 }
1293 _next=next;
1294 }
1295
1296 public int getNext()
1297 {
1298 return _next;
1299 }
1300
1301 public String getString(String elementName) throws Exception
1302 {
1303 return StringUtil.valueOf(get(elementName,false));
1304 }
1305
1306 public String getString(String elementName, boolean manditory) throws Exception
1307 {
1308 return StringUtil.valueOf(get(elementName,manditory));
1309 }
1310
1311 public Object get(String elementName, boolean manditory) throws Exception
1312 {
1313 String attrName=StringUtil.asciiToLowerCase(elementName);
1314 String attr = _node.getAttribute(attrName);
1315 Object value=attr;
1316
1317 for (int i=0;i<_next;i++)
1318 {
1319 Object o = _node.get(i);
1320 if (!(o instanceof XmlParser.Node))
1321 continue;
1322 XmlParser.Node n = (XmlParser.Node)o;
1323 if (elementName.equals(n.getTag()))
1324 {
1325 if (attr!=null)
1326 throw new IllegalStateException("Cannot have attr '"+attrName+"' and element '"+elementName+"'");
1327
1328 value=value(_obj,n);
1329 break;
1330 }
1331 }
1332
1333 if (manditory && value==null)
1334 throw new IllegalStateException("Must have attr '"+attrName+"' or element '"+elementName+"'");
1335
1336 return value;
1337 }
1338
1339 public List<Object> getList(String elementName) throws Exception
1340 {
1341 return getList(elementName,false);
1342 }
1343
1344 public List<Object> getList(String elementName, boolean manditory) throws Exception
1345 {
1346 String attrName=StringUtil.asciiToLowerCase(elementName);
1347 final List<Object> values=new ArrayList<>();
1348
1349 String attr = _node.getAttribute(attrName);
1350 if (attr!=null)
1351 values.addAll(StringUtil.csvSplit(null,attr,0,attr.length()));
1352
1353
1354 for (int i=0;i<_next;i++)
1355 {
1356 Object o = _node.get(i);
1357 if (!(o instanceof XmlParser.Node))
1358 continue;
1359 XmlParser.Node n = (XmlParser.Node)o;
1360
1361 if (elementName.equals(n.getTag()))
1362 {
1363 if (attr!=null)
1364 throw new IllegalStateException("Cannot have attr '"+attrName+"' and element '"+elementName+"'");
1365
1366 values.add(value(_obj,n));
1367 }
1368 }
1369
1370 if (manditory && values.isEmpty())
1371 throw new IllegalStateException("Must have attr '"+attrName+"' or element '"+elementName+"'");
1372
1373 return values;
1374 }
1375
1376 public List<XmlParser.Node> getNodes(String elementName) throws Exception
1377 {
1378 String attrName=StringUtil.asciiToLowerCase(elementName);
1379 final List<XmlParser.Node> values=new ArrayList<>();
1380
1381 String attr = _node.getAttribute(attrName);
1382 if (attr!=null)
1383 {
1384 for (String a : StringUtil.csvSplit(null,attr,0,attr.length()))
1385 {
1386
1387 XmlParser.Node n = new XmlParser.Node(null,elementName,null);
1388 n.add(a);
1389 values.add(n);
1390 }
1391 }
1392
1393 for (int i=0;i<_next;i++)
1394 {
1395 Object o = _node.get(i);
1396 if (!(o instanceof XmlParser.Node))
1397 continue;
1398 XmlParser.Node n = (XmlParser.Node)o;
1399
1400 if (elementName.equals(n.getTag()))
1401 {
1402 if (attr!=null)
1403 throw new IllegalStateException("Cannot have attr '"+attrName+"' and element '"+elementName+"'");
1404
1405 values.add(n);
1406 }
1407 }
1408
1409 return values;
1410 }
1411 }
1412 }
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431 public static void main(final String... args) throws Exception
1432 {
1433 final AtomicReference<Throwable> exception = new AtomicReference<>();
1434
1435 AccessController.doPrivileged(new PrivilegedAction<Object>()
1436 {
1437 public Object run()
1438 {
1439 try
1440 {
1441 Properties properties = null;
1442
1443
1444 try
1445 {
1446 Class<?> config = XmlConfiguration.class.getClassLoader().loadClass("org.eclipse.jetty.start.Config");
1447 properties = (Properties)config.getMethod("getProperties").invoke(null);
1448 LOG.debug("org.eclipse.jetty.start.Config properties = {}",properties);
1449 }
1450 catch (NoClassDefFoundError | ClassNotFoundException e)
1451 {
1452 LOG.ignore(e);
1453 }
1454 catch (Exception e)
1455 {
1456 LOG.warn(e);
1457 }
1458
1459
1460 if (properties == null)
1461 {
1462
1463 properties = new Properties();
1464 properties.putAll(System.getProperties());
1465 }
1466
1467
1468 for (String arg : args)
1469 {
1470 if (arg.indexOf('=')>=0)
1471 {
1472 int i=arg.indexOf('=');
1473 properties.put(arg.substring(0,i),arg.substring(i+1));
1474 }
1475 else if (arg.toLowerCase(Locale.ENGLISH).endsWith(".properties"))
1476 properties.load(Resource.newResource(arg).getInputStream());
1477 }
1478
1479
1480 XmlConfiguration last = null;
1481 Object[] obj = new Object[args.length];
1482 for (int i = 0; i < args.length; i++)
1483 {
1484 if (!args[i].toLowerCase(Locale.ENGLISH).endsWith(".properties") && (args[i].indexOf('=')<0))
1485 {
1486 XmlConfiguration configuration = new XmlConfiguration(Resource.newResource(args[i]).getURI().toURL());
1487 if (last != null)
1488 configuration.getIdMap().putAll(last.getIdMap());
1489 if (properties.size() > 0)
1490 {
1491 Map<String, String> props = new HashMap<>();
1492 for (Object key : properties.keySet())
1493 {
1494 props.put(key.toString(),String.valueOf(properties.get(key)));
1495 }
1496 configuration.getProperties().putAll(props);
1497 }
1498 obj[i] = configuration.configure();
1499 last = configuration;
1500 }
1501 }
1502
1503
1504 for (int i = 0; i < args.length; i++)
1505 {
1506 if (obj[i] instanceof LifeCycle)
1507 {
1508 LifeCycle lc = (LifeCycle)obj[i];
1509 if (!lc.isRunning())
1510 lc.start();
1511 }
1512 }
1513 }
1514 catch (Exception e)
1515 {
1516 LOG.debug(Log.EXCEPTION,e);
1517 exception.set(e);
1518 }
1519 return null;
1520 }
1521 });
1522
1523 Throwable th = exception.get();
1524 if (th != null)
1525 {
1526 if (th instanceof RuntimeException)
1527 throw (RuntimeException)th;
1528 else if (th instanceof Exception)
1529 throw (Exception)th;
1530 else if (th instanceof Error)
1531 throw (Error)th;
1532 throw new Error(th);
1533 }
1534 }
1535 }