/******************************************************************************* * Copyright (c) 2004, 2007 IBM Corporation and 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 * * File: $Source: /cvsroot/slrp/glitter/com.ibm.adtech.glitter/src/com/ibm/adtech/glitter/query/Construct.java,v $ * Created by: Lee Feigenbaum (<a href="mailto:feigenbl@us.ibm.com">feigenbl@us.ibm.com</a>) * Created on: 10/23/06 * Revision: $Id: Construct.java 164 2007-07-31 14:11:09Z mroy $ * * Contributors: IBM Corporation - initial API and implementation * Cambridge Semantics Incorporated - Fork to Anzo *******************************************************************************/ package org.openanzo.glitter.query; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import org.openanzo.exceptions.ExceptionConstants; import org.openanzo.exceptions.LogUtils; import org.openanzo.glitter.exception.GlitterRuntimeException; import org.openanzo.glitter.exception.InvalidBlankNodeLabelException; import org.openanzo.glitter.query.QueryController.QueryStringPrintOptions; import org.openanzo.glitter.syntax.abstrakt.TriplePatternNode; import org.openanzo.rdf.BlankNode; import org.openanzo.rdf.BlankNodeManager; import org.openanzo.rdf.Literal; import org.openanzo.rdf.Resource; import org.openanzo.rdf.Statement; import org.openanzo.rdf.TriplePattern; import org.openanzo.rdf.TriplePatternComponent; import org.openanzo.rdf.URI; import org.openanzo.rdf.Value; import org.openanzo.rdf.Variable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * The {@link Construct} query form applies the result set's bindings to an RDF template, resulting in an RDF graph. * * @author lee <lee@cambridgesemantics.com> * */ public class Construct implements QueryResultForm { private static final Logger log = LoggerFactory.getLogger(Construct.class); private final ArrayList<TriplePatternNode> template; private final ArrayList<TriplePatternComponent> templateGraph; // parallel with template private Collection<Statement> results = null; /** * Constructor. * * @param template * The triple patterns that comprise the CONSTRUCT template. * @param templateGraph * The graph into which each triple pattern should end up. Can be null (no graph), constant IRI, or a variable. */ public Construct(List<TriplePatternNode> template, List<TriplePatternComponent> templateGraph) { this.template = new ArrayList<TriplePatternNode>(template); this.templateGraph = new ArrayList<TriplePatternComponent>(templateGraph); if (this.template.size() != this.templateGraph.size()) throw new GlitterRuntimeException(ExceptionConstants.GLITTER.UNEXPECTED, "Graph parameters not provided for all triples within CONSTRUCT template"); } /** * * @return The CONSTRUCT template triple patterns. */ public List<TriplePatternNode> getTemplate() { return this.template; } /** * @return The list of quad portions of the statements in the CONSTRUCT template. In parallel with the return value of Construct.getTemplate(). */ public List<TriplePatternComponent> getTemplateGraphComponents() { return this.templateGraph; } public SolutionSet refineSolutionsBeforeOrdering(SolutionSet solutions) { return solutions; } public SolutionSet refineSolutionsAfterOrdering(SolutionSet solutions, List<OrderingCondition> sortedByConditions) { return solutions; } public Object serializeResults(SolutionSet solutionSet) { Collection<Statement> results = this.results != null ? this.results : new HashSet<Statement>(); BlankNodeManager bnm = new BlankNodeManager(false); boolean skipTriple; for (PatternSolution solution : solutionSet) { bnm.enterLabelScope(); Iterator<TriplePatternComponent> tpcIter = this.templateGraph.iterator(); for (TriplePatternNode tpn : this.template) { TriplePatternComponent tpc = tpcIter.next(); URI graph = null; skipTriple = false; TriplePattern tp = tpn.getTriplePattern(); TriplePatternComponent[] spo = new TriplePatternComponent[] { tp.getSubject(), tp.getPredicate(), tp.getObject() }; for (int i = 0; i < spo.length; i++) { if (spo[i] instanceof Variable) spo[i] = solution.getBinding((Variable) spo[i]); else if (spo[i] instanceof BlankNode) try { spo[i] = bnm.getBlankNode(spo[i].toString()); } catch (InvalidBlankNodeLabelException e) { log.warn(LogUtils.GLITTER_MARKER, "Invalid blanknode label:" + spo[i].toString(), e); } // if a var. was unbound, don't include this solution if (spo[i] == null) { skipTriple = true; break; } } if (tpc != null) { if (tpc instanceof URI) { graph = (URI) tpc; } else if (tpc instanceof Variable) { Value v = solution.getBinding((Variable) tpc); if (v instanceof URI) { graph = (URI) v; } else { skipTriple = true; } } else { skipTriple = true; } } if (spo[0] instanceof Literal || !(spo[1] instanceof URI)) skipTriple = true; if (!skipTriple) results.add(new Statement((Resource) spo[0], (URI) spo[1], (Value) spo[2], graph)); } bnm.exitLabelScope(); } this.results = results; return results; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("CONSTRUCT { "); { TriplePatternComponent lastGraph = null; for (int i = 0; i < this.template.size(); i++) { TriplePatternNode triple = this.template.get(i); TriplePatternComponent graph = this.templateGraph.get(i); // end a previous graph if the last one is non-null and this one is different if (lastGraph != null && !lastGraph.equals(graph)) { builder.append("} "); } // start a graph if this one is non-null and the last one is different if (graph != null && !graph.equals(lastGraph)) { builder.append("GRAPH "); builder.append(graph.toString()); builder.append(" { "); } builder.append(triple.toString()); if (i + 1 < this.template.size()) builder.append(". "); lastGraph = graph; } } builder.append(" }"); return builder.toString(); } public void prettyPrint(StringBuilder buffer) { buffer.append("Construct("); { TriplePatternComponent lastGraph = null; for (int i = 0; i < this.template.size(); i++) { TriplePatternNode triple = this.template.get(i); TriplePatternComponent graph = this.templateGraph.get(i); // end a previous graph if the last one is non-null and this one is different if (lastGraph != null && !lastGraph.equals(graph)) { buffer.append("), "); } // start a graph if this one is non-null and the last one is different if (graph != null && !graph.equals(lastGraph)) { buffer.append("Graph( "); buffer.append(graph.toString()); buffer.append(", "); } triple.prettyPrint(buffer); if (i + 1 < this.template.size()) buffer.append(", "); lastGraph = graph; } } buffer.append(")"); } public void prettyPrintQueryPart(EnumSet<QueryStringPrintOptions> printFlags, int indentLevel, Map<String, String> uri2prefix, StringBuilder s) { s.append("CONSTRUCT {"); indentLevel++; TriplePatternComponent lastGraph = null; for (int i = 0; i < this.template.size(); i++) { TriplePatternNode triple = this.template.get(i); TriplePatternComponent graph = this.templateGraph.get(i); QueryController.printSeparator(printFlags, indentLevel, s); // end a previous graph if the last one is non-null and this one is different if (lastGraph != null && !lastGraph.equals(graph)) { s.append("}"); indentLevel--; QueryController.printSeparator(printFlags, indentLevel, s); } // start a graph if this one is non-null and the last one is different if (graph != null && !graph.equals(lastGraph)) { s.append("GRAPH "); s.append(graph.toString()); s.append(" { "); indentLevel++; QueryController.printSeparator(printFlags, indentLevel, s); } triple.prettyPrintQueryPart(printFlags, indentLevel, uri2prefix, s); if (i + 1 < this.template.size()) s.append(". "); lastGraph = graph; } indentLevel--; QueryController.printSeparator(printFlags, indentLevel, s); s.append("}"); } public Collection<Variable> getBindableVariables() { return Collections.emptyList(); } public Collection<URI> getReferencedURIs() { HashSet<URI> uris = new HashSet<URI>(); for (TriplePatternNode tpn : this.template) uris.addAll(tpn.getReferencedURIs()); for (TriplePatternComponent tpc : this.templateGraph) if (tpc instanceof URI) uris.add((URI) tpc); return uris; } public Collection<Variable> getReferencedVariables() { HashSet<Variable> vars = new HashSet<Variable>(); for (TriplePatternNode tpn : this.template) vars.addAll(tpn.getReferencedVariables()); for (TriplePatternComponent tpc : this.templateGraph) if (tpc instanceof Variable) vars.add((Variable) tpc); return vars; } }