1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.eclipse.jetty.xml;
15
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.io.StringReader;
19 import java.lang.reflect.Constructor;
20 import java.lang.reflect.Field;
21 import java.lang.reflect.InvocationTargetException;
22 import java.lang.reflect.Method;
23 import java.lang.reflect.Modifier;
24 import java.net.InetAddress;
25 import java.net.MalformedURLException;
26 import java.net.URL;
27 import java.net.UnknownHostException;
28 import java.security.AccessController;
29 import java.security.PrivilegedAction;
30 import java.util.HashMap;
31 import java.util.Iterator;
32 import java.util.Map;
33 import java.util.Properties;
34
35 import org.eclipse.jetty.util.LazyList;
36 import org.eclipse.jetty.util.Loader;
37 import org.eclipse.jetty.util.TypeUtil;
38 import org.eclipse.jetty.util.component.LifeCycle;
39 import org.eclipse.jetty.util.log.Log;
40 import org.eclipse.jetty.util.resource.Resource;
41 import org.xml.sax.InputSource;
42 import org.xml.sax.SAXException;
43
44
45
46
47
48
49
50
51 public class XmlConfiguration
52 {
53
54 private static Class[] __primitives = { Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE,
55 Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE, Void.TYPE};
56
57 private static Class[] __primitiveHolders = { Boolean.class, Character.class, Byte.class,
58 Short.class, Integer.class, Long.class, Float.class, Double.class, Void.class};
59 private static final Integer ZERO=new Integer(0);
60
61
62 private static XmlParser __parser;
63 private XmlParser.Node _config;
64 private Map _idMap = new HashMap();
65 private Map _propertyMap = new HashMap();
66
67
68 private synchronized static void initParser() throws IOException
69 {
70 if (__parser != null) return;
71
72 __parser = new XmlParser();
73 try
74 {
75 URL configURL = Loader.getResource(XmlConfiguration.class, "org/eclipse/jetty/xml/configure_6_0.dtd", true);
76 __parser.redirectEntity("configure.dtd", configURL);
77 __parser.redirectEntity("configure_1_0.dtd", configURL);
78 __parser.redirectEntity("configure_1_1.dtd", configURL);
79 __parser.redirectEntity("configure_1_2.dtd", configURL);
80 __parser.redirectEntity("configure_1_3.dtd", configURL);
81 __parser.redirectEntity("configure_6_0.dtd", configURL);
82
83 __parser.redirectEntity("http://jetty.mortbay.org/configure.dtd", configURL);
84 __parser.redirectEntity("http://jetty.eclipse.org/configure.dtd", configURL);
85 __parser.redirectEntity("http://www.eclipse.org/jetty/configure.dtd", configURL);
86
87 __parser.redirectEntity("-//Mort Bay Consulting//DTD Configure//EN", configURL);
88 __parser.redirectEntity("-//Jetty//Configure//EN", configURL);
89 }
90 catch (ClassNotFoundException e)
91 {
92 Log.warn(e.toString());
93 Log.debug(e);
94 }
95 }
96
97
98
99
100
101
102
103 public XmlConfiguration(URL configuration) throws SAXException, IOException
104 {
105 initParser();
106 synchronized (__parser)
107 {
108 _config = __parser.parse(configuration.toString());
109 }
110 }
111
112
113
114
115
116
117
118
119
120
121 public XmlConfiguration(String configuration) throws SAXException, IOException
122 {
123 initParser();
124 configuration = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<!DOCTYPE Configure PUBLIC \"-//Mort Bay Consulting//DTD Configure 1.2//EN\" \"http://jetty.eclipse.org/configure_1_2.dtd\">"
125 + configuration;
126 InputSource source = new InputSource(new StringReader(configuration));
127 synchronized (__parser)
128 {
129 _config = __parser.parse(source);
130 }
131 }
132
133
134
135
136
137
138
139
140
141 public XmlConfiguration(InputStream configuration) throws SAXException, IOException
142 {
143 initParser();
144 InputSource source = new InputSource(configuration);
145 synchronized (__parser)
146 {
147 _config = __parser.parse(source);
148 }
149 }
150
151
152 public Map getIdMap()
153 {
154 return _idMap;
155 }
156
157
158 public void setIdMap(Map map)
159 {
160 _idMap=map;
161 }
162
163
164 public void setProperties (Map map)
165 {
166 _propertyMap = map;
167 }
168
169
170 public Map getProperties ()
171 {
172 return _propertyMap;
173 }
174
175
176
177
178
179
180
181
182
183 public void configure(Object obj) throws Exception
184 {
185
186 Class oClass = nodeClass(_config);
187 if (!oClass.isInstance(obj))
188 throw new IllegalArgumentException("Object is not of type " + oClass);
189 configure(obj, _config, 0);
190 }
191
192
193
194
195
196
197
198
199
200 public Object configure() throws Exception
201 {
202 Class oClass = nodeClass(_config);
203
204 String id = _config.getAttribute("id");
205 Object obj = id==null?null:_idMap.get(id);
206
207 if (obj==null && oClass !=null)
208 obj = oClass.newInstance();
209
210 if (oClass!=null && !oClass.isInstance(obj))
211 throw new ClassCastException(oClass.toString());
212
213 configure(obj, _config, 0);
214 return obj;
215 }
216
217
218 private Class nodeClass(XmlParser.Node node) throws ClassNotFoundException
219 {
220 String className = node.getAttribute("class");
221 if (className == null) return null;
222
223 return Loader.loadClass(XmlConfiguration.class, className,true);
224 }
225
226
227
228
229
230
231 private void configure(Object obj, XmlParser.Node cfg, int i) throws Exception
232 {
233 String id = cfg.getAttribute("id");
234 if (id!=null)
235 _idMap.put(id,obj);
236
237 for (; i < cfg.size(); i++)
238 {
239 Object o = cfg.get(i);
240 if (o instanceof String) continue;
241 XmlParser.Node node = (XmlParser.Node) o;
242
243 try
244 {
245 String tag = node.getTag();
246 if ("Set".equals(tag))
247 set(obj, node);
248 else if ("Put".equals(tag))
249 put(obj, node);
250 else if ("Call".equals(tag))
251 call(obj, node);
252 else if ("Get".equals(tag))
253 get(obj, node);
254 else if ("New".equals(tag))
255 newObj(obj, node);
256 else if ("Array".equals(tag))
257 newArray(obj, node);
258 else if ("Ref".equals(tag))
259 refObj(obj, node);
260 else if ("Property".equals(tag))
261 propertyObj(obj, node);
262 else
263 throw new IllegalStateException("Unknown tag: " + tag);
264 }
265 catch (Exception e)
266 {
267 Log.warn("Config error at " + node, e.toString());
268 throw e;
269 }
270 }
271 }
272
273
274
275
276
277
278
279
280
281 private void set(Object obj, XmlParser.Node node) throws Exception
282 {
283 String attr = node.getAttribute("name");
284 String name = "set" + attr.substring(0, 1).toUpperCase() + attr.substring(1);
285 Object value = value(obj, node);
286 Object[] arg = { value};
287
288 Class oClass = nodeClass(node);
289 if (oClass != null)
290 obj = null;
291 else
292 oClass = obj.getClass();
293
294 Class[] vClass = { Object.class};
295 if (value != null) vClass[0] = value.getClass();
296
297 if (Log.isDebugEnabled())
298 Log.debug("XML "+(obj!=null?obj.toString():oClass.getName()) + "." + name + "(" + value + ")");
299
300
301 try
302 {
303 Method set = oClass.getMethod(name, vClass);
304 set.invoke(obj, arg);
305 return;
306 }
307 catch (IllegalArgumentException e)
308 {
309 Log.ignore(e);
310 }
311 catch (IllegalAccessException e)
312 {
313 Log.ignore(e);
314 }
315 catch (NoSuchMethodException e)
316 {
317 Log.ignore(e);
318 }
319
320
321 try
322 {
323 Field type = vClass[0].getField("TYPE");
324 vClass[0] = (Class) type.get(null);
325 Method set = oClass.getMethod(name, vClass);
326 set.invoke(obj, arg);
327 return;
328 }
329 catch (NoSuchFieldException e)
330 {
331 Log.ignore(e);
332 }
333 catch (IllegalArgumentException e)
334 {
335 Log.ignore(e);
336 }
337 catch (IllegalAccessException e)
338 {
339 Log.ignore(e);
340 }
341 catch (NoSuchMethodException e)
342 {
343 Log.ignore(e);
344 }
345
346
347 try
348 {
349 Field field = oClass.getField(attr);
350 if (Modifier.isPublic(field.getModifiers()))
351 {
352 field.set(obj, value);
353 return;
354 }
355 }
356 catch (NoSuchFieldException e)
357 {
358 Log.ignore(e);
359 }
360
361
362 Method[] sets = oClass.getMethods();
363 Method set = null;
364 for (int s = 0; sets != null && s < sets.length; s++)
365 {
366 if (name.equals(sets[s].getName()) && sets[s].getParameterTypes().length == 1)
367 {
368
369 try
370 {
371 set = sets[s];
372 sets[s].invoke(obj, arg);
373 return;
374 }
375 catch (IllegalArgumentException e)
376 {
377 Log.ignore(e);
378 }
379 catch (IllegalAccessException e)
380 {
381 Log.ignore(e);
382 }
383 }
384 }
385
386
387 if (set != null)
388 {
389 try
390 {
391 Class sClass = set.getParameterTypes()[0];
392 if (sClass.isPrimitive())
393 {
394 for (int t = 0; t < __primitives.length; t++)
395 {
396 if (sClass.equals(__primitives[t]))
397 {
398 sClass = __primitiveHolders[t];
399 break;
400 }
401 }
402 }
403 Constructor cons = sClass.getConstructor(vClass);
404 arg[0] = cons.newInstance(arg);
405 set.invoke(obj, arg);
406 return;
407 }
408 catch (NoSuchMethodException e)
409 {
410 Log.ignore(e);
411 }
412 catch (IllegalAccessException e)
413 {
414 Log.ignore(e);
415 }
416 catch (InstantiationException e)
417 {
418 Log.ignore(e);
419 }
420 }
421
422
423 throw new NoSuchMethodException(oClass + "." + name + "(" + vClass[0] + ")");
424 }
425
426
427
428
429
430
431
432 private void put(Object obj, XmlParser.Node node) throws Exception
433 {
434 if (!(obj instanceof Map))
435 throw new IllegalArgumentException("Object for put is not a Map: " + obj);
436 Map map = (Map) obj;
437
438 String name = node.getAttribute("name");
439 Object value = value(obj, node);
440 map.put(name, value);
441 if (Log.isDebugEnabled()) Log.debug("XML "+obj + ".put(" + name + "," + value + ")");
442 }
443
444
445
446
447
448
449 private Object get(Object obj, XmlParser.Node node) throws Exception
450 {
451 Class oClass = nodeClass(node);
452 if (oClass != null)
453 obj = null;
454 else
455 oClass = obj.getClass();
456
457 String name = node.getAttribute("name");
458 String id = node.getAttribute("id");
459 if (Log.isDebugEnabled()) Log.debug("XML get " + name);
460
461 try
462 {
463
464 Method method = oClass.getMethod("get" + name.substring(0, 1).toUpperCase()
465 + name.substring(1), (java.lang.Class[]) null);
466 obj = method.invoke(obj, (java.lang.Object[]) null);
467 configure(obj, node, 0);
468 }
469 catch (NoSuchMethodException nsme)
470 {
471 try
472 {
473 Field field = oClass.getField(name);
474 obj = field.get(obj);
475 configure(obj, node, 0);
476 }
477 catch (NoSuchFieldException nsfe)
478 {
479 throw nsme;
480 }
481 }
482 if (id != null) _idMap.put(id, obj);
483 return obj;
484 }
485
486
487
488
489
490
491
492
493
494 private Object call(Object obj, XmlParser.Node node) throws Exception
495 {
496 String id = node.getAttribute("id");
497 Class oClass = nodeClass(node);
498 if (oClass != null)
499 obj = null;
500 else if (obj != null) oClass = obj.getClass();
501 if (oClass == null) throw new IllegalArgumentException(node.toString());
502
503 int size = 0;
504 int argi = node.size();
505 for (int i = 0; i < node.size(); i++)
506 {
507 Object o = node.get(i);
508 if (o instanceof String) continue;
509 if (!((XmlParser.Node) o).getTag().equals("Arg"))
510 {
511 argi = i;
512 break;
513 }
514 size++;
515 }
516
517 Object[] arg = new Object[size];
518 for (int i = 0, j = 0; j < size; i++)
519 {
520 Object o = node.get(i);
521 if (o instanceof String) continue;
522 arg[j++] = value(obj, (XmlParser.Node) o);
523 }
524
525 String method = node.getAttribute("name");
526 if (Log.isDebugEnabled()) Log.debug("XML call " + method);
527
528
529 Method[] methods = oClass.getMethods();
530 for (int c = 0; methods != null && c < methods.length; c++)
531 {
532 if (!methods[c].getName().equals(method)) continue;
533 if (methods[c].getParameterTypes().length != size) continue;
534 if (Modifier.isStatic(methods[c].getModifiers()) != (obj == null)) continue;
535 if ((obj == null) && methods[c].getDeclaringClass() != oClass) continue;
536
537 Object n = null;
538 boolean called = false;
539 try
540 {
541 n = methods[c].invoke(obj, arg);
542 called = true;
543 }
544 catch (IllegalAccessException e)
545 {
546 Log.ignore(e);
547 }
548 catch (IllegalArgumentException e)
549 {
550 Log.ignore(e);
551 }
552 if (called)
553 {
554 if (id != null) _idMap.put(id, n);
555 configure(n, node, argi);
556 return n;
557 }
558 }
559
560 throw new IllegalStateException("No Method: " + node + " on " + oClass);
561 }
562
563
564
565
566
567
568
569 private Object newObj(Object obj, XmlParser.Node node) throws Exception
570 {
571 Class oClass = nodeClass(node);
572 String id = node.getAttribute("id");
573 int size = 0;
574 int argi = node.size();
575 for (int i = 0; i < node.size(); i++)
576 {
577 Object o = node.get(i);
578 if (o instanceof String) continue;
579 if (!((XmlParser.Node) o).getTag().equals("Arg"))
580 {
581 argi = i;
582 break;
583 }
584 size++;
585 }
586
587 Object[] arg = new Object[size];
588 for (int i = 0, j = 0; j < size; i++)
589 {
590 Object o = node.get(i);
591 if (o instanceof String) continue;
592 arg[j++] = value(obj, (XmlParser.Node) o);
593 }
594
595 if (Log.isDebugEnabled()) Log.debug("XML new " + oClass);
596
597
598 Constructor[] constructors = oClass.getConstructors();
599 for (int c = 0; constructors != null && c < constructors.length; c++)
600 {
601 if (constructors[c].getParameterTypes().length != size) continue;
602
603 Object n = null;
604 boolean called = false;
605 try
606 {
607 n = constructors[c].newInstance(arg);
608 called = true;
609 }
610 catch (IllegalAccessException e)
611 {
612 Log.ignore(e);
613 }
614 catch (InstantiationException e)
615 {
616 Log.ignore(e);
617 }
618 catch (IllegalArgumentException e)
619 {
620 Log.ignore(e);
621 }
622 if (called)
623 {
624 if (id != null) _idMap.put(id, n);
625 configure(n, node, argi);
626 return n;
627 }
628 }
629
630 throw new IllegalStateException("No Constructor: " + node + " on " + obj);
631 }
632
633
634
635
636
637
638
639
640 private Object refObj(Object obj, XmlParser.Node node) throws Exception
641 {
642 String id = node.getAttribute("id");
643 obj = _idMap.get(id);
644 if (obj == null) throw new IllegalStateException("No object for id=" + id);
645 configure(obj, node, 0);
646 return obj;
647 }
648
649
650
651
652
653
654
655 private Object newArray(Object obj, XmlParser.Node node) throws Exception
656 {
657
658
659 Class aClass = java.lang.Object.class;
660 String type = node.getAttribute("type");
661 final String id = node.getAttribute("id");
662 if (type != null)
663 {
664 aClass = TypeUtil.fromName(type);
665 if (aClass == null)
666 {
667 if ("String".equals(type))
668 aClass = java.lang.String.class;
669 else if ("URL".equals(type))
670 aClass = java.net.URL.class;
671 else if ("InetAddress".equals(type))
672 aClass = java.net.InetAddress.class;
673 else
674 aClass = Loader.loadClass(XmlConfiguration.class, type,true);
675 }
676 }
677
678 Object al=null;
679
680 Iterator iter = node.iterator("Item");
681 while(iter.hasNext())
682 {
683 XmlParser.Node item= (XmlParser.Node)iter.next();
684 String nid = item.getAttribute("id");
685 Object v = value(obj, item);
686 al=LazyList.add(al,(v==null&&aClass.isPrimitive())?ZERO:v);
687 if (nid != null)
688 _idMap.put(nid, v);
689 }
690
691 Object array = LazyList.toArray(al,aClass);
692 if (id != null)
693 _idMap.put(id, array);
694 return array;
695 }
696
697
698
699
700
701
702 private Object newMap(Object obj, XmlParser.Node node) throws Exception
703 {
704 String id = node.getAttribute("id");
705
706 Map map = new HashMap();
707 if (id != null) _idMap.put(id, map);
708
709 for (int i = 0; i < node.size(); i++)
710 {
711 Object o = node.get(i);
712 if (o instanceof String) continue;
713 XmlParser.Node entry = (XmlParser.Node) o;
714 if (!entry.getTag().equals("Entry")) throw new IllegalStateException("Not an Entry");
715
716
717 XmlParser.Node key=null;
718 XmlParser.Node value=null;
719
720 for (int j = 0; j < entry.size(); j++)
721 {
722 o = entry.get(j);
723 if (o instanceof String) continue;
724 XmlParser.Node item = (XmlParser.Node) o;
725 if (!item.getTag().equals("Item")) throw new IllegalStateException("Not an Item");
726 if (key==null)
727 key=item;
728 else
729 value=item;
730 }
731
732 if (key==null || value==null)
733 throw new IllegalStateException("Missing Item in Entry");
734 String kid = key.getAttribute("id");
735 String vid = value.getAttribute("id");
736
737 Object k = value(obj, key);
738 Object v = value(obj, value);
739 map.put(k,v);
740
741 if (kid != null) _idMap.put(kid, k);
742 if (vid != null) _idMap.put(vid, v);
743 }
744
745 return map;
746 }
747
748
749
750
751
752
753
754 private Object propertyObj(Object obj, XmlParser.Node node) throws Exception
755 {
756 String id = node.getAttribute("id");
757 String name = node.getAttribute("name");
758 Object defval = node.getAttribute("default");
759 Object prop=null;
760 if (_propertyMap!=null && _propertyMap.containsKey(name))
761 {
762 prop=_propertyMap.get(name);
763 }
764 else if (defval != null)
765 prop=defval;
766
767 if (id != null)
768 _idMap.put(id, prop);
769 if (prop!=null)
770 configure(prop, node, 0);
771 return prop;
772 }
773
774
775
776
777
778
779
780 private Object value(Object obj, XmlParser.Node node) throws Exception
781 {
782 Object value = null;
783
784
785 String type = node.getAttribute("type");
786
787
788 String ref = node.getAttribute("ref");
789 if (ref != null)
790 {
791 value = _idMap.get(ref);
792 }
793 else
794 {
795
796 if (node.size() == 0)
797 {
798 if ("String".equals(type)) return "";
799 return null;
800 }
801
802
803 int first = 0;
804 int last = node.size() - 1;
805
806
807 if (type == null || !"String".equals(type))
808 {
809
810 Object item = null;
811 while (first <= last)
812 {
813 item = node.get(first);
814 if (!(item instanceof String)) break;
815 item = ((String) item).trim();
816 if (((String) item).length() > 0) break;
817 first++;
818 }
819
820
821 while (first < last)
822 {
823 item = node.get(last);
824 if (!(item instanceof String)) break;
825 item = ((String) item).trim();
826 if (((String) item).length() > 0) break;
827 last--;
828 }
829
830
831 if (first > last) return null;
832 }
833
834 if (first == last)
835
836 value = itemValue(obj, node.get(first));
837 else
838 {
839
840 StringBuilder buf = new StringBuilder();
841 for (int i = first; i <= last; i++)
842 {
843 Object item = node.get(i);
844 buf.append(itemValue(obj, item));
845 }
846 value = buf.toString();
847 }
848 }
849
850
851 if (value == null)
852 {
853 if ("String".equals(type)) return "";
854 return null;
855 }
856
857
858 if (type == null)
859 {
860 if (value != null && value instanceof String) return ((String) value).trim();
861 return value;
862 }
863
864 if ("String".equals(type) || "java.lang.String".equals(type)) return value.toString();
865
866 Class pClass = TypeUtil.fromName(type);
867 if (pClass != null) return TypeUtil.valueOf(pClass, value.toString());
868
869 if ("URL".equals(type) || "java.net.URL".equals(type))
870 {
871 if (value instanceof URL) return value;
872 try
873 {
874 return new URL(value.toString());
875 }
876 catch (MalformedURLException e)
877 {
878 throw new InvocationTargetException(e);
879 }
880 }
881
882 if ("InetAddress".equals(type) || "java.net.InetAddress".equals(type))
883 {
884 if (value instanceof InetAddress) return value;
885 try
886 {
887 return InetAddress.getByName(value.toString());
888 }
889 catch (UnknownHostException e)
890 {
891 throw new InvocationTargetException(e);
892 }
893 }
894
895 throw new IllegalStateException("Unknown type " + type);
896 }
897
898
899
900
901
902 private Object itemValue(Object obj, Object item) throws Exception
903 {
904
905 if (item instanceof String) return item;
906
907 XmlParser.Node node = (XmlParser.Node) item;
908 String tag = node.getTag();
909 if ("Call".equals(tag)) return call(obj, node);
910 if ("Get".equals(tag)) return get(obj, node);
911 if ("New".equals(tag)) return newObj(obj, node);
912 if ("Ref".equals(tag)) return refObj(obj, node);
913 if ("Array".equals(tag)) return newArray(obj, node);
914 if ("Map".equals(tag)) return newMap(obj, node);
915 if ("Property".equals(tag)) return propertyObj(obj,node);
916
917 if ("SystemProperty".equals(tag))
918 {
919 String name = node.getAttribute("name");
920 String defaultValue = node.getAttribute("default");
921 return System.getProperty(name, defaultValue);
922 }
923
924 Log.warn("Unknown value tag: " + node, new Throwable());
925 return null;
926 }
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950 @SuppressWarnings( "unchecked" )
951 public static void main( final String[] args )
952 {
953
954 AccessController.doPrivileged( new PrivilegedAction()
955 {
956 public Object run()
957 {
958 try
959 {
960
961 Properties properties = new Properties();
962 XmlConfiguration last = null;
963 Object[] obj = new Object[args.length];
964 for ( int i = 0; i < args.length; i++ )
965 {
966 if ( args[i].toLowerCase().endsWith( ".properties" ) )
967 {
968 properties.load( Resource.newResource( args[i] ).getInputStream() );
969 }
970 else
971 {
972 XmlConfiguration configuration =
973 new XmlConfiguration( Resource.newResource( args[i] ).getURL() );
974 if ( last != null )
975 configuration.getIdMap().putAll( last.getIdMap() );
976 if ( properties.size() > 0 )
977 configuration.setProperties( properties );
978 obj[i] = configuration.configure();
979 last = configuration;
980 }
981 }
982
983 for ( int i = 0; i < args.length; i++ )
984 {
985 if ( obj[i] instanceof LifeCycle )
986 {
987 LifeCycle lc = (LifeCycle) obj[i];
988 if ( !lc.isRunning() )
989 lc.start();
990 }
991 }
992 }
993 catch ( Exception e )
994 {
995 Log.warn( Log.EXCEPTION, e );
996 }
997 return null;
998 }
999 } );
1000 }
1001
1002 }
1003