001: // ========================================================================
002: // Copyright 2004-2005 Mort Bay Consulting Pty. Ltd.
003: // ------------------------------------------------------------------------
004: // Licensed under the Apache License, Version 2.0 (the "License");
005: // you may not use this file except in compliance with the License.
006: // You may obtain a copy of the License at
007: // http://www.apache.org/licenses/LICENSE-2.0
008: // Unless required by applicable law or agreed to in writing, software
009: // distributed under the License is distributed on an "AS IS" BASIS,
010: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
011: // See the License for the specific language governing permissions and
012: // limitations under the License.
013: // ========================================================================
014:
015: package org.mortbay.xml;
016:
017: import java.io.IOException;
018: import java.io.InputStream;
019: import java.io.StringReader;
020: import java.lang.reflect.Constructor;
021: import java.lang.reflect.Field;
022: import java.lang.reflect.InvocationTargetException;
023: import java.lang.reflect.Method;
024: import java.lang.reflect.Modifier;
025: import java.net.InetAddress;
026: import java.net.MalformedURLException;
027: import java.net.URL;
028: import java.net.UnknownHostException;
029: import java.util.HashMap;
030: import java.util.Iterator;
031: import java.util.Map;
032:
033: import org.mortbay.component.LifeCycle;
034: import org.mortbay.log.Log;
035: import org.mortbay.resource.Resource;
036: import org.mortbay.util.LazyList;
037: import org.mortbay.util.Loader;
038: import org.mortbay.util.TypeUtil;
039: import org.xml.sax.InputSource;
040: import org.xml.sax.SAXException;
041:
042: /* ------------------------------------------------------------ */
043: /**
044: * Configure Objects from XML. This class reads an XML file conforming to the configure.dtd DTD and
045: * uses it to configure and object by calling set, put or other methods on the object.
046: *
047: * @author Greg Wilkins (gregw)
048: */
049: public class XmlConfiguration {
050:
051: private static Class[] __primitives = { Boolean.TYPE,
052: Character.TYPE, Byte.TYPE, Short.TYPE, Integer.TYPE,
053: Long.TYPE, Float.TYPE, Double.TYPE, Void.TYPE };
054:
055: private static Class[] __primitiveHolders = { Boolean.class,
056: Character.class, Byte.class, Short.class, Integer.class,
057: Long.class, Float.class, Double.class, Void.class };
058: private static final Integer ZERO = new Integer(0);
059:
060: /* ------------------------------------------------------------ */
061: private static XmlParser __parser;
062: private XmlParser.Node _config;
063: private Map _idMap = new HashMap();
064: private Map _propertyMap = new HashMap();
065:
066: /* ------------------------------------------------------------ */
067: private synchronized static void initParser() throws IOException {
068: if (__parser != null)
069: return;
070:
071: __parser = new XmlParser();
072: URL configURL = XmlConfiguration.class.getClassLoader()
073: .getResource("org/mortbay/xml/configure_6_0.dtd");
074: __parser.redirectEntity("configure.dtd", configURL);
075: __parser.redirectEntity("configure_1_3.dtd", configURL);
076: __parser.redirectEntity(
077: "http://jetty.mortbay.org/configure.dtd", configURL);
078: __parser.redirectEntity(
079: "-//Mort Bay Consulting//DTD Configure//EN", configURL);
080: __parser
081: .redirectEntity(
082: "http://jetty.mortbay.org/configure_1_3.dtd",
083: configURL);
084: __parser.redirectEntity(
085: "-//Mort Bay Consulting//DTD Configure 1.3//EN",
086: configURL);
087: __parser.redirectEntity("configure_1_2.dtd", configURL);
088: __parser
089: .redirectEntity(
090: "http://jetty.mortbay.org/configure_1_2.dtd",
091: configURL);
092: __parser.redirectEntity(
093: "-//Mort Bay Consulting//DTD Configure 1.2//EN",
094: configURL);
095: __parser.redirectEntity("configure_1_1.dtd", configURL);
096: __parser
097: .redirectEntity(
098: "http://jetty.mortbay.org/configure_1_1.dtd",
099: configURL);
100: __parser.redirectEntity(
101: "-//Mort Bay Consulting//DTD Configure 1.1//EN",
102: configURL);
103: __parser.redirectEntity("configure_1_0.dtd", configURL);
104: __parser
105: .redirectEntity(
106: "http://jetty.mortbay.org/configure_1_0.dtd",
107: configURL);
108: __parser.redirectEntity(
109: "-//Mort Bay Consulting//DTD Configure 1.0//EN",
110: configURL);
111: }
112:
113: /* ------------------------------------------------------------ */
114: /**
115: * Constructor. Reads the XML configuration file.
116: *
117: * @param configuration
118: */
119: public XmlConfiguration(URL configuration) throws SAXException,
120: IOException {
121: initParser();
122: synchronized (__parser) {
123: _config = __parser.parse(configuration.toString());
124: }
125: }
126:
127: /* ------------------------------------------------------------ */
128: /**
129: * Constructor.
130: *
131: * @param configuration String of XML configuration commands excluding the normal XML preamble.
132: * The String should start with a " <Configure ...." element.
133: * @exception SAXException
134: * @exception IOException
135: */
136: public XmlConfiguration(String configuration) throws SAXException,
137: IOException {
138: initParser();
139: configuration = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<!DOCTYPE Configure PUBLIC \"-//Mort Bay Consulting//DTD Configure 1.2//EN\" \"http://jetty.mortbay.org/configure_1_2.dtd\">"
140: + configuration;
141: InputSource source = new InputSource(new StringReader(
142: configuration));
143: synchronized (__parser) {
144: _config = __parser.parse(source);
145: }
146: }
147:
148: /* ------------------------------------------------------------ */
149: /**
150: * Constructor.
151: *
152: * @param configuration An input stream containing a complete e.g. configuration file
153: * @exception SAXException
154: * @exception IOException
155: */
156: public XmlConfiguration(InputStream configuration)
157: throws SAXException, IOException {
158: initParser();
159: InputSource source = new InputSource(configuration);
160: synchronized (__parser) {
161: _config = __parser.parse(source);
162: }
163: }
164:
165: /* ------------------------------------------------------------ */
166: public Map getIdMap() {
167: return _idMap;
168: }
169:
170: /* ------------------------------------------------------------ */
171: public void setIdMap(Map map) {
172: _idMap = map;
173: }
174:
175: public void setProperties(Map map) {
176: _propertyMap = map;
177: }
178:
179: public Map getProperties() {
180: return _propertyMap;
181: }
182:
183: /* ------------------------------------------------------------ */
184: /**
185: * Configure an object. If the object is of the approprate class, the XML configuration script
186: * is applied to the object.
187: *
188: * @param obj The object to be configured.
189: * @exception Exception
190: */
191: public void configure(Object obj) throws Exception {
192: //Check the class of the object
193: Class oClass = nodeClass(_config);
194: if (!oClass.isInstance(obj))
195: throw new IllegalArgumentException("Object is not of type "
196: + oClass);
197: configure(obj, _config, 0);
198: }
199:
200: /* ------------------------------------------------------------ */
201: /**
202: * Configure an object. If the configuration has an ID, an object is looked up
203: * by ID and it's type check. Otherwise a new object is created.
204: *
205: * @return The newly created configured object.
206: * @exception Exception
207: */
208: public Object configure() throws Exception {
209: Class oClass = nodeClass(_config);
210:
211: String id = _config.getAttribute("id");
212: Object obj = id == null ? null : _idMap.get(id);
213:
214: if (obj == null && oClass != null)
215: obj = oClass.newInstance();
216:
217: if (oClass != null && !oClass.isInstance(obj))
218: throw new ClassCastException(oClass.toString());
219:
220: configure(obj, _config, 0);
221: return obj;
222: }
223:
224: /* ------------------------------------------------------------ */
225: private Class nodeClass(XmlParser.Node node)
226: throws ClassNotFoundException {
227: String className = node.getAttribute("class");
228: if (className == null)
229: return null;
230:
231: return Loader
232: .loadClass(XmlConfiguration.class, className, true);
233: }
234:
235: /* ------------------------------------------------------------ */
236: /*
237: * Recursive configuration step. This method applies the remaining Set, Put and Call elements to
238: * the current object. @param obj @param cfg @param i @exception Exception
239: */
240: private void configure(Object obj, XmlParser.Node cfg, int i)
241: throws Exception {
242: String id = cfg.getAttribute("id");
243: if (id != null)
244: _idMap.put(id, obj);
245:
246: for (; i < cfg.size(); i++) {
247: Object o = cfg.get(i);
248: if (o instanceof String)
249: continue;
250: XmlParser.Node node = (XmlParser.Node) o;
251:
252: try {
253: String tag = node.getTag();
254: if ("Set".equals(tag))
255: set(obj, node);
256: else if ("Put".equals(tag))
257: put(obj, node);
258: else if ("Call".equals(tag))
259: call(obj, node);
260: else if ("Get".equals(tag))
261: get(obj, node);
262: else if ("New".equals(tag))
263: newObj(obj, node);
264: else if ("Array".equals(tag))
265: newArray(obj, node);
266: else if ("Ref".equals(tag))
267: refObj(obj, node);
268: else
269: throw new IllegalStateException("Unknown tag: "
270: + tag);
271: } catch (Exception e) {
272: Log.warn("Config error at " + node, e.toString());
273: throw e;
274: }
275: }
276: }
277:
278: /* ------------------------------------------------------------ */
279: /*
280: * Call a set method. This method makes a best effort to find a matching set method. The type of
281: * the value is used to find a suitable set method by 1. Trying for a trivial type match. 2.
282: * Looking for a native type match. 3. Trying all correctly named methods for an auto
283: * conversion. 4. Attempting to construct a suitable value from original value. @param obj
284: * @param node
285: */
286: private void set(Object obj, XmlParser.Node node) throws Exception {
287: String attr = node.getAttribute("name");
288: String name = "set" + attr.substring(0, 1).toUpperCase()
289: + attr.substring(1);
290: Object value = value(obj, node);
291: Object[] arg = { value };
292:
293: Class oClass = nodeClass(node);
294: if (oClass != null)
295: obj = null;
296: else
297: oClass = obj.getClass();
298:
299: Class[] vClass = { Object.class };
300: if (value != null)
301: vClass[0] = value.getClass();
302:
303: if (Log.isDebugEnabled())
304: Log.debug("XML "
305: + (obj != null ? obj.toString() : oClass.getName())
306: + "." + name + "(" + value + ")");
307:
308: // Try for trivial match
309: try {
310: Method set = oClass.getMethod(name, vClass);
311: set.invoke(obj, arg);
312: return;
313: } catch (IllegalArgumentException e) {
314: Log.ignore(e);
315: } catch (IllegalAccessException e) {
316: Log.ignore(e);
317: } catch (NoSuchMethodException e) {
318: Log.ignore(e);
319: }
320:
321: // Try for native match
322: try {
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: } catch (NoSuchFieldException e) {
329: Log.ignore(e);
330: } catch (IllegalArgumentException e) {
331: Log.ignore(e);
332: } catch (IllegalAccessException e) {
333: Log.ignore(e);
334: } catch (NoSuchMethodException e) {
335: Log.ignore(e);
336: }
337:
338: // Try a field
339: try {
340: Field field = oClass.getField(attr);
341: if (Modifier.isPublic(field.getModifiers())) {
342: field.set(obj, value);
343: return;
344: }
345: } catch (NoSuchFieldException e) {
346: Log.ignore(e);
347: }
348:
349: // Search for a match by trying all the set methods
350: Method[] sets = oClass.getMethods();
351: Method set = null;
352: for (int s = 0; sets != null && s < sets.length; s++) {
353: if (name.equals(sets[s].getName())
354: && sets[s].getParameterTypes().length == 1) {
355: // lets try it
356: try {
357: set = sets[s];
358: sets[s].invoke(obj, arg);
359: return;
360: } catch (IllegalArgumentException e) {
361: Log.ignore(e);
362: } catch (IllegalAccessException e) {
363: Log.ignore(e);
364: }
365: }
366: }
367:
368: // Try converting the arg to the last set found.
369: if (set != null) {
370: try {
371: Class sClass = set.getParameterTypes()[0];
372: if (sClass.isPrimitive()) {
373: for (int t = 0; t < __primitives.length; t++) {
374: if (sClass.equals(__primitives[t])) {
375: sClass = __primitiveHolders[t];
376: break;
377: }
378: }
379: }
380: Constructor cons = sClass.getConstructor(vClass);
381: arg[0] = cons.newInstance(arg);
382: set.invoke(obj, arg);
383: return;
384: } catch (NoSuchMethodException e) {
385: Log.ignore(e);
386: } catch (IllegalAccessException e) {
387: Log.ignore(e);
388: } catch (InstantiationException e) {
389: Log.ignore(e);
390: }
391: }
392:
393: // No Joy
394: throw new NoSuchMethodException(oClass + "." + name + "("
395: + vClass[0] + ")");
396: }
397:
398: /* ------------------------------------------------------------ */
399: /*
400: * Call a put method.
401: *
402: * @param obj @param node
403: */
404: private void put(Object obj, XmlParser.Node node) throws Exception {
405: if (!(obj instanceof Map))
406: throw new IllegalArgumentException(
407: "Object for put is not a Map: " + obj);
408: Map map = (Map) obj;
409:
410: String name = node.getAttribute("name");
411: Object value = value(obj, node);
412: map.put(name, value);
413: if (Log.isDebugEnabled())
414: Log
415: .debug("XML " + obj + ".put(" + name + "," + value
416: + ")");
417: }
418:
419: /* ------------------------------------------------------------ */
420: /*
421: * Call a get method. Any object returned from the call is passed to the configure method to
422: * consume the remaining elements. @param obj @param node @return @exception Exception
423: */
424: private Object get(Object obj, XmlParser.Node node)
425: throws Exception {
426: Class oClass = nodeClass(node);
427: if (oClass != null)
428: obj = null;
429: else
430: oClass = obj.getClass();
431:
432: String name = node.getAttribute("name");
433: String id = node.getAttribute("id");
434: if (Log.isDebugEnabled())
435: Log.debug("XML get " + name);
436:
437: try {
438: // try calling a getXxx method.
439: Method method = oClass.getMethod("get"
440: + name.substring(0, 1).toUpperCase()
441: + name.substring(1), (java.lang.Class[]) null);
442: obj = method.invoke(obj, (java.lang.Object[]) null);
443: configure(obj, node, 0);
444: } catch (NoSuchMethodException nsme) {
445: try {
446: Field field = oClass.getField(name);
447: obj = field.get(obj);
448: configure(obj, node, 0);
449: } catch (NoSuchFieldException nsfe) {
450: throw nsme;
451: }
452: }
453: if (id != null)
454: _idMap.put(id, obj);
455: return obj;
456: }
457:
458: /* ------------------------------------------------------------ */
459: /*
460: * Call a method. A method is selected by trying all methods with matching names and number of
461: * arguments. Any object returned from the call is passed to the configure method to consume the
462: * remaining elements. Note that if this is a static call we consider only methods declared
463: * directly in the given class. i.e. we ignore any static methods in superclasses. @param obj
464: * @param node @return @exception Exception
465: */
466: private Object call(Object obj, XmlParser.Node node)
467: throws Exception {
468: String id = node.getAttribute("id");
469: Class oClass = nodeClass(node);
470: if (oClass != null)
471: obj = null;
472: else if (obj != null)
473: oClass = obj.getClass();
474: if (oClass == null)
475: throw new IllegalArgumentException(node.toString());
476:
477: int size = 0;
478: int argi = node.size();
479: for (int i = 0; i < node.size(); i++) {
480: Object o = node.get(i);
481: if (o instanceof String)
482: continue;
483: if (!((XmlParser.Node) o).getTag().equals("Arg")) {
484: argi = i;
485: break;
486: }
487: size++;
488: }
489:
490: Object[] arg = new Object[size];
491: for (int i = 0, j = 0; j < size; i++) {
492: Object o = node.get(i);
493: if (o instanceof String)
494: continue;
495: arg[j++] = value(obj, (XmlParser.Node) o);
496: }
497:
498: String method = node.getAttribute("name");
499: if (Log.isDebugEnabled())
500: Log.debug("XML call " + method);
501:
502: // Lets just try all methods for now
503: Method[] methods = oClass.getMethods();
504: for (int c = 0; methods != null && c < methods.length; c++) {
505: if (!methods[c].getName().equals(method))
506: continue;
507: if (methods[c].getParameterTypes().length != size)
508: continue;
509: if (Modifier.isStatic(methods[c].getModifiers()) != (obj == null))
510: continue;
511: if ((obj == null)
512: && methods[c].getDeclaringClass() != oClass)
513: continue;
514:
515: Object n = null;
516: boolean called = false;
517: try {
518: n = methods[c].invoke(obj, arg);
519: called = true;
520: } catch (IllegalAccessException e) {
521: Log.ignore(e);
522: } catch (IllegalArgumentException e) {
523: Log.ignore(e);
524: }
525: if (called) {
526: if (id != null)
527: _idMap.put(id, n);
528: configure(n, node, argi);
529: return n;
530: }
531: }
532:
533: throw new IllegalStateException("No Method: " + node + " on "
534: + oClass);
535: }
536:
537: /* ------------------------------------------------------------ */
538: /*
539: * Create a new value object.
540: *
541: * @param obj @param node @return @exception Exception
542: */
543: private Object newObj(Object obj, XmlParser.Node node)
544: throws Exception {
545: Class oClass = nodeClass(node);
546: String id = node.getAttribute("id");
547: int size = 0;
548: int argi = node.size();
549: for (int i = 0; i < node.size(); i++) {
550: Object o = node.get(i);
551: if (o instanceof String)
552: continue;
553: if (!((XmlParser.Node) o).getTag().equals("Arg")) {
554: argi = i;
555: break;
556: }
557: size++;
558: }
559:
560: Object[] arg = new Object[size];
561: for (int i = 0, j = 0; j < size; i++) {
562: Object o = node.get(i);
563: if (o instanceof String)
564: continue;
565: arg[j++] = value(obj, (XmlParser.Node) o);
566: }
567:
568: if (Log.isDebugEnabled())
569: Log.debug("XML new " + oClass);
570:
571: // Lets just try all constructors for now
572: Constructor[] constructors = oClass.getConstructors();
573: for (int c = 0; constructors != null && c < constructors.length; c++) {
574: if (constructors[c].getParameterTypes().length != size)
575: continue;
576:
577: Object n = null;
578: boolean called = false;
579: try {
580: n = constructors[c].newInstance(arg);
581: called = true;
582: } catch (IllegalAccessException e) {
583: Log.ignore(e);
584: } catch (InstantiationException e) {
585: Log.ignore(e);
586: } catch (IllegalArgumentException e) {
587: Log.ignore(e);
588: }
589: if (called) {
590: if (id != null)
591: _idMap.put(id, n);
592: configure(n, node, argi);
593: return n;
594: }
595: }
596:
597: throw new IllegalStateException("No Constructor: " + node
598: + " on " + obj);
599: }
600:
601: /* ------------------------------------------------------------ */
602: /*
603: * Reference an id value object.
604: *
605: * @param obj @param node @return @exception NoSuchMethodException @exception
606: * ClassNotFoundException @exception InvocationTargetException
607: */
608: private Object refObj(Object obj, XmlParser.Node node)
609: throws Exception {
610: String id = node.getAttribute("id");
611: obj = _idMap.get(id);
612: if (obj == null)
613: throw new IllegalStateException("No object for id=" + id);
614: configure(obj, node, 0);
615: return obj;
616: }
617:
618: /* ------------------------------------------------------------ */
619: /*
620: * Create a new array object.
621: *
622: */
623: private Object newArray(Object obj, XmlParser.Node node)
624: throws Exception {
625:
626: // Get the type
627: Class aClass = java.lang.Object.class;
628: String type = node.getAttribute("type");
629: final String id = node.getAttribute("id");
630: if (type != null) {
631: aClass = TypeUtil.fromName(type);
632: if (aClass == null) {
633: if ("String".equals(type))
634: aClass = java.lang.String.class;
635: else if ("URL".equals(type))
636: aClass = java.net.URL.class;
637: else if ("InetAddress".equals(type))
638: aClass = java.net.InetAddress.class;
639: else
640: aClass = Loader.loadClass(XmlConfiguration.class,
641: type, true);
642: }
643: }
644:
645: Object al = null;
646:
647: Iterator iter = node.iterator("Item");
648: while (iter.hasNext()) {
649: XmlParser.Node item = (XmlParser.Node) iter.next();
650: String nid = item.getAttribute("id");
651: Object v = value(obj, item);
652: al = LazyList.add(al,
653: (v == null && aClass.isPrimitive()) ? ZERO : v);
654: if (nid != null)
655: _idMap.put(nid, v);
656: }
657:
658: Object array = LazyList.toArray(al, aClass);
659: if (id != null)
660: _idMap.put(id, array);
661: return array;
662: }
663:
664: /* ------------------------------------------------------------ */
665: /*
666: * Create a new map object.
667: *
668: */
669: private Object newMap(Object obj, XmlParser.Node node)
670: throws Exception {
671: String id = node.getAttribute("id");
672:
673: Map map = new HashMap();
674: if (id != null)
675: _idMap.put(id, map);
676:
677: for (int i = 0; i < node.size(); i++) {
678: Object o = node.get(i);
679: if (o instanceof String)
680: continue;
681: XmlParser.Node entry = (XmlParser.Node) o;
682: if (!entry.getTag().equals("Entry"))
683: throw new IllegalStateException("Not an Entry");
684:
685: XmlParser.Node key = null;
686: XmlParser.Node value = null;
687:
688: for (int j = 0; j < entry.size(); j++) {
689: o = entry.get(j);
690: if (o instanceof String)
691: continue;
692: XmlParser.Node item = (XmlParser.Node) o;
693: if (!item.getTag().equals("Item"))
694: throw new IllegalStateException("Not an Item");
695: if (key == null)
696: key = item;
697: else
698: value = item;
699: }
700:
701: if (key == null || value == null)
702: throw new IllegalStateException("Missing Item in Entry");
703: String kid = key.getAttribute("id");
704: String vid = value.getAttribute("id");
705:
706: Object k = value(obj, key);
707: Object v = value(obj, value);
708: map.put(k, v);
709:
710: if (kid != null)
711: _idMap.put(kid, k);
712: if (vid != null)
713: _idMap.put(vid, v);
714: }
715:
716: return map;
717: }
718:
719: /* ------------------------------------------------------------ */
720: /*
721: * Get the value of an element. If no value type is specified, then white space is trimmed out
722: * of the value. If it contains multiple value elements they are added as strings before being
723: * converted to any specified type. @param node
724: */
725: private Object value(Object obj, XmlParser.Node node)
726: throws Exception {
727: Object value = null;
728:
729: // Get the type
730: String type = node.getAttribute("type");
731:
732: // Try a ref lookup
733: String ref = node.getAttribute("ref");
734: if (ref != null) {
735: value = _idMap.get(ref);
736: } else {
737: // handle trivial case
738: if (node.size() == 0) {
739: if ("String".equals(type))
740: return "";
741: return null;
742: }
743:
744: // Trim values
745: int first = 0;
746: int last = node.size() - 1;
747:
748: // Handle default trim type
749: if (type == null || !"String".equals(type)) {
750: // Skip leading white
751: Object item = null;
752: while (first <= last) {
753: item = node.get(first);
754: if (!(item instanceof String))
755: break;
756: item = ((String) item).trim();
757: if (((String) item).length() > 0)
758: break;
759: first++;
760: }
761:
762: // Skip trailing white
763: while (first < last) {
764: item = node.get(last);
765: if (!(item instanceof String))
766: break;
767: item = ((String) item).trim();
768: if (((String) item).length() > 0)
769: break;
770: last--;
771: }
772:
773: // All white, so return null
774: if (first > last)
775: return null;
776: }
777:
778: if (first == last)
779: // Single Item value
780: value = itemValue(obj, node.get(first));
781: else {
782: // Get the multiple items as a single string
783: StringBuffer buf = new StringBuffer();
784: synchronized (buf) {
785: for (int i = first; i <= last; i++) {
786: Object item = node.get(i);
787: buf.append(itemValue(obj, item));
788: }
789: value = buf.toString();
790: }
791: }
792: }
793:
794: // Untyped or unknown
795: if (value == null) {
796: if ("String".equals(type))
797: return "";
798: return null;
799: }
800:
801: // Try to type the object
802: if (type == null) {
803: if (value != null && value instanceof String)
804: return ((String) value).trim();
805: return value;
806: }
807:
808: if ("String".equals(type) || "java.lang.String".equals(type))
809: return value.toString();
810:
811: Class pClass = TypeUtil.fromName(type);
812: if (pClass != null)
813: return TypeUtil.valueOf(pClass, value.toString());
814:
815: if ("URL".equals(type) || "java.net.URL".equals(type)) {
816: if (value instanceof URL)
817: return value;
818: try {
819: return new URL(value.toString());
820: } catch (MalformedURLException e) {
821: throw new InvocationTargetException(e);
822: }
823: }
824:
825: if ("InetAddress".equals(type)
826: || "java.net.InetAddress".equals(type)) {
827: if (value instanceof InetAddress)
828: return value;
829: try {
830: return InetAddress.getByName(value.toString());
831: } catch (UnknownHostException e) {
832: throw new InvocationTargetException(e);
833: }
834: }
835:
836: throw new IllegalStateException("Unknown type " + type);
837: }
838:
839: /* ------------------------------------------------------------ */
840: /*
841: * Get the value of a single element. @param obj @param item @return @exception Exception
842: */
843: private Object itemValue(Object obj, Object item) throws Exception {
844: // String value
845: if (item instanceof String)
846: return item;
847:
848: XmlParser.Node node = (XmlParser.Node) item;
849: String tag = node.getTag();
850: if ("Call".equals(tag))
851: return call(obj, node);
852: if ("Get".equals(tag))
853: return get(obj, node);
854: if ("New".equals(tag))
855: return newObj(obj, node);
856: if ("Ref".equals(tag))
857: return refObj(obj, node);
858: if ("Array".equals(tag))
859: return newArray(obj, node);
860: if ("Map".equals(tag))
861: return newMap(obj, node);
862:
863: if ("SystemProperty".equals(tag)) {
864: String name = node.getAttribute("name");
865: String defaultValue = node.getAttribute("default");
866: return System.getProperty(name, defaultValue);
867: }
868: if ("Property".equals(tag)) {
869: String name = node.getAttribute("name");
870: Object defval = node.getAttribute("default");
871: if (_propertyMap != null && _propertyMap.containsKey(name)) {
872: return _propertyMap.get(name);
873: } else if (defval != null)
874: return defval;
875: else
876: throw new Exception("Unresolved property name=" + name);
877: }
878:
879: Log.warn("Unknown value tag: " + node, new Throwable());
880: return null;
881: }
882:
883: /* ------------------------------------------------------------ */
884: /* ------------------------------------------------------------ */
885: /* ------------------------------------------------------------ */
886: public static void main(String[] args) {
887: try {
888: XmlConfiguration last = null;
889: Object[] obj = new Object[args.length];
890: for (int i = 0; i < args.length; i++) {
891: XmlConfiguration configuration = new XmlConfiguration(
892: Resource.newResource(args[i]).getURL());
893: if (last != null)
894: configuration.getIdMap().putAll(last.getIdMap());
895: obj[i] = configuration.configure();
896: last = configuration;
897: }
898:
899: for (int i = 0; i < args.length; i++) {
900: if (obj[i] instanceof LifeCycle) {
901: LifeCycle lc = (LifeCycle) obj[i];
902: if (!lc.isRunning())
903: lc.start();
904: }
905: }
906: } catch (Exception e) {
907: Log.warn(Log.EXCEPTION, e);
908: }
909:
910: }
911:
912: }
|