/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is the Kowari Metadata Store.
*
* The Initial Developer of the Original Code is Plugged In Software Pty
* Ltd (http://www.pisoftware.com, mailto:info@pisoftware.com). Portions
* created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
* Plugged In Software Pty Ltd. All Rights Reserved.
*
* Contributor(s): N/A.
*
* [NOTE: The text of this Exhibit A may differ slightly from the text
* of the notices in the Source Code files of the Original Code. You
* should use the text of this Exhibit A rather than the text found in the
* Original Code Source Code for Your Modifications.]
*
*/
package org.mulgara.query;
// Java 2 standard packages
import java.util.*;
// Third party packages
// import org.apache.log4j.Logger;
/**
* A constraint expression composed of two subexpressions and a dyadic operator.
* Can be transformed.
*
* @created 2001-08-12
*
* @author <a href="http://staff.pisoftware.com/raboczi">Simon Raboczi</a>
*
* @version $Revision: 1.8 $
*
* @modified $Date: 2005/01/05 04:58:20 $
*
* @maintenanceAuthor $Author: newmana $
*
* @company <A href="mailto:info@PIsoftware.com">Plugged In Software</A>
*
* @copyright © 2001-2003 <A href="http://www.PIsoftware.com/">Plugged In
* Software Pty Ltd</A>
*
* @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
*/
public abstract class ConstraintOperation extends AbstractConstraintExpression {
/**
* Allow newer compiled version of the stub to operate when changes
* have not occurred with the class.
* NOTE : update this serialVersionUID when a method or a public member is
* deleted.
*/
static final long serialVersionUID = -236847137057853871L;
// /** Logger. */
// private static Logger logger = Logger.getLogger(ConstraintOperation.class);
//
// Constructor
//
/**
* Construct a constraint operation. Subclasses are compelled to use this
* constructor, guaranteeing that the operands are always non-<code>null</code>
* .
*
* @param lhs a non-<code>null</code> model expression
* @param rhs another non-<code>null</code> model expression
*/
protected ConstraintOperation(ConstraintExpression lhs, ConstraintExpression rhs) {
// Validate "lhs" parameter
if (lhs == null) throw new IllegalArgumentException("Null \"lhs\" parameter");
// Validate "rhs" parameter
if (rhs == null) throw new IllegalArgumentException("Null \"rhs\" parameter");
// Initialize fields
elements = new ArrayList<ConstraintExpression>(2);
// Add the LHS
if (isAssociative() && lhs.getClass() == getClass()) {
elements.addAll(((ConstraintOperation)lhs).getElements());
} else {
elements.add(lhs);
}
// Add the RHS
if (isAssociative() && rhs.getClass() == getClass()) {
elements.addAll( ( (ConstraintOperation) rhs).getElements());
} else {
elements.add(rhs);
}
}
/**
* Creates a new ConstraintOperation build on a list of ConstraintExpression
*
* @param elements A list of ConstraintExpression to be the parameters of this expression
*/
protected ConstraintOperation(List<ConstraintExpression> elements) {
// Validate "elements" parameter
if (elements == null) throw new IllegalArgumentException("Null \"elements\" parameter");
// assert elements.size() > 1;
// Initialize fields
this.elements = new ArrayList<ConstraintExpression>();
// add all the elements, flattening if needed
for (ConstraintExpression op: elements) {
if (op.isAssociative() && op.getClass() == getClass()) {
this.elements.addAll(((ConstraintOperation)op).getElements());
} else {
this.elements.add(op);
}
}
}
/**
* Accessor method for the operands.
*
* @return a list of {@link ConstraintExpression}s
*/
public List<ConstraintExpression> getElements() {
return Collections.unmodifiableList(elements);
}
/**
* Get a constraint element by index.
*
* @param index The constraint element to retrieve, from 0 to 3.
* @return The constraint element referred to by index.
*/
public ConstraintExpression getOperand(int index) {
return (ConstraintExpression) elements.get(index);
}
/**
* Defines Structual equality.
*
* @return equality.
*/
public boolean equals(Object o) {
if (!super.equals(o)) return false;
ConstraintOperation co = (ConstraintOperation) o;
if (elements.size() != co.elements.size()) return false;
Iterator<ConstraintExpression> lhs = elements.iterator();
Iterator<ConstraintExpression> rhs = co.elements.iterator();
while (lhs.hasNext()) {
if (!(lhs.next().equals(rhs.next()))) return false;
}
return true;
}
/**
* Get all constraints which are variables. For back-compatibility, this
* method currently ignores the fourth element of the triple.
*
* @return A set containing all variable constraints.
*/
public Set<Variable> getVariables() {
// Check to see if there variables have been retrieved.
if (variables == null) {
Set<Variable> v = new HashSet<Variable>();
for (ConstraintExpression expr: getElements()) v.addAll(expr.getVariables());
variables = Collections.unmodifiableSet(v);
}
return variables;
}
/**
* Generate hashcode for this object.
*
* @return This objects hascode.
*/
public int hashCode() {
int hashCode = 0;
Iterator<ConstraintExpression> i = elements.iterator();
while (i.hasNext()) hashCode ^= i.next().hashCode();
return hashCode;
}
/**
* Convert this object to a string.
*
* @return A string representation of this object.
*/
public String toString() {
StringBuffer buffer = new StringBuffer("(" + getName());
Iterator<ConstraintExpression> i = getElements().iterator();
while (i.hasNext()) {
buffer.append(i.next().toString());
if (i.hasNext()) buffer.append(" ");
}
buffer.append(")");
return buffer.toString();
}
/**
* Indicates if this operation is associative.
* @return <code>true</code> iff this operation is associative.
*/
public boolean isAssociative() {
return true;
}
/**
* Gets the Name attribute of the ConstraintOperation object
*
* @return The Name value
*/
abstract String getName();
/**
* Remove the constraint expressions from the product that have non-intersecting variables.
*
* @param product The list of constraints to test and modify.
*/
protected static void filter(List<ConstraintExpression> product) {
Set<Variable> o1 = new HashSet<Variable>();
// Variables which occur at least once.
Set<Variable> o2 = new HashSet<Variable>();
// Variables which occur two or more times.
// Get a set of variables which occur two or more times.
for (ConstraintExpression oc: product) {
Set<Variable> ocVars = oc.getVariables();
Set<Variable> vars = new HashSet<Variable>(ocVars);
vars.retainAll(o1);
o2.addAll(vars);
o1.addAll(ocVars);
}
// remove the expressions which have non-intersecting variables
for (Iterator<ConstraintExpression> pIt = product.iterator(); pIt.hasNext(); ) {
ConstraintExpression oc = pIt.next();
Set<Variable> vars = new HashSet<Variable>(oc.getVariables());
vars.retainAll(o2);
if (vars.isEmpty()) pIt.remove();
}
}
}