epugh 2004/01/16 06:56:45
Modified: configuration/xdocs changes.xml examples.xml overview.xml
configuration/src/java/org/apache/commons/configuration
CompositeConfiguration.java
ConfigurationFactory.java
configuration/conf testDigesterConfiguration2.xml
Removed: configuration/src/java/org/apache/commons/configuration
ConfigurationXMLDocument.java
configuration/conf testConfigurationXMLDocument.xml
testDigesterCreateObject.xml
configuration/src/test/org/apache/commons/configuration
TestConfigurationXMLDocument.java
Log:
- new class ConfigurationXMLDocument including test case
- Removed className attribute in configuration definition file for
ConfigurationFactory
- New element <hierarchicalDom4j> in configuration definition file
- Updates and enhancements of documentation
Revision Changes Path
1.3 +4 -0 jakarta-commons/configuration/xdocs/changes.xml
Index: changes.xml
===================================================================
RCS file: /home/cvs/jakarta-commons/configuration/xdocs/changes.xml,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- changes.xml 24 Dec 2003 14:28:21 -0000 1.2
+++ changes.xml 16 Jan 2004 14:56:45 -0000 1.3
@@ -7,6 +7,10 @@
<body>
<release version="1.0-dev-4" date="">
+ <action dev="oheger" type="add">
+ ConfigurationFactory now supports the hierarchicalDom4j element in
configuration
+ definition file
+ </action>
<action dev="ebourg" type="update">
Change all Vector objects to List objects.
</action>
1.3 +10 -545 jakarta-commons/configuration/xdocs/examples.xml
Index: examples.xml
===================================================================
RCS file: /home/cvs/jakarta-commons/configuration/xdocs/examples.xml,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- examples.xml 24 Dec 2003 14:28:21 -0000 1.2
+++ examples.xml 16 Jan 2004 14:56:45 -0000 1.3
@@ -428,13 +428,14 @@
<configuration>
<properties fileName="usergui.properties"/>
<dom4j fileName="gui.xml"/>
- <hierarchicalDom4j fileName="tables.xml"/>
+ <dom4j className="org.apache.commons.configuration.HierarchicalDOM4JConfiguration"
+ fileName="tables.xml"/>
</configuration>
]]>
</source>
<p>
- Note that one <code>dom4j</code> element was replaced
by a
- <code>hierarchicalDom4j</code> element. This element
tells the configuration
+ Note the additional <code>className</code> attribute
of the last
+ <code>dom4j</code> element. This attribute tells the
configuration
factory that not the default class for processing XML
documents
should be used, but the class
<code>HierarchicalDOM4JConfiguration</code>.
As the name implies this class is capable of saving the
@@ -506,7 +507,7 @@
and do not have a complex structure the default XML
configuration
class is suitable. If documents are more complex and
their structure
is important, the hierarchy aware class should be
used, which is
- selected by the <code>hierarchicalDom4j</code> element
as
+ enabled by an additional <code>className</code>
attribute as
shown in the example configuration definition file
above.
</p>
</subsection>
@@ -604,8 +605,10 @@
</override>
<additional>
- <hierarchicalDom4j fileName="tables.xml"/>
- <hierarchicalDom4j fileName="tasktables.xml" at="tables"/>
+ <dom4j
className="org.apache.commons.configuration.HierarchicalDOM4JConfiguration"
+ fileName="tables.xml"/>
+ <dom4j
className="org.apache.commons.configuration.HierarchicalDOM4JConfiguration"
+ fileName="tasktables.xml" at="tables"/>
</additional>
</configuration>
]]>
@@ -614,7 +617,7 @@
Compared to the older versions of this file a couple of
changes has been
done. One major difference is that the elements for including
configuration
sources are no longer direct children of the root element, but
are now
- contained in either an <code>override</code> or
<code>additonal</code>
+ contained in either an <code>override</code> or
<code>additional</code>
section. The names of these sections already imply their
purpose.
</p>
<p>
@@ -658,544 +661,6 @@
higher priority (otherwise they could not override the values
of other
sources).
</p>
- </section>
-
- <section name="XML processing">
- <p>
- We have now loaded some configuration sources and accessed
some of the
- properties. What else can we do? One additional feature
provided by
- Configuration is its support for XML-like processing of
<code>Configuration</code>
- objects that is implemented by the
<code>ConfigurationXMLDocument</code>
- class. The XML format for data exchange has become very
popular, so there
- are many use cases why you may want a XML-like view for your
configuration.
- This section shows how to make use of these features.
- </p>
- <subsection name="Basic XML access">
- <p>
- When it comes to XML processing of configuration
sources the
- <code>ConfigurationXMLDocument</code> class is usually
involved.
- When an instance of this class is created a
<code>Configuration</code>
- object is passed to the constructor. All operations
executed on the
- instance are then related to this configuration or a
subset of it.
- </p>
- <p>
- The most fundamental operation for treating a
configuration source
- as a XML document is to request a
<code>ConfigurationXMLReader</code>
- object from the <code>ConfigurationXMLDocument</code>
instance.
- The object returned by this method implements the
- <code>org.xml.sax.XMLReader</code> interface and thus
is a SAX 2
- conform XML parser. This parser can then be passed to
components
- that can deal with SAX events. The following snippet
shows how such
- a SAX parser can be obtained:
- </p>
- <source>
-<![CDATA[
-ConfigurationXMLDocument configDoc = new ConfigurationXMLDocument(config);
-XMLReader reader = configDoc.createXMLReader();
-
-// or:
-// XMLReader reader = configDoc.createXMLReader("tables");
-// Now do something with the reader
-...
-]]>
- </source>
- <p>
- As this example shows it is either possible to obtain
a reader object
- for the whole configuration or for a subset of it. The
obtained object
- can now be used where ever a SAX parser is supported.
There is
- only one thing to mention: The <code>XMLReader</code>
returned
- by <code>createXMLReader()</code> has been initialized
with the
- configuration source (or a subset of it) stored in the
- <code>ConfigurationXMLDocument</code> instance. If now
one of the
- <code>parse()</code> methods is called, the passed in
argument,
- which usually specifies the input source to parse, is
ignored. This
- information is unnecessary because all parsing is
always done on
- the associated <code>Configuration</code> object.
Later in this section
- this fact should become clearer.
- </p>
- </subsection>
- <subsection name="Working with documents">
- <p>
- SAX may be the most efficient, but it is surely not
the most convenient
- way of XML processing. If a document with a complex
structure is to
- be navigated, a DOM based approach is usually more
suitable.
- </p>
- <p>
- <code>ConfigurationXMLDocument</code> provides a
couple of
- overloaded <code>getDocument()</code> methods that
return a dom4j
- <code>Document</code> object. The arguments that can
be passed to
- these methods allow to select a subset of the
configuration source and
- to specify the name of the resulting document's root
element. The following
- code fragment provides an example:
- </p>
- <source>
-<![CDATA[
-ConfigurationXMLDocument configDoc = new ConfigurationXMLDocument(config);
-Document doc = configDoc.getDocument("tables", "database");
-...
-]]>
- </source>
- <p>
- The <code>Document</code> returned here contains all
data below the
- <em>tables</em> section, i.e. it will have the root
element <em>database</em>
- with three <em>table</em> elements as children. In
addition to the
- <code>getDocument()</code> methods there is also a set
of
- <code>getW3cDocument()</code> methods. These methods
act in an
- analogous way, but return a
<code>org.w3c.dom.Document</code> object
- rather than a dom4j document.
- </p>
- <p>
- Once a DOM document has been obtained the whole world
of DOM processing
- is open. Especially dom4j allows for powerful and
convenient manipulations,
- e.g. the document could be transformed using a
stylesheet or written to
- a file. If a configuration source or parts of it
should simply be saved as
- a XML document, there is an even easier way: the
<code>write()</code>
- methods of <code>ConfigurationXMLDocument</code>.
Let's assume our
- example application wants to send its database table
definitions to an
- external tool, maybe to initialize the database
schema. The following code
- shows how an XML file with this information could be
written:
- </p>
- <source>
-<![CDATA[
-ConfigurationXMLDocument configDoc = new ConfigurationXMLDocument(config);
-Writer out = null;
-try
-{
- out = new BufferedWriter(new FileWriter("tabledef.xml"));
- configDoc.write(out, "tables", "database");
-}
-finally
-{
- out.close();
-}
-]]>
- </source>
- </subsection>
- <subsection name="Calling Digester">
- <p>
- <em>Commons Digester</em> is another Apache Jakarta
project that
- implements a powerful engine for processing XML
documents. In this section
- we will make use of Digester to transform the table
definitions into a
- corresponding object model. For this tutorial the
interesting part is
- the stuff related to the communication with Digester;
more information
- about Digester and its features can be found at the
homepage of the
- Digester project.
- </p>
- <p>
- We start with with the definition of a set of beans
that will later store
- information about the database tables and their
fields. To keep this
- example short these are very simple classes with
hardly more than
- a couple of getter and setter methods. As you can see
there are
- corresponding properties for all elements that can
appear in the
- table configuration.
- </p>
- <source>
-<![CDATA[
-public class TestConfigurationXMLDocument
-{
- /** Stores the tables.*/
- private ArrayList tables;
-
- /**
- * Adds a new table object. Called by Digester.
- * @param table the new table
- */
- public void addTable(Table table)
- {
- tables.add(table);
- }
-
- /**
- * A simple bean class for storing information about a table field.
- * Used for the Digester test.
- */
- public static class TableField
- {
- private String name;
- private String type;
-
- public String getName()
- {
- return name;
- }
-
- public String getType()
- {
- return type;
- }
-
- public void setName(String string)
- {
- name = string;
- }
-
- public void setType(String string)
- {
- type = string;
- }
- }
-
- /**
- * A simple bean class for storing information about a database table.
- * Used for the Digester test.
- */
- public static class Table
- {
- /** Stores the list of fields.*/
- private ArrayList fields;
-
- /** Stores the table name.*/
- private String name;
-
- /** Stores the table type.*/
- private String tableType;
-
- public Table()
- {
- fields = new ArrayList();
- }
-
- public String getName()
- {
- return name;
- }
-
- public String getTableType()
- {
- return tableType;
- }
-
- public void setName(String string)
- {
- name = string;
- }
-
- public void setTableType(String string)
- {
- tableType = string;
- }
-
- /**
- * Adds a field.
- * @param field the new field
- */
- public void addField(TableField field)
- {
- fields.add(field);
- }
-
- /**
- * Returns the field with the given index.
- * @param idx the index
- * @return the field with this index
- */
- public TableField getField(int idx)
- {
- return (TableField) fields.get(idx);
- }
-
- /**
- * Returns the number of fields.
- * @return the number of fields
- */
- public int size()
- {
- return fields.size();
- }
- }
-}
-]]>
- </source>
- <p>
- While <code>TableField</code> is almost trivial,
<code>Table</code>
- provides the ability of storing a number of field
objects in an internal
- collection. The test class also defines a collection
that will later
- store the <code>Table</code> objects created from the
configuration.
- </p>
- <p>
- To pass the table configuration to Digester we have to
- <ol>
- <li>
- Ask our
<code>ConfigurationXMLDocument</code> instance for
- a <code>XMLReader</code> for the
<em>tables</em> section.
- </li>
- <li>
- Construct a new Digester object and
pass this XML reader to
- the constructor.
- </li>
- <li>
- Initialize the Digester instance with
the necessary processing rules
- to create a corresponding object
hierarchy for the table definitions.
- </li>
- <li>
- Call the Digester's
<code>parse()</code> method to initiate
- processing.
- </li>
- </ol>
- The following listing shows the implementation of
these steps:
- </p>
- <source>
-<![CDATA[
- public void testCallDigesterComplex() throws Exception
- {
- Digester digester =
- new Digester(configDoc.createXMLReader("tables"));
- digester.addObjectCreate("config/table", Table.class);
- digester.addSetProperties("config/table");
- digester.addCallMethod("config/table/name", "setName", 0);
- digester.addObjectCreate("config/table/fields/field", TableField.class);
- digester.addCallMethod("config/table/fields/field/name",
- "setName", 0);
- digester.addCallMethod("config/table/fields/field/type",
- "setType", 0);
- digester.addSetNext("config/table/fields/field",
- "addField", TableField.class.getName());
- digester.addSetNext("config/table", "addTable", Table.class.getName());
-
- digester.push(this);
- digester.parse("config");
- }
-]]>
- </source>
- <p>
- At the beginning of this listing
<code>createXMLReader()</code>
- is called on the <code>ConfigurationXMLDocument</code>
instance
- to obtain a SAX parser for the configuration subset
with the table
- definitions. When the Digester object is created this
parser is passed
- to its constructor.
- </p>
- <p>
- The major part of the fragment deals with setting up
the necessary
- Digester rules. Details for that can be found in the
Digester documentation.
- In short we define rules to create <code>Table</code>
and
- <code>TableField</code> objects when the corresponding
XML elements
- are detected. The newly created objects are
initialized with the
- properties defined in the XML code. Then it is ensured
that a new
- <code>TableField</code> object is added to a
<code>Table</code>
- and that for each new <code>Table</code> object the
- <code>addTable()</code> method of the test class is
invoked.
- This all conforms to the default usage pattern of
Digester, only two
- points should be noticed:
- </p>
- <p>
- <ul>
- <li>
- The match strings for all Digester
rules have the prefix
- <em>config/table</em>. The reason for
this is that the XML document
- that is generated by the SAX parser
has a corresponding structure.
- Remember when we called
<code>createXMLReader()</code>, we
- specified the string <em>tables</em>
as argument. This means that
- the resulting document will have all
the content that can be found
- in the configuration under the key
<em>tables</em>, which happens
- to be three <em>table</em> elements
with their corresponding
- children. The root element of this
document is named <em>config</em>.
- This is the default name of the root
element if no other name is
- specified. If we had called
<code>createXMLReader("tables", "tabledef")</code>,
- the root element would have been named
<em>tabledef</em> and
- we would have to use match strings of
the form <em>tabledef/table</em>.
- </li>
- <li>
- The call of the Digester's
<code>parse()</code> method is a little
- strange because we only pass in the
string <em>config</em> as
- argument. Fact is that if a
<code>XMLReader</code> obtained
- from
<code>ConfigurationXMLDocument</code> is involved, the
- parameter of the <code>parse()</code>
method is completely
- ignored. The reader always refers to
the configuration source it
- was constructed for. So we could have
used an arbitrary string.
- </li>
- </ul>
- </p>
- <p>
- After the <code>parse()</code> method returns the
<code>tables</code>
- collection of the test class contains three
<code>Table</code> objects
- with all information specified in the configuration.
- </p>
- </subsection>
- <subsection name="Calling Digester for creating simple objects">
- <p>
- If an application's configuration defines complex
objects that should
- be instantiated using Digester it will usually be
necessary to provide
- specific Digester rules as shown in the last section.
But another
- use case is to create an object whose class name is
defined in the
- configuration and to perform some simple
initialization on it.
- </p>
- <p>
- Imagine the example database application wants to open
a connection to
- a database. Because it is a very sophisticated
application it supports
- lots of different databases. To achieve this there is
an abstract
- <code>ConnectionInfo</code> class that provides
typical connect
- properties (such as user name, password and the name
of the database)
- and an abstract <code>connect()</code> method, which
establishes
- the connection to the database:
- </p>
- <source>
-<![CDATA[
- public abstract class ConnectionInfo
- {
- private String dsn;
- private String user;
- private String passwd;
-
- public String getDsn()
- {
- return dsn;
- }
-
- public String getPasswd()
- {
- return passwd;
- }
-
- public String getUser()
- {
- return user;
- }
-
- public void setDsn(String string)
- {
- dsn = string;
- }
-
- public void setPasswd(String string)
- {
- passwd = string;
- }
-
- public void setUser(String string)
- {
- user = string;
- }
-
- /**
- * Creates a connection to a database.
- * Must be defined in sub classes.
- * @return the created connection
- */
- public abstract Connection createConnection() throws SQLException;
- }
-]]>
- </source>
- <p>
- There are now some sub classes of this class, one for
each supported
- database with a proper implementation of
<code>createConnection()</code>.
- When the example application is run it does not know
from start,
- which database it has to access. Instead it determines
the database
- driver class from a configuration property, creates an
instance of it,
- and uses it to obtain a connection. For this use case
the
- <code>callDigester()</code> method of
<code>ConfigurationXMLDocument</code>
- was designed.
- </p>
- <p>
- To demonstrate this feature we start with an
additional configuration source
- that defines the connection of the database to be
used. We call it
- <code>connection.xml</code>.
- </p>
- <source>
-<![CDATA[
-<?xml version="1.0" encoding="UTF-8"?>
-<configuration>
- <connection>
- <class name="myapp.ConnectionInfoOracle">
- <property name="dsn" value="MyData"/>
- <property name="user" value="scott"/>
- <property name="passwd" value="tiger"/>
- </class>
- </connection>
-</configuration>
-]]>
- </source>
- <p>
- This configuration file shows the typical structure of
XML code
- that defines an object to be created using Digester:
There must be
- a <code>class</code> element with a <code>name</code>
attribute
- defining the full qualified name of the class to be
instantiated. In the
- body of the <code>class</code> element there can be an
arbitrary
- number of <code>property</code> elements. Each element
defines
- the name and value of a property to be set, so
Digester will call a
- corresponding setter method on the bean just created.
Here we set
- properties with the names <em>dsn, user</em> and
<em>passwd</em>.
- As you can see, our <code>ConnectionInfo</code> base
class has
- getter and setter methods for exactly these
properties. We have now to
- include this additional configuration file in our
configuration definition file:
- </p>
- <source>
-<![CDATA[
-<?xml version="1.0" encoding="ISO-8859-1" ?>
-<!-- Configuration definition file that demonstrates the
- override and additional sections -->
-
-<configuration>
- <override>
- <properties fileName="usergui.properties"/>
- <dom4j fileName="gui.xml"/>
- </override>
-
- <additional>
- <hierarchicalDom4j fileName="tables.xml"/>
- <hierarchicalDom4j fileName="tasktables.xml" at="tables"/>
- <hierarchicalDom4j fileName="connection.xml"/>
- </additional>
-</configuration>
-]]>
- </source>
- <p>
- After that it is now quite easy to obtain an object
with information
- about a database connection. The following code
fragment shows
- how a connection can be opened (it assumes that the
<code>Configuration</code>
- object obtained from the configuration factory is
stored in a variable named
- <code>config</code>).
- </p>
- <source>
-<![CDATA[
-ConfigurationXMLDocument configDoc = new ConfigurationXMLDocument(config);
-ConnectionInfo connInfo = (ConnectionInfo) configDoc.callDigester("connection");
-Connection conn = connInfo.createConnection();
-]]>
- </source>
- </subsection>
- <subsection name="Some caveats">
- <p>
- At the end of this section about
<code>ConfigurationXMLDocument</code>
- some notes about points a developer should be aware of
are provided:
- </p>
- <p>
- <ul>
- <li>
- The class should not be used on the
<code>Configuration</code>
- object obtained from
<code>ConfigurationFactory</code> as a
- whole. Because this configuration can
contain multiple configuration
- sources including those that override
other properties the results
- are probably not what you expect. You
can of course pass such a
- composite configuration to the
constructor of
- <code>ConfigurationXMLDocument</code>,
but you should then,
- when you call methods on this
instance, always provide a
- configuration key that selects certain
parts of the configuration.
- </li>
- <li>
- The XML processing abilities of the
class naturally work best
- when a
<code>HierarchicalConfiguration</code> object is
- involved. There is also support for
other types of configuration
- sources, but this will work well only
for very simple properties.
- The problem here is the loss of
information concerning the
- structure of the properties (as was
explained in an earlier secion).
- So if you read a configuration source
- using the <code>dom4j</code> element
rather than the
- <code>hierarchicalDom4j</code>
element, XML documents
- generated by
<code>ConfigurationXMLDocument</code> may
- look wired; the same is true for
<code>properties</code>
- elements.
- </li>
- <li>
- If you read a XML configuration file
and then save it again
- using
<code>ConfigurationXMLDocument.write()</code> the
- result is not guaranteed to be identic
to the original file.
- While the document structure is kept
(i.e. the relation between
- elements and their children), there
may be differences in the
- order in which elements are written.
- </li>
- </ul>
- </p>
- </subsection>
</section>
</body>
1.2 +6 -6 jakarta-commons/configuration/xdocs/overview.xml
Index: overview.xml
===================================================================
RCS file: /home/cvs/jakarta-commons/configuration/xdocs/overview.xml,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- overview.xml 23 Dec 2003 15:09:05 -0000 1.1
+++ overview.xml 16 Jan 2004 14:56:45 -0000 1.2
@@ -67,9 +67,9 @@
<?xml version="1.0" encoding="ISO-8859-1" ?>
<configuration>
- <jndi prefix="java:comp/env"/>
- <properties fileName="conf/test.properties"/>
- <dom4j fileName="conf/test.xml"/>
+ <jndi className="org.apache.commons.configuration.JNDIConfiguration"
prefix="java:comp/env"/>
+ <properties className="org.apache.commons.configuration.PropertiesConfiguration"
fileName="conf/test.properties"/>
+ <dom4j className="org.apache.commons.configuration.DOM4JConfiguration"
fileName="conf/test.xml"/>
</configuration>
]]>
</source>
@@ -96,7 +96,7 @@
<subsection name="Classic Properties File">
<source>
<![CDATA[
- <properties fileName="conf/test.properties"/>
+ <properties className="org.apache.commons.configuration.PropertiesConfiguration"
fileName="conf/test.properties"/>
]]>
</source>
<p>
@@ -106,7 +106,7 @@
<subsection name="XML Properties File">
<source>
<![CDATA[
- <dom4j fileName="conf/test.xml"/>
+ <dom4j className="org.apache.commons.configuration.DOM4JConfiguration"
fileName="conf/test.xml"/>
]]>
</source>
<p>
@@ -136,7 +136,7 @@
<subsection name="JNDI Properties File">
<source>
<![CDATA[
- <jndi prefix="java:comp/env"/>
+ <jndi className="org.apache.commons.configuration.JNDIConfiguration"
prefix="java:comp/env"/>
]]>
</source>
<p>
1.3 +2 -6
jakarta-commons/configuration/src/java/org/apache/commons/configuration/CompositeConfiguration.java
Index: CompositeConfiguration.java
===================================================================
RCS file:
/home/cvs/jakarta-commons/configuration/src/java/org/apache/commons/configuration/CompositeConfiguration.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- CompositeConfiguration.java 24 Dec 2003 14:28:22 -0000 1.2
+++ CompositeConfiguration.java 16 Jan 2004 14:56:45 -0000 1.3
@@ -271,8 +271,6 @@
{
CompositeConfiguration subsetCompositeConfiguration =
new CompositeConfiguration();
- Configuration subConf = null;
- int count = 0;
for (ListIterator i = configList.listIterator(); i.hasNext();)
{
Configuration config = (Configuration) i.next();
@@ -280,11 +278,9 @@
if (subset != null)
{
subsetCompositeConfiguration.addConfiguration(subset);
- subConf = subset;
- count++;
}
}
- return (count == 1) ? subConf : subsetCompositeConfiguration;
+ return subsetCompositeConfiguration;
}
/**
* Get a float associated with the given configuration key.
1.3 +18 -11
jakarta-commons/configuration/src/java/org/apache/commons/configuration/ConfigurationFactory.java
Index: ConfigurationFactory.java
===================================================================
RCS file:
/home/cvs/jakarta-commons/configuration/src/java/org/apache/commons/configuration/ConfigurationFactory.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- ConfigurationFactory.java 24 Dec 2003 14:28:22 -0000 1.2
+++ ConfigurationFactory.java 16 Jan 2004 14:56:45 -0000 1.3
@@ -291,12 +291,6 @@
additional);
setupDigesterInstance(
digester,
- matchString + "hierarchicalDom4j",
- new BasePathConfigurationFactory(HierarchicalDOM4JConfiguration.class),
- METH_LOAD,
- additional);
- setupDigesterInstance(
- digester,
matchString + "jndi",
new JNDIConfigurationFactory(),
null,
@@ -418,13 +412,17 @@
/**
* A base class for digester factory classes. This base class maintains
- * a default class for the objects to be created.
+ * a default class for the objects to be created. It also supports a
+ * <code>className</code> attribute for specifying a different class.
* There will be sub classes for specific configuration implementations.
*/
public class DigesterConfigurationFactory
extends AbstractObjectCreationFactory
implements ObjectCreationFactory
{
+ /** Constant for the className attribute.*/
+ protected static final String ATTR_CLASSNAME = "className";
+
/** Actual class to use. */
private Class clazz;
@@ -438,14 +436,23 @@
}
/**
- * Creates an instance of the specified class.
- * @param attribs the attributes (ignored)
+ * Creates an instance of the specified class. If the passed in
+ * attributes contain a <code>className</code> attribute, the value of
+ * this attribute is interpreted as the full qualified class name of
+ * the class to be instantiated. Otherwise the default class is used.
+ * @param attribs the attributes
* @return the new object
* @exception Exception if object creation fails
*/
public Object createObject(Attributes attribs) throws Exception
{
- return clazz.newInstance();
+ Class actCls;
+
+ int idx = attribs.getIndex(ATTR_CLASSNAME);
+ actCls = (idx < 0) ? clazz :
+ Class.forName(attribs.getValue(idx));
+
+ return actCls.newInstance();
}
}
1.2 +2 -2
jakarta-commons/configuration/conf/testDigesterConfiguration2.xml
Index: testDigesterConfiguration2.xml
===================================================================
RCS file:
/home/cvs/jakarta-commons/configuration/conf/testDigesterConfiguration2.xml,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- testDigesterConfiguration2.xml 23 Dec 2003 15:09:05 -0000 1.1
+++ testDigesterConfiguration2.xml 16 Jan 2004 14:56:45 -0000 1.2
@@ -4,8 +4,8 @@
<configuration>
<additional>
- <hierarchicalDom4j fileName="testHierarchicalDOM4JConfiguration.xml"/>
- <hierarchicalDom4j fileName="testDigesterConfigurationInclude1.xml"
at="tables"/>
+ <dom4j
className="org.apache.commons.configuration.HierarchicalDOM4JConfiguration"
fileName="testHierarchicalDOM4JConfiguration.xml"/>
+ <dom4j
className="org.apache.commons.configuration.HierarchicalDOM4JConfiguration"
fileName="testDigesterConfigurationInclude1.xml" at="tables"/>
<properties fileName="testDigesterConfigurationInclude2.properties" at="mail"/>
</additional>
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]