From commits-return-5216-archive-asf-public=cust-asf.ponee.io@clerezza.apache.org Tue Feb 12 06:06:16 2019 Return-Path: X-Original-To: archive-asf-public@cust-asf.ponee.io Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx-eu-01.ponee.io (Postfix) with SMTP id 78B6018062A for ; Tue, 12 Feb 2019 07:06:13 +0100 (CET) Received: (qmail 1604 invoked by uid 500); 12 Feb 2019 06:06:12 -0000 Mailing-List: contact commits-help@clerezza.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@clerezza.apache.org Delivered-To: mailing list commits@clerezza.apache.org Received: (qmail 1595 invoked by uid 99); 12 Feb 2019 06:06:12 -0000 Received: from ec2-52-202-80-70.compute-1.amazonaws.com (HELO gitbox.apache.org) (52.202.80.70) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 12 Feb 2019 06:06:12 +0000 Received: by gitbox.apache.org (ASF Mail Server at gitbox.apache.org, from userid 33) id 773EB82988; Tue, 12 Feb 2019 06:06:11 +0000 (UTC) Date: Tue, 12 Feb 2019 06:06:11 +0000 To: "commits@clerezza.apache.org" Subject: [clerezza] branch reunited updated: CLEREZZA-1037: Move utils from rdf module to api.utils module MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Message-ID: <154995157142.8868.7822796302196937143@gitbox.apache.org> From: hasan@apache.org X-Git-Host: gitbox.apache.org X-Git-Repo: clerezza X-Git-Refname: refs/heads/reunited X-Git-Reftype: branch X-Git-Oldrev: 59ff83d17ca453a64ae0fee133fc0280d813121d X-Git-Newrev: 54c21fe27e68798c77407ab06f17c04ac3ed190f X-Git-Rev: 54c21fe27e68798c77407ab06f17c04ac3ed190f X-Git-NotificationType: ref_changed_plus_diff X-Git-Multimail-Version: 1.5.dev Auto-Submitted: auto-generated 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 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 @@ + + + + + + clerezza + org.apache.clerezza + 8-SNAPSHOT + ../parent/pom.xml + + 4.0.0 + + api.utils + bundle + 8-SNAPSHOT + Clerezza - API Utilities + Utility classes to work with Clerezza API + + + junit + junit + test + + + org.apache.clerezza + api + 8-SNAPSHOT + + + org.apache.clerezza + api.impl + 8-SNAPSHOT + + + org.apache.clerezza + representation + 8-SNAPSHOT + + + org.apache.clerezza + dataset + 8-SNAPSHOT + + + org.apache.clerezza + ontologies + 8-SNAPSHOT + + + org.apache.clerezza + test.utils + 8-SNAPSHOT + test + + + + \ 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 dontExpand = new HashSet(); + 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 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 BlankNodeOrIRI + * + * @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 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 dontExpand, Acceptor acceptor) { + Graph result = new SimpleGraph(); + if (node instanceof BlankNodeOrIRI) { + Iterator 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 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 Iterator getTypeSelectedObjects(IRI property, final Class type) { + final Iterator objects = getObjects(property); + return new Iterator() { + + 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 getLiterals(IRI property) { + final Iterator objects = getObjects(property); + return new Iterator() { + + 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 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 getObjects(IRI property) { + if (resource instanceof BlankNodeOrIRI) { + final Iterator triples = graph.filter((BlankNodeOrIRI) resource, property, null); + return new Iterator() { + + @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() { + + @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 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 getSubjects(IRI property) { + final Iterator triples = graph.filter(null, property, resource); + return new Iterator() { + + @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 getIRIObjects(IRI property) { + return getTypeSelectedObjects(property, IRI.class); + + } + + /** + * Get all available properties as an {@link Iterator}<{@link IRI}>. + * You can use getObjects(IRI property) to get the values of + * each property + * + * @return an iterator over properties of this node + */ + public Iterator getProperties() { + if (resource instanceof BlankNodeOrIRI) { + final Iterator triples = graph.filter((BlankNodeOrIRI) resource, null, null); + return getUniquePredicates(triples); + } else { + return new Iterator() { + + @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 getSubject(IRI property) to get the values of + * each inverse property + * + * @return an iterator over properties pointing to this node + */ + public Iterator getInverseProperties() { + final Iterator 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 getUniquePredicates(final Iterator triples) { + final Set resultSet = new HashSet(); + 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 subject will be related via the property relation 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 RdfList for the node and + * Graph represented by this object. + * + * @return a List to easy access the rdf:List represented by this node + */ + public List 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 tripleIter = graph.filter((BlankNodeOrIRI) resource, predicate, null); + Collection toDelete = new ArrayList(); + 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 BlankNodeOrIRI. + * 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 BlankNodeOrIRI. + * Over the boolean checkPredicate 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 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 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 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 GraphNodes. + * + * @param property + * @return + */ + public Iterator getObjectNodes(IRI property) { + final Iterator objects = this.getObjects(property); + return new Iterator() { + + @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 GraphNodes. + * + * @param property + * @return + */ + public Iterator getSubjectNodes(IRI property) { + final Iterator subjects = this.getSubjects(property); + return new Iterator() { + + @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 Graphs + * + * @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 subGraph + * each triple it appears in is also present in mGraph. Two + * bnodes are considered equals if their contexts (as returned by + * GraphNode.getNodeContext 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 removingTriples = new HashSet(); + //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 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 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 + * http://www.w3.org/TR/rdf-concepts/#dfn-URI-reference 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 java.util.List backed by an RDF + * collection (rdf:List). The list allows modification that are reflected + * to the underlying Graph. It reads the data from the + * Graph 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 Graphs) is + * not problematic. + * + * @author rbn, mir + */ +public class RdfList extends AbstractList { + + 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 listList = new ArrayList(); + private List valueList = new ArrayList(); + 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 + * listRDFTerm 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() { + @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 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 GraphNode is + * an element of. Sublists of other lists are not returned. + * + * @param element + * @return + */ + public static Set findContainingLists(GraphNode element) { + Set listNodes = findContainingListNodes(element); + if (listNodes.isEmpty()) { + return null; + } + + Set rdfLists = new HashSet(); + for (Iterator it = listNodes.iterator(); it.hasNext();) { + GraphNode listNode = it.next(); + rdfLists.add(new RdfList(listNode)); + } + return rdfLists; + } + + /** + * Returns a set of GraphNodeS which are the first list nodes (meaning + * they are not the beginning of a sublist) of the list containing the specified + * GraphNode as an element. + * + * @param element + * @return + */ + public static Set findContainingListNodes(GraphNode element) { + Iterator partOfaListNodesIter = element.getSubjectNodes(RDF.first); + if (!partOfaListNodesIter.hasNext()) { + return null; + } + Set listNodes = new HashSet(); + + while (partOfaListNodesIter.hasNext()) { + listNodes.addAll(findAllListNodes(partOfaListNodesIter.next())); + } + return listNodes; + } + + private static Set findAllListNodes(GraphNode listPart) { + Iterator invRestNodesIter; + Set listNodes = new HashSet(); + 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 alreadyVisited = new HashSet(); + Set resultTripleCollections = new HashSet(); + 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 getSeeAlsoObjectUris(GraphNode node) { + Set result = new HashSet(); + Lock l = node.readLock(); + l.lock(); + try { + Iterator 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 expand(GraphNode node, Set alreadyVisited, int recursion) { + Set rdfSeeAlsoTargets = getSeeAlsoObjectUris(node); + Set result = new HashSet(); + 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 performFilter(final BlankNodeOrIRI subject, + final IRI predicate, final RDFTerm object) { + if (baseTripleCollections.length == 0) { + return new HashSet(0).iterator(); + } + return new Iterator() { + + int currentBaseTC = 0; + Iterator 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 otherGraphs + = new HashSet(Arrays.asList(other.baseTripleCollections)); + Set 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 resultList = new ArrayList(); + 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 aquiredLocks = new HashSet(); + 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 aquiredLocks = new HashSet(); + 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 aquiredLocks = new HashSet(); + 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 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 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 filter(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) { + final Iterator 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 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[] 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 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{ + private final Iterator baseIter; + + private WrappedIteraror(Iterator 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 + org.apache.clerezza.platform.config.PlatformConfig#getBaseUris() + */ + 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> equivalenceSets, boolean addOwlSameAs) { + Map current2ReplacementMap = new HashMap(); + final Graph owlSameAsGraph = new SimpleGraph(); + for (Set equivalenceSet : equivalenceSets) { + final BlankNodeOrIRI replacement = getReplacementFor(equivalenceSet, owlSameAsGraph); + for (BlankNodeOrIRI current : equivalenceSet) { + if (!current.equals(replacement)) { + current2ReplacementMap.put(current, replacement); + } + } + } + final Set newTriples = new HashSet(); + Lock l = mGraph.getLock().writeLock(); + l.lock(); + try { + for (Iterator 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 equivalenceSet, + Graph owlSameAsGraph) { + final Set uriRefs = new HashSet(); + 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 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 uriRefs) { + final Iterator 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 ifps = getIfps(tBox); + final Map> ifp2nodesMap = new HashMap>(); + for (Iterator 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 equivalentNodes = ifp2nodesMap.get(po); + if (equivalentNodes == null) { + equivalentNodes = new HashSet(); + ifp2nodesMap.put(po, equivalentNodes); + } + equivalentNodes.add(triple.getSubject()); + } + Set> unitedEquivalenceSets = uniteSetsWithCommonElement(ifp2nodesMap.values()); + smush(mGraph, unitedEquivalenceSets, true); + } + + + private Set getIfps(Graph tBox) { + final Iterator ifpDefinitions = tBox.filter(null, RDF.type, + OWL.InverseFunctionalProperty); + final Set ifps = new HashSet(); + while (ifpDefinitions.hasNext()) { + final Triple triple = ifpDefinitions.next(); + ifps.add((IRI) triple.getSubject()); + } + return ifps; + } + + private Set> uniteSetsWithCommonElement( + Collection> originalSets) { + Set> result = new HashSet>(); + Iterator> iter = originalSets.iterator(); + while (iter.hasNext()) { + Set originalSet = iter.next(); + //TODO this could be done more efficiently with a map + Set matchingSet = getMatchinSet(originalSet, result); + if (matchingSet != null) { + matchingSet.addAll(originalSet); + } else { + result.add(new HashSet(originalSet)); + } + } + if (result.size() < originalSets.size()) { + return uniteSetsWithCommonElement(result); + } else { + return result; + } + } + + private Set getMatchinSet(Set set, Set> setOfSet) { + for (Set current : setOfSet) { + if (shareElements(set,current)) { + return current; + } + } + return null; + } + + private boolean shareElements(Set set1, Set 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> node2EquivalenceSet = new HashMap>(); + + 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 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 predicate."); + } + final BlankNodeOrIRI subject = triple.getSubject(); + //literals not yet supported + final BlankNodeOrIRI object = (BlankNodeOrIRI)triple.getObject(); + + Set 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(); + } + } else { + Set 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> unitedEquivalenceSets = new HashSet>(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 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 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 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 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 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 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 containingListNodes = RdfList.findContainingListNodes( + new GraphNode(element3, tc)); + Assert.assertEquals(1, containingListNodes.size()); + Assert.assertTrue(containingListNodes.contains(listA)); + + Set 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 litStmts = dataGraph.filter(null, null, lit); + Assert.assertTrue(litStmts.hasNext()); + Triple litStmt = litStmts.next(); + Assert.assertFalse(litStmts.hasNext()); + Iterator 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 properties = node.getProperties(); + while (properties.hasNext()) { + IRI property = properties.next(); + Set objects = createSet(node.getObjects(property)); + Iterator 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 properties = node.getProperties(); + while (properties.hasNext()) { + IRI property = properties.next(); + Set subjects = createSet(node.getSubjects(property)); + Iterator 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 props = new ArrayList(); + 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 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 createSet(Iterator resources) { + Set set = new HashSet(); + 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 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 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 litStmts = dataGraph.filter(null, null, lit); + Assert.assertTrue(litStmts.hasNext()); + Triple litStmt = litStmts.next(); + Assert.assertFalse(litStmts.hasNext()); + Iterator 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); + } + +}