/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.jena.sparql.core; import java.util.Iterator ; import org.apache.jena.atlas.iterator.Iter ; import org.apache.jena.atlas.lib.Sync ; import org.apache.jena.graph.Node ; import org.apache.jena.graph.Triple ; import org.apache.jena.graph.impl.GraphBase ; import org.apache.jena.riot.other.GLib ; import org.apache.jena.shared.JenaException ; import org.apache.jena.shared.PrefixMapping ; import org.apache.jena.shared.impl.PrefixMappingImpl ; import org.apache.jena.sparql.SystemARQ ; import org.apache.jena.sparql.graph.GraphUnionRead ; import org.apache.jena.util.iterator.ExtendedIterator ; import org.apache.jena.util.iterator.WrappedIterator ; /** Implement a Graph as a view of the DatasetGraph. * * It maps graph operations to quad operations. * * {@link GraphUnionRead} provides a union graph that does not assume quads, but loops on graphs. * * @see GraphUnionRead */ public class GraphView extends GraphBase implements Sync { // Beware this implements union graph - implementations may wish // to do better so see protected method below. static class GraphViewException extends JenaException { public GraphViewException() { super(); } public GraphViewException(String message) { super(message); } public GraphViewException(Throwable cause) { super(cause) ; } public GraphViewException(String message, Throwable cause) { super(message, cause) ; } } private final DatasetGraph dsg ; private final Node gn ; // null for default graph. // Factory style. public static GraphView createDefaultGraph(DatasetGraph dsg) { return new GraphView(dsg, Quad.defaultGraphNodeGenerated) ; } public static GraphView createNamedGraph(DatasetGraph dsg, Node graphIRI) { return new GraphView(dsg, graphIRI) ; } public static GraphView createUnionGraph(DatasetGraph dsg) { return new GraphView(dsg, Quad.unionGraph) ; } // If inherited. protected GraphView(DatasetGraph dsg, Node gn) { this.dsg = dsg ; this.gn = gn ; } /** * Return the graph name for this graph in the dataset it is a view of. * Returns {@code null} for the default graph. */ public Node getGraphName() { return (gn == Quad.defaultGraphNodeGenerated) ? null : gn ; } /** Return the DatasetGraph we are viewing. */ public DatasetGraph getDataset() { return dsg ; } protected final boolean isDefaultGraph() { return isDefaultGraph(gn) ; } protected final boolean isUnionGraph() { return isUnionGraph(gn) ; } protected static final boolean isDefaultGraph(Node gn) { return gn == null || Quad.isDefaultGraph(gn) ; } protected static final boolean isUnionGraph(Node gn) { return Quad.isUnionGraph(gn) ; } // TODO Unsatisfactory - need PrefixMap support by DSGs // and sort out PrefixMap/PrefixMapping. @Override protected PrefixMapping createPrefixMapping() { // Subclasses should override this but in the absence of anything better ... return new PrefixMappingImpl() ; } @Override protected ExtendedIterator<Triple> graphBaseFind(Triple m) { if ( m == null ) m = Triple.ANY ; Node s = m.getMatchSubject() ; Node p = m.getMatchPredicate() ; Node o = m.getMatchObject() ; return graphBaseFind(s, p, o) ; } @Override protected ExtendedIterator<Triple> graphBaseFind(Node s, Node p, Node o) { if ( Quad.isUnionGraph(gn) ) return graphUnionFind(s, p, o) ; Node g = graphNode(gn) ; Iterator<Triple> iter = GLib.quads2triples(dsg.find(g, s, p, o)) ; return WrappedIterator.createNoRemove(iter) ; } private static Node graphNode(Node gn) { return ( gn == null ) ? Quad.defaultGraphNodeGenerated : gn ; } protected ExtendedIterator<Triple> graphUnionFind(Node s, Node p, Node o) { Node g = graphNode(gn) ; // Implementations may wish to do better so this is separated out. // For example, Iter.distinctAdjacent is a lot cheaper than Iter.distinct // but assumes thing come back in a particular order Iterator<Quad> iterQuads = getDataset().find(g, s, p, o) ; Iterator<Triple> iter = GLib.quads2triples(iterQuads) ; // Suppress duplicates after projecting to triples. iter = Iter.distinct(iter) ; return WrappedIterator.createNoRemove(iter) ; } @Override public void performAdd( Triple t ) { Node g = graphNode(gn) ; if ( Quad.isUnionGraph(g) ) throw new GraphViewException("Can't update the default union graph of a dataset") ; Node s = t.getSubject() ; Node p = t.getPredicate() ; Node o = t.getObject() ; dsg.add(g, s, p, o) ; } @Override public void performDelete( Triple t ) { Node g = graphNode(gn) ; if ( Quad.isUnionGraph(g) ) throw new GraphViewException("Can't update the default union graph of a dataset") ; Node s = t.getSubject() ; Node p = t.getPredicate() ; Node o = t.getObject() ; dsg.delete(g, s, p, o) ; } @Override public void sync() { SystemARQ.sync(dsg); } }