All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.topbraid.jenax.util.DiffGraph Maven / Gradle / Ivy

There is a newer version: 1.4.3
Show newest version
package org.topbraid.jenax.util;

import java.util.HashSet;
import java.util.Set;

import org.apache.jena.graph.Graph;
import org.apache.jena.graph.Node;
import org.apache.jena.graph.Triple;
import org.apache.jena.graph.impl.GraphMatcher;
import org.apache.jena.graph.impl.GraphWithPerform;
import org.apache.jena.mem.GraphMem;
import org.apache.jena.shared.PrefixMapping;
import org.apache.jena.shared.impl.PrefixMappingImpl;
import org.apache.jena.util.iterator.ExtendedIterator;


// TODO: note this graph does not correctly implement GraphWithPerform and event notification contracts
/**
 * A WrappedGraph that filters out deleted triples or adds added triples, without
 * modifying the underlying base graph.
 * 
 * Similar to BufferingGraph in TopBraid, but with minimal code dependencies
 * and simpler contracts that are just right for use in SPARQLMotion.
 * 
 * @author Holger Knublauch
 */
public class DiffGraph extends TransparentWrappedGraph {

	/**
	 * This graph has additional triples that are not in the delegate.
	 */
	private GraphWithPerform addedGraph = new GraphMem();
	
	/**
	 * This Set has triples that are in the delegate but are excluded
	 * from the filtered graph.
	 */
	protected Set deletedTriples = new HashSet();
	
	private PrefixMapping pm;

	
	public DiffGraph(Graph base) {
		super(base);
	}
	
	
	@Override
	public void add(Triple t) {
		performAdd(t);
	}


	@Override
	public void delete(Triple t) {
		performDelete(t);
	}


	public Graph getAddedGraph() {
		return addedGraph;
	}

	
	@Override
	public boolean contains(Node s, Node p, Node o) {
		return contains(Triple.create(s, p, o));
	}
	
	
	@Override
	public boolean contains(Triple t) {
		if(addedGraph.contains(t)) {
			return true;
		}
		else {
			ExtendedIterator it = base.find(t);
			while(it.hasNext()) {
				Triple n = it.next();
				if(!deletedTriples.contains(n)) {
					it.close();
					return true;
				}
			}
			return false;
		}
	}

	
	// TODO: If the delegate does not use equals for add and delete
	// but sameValueAs then this code is incorrect.
	// Specifically we should be able to show bugs with TDB which does
	// something different from either equals or sameValueAs.
	private boolean containsByEquals(Graph g,Triple t) {
		ExtendedIterator it = g.find(t);
		try {
			while (it.hasNext()) {
				if (t.equals(it.next())) 
					return true;
			}
		}
		finally {
			it.close();
		}
		return false;
	}


	@Override
	public ExtendedIterator find(Node s, Node p, Node o) {

		// First get the underlying base query (without any buffered triples)
		ExtendedIterator base = super.find(s, p, o);

		// If deleted triples exist then continue with a filtered iterator
		if(deletedTriples.size() > 0) {
			// base without deleted triples.
			base = base.filterDrop(deletedTriples::contains);
		}

		// If added triples exist then chain the two together
		// this iterator supports remove and removes correctly for this graph
		ExtendedIterator added = addedGraph.find(s, p, o);
		if(added.hasNext()) {
			return base.andThen(added);  // base and added are guaranteed disjoint
		}
		else {
			return base;
		}
	}


	@Override
	public ExtendedIterator find(Triple m) {
		return find(m.getMatchSubject(), m.getMatchPredicate(), m.getMatchObject());
	}


	public Set getDeletedTriples() {
		return deletedTriples;
	}


	@Override
	public PrefixMapping getPrefixMapping() {
		if (pm == null) {
			// copy delegate's prefix mapping.
			pm = new PrefixMappingImpl().setNsPrefixes(base.getPrefixMapping());
		}
		return pm;
	}

	
	@Override
	public boolean isEmpty() {
		if (!addedGraph.isEmpty()) {
			return false;
		}
		if (deletedTriples.isEmpty()) {
			return base.isEmpty();
		}
		ExtendedIterator it = find(Triple.ANY);
		try {
			return !it.hasNext();
		}
		finally {
			it.close();
		}
	}

	
    @Override
    public boolean isIsomorphicWith(Graph g) { 
		return g != null && GraphMatcher.equals(this, g);
    }


	@Override
	public void performAdd(Triple t) {
    	if (deletedTriples.contains(t)) {
    		deletedTriples.remove(t);
    		// getEventManager().notifyAddTriple(this, t);
    	}
    	else if (containsByEquals(addedGraph,t) || containsByEquals(base, t) ) {
    		// notify even unsuccessful adds - see javadoc for graphlistener
    		// getEventManager().notifyAddTriple(this, t);
        }
    	else {
    		// addedGraph does notification for us.
    		addedGraph.add(t);
    	}
	}


	@Override
	public void performDelete(Triple t) {
		if( containsByEquals(addedGraph,t) ) {
			// addedGraph does notification for us.
			addedGraph.delete(t);
		} 
		else if ( containsByEquals(base, t) ) {
			deletedTriples.add(t);
			// getEventManager().notifyDeleteTriple(this, t);
		} 
		else {
			// notify even unsuccessful deletes - see javadoc for graphlistener
			// getEventManager().notifyDeleteTriple(this, t);
			return;
		}
	}

	
	@Override
	public int size() {
		return super.size() - deletedTriples.size() + addedGraph.size();
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy