/*
* Copyright 2008 Fedora Commons, Inc.
*
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mulgara.krule;
import java.io.Serializable;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.jrdf.graph.Literal;
import org.jrdf.graph.Node;
import org.jrdf.graph.URIReference;
import org.mulgara.itql.VariableFactoryImpl;
import org.mulgara.query.ConstantValue;
import org.mulgara.query.ConstraintElement;
import org.mulgara.query.ConstraintExpression;
import org.mulgara.query.ConstraintHaving;
import org.mulgara.query.GraphExpression;
import org.mulgara.query.GraphResource;
import org.mulgara.query.GraphUnion;
import org.mulgara.query.Order;
import org.mulgara.query.Query;
import org.mulgara.query.SelectElement;
import org.mulgara.query.UnconstrainedAnswer;
import org.mulgara.query.Variable;
import org.mulgara.query.VariableFactory;
import org.mulgara.query.rdf.Krule;
import org.mulgara.query.rdf.LiteralImpl;
import org.mulgara.query.rdf.URIReferenceImpl;
/**
* A structure to describe an iTQL query.
*
* @created 2005-5-27
* @author <a href="mailto:gearon@users.sourceforge.net">Paula Gearon</a>
* @version $Revision: 1.2 $
* @modified $Date: 2005/07/03 12:56:44 $
* @maintenanceAuthor $Author: pgearon $
* @copyright © 2005 <a href="http://www.fedora-commons.org/">Fedora Commons</a>
*/
public class QueryStruct implements Serializable {
static final long serialVersionUID = -6472138136362435835L;
/** Logger. */
private static final Logger logger = Logger.getLogger(QueryStruct.class.getName());
/** List of elements which are variables, or ConstantValues. */
private List<SelectElement> variables = null;
/** The graph expresison for the query. */
private GraphExpression graphs = null;
/** The where clause of the query. */
private ConstraintExpression where = null;
/** The having clause for the query. */
private ConstraintHaving having = null;
/**
* Constructor. Converts string descriptions of the values and variables into the constraint elements.
*
* @param valueSelection The element nodes.
* @param selTypes The types of the elements, defined in the krule namespace.
* @param uriReferences A map of all krule:ref_* objects to the appropriate {@link org.jrdf.graph.URIReference}s.
* @param varReferences A map of all krule:var_* objects to the appropriate name.
* @throws IllegalArgumentException If the types are incorrect, the elements are not named as expected,
* or the references are not found in the references map.
*/
public QueryStruct(
List<URIReference> valueSelection, List<URIReference> selTypes,
Map<URIReference,URIReference> uriReferences, Map<URIReference,Variable> varReferences,
Map<Node,Literal> litReferences
) {
if (valueSelection.size() <= 0 || selTypes.size() <= 0 || valueSelection.size() != selTypes.size()) {
throw new IllegalArgumentException("Wrong number of elements for a rule query");
}
URIReference[] vs = valueSelection.toArray(new URIReference[valueSelection.size()]);
URIReference[] types = selTypes.toArray(new URIReference[selTypes.size()]);
// If there is a non-multiple of 3 in the selection variables, then this is a check rule
// and we can only select variables in check rules
boolean varsOnly = vs.length % 3 != 0;
VariableFactory variableFactory = new VariableFactoryImpl();
// set up a list of variables
variables = new ArrayList<SelectElement>();
// convert the parameters to usable objects
for (int i = 0; i < vs.length; i++) {
ConstraintElement select = null;
URIReference element = vs[i];
// check the type
if (types[i].equals(Krule.URI_REF)) {
// check that this didn't have a non-multiple of 3 in the selection values
if (varsOnly) throw new IllegalArgumentException("Wrong number of elements for a rule query: " + vs.length);
// get the referred value from the map
select = (URIReferenceImpl)uriReferences.get(element);
// assume that literals do not have the "Value" type inferred
variables.add(new ConstantValue(variableFactory.newVariable(), (URIReferenceImpl)select));
} else if (types[i].equals(Krule.VARIABLE)) {
// get the variable
select = (Variable)varReferences.get(element);
variables.add((Variable)select);
} else if (types[i].equals(Krule.LITERAL)) {
if (i % 3 != 2) {
throw new IllegalArgumentException("Selection literal in illegal position in query");
}
// check that this didn't have a non-multiple of 3 in the selection values
if (varsOnly) throw new IllegalArgumentException("Wrong number of elements for a rule query: " + vs.length);
// get the literal
select = (LiteralImpl)litReferences.get(element);
variables.add(new ConstantValue(variableFactory.newVariable(), (LiteralImpl)select));
} else {
throw new IllegalArgumentException("Unknown selection type in rule query.");
}
if (select == null) {
throw new IllegalArgumentException("Unable to resolve a reference for: " + element);
}
}
}
/**
* Construct a query structure with a known list of select elements.
* @param vars The select elements for this query.
*/
public QueryStruct(List<SelectElement> vars) {
if (vars.size() <= 0) throw new IllegalArgumentException("Wrong number of elements for a rule query");
this.variables = new ArrayList<SelectElement>(vars);
// If there is a non-multiple of 3 in the selection variables, then this is a check rule
// and we can only select variables in check rules
boolean varsOnly = variables.size() % 3 != 0;
// Validate the select elements.
for (int i = 0; i < variables.size(); i++) {
SelectElement var = variables.get(i);
if (varsOnly && !(var instanceof Variable)) {
throw new IllegalArgumentException("Wrong number of elements for a rule query: " + variables.size());
}
if ((var instanceof ConstantValue) && (((ConstantValue)var).getValue() instanceof Literal) && i % 3 != 2) {
throw new IllegalArgumentException("Selection literal in illegal position in query");
}
}
}
/**
* Returns the number of elements to be returned from this query.
* @return The number of selection elements from the query.
*/
public int elementCount() {
return variables.size();
}
/**
* Sets the where clause for the query.
*
* @param constraints The constraint expression defining the where clause.
*/
public void setWhereClause(ConstraintExpression constraints) {
where = constraints;
}
/**
* Sets the having clause for the query.
*
* @param having The having constraint expression defining the having clause.
*/
public void setHavingClause(ConstraintHaving having) {
this.having = having;
}
/**
* Sets the default graph expression for the query.
*
* @param expr The graph expression for the query.
*/
public void setGraphExpression(GraphExpression expr) {
this.graphs = expr;
}
/**
* Sets the default graph expression for the query.
*
* @param expr The base graph expression for the query.
* @param secondGraphUri The secondary graph URI for the query.
*/
public void setGraphExpression(GraphExpression expr, URI secondGraphUri) {
if (GraphResource.sameAs(expr, secondGraphUri)) {
setGraphExpression(expr);
} else {
setGraphExpression(new GraphUnion(expr, new GraphResource(secondGraphUri)));
}
}
/**
* Constructs a new query based on the current data.
*
* @return a new {@link org.mulgara.query.Query}
*/
@SuppressWarnings("unchecked")
public Query extractQuery() {
logger.debug("Extracting query");
return new Query(variables, graphs, where, having, (List<Order>)Collections.EMPTY_LIST, null, 0, true, new UnconstrainedAnswer());
}
}