/* * 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