package org.aksw.jena_sparql_api.utils;
import java.util.ArrayList;
import java.util.List;
import org.apache.jena.graph.Node;
import org.apache.jena.graph.Triple;
import org.apache.jena.sparql.core.Quad;
import org.apache.jena.sparql.core.TriplePath;
import org.apache.jena.sparql.expr.Expr;
import org.apache.jena.sparql.syntax.Element;
import org.apache.jena.sparql.syntax.ElementAssign;
import org.apache.jena.sparql.syntax.ElementBind;
import org.apache.jena.sparql.syntax.ElementData;
import org.apache.jena.sparql.syntax.ElementDataset;
import org.apache.jena.sparql.syntax.ElementExists;
import org.apache.jena.sparql.syntax.ElementFilter;
import org.apache.jena.sparql.syntax.ElementGroup;
import org.apache.jena.sparql.syntax.ElementMinus;
import org.apache.jena.sparql.syntax.ElementNamedGraph;
import org.apache.jena.sparql.syntax.ElementNotExists;
import org.apache.jena.sparql.syntax.ElementOptional;
import org.apache.jena.sparql.syntax.ElementPathBlock;
import org.apache.jena.sparql.syntax.ElementService;
import org.apache.jena.sparql.syntax.ElementSubQuery;
import org.apache.jena.sparql.syntax.ElementTriplesBlock;
import org.apache.jena.sparql.syntax.ElementUnion;
import org.apache.jena.sparql.syntax.ElementVisitor;
// Adoption by Claus Stadler 2013
/**
* <p>Utility class that walks the Elements of an ARQ query tree and
* collects information that is later used to build an SQL query.</p>
*
* <p>The class provides a different view on the tree of Element
* instances. In this view, the nodes are ElementTreeAnalyser
* instances, and the structure of the tree differs in several
* ways from the Element tree:</p>
*
* <ul>
* <li>ElementGroups and ElementBlocks are flattened away</li>
* <li>Only OPTIONALs and UNIONs are presented as child nodes</li>
* <li>The difference between ElementTriplePattern and
* ElementBasePattern is hidden</li>
* <li>Some obvious simplifications have been done, like dropping
* OPTIONALs that do not bind, or flatten single-element UNIONs</li>
* <li>GRAPH clauses and triples are flattened into triples, quads,
* and graphNames, where triples are to be matched against the
* default graph, quads are to be matched against the named graphs,
* and graphNames are to be matched against the list of graph names,
* regardless of triples therein.</li>
* </ul>
*
* @author Richard Cyganiak (richard@cyganiak.de)
* @version $Id$
*/
public class ElementTreeAnalyser implements ElementVisitor {
private Node defaultGraphName;
private boolean isEmpty = true;
private boolean canBind = false;
private boolean mustMatchTriple = false;
//private List<Triple> triples = new ArrayList(); // Triples
private List<Quad> quads = new ArrayList<Quad>(); // Quads
private List<Node> graphNames = new ArrayList<Node>(); // Nodes
private List<ElementTreeAnalyser> optionals = new ArrayList<ElementTreeAnalyser>(); // ElementAnalysers
private List<ElementTreeAnalyser> unions = new ArrayList<ElementTreeAnalyser>(); // Lists of ElementAnalysers
private List<Expr> filterExprs = new ArrayList<Expr>(); // Constraints
public ElementTreeAnalyser(Element element) {
this(element, Quad.defaultGraphNodeGenerated);
}
public ElementTreeAnalyser(Element element, Node defaultGraphName) {
this.defaultGraphName = defaultGraphName;
element.visit(this);
}
public boolean isEmpty() {
return isEmpty;
}
public boolean canBind() {
return canBind;
}
public boolean mustMatchTriple() {
return mustMatchTriple;
}
public List<Quad> getQuads() {
return quads;
}
public List<ElementTreeAnalyser> getOptionals() {
return optionals;
}
public List<Node> getGraphNames() {
return graphNames;
}
public List<ElementTreeAnalyser> getUnions() {
return unions;
}
// public List graphNames() {
// return graphNames;
// }
public List<ElementTreeAnalyser> optionals() {
return optionals;
}
public List<ElementTreeAnalyser> unions() {
return unions;
}
public List<Expr> getFilterExprs() {
return filterExprs;
}
public void visit(ElementTriplesBlock el) {
for(Triple t : el.getPattern().getList()) {
isEmpty = false;
if (t.getSubject().isVariable()
|| t.getPredicate().isVariable()
|| t.getObject().isVariable()) {
canBind = true;
}
if (defaultGraphName == null) {
Quad quad = new Quad(defaultGraphName, t);
quads.add(quad);
} else {
quads.add(new Quad(defaultGraphName, t));
}
mustMatchTriple = true;
}
}
public void visit(ElementFilter el) {
isEmpty = false;
filterExprs.add(el.getExpr());
}
public void visit(ElementUnion el) {
List<Element> elements = el.getElements();
if (elements.size() == 1) {
elements.get(0).visit(this);
return;
}
List<ElementTreeAnalyser> union = new ArrayList<ElementTreeAnalyser>();
boolean allMustMatchTriple = true;
boolean anyMustMatchTriple = false;
for(Element element : el.getElements()) {
ElementTreeAnalyser analyser = new ElementTreeAnalyser(element, defaultGraphName);
if (analyser.isEmpty()) {
allMustMatchTriple = false;
continue;
}
isEmpty = false;
if (analyser.canBind()) {
canBind = true;
}
allMustMatchTriple = allMustMatchTriple && analyser.mustMatchTriple();
anyMustMatchTriple = anyMustMatchTriple || analyser.mustMatchTriple();
union.add(analyser);
}
if (anyMustMatchTriple && allMustMatchTriple) {
mustMatchTriple = true;
}
if (!union.isEmpty()) {
unions.addAll(union);
}
}
// public void visit(ElementBlock el) {
// recurse(Collections.singletonList(el.getPatternElement()));
// }
public void visit(ElementOptional el) {
ElementTreeAnalyser optional = new ElementTreeAnalyser(el.getOptionalElement(), defaultGraphName);
if (optional.isEmpty() || !optional.canBind()) {
return;
}
isEmpty = false;
canBind = true;
optionals.add(optional);
}
public void visit(ElementGroup el) {
recurse(el.getElements());
}
public void visit(ElementNamedGraph el) {
isEmpty = false;
ElementTreeAnalyser analyser = new ElementTreeAnalyser(el.getElement(), el.getGraphNameNode());
if (!analyser.mustMatchTriple()) {
graphNames.add(el.getGraphNameNode());
}
if (el.getGraphNameNode().isVariable() || analyser.canBind()) {
canBind = true;
}
for(Quad quad : analyser.getQuads()) {
quads.add(new Quad(el.getGraphNameNode(), quad.asTriple()));
}
quads.addAll(analyser.getQuads());
graphNames.addAll(analyser.getGraphNames());
optionals.addAll(analyser.getOptionals());
unions.addAll(analyser.getUnions());
filterExprs.addAll(analyser.getFilterExprs());
}
private void recurse(List<Element> elements) {
for(Element element : elements) {
element.visit(this);
}
}
@Override
public void visit(ElementPathBlock el) {
// TODO Paths not handled yet
List<TriplePath> triplePaths = el.getPattern().getList();
for(TriplePath triplePath : triplePaths) {
Triple triple = triplePath.asTriple();
Quad quad = new Quad(defaultGraphName, triple);
quads.add(quad);
}
//throw new RuntimeException("Not implemented");
}
@Override
public void visit(ElementAssign el) {
throw new RuntimeException("Not implemented");
}
@Override
public void visit(ElementBind el) {
throw new RuntimeException("Not implemented");
}
@Override
public void visit(ElementData el) {
throw new RuntimeException("Not implemented");
}
@Override
public void visit(ElementDataset el) {
throw new RuntimeException("Not implemented");
}
@Override
public void visit(ElementExists el) {
throw new RuntimeException("Not implemented");
}
@Override
public void visit(ElementNotExists el) {
throw new RuntimeException("Not implemented");
}
@Override
public void visit(ElementMinus el) {
throw new RuntimeException("Not implemented");
}
@Override
public void visit(ElementService el) {
throw new RuntimeException("Not implemented");
}
// @Override
// public void visit(ElementFetch el) {
// throw new RuntimeException("Not implemented");
// }
@Override
public void visit(ElementSubQuery el) {
throw new RuntimeException("Not implemented");
}
}
/*
* (c) Copyright 2000, 2001, 2002, 2003, 2004, 2005 Hewlett-Packard Development Company, LP
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id$
*/