Class DefaultExpressionEngine
- java.lang.Object
-
- org.apache.commons.configuration.tree.DefaultExpressionEngine
-
- All Implemented Interfaces:
ExpressionEngine
public class DefaultExpressionEngine extends java.lang.Object implements ExpressionEngine
A default implementation of the
ExpressionEngine
interface providing the "native"e; expression language for hierarchical configurations.This class implements a rather simple expression language for navigating through a hierarchy of configuration nodes. It supports the following operations:
- Navigating from a node to one of its children using the child node delimiter, which is by the default a dot (".").
- Navigating from a node to one of its attributes using the attribute node
delimiter, which by default follows the XPATH like syntax
[@<attributeName>]
. - If there are multiple child or attribute nodes with the same name, a specific node can be selected using a numerical index. By default indices are written in parenthesis.
As an example consider the following XML document:
<database> <tables> <table type="system"> <name>users</name> <fields> <field> <name>lid</name> <type>long</name> </field> <field> <name>usrName</name> <type>java.lang.String</type> </field> ... </fields> </table> <table> <name>documents</name> <fields> <field> <name>docid</name> <type>long</type> </field> ... </fields> </table> ... </tables> </database>
If this document is parsed and stored in a hierarchical configuration object, for instance the key
tables.table(0).name
can be used to find out the name of the first table. In oppositetables.table.name
would return a collection with the names of all available tables. Similarly the keytables.table(1).fields.field.name
returns a collection with the names of all fields of the second table. If another index is added after thefield
element, a single field can be accessed:tables.table(1).fields.field(0).name
. The keytables.table(0)[@type]
would select the type attribute of the first table.This example works with the default values for delimiters and index markers. It is also possible to set custom values for these properties so that you can adapt a
DefaultExpressionEngine
to your personal needs.- Since:
- 1.3
- Version:
- $Id: DefaultExpressionEngine.java 1301991 2012-03-17 20:18:02Z sebb $
- Author:
- Commons Configuration team
-
-
Field Summary
Fields Modifier and Type Field Description static java.lang.String
DEFAULT_ATTRIBUTE_END
Constant for the default attribute end marker.static java.lang.String
DEFAULT_ATTRIBUTE_START
Constant for the default attribute start marker.static java.lang.String
DEFAULT_ESCAPED_DELIMITER
Constant for the default escaped property delimiter.static java.lang.String
DEFAULT_INDEX_END
Constant for the default index end marker.static java.lang.String
DEFAULT_INDEX_START
Constant for the default index start marker.static java.lang.String
DEFAULT_PROPERTY_DELIMITER
Constant for the default property delimiter.
-
Constructor Summary
Constructors Constructor Description DefaultExpressionEngine()
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description protected ConfigurationNode
findLastPathNode(DefaultConfigurationKey.KeyIterator keyIt, ConfigurationNode node)
Finds the last existing node for an add operation.protected void
findNodesForKey(DefaultConfigurationKey.KeyIterator keyPart, ConfigurationNode node, java.util.Collection<ConfigurationNode> nodes)
Recursive helper method for evaluating a key.java.lang.String
getAttributeEnd()
Sets the attribute end marker.java.lang.String
getAttributeStart()
Returns the attribute start marker.java.lang.String
getEscapedDelimiter()
Returns the escaped property delimiter string.java.lang.String
getIndexEnd()
Returns the index end marker.java.lang.String
getIndexStart()
Returns the index start marker.java.lang.String
getPropertyDelimiter()
Returns the property delimiter.java.lang.String
nodeKey(ConfigurationNode node, java.lang.String parentKey)
Determines the key of the passed in node.NodeAddData
prepareAdd(ConfigurationNode root, java.lang.String key)
Prepares Adding the property with the specified key.java.util.List<ConfigurationNode>
query(ConfigurationNode root, java.lang.String key)
Evaluates the given key and returns all matching nodes.void
setAttributeEnd(java.lang.String attributeEnd)
Sets the attribute end marker.void
setAttributeStart(java.lang.String attributeStart)
Sets the attribute start marker.void
setEscapedDelimiter(java.lang.String escapedDelimiter)
Sets the escaped property delimiter string.void
setIndexEnd(java.lang.String indexEnd)
Sets the index end marker.void
setIndexStart(java.lang.String indexStart)
Sets the index start marker.void
setPropertyDelimiter(java.lang.String propertyDelimiter)
Sets the property delimiter.
-
-
-
Field Detail
-
DEFAULT_PROPERTY_DELIMITER
public static final java.lang.String DEFAULT_PROPERTY_DELIMITER
Constant for the default property delimiter.- See Also:
- Constant Field Values
-
DEFAULT_ESCAPED_DELIMITER
public static final java.lang.String DEFAULT_ESCAPED_DELIMITER
Constant for the default escaped property delimiter.- See Also:
- Constant Field Values
-
DEFAULT_ATTRIBUTE_START
public static final java.lang.String DEFAULT_ATTRIBUTE_START
Constant for the default attribute start marker.- See Also:
- Constant Field Values
-
DEFAULT_ATTRIBUTE_END
public static final java.lang.String DEFAULT_ATTRIBUTE_END
Constant for the default attribute end marker.- See Also:
- Constant Field Values
-
DEFAULT_INDEX_START
public static final java.lang.String DEFAULT_INDEX_START
Constant for the default index start marker.- See Also:
- Constant Field Values
-
DEFAULT_INDEX_END
public static final java.lang.String DEFAULT_INDEX_END
Constant for the default index end marker.- See Also:
- Constant Field Values
-
-
Method Detail
-
getAttributeEnd
public java.lang.String getAttributeEnd()
Sets the attribute end marker.- Returns:
- the attribute end marker
-
setAttributeEnd
public void setAttributeEnd(java.lang.String attributeEnd)
Sets the attribute end marker.- Parameters:
attributeEnd
- the attribute end marker; can be null if no end marker is needed
-
getAttributeStart
public java.lang.String getAttributeStart()
Returns the attribute start marker.- Returns:
- the attribute start marker
-
setAttributeStart
public void setAttributeStart(java.lang.String attributeStart)
Sets the attribute start marker. Attribute start and end marker are used together to detect attributes in a property key.- Parameters:
attributeStart
- the attribute start marker
-
getEscapedDelimiter
public java.lang.String getEscapedDelimiter()
Returns the escaped property delimiter string.- Returns:
- the escaped property delimiter
-
setEscapedDelimiter
public void setEscapedDelimiter(java.lang.String escapedDelimiter)
Sets the escaped property delimiter string. With this string a delimiter that belongs to the key of a property can be escaped. If for instance "." is used as property delimiter, you can set the escaped delimiter to "\." and can then escape the delimiter with a back slash.- Parameters:
escapedDelimiter
- the escaped delimiter string
-
getIndexEnd
public java.lang.String getIndexEnd()
Returns the index end marker.- Returns:
- the index end marker
-
setIndexEnd
public void setIndexEnd(java.lang.String indexEnd)
Sets the index end marker.- Parameters:
indexEnd
- the index end marker
-
getIndexStart
public java.lang.String getIndexStart()
Returns the index start marker.- Returns:
- the index start marker
-
setIndexStart
public void setIndexStart(java.lang.String indexStart)
Sets the index start marker. Index start and end marker are used together to detect indices in a property key.- Parameters:
indexStart
- the index start marker
-
getPropertyDelimiter
public java.lang.String getPropertyDelimiter()
Returns the property delimiter.- Returns:
- the property delimiter
-
setPropertyDelimiter
public void setPropertyDelimiter(java.lang.String propertyDelimiter)
Sets the property delimiter. This string is used to split the parts of a property key.- Parameters:
propertyDelimiter
- the property delimiter
-
query
public java.util.List<ConfigurationNode> query(ConfigurationNode root, java.lang.String key)
Evaluates the given key and returns all matching nodes. This method supports the syntax as described in the class comment.- Specified by:
query
in interfaceExpressionEngine
- Parameters:
root
- the root nodekey
- the key- Returns:
- a list with the matching nodes
-
nodeKey
public java.lang.String nodeKey(ConfigurationNode node, java.lang.String parentKey)
Determines the key of the passed in node. This implementation takes the given parent key, adds a property delimiter, and then adds the node's name. (For attribute nodes the attribute delimiters are used instead.) The name of the root node is a blanc string. Note that no indices will be returned.- Specified by:
nodeKey
in interfaceExpressionEngine
- Parameters:
node
- the node whose key is to be determinedparentKey
- the key of this node's parent- Returns:
- the key for the given node
-
prepareAdd
public NodeAddData prepareAdd(ConfigurationNode root, java.lang.String key)
Prepares Adding the property with the specified key.
To be able to deal with the structure supported by hierarchical configuration implementations the passed in key is of importance, especially the indices it might contain. The following example should clarify this: Suppose the actual node structure looks like the following:
tables +-- table +-- name = user +-- fields +-- field +-- name = uid +-- field +-- name = firstName ... +-- table +-- name = documents +-- fields ...
In this example a database structure is defined, e.g. all fields of the first table could be accessed using the key
tables.table(0).fields.field.name
. 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 justconfig.addProperty("tables.table.fields.field.name", "newField");
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
field
; because there are multiple fields and no explicit index is provided, a newname
property would be added to the last field - which is probably not what was desired.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
table
element as intables.table(1).fields
. 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 additionalname
element to the last field of the table, but we want a complete newfield
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:config.addProperty("tables.table(1).fields.field(-1).name", "newField");
With this notation it is possible to add new branches everywhere. We could for instance create a new
table
element by specifyingconfig.addProperty("tables.table(-1).fields.field.name", "newField2");
(Note that because after the
table
element a new branch is created indices in following elements are not relevant; the branch is new so there cannot be any ambiguities.)- Specified by:
prepareAdd
in interfaceExpressionEngine
- Parameters:
root
- the root node of the nodes hierarchykey
- the key of the new property- Returns:
- a data object with information needed for the add operation
-
findNodesForKey
protected void findNodesForKey(DefaultConfigurationKey.KeyIterator keyPart, ConfigurationNode node, java.util.Collection<ConfigurationNode> nodes)
Recursive helper method for evaluating a key. This method processes all facets of a configuration key, traverses the tree of properties and fetches the the nodes of all matching properties.- Parameters:
keyPart
- the configuration key iteratornode
- the actual nodenodes
- here the found nodes are stored
-
findLastPathNode
protected ConfigurationNode findLastPathNode(DefaultConfigurationKey.KeyIterator keyIt, ConfigurationNode node)
Finds the last existing node for an add operation. This method traverses the configuration node tree along the specified key. The last existing node on this path is returned.- Parameters:
keyIt
- the key iteratornode
- the actual node- Returns:
- the last existing node on the given path
-
-