// ======================================================================== // Copyright (c) 1999 Mort Bay Consulting (Australia) Pty. Ltd. // $Id: XmlConfiguration.java,v 1.15.2.6 2003/07/11 00:55:01 jules_gosnell Exp $ // ======================================================================== package org.mortbay.xml; import java.io.IOException; import java.io.StringReader; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.URL; import java.net.UnknownHostException; import java.util.Map; import org.mortbay.util.Code; import org.mortbay.util.InetAddrPort; import org.mortbay.util.Loader; import org.mortbay.util.TypeUtil; import org.mortbay.util.Resource; import org.xml.sax.InputSource; import org.xml.sax.SAXException; /* ------------------------------------------------------------ */ /** Configure Objects from XML. * This class reads an XML file conforming to the configure.dtd DTD * and uses it to configure and object by calling set, put or other * methods on the object. * * @version $Id: XmlConfiguration.java,v 1.15.2.6 2003/07/11 00:55:01 jules_gosnell Exp $ * @author Greg Wilkins (gregw) */ public class XmlConfiguration { private static Class[] __primitives = { Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE, Void.TYPE }; private static Class[] __primitiveHolders = { Boolean.class, Character.class, Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, Void.class }; /* ------------------------------------------------------------ */ private static XmlParser __parser; private XmlParser.Node _config; /* ------------------------------------------------------------ */ private synchronized static void initParser() throws IOException { if (__parser!=null) return; __parser = new XmlParser(); Resource config12Resource=Resource.newSystemResource("org/mortbay/xml/configure_1_2.dtd"); Code.assertTrue(config12Resource.exists(), "org/mortbay/xml/configure_1_2.dtd"); __parser.redirectEntity ("configure.dtd",config12Resource); __parser.redirectEntity ("configure_1_2.dtd", config12Resource); __parser.redirectEntity ("http://jetty.mortbay.org/configure_1_2.dtd", config12Resource); __parser.redirectEntity ("-//Mort Bay Consulting//DTD Configure 1.2//EN", config12Resource); Resource config11Resource=Resource.newSystemResource("org/mortbay/xml/configure_1_1.dtd"); Code.assertTrue(config11Resource.exists(), "org/mortbay/xml/configure_1_1.dtd"); __parser.redirectEntity ("configure_1_1.dtd", config11Resource); __parser.redirectEntity ("http://jetty.mortbay.org/configure_1_1.dtd", config11Resource); __parser.redirectEntity ("-//Mort Bay Consulting//DTD Configure 1.1//EN", config11Resource); Resource config10Resource=Resource.newSystemResource("org/mortbay/xml/configure_1_0.dtd"); Code.assertTrue(config10Resource.exists(), "org/mortbay/xml/configure_1_0.dtd"); __parser.redirectEntity ("configure_1_0.dtd", config10Resource); __parser.redirectEntity ("http://jetty.mortbay.org/configure_1_0.dtd", config10Resource); __parser.redirectEntity ("-//Mort Bay Consulting//DTD Configure 1.0//EN", config10Resource); } /* ------------------------------------------------------------ */ /** Constructor. * Reads the XML configuration file. * @param configuration */ public XmlConfiguration(URL configuration) throws SAXException, IOException { initParser(); synchronized(__parser) { _config = __parser.parse(configuration.toString()); } } /* ------------------------------------------------------------ */ /** Constructor. * @param configuration String of XML configuration commands * excluding the normal XML preamble. The String should start with * a "\n"+ configuration; InputSource source = new InputSource(new StringReader(configuration)); synchronized(__parser) { _config = __parser.parse(source); } } /* ------------------------------------------------------------ */ /** Configure an object. * If the object is of the approprate class, the XML configuration * script is applied to the object. * @param obj The object to be configured. * @exception ClassNotFoundException * @exception NoSuchMethodException * @exception InvocationTargetException */ public void configure(Object obj) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { //Check the class of the object Class oClass = nodeClass(_config); if (!oClass.isInstance(obj)) throw new IllegalArgumentException("Object is not of type "+oClass); configure(obj,_config,0); } /* ------------------------------------------------------------ */ /** Create a new object and configure it. * A new object is created and configured. * @return The newly created configured object. * @exception ClassNotFoundException * @exception NoSuchMethodException * @exception InvocationTargetException * @exception InstantiationException * @exception IllegalAccessException */ public Object newInstance() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { Class oClass = nodeClass(_config); Object obj = oClass.newInstance(); configure(obj,_config,0); return obj; } /* ------------------------------------------------------------ */ private Class nodeClass(XmlParser.Node node) throws ClassNotFoundException { String className=node.getAttribute("class"); if (className==null) return null; return Loader.loadClass(XmlConfiguration.class,className); } /* ------------------------------------------------------------ */ /* Recursive configuration step. * This method applies the remaining Set, Put and Call elements * to the current object. * @param obj * @param cfg * @param i * @exception ClassNotFoundException * @exception NoSuchMethodException * @exception InvocationTargetException */ private void configure(Object obj,XmlParser.Node cfg,int i) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { for(;i0) break; first++; } // Skip trailing white while(first0) break; last--; } // All white, so return null if (first>last) return null; } Object value=null; if (first==last) // Single Item value value=itemValue(obj,node.get(first)); else { // Get the multiple items as a single string StringBuffer buf = new StringBuffer(); synchronized(buf) { for (int i=first;i<=last;i++) { Object item = node.get(i); buf.append(itemValue(obj,item)); } value=buf.toString(); } } // Untyped or unknown if (value==null ) { if ("String".equals(type)) return ""; return null; } // Try to type the object if (type==null) { if (value !=null && value instanceof String) return ((String)value).trim(); return value; } if ("String".equals(type) || "java.lang.String".equals(type)) return value.toString(); Class pClass = TypeUtil.fromName(type); if (pClass!=null) return TypeUtil.valueOf(pClass,value.toString()); if ("URL".equals(type) || "java.net.URL".equals(type)) { if (value instanceof URL) return value; try{return new URL(value.toString());} catch(MalformedURLException e) {throw new InvocationTargetException(e);} } if ("InetAddress".equals(type)|| "java.net.InetAddress".equals(type)) { if (value instanceof InetAddress) return value; try {return InetAddress.getByName(value.toString());} catch(UnknownHostException e) {throw new InvocationTargetException(e);} } if ("InetAddrPort".equals(type) || "org.mortbay.util.InetAddrPort".equals(type)) { if (value instanceof InetAddrPort) return value; try{return new InetAddrPort(value.toString());} catch(UnknownHostException e) {throw new InvocationTargetException(e);} } throw new IllegalStateException("Unknown type "+type); } /* ------------------------------------------------------------ */ /* Get the value of a single element. * @param obj * @param item * @return * @exception ClassNotFoundException */ private Object itemValue(Object obj, Object item) throws NoSuchMethodException, ClassNotFoundException, InvocationTargetException, IllegalAccessException { // String value if (item instanceof String) return item; XmlParser.Node node=(XmlParser.Node)item; String tag=node.getTag(); if ("Call".equals(tag)) return call(obj,node); if ("Get".equals(tag)) return get(obj,node); if ("New".equals(tag)) return newObj(obj,node); if ("Array".equals(tag)) return newArray(obj,node); if ("SystemProperty".equals(tag)) { String name=node.getAttribute("name"); String defaultValue=node.getAttribute("default"); return System.getProperty(name, defaultValue); } Code.warning("Unknown value tag: "+node,new Throwable()); return null; } /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ public static void main(String[] arg) { try { for (int i=0;i