You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@clerezza.apache.org by ha...@apache.org on 2019/02/12 06:06:11 UTC

[clerezza] branch reunited updated: CLEREZZA-1037: Move utils from rdf module to api.utils module

This is an automated email from the ASF dual-hosted git repository.

hasan pushed a commit to branch reunited
in repository https://gitbox.apache.org/repos/asf/clerezza.git


The following commit(s) were added to refs/heads/reunited by this push:
     new 54c21fe  CLEREZZA-1037: Move utils from rdf module to api.utils module
54c21fe is described below

commit 54c21fe27e68798c77407ab06f17c04ac3ed190f
Author: Hasan <ha...@apache.org>
AuthorDate: Tue Feb 12 07:05:28 2019 +0100

    CLEREZZA-1037: Move utils from rdf module to api.utils module
---
 api.utils/pom.xml                                  |  75 +++
 .../org/apache/clerezza/api/utils/GraphNode.java   | 720 +++++++++++++++++++++
 .../org/apache/clerezza/api/utils/GraphUtils.java  | 158 +++++
 .../org/apache/clerezza/api/utils/IRIUtil.java     |  62 ++
 .../org/apache/clerezza/api/utils/RdfList.java     | 350 ++++++++++
 .../apache/clerezza/api/utils/SeeAlsoExpander.java | 113 ++++
 .../org/apache/clerezza/api/utils/Smusher.java     |  61 ++
 .../org/apache/clerezza/api/utils/UnionGraph.java  | 279 ++++++++
 .../clerezza/api/utils/UnionWatchableGraph.java    |  57 ++
 .../clerezza/api/utils/UriMutatingGraph.java       | 217 +++++++
 .../utils/graphnodeprovider/GraphNodeProvider.java |  51 ++
 .../clerezza/api/utils/smushing/BaseSmusher.java   | 130 ++++
 .../clerezza/api/utils/smushing/IfpSmusher.java    | 165 +++++
 .../clerezza/api/utils/smushing/SameAsSmusher.java | 109 ++++
 .../apache/clerezza/api/utils/GraphUtilsTest.java  | 103 +++
 .../apache/clerezza/api/utils/IfpSmushTest.java    | 115 ++++
 .../org/apache/clerezza/api/utils/RdfListTest.java | 182 ++++++
 .../apache/clerezza/api/utils/SameAsSmushTest.java |  77 +++
 .../apache/clerezza/api/utils/TestGraphNode.java   | 266 ++++++++
 .../apache/clerezza/api/utils/UnionGraphTest.java  |  79 +++
 .../api/utils/smushing/SameAsSmushTest.java        |  91 +++
 21 files changed, 3460 insertions(+)

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