org.apache.commons.configuration.tree

Class DefaultExpressionEngine

public class DefaultExpressionEngine extends 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:

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 opposite tables.table.name would return a collection with the names of all available tables. Similarily the key tables.table(1).fields.field.name returns a collection with the names of all fields of the second table. If another index is added after the field element, a single field can be accessed: tables.table(1).fields.field(0).name. The key tables.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 439648 2006-09-02 20:42:10Z oheger $

Author: Oliver Heger

Field Summary
StringattributeEnd
Stores the attribute end marker.
StringattributeStart
Stores the attribute start marker.
static StringDEFAULT_ATTRIBUTE_END
Constant for the default attribute end marker.
static StringDEFAULT_ATTRIBUTE_START
Constant for the default attribute start marker.
static StringDEFAULT_ESCAPED_DELIMITER
Constant for the default escaped property delimiter.
static StringDEFAULT_INDEX_END
Constant for the default index end marker.
static StringDEFAULT_INDEX_START
Constant for the default index start marker.
static StringDEFAULT_PROPERTY_DELIMITER
Constant for the default property delimiter.
StringescapedDelimiter
Stores the escaped property delimiter.
StringindexEnd
stores the index end marker.
StringindexStart
Stores the index start marker.
StringpropertyDelimiter
Stores the property delimiter.
Method Summary
protected ConfigurationNodefindLastPathNode(DefaultConfigurationKey.KeyIterator keyIt, ConfigurationNode node)
Finds the last existing node for an add operation.
protected voidfindNodesForKey(DefaultConfigurationKey.KeyIterator keyPart, ConfigurationNode node, Collection nodes)
Recursive helper method for evaluating a key.
StringgetAttributeEnd()
Sets the attribute end marker.
StringgetAttributeStart()
Returns the attribute start marker.
StringgetEscapedDelimiter()
Returns the escaped property delimiter string.
StringgetIndexEnd()
Returns the index end marker.
StringgetIndexStart()
Returns the index start marker.
StringgetPropertyDelimiter()
Returns the property delimiter.
StringnodeKey(ConfigurationNode node, String parentKey)
Determines the key of the passed in node.
NodeAddDataprepareAdd(ConfigurationNode root, String key)

Prepares Adding the property with the specified key.

voidprocessSubNodes(DefaultConfigurationKey.KeyIterator keyPart, List subNodes, Collection nodes)
Called by findNodesForKey() to process the sub nodes of the current node depending on the type of the current key part (children, attributes, or both).
Listquery(ConfigurationNode root, String key)
Evaluates the given key and returns all matching nodes.
voidsetAttributeEnd(String attributeEnd)
Sets the attribute end marker.
voidsetAttributeStart(String attributeStart)
Sets the attribute start marker.
voidsetEscapedDelimiter(String escapedDelimiter)
Sets the escaped property delimiter string.
voidsetIndexEnd(String indexEnd)
Sets the index end marker.
voidsetIndexStart(String indexStart)
Sets the index start marker.
voidsetPropertyDelimiter(String propertyDelimiter)
Sets the property delmiter.

Field Detail

attributeEnd

private String attributeEnd
Stores the attribute end marker.

attributeStart

private String attributeStart
Stores the attribute start marker.

DEFAULT_ATTRIBUTE_END

public static final String DEFAULT_ATTRIBUTE_END
Constant for the default attribute end marker.

DEFAULT_ATTRIBUTE_START

public static final String DEFAULT_ATTRIBUTE_START
Constant for the default attribute start marker.

DEFAULT_ESCAPED_DELIMITER

public static final String DEFAULT_ESCAPED_DELIMITER
Constant for the default escaped property delimiter.

DEFAULT_INDEX_END

public static final String DEFAULT_INDEX_END
Constant for the default index end marker.

DEFAULT_INDEX_START

public static final String DEFAULT_INDEX_START
Constant for the default index start marker.

DEFAULT_PROPERTY_DELIMITER

public static final String DEFAULT_PROPERTY_DELIMITER
Constant for the default property delimiter.

escapedDelimiter

private String escapedDelimiter
Stores the escaped property delimiter.

indexEnd

private String indexEnd
stores the index end marker.

indexStart

private String indexStart
Stores the index start marker.

propertyDelimiter

private String propertyDelimiter
Stores the property delimiter.

Method Detail

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 iterator node the actual node

Returns: the last existing node on the given path

findNodesForKey

protected void findNodesForKey(DefaultConfigurationKey.KeyIterator keyPart, ConfigurationNode node, Collection 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 iterator node the actual node nodes here the found nodes are stored

getAttributeEnd

public String getAttributeEnd()
Sets the attribute end marker.

Returns: the attribute end marker

getAttributeStart

public String getAttributeStart()
Returns the attribute start marker.

Returns: the attribute start marker

getEscapedDelimiter

public String getEscapedDelimiter()
Returns the escaped property delimiter string.

Returns: the escaped property delimiter

getIndexEnd

public String getIndexEnd()
Returns the index end marker.

Returns: the index end marker

getIndexStart

public String getIndexStart()
Returns the index start marker.

Returns: the index start marker

getPropertyDelimiter

public String getPropertyDelimiter()
Returns the property delimiter.

Returns: the property delimiter

nodeKey

public String nodeKey(ConfigurationNode node, 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.

Parameters: node the node whose key is to be determined parentKey the key of this node's parent

Returns: the key for the given node

prepareAdd

public NodeAddData prepareAdd(ConfigurationNode root, 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 clearify 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 just

 config.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 new name property would be added to the last field - which is propably 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 in tables.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 additional name element to the last field of the table, but we want a complete new field 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 specifying

 config.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.)

Parameters: root the root node of the nodes hierarchy key the key of the new property

Returns: a data object with information needed for the add operation

processSubNodes

private void processSubNodes(DefaultConfigurationKey.KeyIterator keyPart, List subNodes, Collection nodes)
Called by findNodesForKey() to process the sub nodes of the current node depending on the type of the current key part (children, attributes, or both).

Parameters: keyPart the key part subNodes a list with the sub nodes to process nodes the target collection

query

public List query(ConfigurationNode root, String key)
Evaluates the given key and returns all matching nodes. This method supports the syntax as described in the class comment.

Parameters: root the root node key the key

Returns: a list with the matching nodes

setAttributeEnd

public void setAttributeEnd(String attributeEnd)
Sets the attribute end marker.

Parameters: attributeEnd the attribute end marker; can be null if no end marker is needed

setAttributeStart

public void setAttributeStart(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

setEscapedDelimiter

public void setEscapedDelimiter(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

setIndexEnd

public void setIndexEnd(String indexEnd)
Sets the index end marker.

Parameters: indexEnd the index end marker

setIndexStart

public void setIndexStart(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

setPropertyDelimiter

public void setPropertyDelimiter(String propertyDelimiter)
Sets the property delmiter. This string is used to split the parts of a property key.

Parameters: propertyDelimiter the property delimiter