/*******************************************************************************
* Copyright (c) 2009 Cambridge Semantics Incorporated.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Cambridge Semantics Incorporated
*******************************************************************************/
package org.openanzo.glitter.query;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.collections15.BidiMap;
import org.apache.commons.collections15.bidimap.TreeBidiMap;
import org.openanzo.glitter.Engine;
import org.openanzo.glitter.dataset.QueryDataset;
import org.openanzo.glitter.syntax.concrete.ParseException;
import org.openanzo.rdf.URI;
import org.openanzo.rdf.Variable;
/**
* A SubqueryController specializes {@link QueryController} to be used for capturing the details of a subquery. Subqueries are more limited versions of full
* queries - they can only be initialized from existing queries and copy things like base URI, prefix map, and dataset information from their parent.
*
* @author lee <lee@cambridgesemantics.com>
*
*/
public class SubqueryController extends QueryController {
private QueryController parent;
/**
* @param parent
*/
public SubqueryController(QueryController parent) {
this.parent = parent;
}
@Override
public void setEngine(Engine engine) {
if (engine == null || !engine.equals(getEngine()))
throw new UnsupportedOperationException("Subqueries cannot have a different engine from the parent query.");
}
@Override
public Engine getEngine() {
return this.parent.getEngine();
}
@Override
public QueryDataset getQueryDataset() {
return parent.getQueryDataset();
}
@Override
public void setQueryDataset(QueryDataset queryDataset) {
throw new UnsupportedOperationException("Subqueries cannot set the query Dataset.");
}
@Override
public void setBaseUri(URI u) {
throw new UnsupportedOperationException("Subqueries cannot have a different base URI from the parent query.");
}
@Override
public URI getBaseUri() {
return this.parent.getBaseUri();
}
@Override
public void mapPrefix(String prefix, URI uri) {
throw new UnsupportedOperationException("Subqueries cannot have a different set of prefixes from the parent query.");
}
@Override
public URI resolveQName(String prefix, String localPart) throws ParseException {
return this.parent.resolveQName(prefix, localPart);
}
@Override
public SolutionGenerator getSolutionGenerator() {
return this.parent.getSolutionGenerator();
}
@Override
public void setSolutionGenerator(SolutionGenerator solutionGenerator) {
throw new UnsupportedOperationException("Subqueries cannot have a different solution generator from the parent query.");
}
@Override
public void prettyPrint(StringBuilder buffer) {
buffer.append("Query(");
int limit = this.getLimit();
if (limit > -1)
buffer.append("LIMIT(" + limit + "), ");
int offset = this.getOffset();
if (offset > -1)
buffer.append("OFFSET(" + offset + "), ");
List<OrderingCondition> orderingConditions = this.getOrderingConditions();
if (orderingConditions.size() > 0) {
buffer.append("OrderBy(");
int i = 0;
for (OrderingCondition condition : orderingConditions) {
condition.getCondition().prettyPrint(buffer);
if (++i < orderingConditions.size())
buffer.append(", ");
}
buffer.append("), ");
}
this.getQueryResultForm().prettyPrint(buffer);
buffer.append(", GraphPattern(");
queryPattern.prettyPrint(buffer);
buffer.append(")");
buffer.append(")");
}
/**
* Pretty print query string
*
* @param printFlags
* print flags
* @param startIndentLevel
* @return pretty print version of query
*/
@SuppressWarnings("all")
public String prettyPrintQueryString(EnumSet<QueryStringPrintOptions> printFlags, int startIndentLevel) {
StringBuilder s = new StringBuilder();
prettyPrintQueryStringPart(printFlags, startIndentLevel, s);
return s.toString();
}
/**
* Pretty print query string
*
* @param printFlags
* print flags
* @param startIndentLevel
* @return pretty print version of query
*/
@SuppressWarnings("all")
public void prettyPrintQueryStringPart(EnumSet<QueryStringPrintOptions> printFlags, int startIndentLevel, StringBuilder s) {
QueryResultForm queryResultForm = this.getQueryResultForm();
final BidiMap<String, String> prefix2uri = new TreeBidiMap<String, String>();
Map<String, String> uri2prefix = prefix2uri.inverseBidiMap();
for (Entry<String, URI> e : this.parent.prefixMap.entrySet())
prefix2uri.put(e.getKey(), e.getValue().toString());
this.resultForm.prettyPrintQueryPart(printFlags, startIndentLevel, uri2prefix, s);
printSeparator(printFlags, startIndentLevel, s);
s.append("WHERE {");
printSeparator(printFlags, startIndentLevel + 1, s);
this.queryPattern.prettyPrintQueryPart(printFlags, startIndentLevel + 1, uri2prefix, s);
printSeparator(printFlags, startIndentLevel, s);
s.append("}");
if (queryResultForm instanceof Projection) {
Projection projection = (Projection) queryResultForm;
if (!projection.getGroupByVariables().isEmpty()) {
printSeparator(printFlags, startIndentLevel, s);
projection.prettyPrintGroupByQueryPart(printFlags, startIndentLevel, uri2prefix, s);
}
}
if (this.ordering.size() > 0) {
printSeparator(printFlags, 0, s);
s.append("ORDER BY ");
for (int i = 0; i < this.ordering.size(); i++) {
OrderingCondition c = this.ordering.get(i);
if (i != 0)
s.append(' ');
c.prettyPrintQueryPart(printFlags, startIndentLevel, uri2prefix, s);
}
printSeparator(printFlags, startIndentLevel, s);
}
if (this.limit > -1) {
printSeparator(printFlags, startIndentLevel, s);
s.append("LIMIT ");
s.append(this.limit);
}
if (this.offset > -1) {
printSeparator(printFlags, startIndentLevel, s);
s.append("OFFSET ");
s.append(this.offset);
}
}
@Override
public String getQueryString(boolean includeFromClauses) {
QueryResultForm queryResultForm = this.getQueryResultForm();
StringBuilder s = new StringBuilder(this.resultForm.toString());
s.append(" WHERE { ");
s.append(this.queryPattern);
s.append(" }");
if (this.ordering.size() > 0) {
s.append(" ORDER BY");
for (OrderingCondition c : this.ordering)
s.append(" " + c.getCondition());
}
if (queryResultForm instanceof Projection) {
Projection projection = (Projection) queryResultForm;
List<Variable> vars = projection.getGroupByVariables();
if (vars != null && !vars.isEmpty()) {
s.append(" GROUP BY");
for (Variable v : vars)
s.append(" " + v);
}
}
if (this.limit > -1)
s.append(" LIMIT " + this.limit);
if (this.offset > -1)
s.append(" OFFSET " + this.offset);
return s.toString();
}
}