blob: 6ff367c7c4020e8e3fed42818d54e942aeb18490 [file] [log] [blame]
/**
* 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.*;
import org.apache.jena.graph.impl.GraphBase ;
import org.apache.jena.riot.other.GLib ;
import org.apache.jena.shared.AddDeniedException;
import org.apache.jena.shared.DeleteDeniedException;
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 NamedGraph, 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 ;
// null for default graph.
private final Node gn ;
private final TransactionHandlerView transactionHandler;
// 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) ; }
protected GraphView(DatasetGraph dsg, Node gn) {
this.dsg = dsg ;
this.gn = gn ;
this.transactionHandler = new TransactionHandlerView(dsg);
}
/**
* Return the graph name for this graph in the dataset it is a view of.
* Returns {@code null} for the default graph.
*/
@Override
public Node getGraphName() {
return (gn == Quad.defaultGraphNodeGenerated) ? null : gn ;
}
/** Return the {@link 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) ; }
@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 things 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 AddDeniedException("Can't update the 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 DeleteDeniedException("Can't update the 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 remove(Node s, Node p, Node o) {
if ( getEventManager().listening() ) {
// Have to do it the hard way so that triple events happen.
super.remove(s, p, o);
return;
}
dsg.deleteAny(getGraphName(), s, p, o);
// We know no one is listening ...
// getEventManager().notifyEvent(this, GraphEvents.remove(s, p, o) );
}
/**
* Subclasses may wish to provide {@code graphBaseSize} otherwise {@link GraphBase} uses {@code find()}.
*/
@Override protected int graphBaseSize() { return super.graphBaseSize(); }
@Override
public void sync() {
SystemARQ.sync(dsg);
}
@Override
public TransactionHandler getTransactionHandler() {
return new TransactionHandlerView(dsg);
}
@Override
public Capabilities getCapabilities() {
if (capabilities == null)
capabilities = new GraphViewCapabilities();
return capabilities;
}
protected static class GraphViewCapabilities implements Capabilities {
@Override
public boolean sizeAccurate() {
return true;
}
@Override
public boolean addAllowed() {
return addAllowed(false);
}
@Override
public boolean addAllowed(boolean every) {
return true;
}
@Override
public boolean deleteAllowed() {
return deleteAllowed(false);
}
@Override
public boolean deleteAllowed(boolean every) {
return true;
}
@Override
public boolean canBeEmpty() {
return true;
}
@Override
public boolean iteratorRemoveAllowed() {
//Default for GraphViews is that iterators do not provide remove.
return false;
}
@Override
public boolean findContractSafe() {
return true;
}
@Override
public boolean handlesLiteralTyping() {
return false;
}
}
}