/*
* JBoss, Home of Professional Open Source.
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership. Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/
package org.teiid.query.sql.lang;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.teiid.core.util.EquivalenceUtil;
import org.teiid.core.util.HashCodeUtil;
import org.teiid.query.QueryPlugin;
import org.teiid.query.sql.LanguageVisitor;
/**
* This class represents a compound criteria for logical expressions. A logical
* expression involves one or more criteria and a logical operator. The valid
* operators are "AND" and "OR".
*/
public class CompoundCriteria extends LogicalCriteria {
/** Constant indicating the logical "or" of two or more criteria. */
public static final int OR = 1;
/** Constant indicating the logical "and" of two or more criteria.*/
public static final int AND = 0;
/** The criterias. */
private List<Criteria> criteria; // List<Criteria>
/** The logical operator. */
private int operator = 0;
/**
* Constructs a default instance of this class.
*/
public CompoundCriteria() {
criteria = new ArrayList<Criteria>(2);
}
/**
* Constructs an instance of this class given the criteria. Subclasses are
* responsible for defining how the criteria are inter-related in a logical
* expression.
* @param criteria List of {@link Criteria} being added
*/
public CompoundCriteria( List<? extends Criteria> criteria ) {
this();
Iterator<? extends Criteria> iter = criteria.iterator();
while ( iter.hasNext() ) {
addCriteria( iter.next() );
}
}
/**
* Constructs an instance of this class given a binary logical expression.
* The logical expression is constructed in terms of a left criteria clause,
* an operator (either OR or AND), and a right criteria clause.
*
* @param left The criteria left of the operator
* @param right The criteria right of the operator
* @param operator The logical operator
*
* @see #set(int,Criteria,Criteria)
*/
public CompoundCriteria( int operator, Criteria left, Criteria right ) {
this();
set(operator,left,right);
}
/**
* Constructs an instance of this class given a general logical expression.
* The logical expression is constructed in terms of an operator (either OR
* or AND), and a set of criteria clauses.
*
* @param operator The logical operator
* @param criteria The list of {@link Criteria}
*/
public CompoundCriteria( int operator, List criteria ) {
this();
set(operator,criteria);
}
/**
* Returns the operator used in the logical expression. The returned value
* can be compared to constants defined in this class.
* @return The operator
*/
public int getOperator() {
return this.operator;
}
/**
* Return true if the specified operator is a valid operator
* @param operator Operator to check
* @return True if valid
*/
private boolean isValidOperator(int operator) {
return (operator == OR || operator == AND);
}
/**
* Sets the operator used in the logical expression.
* @param operator The operator
* @throws IllegalArgumentException If operator is invalid
*/
public void setOperator(int operator) {
if (!isValidOperator(operator)) {
throw new IllegalArgumentException(QueryPlugin.Util.getString("ERR.015.010.0002", operator)); //$NON-NLS-1$
}
this.operator = operator;
}
/**
* Returns the list of criteria.
* @return List of {@link Criteria}
*/
public List<Criteria> getCriteria() {
return this.criteria;
}
/**
* Sets the criteria.
* @param criteria The list of {@link Criteria}
*/
public void setCriteria(List<Criteria> criteria) {
this.criteria = criteria;
}
/**
* Returns the number of criteria in this clause.
* @return Criteria
*/
public int getCriteriaCount() {
return this.criteria.size();
}
/**
* Returns the criteria at the specified index.
* @return Criteria
* @throws IllegalArgumentException if no criteria have been specified
*/
public Criteria getCriteria( int index ) {
return this.criteria.get(index);
}
/**
* Add another criteria to the clause.
* @param criteria The criteria
*/
public void addCriteria( Criteria criteria ) {
this.criteria.add(criteria);
}
/**
* Reset criteria so there are no more. After this call, <code>
* getCriteriaCount</code> will return 0.
*/
protected void reset() {
criteria.clear();
}
/**
* Sets a "standard" operand-operator-operand criteria.
*
* @param operator The logical operator
* @param left The first criteria
* @param right The second criteria
*
* @see #set(int,List)
*/
public void set( int operator, Criteria left, Criteria right ) {
reset();
setOperator(operator);
addCriteria(left);
addCriteria(right);
}
/**
* Sets a "standard" unary criteria.
*
* @param operator The unary logical operator
* @param criteria The criteria
*
* @see #set(int,List)
*/
public void set( int operator, Criteria criteria) {
reset();
setOperator(operator);
addCriteria(criteria);
}
/**
* Sets the operator and an arbitrary set of criteria.
*
* @param operator The logical operator
* @param criteria The set of criteria
*
* @see #set(int,Criteria,Criteria)
*/
public void set( int operator, List criteria ) {
reset();
setOperator(operator);
Iterator iter = criteria.iterator();
while ( iter.hasNext() ) {
addCriteria( (Criteria)iter.next() );
}
}
public void acceptVisitor(LanguageVisitor visitor) {
visitor.visit(this);
}
/**
* Get hash code. WARNING: The hash code is based on data in the criteria.
* If data values are changed, the hash code will change - don't hash this
* object and change values.
*/
public int hashCode() {
int hc = 0;
hc = HashCodeUtil.hashCode(hc, getOperator());
hc = HashCodeUtil.hashCode(hc, getCriteria());
return hc;
}
/**
* Override equals() method.
*/
public boolean equals(Object obj) {
if(obj == this) {
return true;
}
if(!(obj instanceof CompoundCriteria)) {
return false;
}
CompoundCriteria cc = (CompoundCriteria)obj;
return cc.getOperator() == getOperator() &&
EquivalenceUtil.areEqual(cc.getCriteria(), getCriteria());
}
/**
* Deep clone. It returns a new LogicalCriteria with a new list of clones
* of the criteria objects.
*/
public Object clone() {
CompoundCriteria copy = new CompoundCriteria();
copy.setOperator(getOperator());
// Clone each sub-criteria
List crits = getCriteria();
for(int i=0; i<crits.size(); i++) {
Criteria crit = (Criteria) crits.get(i);
if(crit == null) {
copy.addCriteria(null);
} else {
copy.addCriteria( (Criteria) crit.clone() );
}
}
return copy;
}
} // END CLASS