You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@clerezza.apache.org by ha...@apache.org on 2019/02/12 06:06:11 UTC
[clerezza] branch reunited updated: CLEREZZA-1037: Move utils from
rdf module to api.utils module
This is an automated email from the ASF dual-hosted git repository.
hasan pushed a commit to branch reunited
in repository https://gitbox.apache.org/repos/asf/clerezza.git
The following commit(s) were added to refs/heads/reunited by this push:
new 54c21fe CLEREZZA-1037: Move utils from rdf module to api.utils module
54c21fe is described below
commit 54c21fe27e68798c77407ab06f17c04ac3ed190f
Author: Hasan <ha...@apache.org>
AuthorDate: Tue Feb 12 07:05:28 2019 +0100
CLEREZZA-1037: Move utils from rdf module to api.utils module
---
api.utils/pom.xml | 75 +++
.../org/apache/clerezza/api/utils/GraphNode.java | 720 +++++++++++++++++++++
.../org/apache/clerezza/api/utils/GraphUtils.java | 158 +++++
.../org/apache/clerezza/api/utils/IRIUtil.java | 62 ++
.../org/apache/clerezza/api/utils/RdfList.java | 350 ++++++++++
.../apache/clerezza/api/utils/SeeAlsoExpander.java | 113 ++++
.../org/apache/clerezza/api/utils/Smusher.java | 61 ++
.../org/apache/clerezza/api/utils/UnionGraph.java | 279 ++++++++
.../clerezza/api/utils/UnionWatchableGraph.java | 57 ++
.../clerezza/api/utils/UriMutatingGraph.java | 217 +++++++
.../utils/graphnodeprovider/GraphNodeProvider.java | 51 ++
.../clerezza/api/utils/smushing/BaseSmusher.java | 130 ++++
.../clerezza/api/utils/smushing/IfpSmusher.java | 165 +++++
.../clerezza/api/utils/smushing/SameAsSmusher.java | 109 ++++
.../apache/clerezza/api/utils/GraphUtilsTest.java | 103 +++
.../apache/clerezza/api/utils/IfpSmushTest.java | 115 ++++
.../org/apache/clerezza/api/utils/RdfListTest.java | 182 ++++++
.../apache/clerezza/api/utils/SameAsSmushTest.java | 77 +++
.../apache/clerezza/api/utils/TestGraphNode.java | 266 ++++++++
.../apache/clerezza/api/utils/UnionGraphTest.java | 79 +++
.../api/utils/smushing/SameAsSmushTest.java | 91 +++
21 files changed, 3460 insertions(+)
diff --git a/api.utils/pom.xml b/api.utils/pom.xml
new file mode 100644
index 0000000..e67e3be
--- /dev/null
+++ b/api.utils/pom.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>clerezza</artifactId>
+ <groupId>org.apache.clerezza</groupId>
+ <version>8-SNAPSHOT</version>
+ <relativePath>../parent/pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>api.utils</artifactId>
+ <packaging>bundle</packaging>
+ <version>8-SNAPSHOT</version>
+ <name>Clerezza - API Utilities</name>
+ <description>Utility classes to work with Clerezza API</description>
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.clerezza</groupId>
+ <artifactId>api</artifactId>
+ <version>8-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.clerezza</groupId>
+ <artifactId>api.impl</artifactId>
+ <version>8-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.clerezza</groupId>
+ <artifactId>representation</artifactId>
+ <version>8-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.clerezza</groupId>
+ <artifactId>dataset</artifactId>
+ <version>8-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.clerezza</groupId>
+ <artifactId>ontologies</artifactId>
+ <version>8-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.clerezza</groupId>
+ <artifactId>test.utils</artifactId>
+ <version>8-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/api.utils/src/main/java/org/apache/clerezza/api/utils/GraphNode.java b/api.utils/src/main/java/org/apache/clerezza/api/utils/GraphNode.java
new file mode 100644
index 0000000..bedf30d
--- /dev/null
+++ b/api.utils/src/main/java/org/apache/clerezza/api/utils/GraphNode.java
@@ -0,0 +1,720 @@
+/*
+ * 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.clerezza.api.utils;
+
+import org.apache.clerezza.api.*;
+import org.apache.clerezza.api.impl.TripleImpl;
+import org.apache.clerezza.api.impl.graph.SimpleGraph;
+import org.apache.clerezza.api.impl.literal.LiteralFactory;
+
+import java.util.*;
+import java.util.concurrent.locks.Lock;
+
+/**
+ * This class represents a node in the context of a graph. It provides
+ * utility methods to explore and modify its neighbourhood. The method
+ * modifying the graph will throw an {@link UnsupportedOperationException}
+ * it the underlying Graph in immutable (i.e. is a {@link ImmutableGraph}.
+ *
+ * @since 0.2
+ * @author reto, mir
+ */
+public class GraphNode {
+
+ private final RDFTerm resource;
+ private final Graph graph;
+
+ /**
+ * Create a GraphNode representing resource within graph.
+ *
+ * @param resource the resource this GraphNode represents
+ * @param graph the Graph that describes the resource
+ */
+ public GraphNode(RDFTerm resource, Graph graph) {
+ if (resource == null) {
+ throw new IllegalArgumentException("resource may not be null");
+ }
+ if (graph == null) {
+ throw new IllegalArgumentException("graph may not be null");
+ }
+ this.resource = resource;
+ this.graph = graph;
+ }
+
+ /**
+ * Gets the graph the node represented by this instance is in
+ *
+ * @return the graph of this GraphNode
+ */
+ public Graph getGraph() {
+ return graph;
+ }
+
+ /**
+ * Gets the unwrapped node
+ *
+ * @return the node represented by this GraphNode
+ */
+ public RDFTerm getNode() {
+ return resource;
+ }
+
+ /**
+ * Deletes the context of a node
+ * @see getNodeContext()
+ */
+ public void deleteNodeContext() {
+ for (Triple triple : getNodeContext()) {
+ graph.remove(triple);
+ }
+ }
+
+ /**
+ * The context of a node are the triples containing a node
+ * as subject or object and recursively the context of the b-nodes in any
+ * of these statements.
+ *
+ * The triples in the ImmutableGraph returned by this method contain the same bnode
+ * instances as in the original graph.
+ *
+ * @return the context of the node represented by the instance
+ */
+ public ImmutableGraph getNodeContext() {
+ Lock l = readLock();
+ l.lock();
+ try {
+ final HashSet<RDFTerm> dontExpand = new HashSet<RDFTerm>();
+ dontExpand.add(resource);
+ if (resource instanceof IRI) {
+ return getContextOf((IRI) resource, dontExpand).getImmutableGraph();
+ }
+ return getContextOf(resource, dontExpand).getImmutableGraph();
+ } finally {
+ l.unlock();
+ }
+
+ }
+
+ private Graph getContextOf(IRI node, final Set<RDFTerm> dontExpand) {
+ final String uriPrefix = node.getUnicodeString()+'#';
+ return getContextOf(node, dontExpand, new Acceptor() {
+
+ @Override
+ public boolean expand(RDFTerm resource) {
+ if (resource instanceof BlankNode) {
+ return true;
+ }
+ if (resource instanceof IRI) {
+ return ((IRI)resource).getUnicodeString().startsWith(uriPrefix);
+ }
+ return false;
+ }
+ });
+ }
+
+ /**
+ * Returns the context of a <code>BlankNodeOrIRI</code>
+ *
+ * @param node
+ * @param dontExpand a list of bnodes at which to stop expansion, if node
+ * is a BlankNode it should be contained (potentially faster)
+ * @return the context of a node
+ */
+ private Graph getContextOf(RDFTerm node, final Set<RDFTerm> dontExpand) {
+ return getContextOf(node, dontExpand, new Acceptor() {
+
+ @Override
+ public boolean expand(RDFTerm resource) {
+ if (resource instanceof BlankNode) {
+ return true;
+ }
+ return false;
+ }
+ });
+ }
+
+ private interface Acceptor {
+ boolean expand(RDFTerm resource);
+ }
+ private Graph getContextOf(RDFTerm node, final Set<RDFTerm> dontExpand, Acceptor acceptor) {
+ Graph result = new SimpleGraph();
+ if (node instanceof BlankNodeOrIRI) {
+ Iterator<Triple> forwardProperties = graph.filter((BlankNodeOrIRI) node, null, null);
+ while (forwardProperties.hasNext()) {
+ Triple triple = forwardProperties.next();
+ result.add(triple);
+ RDFTerm object = triple.getObject();
+ if (acceptor.expand(object) && !dontExpand.contains(object)) {
+ dontExpand.add(object);
+ result.addAll(getContextOf(object, dontExpand, acceptor));
+ }
+ }
+ }
+ Iterator<Triple> backwardProperties = graph.filter(null, null, node);
+ while (backwardProperties.hasNext()) {
+ Triple triple = backwardProperties.next();
+ result.add(triple);
+ BlankNodeOrIRI subject = triple.getSubject();
+ if (acceptor.expand(subject) && !dontExpand.contains(subject)) {
+ dontExpand.add(subject);
+ result.addAll(getContextOf(subject, dontExpand, acceptor));
+ }
+ }
+ return result;
+ }
+
+ private <T> Iterator<T> getTypeSelectedObjects(IRI property, final Class<T> type) {
+ final Iterator<RDFTerm> objects = getObjects(property);
+ return new Iterator<T>() {
+
+ T next = prepareNext();
+
+ @Override
+ public boolean hasNext() {
+ return next != null;
+ }
+
+ @Override
+ public T next() {
+ T result = next;
+ next = prepareNext();
+ return result;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ private T prepareNext() {
+ while (objects.hasNext()) {
+ RDFTerm nextObject = objects.next();
+ if (type.isAssignableFrom(nextObject.getClass())) {
+ return (T) nextObject;
+ }
+ }
+ return null;
+ }
+ };
+ }
+
+ public Iterator<Literal> getLiterals(IRI property) {
+ final Iterator<RDFTerm> objects = getObjects(property);
+ return new Iterator<Literal>() {
+
+ Literal next = prepareNext();
+
+ @Override
+ public boolean hasNext() {
+ return next != null;
+ }
+
+ @Override
+ public Literal next() {
+ Literal result = next;
+ next = prepareNext();
+ return result;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ private Literal prepareNext() {
+ while (objects.hasNext()) {
+ RDFTerm nextObject = objects.next();
+ if (nextObject instanceof Literal) {
+ return (Literal) nextObject;
+ }
+ }
+ return null;
+ }
+ };
+ }
+
+ /**
+ * Count the number of triples in the underlying triple-collection
+ * with this node as subject and a specified property as predicate.
+ *
+ * @param property the property to be examined
+ * @return the number of triples in the underlying triple-collection
+ * which meet the specified condition
+ */
+ public int countObjects(IRI property) {
+ return countTriples(graph.filter((BlankNodeOrIRI) resource, property, null));
+ }
+
+ private int countTriples(final Iterator<Triple> triples) {
+ int count = 0;
+ while (triples.hasNext()) {
+ triples.next();
+ count++;
+ }
+ return count;
+ }
+
+ /**
+ * Get the objects of statements with this node as subject and a specified
+ * property as predicate.
+ *
+ * @param property the property
+ * @return
+ */
+ public Iterator<RDFTerm> getObjects(IRI property) {
+ if (resource instanceof BlankNodeOrIRI) {
+ final Iterator<Triple> triples = graph.filter((BlankNodeOrIRI) resource, property, null);
+ return new Iterator<RDFTerm>() {
+
+ @Override
+ public boolean hasNext() {
+ return triples.hasNext();
+ }
+
+ @Override
+ public RDFTerm next() {
+ final Triple triple = triples.next();
+ if (triple != null) {
+ return triple.getObject();
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+ };
+ } else {
+ return new Iterator<RDFTerm>() {
+
+ @Override
+ public boolean hasNext() {
+ return false;
+ }
+
+ @Override
+ public RDFTerm next() {
+ return null;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+ };
+ }
+ }
+
+ /**
+ * Checks wether this node has the given property with the given value.
+ * If the given value is null, then it is checked if this node has the
+ * specified property regardless of its value.
+ *
+ * @param property
+ * @param object
+ * @return true if the node represented by this object is the subject of a
+ * statement with the given prediate and object, false otherwise
+ */
+ public boolean hasProperty(IRI property, RDFTerm object) {
+ Lock l = readLock();
+ l.lock();
+ try {
+ Iterator<RDFTerm> objects = getObjects(property);
+ if (object == null) {
+ return objects.hasNext();
+ }
+ while (objects.hasNext()) {
+ if (objects.next().equals(object)) {
+ return true;
+ }
+ }
+ return false;
+ } finally {
+ l.unlock();
+ }
+ }
+
+ /**
+ * Count the number of triples in the underlying triple-collection
+ * with this node as object and a specified property as predicate.
+ *
+ * @param property the property to be examined
+ * @return the number of triples in the underlying triple-collection
+ * which meet the specified condition
+ */
+ public int countSubjects(IRI property) {
+ Lock l = readLock();
+ l.lock();
+ try {
+ return countTriples(graph.filter(null, property, resource));
+ } finally {
+ l.unlock();
+ }
+ }
+
+ /**
+ * Get the subjects of statements with this node as object and a specified
+ * property as predicate.
+ *
+ * @param property the property
+ * @return
+ */
+ public Iterator<BlankNodeOrIRI> getSubjects(IRI property) {
+ final Iterator<Triple> triples = graph.filter(null, property, resource);
+ return new Iterator<BlankNodeOrIRI>() {
+
+ @Override
+ public boolean hasNext() {
+ return triples.hasNext();
+ }
+
+ @Override
+ public BlankNodeOrIRI next() {
+ return triples.next().getSubject();
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+ };
+ }
+
+ public Iterator<IRI> getIRIObjects(IRI property) {
+ return getTypeSelectedObjects(property, IRI.class);
+
+ }
+
+ /**
+ * Get all available properties as an {@link Iterator}<{@link IRI}>.
+ * You can use <code>getObjects(IRI property)</code> to get the values of
+ * each property
+ *
+ * @return an iterator over properties of this node
+ */
+ public Iterator<IRI> getProperties() {
+ if (resource instanceof BlankNodeOrIRI) {
+ final Iterator<Triple> triples = graph.filter((BlankNodeOrIRI) resource, null, null);
+ return getUniquePredicates(triples);
+ } else {
+ return new Iterator<IRI>() {
+
+ @Override
+ public boolean hasNext() {
+ return false;
+ }
+
+ @Override
+ public IRI next() {
+ return null;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+ };
+ }
+ }
+
+ /**
+ * Get all inverse properties as an {@link Iterator}<{@link IRI}>.
+ * You can use <code>getSubject(IRI property)</code> to get the values of
+ * each inverse property
+ *
+ * @return an iterator over properties pointing to this node
+ */
+ public Iterator<IRI> getInverseProperties() {
+ final Iterator<Triple> triples = graph.filter(null, null, resource);
+ return getUniquePredicates(triples);
+ }
+
+ /**
+ *
+ * @param triples
+ * @returnan {@link Iterator}<{@link IRI}> containing the predicates from
+ * an {@link Iterator}<{@link Triple}>
+ */
+ private Iterator<IRI> getUniquePredicates(final Iterator<Triple> triples) {
+ final Set<IRI> resultSet = new HashSet<IRI>();
+ while (triples.hasNext()) {
+ resultSet.add(triples.next().getPredicate());
+ }
+ return resultSet.iterator();
+ }
+
+ /**
+ * Adds a property to the node with the specified predicate and object
+ *
+ * @param predicate
+ * @param object
+ */
+ public void addProperty(IRI predicate, RDFTerm object) {
+ if (resource instanceof BlankNodeOrIRI) {
+ graph.add(new TripleImpl((BlankNodeOrIRI) resource, predicate, object));
+ } else {
+ throw new RuntimeException("Literals cannot be the subject of a statement");
+ }
+ }
+
+
+ /**
+ * Coverts the value into a typed literals and sets it as object of the
+ * specified property
+ *
+ * @param property the predicate of the triple to be created
+ * @param value the value of the typed literal object
+ */
+ public void addPropertyValue(IRI property, Object value) {
+ addProperty(property,
+ LiteralFactory.getInstance().createTypedLiteral(value));
+ }
+
+ /**
+ * Adds a property to the node with the inverse of the specified predicate and object
+ * In other words <code>subject</code> will be related via the property <code>relation</code> to this node.
+ *
+ * @param predicate
+ * @param subject
+ */
+ public void addInverseProperty(IRI predicate, RDFTerm subject) {
+ if (subject instanceof BlankNodeOrIRI) {
+ graph.add(new TripleImpl((BlankNodeOrIRI) subject, predicate, resource));
+ } else {
+ throw new RuntimeException("Literals cannot be the subject of a statement");
+ }
+ }
+
+
+ /**
+ * creates and returns an <code>RdfList</code> for the node and
+ * Graph represented by this object.
+ *
+ * @return a List to easy access the rdf:List represented by this node
+ */
+ public List<RDFTerm> asList() {
+ if (resource instanceof BlankNodeOrIRI) {
+ return new RdfList((BlankNodeOrIRI) resource, graph);
+ } else {
+ throw new RuntimeException("Literals cannot be the subject of a List");
+ }
+ }
+
+ /**
+ * Deletes all statement with the current node as subject and the specified
+ * predicate
+ *
+ * @param predicate
+ */
+ public void deleteProperties(IRI predicate) {
+ if (resource instanceof BlankNodeOrIRI) {
+ Iterator<Triple> tripleIter = graph.filter((BlankNodeOrIRI) resource, predicate, null);
+ Collection<Triple> toDelete = new ArrayList<Triple>();
+ while (tripleIter.hasNext()) {
+ Triple triple = tripleIter.next();
+ toDelete.add(triple);
+ }
+ for (Triple triple : toDelete) {
+ graph.remove(triple);
+ }
+ }
+ }
+
+ /**
+ * Delete property to the node with the specified predicate and object
+ *
+ * @param predicate
+ * @param object
+ */
+ public void deleteProperty(IRI predicate, RDFTerm object) {
+ if (resource instanceof BlankNodeOrIRI) {
+ graph.remove(new TripleImpl((BlankNodeOrIRI) resource, predicate, object));
+ }
+ }
+
+ @Override
+ public String toString() {
+ return resource.toString();
+ }
+
+ /**
+ * Replaces the graph node resouce with the specified <code>BlankNodeOrIRI</code>.
+ * The resource is only replaced where it is either subject or object.
+ * @param replacement
+ * @return a GraphNode representing the replecement node
+ */
+ public GraphNode replaceWith(BlankNodeOrIRI replacement) {
+ return replaceWith(replacement, false);
+ }
+
+ /**
+ * Replaces the graph node resouce with the specified <code>BlankNodeOrIRI</code>.
+ * Over the boolean <code>checkPredicate</code> it can be specified if the
+ * resource should also be replaced where it is used as predicate.
+ * @param replacement
+ * @param checkPredicates
+ * @return a GraphNode representing the replecement node
+ */
+ public GraphNode replaceWith(BlankNodeOrIRI replacement, boolean checkPredicates) {
+ Graph newTriples = new SimpleGraph();
+ if (!(resource instanceof Literal)) {
+ Iterator<Triple> subjectTriples = graph.filter((BlankNodeOrIRI) resource, null,
+ null);
+ while (subjectTriples.hasNext()) {
+ Triple triple = subjectTriples.next();
+ Triple newTriple = new TripleImpl(replacement, triple.getPredicate(),
+ triple.getObject());
+ subjectTriples.remove();
+ newTriples.add(newTriple);
+ }
+ graph.addAll(newTriples);
+ newTriples.clear();
+ }
+
+ Iterator<Triple> objectTriples = graph.filter(null, null, resource);
+ while (objectTriples.hasNext()) {
+ Triple triple = objectTriples.next();
+ Triple newTriple = new TripleImpl(triple.getSubject(),
+ triple.getPredicate(), replacement);
+ objectTriples.remove();
+ newTriples.add(newTriple);
+ }
+ graph.addAll(newTriples);
+ newTriples.clear();
+
+ if (checkPredicates && replacement instanceof IRI
+ && resource instanceof IRI) {
+ Iterator<Triple> predicateTriples = graph.filter(null,
+ (IRI) resource, null);
+ while (predicateTriples.hasNext()) {
+ Triple triple = predicateTriples.next();
+ Triple newTriple = new TripleImpl(triple.getSubject(),
+ (IRI) replacement, triple.getObject());
+ predicateTriples.remove();
+ newTriples.add(newTriple);
+ }
+ graph.addAll(newTriples);
+ }
+ return new GraphNode(replacement, graph);
+ }
+
+ /**
+ * Returns a iterator containing all objects of the triples where this
+ * graph node is the subject and has the specified property. The objects
+ * are returned as <code>GraphNode</code>s.
+ *
+ * @param property
+ * @return
+ */
+ public Iterator<GraphNode> getObjectNodes(IRI property) {
+ final Iterator<RDFTerm> objects = this.getObjects(property);
+ return new Iterator<GraphNode>() {
+
+ @Override
+ public boolean hasNext() {
+ return objects.hasNext();
+ }
+
+ @Override
+ public GraphNode next() {
+ RDFTerm object = objects.next();
+ return new GraphNode(object, graph);
+
+ }
+
+ @Override
+ public void remove() {
+ objects.remove();
+ }
+ };
+ }
+
+ /**
+ * Returns a iterator containing all subjects of the triples where this
+ * graph node is the object and has the specified property. The subjects
+ * are returned as <code>GraphNode</code>s.
+ *
+ * @param property
+ * @return
+ */
+ public Iterator<GraphNode> getSubjectNodes(IRI property) {
+ final Iterator<BlankNodeOrIRI> subjects = this.getSubjects(property);
+ return new Iterator<GraphNode>() {
+
+ @Override
+ public boolean hasNext() {
+ return subjects.hasNext();
+ }
+
+ @Override
+ public GraphNode next() {
+ RDFTerm object = subjects.next();
+ return new GraphNode(object, graph);
+
+ }
+
+ @Override
+ public void remove() {
+ subjects.remove();
+ }
+ };
+ }
+
+ /**
+ *
+ * @param obj
+ * @return true if obj is an instance of the same class represening the same
+ * node in the same graph, subclasses may have different identity criteria.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null || !(obj.getClass().equals(getClass()))) {
+ return false;
+ }
+ GraphNode other = (GraphNode) obj;
+ return getNode().equals(other.getNode())
+ && getGraph().equals(other.getGraph());
+ }
+
+ @Override
+ public int hashCode() {
+ return 13 * getNode().hashCode() + getGraph().hashCode();
+ }
+
+ /**
+ * @return a ReadLock if the underlying ImmutableGraph is a LockableGraph it returns its lock, otherwise null
+ */
+ public Lock readLock() {
+
+ return getGraph().getLock().readLock();
+
+ }
+
+ /**
+ *
+ * @return
+ */
+ public Lock writeLock() {
+
+ return (getGraph()).getLock().writeLock();
+
+ }
+}
diff --git a/api.utils/src/main/java/org/apache/clerezza/api/utils/GraphUtils.java b/api.utils/src/main/java/org/apache/clerezza/api/utils/GraphUtils.java
new file mode 100644
index 0000000..51e25b1
--- /dev/null
+++ b/api.utils/src/main/java/org/apache/clerezza/api/utils/GraphUtils.java
@@ -0,0 +1,158 @@
+/*
+ * 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.clerezza.api.utils;
+
+import org.apache.clerezza.api.*;
+import org.apache.clerezza.api.impl.graph.SimpleGraph;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * Utility methods to manipulate <code>Graph</code>s
+ *
+ * @author reto
+ */
+public class GraphUtils {
+
+ /**
+ * Removes a subGraph from an Graph. The subGraph must match a subgraph of
+ * Graph so that for every node in <code>subGraph</code>
+ * each triple it appears in is also present in <code>mGraph</code>. Two
+ * bnodes are considered equals if their contexts (as returned by
+ * <code>GraphNode.getNodeContext</code> are equals.
+ *
+ * @param mGraph
+ * @param subGraph
+ * @throws org.apache.clerezza.rdf.utils.GraphUtils.NoSuchSubGraphException
+ */
+ public static void removeSubGraph(Graph mGraph, Graph subGraph)
+ throws NoSuchSubGraphException {
+ //point to triples of mGraph that are to be removed (if something is removed)
+ final Set<Triple> removingTriples = new HashSet<Triple>();
+ //we first check only the grounded triples and put the non-grounded in here:
+ final Graph unGroundedTriples = new SimpleGraph();
+ for (Triple triple : subGraph) {
+ if (isGrounded(triple)) {
+ if (!mGraph.contains(triple)) {
+ throw new NoSuchSubGraphException();
+ }
+ removingTriples.add(triple);
+ } else {
+ unGroundedTriples.add(triple);
+ }
+ }
+
+ //we first remove the context of bnodes we find in object position
+ OBJ_BNODE_LOOP: while (true) {
+ final Triple triple = getTripleWithBlankNodeObject(unGroundedTriples);
+ if (triple == null) {
+ break;
+ }
+ final GraphNode objectGN = new GraphNode(triple.getObject(), unGroundedTriples);
+ BlankNodeOrIRI subject = triple.getSubject();
+ ImmutableGraph context = objectGN.getNodeContext();
+ Iterator<Triple> potentialIter = mGraph.filter(subject, triple.getPredicate(), null);
+ while (potentialIter.hasNext()) {
+ try {
+ final Triple potentialTriple = potentialIter.next();
+ BlankNode potentialMatch = (BlankNode)potentialTriple.getObject();
+ final ImmutableGraph potentialContext = new GraphNode(potentialMatch, mGraph).getNodeContext();
+ if (potentialContext.equals(context)) {
+ removingTriples.addAll(potentialContext);
+ unGroundedTriples.removeAll(context);
+ continue OBJ_BNODE_LOOP;
+ }
+ } catch (ClassCastException e) {
+ continue;
+ }
+ }
+ throw new NoSuchSubGraphException();
+ }
+ SUBJ_BNODE_LOOP: while (true) {
+ final Triple triple = getTripleWithBlankNodeSubject(unGroundedTriples);
+ if (triple == null) {
+ break;
+ }
+ final GraphNode subjectGN = new GraphNode(triple.getSubject(), unGroundedTriples);
+ RDFTerm object = triple.getObject();
+ if (object instanceof BlankNode) {
+ object = null;
+ }
+ ImmutableGraph context = subjectGN.getNodeContext();
+ Iterator<Triple> potentialIter = mGraph.filter(null, triple.getPredicate(), object);
+ while (potentialIter.hasNext()) {
+ try {
+ final Triple potentialTriple = potentialIter.next();
+ BlankNode potentialMatch = (BlankNode)potentialTriple.getSubject();
+ final ImmutableGraph potentialContext = new GraphNode(potentialMatch, mGraph).getNodeContext();
+ if (potentialContext.equals(context)) {
+ removingTriples.addAll(potentialContext);
+ unGroundedTriples.removeAll(context);
+ continue SUBJ_BNODE_LOOP;
+ }
+ } catch (ClassCastException e) {
+ continue;
+ }
+ }
+ throw new NoSuchSubGraphException();
+ }
+ mGraph.removeAll(removingTriples);
+ }
+
+ private static boolean isGrounded(Triple triple) {
+ if (triple.getSubject() instanceof BlankNode) {
+ return false;
+ }
+ if (triple.getObject() instanceof BlankNode) {
+ return false;
+ }
+ return true;
+ }
+
+ /** retrun triples with a bnode only at object position
+ *
+ * @param triples
+ * @return
+ */
+ private static Triple getTripleWithBlankNodeObject(Graph triples) {
+ for (Triple triple : triples) {
+ if (triple.getSubject() instanceof BlankNode) {
+ continue;
+ }
+ if (triple.getObject() instanceof BlankNode) {
+ return triple;
+ }
+ }
+ return null;
+ }
+ private static Triple getTripleWithBlankNodeSubject(Graph triples) {
+ for (Triple triple : triples) {
+ if (triple.getSubject() instanceof BlankNode) {
+ return triple;
+ }
+ }
+ return null;
+ }
+
+ public static class NoSuchSubGraphException extends Exception {
+ }
+
+}
diff --git a/api.utils/src/main/java/org/apache/clerezza/api/utils/IRIUtil.java b/api.utils/src/main/java/org/apache/clerezza/api/utils/IRIUtil.java
new file mode 100644
index 0000000..e233052
--- /dev/null
+++ b/api.utils/src/main/java/org/apache/clerezza/api/utils/IRIUtil.java
@@ -0,0 +1,62 @@
+/*
+ * 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.clerezza.api.utils;
+
+/**
+ * A utility class for IRI and String manipulations.
+ *
+ * @author tio
+ */
+public class IRIUtil {
+
+ /**
+ * Strips #x00 - #x1F and #x7F-#x9F from a Unicode string
+ * @see <a href="http://www.w3.org/TR/rdf-concepts/#dfn-URI-reference">
+ * http://www.w3.org/TR/rdf-concepts/#dfn-URI-reference</a> and
+ * replaces all US-ASCII space character with a "+".
+ *
+ * @param inputChars
+ * @return the stripped string
+ *
+ */
+ public static String stripNonIRIChars(CharSequence inputChars) {
+
+ if (inputChars == null) {
+ return "";
+ }
+
+ StringBuffer buffer = new StringBuffer();
+
+ for (int i = 0; i < inputChars.length(); i++) {
+ char c = inputChars.charAt(i);
+
+ if (!isIllegal(c)) {
+ buffer.append(c);
+ }
+ }
+ return buffer.toString().replaceAll("\\s+", "+");
+ }
+
+ private static boolean isIllegal(char ch) {
+ if ((ch >= 0x7F) && (ch <= 0x9F)) {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/api.utils/src/main/java/org/apache/clerezza/api/utils/RdfList.java b/api.utils/src/main/java/org/apache/clerezza/api/utils/RdfList.java
new file mode 100644
index 0000000..e3bdc34
--- /dev/null
+++ b/api.utils/src/main/java/org/apache/clerezza/api/utils/RdfList.java
@@ -0,0 +1,350 @@
+/*
+ * 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.clerezza.api.utils;
+
+import org.apache.clerezza.api.*;
+import org.apache.clerezza.api.impl.TripleImpl;
+import org.apache.clerezza.ontologies.OWL;
+import org.apache.clerezza.ontologies.RDF;
+import org.apache.clerezza.representation.Serializer;
+import org.apache.clerezza.representation.SupportedFormat;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.FileOutputStream;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.*;
+
+/**
+ * An implementation of an <code>java.util.List</code> backed by an RDF
+ * collection (rdf:List). The list allows modification that are reflected
+ * to the underlying <code>Graph</code>. It reads the data from the
+ * <code>Graph</code> when it is first needed, so changes to the
+ * Graph affecting the rdf:List may or may not have an effect on the
+ * values returned by instances of this class. For that reason only one
+ * instance of this class should be used for accessing an rdf:List of sublists
+ * thereof when the lists are being modified, having multiple lists exclusively
+ * for read operations (such as for immutable <code>Graph</code>s) is
+ * not problematic.
+ *
+ * @author rbn, mir
+ */
+public class RdfList extends AbstractList<RDFTerm> {
+
+ private static final Logger logger = LoggerFactory.getLogger(RdfList.class);
+
+ private final static IRI RDF_NIL =
+ new IRI("http://www.w3.org/1999/02/22-rdf-syntax-ns#nil");
+ /**
+ * a list of the linked rdf:List elements in order
+ */
+ private List<BlankNodeOrIRI> listList = new ArrayList<BlankNodeOrIRI>();
+ private List<RDFTerm> valueList = new ArrayList<RDFTerm>();
+ private BlankNodeOrIRI firstList;
+ private Graph tc;
+ private boolean totallyExpanded = false;
+
+ /**
+ * Get a list for the specified resource.
+ *
+ * If the list is modified using the created instance
+ * <code>listRDFTerm</code> will always be the first list.
+ *
+ * @param listRDFTerm
+ * @param tc
+ */
+ public RdfList(BlankNodeOrIRI listRDFTerm, Graph tc) {
+ firstList = listRDFTerm;
+ this.tc = tc;
+
+ }
+
+ /**
+ * Get a list for the specified resource node.
+ *
+ * @param listNode
+ */
+ public RdfList(GraphNode listNode) {
+ this((BlankNodeOrIRI)listNode.getNode(), listNode.getGraph());
+ }
+
+ /**
+ * Creates an empty RdfList by writing a triple
+ * "{@code listRDFTerm} owl:sameAs rdf.nil ." to {@code tc}.
+ *
+ * @param listRDFTerm
+ * @param tc
+ * @return an empty rdf:List.
+ * @throws IllegalArgumentException
+ * if the provided {@code listRDFTerm} is a non-empty rdf:List.
+ */
+ public static RdfList createEmptyList(BlankNodeOrIRI listRDFTerm, Graph tc)
+ throws IllegalArgumentException {
+
+ if (!tc.filter(listRDFTerm, RDF.first, null).hasNext()) {
+ RdfList list = new RdfList(listRDFTerm, tc);
+ list.tc.add(new TripleImpl(listRDFTerm, OWL.sameAs, RDF_NIL));
+ return list;
+ } else {
+ throw new IllegalArgumentException(listRDFTerm + "is a non-empty rdf:List.");
+ }
+ }
+
+ private void expandTill(int pos) {
+ if (totallyExpanded) {
+ return;
+ }
+ BlankNodeOrIRI currentList;
+ if (listList.size() > 0) {
+ currentList = listList.get(listList.size()-1);
+ } else {
+ currentList = firstList;
+ if (!tc.filter(currentList, RDF.first, null).hasNext()) {
+ return;
+ }
+ listList.add(currentList);
+ valueList.add(getFirstEntry(currentList));
+ }
+ if (listList.size() >= pos) {
+ return;
+ }
+ while (true) {
+ currentList = getRest(currentList);
+ if (currentList.equals(RDF_NIL)) {
+ totallyExpanded = true;
+ break;
+ }
+ if (listList.size() == pos) {
+ break;
+ }
+ valueList.add(getFirstEntry(currentList));
+ listList.add(currentList);
+ }
+ }
+
+
+
+ @Override
+ public RDFTerm get(int index) {
+ expandTill(index + 1);
+ return valueList.get(index);
+ }
+
+ @Override
+ public int size() {
+ expandTill(Integer.MAX_VALUE);
+ return valueList.size();
+ }
+
+ @Override
+ public void add(int index, RDFTerm element) {
+ expandTill(index);
+ if (index == 0) {
+ //special casing to make sure the first list remains the same resource
+ if (listList.size() == 0) {
+ tc.remove(new TripleImpl(firstList, OWL.sameAs, RDF_NIL));
+ tc.add(new TripleImpl(firstList, RDF.rest, RDF_NIL));
+ tc.add(new TripleImpl(firstList, RDF.first, element));
+ listList.add(firstList);
+ } else {
+ tc.remove(new TripleImpl(listList.get(0), RDF.first, valueList.get(0)));
+ tc.add(new TripleImpl(listList.get(0), RDF.first, element));
+ addInRdfList(1, valueList.get(0));
+ }
+ } else {
+ addInRdfList(index, element);
+ }
+ valueList.add(index, element);
+ }
+
+ /**
+ *
+ * @param index is > 0
+ * @param element
+ */
+ private void addInRdfList(int index, RDFTerm element) {
+ expandTill(index+1);
+ BlankNodeOrIRI newList = new BlankNode() {
+ };
+ tc.add(new TripleImpl(newList, RDF.first, element));
+ if (index < listList.size()) {
+ tc.add(new TripleImpl(newList, RDF.rest, listList.get(index)));
+ tc.remove(new TripleImpl(listList.get(index - 1), RDF.rest, listList.get(index)));
+ } else {
+ tc.remove(new TripleImpl(listList.get(index - 1), RDF.rest, RDF_NIL));
+ tc.add(new TripleImpl(newList, RDF.rest, RDF_NIL));
+
+ }
+ tc.add(new TripleImpl(listList.get(index - 1), RDF.rest, newList));
+ listList.add(index, newList);
+ }
+
+ @Override
+ public RDFTerm remove(int index) {
+ //keeping the first list resource
+ tc.remove(new TripleImpl(listList.get(index), RDF.first, valueList.get(index)));
+ if (index == (listList.size() - 1)) {
+ tc.remove(new TripleImpl(listList.get(index), RDF.rest, RDF_NIL));
+ if (index > 0) {
+ tc.remove(new TripleImpl(listList.get(index - 1), RDF.rest, listList.get(index)));
+ tc.add(new TripleImpl(listList.get(index - 1), RDF.rest, RDF_NIL));
+ } else {
+ tc.add(new TripleImpl(listList.get(index), OWL.sameAs, RDF_NIL));
+ }
+ listList.remove(index);
+ } else {
+ tc.add(new TripleImpl(listList.get(index), RDF.first, valueList.get(index+1)));
+ tc.remove(new TripleImpl(listList.get(index), RDF.rest, listList.get(index + 1)));
+ tc.remove(new TripleImpl(listList.get(index + 1), RDF.first, valueList.get(index + 1)));
+ if (index == (listList.size() - 2)) {
+ tc.remove(new TripleImpl(listList.get(index + 1), RDF.rest, RDF_NIL));
+ tc.add(new TripleImpl(listList.get(index), RDF.rest, RDF_NIL));
+ } else {
+ tc.remove(new TripleImpl(listList.get(index + 1), RDF.rest, listList.get(index + 2)));
+ tc.add(new TripleImpl(listList.get(index), RDF.rest, listList.get(index + 2)));
+ }
+ listList.remove(index+1);
+ }
+ return valueList.remove(index);
+ }
+
+ private BlankNodeOrIRI getRest(BlankNodeOrIRI list) {
+ return (BlankNodeOrIRI) tc.filter(list, RDF.rest, null).next().getObject();
+ }
+
+ private RDFTerm getFirstEntry(final BlankNodeOrIRI listRDFTerm) {
+ try {
+ return tc.filter(listRDFTerm, RDF.first, null).next().getObject();
+ } catch (final NullPointerException e) {
+ RuntimeException runtimeEx = AccessController.doPrivileged(new PrivilegedAction<RuntimeException>() {
+ @Override
+ public RuntimeException run(){
+ try {
+ final FileOutputStream fileOutputStream = new FileOutputStream("/tmp/broken-list.nt");
+ final GraphNode graphNode = new GraphNode(listRDFTerm, tc);
+ Serializer.getInstance().serialize(fileOutputStream, graphNode.getNodeContext(), SupportedFormat.N_TRIPLE);
+ fileOutputStream.flush();
+ logger.warn("GraphNode: " + graphNode);
+ final Iterator<IRI> properties = graphNode.getProperties();
+ while (properties.hasNext()) {
+ logger.warn("available: " + properties.next());
+ }
+ return new RuntimeException("broken list " + listRDFTerm, e);
+ } catch (Exception ex) {
+ return new RuntimeException(ex);
+ }
+
+ }
+ });
+ throw runtimeEx;
+ }
+ }
+
+ public BlankNodeOrIRI getListRDFTerm() {
+ return firstList;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final RdfList other = (RdfList) obj;
+
+ if (!other.firstList.equals(this.firstList)) {
+ return false;
+ }
+
+ if (!other.tc.equals(this.tc)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return 17 * this.firstList.hashCode() + this.tc.hashCode();
+ }
+
+ /**
+ * Returns the rdf lists of which the specified <code>GraphNode</code> is
+ * an element of. Sublists of other lists are not returned.
+ *
+ * @param element
+ * @return
+ */
+ public static Set<RdfList> findContainingLists(GraphNode element) {
+ Set<GraphNode> listNodes = findContainingListNodes(element);
+ if (listNodes.isEmpty()) {
+ return null;
+ }
+
+ Set<RdfList> rdfLists = new HashSet<RdfList>();
+ for (Iterator<GraphNode> it = listNodes.iterator(); it.hasNext();) {
+ GraphNode listNode = it.next();
+ rdfLists.add(new RdfList(listNode));
+ }
+ return rdfLists;
+ }
+
+ /**
+ * Returns a set of <code>GraphNode</code>S which are the first list nodes (meaning
+ * they are not the beginning of a sublist) of the list containing the specified
+ * <code>GraphNode</code> as an element.
+ *
+ * @param element
+ * @return
+ */
+ public static Set<GraphNode> findContainingListNodes(GraphNode element) {
+ Iterator<GraphNode> partOfaListNodesIter = element.getSubjectNodes(RDF.first);
+ if (!partOfaListNodesIter.hasNext()) {
+ return null;
+ }
+ Set<GraphNode> listNodes = new HashSet<GraphNode>();
+
+ while (partOfaListNodesIter.hasNext()) {
+ listNodes.addAll(findAllListNodes(partOfaListNodesIter.next()));
+ }
+ return listNodes;
+ }
+
+ private static Set<GraphNode> findAllListNodes(GraphNode listPart) {
+ Iterator<GraphNode> invRestNodesIter;
+ Set<GraphNode> listNodes = new HashSet<GraphNode>();
+ do {
+ invRestNodesIter = listPart.getSubjectNodes(RDF.rest);
+ if (invRestNodesIter.hasNext()) {
+ listPart = invRestNodesIter.next();
+ while (invRestNodesIter.hasNext()) {
+ GraphNode graphNode = invRestNodesIter.next();
+ listNodes.addAll(findAllListNodes(graphNode));
+ }
+ } else {
+ listNodes.add(listPart);
+ break;
+ }
+ } while (true);
+ return listNodes;
+ }
+}
diff --git a/api.utils/src/main/java/org/apache/clerezza/api/utils/SeeAlsoExpander.java b/api.utils/src/main/java/org/apache/clerezza/api/utils/SeeAlsoExpander.java
new file mode 100644
index 0000000..2cf73cd
--- /dev/null
+++ b/api.utils/src/main/java/org/apache/clerezza/api/utils/SeeAlsoExpander.java
@@ -0,0 +1,113 @@
+/*
+ * 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.clerezza.api.utils;
+
+import org.apache.clerezza.api.Graph;
+import org.apache.clerezza.api.IRI;
+import org.apache.clerezza.api.RDFTerm;
+import org.apache.clerezza.dataset.NoSuchEntityException;
+import org.apache.clerezza.dataset.TcManager;
+import org.apache.clerezza.ontologies.RDFS;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.concurrent.locks.Lock;
+
+/**
+ * Expands a GraphNode expanding SeeAlso-References of the node.
+ *
+ * @author reto
+ */
+public class SeeAlsoExpander {
+ /**
+ * using TcManger instead of TcProvider as this ensures LockableGraphs
+ */
+ private final TcManager tcManager;
+ public SeeAlsoExpander(TcManager tcManager) {
+ this.tcManager = tcManager;
+
+ }
+
+ /**
+ * expands a node dereferencing its rdfs:seeAlso references using the
+ * tcManager associated to this instance. If the added TripleCollections
+ * also associate rdfs:seeAlso properties to node this are expanded till
+ * the maximum recursion depth specified.
+ *
+ * @param node the node to be expanded
+ * @param recursion the maximum recursion depth
+ * @return a new GraphNode over the union of the original and all expansion graphs
+ */
+ public GraphNode expand(GraphNode node, int recursion) {
+ Set<IRI> alreadyVisited = new HashSet();
+ Set<Graph> resultTripleCollections = new HashSet<Graph>();
+ resultTripleCollections.add(node.getGraph());
+ for (IRI uriRef : expand(node, alreadyVisited, recursion)) {
+ try {
+ resultTripleCollections.add(tcManager.getGraph(uriRef));
+ } catch (NoSuchEntityException e) {
+ //ignore
+ }
+ }
+ return new GraphNode(node.getNode(),
+ new UnionGraph(resultTripleCollections.toArray(
+ new Graph[resultTripleCollections.size()])));
+
+ }
+
+ private Set<IRI> getSeeAlsoObjectUris(GraphNode node) {
+ Set<IRI> result = new HashSet<IRI>();
+ Lock l = node.readLock();
+ l.lock();
+ try {
+ Iterator<RDFTerm> objects = node.getObjects(RDFS.seeAlso);
+ while (objects.hasNext()) {
+ RDFTerm next = objects.next();
+ if (next instanceof IRI) {
+ result.add((IRI)next);
+ }
+ }
+ } finally {
+ l.unlock();
+ }
+ return result;
+ }
+
+ private Set<IRI> expand(GraphNode node, Set<IRI> alreadyVisited, int recursion) {
+ Set<IRI> rdfSeeAlsoTargets = getSeeAlsoObjectUris(node);
+ Set<IRI> result = new HashSet<IRI>();
+ result.addAll(rdfSeeAlsoTargets);
+ recursion++;
+ if (recursion > 0) {
+ rdfSeeAlsoTargets.removeAll(alreadyVisited);
+ alreadyVisited.addAll(rdfSeeAlsoTargets);
+ for (IRI target : rdfSeeAlsoTargets) {
+ try {
+ result.addAll(expand(new GraphNode(node.getNode(),
+ tcManager.getGraph(target)), alreadyVisited, recursion));
+ } catch (NoSuchEntityException e) {
+ //ignore
+ }
+ }
+ }
+ return result;
+ }
+
+}
diff --git a/api.utils/src/main/java/org/apache/clerezza/api/utils/Smusher.java b/api.utils/src/main/java/org/apache/clerezza/api/utils/Smusher.java
new file mode 100644
index 0000000..1dbb8f2
--- /dev/null
+++ b/api.utils/src/main/java/org/apache/clerezza/api/utils/Smusher.java
@@ -0,0 +1,61 @@
+/*
+ * 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.clerezza.api.utils;
+
+import org.apache.clerezza.api.Graph;
+import org.apache.clerezza.api.utils.smushing.IfpSmusher;
+import org.apache.clerezza.api.utils.smushing.SameAsSmusher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A utility to smush equivalent resources. For greater flexibility use the
+ * classes in the smushing package.
+ *
+ * @author reto
+ */
+public class Smusher {
+
+ static final Logger log = LoggerFactory.getLogger(Smusher.class);
+
+ /**
+ * smush mGaph given the ontological facts. Currently it does only one step
+ * ifp smushin, i.e. only ifps are taken in account and only nodes that have
+ * the same node as ifp object in the orignal graph are equates. (calling
+ * the method a second time might lead to additional smushings.)
+ *
+ * @param mGraph
+ * @param tBox
+ */
+ public static void smush(Graph mGraph, Graph tBox) {
+ new IfpSmusher().smush(mGraph, tBox);
+ }
+
+ /**
+ * Smushes the specified graph adding owl:sameAs statements pointing to the new canonical IRI
+ *
+ * @param mGraph
+ * @param owlSameStatements
+ */
+ public static void sameAsSmush(Graph mGraph, Graph owlSameStatements) {
+ new SameAsSmusher().smush(mGraph, owlSameStatements, true);
+ }
+
+
+}
diff --git a/api.utils/src/main/java/org/apache/clerezza/api/utils/UnionGraph.java b/api.utils/src/main/java/org/apache/clerezza/api/utils/UnionGraph.java
new file mode 100644
index 0000000..3f939ce
--- /dev/null
+++ b/api.utils/src/main/java/org/apache/clerezza/api/utils/UnionGraph.java
@@ -0,0 +1,279 @@
+/*
+ * 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.clerezza.api.utils;
+
+import org.apache.clerezza.api.*;
+import org.apache.clerezza.api.impl.graph.AbstractGraph;
+
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+
+/**
+ *
+ * This class represents the union of multiple triple collections. A UnionGraph
+ * appears like a merge of the different graphs (see.
+ * http://www.w3.org/TR/rdf-mt/#graphdefs).
+ *
+ * @author hasan
+ */
+public class UnionGraph extends AbstractGraph {
+
+ protected Graph[] baseTripleCollections;
+ private Lock readLock;
+ private Lock writeLock;
+
+ /**
+ * Constructs a UnionGraph over the specified baseTripleCollections. Write
+ * and delete operations are forwarded to the first baseTripleCollections.
+ *
+ * @param baseTripleCollections the baseTripleCollections
+ */
+ public UnionGraph(Graph... baseTripleCollections) {
+ this.baseTripleCollections = baseTripleCollections;
+ readLock = getPartialReadLock(0);
+ writeLock = createWriteLock();
+ }
+
+ @Override
+ public int performSize() {
+ int size = 0;
+ for (Graph graph : baseTripleCollections) {
+ size += graph.size();
+ }
+ return size;
+ }
+
+ @Override
+ public Iterator<Triple> performFilter(final BlankNodeOrIRI subject,
+ final IRI predicate, final RDFTerm object) {
+ if (baseTripleCollections.length == 0) {
+ return new HashSet<Triple>(0).iterator();
+ }
+ return new Iterator<Triple>() {
+
+ int currentBaseTC = 0;
+ Iterator<Triple> currentBaseIter = baseTripleCollections[0].filter(
+ subject, predicate, object);
+ private Triple lastReturned;
+
+ @Override
+ public boolean hasNext() {
+ if (currentBaseIter.hasNext()) {
+ return true;
+ }
+ if (currentBaseTC == baseTripleCollections.length - 1) {
+ return false;
+ }
+ currentBaseTC++;
+ currentBaseIter = baseTripleCollections[currentBaseTC].filter(
+ subject, predicate, object);
+ return hasNext();
+ }
+
+ @Override
+ public Triple next() {
+ lastReturned = hasNext() ? currentBaseIter.next() : null;
+ return lastReturned;
+ }
+
+ @Override
+ public void remove() {
+ if (lastReturned == null) {
+ throw new IllegalStateException();
+ }
+ if (currentBaseTC == 0) {
+ currentBaseIter.remove();
+ }
+ lastReturned = null;
+ }
+ };
+ }
+
+ @Override
+ public boolean add(Triple e) {
+ if (baseTripleCollections.length == 0) {
+ throw new RuntimeException("no base graph for adding triples");
+ }
+ return baseTripleCollections[0].add(e);
+ }
+
+ @Override
+ public boolean remove(Object e) {
+ if (baseTripleCollections.length == 0) {
+ throw new RuntimeException("no base graph for removing triples");
+ }
+ return baseTripleCollections[0].remove(e);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj.getClass().equals(getClass()))) {
+ return false;
+ }
+ UnionGraph other = (UnionGraph) obj;
+ Set<Graph> otherGraphs
+ = new HashSet(Arrays.asList(other.baseTripleCollections));
+ Set<Graph> thisGraphs
+ = new HashSet(Arrays.asList(baseTripleCollections));
+ return thisGraphs.equals(otherGraphs)
+ && baseTripleCollections[0].equals(other.baseTripleCollections[0]);
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 0;
+ for (Graph graph : baseTripleCollections) {
+ hash += graph.hashCode();
+ }
+ hash *= baseTripleCollections[0].hashCode();
+ return hash;
+ }
+
+ @Override
+ public ReadWriteLock getLock() {
+ return readWriteLock;
+ }
+ private ReadWriteLock readWriteLock = new ReadWriteLock() {
+
+ @Override
+ public Lock readLock() {
+ return readLock;
+ }
+
+ @Override
+ public Lock writeLock() {
+ return writeLock;
+ }
+ };
+
+ private Lock getPartialReadLock(int startPos) {
+ ArrayList<Lock> resultList = new ArrayList<Lock>();
+ for (int i = startPos; i < baseTripleCollections.length; i++) {
+ Graph graph = baseTripleCollections[i];
+
+ final Lock lock = graph.getLock().readLock();
+ resultList.add(lock);
+ }
+ return new UnionLock(resultList.toArray(new Lock[resultList.size()]));
+ }
+
+ private Lock createWriteLock() {
+ Lock partialReadLock = getPartialReadLock(1);
+
+ Lock baseWriteLock
+ = (baseTripleCollections[0]).getLock().writeLock();
+ return new UnionLock(baseWriteLock, partialReadLock);
+
+ }
+
+ ;
+
+
+ private static class UnionLock implements Lock {
+
+ Lock[] locks;
+
+ public UnionLock(Lock... locks) {
+ this.locks = locks;
+ }
+
+ @Override
+ public void lock() {
+ boolean isLocked = false;
+ while (!isLocked) {
+ try {
+ isLocked = tryLock(10000, TimeUnit.NANOSECONDS);
+ } catch (InterruptedException ex) {
+
+ }
+ }
+ }
+
+ @Override
+ public void lockInterruptibly() throws InterruptedException {
+ Set<Lock> aquiredLocks = new HashSet<Lock>();
+ try {
+ for (Lock lock : locks) {
+ lock.lockInterruptibly();
+ aquiredLocks.add(lock);
+ }
+ } catch (InterruptedException e) {
+ for (Lock lock : aquiredLocks) {
+ lock.unlock();
+ }
+ throw e;
+ }
+ }
+
+ @Override
+ public boolean tryLock() {
+ Set<Lock> aquiredLocks = new HashSet<Lock>();
+ for (Lock lock : locks) {
+ if (!lock.tryLock()) {
+ for (Lock aquiredLock : aquiredLocks) {
+ aquiredLock.unlock();
+ }
+ return false;
+ }
+ aquiredLocks.add(lock);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
+ Set<Lock> aquiredLocks = new HashSet<Lock>();
+ long timeInNanos = unit.convert(time, TimeUnit.NANOSECONDS);
+ long startTime = System.nanoTime();
+ try {
+ for (Lock lock : locks) {
+ if (!lock.tryLock((timeInNanos + startTime) - System.nanoTime(),
+ TimeUnit.NANOSECONDS)) {
+ for (Lock aquiredLock : aquiredLocks) {
+ aquiredLock.unlock();
+ }
+ return false;
+ }
+ aquiredLocks.add(lock);
+ }
+ } catch (InterruptedException e) {
+ for (Lock lock : aquiredLocks) {
+ lock.unlock();
+ }
+ throw e;
+ }
+ return true;
+ }
+
+ @Override
+ public void unlock() {
+ for (Lock lock : locks) {
+ lock.unlock();
+ }
+ }
+
+ @Override
+ public Condition newCondition() {
+ throw new UnsupportedOperationException("Conditions not supported.");
+ }
+ }
+}
diff --git a/api.utils/src/main/java/org/apache/clerezza/api/utils/UnionWatchableGraph.java b/api.utils/src/main/java/org/apache/clerezza/api/utils/UnionWatchableGraph.java
new file mode 100644
index 0000000..81b2dbf
--- /dev/null
+++ b/api.utils/src/main/java/org/apache/clerezza/api/utils/UnionWatchableGraph.java
@@ -0,0 +1,57 @@
+/*
+ * 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.clerezza.api.utils;
+
+import org.apache.clerezza.api.Graph;
+import org.apache.clerezza.api.WatchableGraph;
+import org.apache.clerezza.api.event.FilterTriple;
+import org.apache.clerezza.api.event.GraphListener;
+
+/**
+ *
+ * @author developer
+ */
+public class UnionWatchableGraph extends UnionGraph implements WatchableGraph {
+
+ public UnionWatchableGraph(WatchableGraph... baseTripleCollections) {
+ super(baseTripleCollections);
+ }
+ @Override
+ public void addGraphListener(GraphListener listener, FilterTriple filter) {
+ for (Graph graph : baseTripleCollections) {
+ ((WatchableGraph)graph).addGraphListener(listener, filter);
+ }
+ }
+
+ @Override
+ public void addGraphListener(GraphListener listener, FilterTriple filter, long delay) {
+ for (Graph graph : baseTripleCollections) {
+ ((WatchableGraph)graph).addGraphListener(listener, filter, delay);
+ }
+ }
+
+ @Override
+ public void removeGraphListener(GraphListener listener) {
+ for (Graph graph : baseTripleCollections) {
+ ((WatchableGraph)graph).removeGraphListener(listener);
+ }
+ }
+
+
+}
diff --git a/api.utils/src/main/java/org/apache/clerezza/api/utils/UriMutatingGraph.java b/api.utils/src/main/java/org/apache/clerezza/api/utils/UriMutatingGraph.java
new file mode 100644
index 0000000..0c6871c
--- /dev/null
+++ b/api.utils/src/main/java/org/apache/clerezza/api/utils/UriMutatingGraph.java
@@ -0,0 +1,217 @@
+/*
+ * 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.clerezza.api.utils;
+
+import org.apache.clerezza.api.*;
+import org.apache.clerezza.api.impl.TripleImpl;
+import org.apache.clerezza.api.impl.graph.SimpleImmutableGraph;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.concurrent.locks.ReadWriteLock;
+
+/**
+ * This wrapps a Triplecollection changing a prefix for the IRIs contained
+ * in subject or object position.
+ *
+ * Currently it only supports read opearations.
+ *
+ * @author reto
+ */
+public class UriMutatingGraph implements Graph {
+
+ private final Graph base;
+ private final String sourcePrefix;
+ private final String targetPrefix;
+ private final int sourcePrefixLength;
+ private final int targetPrefixLength;
+
+ public UriMutatingGraph(Graph base, String sourcePrefix,
+ String targetPrefix) {
+ this.base = base;
+ this.sourcePrefix = sourcePrefix;
+ sourcePrefixLength= sourcePrefix.length();
+ this.targetPrefix = targetPrefix;
+ targetPrefixLength= targetPrefix.length();
+ }
+
+ private <R extends RDFTerm> R toTargetRDFTerm(final R sourceRDFTerm) {
+ if (sourceRDFTerm instanceof IRI) {
+ final IRI sourceIRI = (IRI) sourceRDFTerm;
+ if (sourceIRI.getUnicodeString().startsWith(sourcePrefix)) {
+ final String uriRest = sourceIRI.getUnicodeString()
+ .substring(sourcePrefixLength);
+ return (R) new IRI(targetPrefix+uriRest);
+ }
+ }
+ return sourceRDFTerm;
+ }
+
+ private Triple toTargetTriple(Triple triple) {
+ if (triple == null) {
+ return null;
+ }
+ return new TripleImpl(toTargetRDFTerm(triple.getSubject()),
+ triple.getPredicate(), toTargetRDFTerm(triple.getObject()));
+ }
+
+ private <R extends RDFTerm> R toSourceRDFTerm(final R targetRDFTerm) {
+ if (targetRDFTerm instanceof IRI) {
+ final IRI sourceIRI = (IRI) targetRDFTerm;
+ if (sourceIRI.getUnicodeString().startsWith(targetPrefix)) {
+ final String uriRest = sourceIRI.getUnicodeString()
+ .substring(targetPrefixLength);
+ return (R) new IRI(sourcePrefix+uriRest);
+ }
+ }
+ return targetRDFTerm;
+ }
+
+ private Triple toSourceTriple(Triple triple) {
+ if (triple == null) {
+ return null;
+ }
+ return new TripleImpl(toSourceRDFTerm(triple.getSubject()),
+ triple.getPredicate(), toSourceRDFTerm(triple.getObject()));
+ }
+
+ @Override
+ public Iterator<Triple> filter(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ final Iterator<Triple> baseIter = base.filter(toSourceRDFTerm(subject),
+ predicate, toSourceRDFTerm(object));
+ return new WrappedIteraror(baseIter);
+
+
+ }
+
+
+ @Override
+ public int size() {
+ return base.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return base.isEmpty();
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ return base.contains(toSourceTriple((Triple)o));
+ }
+
+ @Override
+ public Iterator<Triple> iterator() {
+ return filter(null, null, null);
+ }
+
+ @Override
+ public Object[] toArray() {
+ Object[] result = base.toArray();
+ for (int i = 0; i < result.length; i++) {
+ Triple triple = (Triple) result[i];
+ result[i] = toTargetTriple(triple);
+ }
+ return result;
+ }
+
+ @Override
+ public <T> T[] toArray(T[] a) {
+ T[] result = base.toArray(a);
+ for (int i = 0; i < result.length; i++) {
+ Triple triple = (Triple) result[i];
+ result[i] = (T) toTargetTriple(triple);
+ }
+ return result;
+ }
+
+ @Override
+ public boolean add(Triple e) {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ @Override
+ public boolean containsAll(Collection<?> c) {
+ for (Object object : c) {
+ if (!contains(object)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends Triple> c) {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ @Override
+ public boolean removeAll(Collection<?> c) {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ @Override
+ public boolean retainAll(Collection<?> c) {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ @Override
+ public void clear() {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ @Override
+ public ImmutableGraph getImmutableGraph() {
+ return new SimpleImmutableGraph(this);
+ }
+
+ @Override
+ public ReadWriteLock getLock() {
+ return base.getLock();
+ }
+
+ class WrappedIteraror implements Iterator<Triple>{
+ private final Iterator<Triple> baseIter;
+
+ private WrappedIteraror(Iterator<Triple> baseIter) {
+ this.baseIter = baseIter;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return baseIter.hasNext();
+ }
+
+ @Override
+ public Triple next() {
+ return toTargetTriple(baseIter.next());
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ }
+}
diff --git a/api.utils/src/main/java/org/apache/clerezza/api/utils/graphnodeprovider/GraphNodeProvider.java b/api.utils/src/main/java/org/apache/clerezza/api/utils/graphnodeprovider/GraphNodeProvider.java
new file mode 100644
index 0000000..f72106d
--- /dev/null
+++ b/api.utils/src/main/java/org/apache/clerezza/api/utils/graphnodeprovider/GraphNodeProvider.java
@@ -0,0 +1,51 @@
+/*
+ * 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.clerezza.api.utils.graphnodeprovider;
+
+import org.apache.clerezza.api.IRI;
+import org.apache.clerezza.api.utils.GraphNode;
+
+/**
+ * A service that returns a GraphNode for a specified named resource, the
+ * returned GraphNode has as BaseGraph the ContentGraph provided by the
+ * ContentGraphProvider and the for remote uris the Graphs they dereference to
+ * and for local URIs with a path-section starting with /user/{username}/ the
+ * local-public-graph of that user.
+ */
+public interface GraphNodeProvider {
+
+ /**
+ * Get a GraphNode for the specified resource, see class comments for
+ * details.
+ */
+ GraphNode get(IRI uriRef);
+
+ /**
+ * Get a GraphNode for the specified resource, The resource is assumed to be
+ * local, i.e. the method behaves like get(IRI) for a Uri with an
+ authority section contained in the Set retuned by
+ <code>org.apache.clerezza.platform.config.PlatformConfig#getBaseUris()</code>
+ */
+ GraphNode getLocal(IRI uriRef);
+
+ /**
+ * return true iff getLocal(uriRef).getNodeContext.size > 0
+ */
+ boolean existsLocal(IRI uriRef);
+}
diff --git a/api.utils/src/main/java/org/apache/clerezza/api/utils/smushing/BaseSmusher.java b/api.utils/src/main/java/org/apache/clerezza/api/utils/smushing/BaseSmusher.java
new file mode 100644
index 0000000..569e638
--- /dev/null
+++ b/api.utils/src/main/java/org/apache/clerezza/api/utils/smushing/BaseSmusher.java
@@ -0,0 +1,130 @@
+/*
+ * 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.clerezza.api.utils.smushing;
+
+import org.apache.clerezza.api.*;
+import org.apache.clerezza.api.impl.TripleImpl;
+import org.apache.clerezza.api.impl.graph.SimpleGraph;
+import org.apache.clerezza.ontologies.OWL;
+
+import java.util.*;
+import java.util.concurrent.locks.Lock;
+
+/**
+ *
+ * @author Reto
+ */
+public class BaseSmusher {
+
+ /**
+ * Smushes the resources in mGraph that belong to the same set in equivalenceSets,
+ * i.e. it adds all properties to one of the resources in the equivalence set.
+ *
+ * Optionally owl:sameAs statement are added that point from the IRIs that
+ * no longer have properties to the one with properties. If addOwlSameAs
+ * is false the IRIs will just disappear from the graph.
+ *
+ * @param mGraph the graph to smush
+ * @param equivalenceSets sets of equivalent resources
+ * @param addOwlSameAs whether owl:sameAs statements should be added
+ */
+ public void smush(Graph mGraph, Set<Set<BlankNodeOrIRI>> equivalenceSets, boolean addOwlSameAs) {
+ Map<BlankNodeOrIRI, BlankNodeOrIRI> current2ReplacementMap = new HashMap<BlankNodeOrIRI, BlankNodeOrIRI>();
+ final Graph owlSameAsGraph = new SimpleGraph();
+ for (Set<BlankNodeOrIRI> equivalenceSet : equivalenceSets) {
+ final BlankNodeOrIRI replacement = getReplacementFor(equivalenceSet, owlSameAsGraph);
+ for (BlankNodeOrIRI current : equivalenceSet) {
+ if (!current.equals(replacement)) {
+ current2ReplacementMap.put(current, replacement);
+ }
+ }
+ }
+ final Set<Triple> newTriples = new HashSet<Triple>();
+ Lock l = mGraph.getLock().writeLock();
+ l.lock();
+ try {
+ for (Iterator<Triple> it = mGraph.iterator(); it.hasNext();) {
+ final Triple triple = it.next();
+ final BlankNodeOrIRI subject = triple.getSubject();
+ BlankNodeOrIRI subjectReplacement = current2ReplacementMap.get(subject);
+ final RDFTerm object = triple.getObject();
+ @SuppressWarnings(value = "element-type-mismatch")
+ RDFTerm objectReplacement = current2ReplacementMap.get(object);
+ if ((subjectReplacement != null) || (objectReplacement != null)) {
+ it.remove();
+ if (subjectReplacement == null) {
+ subjectReplacement = subject;
+ }
+ if (objectReplacement == null) {
+ objectReplacement = object;
+ }
+ newTriples.add(new TripleImpl(subjectReplacement, triple.getPredicate(), objectReplacement));
+ }
+ }
+ for (Triple triple : newTriples) {
+ mGraph.add(triple);
+ }
+ mGraph.addAll(owlSameAsGraph);
+ } finally {
+ l.unlock();
+ }
+ }
+
+ private BlankNodeOrIRI getReplacementFor(Set<BlankNodeOrIRI> equivalenceSet,
+ Graph owlSameAsGraph) {
+ final Set<IRI> uriRefs = new HashSet<IRI>();
+ for (BlankNodeOrIRI nonLiteral : equivalenceSet) {
+ if (nonLiteral instanceof IRI) {
+ uriRefs.add((IRI) nonLiteral);
+ }
+ }
+ switch (uriRefs.size()) {
+ case 1:
+ return uriRefs.iterator().next();
+ case 0:
+ return new BlankNode();
+ }
+ final IRI preferedIRI = getPreferedIRI(uriRefs);
+ final Iterator<IRI> uriRefIter = uriRefs.iterator();
+ while (uriRefIter.hasNext()) {
+ IRI uriRef = uriRefIter.next();
+ if (!uriRef.equals(preferedIRI)) {
+ owlSameAsGraph.add(new TripleImpl(uriRef, OWL.sameAs, preferedIRI));
+ }
+ }
+ return preferedIRI;
+ }
+
+
+ /**
+ * Returns a prefered IRI for the IRIs in a set. Typically and in the
+ * default implementation the IRI will be one of the set. Note however that
+ * subclass implementations may also return another IRI to be used.
+ *
+ * @param uriRefs
+ * @return
+ */
+ protected IRI getPreferedIRI(Set<IRI> uriRefs) {
+ final Iterator<IRI> uriRefIter = uriRefs.iterator();
+ //instead of an arbitrary one we might either decide lexicographically
+ //or look at their frequency in mGraph
+ return uriRefIter.next();
+ }
+
+}
diff --git a/api.utils/src/main/java/org/apache/clerezza/api/utils/smushing/IfpSmusher.java b/api.utils/src/main/java/org/apache/clerezza/api/utils/smushing/IfpSmusher.java
new file mode 100644
index 0000000..4c57af5
--- /dev/null
+++ b/api.utils/src/main/java/org/apache/clerezza/api/utils/smushing/IfpSmusher.java
@@ -0,0 +1,165 @@
+/*
+ * 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.clerezza.api.utils.smushing;
+
+import org.apache.clerezza.api.*;
+import org.apache.clerezza.ontologies.OWL;
+import org.apache.clerezza.ontologies.RDF;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.*;
+
+/**
+ * A utility to equate duplicate nodes in an Mgarph, currently only nodes with
+ * a shared ifp are equated.
+ *
+ * @author reto
+ */
+public class IfpSmusher extends BaseSmusher {
+
+ static final Logger log = LoggerFactory.getLogger(IfpSmusher.class);
+
+ /**
+ * smush mGaph given the ontological facts. Currently it does only
+ * one step ifp smushin, i.e. only ifps are taken in account and only
+ * nodes that have the same node as ifp object in the orignal graph are
+ * equates. (calling the method a second time might lead to additional
+ * smushings.)
+ *
+ * @param mGraph
+ * @param tBox
+ */
+ public void smush(Graph mGraph, Graph tBox) {
+ final Set<IRI> ifps = getIfps(tBox);
+ final Map<PredicateObject, Set<BlankNodeOrIRI>> ifp2nodesMap = new HashMap<PredicateObject, Set<BlankNodeOrIRI>>();
+ for (Iterator<Triple> it = mGraph.iterator(); it.hasNext();) {
+ final Triple triple = it.next();
+ final IRI predicate = triple.getPredicate();
+ if (!ifps.contains(predicate)) {
+ continue;
+ }
+ final PredicateObject po = new PredicateObject(predicate, triple.getObject());
+ Set<BlankNodeOrIRI> equivalentNodes = ifp2nodesMap.get(po);
+ if (equivalentNodes == null) {
+ equivalentNodes = new HashSet<BlankNodeOrIRI>();
+ ifp2nodesMap.put(po, equivalentNodes);
+ }
+ equivalentNodes.add(triple.getSubject());
+ }
+ Set<Set<BlankNodeOrIRI>> unitedEquivalenceSets = uniteSetsWithCommonElement(ifp2nodesMap.values());
+ smush(mGraph, unitedEquivalenceSets, true);
+ }
+
+
+ private Set<IRI> getIfps(Graph tBox) {
+ final Iterator<Triple> ifpDefinitions = tBox.filter(null, RDF.type,
+ OWL.InverseFunctionalProperty);
+ final Set<IRI> ifps = new HashSet<IRI>();
+ while (ifpDefinitions.hasNext()) {
+ final Triple triple = ifpDefinitions.next();
+ ifps.add((IRI) triple.getSubject());
+ }
+ return ifps;
+ }
+
+ private <T> Set<Set<T>> uniteSetsWithCommonElement(
+ Collection<Set<T>> originalSets) {
+ Set<Set<T>> result = new HashSet<Set<T>>();
+ Iterator<Set<T>> iter = originalSets.iterator();
+ while (iter.hasNext()) {
+ Set<T> originalSet = iter.next();
+ //TODO this could be done more efficiently with a map
+ Set<T> matchingSet = getMatchinSet(originalSet, result);
+ if (matchingSet != null) {
+ matchingSet.addAll(originalSet);
+ } else {
+ result.add(new HashSet<T>(originalSet));
+ }
+ }
+ if (result.size() < originalSets.size()) {
+ return uniteSetsWithCommonElement(result);
+ } else {
+ return result;
+ }
+ }
+
+ private <T> Set<T> getMatchinSet(Set<T> set, Set<Set<T>> setOfSet) {
+ for (Set<T> current : setOfSet) {
+ if (shareElements(set,current)) {
+ return current;
+ }
+ }
+ return null;
+ }
+
+ private <T> boolean shareElements(Set<T> set1, Set<T> set2) {
+ for (T elem : set2) {
+ if (set1.contains(elem)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ class PredicateObject {
+
+ final IRI predicate;
+ final RDFTerm object;
+
+ public PredicateObject(IRI predicate, RDFTerm object) {
+ this.predicate = predicate;
+ this.object = object;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final PredicateObject other = (PredicateObject) obj;
+ if (this.predicate != other.predicate && !this.predicate.equals(other.predicate)) {
+ return false;
+ }
+ if (this.object != other.object && !this.object.equals(other.object)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 3;
+ hash = 29 * hash + this.predicate.hashCode();
+ hash = 13 * hash + this.object.hashCode();
+ return hash;
+ }
+
+ @Override
+ public String toString() {
+ return "("+predicate+", "+object+")";
+ }
+
+
+ };
+}
diff --git a/api.utils/src/main/java/org/apache/clerezza/api/utils/smushing/SameAsSmusher.java b/api.utils/src/main/java/org/apache/clerezza/api/utils/smushing/SameAsSmusher.java
new file mode 100644
index 0000000..3571ae6
--- /dev/null
+++ b/api.utils/src/main/java/org/apache/clerezza/api/utils/smushing/SameAsSmusher.java
@@ -0,0 +1,109 @@
+/*
+ * 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.clerezza.api.utils.smushing;
+
+import org.apache.clerezza.api.BlankNodeOrIRI;
+import org.apache.clerezza.api.Graph;
+import org.apache.clerezza.api.IRI;
+import org.apache.clerezza.api.Triple;
+import org.apache.clerezza.ontologies.OWL;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.*;
+
+/**
+ * A utility to equate duplicate nodes in an Mgraph. This unifies owl:sameAs
+ * resources.
+ *
+ * @author reto
+ */
+public class SameAsSmusher extends BaseSmusher {
+
+ static final Logger log = LoggerFactory.getLogger(SameAsSmusher.class);
+
+ /**
+ * This will ensure that all properties of sameAs resources are associated
+ * to the preferedIRI as returned by {@code getPreferedIRI}
+ * @param mGraph
+ * @param owlSameStatements
+ * @param addCanonicalSameAsStatements if true owl:sameAsStatements with the preferedIRI as object will be added
+ */
+ public void smush(Graph mGraph,
+ Graph owlSameStatements,
+ boolean addCanonicalSameAsStatements) {
+
+ log.info("Starting smushing");
+
+ // This hashmap contains a uri (key) and the set of equivalent uris (value)
+ final Map<BlankNodeOrIRI, Set<BlankNodeOrIRI>> node2EquivalenceSet = new HashMap<BlankNodeOrIRI, Set<BlankNodeOrIRI>>();
+
+ log.info("Creating the sets of equivalent uris of each subject or object in the owl:sameAs statements");
+ // Determines for each subject and object in all the owl:sameAs statements the set of ewquivalent uris
+ for (Iterator<Triple> it = owlSameStatements.iterator(); it.hasNext();) {
+ final Triple triple = it.next();
+ final IRI predicate = triple.getPredicate();
+ if (!predicate.equals(OWL.sameAs)) {
+ throw new RuntimeException("Statements must use only <http://www.w3.org/2002/07/owl#sameAs> predicate.");
+ }
+ final BlankNodeOrIRI subject = triple.getSubject();
+ //literals not yet supported
+ final BlankNodeOrIRI object = (BlankNodeOrIRI)triple.getObject();
+
+ Set<BlankNodeOrIRI> equivalentNodes = node2EquivalenceSet.get(subject);
+
+ // if there is not a set of equivalent uris then create a new set
+ if (equivalentNodes == null) {
+ equivalentNodes = node2EquivalenceSet.get(object);
+ if (equivalentNodes == null) {
+ equivalentNodes = new HashSet<BlankNodeOrIRI>();
+ }
+ } else {
+ Set<BlankNodeOrIRI> objectSet = node2EquivalenceSet.get(object);
+ if ((objectSet != null) && (objectSet != equivalentNodes)) {
+ //merge two sets
+ for (BlankNodeOrIRI res : objectSet) {
+ node2EquivalenceSet.remove(res);
+ }
+ for (BlankNodeOrIRI res : objectSet) {
+ node2EquivalenceSet.put(res,equivalentNodes);
+ }
+ equivalentNodes.addAll(objectSet);
+ }
+ }
+
+ // add both subject and object of the owl:sameAs statement to the set of equivalent uris
+ equivalentNodes.add(subject);
+ equivalentNodes.add(object);
+
+ // use both uris in the owl:sameAs statement as keys for the set of equivalent uris
+ node2EquivalenceSet.put(subject, equivalentNodes);
+ node2EquivalenceSet.put(object, equivalentNodes);
+
+ log.info("Sets of equivalent uris created.");
+
+ }
+
+ // This set contains the sets of equivalent uris
+ Set<Set<BlankNodeOrIRI>> unitedEquivalenceSets = new HashSet<Set<BlankNodeOrIRI>>(node2EquivalenceSet.values());
+ smush(mGraph, unitedEquivalenceSets, addCanonicalSameAsStatements);
+ }
+
+
+}
diff --git a/api.utils/src/test/java/org/apache/clerezza/api/utils/GraphUtilsTest.java b/api.utils/src/test/java/org/apache/clerezza/api/utils/GraphUtilsTest.java
new file mode 100644
index 0000000..f5df426
--- /dev/null
+++ b/api.utils/src/test/java/org/apache/clerezza/api/utils/GraphUtilsTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.clerezza.api.utils;
+
+import org.apache.clerezza.api.BlankNode;
+import org.apache.clerezza.api.Graph;
+import org.apache.clerezza.api.IRI;
+import org.apache.clerezza.api.impl.TripleImpl;
+import org.apache.clerezza.api.impl.graph.SimpleGraph;
+import org.apache.clerezza.api.utils.GraphUtils.NoSuchSubGraphException;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ *
+ * @author reto
+ */
+public class GraphUtilsTest {
+
+ final IRI u1 = new IRI("http://ex.org/1");
+ final IRI u2 = new IRI("http://ex.org/2");
+ final IRI u3 = new IRI("http://ex.org/3");
+
+ @Test
+ public void removeSubGraph() throws NoSuchSubGraphException {
+ Graph baseGraph = createBaseGraph();
+
+ Graph subGraph = new SimpleGraph();
+ {
+ BlankNode bNode1 = new BlankNode();
+ BlankNode bNode2 = new BlankNode();
+ subGraph.add(new TripleImpl(u1, u2, bNode2));
+ subGraph.add(new TripleImpl(bNode2, u2, bNode2));
+ subGraph.add(new TripleImpl(bNode2, u2, bNode1));
+ }
+ GraphUtils.removeSubGraph(baseGraph, subGraph);
+ Assert.assertEquals(1, baseGraph.size());
+ }
+
+ private Graph createBaseGraph() {
+ Graph baseGraph = new SimpleGraph();
+ {
+ BlankNode bNode1 = new BlankNode();
+ BlankNode bNode2 = new BlankNode();
+ baseGraph.add(new TripleImpl(u1, u2, bNode2));
+ baseGraph.add(new TripleImpl(bNode2, u2, bNode2));
+ baseGraph.add(new TripleImpl(bNode2, u2, bNode1));
+ baseGraph.add(new TripleImpl(u3, u2, u1));
+ }
+ return baseGraph;
+ }
+
+ /** It is required that the subgraph comprises the whole context of the Bnodes it ioncludes
+ *
+ * @throws org.apache.clerezza.utils.GraphUtils.NoSuchSubGraphException
+ */
+ @Test(expected=NoSuchSubGraphException.class)
+ public void removeIncompleteSubGraph() throws NoSuchSubGraphException {
+ Graph baseGraph = createBaseGraph();
+
+ Graph subGraph = new SimpleGraph();
+ {
+ BlankNode bNode1 = new BlankNode();
+ BlankNode bNode2 = new BlankNode();
+ subGraph.add(new TripleImpl(u1, u2, bNode2));
+ subGraph.add(new TripleImpl(bNode2, u2, bNode2));
+ }
+ GraphUtils.removeSubGraph(baseGraph, subGraph);
+ }
+
+ @Test(expected=NoSuchSubGraphException.class)
+ public void removeInvalidSubGraph() throws NoSuchSubGraphException {
+ Graph baseGraph = createBaseGraph();
+
+ Graph subGraph = new SimpleGraph();
+ {
+ BlankNode bNode1 = new BlankNode();
+ BlankNode bNode2 = new BlankNode();
+ subGraph.add(new TripleImpl(u1, u2, bNode2));
+ subGraph.add(new TripleImpl(bNode2, u2, bNode2));
+ baseGraph.add(new TripleImpl(bNode2, u2, bNode1));
+ baseGraph.add(new TripleImpl(bNode2, u2, new BlankNode()));
+ }
+ GraphUtils.removeSubGraph(baseGraph, subGraph);
+ }
+}
+
diff --git a/api.utils/src/test/java/org/apache/clerezza/api/utils/IfpSmushTest.java b/api.utils/src/test/java/org/apache/clerezza/api/utils/IfpSmushTest.java
new file mode 100644
index 0000000..18d3f9d
--- /dev/null
+++ b/api.utils/src/test/java/org/apache/clerezza/api/utils/IfpSmushTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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.clerezza.api.utils;
+
+import org.apache.clerezza.api.BlankNode;
+import org.apache.clerezza.api.Graph;
+import org.apache.clerezza.api.IRI;
+import org.apache.clerezza.api.impl.TripleImpl;
+import org.apache.clerezza.api.impl.graph.SimpleGraph;
+import org.apache.clerezza.api.impl.literal.PlainLiteralImpl;
+import org.apache.clerezza.ontologies.FOAF;
+import org.apache.clerezza.ontologies.OWL;
+import org.apache.clerezza.ontologies.RDF;
+import org.apache.clerezza.ontologies.RDFS;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ *
+ * @author reto
+ */
+public class IfpSmushTest {
+
+ private Graph ontology = new SimpleGraph();
+ {
+ ontology.add(new TripleImpl(FOAF.mbox, RDF.type, OWL.InverseFunctionalProperty));
+ }
+
+ @Test
+ public void simpleBlankNode() {
+ Graph mGraph = new SimpleGraph();
+ IRI mbox1 = new IRI("mailto:foo@example.org");
+ final BlankNode bNode1 = new BlankNode();
+ mGraph.add(new TripleImpl(bNode1, FOAF.mbox, mbox1));
+ mGraph.add(new TripleImpl(bNode1, RDFS.comment,
+ new PlainLiteralImpl("a comment")));
+ final BlankNode bNode2 = new BlankNode();
+ mGraph.add(new TripleImpl(bNode2, FOAF.mbox, mbox1));
+ mGraph.add(new TripleImpl(bNode2, RDFS.comment,
+ new PlainLiteralImpl("another comment")));
+ Smusher.smush(mGraph, ontology);
+ Assert.assertEquals(3, mGraph.size());
+ }
+
+ @Test
+ public void overlappingEquivalenceClasses() {
+ Graph mGraph = new SimpleGraph();
+ IRI mbox1 = new IRI("mailto:foo@example.org");
+ final BlankNode bNode1 = new BlankNode();
+ mGraph.add(new TripleImpl(bNode1, FOAF.mbox, mbox1));
+ mGraph.add(new TripleImpl(bNode1, RDFS.comment,
+ new PlainLiteralImpl("a comment")));
+ final BlankNode bNode2 = new BlankNode();
+ IRI mbox2 = new IRI("mailto:bar@example.org");
+ mGraph.add(new TripleImpl(bNode2, FOAF.mbox, mbox1));
+ mGraph.add(new TripleImpl(bNode2, FOAF.mbox, mbox2));
+ mGraph.add(new TripleImpl(bNode2, RDFS.comment,
+ new PlainLiteralImpl("another comment")));
+ final BlankNode bNode3 = new BlankNode();
+ mGraph.add(new TripleImpl(bNode3, FOAF.mbox, mbox2));
+ mGraph.add(new TripleImpl(bNode3, RDFS.comment,
+ new PlainLiteralImpl("yet another comment")));
+ Smusher.smush(mGraph, ontology);
+ Assert.assertEquals(5, mGraph.size());
+ }
+
+ @Test
+ public void oneIRI() {
+ Graph mGraph = new SimpleGraph();
+ IRI mbox1 = new IRI("mailto:foo@example.org");
+ final IRI resource = new IRI("http://example.org/");
+ mGraph.add(new TripleImpl(resource, FOAF.mbox, mbox1));
+ mGraph.add(new TripleImpl(resource, RDFS.comment,
+ new PlainLiteralImpl("a comment")));
+ final BlankNode bNode2 = new BlankNode();
+ mGraph.add(new TripleImpl(bNode2, FOAF.mbox, mbox1));
+ mGraph.add(new TripleImpl(bNode2, RDFS.comment,
+ new PlainLiteralImpl("another comment")));
+ Smusher.smush(mGraph, ontology);
+ Assert.assertEquals(3, mGraph.size());
+ }
+
+ @Test
+ public void twoIRIs() {
+ Graph mGraph = new SimpleGraph();
+ IRI mbox1 = new IRI("mailto:foo@example.org");
+ final IRI resource1 = new IRI("http://example.org/");
+ mGraph.add(new TripleImpl(resource1, FOAF.mbox, mbox1));
+ mGraph.add(new TripleImpl(resource1, RDFS.comment,
+ new PlainLiteralImpl("a comment")));
+ final IRI resource2 = new IRI("http://2.example.org/");
+ mGraph.add(new TripleImpl(resource2, FOAF.mbox, mbox1));
+ mGraph.add(new TripleImpl(resource2, RDFS.comment,
+ new PlainLiteralImpl("another comment")));
+ Smusher.smush(mGraph, ontology);
+ Assert.assertEquals(4, mGraph.size());
+ }
+
+}
diff --git a/api.utils/src/test/java/org/apache/clerezza/api/utils/RdfListTest.java b/api.utils/src/test/java/org/apache/clerezza/api/utils/RdfListTest.java
new file mode 100644
index 0000000..ea19303
--- /dev/null
+++ b/api.utils/src/test/java/org/apache/clerezza/api/utils/RdfListTest.java
@@ -0,0 +1,182 @@
+/*
+ * 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.clerezza.api.utils;
+
+import junit.framework.Assert;
+import org.apache.clerezza.api.BlankNode;
+import org.apache.clerezza.api.Graph;
+import org.apache.clerezza.api.IRI;
+import org.apache.clerezza.api.RDFTerm;
+import org.apache.clerezza.api.impl.graph.SimpleGraph;
+import org.apache.clerezza.api.impl.literal.PlainLiteralImpl;
+import org.junit.Test;
+
+import java.util.List;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ *
+ * @author rbn
+ */
+public class RdfListTest {
+
+ @Test
+ public void listCreationAndAccess() {
+ Graph tc = new SimpleGraph();
+ List<RDFTerm> list = new RdfList(new IRI("http://example.org/mytest"), tc);
+ assertEquals(0, list.size());
+ list.add(new PlainLiteralImpl("hello"));
+ list.add(new PlainLiteralImpl("world"));
+ assertEquals(new PlainLiteralImpl("hello"), list.get(0));
+ assertEquals(new PlainLiteralImpl("world"), list.get(1));
+ assertEquals(2, list.size());
+ list.add(new PlainLiteralImpl("welcome"));
+ assertEquals(3, list.size());
+ assertEquals(new PlainLiteralImpl("welcome"), list.get(2));
+ list.add(1, new PlainLiteralImpl("interesting"));
+ assertEquals(4, list.size());
+ assertEquals(new PlainLiteralImpl("interesting"), list.get(1));
+ assertEquals(new PlainLiteralImpl("world"), list.get(2));
+ assertEquals(new PlainLiteralImpl("welcome"), list.get(3));
+ list.add(0, new PlainLiteralImpl("start"));
+ assertEquals(5, list.size());
+ assertEquals(new PlainLiteralImpl("hello"), list.get(1));
+ assertEquals(new PlainLiteralImpl("interesting"), list.get(2));
+ List<RDFTerm> list2 = new RdfList(new IRI("http://example.org/mytest"), tc);
+ assertEquals(5, list2.size());
+ assertEquals(new PlainLiteralImpl("hello"), list2.get(1));
+ assertEquals(new PlainLiteralImpl("interesting"), list2.get(2));
+ list2.remove(2);
+ assertEquals(4, list2.size());
+ assertEquals(new PlainLiteralImpl("hello"), list2.get(1));
+ assertEquals(new PlainLiteralImpl("world"), list2.get(2));
+ while (list2.size() > 0) {
+ list2.remove(0);
+ }
+ assertEquals(1, tc.size()); //list = rdf:nil statement
+ list2.add(0, new PlainLiteralImpl("restart"));
+ list2.add(1, new PlainLiteralImpl("over"));
+ assertEquals(2, list2.size());
+ list2.add(new PlainLiteralImpl("2"));
+ list2.add(new PlainLiteralImpl("3"));
+ assertEquals(4, list2.size());
+ list2.add(new PlainLiteralImpl("4"));
+ list2.add(new PlainLiteralImpl("5"));
+ assertEquals(new PlainLiteralImpl("3"), list2.get(3));
+ }
+
+ @Test
+ public void listCreationAndAccess2() {
+ Graph tc = new SimpleGraph();
+ List<RDFTerm> list = new RdfList(new IRI("http://example.org/mytest"), tc);
+ assertEquals(0, list.size());
+ list.add(0,new PlainLiteralImpl("world"));
+ list = new RdfList(new IRI("http://example.org/mytest"), tc);
+ list.add(0,new PlainLiteralImpl("beautifuly"));
+ list = new RdfList(new IRI("http://example.org/mytest"), tc);
+ list.add(0,new PlainLiteralImpl("hello"));
+ assertEquals(new PlainLiteralImpl("hello"), list.get(0));
+ assertEquals(new PlainLiteralImpl("beautifuly"), list.get(1));
+ assertEquals(new PlainLiteralImpl("world"), list.get(2));
+ }
+
+ @Test
+ public void listCreationAndAccess3() {
+ Graph tc = new SimpleGraph();
+ List<RDFTerm> list = new RdfList(new IRI("http://example.org/mytest"), tc);
+ assertEquals(0, list.size());
+ BlankNode node0 = new BlankNode() {};
+ BlankNode node1 = new BlankNode() {};
+ BlankNode node2 = new BlankNode() {};
+ list.add(0,node2);
+ list.add(0,node1);
+ list.add(0,node0);
+ assertEquals(node0, list.get(0));
+ assertEquals(node1, list.get(1));
+ assertEquals(node2, list.get(2));
+ }
+
+ @Test
+ public void secondButLastElementAccessTest() {
+ Graph tc = new SimpleGraph();
+ List<RDFTerm> list = new RdfList(new IRI("http://example.org/mytest2"), tc);
+ list.add(new PlainLiteralImpl("hello"));
+ list.add(new PlainLiteralImpl("world"));
+ list.remove(1);
+ assertEquals(1, list.size());
+ }
+
+ @Test
+ public void cleanGraphAfterRemoval() {
+ Graph tc = new SimpleGraph();
+ List<RDFTerm> list = new RdfList(new IRI("http://example.org/mytest"), tc);
+ list.add(new PlainLiteralImpl("hello"));
+ list.add(new PlainLiteralImpl("world"));
+ list.remove(1);
+ Assert.assertEquals(2, tc.size());
+
+ }
+
+ @Test
+ public void findContainingListNodesAndfindContainingListsTest() {
+ Graph tc = new SimpleGraph();
+ GraphNode listA = new GraphNode(new IRI("http:///listA"), tc);
+ GraphNode listB = new GraphNode(new IRI("http:///listB"), tc);
+ BlankNode element1 = new BlankNode();
+ BlankNode element2 = new BlankNode();
+ BlankNode element3 = new BlankNode();
+ BlankNode element4 = new BlankNode();
+ BlankNode element5 = new BlankNode();
+
+ RdfList rdfListA = new RdfList(listA);
+ rdfListA.add(element1);
+ rdfListA.add(element2);
+ rdfListA.add(element3);
+ rdfListA.add(element4);
+
+ RdfList rdfListB = new RdfList(listB);
+ rdfListB.add(element2);
+ rdfListB.add(element4);
+ rdfListB.add(element5);
+
+ Set<GraphNode> containingListNodes = RdfList.findContainingListNodes(
+ new GraphNode(element3, tc));
+ Assert.assertEquals(1, containingListNodes.size());
+ Assert.assertTrue(containingListNodes.contains(listA));
+
+ Set<RdfList> containingLists = RdfList.findContainingLists(
+ new GraphNode(element3, tc));
+ Assert.assertEquals(1, containingLists.size());
+ Assert.assertTrue(containingLists.contains(rdfListA));
+
+ containingListNodes = RdfList.findContainingListNodes(
+ new GraphNode(element4, tc));
+ Assert.assertEquals(2, containingListNodes.size());
+ Assert.assertTrue(containingListNodes.contains(listA));
+ Assert.assertTrue(containingListNodes.contains(listB));
+
+ containingLists = RdfList.findContainingLists(
+ new GraphNode(element4, tc));
+ Assert.assertEquals(2, containingLists.size());
+ Assert.assertTrue(containingLists.contains(rdfListA));
+ Assert.assertTrue(containingLists.contains(rdfListB));
+ }
+}
\ No newline at end of file
diff --git a/api.utils/src/test/java/org/apache/clerezza/api/utils/SameAsSmushTest.java b/api.utils/src/test/java/org/apache/clerezza/api/utils/SameAsSmushTest.java
new file mode 100644
index 0000000..c03e3c8
--- /dev/null
+++ b/api.utils/src/test/java/org/apache/clerezza/api/utils/SameAsSmushTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.clerezza.api.utils;
+
+import org.apache.clerezza.api.Graph;
+import org.apache.clerezza.api.IRI;
+import org.apache.clerezza.api.Literal;
+import org.apache.clerezza.api.Triple;
+import org.apache.clerezza.api.impl.TripleImpl;
+import org.apache.clerezza.api.impl.graph.SimpleGraph;
+import org.apache.clerezza.api.impl.literal.PlainLiteralImpl;
+import org.apache.clerezza.ontologies.FOAF;
+import org.apache.clerezza.ontologies.OWL;
+import org.apache.clerezza.ontologies.RDFS;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Iterator;
+
+/**
+ *
+ * @author reto
+ */
+public class SameAsSmushTest {
+
+ private final IRI uriA = new IRI("http://example.org/A");
+ private final IRI uriB = new IRI("http://example.org/B");
+ private final Literal lit = new PlainLiteralImpl("That's me (and you)");
+
+ private Graph sameAsStatements = new SimpleGraph();
+ {
+ sameAsStatements.add(new TripleImpl(uriA, OWL.sameAs, uriB));
+ }
+
+ private Graph dataGraph = new SimpleGraph();
+ {
+ dataGraph.add(new TripleImpl(uriA, FOAF.knows, uriB));
+ dataGraph.add(new TripleImpl(uriB, RDFS.label, lit));
+ dataGraph.add(new TripleImpl(uriA, RDFS.label, lit));
+ }
+
+ @Test
+ public void simple() {
+ Assert.assertEquals(3, dataGraph.size());
+ Smusher.sameAsSmush(dataGraph, sameAsStatements);
+ Assert.assertEquals(3, dataGraph.size());
+ Assert.assertTrue(dataGraph.filter(null, OWL.sameAs, null).hasNext());
+ //exactly one statement with literal
+ Iterator<Triple> litStmts = dataGraph.filter(null, null, lit);
+ Assert.assertTrue(litStmts.hasNext());
+ Triple litStmt = litStmts.next();
+ Assert.assertFalse(litStmts.hasNext());
+ Iterator<Triple> knowsStmts = dataGraph.filter(null, FOAF.knows, null);
+ Assert.assertTrue(knowsStmts.hasNext());
+ Triple knowStmt = knowsStmts.next();
+ Assert.assertEquals(knowStmt.getSubject(), knowStmt.getObject());
+ Assert.assertEquals(litStmt.getSubject(), knowStmt.getObject());
+ Assert.assertEquals(litStmt.getSubject(), dataGraph.filter(null, OWL.sameAs, null).next().getObject());
+ }
+
+}
diff --git a/api.utils/src/test/java/org/apache/clerezza/api/utils/TestGraphNode.java b/api.utils/src/test/java/org/apache/clerezza/api/utils/TestGraphNode.java
new file mode 100644
index 0000000..3d0f8e3
--- /dev/null
+++ b/api.utils/src/test/java/org/apache/clerezza/api/utils/TestGraphNode.java
@@ -0,0 +1,266 @@
+/*
+ * 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.clerezza.api.utils;
+
+import junit.framework.Assert;
+import org.apache.clerezza.api.*;
+import org.apache.clerezza.api.impl.TripleImpl;
+import org.apache.clerezza.api.impl.graph.SimpleGraph;
+import org.apache.clerezza.api.impl.literal.PlainLiteralImpl;
+import org.apache.clerezza.test.utils.RandomGraph;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ *
+ * @author reto, mir
+ */
+public class TestGraphNode {
+
+ @Test
+ public void nodeContext() {
+ Graph g = new SimpleGraph();
+ BlankNode bNode1 = new BlankNode() {};
+ BlankNode bNode2 = new BlankNode() {};
+ IRI property1 = new IRI("http://example.org/property1");
+ IRI property2 = new IRI("http://example.org/property2");
+ g.add(new TripleImpl(bNode1, property1, new PlainLiteralImpl("literal")));
+ g.add(new TripleImpl(bNode1, property2, property1));
+ g.add(new TripleImpl(bNode2, property2, bNode1));
+ g.add(new TripleImpl(property1, property1, bNode2));
+ g.add(new TripleImpl(property1, property1, new PlainLiteralImpl("bla bla")));
+ GraphNode n = new GraphNode(bNode1, g);
+ Assert.assertEquals(4, n.getNodeContext().size());
+ n.deleteNodeContext();
+ Assert.assertEquals(1, g.size());
+ Assert.assertFalse(n.getObjects(property2).hasNext());
+ }
+
+ @Test
+ public void addNode() {
+ Graph g = new SimpleGraph();
+ BlankNode bNode1 = new BlankNode() {};
+ BlankNode bNode2 = new BlankNode() {};
+ IRI property1 = new IRI("http://example.org/property1");
+ GraphNode n = new GraphNode(bNode1, g);
+ n.addProperty(property1, bNode2);
+ Assert.assertEquals(1, g.size());
+ }
+
+ @Test
+ public void testGetSubjectAndObjectNodes() {
+ RandomGraph graph = new RandomGraph(500, 20, new SimpleGraph());
+ for (int j = 0; j < 200; j++) {
+ Triple randomTriple = graph.getRandomTriple();
+ GraphNode node = new GraphNode(randomTriple.getSubject(), graph);
+ Iterator<IRI> properties = node.getProperties();
+ while (properties.hasNext()) {
+ IRI property = properties.next();
+ Set<RDFTerm> objects = createSet(node.getObjects(property));
+ Iterator<GraphNode> objectNodes = node.getObjectNodes(property);
+ while (objectNodes.hasNext()) {
+ GraphNode graphNode = objectNodes.next();
+ Assert.assertTrue(objects.contains(graphNode.getNode()));
+ }
+ }
+ }
+
+ for (int j = 0; j < 200; j++) {
+ Triple randomTriple = graph.getRandomTriple();
+ GraphNode node = new GraphNode(randomTriple.getObject(), graph);
+ Iterator<IRI> properties = node.getProperties();
+ while (properties.hasNext()) {
+ IRI property = properties.next();
+ Set<RDFTerm> subjects = createSet(node.getSubjects(property));
+ Iterator<GraphNode> subjectNodes = node.getSubjectNodes(property);
+ while (subjectNodes.hasNext()) {
+ GraphNode graphNode = subjectNodes.next();
+ Assert.assertTrue(subjects.contains(graphNode.getNode()));
+ }
+ }
+ }
+ }
+
+ @Test
+ public void getAvailableProperties(){
+ Graph g = new SimpleGraph();
+ BlankNode bNode1 = new BlankNode() {};
+ BlankNode bNode2 = new BlankNode() {};
+ IRI property1 = new IRI("http://example.org/property1");
+ IRI property2 = new IRI("http://example.org/property2");
+ IRI property3 = new IRI("http://example.org/property3");
+ IRI property4 = new IRI("http://example.org/property4");
+ ArrayList<IRI> props = new ArrayList<IRI>();
+ props.add(property1);
+ props.add(property2);
+ props.add(property3);
+ props.add(property4);
+ GraphNode n = new GraphNode(bNode1, g);
+ n.addProperty(property1, bNode2);
+ n.addProperty(property2, bNode2);
+ n.addProperty(property3, bNode2);
+ n.addProperty(property4, bNode2);
+ Iterator<IRI> properties = n.getProperties();
+ int i = 0;
+ while(properties.hasNext()){
+ i++;
+ IRI prop = properties.next();
+ Assert.assertTrue(props.contains(prop));
+ props.remove(prop);
+ }
+ Assert.assertEquals(i, 4);
+ Assert.assertEquals(props.size(), 0);
+
+ }
+
+ @Test
+ public void deleteAll() {
+ Graph g = new SimpleGraph();
+ BlankNode bNode1 = new BlankNode() {};
+ BlankNode bNode2 = new BlankNode() {};
+ IRI property1 = new IRI("http://example.org/property1");
+ IRI property2 = new IRI("http://example.org/property2");
+ //the two properties two be deleted
+ g.add(new TripleImpl(bNode1, property1, new PlainLiteralImpl("literal")));
+ g.add(new TripleImpl(bNode1, property1, new PlainLiteralImpl("bla bla")));
+ //this 3 properties should stay
+ g.add(new TripleImpl(bNode1, property2, property1));
+ g.add(new TripleImpl(property1, property1, new PlainLiteralImpl("bla bla")));
+ g.add(new TripleImpl(bNode2, property1, new PlainLiteralImpl("bla bla")));
+ GraphNode n = new GraphNode(bNode1, g);
+ n.deleteProperties(property1);
+ Assert.assertEquals(3, g.size());
+ }
+
+ @Test
+ public void deleteSingleProperty() {
+ Graph g = new SimpleGraph();
+ BlankNode bNode1 = new BlankNode() {};
+ BlankNode bNode2 = new BlankNode() {};
+ IRI property1 = new IRI("http://example.org/property1");
+ IRI property2 = new IRI("http://example.org/property2");
+ //the properties two be deleted
+ g.add(new TripleImpl(bNode1, property1, new PlainLiteralImpl("literal")));
+ //this 4 properties should stay
+ g.add(new TripleImpl(bNode1, property1, new PlainLiteralImpl("bla bla")));
+ g.add(new TripleImpl(bNode1, property2, property1));
+ g.add(new TripleImpl(property1, property1, new PlainLiteralImpl("bla bla")));
+ g.add(new TripleImpl(bNode2, property1, new PlainLiteralImpl("bla bla")));
+ GraphNode n = new GraphNode(bNode1, g);
+ n.deleteProperty(property1, new PlainLiteralImpl("literal"));
+ Assert.assertEquals(4, g.size());
+ }
+
+ @Test
+ public void replaceWith() {
+ Graph initialGraph = new SimpleGraph();
+ BlankNode bNode1 = new BlankNode();
+ BlankNode bNode2 = new BlankNode();
+ BlankNode newBnode = new BlankNode();
+ IRI property1 = new IRI("http://example.org/property1");
+ IRI property2 = new IRI("http://example.org/property2");
+ IRI newIRI = new IRI("http://example.org/newName");
+ Literal literal1 = new PlainLiteralImpl("literal");
+ Literal literal2 = new PlainLiteralImpl("bla bla");
+
+ Triple triple1 = new TripleImpl(bNode1, property1, literal1);
+ Triple triple2 = new TripleImpl(bNode1, property2, property1);
+ Triple triple3 = new TripleImpl(bNode2, property2, bNode1);
+ Triple triple4 = new TripleImpl(property1, property1, bNode2);
+ Triple triple5 = new TripleImpl(property1, property1, literal2);
+ initialGraph.add(triple1);
+ initialGraph.add(triple2);
+ initialGraph.add(triple3);
+ initialGraph.add(triple4);
+ initialGraph.add(triple5);
+ GraphNode node = new GraphNode(property1,
+ new SimpleGraph(initialGraph.iterator()));
+
+ node.replaceWith(newIRI, true);
+ Assert.assertEquals(5, node.getGraph().size());
+ Triple expectedTriple1 = new TripleImpl(bNode1, newIRI, literal1);
+ Triple expectedTriple2 = new TripleImpl(bNode1, property2, newIRI);
+ Triple expectedTriple3 = new TripleImpl(newIRI, newIRI, bNode2);
+ Triple expectedTriple4 = new TripleImpl(newIRI, newIRI, literal2);
+
+ Assert.assertTrue(node.getGraph().contains(expectedTriple1));
+ Assert.assertTrue(node.getGraph().contains(expectedTriple2));
+ Assert.assertTrue(node.getGraph().contains(expectedTriple3));
+ Assert.assertTrue(node.getGraph().contains(expectedTriple4));
+
+ Assert.assertFalse(node.getGraph().contains(triple1));
+ Assert.assertFalse(node.getGraph().contains(triple2));
+ Assert.assertFalse(node.getGraph().contains(triple4));
+ Assert.assertFalse(node.getGraph().contains(triple5));
+
+ node = new GraphNode(property1, new SimpleGraph(initialGraph.iterator()));
+ node.replaceWith(newBnode);
+ Triple expectedTriple5 = new TripleImpl(bNode1, property2, newBnode);
+ Triple expectedTriple6 = new TripleImpl(newBnode, property1, bNode2);
+ Triple expectedTriple7 = new TripleImpl(newBnode, property1, literal2);
+
+ Assert.assertTrue(node.getGraph().contains(triple1));
+ Assert.assertTrue(node.getGraph().contains(expectedTriple5));
+ Assert.assertTrue(node.getGraph().contains(expectedTriple6));
+ Assert.assertTrue(node.getGraph().contains(expectedTriple7));
+
+ node = new GraphNode(literal1, new SimpleGraph(initialGraph.iterator()));
+ node.replaceWith(newBnode);
+ Triple expectedTriple8 = new TripleImpl(bNode1, property1, newBnode);
+ Assert.assertTrue(node.getGraph().contains(expectedTriple8));
+
+ node = new GraphNode(property1, new SimpleGraph(initialGraph.iterator()));
+ node.replaceWith(newIRI);
+ Triple expectedTriple9 = new TripleImpl(bNode1, property2, newIRI);
+ Triple expectedTriple10 = new TripleImpl(newIRI, property1, bNode2);
+ Triple expectedTriple11 = new TripleImpl(newIRI, property1, literal2);
+ Assert.assertTrue(node.getGraph().contains(triple1));
+ Assert.assertTrue(node.getGraph().contains(expectedTriple9));
+ Assert.assertTrue(node.getGraph().contains(expectedTriple10));
+ Assert.assertTrue(node.getGraph().contains(expectedTriple11));
+ }
+
+ @Test
+ public void equality() {
+ Graph g = new SimpleGraph();
+ BlankNode bNode1 = new BlankNode() {};
+ BlankNode bNode2 = new BlankNode() {};
+ IRI property1 = new IRI("http://example.org/property1");
+ GraphNode n = new GraphNode(bNode1, g);
+ n.addProperty(property1, bNode2);
+ Assert.assertTrue(n.equals(new GraphNode(bNode1, g)));
+ Assert.assertFalse(n.equals(new GraphNode(bNode2, g)));
+ GraphNode n2 = null;
+ Assert.assertFalse(n.equals(n2));
+ }
+
+ private Set<RDFTerm> createSet(Iterator<? extends RDFTerm> resources) {
+ Set<RDFTerm> set = new HashSet<RDFTerm>();
+ while (resources.hasNext()) {
+ RDFTerm resource = resources.next();
+ set.add(resource);
+ }
+ return set;
+ }
+
+}
diff --git a/api.utils/src/test/java/org/apache/clerezza/api/utils/UnionGraphTest.java b/api.utils/src/test/java/org/apache/clerezza/api/utils/UnionGraphTest.java
new file mode 100644
index 0000000..e1f8e33
--- /dev/null
+++ b/api.utils/src/test/java/org/apache/clerezza/api/utils/UnionGraphTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.clerezza.api.utils;
+
+import org.apache.clerezza.api.BlankNode;
+import org.apache.clerezza.api.Graph;
+import org.apache.clerezza.api.IRI;
+import org.apache.clerezza.api.Triple;
+import org.apache.clerezza.api.impl.TripleImpl;
+import org.apache.clerezza.api.impl.graph.SimpleGraph;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Iterator;
+
+/**
+ *
+ * @author hasan
+ */
+public class UnionGraphTest {
+
+ private final IRI uriRef1 =
+ new IRI("http://example.org/ontology#res1");
+ private final IRI uriRef2 =
+ new IRI("http://example.org/ontology#res2");
+ private final IRI uriRef3 =
+ new IRI("http://example.org/ontology#res3");
+ private final IRI uriRef4 =
+ new IRI("http://example.org/ontology#res4");
+
+ @Test
+ public void readAccess() {
+ Graph graph = new SimpleGraph();
+ Graph graph2 = new SimpleGraph();
+ BlankNode bnode = new BlankNode() {
+ };
+ graph.add(new TripleImpl(uriRef1, uriRef2, uriRef1));
+ graph2.add(new TripleImpl(bnode, uriRef1, uriRef3));
+ Graph unionGraph = new UnionGraph(graph, graph2);
+ Iterator<Triple> unionTriples = unionGraph.iterator();
+ Assert.assertTrue(unionTriples.hasNext());
+ unionTriples.next();
+ Assert.assertTrue(unionTriples.hasNext());
+ unionTriples.next();
+ Assert.assertFalse(unionTriples.hasNext());
+ Assert.assertEquals(2, unionGraph.size());
+ }
+
+ @Test
+ public void writeAccess() {
+ Graph graph = new SimpleGraph();
+ Graph graph2 = new SimpleGraph();
+ BlankNode bnode = new BlankNode() {
+ };
+ graph2.add(new TripleImpl(bnode, uriRef1, uriRef3));
+ Graph unionGraph = new UnionGraph(graph, graph2);
+ Assert.assertEquals(1, unionGraph.size());
+ unionGraph.add(new TripleImpl(uriRef4, uriRef1, uriRef3));
+ Assert.assertEquals(1, graph.size());
+ Assert.assertEquals(2, unionGraph.size());
+ Assert.assertEquals(1, graph2.size());
+ }
+}
\ No newline at end of file
diff --git a/api.utils/src/test/java/org/apache/clerezza/api/utils/smushing/SameAsSmushTest.java b/api.utils/src/test/java/org/apache/clerezza/api/utils/smushing/SameAsSmushTest.java
new file mode 100644
index 0000000..10ae1f0
--- /dev/null
+++ b/api.utils/src/test/java/org/apache/clerezza/api/utils/smushing/SameAsSmushTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.clerezza.api.utils.smushing;
+
+import org.apache.clerezza.api.Graph;
+import org.apache.clerezza.api.IRI;
+import org.apache.clerezza.api.Literal;
+import org.apache.clerezza.api.Triple;
+import org.apache.clerezza.api.impl.TripleImpl;
+import org.apache.clerezza.api.impl.graph.SimpleGraph;
+import org.apache.clerezza.api.impl.literal.PlainLiteralImpl;
+import org.apache.clerezza.ontologies.FOAF;
+import org.apache.clerezza.ontologies.OWL;
+import org.apache.clerezza.ontologies.RDFS;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ *
+ * @author reto
+ */
+public class SameAsSmushTest {
+
+ private final IRI uriA = new IRI("http://example.org/A");
+ private final IRI uriB = new IRI("http://example.org/B");
+ private final IRI uriC = new IRI("http://example.org/C");
+
+ private final Literal lit = new PlainLiteralImpl("That's me (and you)");
+
+ private Graph sameAsStatements = new SimpleGraph();
+ {
+ sameAsStatements.add(new TripleImpl(uriA, OWL.sameAs, uriB));
+ }
+
+ private Graph dataGraph = new SimpleGraph();
+ {
+ dataGraph.add(new TripleImpl(uriA, FOAF.knows, uriB));
+ dataGraph.add(new TripleImpl(uriB, RDFS.label, lit));
+ dataGraph.add(new TripleImpl(uriA, RDFS.label, lit));
+ }
+
+ @Test
+ public void simple() {
+ SameAsSmusher smusher = new SameAsSmusher() {
+
+ @Override
+ protected IRI getPreferedIRI(Set<IRI> uriRefs) {
+ if (!uriRefs.contains(uriA)) throw new RuntimeException("not the set we excpect");
+ if (!uriRefs.contains(uriB)) throw new RuntimeException("not the set we excpect");
+ return uriC;
+ }
+
+ };
+ Assert.assertEquals(3, dataGraph.size());
+ smusher.smush(dataGraph, sameAsStatements, true);
+ Assert.assertEquals(4, dataGraph.size());
+ Assert.assertTrue(dataGraph.filter(null, OWL.sameAs, null).hasNext());
+ //exactly one statement with literal
+ Iterator<Triple> litStmts = dataGraph.filter(null, null, lit);
+ Assert.assertTrue(litStmts.hasNext());
+ Triple litStmt = litStmts.next();
+ Assert.assertFalse(litStmts.hasNext());
+ Iterator<Triple> knowsStmts = dataGraph.filter(null, FOAF.knows, null);
+ Assert.assertTrue(knowsStmts.hasNext());
+ Triple knowStmt = knowsStmts.next();
+ Assert.assertEquals(knowStmt.getSubject(), knowStmt.getObject());
+ Assert.assertEquals(litStmt.getSubject(), knowStmt.getObject());
+ Assert.assertEquals(litStmt.getSubject(), dataGraph.filter(null, OWL.sameAs, null).next().getObject());
+ Assert.assertEquals(knowStmt.getSubject(), uriC);
+ }
+
+}