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