📄 xmlconfiguration.java
字号:
// ========================================================================// Copyright 2004-2005 Mort Bay Consulting Pty. Ltd.// ------------------------------------------------------------------------// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.// ========================================================================package org.mortbay.xml;import java.io.IOException;import java.io.InputStream;import java.io.StringReader;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.HashMap;import java.util.Iterator;import java.util.Map;import java.util.Properties;import org.mortbay.component.LifeCycle;import org.mortbay.log.Log;import org.mortbay.resource.Resource;import org.mortbay.util.LazyList;import org.mortbay.util.Loader;import org.mortbay.util.TypeUtil;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. * * @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 final Integer ZERO=new Integer(0); /* ------------------------------------------------------------ */ private static XmlParser __parser; private XmlParser.Node _config; private Map _idMap = new HashMap(); private Map _propertyMap = new HashMap(); /* ------------------------------------------------------------ */ private synchronized static void initParser() throws IOException { if (__parser != null) return; __parser = new XmlParser(); try { URL configURL = Loader.getResource(XmlConfiguration.class, "org/mortbay/xml/configure_6_0.dtd", true); __parser.redirectEntity("configure.dtd", configURL); __parser.redirectEntity("configure_1_3.dtd", configURL); __parser.redirectEntity("http://jetty.mortbay.org/configure.dtd", configURL); __parser.redirectEntity("-//Mort Bay Consulting//DTD Configure//EN", configURL); __parser.redirectEntity("http://jetty.mortbay.org/configure_1_3.dtd", configURL); __parser.redirectEntity("-//Mort Bay Consulting//DTD Configure 1.3//EN", configURL); __parser.redirectEntity("configure_1_2.dtd", configURL); __parser.redirectEntity("http://jetty.mortbay.org/configure_1_2.dtd", configURL); __parser.redirectEntity("-//Mort Bay Consulting//DTD Configure 1.2//EN", configURL); __parser.redirectEntity("configure_1_1.dtd", configURL); __parser.redirectEntity("http://jetty.mortbay.org/configure_1_1.dtd", configURL); __parser.redirectEntity("-//Mort Bay Consulting//DTD Configure 1.1//EN", configURL); __parser.redirectEntity("configure_1_0.dtd", configURL); __parser.redirectEntity("http://jetty.mortbay.org/configure_1_0.dtd", configURL); __parser.redirectEntity("-//Mort Bay Consulting//DTD Configure 1.0//EN", configURL); } catch (ClassNotFoundException e) { Log.warn(e.toString()); Log.debug(e); } } /* ------------------------------------------------------------ */ /** * 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 " <Configure ...." element. * @exception SAXException * @exception IOException */ public XmlConfiguration(String configuration) throws SAXException, IOException { initParser(); 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\">" + configuration; InputSource source = new InputSource(new StringReader(configuration)); synchronized (__parser) { _config = __parser.parse(source); } } /* ------------------------------------------------------------ */ /** * Constructor. * * @param configuration An input stream containing a complete e.g. configuration file * @exception SAXException * @exception IOException */ public XmlConfiguration(InputStream configuration) throws SAXException, IOException { initParser(); InputSource source = new InputSource(configuration); synchronized (__parser) { _config = __parser.parse(source); } } /* ------------------------------------------------------------ */ public Map getIdMap() { return _idMap; } /* ------------------------------------------------------------ */ public void setIdMap(Map map) { _idMap=map; } /* ------------------------------------------------------------ */ public void setProperties (Map map) { _propertyMap = map; } /* ------------------------------------------------------------ */ public Map getProperties () { return _propertyMap; } /* ------------------------------------------------------------ */ /** * 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 Exception */ public void configure(Object obj) throws Exception { //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); } /* ------------------------------------------------------------ */ /** * Configure an object. If the configuration has an ID, an object is looked up * by ID and it's type check. Otherwise a new object is created. * * @return The newly created configured object. * @exception Exception */ public Object configure() throws Exception { Class oClass = nodeClass(_config); String id = _config.getAttribute("id"); Object obj = id==null?null:_idMap.get(id); if (obj==null && oClass !=null) obj = oClass.newInstance(); if (oClass!=null && !oClass.isInstance(obj)) throw new ClassCastException(oClass.toString()); 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,true); } /* ------------------------------------------------------------ */ /* * Recursive configuration step. This method applies the remaining Set, Put and Call elements to * the current object. @param obj @param cfg @param i @exception Exception */ private void configure(Object obj, XmlParser.Node cfg, int i) throws Exception { String id = cfg.getAttribute("id"); if (id!=null) _idMap.put(id,obj); for (; i < cfg.size(); i++) { Object o = cfg.get(i); if (o instanceof String) continue; XmlParser.Node node = (XmlParser.Node) o; try { String tag = node.getTag(); if ("Set".equals(tag)) set(obj, node); else if ("Put".equals(tag)) put(obj, node); else if ("Call".equals(tag)) call(obj, node); else if ("Get".equals(tag)) get(obj, node); else if ("New".equals(tag)) newObj(obj, node); else if ("Array".equals(tag)) newArray(obj, node); else if ("Ref".equals(tag)) refObj(obj, node); else if ("Property".equals(tag)) propertyObj(obj, node); else throw new IllegalStateException("Unknown tag: " + tag); } catch (Exception e) { Log.warn("Config error at " + node, e.toString()); throw e; } } } /* ------------------------------------------------------------ */ /* * Call a set method. This method makes a best effort to find a matching set method. The type of * the value is used to find a suitable set method by 1. Trying for a trivial type match. 2. * Looking for a native type match. 3. Trying all correctly named methods for an auto * conversion. 4. Attempting to construct a suitable value from original value. @param obj * @param node */ private void set(Object obj, XmlParser.Node node) throws Exception { String attr = node.getAttribute("name"); String name = "set" + attr.substring(0, 1).toUpperCase() + attr.substring(1); Object value = value(obj, node); Object[] arg = { value}; Class oClass = nodeClass(node); if (oClass != null) obj = null; else oClass = obj.getClass(); Class[] vClass = { Object.class}; if (value != null) vClass[0] = value.getClass(); if (Log.isDebugEnabled()) Log.debug("XML "+(obj!=null?obj.toString():oClass.getName()) + "." + name + "(" + value + ")"); // Try for trivial match try { Method set = oClass.getMethod(name, vClass); set.invoke(obj, arg); return; } catch (IllegalArgumentException e) { Log.ignore(e); } catch (IllegalAccessException e) { Log.ignore(e); } catch (NoSuchMethodException e) { Log.ignore(e); } // Try for native match try { Field type = vClass[0].getField("TYPE"); vClass[0] = (Class) type.get(null); Method set = oClass.getMethod(name, vClass); set.invoke(obj, arg); return; } catch (NoSuchFieldException e) { Log.ignore(e); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -