/* * 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): * The copyright to this file is held by: * The Australian Commonwealth Government * Department of Defense * Developed by Netymon Pty Ltd * under contract 4500430665 * contributed to the Mulgara Project under the * Mozilla Public License version 1.1 * per clause 4.1.3 of the above contract. * * getModel() contributed by Netymon Pty Ltd on behalf of * The Australian Commonwealth Government under contract 4500507038. * * [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.resolver.xsd; // Java 2 standard packages import java.util.Collections; import java.util.Set; // Third party packages import org.apache.log4j.Logger; // Apache Log4J // Local classes import org.mulgara.query.Constraint; import org.mulgara.query.ConstraintElement; import org.mulgara.query.Variable; import org.mulgara.query.rdf.URIReferenceImpl; import org.jrdf.graph.URIReference; /** * A constraint representing a bounded interval between two XSD values. * * Such constraints are synthesized from pairs of regular constraints during * symbolic optimization. * * @created 2005-05-02 * * @author <a href="mailto:raboczi@itee.uq.edu.au">Simon Raboczi</a> * * @version $Revision: 1.3 $ * * @modified $Date: 2005/06/09 09:26:20 $ @maintenanceAuthor $Author: raboczi $ * * @copyright ©2005 <a href="http://www.defence.gov.au/"> * Australian Commonwealth Government, Department of Defence</a> * * @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a> */ public class IntervalConstraint implements Constraint { /** Logger */ @SuppressWarnings("unused") private static final Logger logger = Logger.getLogger(IntervalConstraint.class.getName()); /** * 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. */ private static final long serialVersionUID = 7653707287858079768L; /** * The variable under constraint. * * This is never <code>null</code>. */ private final Variable variable; /** * The lower bound of the interval. * * If the interval has no lower bound, this will be <code>null</code>. */ private final Bound lowerBound; /** * The upper bound of the interval. * * If the interval has no upper bound, this will be <code>null</code>. */ private final Bound upperBound; /** * The model used to reference the XSD Resolver from this constraint. */ private final URIReference model; /** * Sole constructor. * * @param variable the variable to constrain, never <code>null</code> * @param lowerBound the lower bound of the interval, or <code>null</code> * if the interval has no lower bound * @param upperBound the upper bound of the interval, or <code>null</code> * if the interval has no upper bound * @throws IllegalArgumentException if <var>variable</var> is * <code>null</code> */ IntervalConstraint(Variable variable, Bound lowerBound, Bound upperBound, URIReference model) { if (variable == null) { throw new IllegalArgumentException("Null \"variable\" parameter"); } if (model == null) { throw new IllegalArgumentException("Null 'model' parameter"); } // Initialize field this.variable = variable; this.lowerBound = lowerBound; this.upperBound = upperBound; this.model = model; } /** * Used to create a copy of this constraint with a new variable and model. * @param variable The variable to use in the new constraint. * @param model The model to use in the new constraint. * @return A new constraint with the same properties as this one, but with a different variable and model. */ public IntervalConstraint mutateTo(Variable variable, URIReference model) { return new IntervalConstraint(variable, lowerBound, upperBound, model); } /** * @param intervalConstraint an instance constraining the same variable as * this one, never <code>null</code> * @throws IllegalArgumentException if the <var>intervalConstraint</var> does * not constrain the same variable as this instance or is <code>null</code> */ IntervalConstraint conjoin(IntervalConstraint intervalConstraint) { // Validate "intervalConstraint" parameter if (intervalConstraint == null) { throw new IllegalArgumentException( "Null \"intervalConstraint\" parameter" ); } if (!intervalConstraint.getVariable().equals(variable)) { throw new IllegalArgumentException( "Mismatch variables: " + intervalConstraint.getVariable() + " and " + variable ); } return new IntervalConstraint( variable, maximumBound(lowerBound, intervalConstraint.lowerBound), minimumBound(upperBound, intervalConstraint.upperBound), model ); } public ConstraintElement getModel() { return new URIReferenceImpl(model.getURI()); } public ConstraintElement getElement(int index) { throw new IllegalStateException("Cannot index IntervalConstraint"); } public boolean isRepeating() { return false; } /** * Return the maximum of two {@link Bound}s. * * @param lhs a bound, possibly <code>null</code> * @param rhs another bound, possibly <code>null</code> * @return the largest of <var>lhs</var> and <var>rhs</var>, or * <code>null</code> if both are <code>null</code> */ private static Bound maximumBound(Bound lhs, Bound rhs) { if (lhs == null) { return (rhs == null) ? null : rhs; } else { if (rhs == null) { return lhs; } else { if (lhs.getValue() < rhs.getValue()) return rhs; if (lhs.getValue() > rhs.getValue()) return lhs; assert lhs.getValue() == rhs.getValue(); return lhs.isClosed() ? lhs : rhs; } } } /** * Return the minimum of two {@link Bound}s. * * @param lhs a bound, possibly <code>null</code> * @param rhs another bound, possibly <code>null</code> * @return the smallest of <var>lhs</var> and <var>rhs</var>, or * <code>null</code> if both are <code>null</code> */ private static Bound minimumBound(Bound lhs, Bound rhs) { if (lhs == null) { return (rhs == null) ? null : rhs; } else { if (rhs == null) { return lhs; } else { if (lhs.getValue() < rhs.getValue()) return lhs; if (lhs.getValue() > rhs.getValue()) return rhs; assert lhs.getValue() == rhs.getValue(); return lhs.isClosed() ? rhs : lhs; } } } /** * @return the lower {@link Bound} of the constraint, or <code>null</code> * if it has no lower {@link Bound} */ Bound getLowerBound() { return lowerBound; } /** * @return the upper {@link Bound} of the constraint, or <code>null</code> * if it has no upper {@link Bound} */ Bound getUpperBound() { return upperBound; } /** * @return the constrained variable */ Variable getVariable() { return variable; } /** * @return <code>true</code> if the constraint can never be satisfied (i.e. * the lower bound is above the upper bound) */ boolean isEmpty() { if (lowerBound == null) return false; if (upperBound == null) return false; if (lowerBound.getValue() < upperBound.getValue()) return false; if (lowerBound.getValue() > upperBound.getValue()) return true; assert lowerBound.getValue() == upperBound.getValue(); return !(lowerBound.isClosed() && upperBound.isClosed()); } /** * @return whether the interval admits only a single value */ boolean isSingleton() { return lowerBound != null && lowerBound.isClosed() && lowerBound.equals(upperBound); } /** * @return whether the interval has neither a lower nor an upper bound, and * is thus not really a constraint at all */ boolean isUnconstrained() { return (lowerBound == null) && (upperBound == null); } // // Methods implementing ConstraintExpression // public Set<Variable> getVariables() { return Collections.singleton(variable); } // // Methods overriding Object // /** * Equality is by value rather than by reference. */ public boolean equals(Object object) { if (object == null) return false; if (object.getClass() != IntervalConstraint.class) return false; assert object instanceof IntervalConstraint; IntervalConstraint intervalConstraint = (IntervalConstraint) object; if (isEmpty() && intervalConstraint.isEmpty()) return true; if (isUnconstrained() && intervalConstraint.isUnconstrained()) return true; return variable.equals(intervalConstraint.variable) && Bound.equals(lowerBound, intervalConstraint.lowerBound) && Bound.equals(upperBound, intervalConstraint.upperBound); } /** @see java.lang.Object#hashCode() */ public int hashCode() { return (lowerBound == null ? 1 : lowerBound.hashCode()) + (upperBound == null ? 7 : upperBound.hashCode()); } /** * @return a legible representation of the constraint, for instance * <code>[1.5 < $x <= 2.5]</code> */ public String toString() { StringBuffer buffer = new StringBuffer("["); if (lowerBound != null) { buffer.append(lowerBound.getValue()); buffer.append(lowerBound.isClosed() ? " <= " : " < "); } buffer.append(variable); if (upperBound != null) { buffer.append(upperBound.isClosed() ? " <= " : " < "); buffer.append(upperBound.getValue()); } buffer.append("]"); return buffer.toString(); } /** * Not a binary operation, so not a binary constraint. * @return <code>false</code> to indicate that this operation is not associative. */ public boolean isAssociative() { return false; } }