//
// Copyright (c)1998-2011 Pearson Education, Inc. or its affiliate(s).
// All rights reserved.
//
package openadk.library;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
/**
* A group of query conditions.<p>
*
* A ConditionGroup is a container for Condition objects that are evaluated
* together as a group using the Boolean operator passed to the constructor.
* ConditionGroups may be nested such that each ConditionGroup is evaluated
* using the Boolean operator passed to the constructor.
* <p>
*
* @author Eric Petersen
* @version 1.0
*/
public class ConditionGroup implements Serializable
{
/** The Conditions and nested ConditionGroups that comprise this group */
protected List<Serializable> fConditions;
/** The Boolean operator to use when joining conditions in this group */
protected GroupOperators fOp;
/**
* Constructs a ConditionGroup
* @param ops The Boolean operator to use when joining conditions in this
* group; either <code>Condition.AND</code> or <code>Condition.OR</code>
*/
public ConditionGroup( GroupOperators ops )
{
fOp = ops;
}
/**
* Gets the Boolean operator for joining all conditions in this group
* @return A constant from the Condition class (e.g. <code>Condition.AND</code>)
*/
public GroupOperators getOperator()
{
return fOp;
}
/**
* Gets the conditions in this group. If the group consists of only nested
* ConditionGroups, an empty array is returned; use the getConditionGroups
* method to retrieve the nested groups.<p>
*
* @return An array of Conditions added to this group, or an empty array
* if the group consists of only nested ConditionGroups
*/
public Condition[] getConditions()
{
List<Object> v = new ArrayList<Object>();
if( fConditions != null ) {
for( int i = 0; i < fConditions.size(); i++ ) {
Object o = fConditions.get( i );
if( o instanceof Condition ){
v.add( o );
}
}
}
Condition[] arr = new Condition[ v.size() ];
v.toArray( arr );
return arr;
}
/**
* Gets the nested ConditionGroups in this group. If the group does not
* contain any nested ConditionGroups and is comprised of only Condition
* elements, an empty array is returned
* @return An array of ConditionGroup
*/
public ConditionGroup[] getGroups()
{
List<Object> v = new ArrayList<Object>();
if( fConditions != null ) {
for( int i = 0; i < fConditions.size(); i++ ) {
Object o = fConditions.get( i );
if( o instanceof ConditionGroup ){
v.add( o );
}
}
}
ConditionGroup[] arr = new ConditionGroup[ v.size() ];
v.toArray( arr );
return arr;
}
/**
* Adds a Condition to this group
* @param cond The condition to add to this group of conditions
*/
public void addCondition( Condition cond )
{
if( fConditions == null ){
fConditions = new ArrayList<Serializable>();
}
fConditions.add( cond );
}
/**
* Adds a condition to this group.<p>
*
* This method of adding conditions is convenient for adding conditions involving
* root attributes or elements to a query. If you need to add conditions on deeply
* nested elements, use {@link #addCondition(String, ComparisonOperators, String)}
* @param field The metadata element that represents the field, such as
* <code>StudentDTD.STUDENTPERSONAL_REFID</code>
* @param ops The ComparisonOperator to use for this query condition
* @param value The value to compare to this field using the comparison operator
*/
public void addCondition( ElementDef field, ComparisonOperators ops, String value )
{
addCondition( new Condition( field, ops,value ) );
}
/**
* Internal only. Adds a query condition to this condition group by evaluating the XPath.
* If possible, the ElementDef representing the field will be evaluated
* @param objectDef The metadata definition of the parent object
* @param xPath The xpath to the field
* @param ops The ComparisonOperator to apply
* @param value The value to compare the field to
*/
void addCondition( ElementDef objectDef, String xPath, ComparisonOperators ops, String value )
{
addCondition( new Condition( objectDef, xPath, ops,value ) );
}
/**
* Add a condition to this group using a deeply nested path. Using this
* method of adding query condition allows for specifying deeply nested query
* conditions. However, the xpath specified here is specific to the version
* of SIF<p>
*
* To ensure your code works with all versions of SIF, you should use
* {@link #addCondition(ElementDef, ComparisonOperators, String)} whenever possible.
* <p>
*
* @param xPath The XPath representation of this field
* @param ops The ComparisonOperator to apply
* @param value The value to compare the field to
*/
public void addCondition( String xPath, ComparisonOperators ops, String value )
{
addCondition( new Condition( xPath, ops, value ) );
}
/**
* Adds a nested ConditionGroup to this group
* @param group The ConditionGropu to add to this group
*/
public void addGroup( ConditionGroup group )
{
if( fConditions == null ){
fConditions = new Vector<Serializable>();
}
fConditions.add( group );
}
/**
* Determines if there are any conditions in this group, including any
* nested ConditionGroups
* @return True if this group contains any conditions
*/
public boolean hasConditions()
{
if( fConditions != null )
{
for( int i = 0; i < fConditions.size(); i++ ) {
Object o = fConditions.get( i );
if( o instanceof Condition )
return true;
if( o instanceof ConditionGroup && ((ConditionGroup)o).hasConditions() )
return true;
}
}
return false;
}
/**
* Tests if this ConditionGroup has a Condition for a specific element or
* attribute. Nested ConditionGroups are not included in the search.
* <p>
*
* @param elementOrAttr The ElementDef constant from the SIFDTD class that
* identifies the specific attribute or element to search for
* @return The matching Condition object or <code>null</code> if the group
* does not contain a Condition for the specified element or attribute
*
* @deprecated Please use {@link #hasCondition(String)} to support deeply nested
* query conditions
*/
public Condition hasCondition( ElementDef elementOrAttr )
{
if( fConditions != null ) {
for( Object o : fConditions ) {
if( o instanceof Condition ){
Condition cond = (Condition)o;
if( cond.fField != null && cond.fField.name().equals( elementOrAttr.name() ) ){
return cond;
}
}
}
}
return null;
}
/**
* Tests if this ConditionGroup has a Condition for a specific XPath.
* Nested ConditionGroups are not included in the search.
* <p>
*
* @param xPath The xPath representation of the query field. e.g. "Name/FirstName"
* @return The matching Condition object or <code>null</code> if the root
* condition group does not contain a Condition for the specified path.
*/
public Condition hasCondition( String xPath )
{
if( fConditions != null ) {
for( int i = 0; i < fConditions.size(); i++ ) {
Object o = fConditions.get(i);
if( o instanceof Condition && ((Condition)o).fXPath.equals( xPath ) )
return (Condition)o;
}
}
return null;
}
/**
* Gets the number of conditions in this group.<p>
*
* @return The number of conditions that will be returned by the
* getConditions method, or 0 if there are no conditions in the group
* or if the group is comprised of only nested ConditionGroups
*/
public int size()
{
int cnt = 0;
if( fConditions != null ) {
for( int i = 0; i < fConditions.size(); i++ ) {
Object o = fConditions.get(i);
if( o instanceof Condition )
cnt++;
}
}
return cnt;
}
}