/*
* 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.graph;
import java.util.Iterator ;
import java.util.List ;
import java.util.Set ;
import org.apache.jena.graph.impl.GraphWithPerform ;
import org.apache.jena.util.IteratorCollection ;
import org.apache.jena.util.iterator.ExtendedIterator ;
import org.apache.jena.util.iterator.WrappedIterator ;
/**
An ad-hoc collection of useful code for graphs
*/
public class GraphUtil
{
/**
* Only static methods here - the class cannot be instantiated.
*/
private GraphUtil()
{}
/** Return an iterator over the unique subjects with predciate p and object o.
* p and o can be wildcards (Node.ANY)
* @param g Graph
* @param p Predicate - may be Node.ANY
* @param o Object - may be Node.ANY
* @return ExtendedIterator
*/
public static ExtendedIterator<Node> listSubjects(Graph g, Node p, Node o) {
// Restore a minimal QueryHandler?
ExtendedIterator<Triple> iter = g.find(Node.ANY, p, o) ;
Set<Node> nodes = iter.mapWith(t -> t.getSubject()).toSet() ;
return WrappedIterator.createNoRemove(nodes.iterator()) ;
}
/** Return an iterator over the unique predicate between s and o.
* s and o can be wildcards (Node.ANY)
* @param g Graph
* @param s Subject - may be Node.ANY
* @param o Object - may be Node.ANY
* @return ExtendedIterator
*/
public static ExtendedIterator<Node> listPredicates(Graph g, Node s, Node o) {
ExtendedIterator<Triple> iter = g.find(s,Node.ANY, o) ;
Set<Node> nodes = iter.mapWith(t -> t.getPredicate()).toSet() ;
return WrappedIterator.createNoRemove(nodes.iterator()) ;
}
/** Return an iterator over the unique objects with a given subject and object.
* s and p can be wildcards (Node.ANY)
* @param g Graph
* @param s Subject - may be Node.ANY
* @param p Predicate - may be Node.ANY
* @return ExtendedIterator
*/
public static ExtendedIterator<Node> listObjects(Graph g, Node s, Node p) {
ExtendedIterator<Triple> iter = g.find(s, p, Node.ANY) ;
Set<Node> nodes = iter.mapWith(t -> t.getObject()).toSet() ;
return WrappedIterator.createNoRemove(nodes.iterator()) ;
}
/** Does the graph use the node anywhere as a subject, predciate or object? */
public static boolean containsNode(Graph graph, Node node) {
return
graph.contains(node, Node.ANY, Node.ANY) ||
graph.contains(Node.ANY, Node.ANY, node) ||
graph.contains(Node.ANY, node, Node.ANY) ;
}
/* Control how events are dealt with in bulk */
private static final boolean OldStyle = true ;
/**
* Answer an iterator covering all the triples in the specified graph.
*
* @param g
* the graph from which to extract triples
* @return an iterator over all the graph's triples
*/
public static ExtendedIterator<Triple> findAll(Graph g) {
return g.find(Triple.ANY) ;
}
public static void add(Graph graph, Triple[] triples) {
if ( OldStyle && graph instanceof GraphWithPerform )
{
GraphWithPerform g = (GraphWithPerform)graph ;
for (Triple t : triples )
g.performAdd(t) ;
graph.getEventManager().notifyAddArray(graph, triples) ;
}
else
{
for (Triple t : triples )
graph.add(t) ;
}
}
public static void add(Graph graph, List<Triple> triples) {
if ( OldStyle && graph instanceof GraphWithPerform )
{
GraphWithPerform g = (GraphWithPerform)graph ;
for (Triple t : triples)
g.performAdd(t) ;
graph.getEventManager().notifyAddList(graph, triples) ;
} else
{
for (Triple t : triples)
graph.add(t) ;
}
}
public static void add(Graph graph, Iterator<Triple> it) {
// Materialize to avoid ConcurrentModificationException.
List<Triple> s = IteratorCollection.iteratorToList(it) ;
if ( OldStyle && graph instanceof GraphWithPerform )
{
GraphWithPerform g = (GraphWithPerform)graph ;
for (Triple t : s)
g.performAdd(t) ;
graph.getEventManager().notifyAddIterator(graph, s) ;
}
else
{
for (Triple t : s)
graph.add(t) ;
}
}
/** Add triples into the destination (arg 1) from the source (arg 2)*/
public static void addInto(Graph dstGraph, Graph srcGraph ) {
dstGraph.getPrefixMapping().setNsPrefixes(srcGraph.getPrefixMapping()) ;
addIteratorWorker(dstGraph, GraphUtil.findAll( srcGraph ));
dstGraph.getEventManager().notifyAddGraph( dstGraph, srcGraph );
}
private static void addIteratorWorker( Graph graph, Iterator<Triple> it ) {
List<Triple> s = IteratorCollection.iteratorToList( it );
if ( OldStyle && graph instanceof GraphWithPerform )
{
GraphWithPerform g = (GraphWithPerform)graph ;
for (Triple t : s )
g.performAdd(t) ;
}
else
{
for (Triple t : s )
graph.add(t) ;
}
}
public static void delete(Graph graph, Triple[] triples) {
if ( OldStyle && graph instanceof GraphWithPerform ) {
GraphWithPerform g = (GraphWithPerform)graph ;
for ( Triple t : triples )
g.performDelete(t) ;
graph.getEventManager().notifyDeleteArray(graph, triples) ;
} else {
for ( Triple t : triples )
graph.delete(t) ;
}
}
public static void delete(Graph graph, List<Triple> triples)
{
if ( OldStyle && graph instanceof GraphWithPerform ) {
GraphWithPerform g = (GraphWithPerform)graph ;
for ( Triple t : triples )
g.performDelete(t) ;
graph.getEventManager().notifyDeleteList(graph, triples) ;
} else {
for ( Triple t : triples )
graph.delete(t) ;
}
}
public static void delete(Graph graph, Iterator<Triple> it)
{
// Materialize to avoid ConcurrentModificationException.
List<Triple> s = IteratorCollection.iteratorToList(it) ;
if ( OldStyle && graph instanceof GraphWithPerform ) {
GraphWithPerform g = (GraphWithPerform)graph ;
for ( Triple t : s )
g.performDelete(t) ;
graph.getEventManager().notifyDeleteIterator(graph, s) ;
} else {
for ( Triple t : s )
graph.delete(t) ;
}
}
/** Delete triples the destination (arg 1) as given in the source (arg 2) */
public static void deleteFrom(Graph dstGraph, Graph srcGraph) {
deleteIteratorWorker(dstGraph, GraphUtil.findAll(srcGraph)) ;
dstGraph.getEventManager().notifyDeleteGraph(dstGraph, srcGraph) ;
}
private static void deleteIteratorWorker(Graph graph, Iterator<Triple> it) {
List<Triple> s = IteratorCollection.iteratorToList(it) ;
if ( OldStyle && graph instanceof GraphWithPerform ) {
GraphWithPerform g = (GraphWithPerform)graph ;
for ( Triple t : s )
g.performDelete(t) ;
} else {
for ( Triple t : s )
graph.delete(t) ;
}
}
private static final int sliceSize = 1000 ;
/** A safe and cautious remove() function that converts the remove to
* a number of {@link Graph#delete(Triple)} operations.
* <p>
* To avoid any possible ConcurrentModificationExceptions,
* it finds batches of triples, deletes them and tries again until
* no more triples matching the input can be found.
*/
public static void remove(Graph g, Node s, Node p, Node o) {
// Beware of ConcurrentModificationExceptions.
// Delete in batches.
// That way, there is no active iterator when a delete
// from the indexes happens.
Triple[] array = new Triple[sliceSize] ;
while (true) {
// Convert/cache s,p,o?
// The Node Cache will catch these so don't worry unduely.
ExtendedIterator<Triple> iter = g.find(s, p, o) ;
// Get a slice
int len = 0 ;
for ( ; len < sliceSize ; len++ ) {
if ( !iter.hasNext() )
break ;
array[len] = iter.next() ;
}
// Delete them.
for ( int i = 0 ; i < len ; i++ ) {
g.delete(array[i]) ;
array[i] = null ;
}
// Finished?
if ( len < sliceSize )
break ;
}
}
}