|
What this is
Other links
The source code
package net.myvietnam.mvncore.configuration;
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999-2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowledgement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgement may appear in the software itself,
* if and wherever such third-party acknowledgements normally appear.
*
* 4. The names "The Jakarta Project", "Commons", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Stack;
import org.apache.commons.digester.AbstractObjectCreationFactory;
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.ObjectCreationFactory;
import org.apache.commons.digester.xmlrules.DigesterLoader;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
/**
* Factory class to create a CompositeConfiguration from a .xml file using
* Digester. By default it can handle the Configurations from commons-
* configuration. If you need to add your own, then you can pass in your own
* digester rules to use. It is also namespace aware, by providing a
* digesterRuleNamespaceURI.
*
* @author <a href="mailto:epugh@upstate.com">Eric Pugh
* @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen
* @author <a href="mailto:oliver.heger@t-online.de">Oliver Heger
* @version $Id: ConfigurationFactory.java,v 1.1 2003/12/09 08:25:30 huumai Exp $
*/
public class ConfigurationFactory implements BasePathLoader
{
/** Constant for the root element in the info file.*/
private static final String SEC_ROOT = "configuration/";
/** Constant for the override section.*/
private static final String SEC_OVERRIDE = SEC_ROOT + "override/";
/** Constant for the additional section.*/
private static final String SEC_ADDITIONAL = SEC_ROOT + "additional/";
/** Constant for the name of the load method.*/
private static final String METH_LOAD = "load";
/** Constant for the default base path (points to actual directory).*/
private static final String DEF_BASE_PATH = ".";
/** The XML file with the details about the configuration to load */
private String configurationFileName;
/** The URL to the XML file with the details about the configuration to
* load.
*/
private URL configurationURL;
/**
* The implicit base path for included files. This path is determined by
* the configuration to load and used unless no other base path was
* explicitely specified.
*/
private String impliciteBasePath;
/** The basePath to prefix file paths for file based property files. */
private String basePath;
/** static logger */
private static Log log = LogFactory.getLog(ConfigurationFactory.class);
/** URL for xml digester rules file */
private URL digesterRules;
/** The digester namespace to parse */
private String digesterRuleNamespaceURI;
/**
* C'tor
*/
public ConfigurationFactory()
{
setBasePath(DEF_BASE_PATH);
}
/**
* C'tor with ConfigurationFile Name passed
*
* @param configurationFileName The path to the configuration file
*/
public ConfigurationFactory(String configurationFileName)
{
this.configurationFileName = configurationFileName;
}
/**
* Return the configuration provided by this factory. It
* loads the configuration file which is a XML description of
* the actual configurations to load. It can contain various
* different types of configuration, currently Properties, XML and JNDI.
*
* @return A Configuration object
* @throws Exception A generic exception that we had trouble during the
* loading of the configuration data.
*/
public Configuration getConfiguration() throws Exception
{
Digester digester;
ConfigurationBuilder builder = new ConfigurationBuilder();
URL url = getConfigurationURL();
if(url == null)
{
url = ConfigurationUtils.getURL(impliciteBasePath,
getConfigurationFileName());
} /* if */
InputStream input = url.openStream();
if (getDigesterRules() == null)
{
digester = new Digester();
configureNamespace(digester);
initDefaultDigesterRules(digester);
}
else
{
digester = DigesterLoader.createDigester(getDigesterRules());
// This might already be too late. As far as I can see, the namespace
// awareness must be configured before the digester rules are loaded.
configureNamespace(digester);
}
// Put the composite builder object below all of the other objects.
digester.push(builder);
// Parse the input stream to configure our mappings
try
{
digester.parse(input);
input.close();
}
catch (SAXException e)
{
log.error("SAX Exception caught", e);
throw e;
}
return builder.getConfiguration();
}
/**
* Returns the configurationFile.
*
* @return The name of the configuration file. Can be null.
*/
public String getConfigurationFileName()
{
return configurationFileName;
}
/**
* Sets the configurationFile.
* @param configurationFileName The name of the configurationFile to use.
*/
public void setConfigurationFileName(String configurationFileName)
{
File file = new File(configurationFileName).getAbsoluteFile();
this.configurationFileName = file.getName();
impliciteBasePath = file.getParent();
}
/**
* Returns the URL of the configuration file to be loaded.
* @return the URL of the configuration to load
*/
public URL getConfigurationURL()
{
return configurationURL;
}
/**
* Sets the URL of the configuration to load. This configuration can be
* either specified by a file name or by a URL.
* @param url the URL of the configuration to load
*/
public void setConfigurationURL(URL url)
{
configurationURL = url;
impliciteBasePath = url.toString();
// The following is a hack caused by the need to keep backwards
// compatibility: Per default the base path is set to the current
// directory. For loading from a URL this makes no sense. So
// unless no specific base path was set we clear it.
if(DEF_BASE_PATH.equals(getBasePath()))
{
setBasePath(null);
} /* if */
}
/**
* Returns the digesterRules.
* @return URL
*/
public URL getDigesterRules()
{
return digesterRules;
}
/**
* Sets the digesterRules.
* @param digesterRules The digesterRules to set
*/
public void setDigesterRules(URL digesterRules)
{
this.digesterRules = digesterRules;
}
/**
* Initializes the parsing rules for the default digester
*
* This allows the Configuration Factory to understand the
* default types: Properties, XML and JNDI. Two special sections are
* introduced: <code><override> and
* <code><additional>.
*
* @param digester The digester to configure
*/
protected void initDefaultDigesterRules(Digester digester)
{
initDigesterSectionRules(digester, SEC_ROOT, false);
initDigesterSectionRules(digester, SEC_OVERRIDE, false);
initDigesterSectionRules(digester, SEC_ADDITIONAL, true);
}
/**
* Sets up digester rules for a specified section of the configuration
* info file.
* @param digester the current digester instance
* @param matchString specifies the section
* @param additional a flag if rules for the additional section are to be
* added
*/
protected void initDigesterSectionRules(Digester digester,
String matchString, boolean additional)
{
setupDigesterInstance(
digester,
matchString + "properties",
new BasePathConfigurationFactory(PropertiesConfiguration.class),
METH_LOAD,
additional);
setupDigesterInstance(
digester,
matchString + "dom4j",
new BasePathConfigurationFactory(DOM4JConfiguration.class),
METH_LOAD,
additional);
setupDigesterInstance(
digester,
matchString + "hierarchicalDom4j",
new BasePathConfigurationFactory(HierarchicalDOM4JConfiguration.class),
METH_LOAD,
additional);
setupDigesterInstance(
digester,
matchString + "jndi",
new JNDIConfigurationFactory(),
null,
additional);
}
/**
* Sets up digester rules for a configuration to be loaded.
* @param digester the current digester
* @param matchString the pattern to match with this rule
* @param factory an ObjectCreationFactory instance to use for creating new
* objects
* @param method the name of a method to be called or <b>null for none
* @param additional a flag if rules for the additional section are to be
* added
*/
protected void setupDigesterInstance(
Digester digester,
String matchString,
ObjectCreationFactory factory,
String method,
boolean additional)
{
if(additional)
{
setupUnionRules(digester, matchString);
} /* if */
digester.addFactoryCreate(matchString, factory);
digester.addSetProperties(matchString);
if(method != null)
{
digester.addCallMethod(matchString, method);
} /* if */
digester.addSetNext(
matchString,
"addConfiguration",
Configuration.class.getName());
}
/**
* Sets up rules for configurations in the additional section.
* @param digester the current digester
* @param matchString the pattern to match with this rule
*/
protected void setupUnionRules(Digester digester, String matchString)
{
digester.addObjectCreate(matchString,
AdditionalConfigurationData.class);
digester.addSetProperties(matchString);
digester.addSetNext(matchString, "addAdditionalConfig",
AdditionalConfigurationData.class.getName());
}
/**
* Returns the digesterRuleNamespaceURI.
*
* @return A String with the digesterRuleNamespaceURI.
*/
public String getDigesterRuleNamespaceURI()
{
return digesterRuleNamespaceURI;
}
/**
* Sets the digesterRuleNamespaceURI.
*
* @param digesterRuleNamespaceURI The new digesterRuleNamespaceURI to use
*/
public void setDigesterRuleNamespaceURI(String digesterRuleNamespaceURI)
{
this.digesterRuleNamespaceURI = digesterRuleNamespaceURI;
}
/**
* Configure the current digester to be namespace aware and to have
* a Configuration object to which all of the other configurations
* should be added
*
* @param digester The Digester to configure
*/
private void configureNamespace(Digester digester)
{
if (getDigesterRuleNamespaceURI() != null)
{
digester.setNamespaceAware(true);
digester.setRuleNamespaceURI(getDigesterRuleNamespaceURI());
}
else
{
digester.setNamespaceAware(false);
}
digester.setValidating(false);
}
/**
* Returns the Base path from which this Configuration Factory operates.
* This is never null. If you set the BasePath to null, then a base path
* according to the configuration to load is returned.
*
* @return The base Path of this configuration factory.
*/
public String getBasePath()
{
String path = StringUtils.isEmpty(basePath) ?
impliciteBasePath : basePath;
return StringUtils.isEmpty(path) ? "." : path;
}
/**
* Sets the basePath for all file references from this Configuration Factory.
* Normally a base path need not to be set because it is determined by
* the location of the configuration file to load. All relative pathes in
* this file are resolved relative to this file. Setting a base path makes
* sense if such relative pathes should be otherwise resolved, e.g. if
* the configuration file is loaded from the class path and all sub
* configurations it refers to are stored in a special config directory.
*
* @param basePath The new basePath to set.
*/
public void setBasePath(String basePath)
{
this.basePath = basePath;
}
/**
* A base class for digester factory classes. This base class maintains
* a default class for the objects to be created.
* There will be sub classes for specific configuration implementations.
*/
public class DigesterConfigurationFactory
extends AbstractObjectCreationFactory
implements ObjectCreationFactory
{
/** Actual class to use. */
private Class clazz;
/**
* Creates a new instance of <code>DigesterConfigurationFactory.
* @param clazz the class which we should instantiate
*/
public DigesterConfigurationFactory(Class clazz)
{
this.clazz = clazz;
}
/**
* Creates an instance of the specified class.
* @param attribs the attributes (ignored)
* @return the new object
* @exception Exception if object creation fails
*/
public Object createObject(Attributes attribs) throws Exception
{
return clazz.newInstance();
}
}
/**
* A tiny inner class that allows the Configuration Factory to
* let the digester construct BasePathConfiguration objects
* that already have the correct base Path set.
*
*/
public class BasePathConfigurationFactory
extends DigesterConfigurationFactory
{
/**
* C'tor
*
* @param clazz The class which we should instantiate.
*/
public BasePathConfigurationFactory(Class clazz)
{
super(clazz);
}
/**
* Gets called by the digester.
*
* @param attributes the actual attributes
* @return the new object
* @throws Exception Couldn't instantiate the requested object.
*/
public Object createObject(Attributes attributes) throws Exception
{
BasePathLoader bpl =
(BasePathLoader) super.createObject(attributes);
bpl.setBasePath(getBasePath());
return bpl;
}
}
/**
* A tiny inner class that allows the Configuration Factory to
* let the digester construct JNDIPathConfiguration objects.
*
*/
public class JNDIConfigurationFactory
extends DigesterConfigurationFactory
{
/**
* C'tor
*/
public JNDIConfigurationFactory()
{
super(JNDIConfiguration.class);
}
}
/**
* A simple data class that holds all information about a configuration
* from the <code><additional> section.
*/
public static class AdditionalConfigurationData
{
/** Stores the configuration object.*/
private Configuration configuration;
/** Stores the location of this configuration in the global tree.*/
private String at;
/**
* Returns the value of the <code>at attribute.
* @return the at attribute
*/
public String getAt()
{
return at;
}
/**
* Sets the value of the <code>at attribute.
* @param string the attribute value
*/
public void setAt(String string)
{
at = string;
}
/**
* Returns the configuration object.
* @return the configuration
*/
public Configuration getConfiguration()
{
return configuration;
}
/**
* Sets the configuration object. Note: Normally this method should be
* named <code>setConfiguration(), but the name
* <code>addConfiguration() is required by some of the digester
* rules.
* @param config the configuration to set
*/
public void addConfiguration(Configuration config)
{
configuration = config;
}
}
/**
* An internally used helper class for constructing the composite
* configuration object.
*/
public static class ConfigurationBuilder
{
/** Stores the composite configuration.*/
private CompositeConfiguration config;
/** Stores a collection with the configs from the additional section.*/
private Collection additionalConfigs;
/**
* Creates a new instance of <code>ConfigurationBuilder.
*/
public ConfigurationBuilder()
{
config = new CompositeConfiguration();
additionalConfigs = new LinkedList();
}
/**
* Adds a new configuration to this object. This method is called by
* Digester.
* @param conf the configuration to be added
*/
public void addConfiguration(Configuration conf)
{
config.addConfiguration(conf);
}
/**
* Adds information about an additional configuration. This method is
* called by Digester.
* @param data the data about the additional configuration
*/
public void addAdditionalConfig(AdditionalConfigurationData data)
{
additionalConfigs.add(data);
}
/**
* Returns the final composite configuration.
* @return the final configuration object
*/
public CompositeConfiguration getConfiguration()
{
if(!additionalConfigs.isEmpty())
{
Configuration unionConfig =
createAdditionalConfiguration(additionalConfigs);
if(unionConfig != null)
{
addConfiguration(unionConfig);
} /* if */
additionalConfigs.clear();
} /* if */
return config;
}
/**
* Creates a configuration object with the union of all properties
* defined in the <code><additional> section. This
* implementation returns a <code>HierarchicalConfiguration
* object.
* @param configs a collection with
* <code>AdditionalConfigurationData objects
* @return the union configuration (can be <b>null)
*/
protected Configuration createAdditionalConfiguration(
Collection configs)
{
HierarchicalConfiguration result = new HierarchicalConfiguration();
for(Iterator it = configs.iterator(); it.hasNext();)
{
AdditionalConfigurationData cdata =
(AdditionalConfigurationData) it.next();
result.addNodes(cdata.getAt(),
createRootNode(cdata).getChildren().asVector());
} /* for */
return (result.isEmpty()) ? null : result;
}
/**
* Creates a configuration root node for the specified configuration.
* @param cdata the configuration data object
* @return a root node for this configuration
*/
private HierarchicalConfiguration.Node createRootNode(
AdditionalConfigurationData cdata)
{
if(cdata.getConfiguration() instanceof HierarchicalConfiguration)
{
// we can directly use this configuration's root node
return ((HierarchicalConfiguration) cdata.getConfiguration())
.getRoot();
} /* if */
else
{
// transform configuration to a hierarchical root node
HierarchicalConfigurationNodeConverter conv =
new HierarchicalConfigurationNodeConverter();
conv.process(cdata.getConfiguration());
return conv.getRootNode();
} /* else */
}
}
/**
* A specialized <code>HierarchicalConfigurationConverter class
* that creates a <code>HierarchicalConfiguration root node from
* an arbitrary <code>Configuration object. This class is used to
* add additional configuration objects to the hierarchical configuration
* managed by the <code>ConfigurationBuilder.
*/
static class HierarchicalConfigurationNodeConverter
extends HierarchicalConfigurationConverter
{
/** A stack for constructing the hierarchy.*/
private Stack nodes;
/** Stores the root node.*/
private HierarchicalConfiguration.Node root;
/**
* Default constructor.
*/
public HierarchicalConfigurationNodeConverter()
{
nodes = new Stack();
root = new HierarchicalConfiguration.Node();
nodes.push(root);
}
/**
* Callback for an element start event. Creates a new node and adds
* it to the actual parent.
* @param name the name of the new node
* @param value the node's value
*/
protected void elementStart(String name, Object value)
{
HierarchicalConfiguration.Node parent =
(HierarchicalConfiguration.Node) nodes.peek();
HierarchicalConfiguration.Node child =
new HierarchicalConfiguration.Node(name);
if(value != null)
{
child.setValue(value);
} /* if */
parent.addChild(child);
nodes.push(child);
}
/**
* Callback for an element end event. Clears the stack.
* @param name the name of the element
*/
protected void elementEnd(String name)
{
nodes.pop();
}
/**
* Returns the constructed root node.
* @return the root node
*/
public HierarchicalConfiguration.Node getRootNode()
{
return root;
}
}
}
|
| ... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.