Author: oheger
Date: Thu Jan 5 07:34:20 2006
New Revision: 366201
URL: http://svn.apache.org/viewcvs?rev=366201&view=rev
Log:
Incorporated new expression engine classes into HierarchicalConfiguration; this
class now supports pluggable expression engines.
Added:
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ConfigurationNodeVisitorAdapter.java
(with props)
Modified:
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/HierarchicalConfiguration.java
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestHierarchicalConfiguration.java
Modified:
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/HierarchicalConfiguration.java
URL:
http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/HierarchicalConfiguration.java?rev=366201&r1=366200&r2=366201&view=diff
==============================================================================
---
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/HierarchicalConfiguration.java
(original)
+++
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/HierarchicalConfiguration.java
Thu Jan 5 07:34:20 2006
@@ -27,7 +27,12 @@
import org.apache.commons.collections.set.ListOrderedSet;
import org.apache.commons.collections.iterators.SingletonIterator;
+import org.apache.commons.configuration.tree.ConfigurationNode;
+import org.apache.commons.configuration.tree.ConfigurationNodeVisitorAdapter;
import org.apache.commons.configuration.tree.DefaultConfigurationNode;
+import org.apache.commons.configuration.tree.DefaultExpressionEngine;
+import org.apache.commons.configuration.tree.ExpressionEngine;
+import org.apache.commons.configuration.tree.NodeAddData;
import org.apache.commons.lang.StringUtils;
/**
@@ -95,12 +100,15 @@
*/
public class HierarchicalConfiguration extends AbstractConfiguration
implements Serializable, Cloneable
{
- /** Constant for a new dummy key. */
- private static final String NEW_KEY = "newKey";
+ /** Stores the default expression engine to be used for new objects.*/
+ private static ExpressionEngine defaultExpressionEngine = new
DefaultExpressionEngine();
/** Stores the root node of this configuration. */
private Node root = new Node();
+ /** Stores the expression engine for this instance.*/
+ private ExpressionEngine expressionEngine;
+
/**
* Returns the root node of this hierarchical configuration.
*
@@ -126,8 +134,66 @@
}
/**
- * Fetches the specified property. Performs a recursive lookup in the tree
- * with the configuration properties.
+ * Returns the default expression engine.
+ *
+ * @return the default expression engine
+ * @since 1.3
+ */
+ public static ExpressionEngine getDefaultExpressionEngine()
+ {
+ return defaultExpressionEngine;
+ }
+
+ /**
+ * Sets the default expression engine. This expression engine will be used
+ * if no specific engine was set for an instance. It is shared between all
+ * hierarchical configuration instances. So modifying its properties will
+ * impact all instances, for which no specific engine is set.
+ *
+ * @param engine the new default expression engine
+ * @since 1.3
+ */
+ public static void setDefaultExpressionEngine(ExpressionEngine engine)
+ {
+ if (engine == null)
+ {
+ throw new IllegalArgumentException(
+ "Default expression engine must not be null!");
+ }
+ defaultExpressionEngine = engine;
+ }
+
+ /**
+ * Returns the expression engine used by this configuration. This method
+ * will never return <b>null</b>; if no specific expression engine was set,
+ * the default expression engine will be returned.
+ *
+ * @return the current expression engine
+ * @since 1.3
+ */
+ public ExpressionEngine getExpressionEngine()
+ {
+ return (expressionEngine != null) ? expressionEngine
+ : getDefaultExpressionEngine();
+ }
+
+ /**
+ * Sets the expression engine to be used by this configuration. All
property
+ * keys this configuration has to deal with will be interpreted by this
+ * engine.
+ *
+ * @param expressionEngine the new expression engine; can be <b>null</b>,
+ * then the default expression engine will be used
+ * @since 1.3
+ */
+ public void setExpressionEngine(ExpressionEngine expressionEngine)
+ {
+ this.expressionEngine = expressionEngine;
+ }
+
+ /**
+ * Fetches the specified property. This task is delegated to the associated
+ * expression engine.
*
* @param key the key to be looked up
* @return the found value
@@ -164,92 +230,18 @@
}
/**
- * <p>Adds the property with the specified key.</p><p>To be able to deal
- * with the structure supported by this configuration implementation the
- * passed in key is of importance, especially the indices it might contain.
- * The following example should clearify this: Suppose the actual
- * configuration contains the following elements:</p><p>
- *
- * <pre>
- * tables
- * +-- table
- * +-- name = user
- * +-- fields
- * +-- field
- * +-- name = uid
- * +-- field
- * +-- name = firstName
- * ...
- * +-- table
- * +-- name = documents
- * +-- fields
- * ...
- * </pre>
- *
- * </p><p>In this example a database structure is defined, e.g. all fields
- * of the first table could be accessed using the key
- * <code>tables.table(0).fields.field.name</code>. If now properties are
- * to be added, it must be exactly specified at which position in the
- * hierarchy the new property is to be inserted. So to add a new field name
- * to a table it is not enough to say just</p><p>
- *
- * <pre>
- * config.addProperty("tables.table.fields.field.name", "newField");
- * </pre>
- *
- * </p><p>The statement given above contains some ambiguity. For instance
- * it is not clear, to which table the new field should be added. If this
- * method finds such an ambiguity, it is resolved by following the last
- * valid path. Here this would be the last table. The same is true for the
- * <code>field</code>; because there are multiple fields and no explicit
- * index is provided, a new <code>name</code> property would be added to
- * the last field - which is propably not what was desired.</p><p>To make
- * things clear explicit indices should be provided whenever possible. In
- * the example above the exact table could be specified by providing an
- * index for the <code>table</code> element as in
- * <code>tables.table(1).fields</code>. By specifying an index it can
- * also be expressed that at a given position in the configuration tree a
- * new branch should be added. In the example above we did not want to add
- * an additional <code>name</code> element to the last field of the table,
- * but we want a complete new <code>field</code> element. This can be
- * achieved by specifying an invalid index (like -1) after the element
where
- * a new branch should be created. Given this our example would run:</p>
- * <p>
- *
- * <pre>
- * config.addProperty("tables.table(1).fields.field(-1).name", "newField");
- * </pre>
- *
- * </p><p>With this notation it is possible to add new branches
- * everywhere. We could for instance create a new <code>table</code>
- * element by specifying</p><p>
- *
- * <pre>
- * config.addProperty("tables.table(-1).fields.field.name", "newField2");
- * </pre>
- *
- * </p><p>(Note that because after the <code>table</code> element a new
- * branch is created indices in following elements are not relevant; the
- * branch is new so there cannot be any ambiguities.)</p>
+ * Adds the property with the specified key. This task will be delegated to
+ * the associated <code>ExpressionEngine</code>, so the passed in key
+ * must match the requirements of this implementation.
*
* @param key the key of the new property
* @param obj the value of the new property
*/
protected void addPropertyDirect(String key, Object obj)
{
- ConfigurationKey.KeyIterator it = new ConfigurationKey(key).iterator();
- Node parent = fetchAddNode(it, getRoot());
-
- Node child = createNode(it.currentKey(false));
- child.setValue(obj);
- if (it.isAttribute())
- {
- parent.addAttribute(child);
- }
- else
- {
- parent.addChild(child);
- }
+ NodeAddData data = getExpressionEngine().prepareAdd(getRoot(), key);
+ ConfigurationNode node = processNodeAddData(data);
+ node.setValue(obj);
}
/**
@@ -258,7 +250,9 @@
* instead of a single property a whole collection of nodes can be added -
* and thus complete configuration sub trees. E.g. with this method it is
* possible to add parts of another <code>HierarchicalConfiguration</code>
- * object to this object.
+ * object to this object. If the passed in key refers to an existing and
+ * unique node, the new nodes are added to this node. Otherwise a new node
+ * will be created at the specified position in the hierarchy.
*
* @param key the key where the nodes are to be added; can be <b>null </b>,
* then they are added to the root node
@@ -272,26 +266,36 @@
return;
}
- Node parent;
- if (StringUtils.isEmpty(key))
+ ConfigurationNode parent;
+ List target = fetchNodeList(key);
+ if (target.size() == 1)
{
- parent = getRoot();
+ // existing unique key
+ parent = (ConfigurationNode) target.get(0);
}
else
{
- ConfigurationKey.KeyIterator kit = new
ConfigurationKey(key).iterator();
- parent = fetchAddNode(kit, getRoot());
-
- // fetchAddNode() does not really fetch the last component,
- // but one before. So we must perform an additional step.
- ConfigurationKey keyNew = new
ConfigurationKey(kit.currentKey(true));
- keyNew.append(NEW_KEY);
- parent = fetchAddNode(keyNew.iterator(), parent);
+ // otherwise perform an add operation
+ parent = processNodeAddData(getExpressionEngine().prepareAdd(
+ getRoot(), key));
}
+ if (parent.isAttribute())
+ {
+ throw new IllegalArgumentException(
+ "Cannot add nodes to an attribute node!");
+ }
for (Iterator it = nodes.iterator(); it.hasNext();)
{
- parent.addChild((Node) it.next());
+ ConfigurationNode child = (ConfigurationNode) it.next();
+ if (child.isAttribute())
+ {
+ parent.addAttribute(child);
+ }
+ else
+ {
+ parent.addChild(child);
+ }
}
}
@@ -440,7 +444,7 @@
public Iterator getKeys()
{
DefinedKeysVisitor visitor = new DefinedKeysVisitor();
- getRoot().visit(visitor, new ConfigurationKey());
+ getRoot().visit(visitor);
return visitor.getKeyList().iterator();
}
@@ -457,18 +461,17 @@
{
DefinedKeysVisitor visitor = new DefinedKeysVisitor(prefix);
List nodes = fetchNodeList(prefix);
- ConfigurationKey key = new ConfigurationKey();
for (Iterator itNodes = nodes.iterator(); itNodes.hasNext();)
{
Node node = (Node) itNodes.next();
for (Iterator it = node.getChildren().iterator(); it.hasNext();)
{
- ((Node) it.next()).visit(visitor, key);
+ ((Node) it.next()).visit(visitor);
}
for (Iterator it = node.getAttributes().iterator(); it.hasNext();)
{
- ((Node) it.next()).visit(visitor, key);
+ ((Node) it.next()).visit(visitor);
}
}
@@ -526,9 +529,7 @@
*/
protected List fetchNodeList(String key)
{
- List nodes = new LinkedList();
- findPropertyNodes(new ConfigurationKey(key).iterator(), getRoot(),
nodes);
- return nodes;
+ return getExpressionEngine().query(getRoot(), key);
}
/**
@@ -539,33 +540,14 @@
* @param keyPart the configuration key iterator
* @param node the actual node
* @param nodes here the found nodes are stored
+ * @deprecated Property keys are now evaluated by the expression engine
+ * associated with the configuration; this method will no longer be called.
+ * If you want to modify the way properties are looked up, consider
+ * implementing you own <code>ExpressionEngine</code> implementation.
*/
- protected void findPropertyNodes(ConfigurationKey.KeyIterator keyPart,
Node node, Collection nodes)
+ protected void findPropertyNodes(ConfigurationKey.KeyIterator keyPart,
+ Node node, Collection nodes)
{
- if (!keyPart.hasNext())
- {
- nodes.add(node);
- }
- else
- {
- String key = keyPart.nextKey(false);
- List children = keyPart.isAttribute() ? node.getAttributes(key) :
node.getChildren(key);
- if (keyPart.hasIndex())
- {
- if (keyPart.getIndex() < children.size() && keyPart.getIndex()
>= 0)
- {
- findPropertyNodes((ConfigurationKey.KeyIterator)
keyPart.clone(), (Node) children.get(keyPart
- .getIndex()), nodes);
- }
- }
- else
- {
- for (Iterator it = children.iterator(); it.hasNext();)
- {
- findPropertyNodes((ConfigurationKey.KeyIterator)
keyPart.clone(), (Node) it.next(), nodes);
- }
- }
- }
}
/**
@@ -624,15 +606,15 @@
* @param keyIt the iterator for the key of the new property
* @param startNode the node to start the search with
* @return the parent node for the add operation
+ * @deprecated Adding new properties is now to a major part delegated to
the
+ * <code>ExpressionEngine</code> associated with this configuration
instance.
+ * This method will no longer be called. Developers who want to modify the
+ * process of adding new properties should consider implementing their own
+ * expression engine.
*/
protected Node fetchAddNode(ConfigurationKey.KeyIterator keyIt, Node
startNode)
{
- if (!keyIt.hasNext())
- {
- throw new IllegalArgumentException("Key must be defined!");
- }
-
- return createAddPath(keyIt, findLastPathNode(keyIt, startNode));
+ return null;
}
/**
@@ -643,29 +625,15 @@
* @param keyIt the key iterator
* @param node the actual node
* @return the last existing node on the given path
+ * @deprecated Adding new properties is now to a major part delegated to
the
+ * <code>ExpressionEngine</code> associated with this configuration
instance.
+ * This method will no longer be called. Developers who want to modify the
+ * process of adding new properties should consider implementing their own
+ * expression engine.
*/
protected Node findLastPathNode(ConfigurationKey.KeyIterator keyIt, Node
node)
{
- String keyPart = keyIt.nextKey(false);
-
- if (keyIt.hasNext())
- {
- List list = keyIt.isAttribute() ? node.getAttributes(keyPart) :
node.getChildren(keyPart);
- int idx = (keyIt.hasIndex()) ? keyIt.getIndex() : list.size() - 1;
- if (idx < 0 || idx >= list.size())
- {
- return node;
- }
- else
- {
- return findLastPathNode(keyIt, (Node) list.get(idx));
- }
- }
-
- else
- {
- return node;
- }
+ return null;
}
/**
@@ -676,21 +644,15 @@
* @param keyIt the key iterator
* @param root the base node of the path to be created
* @return the last node of the path
+ * @deprecated Adding new properties is now to a major part delegated to
the
+ * <code>ExpressionEngine</code> associated with this configuration
instance.
+ * This method will no longer be called. Developers who want to modify the
+ * process of adding new properties should consider implementing their own
+ * expression engine.
*/
protected Node createAddPath(ConfigurationKey.KeyIterator keyIt, Node root)
{
- if (keyIt.hasNext())
- {
- Node child = createNode(keyIt.currentKey(false));
- child.setAttribute(keyIt.isAttribute());
- root.addChild(child);
- keyIt.next();
- return createAddPath(keyIt, child);
- }
- else
- {
- return root;
- }
+ return null;
}
/**
@@ -708,6 +670,39 @@
}
/**
+ * Helper method for processing a node add data object obtained from the
+ * expression engine. This method will create all new nodes.
+ *
+ * @param data the data object
+ * @return the new node
+ * @since 1.3
+ */
+ private ConfigurationNode processNodeAddData(NodeAddData data)
+ {
+ ConfigurationNode node = data.getParent();
+
+ // Create missing nodes on the path
+ for (Iterator it = data.getPathNodes().iterator(); it.hasNext();)
+ {
+ ConfigurationNode child = createNode((String) it.next());
+ node.addChild(child);
+ node = child;
+ }
+
+ // Add new target node
+ ConfigurationNode child = createNode(data.getNewNodeName());
+ if (data.isAttribute())
+ {
+ node.addAttribute(child);
+ }
+ else
+ {
+ node.addChild(child);
+ }
+ return child;
+ }
+
+ /**
* A data class for storing (hierarchical) property information. A property
* can have a value and an arbitrary number of child properties. From
version 1.3 on this class
* is only a thin wrapper over the <code>[EMAIL PROTECTED]
org.apache.commons.configuration.tree.DefaultConfigurationNode
DefaultconfigurationNode}</code>
@@ -947,15 +942,14 @@
/**
* A specialized visitor that fills a list with keys that are defined in a
* node hierarchy.
- *
*/
- static class DefinedKeysVisitor extends NodeVisitor
+ class DefinedKeysVisitor extends ConfigurationNodeVisitorAdapter
{
/** Stores the list to be filled. */
private Set keyList;
- /** Stores a prefix for the keys. */
- private String prefix;
+ /** A stack with the keys of the already processed nodes. */
+ private Stack parentKeys;
/**
* Default constructor.
@@ -963,6 +957,7 @@
public DefinedKeysVisitor()
{
keyList = new ListOrderedSet();
+ parentKeys = new Stack();
}
/**
@@ -974,7 +969,7 @@
public DefinedKeysVisitor(String prefix)
{
this();
- this.prefix = prefix;
+ parentKeys.push(prefix);
}
/**
@@ -988,40 +983,31 @@
}
/**
- * Visits the specified node. If this node has a value, its key is
added
- * to the internal list.
+ * Visits the node after its children has been processed. Removes this
+ * node's key from the stack.
*
- * @param node the node to be visited
- * @param key the key of this node
+ * @param node the node
*/
- public void visitBeforeChildren(Node node, ConfigurationKey key)
+ public void visitAfterChildren(ConfigurationNode node)
{
- if (node.getValue() != null && key != null)
- {
- addKey(key);
- }
+ parentKeys.pop();
}
/**
- * Adds the specified key to the internal list.
+ * Visits the specified node. If this node has a value, its key is
added
+ * to the internal list.
*
- * @param key the key to add
+ * @param node the node to be visited
*/
- protected void addKey(ConfigurationKey key)
+ public void visitBeforeChildren(ConfigurationNode node)
{
- if (prefix == null)
- {
- keyList.add(key.toString());
- }
- else
+ String parentKey = parentKeys.isEmpty() ? null
+ : (String) parentKeys.peek();
+ String key = getExpressionEngine().nodeKey(node, parentKey);
+ parentKeys.push(key);
+ if (node.getValue() != null)
{
- StringBuffer buf = new StringBuffer(prefix);
- if (!key.isAttributeKey())
- {
- buf.append(ConfigurationKey.PROPERTY_DELIMITER);
- }
- buf.append(key);
- keyList.add(buf.toString());
+ keyList.add(key);
}
}
}
Added:
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ConfigurationNodeVisitorAdapter.java
URL:
http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ConfigurationNodeVisitorAdapter.java?rev=366201&view=auto
==============================================================================
---
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ConfigurationNodeVisitorAdapter.java
(added)
+++
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ConfigurationNodeVisitorAdapter.java
Thu Jan 5 07:34:20 2006
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2005-2006 The Apache Software Foundation.
+ *
+ * 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.apache.commons.configuration.tree;
+
+/**
+ * <p>
+ * A simple adapter class that simplyfies writing custom node visitor
+ * implementations.
+ * </p>
+ * <p>
+ * This class provides dummy implementations for the methods defined in the
+ * <code>ConfigurationNodeVisitor</code> interface. Derived classes only need
+ * to override the methods they really need.
+ * </p>
+ *
+ * @author Oliver Heger
+ */
+public class ConfigurationNodeVisitorAdapter implements
+ ConfigurationNodeVisitor
+{
+ /**
+ * Empty dummy implementation of this interface method.
+ *
+ * @param node the node
+ */
+ public void visitBeforeChildren(ConfigurationNode node)
+ {
+ }
+
+ /**
+ * Empty dummy implementation of this interface method.
+ *
+ * @param node the node
+ */
+ public void visitAfterChildren(ConfigurationNode node)
+ {
+ }
+
+ /**
+ * Dummy implementation of this interface method. Returns always
<b>false</b>.
+ *
+ * @return the terminate flag
+ */
+ public boolean terminate()
+ {
+ return false;
+ }
+}
Propchange:
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ConfigurationNodeVisitorAdapter.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ConfigurationNodeVisitorAdapter.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange:
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ConfigurationNodeVisitorAdapter.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified:
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestHierarchicalConfiguration.java
URL:
http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestHierarchicalConfiguration.java?rev=366201&r1=366200&r2=366201&view=diff
==============================================================================
---
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestHierarchicalConfiguration.java
(original)
+++
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestHierarchicalConfiguration.java
Thu Jan 5 07:34:20 2006
@@ -1,5 +1,5 @@
/*
- * Copyright 2001-2005 The Apache Software Foundation.
+ * Copyright 2001-2006 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License")
* you may not use this file except in compliance with the License.
@@ -23,7 +23,10 @@
import java.util.List;
import java.util.Set;
+import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.configuration.HierarchicalConfiguration.Node;
+import org.apache.commons.configuration.tree.DefaultExpressionEngine;
+import org.apache.commons.configuration.tree.ExpressionEngine;
import junit.framework.TestCase;
@@ -387,18 +390,44 @@
assertEquals("birthDate",
config.getString("tables.table(0).fields.field(5).name"));
assertEquals("lastLogin",
config.getString("tables.table(0).fields.field(6).name"));
assertEquals("language",
config.getString("tables.table(0).fields.field(7).name"));
+ }
+
+ /**
+ * Tests the addNodes() method when the provided key does not exist. In
+ * this case, a new node (or even a complete new branch) will be created.
+ */
+ public void testAddNodesForNonExistingKey()
+ {
+ Collection nodes = new ArrayList();
+ nodes.add(createNode("usr", "scott"));
+ Node nd = createNode("pwd", "tiger");
+ nd.setAttribute(true);
+ nodes.add(nd);
+ config.addNodes("database.connection.settings", nodes);
+ assertEquals("Usr node not found", "scott",
config.getString("database.connection.settings.usr"));
+ assertEquals("Pwd node not found", "tiger", config.getString("[EMAIL
PROTECTED]"));
+ }
+
+ /**
+ * Tests the addNodes() method when the new nodes should be added to an
+ * attribute node. This is not allowed.
+ */
+ public void testAddNodesWithAttributeKey()
+ {
+ Collection nodes = new ArrayList();
+ nodes.add(createNode("testNode", "yes"));
try
{
- config.addNodes(".", nodes);
- fail("Could use empty key!");
+ config.addNodes("[EMAIL PROTECTED]", nodes);
+ fail("Could add nodes to an attribute node!");
}
catch(IllegalArgumentException iex)
{
//ok
}
}
-
+
/**
* Tests removing children from a configuration node.
*/
@@ -452,6 +481,49 @@
}
/**
+ * Tests setting a custom expression engine, which uses a slightly
different
+ * syntax.
+ */
+ public void testSetExpressionEngine()
+ {
+ config.setExpressionEngine(null);
+ assertNotNull("Expression engine is null",
config.getExpressionEngine());
+ assertSame("Default engine is not used", HierarchicalConfiguration
+ .getDefaultExpressionEngine(), config.getExpressionEngine());
+
+ config.setExpressionEngine(createAlternativeExpressionEngine());
+ checkAlternativeSyntax();
+ }
+
+ /**
+ * Tests setting the default expression engine. This should impact all
+ * configuration instances that do not have their own engine.
+ */
+ public void testSetDefaultExpressionEngine()
+ {
+ HierarchicalConfiguration
+
.setDefaultExpressionEngine(createAlternativeExpressionEngine());
+ checkAlternativeSyntax();
+ }
+
+ /**
+ * Tests setting the default expression engine to null. This should not be
+ * allowed.
+ */
+ public void testSetDefaultExpressionEngineNull()
+ {
+ try
+ {
+ HierarchicalConfiguration.setDefaultExpressionEngine(null);
+ fail("Could set default expression engine to null!");
+ }
+ catch (IllegalArgumentException iex)
+ {
+ // ok
+ }
+ }
+
+ /**
* Helper method for testing the getKeys(String) method.
* @param prefix the key to pass into getKeys()
* @param expected the expected result
@@ -482,7 +554,52 @@
}
/**
+ * Helper method for checking keys using an alternative syntax.
+ */
+ private void checkAlternativeSyntax()
+ {
+ assertNull(config.getProperty("tables/table/resultset"));
+ assertNull(config.getProperty("tables/table/fields/field"));
+
+ Object prop = config.getProperty("tables/table[0]/fields/field/name");
+ assertNotNull(prop);
+ assertTrue(prop instanceof Collection);
+ assertEquals(5, ((Collection) prop).size());
+
+ prop = config.getProperty("tables/table/fields/field/name");
+ assertNotNull(prop);
+ assertTrue(prop instanceof Collection);
+ assertEquals(10, ((Collection) prop).size());
+
+ prop = config.getProperty("tables/table/fields/field[3]/name");
+ assertNotNull(prop);
+ assertTrue(prop instanceof Collection);
+ assertEquals(2, ((Collection) prop).size());
+
+ prop = config.getProperty("tables/table[1]/fields/field[2]/name");
+ assertNotNull(prop);
+ assertEquals("creationDate", prop.toString());
+
+ Set keys = new HashSet();
+ CollectionUtils.addAll(keys, config.getKeys());
+ assertEquals("Wrong number of defined keys", 2, keys.size());
+ assertTrue("Key not found", keys.contains("tables/table/name"));
+ assertTrue("Key not found", keys
+ .contains("tables/table/fields/field/name"));
+ }
+
+ private ExpressionEngine createAlternativeExpressionEngine()
+ {
+ DefaultExpressionEngine engine = new DefaultExpressionEngine();
+ engine.setPropertyDelimiter("/");
+ engine.setIndexStart("[");
+ engine.setIndexEnd("]");
+ return engine;
+ }
+
+ /**
* Helper method for creating a field node with its children.
+ *
* @param name the name of the field
* @return the field node
*/
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]