/*
* 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.util.graph;
import java.util.Collection ;
import java.util.Iterator ;
import java.util.SortedMap ;
import java.util.TreeMap ;
import java.util.function.Predicate;
import java.util.regex.Matcher ;
import java.util.regex.Pattern ;
import org.apache.jena.atlas.logging.Log ;
import org.apache.jena.graph.Graph ;
import org.apache.jena.graph.Node ;
import org.apache.jena.graph.Triple ;
import org.apache.jena.sparql.expr.Expr ;
import org.apache.jena.util.iterator.ExtendedIterator ;
import org.apache.jena.vocabulary.RDF ;
import org.apache.jena.vocabulary.RDFS ;
public class GraphContainerUtils
{
private static final Node RDFtype = RDF.type.asNode() ;
private static final Node BAG = RDF.Bag.asNode() ;
private static final Node ALT = RDF.Alt.asNode() ;
private static final Node SEQ = RDF.Seq.asNode() ;
private static final String membershipPattern$ = RDF.getURI()+"_(\\d+)" ;
private static final Pattern membershipPattern = Pattern.compile(membershipPattern$) ;
private static final int NOT_FOUND = -9999 ;
public static Collection<Node> containerMembers(Graph graph, Node container)
{ return containerMembers(graph, container, null) ; }
public static Collection<Node> containerMembers(Graph graph, Node container, Node containerType)
{
if ( ! isContainer(graph, container, containerType) )
return null ;
ExtendedIterator<Triple> iter = graph.find(container, Node.ANY, Node.ANY) ;
SortedMap<Integer, Node> triples = new TreeMap<>(order) ;
try {
for ( ; iter.hasNext() ; )
{
Triple t = iter.next() ;
int index = getIndex(t) ;
if ( index == NOT_FOUND )
continue ;
// Insert
triples.put(new Integer(index), t.getObject()) ;
}
} finally { iter.close() ; }
return triples.values() ;
}
// List x = new ArrayList() ;
// try {
// for ( ; iter.hasNext() ; )
// {
// // Sort triples in a sorted set.
// // Then extract.
// Triple t = (Triple)iter.next() ;
// String p = t.getPredicate().getURI() ;
//
// if ( p.matches(membershipPattern) )
// x.add(t.getObject()) ;
// }
// } finally { iter.close() ; }
// return x ;
// }
public static boolean isContainerMember(Graph graph, Node container, Node containerType, Node member)
{
return countContainerMember(graph, container, containerType, member, true) != 0 ;
}
public static int countContainerMember(Graph graph, Node container, Node containerType, Node member)
{
return countContainerMember(graph, container, containerType, member, false) ;
}
private static Node RDFSmember = RDFS.member.asNode() ;
private static Predicate<Triple> filterRDFSmember = new Predicate<Triple>() {
@Override
public boolean test(Triple triple) {
Node p = triple.getPredicate() ;
if ( ! triple.getPredicate().isURI() )
return false ;
if (RDFSmember.equals(p) )
return true ;
String u = triple.getPredicate().getURI() ;
return membershipPattern.matcher(u).matches() ;
} } ;
/** Calculate graph.find(?, rdfs:member, ?) */
public static Iterator<Triple> rdfsMember(Graph graph, Node s, Node o) {
ExtendedIterator<Triple> iter = graph.find(s, Node.ANY, o) ;
return iter.filterKeep(filterRDFSmember) ;
}
private static int countContainerMember(Graph graph, Node container, Node containerType, Node member, boolean stopEarly)
{
if ( graph == null )
{
Log.warn(GraphContainerUtils.class, "containerMember called with null graph") ;
return 0 ;
}
if ( container == null )
{
Log.warn(GraphContainerUtils.class, "containerMember called with null list") ;
return 0 ;
}
if ( member == null )
{
Log.warn(GraphContainerUtils.class, "containerMember called with null member") ;
return 0 ;
}
if ( ! isContainer(graph, container, containerType) )
return 0 ;
int count = 0 ;
ExtendedIterator<Triple> iter = graph.find(container, Node.ANY, member) ;
try {
for ( ; iter.hasNext() ; )
{
Triple t = iter.next() ;
Node p = t.getPredicate() ;
String u = p.getURI() ;
if ( membershipPattern.matcher(u).matches() ) {
count ++ ;
if ( stopEarly )
return count ;
}
}
} finally { iter.close() ; }
return count ;
}
// public static boolean isContainer(Graph graph, Node container)
// { return isContainer(graph, container, null) ; }
public static boolean isContainer(Graph graph, Node container, Node containerType)
{
// if ( container.isLiteral() )
// return false ;
if ( containerType == null )
return isContainer(graph, container, BAG) ||
isContainer(graph, container, ALT) ||
isContainer(graph, container, SEQ) ;
return graph.contains(container, RDFtype, containerType) ;
}
private static int getIndex(Triple triple)
{
String u = triple.getPredicate().getURI() ;
// Must be _nnn.
Matcher m = membershipPattern.matcher(u);
if ( ! m.find() )
return NOT_FOUND ;
String index = m.group(1) ;
return Integer.parseInt(index) ;
}
static ContainerOrder order = new ContainerOrder() ;
static private class ContainerOrder implements java.util.Comparator<Integer>
{
@Override
public int compare(Integer i1, Integer i2)
{
int index1 = i1.intValue() ;
int index2 = i2.intValue() ;
if ( index1 < index2 ) return Expr.CMP_LESS ;
if ( index1 > index2 ) return Expr.CMP_GREATER ;
return Expr.CMP_EQUAL ;
}
}
}