/*
* 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
* Northrop Grumman Corporation. All Rights Reserved.
*
* This file is an original work and contains no Original Code. It was
* developed by Netymon Pty Ltd under contract to the Australian
* Commonwealth Government, Defense Science and Technology Organisation
* under contract #4500507038 and is contributed back to the Kowari/Mulgara
* Project as per clauses 4.1.3 and 4.1.4 of the above contract.
*
* Contributor(s): N/A.
*
* Copyright:
* The copyright on this file is held by:
* The Australian Commonwealth Government
* Department of Defense
* Developed by Netymon Pty Ltd
* Copyright (C) 2006
* The Australian Commonwealth Government
* Department of Defense
*
* [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.relational;
// Java 2 standard packages
import static org.mulgara.util.ObjectUtil.eq;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.net.URI;
// Third party packages
// import org.apache.log4j.Logger; // Apache Log4J
import org.jrdf.graph.URIReference;
// Local classes
import org.mulgara.query.Constraint;
import org.mulgara.query.ConstraintElement;
import org.mulgara.query.ConstraintExpression;
import org.mulgara.query.Value;
import org.mulgara.query.Variable;
import org.mulgara.query.rdf.URIReferenceImpl;
import org.mulgara.resolver.spi.QueryEvaluationContext;
// FIXME: Need to work out how to delegate localizations and bindings.
import org.mulgara.resolver.ConstraintOperations;
/**
* A constraint representing a relational query.
*
* @created 2005-05-02
*
* @author <a href="mailto:raboczi@itee.uq.edu.au">Simon Raboczi</a>
*
* @version $Revision: 1.1.1.1 $
*
* @modified $Date: 2005/10/30 19:21:19 $ @maintenanceAuthor $Author: prototypo $
*
* @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 RelationalConstraint implements Constraint {
// /** Logger */
// private static Logger logger = Logger.getLogger(RelationalConstraint.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 = -2930975307291404712L;
private Set<ConstraintExpression> rdfTypeConstraints;
private Map<ConstraintElement,List<Constraint>> predConstraints;
private ConstraintElement model;
private Set<Variable> variables;
private static final URIReference rdftype;
static {
try {
rdftype = new URIReferenceImpl(new URI("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"));
} catch (Exception e) {
throw new IllegalStateException("Invalid rdf:type uri");
}
}
/**
* Sole constructor.
*/
public RelationalConstraint() {
this.rdfTypeConstraints = new HashSet<ConstraintExpression>();
this.variables = new HashSet<Variable>();
this.predConstraints = new HashMap<ConstraintElement,List<Constraint>>();
}
public RelationalConstraint(Constraint constraint) {
this();
conjoinWith(constraint);
}
public void conjoinWith(RelationalConstraint constraint) {
preliminaries(constraint);
rdfTypeConstraints.addAll(constraint.rdfTypeConstraints);
for (ConstraintElement key: constraint.predConstraints.keySet()) {
List<Constraint> lhs = constraint.predConstraints.get(key);
List<Constraint> rhs = predConstraints.get(key);
if (rhs == null) {
predConstraints.put(key, lhs);
} else {
rhs.addAll(lhs);
}
}
}
public void conjoinWith(Constraint constraint) {
preliminaries(constraint);
if (constraint.getElement(1).equals(rdftype)) {
rdfTypeConstraints.add(constraint);
} else {
// } else if (constraint.getElement(0) instanceof Variable) {
List<Constraint> preds = predConstraints.get(constraint.getElement(0));
if (preds == null) {
preds = new ArrayList<Constraint>();
predConstraints.put((ConstraintElement)constraint.getElement(0), preds);
}
preds.add(constraint);
}
}
public void preliminaries(Constraint constraint) {
if (model == null) {
model = constraint.getModel();
} else if (!model.equals(constraint.getModel())) {
throw new IllegalStateException("Can't combine relational constraints against different models");
}
variables.addAll(constraint.getVariables());
}
public Set<ConstraintExpression> getRdfTypeConstraints() {
return rdfTypeConstraints;
}
public List<Constraint> getConstraintsBySubject(ConstraintElement subj) {
List<Constraint> list = predConstraints.get(subj);
return list != null ? list : new ArrayList<Constraint>();
}
public ConstraintElement getModel() {
return model;
}
public ConstraintElement getElement(int index) {
throw new IllegalStateException("Cannot index RelationalConstraint");
}
public boolean isRepeating() {
return false;
}
public Set<Variable> getVariables() {
return variables;
}
/**
* 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;
}
static RelationalConstraint localize(QueryEvaluationContext context, RelationalConstraint constraint) throws Exception {
RelationalConstraint localized = new RelationalConstraint();
// Aliasing may be a problem, not sure but subqueries might complain.
// Not sure how it interacts with bindvariables. If a problem then
// deep copy.
// We don't localize because the constraint manipulation is done in global space.
localized.rdfTypeConstraints = constraint.rdfTypeConstraints;
localized.predConstraints = constraint.predConstraints;
localized.model = context.localize(constraint.model);
localized.variables.addAll(constraint.variables);
return localized;
}
static RelationalConstraint bind(Map<Variable,Value> bindings, RelationalConstraint constraint) throws Exception {
RelationalConstraint bound = new RelationalConstraint();
for (ConstraintExpression c: constraint.rdfTypeConstraints) {
bound.rdfTypeConstraints.add(ConstraintOperations.bindVariables(bindings, c));
}
for (ConstraintElement key: constraint.predConstraints.keySet()) {
List<Constraint> entry = constraint.predConstraints.get(key);
List<Constraint> bentry = new ArrayList<Constraint>();
for (Constraint jc: entry) {
bentry.add((Constraint)ConstraintOperations.bindVariables(bindings, jc));
}
constraint.predConstraints.put(key, bentry);
}
bound.model = constraint.model; // Can't be a variable
bound.variables.addAll(constraint.variables);
bound.variables.removeAll(bindings.keySet());
return bound;
}
// Not sure if permitting mutation here is a problem.
// We might have to do a clone and edit in the descriptor.
void rewriteModel(ConstraintElement newModel) {
this.model = newModel;
}
public String toString() {
return "RC{" + variables + "} | " + rdfTypeConstraints + " # " + predConstraints;
}
public boolean equals(Object o) {
if (!(o instanceof RelationalConstraint)) return false;
RelationalConstraint r = (RelationalConstraint)o;
return eq(model, r.model) && eq(variables, r.variables) &&
eq(rdfTypeConstraints, r.rdfTypeConstraints) && eq(predConstraints, r.predConstraints);
}
}