Author: mir
Date: Tue Jul  6 16:46:12 2010
New Revision: 960941

URL: http://svn.apache.org/viewvc?rev=960941&view=rev
Log:
CLEREZZA-245: Added read/write locks to hierarchy service. 
SimpleTripleCollection is now configurable to throw 
ConcurrentModificationExceptions (for testing). Implemented 
LockableMGraphWrapperForTesting in rdf.core.test.

Added:
    
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.rdf.core.test/src/main/java/org/apache/clerezza/rdf/core/test/LockChecker.java
    
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.rdf.core.test/src/main/java/org/apache/clerezza/rdf/core/test/LockableMGraphWrapperForTesting.java
    
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.rdf.core.test/src/main/java/org/apache/clerezza/rdf/core/test/LockingIteratorForTesting.java
Modified:
    
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content/pom.xml
    
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content/src/main/java/org/apache/clerezza/platform/content/hierarchy/CollectionNode.java
    
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content/src/main/java/org/apache/clerezza/platform/content/hierarchy/HierarchyNode.java
    
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content/src/main/java/org/apache/clerezza/platform/content/hierarchy/HierarchyService.java
    
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content/src/test/java/org/apache/clerezza/platform/content/hierarchy/HierarchyTest.java
    
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.rdf.core/src/main/java/org/apache/clerezza/rdf/core/impl/SimpleTripleCollection.java
    
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.rdf.core/src/test/java/org/apache/clerezza/rdf/core/impl/SimpleTripleCollectionTest.java

Modified: 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content/pom.xml
URL: 
http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content/pom.xml?rev=960941&r1=960940&r2=960941&view=diff
==============================================================================
--- 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content/pom.xml
 (original)
+++ 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content/pom.xml
 Tue Jul  6 16:46:12 2010
@@ -94,6 +94,11 @@
                        
<artifactId>org.apache.clerezza.rdf.metadata</artifactId>
                </dependency>
                <dependency>
+                       <groupId>org.apache.clerezza</groupId>
+                       
<artifactId>org.apache.clerezza.rdf.core.test</artifactId>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
                        <groupId>junit</groupId>
                        <artifactId>junit</artifactId>
                        <scope>test</scope>

Modified: 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content/src/main/java/org/apache/clerezza/platform/content/hierarchy/CollectionNode.java
URL: 
http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content/src/main/java/org/apache/clerezza/platform/content/hierarchy/CollectionNode.java?rev=960941&r1=960940&r2=960941&view=diff
==============================================================================
--- 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content/src/main/java/org/apache/clerezza/platform/content/hierarchy/CollectionNode.java
 (original)
+++ 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content/src/main/java/org/apache/clerezza/platform/content/hierarchy/CollectionNode.java
 Tue Jul  6 16:46:12 2010
@@ -22,6 +22,7 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import java.util.concurrent.locks.Lock;
 import org.apache.clerezza.rdf.core.BNode;
 import org.apache.clerezza.rdf.core.NonLiteral;
 import org.apache.clerezza.rdf.core.Resource;
@@ -48,7 +49,12 @@ public class CollectionNode extends Hier
        }
 
        boolean isValid() {
-               return this.hasProperty(RDF.type, HIERARCHY.Collection);
+               readLock().lock();
+               try {
+                       return this.hasProperty(RDF.type, HIERARCHY.Collection);
+               } finally {
+                       readLock().unlock();
+               }
        }
 
        /**
@@ -78,19 +84,24 @@ public class CollectionNode extends Hier
         * @return
         */
        public List<HierarchyNode> getMembers() {
+               List<HierarchyNode> nodes;
                List<Resource> membersListRdf = getMembersRdf();
-               List<HierarchyNode> nodes =
-                               new 
ArrayList<HierarchyNode>(membersListRdf.size());
-               Iterator<Resource> membersIter = membersListRdf.iterator();
-               while (membersIter.hasNext()) {
-                       UriRef uri = (UriRef) membersIter.next();
-                       try {
-                               
nodes.add(hierarchyService.getHierarchyNode(uri));
-                       } catch (NodeDoesNotExistException ex) {
-                               throw new RuntimeException(ex);
-                       } catch (UnknownRootExcetpion ex) {
-                               throw new RuntimeException(ex);
+               readLock().lock();
+               try {
+                       nodes = new 
ArrayList<HierarchyNode>(membersListRdf.size());
+                       Iterator<Resource> membersIter = 
membersListRdf.iterator();
+                       while (membersIter.hasNext()) {
+                               UriRef uri = (UriRef) membersIter.next();
+                               try {
+                                       
nodes.add(hierarchyService.getHierarchyNode(uri));
+                               } catch (NodeDoesNotExistException ex) {
+                                       throw new RuntimeException(ex);
+                               } catch (UnknownRootExcetpion ex) {
+                                       throw new RuntimeException(ex);
+                               }
                        }
+               } finally {
+                       readLock().unlock();
                }
                return Collections.unmodifiableList(nodes);
        }
@@ -100,15 +111,30 @@ public class CollectionNode extends Hier
         * @return
         */
        List<Resource> getMembersRdf() {
-               Iterator<Resource> members = this.getObjects(HIERARCHY.members);
-               RdfList membersList;
-               if (members.hasNext()) {
-                       membersList = new RdfList((BNode)members.next(), 
getGraph());
-               } else {
+               RdfList membersList = null;
+               Lock readLock = readLock();
+               readLock.lock();
+               try {
+                       Iterator<Resource> members = 
this.getObjects(HIERARCHY.members);
+                       if (members.hasNext()) {
+                               membersList = new RdfList((BNode) 
members.next(), getGraph());
+                       }
+               } finally {
+                       readLock.unlock();
+               }
+               if (membersList == null) {
                        BNode newMembers = new BNode();
-                       this.addProperty(HIERARCHY.members, newMembers);
-                       membersList = new RdfList(newMembers, getGraph());
+                       Lock writLock = writeLock();
+                       writLock.lock();
+                       try {
+                               this.addProperty(HIERARCHY.members, newMembers);
+                               membersList = new RdfList(newMembers, 
getGraph());                              
+                       } finally {
+                               writLock.unlock();
+                       }
+                       
                }
+
                return membersList;
        }
 
@@ -163,16 +189,22 @@ public class CollectionNode extends Hier
 
        @Override
        public void delete() {
-               List<HierarchyNode> members = getMembers();
-               Iterator<HierarchyNode> membersIter = members.iterator();
-               while (membersIter.hasNext()) {
-                       HierarchyNode hierarchyNode = membersIter.next();
-                       hierarchyNode.delete();
-               }
-               deleteCollection();
-               super.delete();
-               if (hierarchyService.getRoots().contains(this)) {
-                       hierarchyService.removeRoot(this);
+               Lock writeLock = writeLock();
+               writeLock.lock();
+               try {
+                       List<HierarchyNode> members = getMembers();
+                       Iterator<HierarchyNode> membersIter = 
members.iterator();
+                       while (membersIter.hasNext()) {
+                               HierarchyNode hierarchyNode = 
membersIter.next();
+                               hierarchyNode.delete();
+                       }
+                       deleteCollection();
+                       super.delete();
+                       if (hierarchyService.getRoots().contains(this)) {
+                               hierarchyService.removeRoot(this);
+                       }
+               } finally {
+                       writeLock.unlock();
                }
        }
 

Modified: 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content/src/main/java/org/apache/clerezza/platform/content/hierarchy/HierarchyNode.java
URL: 
http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content/src/main/java/org/apache/clerezza/platform/content/hierarchy/HierarchyNode.java?rev=960941&r1=960940&r2=960941&view=diff
==============================================================================
--- 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content/src/main/java/org/apache/clerezza/platform/content/hierarchy/HierarchyNode.java
 (original)
+++ 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content/src/main/java/org/apache/clerezza/platform/content/hierarchy/HierarchyNode.java
 Tue Jul  6 16:46:12 2010
@@ -19,6 +19,7 @@
 package org.apache.clerezza.platform.content.hierarchy;
 
 import java.util.List;
+import java.util.concurrent.locks.Lock;
 import org.apache.clerezza.rdf.core.NonLiteral;
 import org.apache.clerezza.rdf.core.Resource;
 import org.apache.clerezza.rdf.core.TripleCollection;
@@ -120,23 +121,31 @@ public class HierarchyNode extends Graph
                } catch (UriException ex) {
                        throw new RuntimeException(ex);
                }
-               if (newParent.equals(getParent())) {
-                       UriRef nodeUri = getNode();
-                       List<Resource> membersRdfList = 
newParent.getMembersRdf();
-                       int oldPos = membersRdfList.indexOf(nodeUri);           
        
-                       if (oldPos < pos) {
-                               pos -= 1;
-                       }                       
-                       if (name.equals(getName())) {                           
-                               if (oldPos != pos) {
-                                       membersRdfList.remove(nodeUri);
-                                       membersRdfList.add(pos, nodeUri);
-                               }                               
-                               return this;
+
+               Lock writeLock = writeLock();
+               writeLock.lock();
+               try {
+                       if (newParent.equals(getParent())) {
+                               UriRef nodeUri = getNode();
+                               List<Resource> membersRdfList = 
newParent.getMembersRdf();
+                               int oldPos = membersRdfList.indexOf(nodeUri);
+                               if (oldPos < pos) {
+                                       pos -= 1;
+                               }
+                               if (name.equals(getName())) {
+                                       if (oldPos != pos) {
+                                               membersRdfList.remove(nodeUri);
+                                               membersRdfList.add(pos, 
nodeUri);
+                                       }
+                                       return this;
+                               }
                        }
-               }               
-               String newUriString = newParent.getNode().getUnicodeString() +
-                               name;
+               } finally {
+                       writeLock.unlock();
+               }
+               String newUriString = newParent.getNode().getUnicodeString()
+                               + name;
+
                String alternativeUriString = newUriString;
                if (this instanceof CollectionNode) {
                        newUriString += "/";
@@ -146,28 +155,39 @@ public class HierarchyNode extends Graph
                UriRef newUri = new UriRef(newUriString);
                UriRef alternativeUri = new UriRef(alternativeUriString);
                List<Resource> parentMembers = newParent.getMembersRdf();
-               if (parentMembers.contains(newUri) || 
parentMembers.contains(alternativeUri)) {
-                       HierarchyNode existingNode = null;
-                       try {
+               Lock newParentReadLock = newParent.readLock();
+               newParentReadLock.lock();
+               try {
+                       if (parentMembers.contains(newUri) || 
parentMembers.contains(alternativeUri)) {
+                               HierarchyNode existingNode = null;
                                try {
-                                       existingNode = 
hierarchyService.getHierarchyNode(newUri);
-                               } catch (NodeDoesNotExistException ex) {
                                        try {
-                                               existingNode = 
hierarchyService.getHierarchyNode(alternativeUri);
-                                       } catch (NodeDoesNotExistException e) {
-                                               throw new RuntimeException(ex);
+                                               existingNode = 
hierarchyService.getHierarchyNode(newUri);
+                                       } catch (NodeDoesNotExistException ex) {
+                                               try {
+                                                       existingNode = 
hierarchyService.getHierarchyNode(alternativeUri);
+                                               } catch 
(NodeDoesNotExistException e) {
+                                                       throw new 
RuntimeException(ex);
+                                               }
                                        }
+                               } catch (UnknownRootExcetpion ex) {
+                                       throw new RuntimeException(ex);
                                }
-                       } catch (UnknownRootExcetpion ex) {
-                               throw new RuntimeException(ex);
+                               throw new 
NodeAlreadyExistsException(existingNode);
                        }
-                       throw new NodeAlreadyExistsException(existingNode);
+               } finally {
+                       newParentReadLock.unlock();
                }
-               deleteFromParent();
+               writeLock().lock();
+               try {
+                       deleteFromParent();
 
-               HierarchyNode movedNode = replaceWith(newUri);
-               newParent.addMember(movedNode, pos);
-               return movedNode;
+                       HierarchyNode movedNode = replaceWith(newUri);
+                       newParent.addMember(movedNode, pos);
+                       return movedNode;
+               } finally {
+                       writeLock().unlock();
+               }
        }
 
        /**

Modified: 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content/src/main/java/org/apache/clerezza/platform/content/hierarchy/HierarchyService.java
URL: 
http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content/src/main/java/org/apache/clerezza/platform/content/hierarchy/HierarchyService.java?rev=960941&r1=960940&r2=960941&view=diff
==============================================================================
--- 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content/src/main/java/org/apache/clerezza/platform/content/hierarchy/HierarchyService.java
 (original)
+++ 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content/src/main/java/org/apache/clerezza/platform/content/hierarchy/HierarchyService.java
 Tue Jul  6 16:46:12 2010
@@ -116,8 +116,14 @@ public class HierarchyService {
                                        throw ex;
                                }
                        }
-                       if (!parent.getMembersRdf().contains(nodeUri)) {
-                               throw new NodeDoesNotExistException(nodeUri);
+                       Lock parentReadLock = parent.readLock();
+                       parentReadLock.lock();
+                       try {
+                               if (!parent.getMembersRdf().contains(nodeUri)) {
+                                       throw new 
NodeDoesNotExistException(nodeUri);
+                               }
+                       } finally {
+                               parentReadLock.unlock();
                        }
                }
        }
@@ -169,8 +175,14 @@ public class HierarchyService {
                handleRootOfUri(uri);
                HierarchyNode hierarchyNode;
                hierarchyNode = new HierarchyNode(uri, 
cgProvider.getContentGraph(), this);
-               addToParent(hierarchyNode, posInParent);
-               addCreationProperties(hierarchyNode);
+               Lock writeLocke = hierarchyNode.writeLock();
+               writeLocke.lock();
+               try {
+                       addToParent(hierarchyNode, posInParent);
+                       addCreationProperties(hierarchyNode);
+               } finally {
+                       writeLocke.lock();
+               }
                return hierarchyNode;
        }
 
@@ -324,9 +336,15 @@ public class HierarchyService {
                handleRootOfUri(uri);
                CollectionNode collectionNode;
                collectionNode = new CollectionNode(uri, 
cgProvider.getContentGraph(), this);
-               addCollectionTypeTriple(collectionNode);
-               addToParent(collectionNode, posInParent);
-               addCreationProperties(collectionNode);
+               Lock writeLocke = collectionNode.writeLock();
+               writeLocke.lock();
+               try {
+                       addCollectionTypeTriple(collectionNode);
+                       addToParent(collectionNode, posInParent);
+                       addCreationProperties(collectionNode);
+               } finally {
+                       writeLocke.unlock();
+               }
                return collectionNode;
        }
 
@@ -415,8 +433,14 @@ public class HierarchyService {
 
        private void addRoot(UriRef baseUri) {
                CollectionNode node = new CollectionNode(baseUri, 
cgProvider.getContentGraph(), this);
-               addCollectionTypeTriple(node);
-               roots.add(node);
+               Lock writeLock = node.writeLock();
+               writeLock.lock();
+               try {
+                       addCollectionTypeTriple(node);
+                       roots.add(node);
+               } finally {
+                       writeLock.unlock();
+               }               
        }
 
        protected void deactivate(ComponentContext componentContext) {

Modified: 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content/src/test/java/org/apache/clerezza/platform/content/hierarchy/HierarchyTest.java
URL: 
http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content/src/test/java/org/apache/clerezza/platform/content/hierarchy/HierarchyTest.java?rev=960941&r1=960940&r2=960941&view=diff
==============================================================================
--- 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content/src/test/java/org/apache/clerezza/platform/content/hierarchy/HierarchyTest.java
 (original)
+++ 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content/src/test/java/org/apache/clerezza/platform/content/hierarchy/HierarchyTest.java
 Tue Jul  6 16:46:12 2010
@@ -22,6 +22,7 @@ import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.locks.Lock;
 import org.apache.clerezza.rdf.utils.GraphNode;
 import org.junit.Assert;
 import org.junit.Test;
@@ -31,10 +32,12 @@ import org.apache.clerezza.rdf.core.BNod
 import org.apache.clerezza.rdf.core.MGraph;
 import org.apache.clerezza.rdf.core.Triple;
 import org.apache.clerezza.rdf.core.UriRef;
+import org.apache.clerezza.rdf.core.access.LockableMGraph;
 import org.apache.clerezza.rdf.core.access.LockableMGraphWrapper;
 import org.apache.clerezza.rdf.core.impl.PlainLiteralImpl;
 import org.apache.clerezza.rdf.core.impl.SimpleMGraph;
 import org.apache.clerezza.rdf.core.impl.TripleImpl;
+import org.apache.clerezza.rdf.core.test.LockableMGraphWrapperForTesting;
 import org.apache.clerezza.rdf.ontologies.HIERARCHY;
 import org.apache.clerezza.rdf.ontologies.PLATFORM;
 import org.apache.clerezza.rdf.ontologies.RDF;
@@ -62,8 +65,8 @@ public class HierarchyTest{
        private UriRef newRoot = new UriRef("http://newRoot/";);
        private UriRef newRootTest = new UriRef("http://newRoot/test/";);
        private UriRef newRoot2Resource = new 
UriRef("http://newRoot2/resource";);
-       private UriRef newRoot2 = new UriRef("http://newRoot2/";); 
-
+       private UriRef newRoot2 = new UriRef("http://newRoot2/";);
+               
        @Test
        public void listPositionTest() throws Exception{
                HierarchyService hierarchyService = getHierarchyService();
@@ -288,8 +291,12 @@ public class HierarchyTest{
                Assert.assertTrue(exceptionThrown);
        }
        
-       private static class MyContentGraphProvider extends 
ContentGraphProvider {
-               private MGraph graph = new SimpleMGraph();
+       private class MyContentGraphProvider extends ContentGraphProvider {
+               SimpleMGraph contentGraph = new SimpleMGraph();
+               {
+                       contentGraph.setCheckConcurrency(true);
+               }
+               private MGraph graph = new 
LockableMGraphWrapperForTesting(contentGraph);
                @Override
                public MGraph getContentGraph() {
                        return graph;
@@ -321,7 +328,14 @@ public class HierarchyTest{
                hierarchyService.systemGraph = systemGraph;
                Triple rootTriple = new TripleImpl(root,
                        RDF.type, HIERARCHY.Collection);
-               myCgProvider.getContentGraph().add(rootTriple);
+               LockableMGraph lockableContentGraph = (LockableMGraph) 
myCgProvider.getContentGraph();
+               Lock writeLock = lockableContentGraph.getLock().writeLock();
+               writeLock.lock();
+               try {
+                       lockableContentGraph.add(rootTriple);
+               } finally {
+                       writeLock.unlock();
+               }
                hierarchyService.activate(null);
                return hierarchyService;
        }

Added: 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.rdf.core.test/src/main/java/org/apache/clerezza/rdf/core/test/LockChecker.java
URL: 
http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.rdf.core.test/src/main/java/org/apache/clerezza/rdf/core/test/LockChecker.java?rev=960941&view=auto
==============================================================================
--- 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.rdf.core.test/src/main/java/org/apache/clerezza/rdf/core/test/LockChecker.java
 (added)
+++ 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.rdf.core.test/src/main/java/org/apache/clerezza/rdf/core/test/LockChecker.java
 Tue Jul  6 16:46:12 2010
@@ -0,0 +1,39 @@
+/*
+ *  Copyright 2010 mir.
+ * 
+ *  Licensed 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.
+ *  under the License.
+ */
+
+package org.apache.clerezza.rdf.core.test;
+
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ *
+ * @author mir
+ */
+class LockChecker {
+
+       public static void checkIfReadLocked(ReentrantReadWriteLock lock) {
+               if (lock.getReadLockCount() == 0 && 
!lock.isWriteLockedByCurrentThread()) {
+                       throw new RuntimeException("Neither read- nor 
write-locked");
+               }
+       }
+
+       public static void checkIfWriteLocked(ReentrantReadWriteLock lock) {
+               if (!lock.isWriteLockedByCurrentThread()) {
+                       throw new RuntimeException("Not write-locked");
+               }
+       }
+}

Added: 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.rdf.core.test/src/main/java/org/apache/clerezza/rdf/core/test/LockableMGraphWrapperForTesting.java
URL: 
http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.rdf.core.test/src/main/java/org/apache/clerezza/rdf/core/test/LockableMGraphWrapperForTesting.java?rev=960941&view=auto
==============================================================================
--- 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.rdf.core.test/src/main/java/org/apache/clerezza/rdf/core/test/LockableMGraphWrapperForTesting.java
 (added)
+++ 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.rdf.core.test/src/main/java/org/apache/clerezza/rdf/core/test/LockableMGraphWrapperForTesting.java
 Tue Jul  6 16:46:12 2010
@@ -0,0 +1,245 @@
+/*
+ * 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.rdf.core.test;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import org.apache.clerezza.rdf.core.Graph;
+import org.apache.clerezza.rdf.core.MGraph;
+import org.apache.clerezza.rdf.core.NonLiteral;
+import org.apache.clerezza.rdf.core.Resource;
+import org.apache.clerezza.rdf.core.Triple;
+import org.apache.clerezza.rdf.core.UriRef;
+import org.apache.clerezza.rdf.core.access.LockableMGraph;
+import org.apache.clerezza.rdf.core.event.FilterTriple;
+import org.apache.clerezza.rdf.core.event.GraphListener;
+
+/**
+ * Wrappes an MGraph as a LockableMGraph. If a method is called that reads
+ * or modifies the wrapped graph and the appropriate lock is not set, then a
+ * RuntimeException is thrown.
+ *
+ * @author rbn, mir
+ */
+public class LockableMGraphWrapperForTesting implements LockableMGraph {
+
+       private final ReentrantReadWriteLock lock = new 
ReentrantReadWriteLock();
+       private final Lock readLock = lock.readLock();
+       private final Lock writeLock = lock.writeLock();
+       private final MGraph wrapped;
+
+       /**
+        * Constructs a LocalbleMGraph for an MGraph.
+        *
+        * @param providedMGraph a non-lockable mgraph
+        */
+       public LockableMGraphWrapperForTesting(final MGraph providedMGraph) {
+               this.wrapped = providedMGraph;
+       }
+
+       @Override
+       public ReadWriteLock getLock() {
+               return lock;
+       }
+
+       @Override
+       public Graph getGraph() {
+               LockChecker.checkIfReadLocked(lock);
+               readLock.lock();
+               try {
+                       return wrapped.getGraph();
+               } finally {
+                       readLock.unlock();
+               }
+       }
+
+       @Override
+       public Iterator<Triple> filter(NonLiteral subject, UriRef predicate, 
Resource object) {
+               LockChecker.checkIfReadLocked(lock);
+               readLock.lock();
+               try {
+                       return new 
LockingIteratorForTesting(wrapped.filter(subject, predicate, object), lock);
+               } finally {
+                       readLock.unlock();
+               }
+       }
+
+       @Override
+       public int size() {
+               LockChecker.checkIfReadLocked(lock);
+               readLock.lock();
+               try {
+                       return wrapped.size();
+               } finally {
+                       readLock.unlock();
+               }
+       }
+
+       @Override
+       public boolean isEmpty() {
+               LockChecker.checkIfReadLocked(lock);
+               readLock.lock();
+               try {
+                       return wrapped.isEmpty();
+               } finally {
+                       readLock.unlock();
+               }
+       }
+
+       @Override
+       @SuppressWarnings("element-type-mismatch")
+       public boolean contains(Object o) {
+               LockChecker.checkIfReadLocked(lock);
+               readLock.lock();
+               try {
+                       return wrapped.contains(o);
+               } finally {
+                       readLock.unlock();
+               }
+       }
+
+       @Override
+       public Iterator<Triple> iterator() {
+               LockChecker.checkIfReadLocked(lock);
+               readLock.lock();
+               try {
+                       return new 
LockingIteratorForTesting(wrapped.iterator(), lock);
+               } finally {
+                       readLock.unlock();
+               }
+       }
+
+       @Override
+       public Object[] toArray() {
+               LockChecker.checkIfReadLocked(lock);
+               readLock.lock();
+               try {
+                       return wrapped.toArray();
+               } finally {
+                       readLock.unlock();
+               }
+       }
+
+       @Override
+       public <T> T[] toArray(T[] a) {
+               LockChecker.checkIfReadLocked(lock);
+               readLock.lock();
+               try {
+                       return wrapped.toArray(a);
+               } finally {
+                       readLock.unlock();
+               }
+       }
+
+       @Override
+       public boolean containsAll(Collection<?> c) {
+               LockChecker.checkIfReadLocked(lock);
+               readLock.lock();
+               try {
+                       return wrapped.containsAll(c);
+               } finally {
+                       readLock.unlock();
+               }
+       }
+
+       @Override
+       public boolean add(Triple e) {
+               LockChecker.checkIfWriteLocked(lock);
+               writeLock.lock();
+               try {
+                       return wrapped.add(e);
+               } finally {
+                       writeLock.unlock();
+               }
+       }
+
+       @Override
+       public boolean remove(Object o) {
+               LockChecker.checkIfWriteLocked(lock);
+               writeLock.lock();
+               try {
+                       return wrapped.remove(o);
+               } finally {
+                       writeLock.unlock();
+               }
+       }
+
+       @Override
+       public boolean addAll(Collection<? extends Triple> c) {
+               LockChecker.checkIfWriteLocked(lock);
+               writeLock.lock();
+               try {
+                       return wrapped.addAll(c);
+               } finally {
+                       writeLock.unlock();
+               }
+       }
+
+       @Override
+       public boolean removeAll(Collection<?> c) {
+               LockChecker.checkIfWriteLocked(lock);
+               writeLock.lock();
+               try {
+                       return wrapped.removeAll(c);
+               } finally {
+                       writeLock.unlock();
+               }
+       }
+
+       @Override
+       public boolean retainAll(Collection<?> c) {
+               LockChecker.checkIfWriteLocked(lock);
+               writeLock.lock();
+               try {
+                       return wrapped.retainAll(c);
+               } finally {
+                       writeLock.unlock();
+               }
+       }
+
+       @Override
+       public void clear() {
+               LockChecker.checkIfWriteLocked(lock);
+               writeLock.lock();
+               try {
+                       wrapped.clear();
+               } finally {
+                       writeLock.unlock();
+               }
+       }
+
+       @Override
+       public void addGraphListener(GraphListener listener, FilterTriple 
filter, long delay) {
+               wrapped.addGraphListener(listener, filter, delay);
+       }
+
+       @Override
+       public void addGraphListener(GraphListener listener, FilterTriple 
filter) {
+               wrapped.addGraphListener(listener, filter);
+       }
+
+       @Override
+       public void removeGraphListener(GraphListener listener) {
+               wrapped.removeGraphListener(listener);
+       }
+
+}

Added: 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.rdf.core.test/src/main/java/org/apache/clerezza/rdf/core/test/LockingIteratorForTesting.java
URL: 
http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.rdf.core.test/src/main/java/org/apache/clerezza/rdf/core/test/LockingIteratorForTesting.java?rev=960941&view=auto
==============================================================================
--- 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.rdf.core.test/src/main/java/org/apache/clerezza/rdf/core/test/LockingIteratorForTesting.java
 (added)
+++ 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.rdf.core.test/src/main/java/org/apache/clerezza/rdf/core/test/LockingIteratorForTesting.java
 Tue Jul  6 16:46:12 2010
@@ -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.rdf.core.test;
+
+import java.util.Iterator;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import org.apache.clerezza.rdf.core.Triple;
+
+/**
+ * Wrapps an iterator<Triple> reading all elements to a cache on construction
+ * and returning them from that cache.
+ * @author reto
+ */
+class LockingIteratorForTesting implements Iterator<Triple> {
+
+       private Iterator<Triple> base;
+       private Lock readLock;
+       private Lock writeLock;
+       private ReentrantReadWriteLock lock;
+
+       public LockingIteratorForTesting(Iterator<Triple> iterator, 
ReentrantReadWriteLock lock) {
+               base = iterator;
+               readLock = lock.readLock();
+               writeLock = lock.writeLock();
+               this.lock = lock;
+       }
+
+       @Override
+       public boolean hasNext() {
+               LockChecker.checkIfReadLocked(lock);
+               readLock.lock();
+               try {
+                       return base.hasNext();
+               } finally {
+                       readLock.unlock();
+               }
+       }
+
+       @Override
+       public Triple next() {
+               LockChecker.checkIfReadLocked(lock);
+               readLock.lock();
+               try {
+                       return base.next();
+               } finally {
+                       readLock.unlock();
+               }
+       }
+
+       @Override
+       public void remove() {
+               LockChecker.checkIfWriteLocked(lock);
+               writeLock.lock();
+               try {
+                       base.remove();
+               } finally {
+                       writeLock.unlock();
+               }
+       }
+
+
+}

Modified: 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.rdf.core/src/main/java/org/apache/clerezza/rdf/core/impl/SimpleTripleCollection.java
URL: 
http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.rdf.core/src/main/java/org/apache/clerezza/rdf/core/impl/SimpleTripleCollection.java?rev=960941&r1=960940&r2=960941&view=diff
==============================================================================
--- 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.rdf.core/src/main/java/org/apache/clerezza/rdf/core/impl/SimpleTripleCollection.java
 (original)
+++ 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.rdf.core/src/main/java/org/apache/clerezza/rdf/core/impl/SimpleTripleCollection.java
 Tue Jul  6 16:46:12 2010
@@ -18,8 +18,11 @@
  */
 package org.apache.clerezza.rdf.core.impl;
 
+import java.lang.ref.SoftReference;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.ConcurrentModificationException;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -41,13 +44,62 @@ import org.apache.clerezza.rdf.core.UriR
  */
 class SimpleTripleCollection extends AbstractTripleCollection {
 
-       Set<Triple> triples;
+       final Set<Triple> triples;
 
+       private boolean checkConcurrency = false;
+
+       class SimpleIterator implements Iterator<Triple> {
+
+               private Iterator<Triple> listIter;
+               private boolean isValid = true;
+
+               public SimpleIterator(Iterator<Triple> listIter) {
+                       this.listIter = listIter;
+               }
+               private Triple currentNext;
+
+               @Override
+               public boolean hasNext() {
+                       checkValidity();
+                       return listIter.hasNext();
+               }
+
+               @Override
+               public Triple next() {
+                       checkValidity();
+                       currentNext = listIter.next();
+                       return currentNext;
+               }               
+
+               @Override
+               public void remove() {
+                       checkValidity();
+                       listIter.remove();
+                       triples.remove(currentNext);                    
+                       invalidateIterators(this);                      
+               }
+
+               private void checkValidity() throws 
ConcurrentModificationException {
+                       if (checkConcurrency && !isValid) {
+                               throw new ConcurrentModificationException();
+                       }
+               }
+
+               private void invalidate() {
+                       if (checkConcurrency) {
+                               isValid = false;
+                       }
+               }
+       }       
+       
+       private Set<SoftReference<SimpleIterator>> iterators = 
+                       Collections.synchronizedSet(new 
HashSet<SoftReference<SimpleIterator>>());
+       
        /**
         * Creates an empty SimpleTripleCollection
         */
        public SimpleTripleCollection() {
-               triples = new HashSet<Triple>();
+               triples = Collections.synchronizedSet(new HashSet<Triple>());
        }
 
        /**
@@ -91,53 +143,69 @@ class SimpleTripleCollection extends Abs
 
        @Override
        public Iterator<Triple> performFilter(final NonLiteral subject, final 
UriRef predicate, final Resource object) {
-               Iterator<Triple> baseIter = triples.iterator();
                final List<Triple> tripleList = new ArrayList<Triple>();
-               while (baseIter.hasNext()) {
-                       Triple triple = baseIter.next();
-                       if ((subject != null) &&
-                               (!triple.getSubject().equals(subject))) {
+               synchronized (triples) {
+                       Iterator<Triple> baseIter = triples.iterator();
+                       while (baseIter.hasNext()) {
+                               Triple triple = baseIter.next();
+                               if ((subject != null)
+                                               && 
(!triple.getSubject().equals(subject))) {
                                        continue;
                                }
-                               if ((predicate != null) &&
-                                               
(!triple.getPredicate().equals(predicate))) {
+                               if ((predicate != null)
+                                               && 
(!triple.getPredicate().equals(predicate))) {
                                        continue;
                                }
-                               if ((object != null) &&
-                                               
(!triple.getObject().equals(object))) {
+                               if ((object != null)
+                                               && 
(!triple.getObject().equals(object))) {
                                        continue;
                                }
-                       tripleList.add(triple);                 
-               }
-               
-               final Iterator<Triple> listIter = tripleList.iterator();
-               
-               return new Iterator<Triple>() {
-
-                       private Triple currentNext;
-                       
-                       @Override
-                       public boolean hasNext() {
-                               return listIter.hasNext();
+                               tripleList.add(triple);
                        }
 
-                       @Override
-                       public Triple next() {
-                               currentNext = listIter.next();
-                               return currentNext;
-                       }
-
-                       @Override
-                       public void remove() {
-                               listIter.remove();
-                               triples.remove(currentNext);
-                       }                       
-               };
+                       final Iterator<Triple> listIter = tripleList.iterator();
+                       SimpleIterator resultIter = new 
SimpleIterator(listIter);
+                       iterators.add(new 
SoftReference<SimpleIterator>(resultIter));
+                       return resultIter;
+               }
        }
 
 
        @Override
        public boolean performAdd(Triple e) {
-               return triples.add(e);
+               boolean modified = triples.add(e);
+               if (modified) {
+                       invalidateIterators(null);
+               }
+               return modified;
+       }
+       
+       private void invalidateIterators(SimpleIterator caller) {
+               if (!checkConcurrency) {
+                       return;
+               }
+               Set<SoftReference> oldReferences = new HashSet<SoftReference>();
+               for (SoftReference<SimpleTripleCollection.SimpleIterator> 
softReference : iterators) {
+                       SimpleIterator simpleIterator = softReference.get();
+                       if (simpleIterator == null) {
+                               oldReferences.add(softReference);
+                               continue;
+                       }
+                       if (simpleIterator != caller) {
+                               simpleIterator.invalidate();
+                       }                       
+               }
+               iterators.removeAll(oldReferences);
+       }
+
+       /**
+        * Specifies whether or not to throw 
<code>ConcurrentModificationException</code>s,
+        * if this simple triple collection is modified concurrently. 
Concurrency
+        * check is set to false by default.
+        *
+        * @param bool Specifies whether or not to check concurrent 
modifications.
+        */
+       public void setCheckConcurrency(boolean bool) {
+               checkConcurrency = bool;
        }
 }

Modified: 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.rdf.core/src/test/java/org/apache/clerezza/rdf/core/impl/SimpleTripleCollectionTest.java
URL: 
http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.rdf.core/src/test/java/org/apache/clerezza/rdf/core/impl/SimpleTripleCollectionTest.java?rev=960941&r1=960940&r2=960941&view=diff
==============================================================================
--- 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.rdf.core/src/test/java/org/apache/clerezza/rdf/core/impl/SimpleTripleCollectionTest.java
 (original)
+++ 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.rdf.core/src/test/java/org/apache/clerezza/rdf/core/impl/SimpleTripleCollectionTest.java
 Tue Jul  6 16:46:12 2010
@@ -18,6 +18,7 @@
  */
 package org.apache.clerezza.rdf.core.impl;
 
+import java.util.ConcurrentModificationException;
 import java.util.Iterator;
 import org.junit.Assert;
 import org.junit.Test;
@@ -85,5 +86,22 @@ public class SimpleTripleCollectionTest 
                        iter.remove();
                }
                Assert.assertEquals(3, stc.size());
-       }       
+       }
+
+       @Test(expected=ConcurrentModificationException.class)
+       public void remove() {
+               SimpleTripleCollection stc = new SimpleTripleCollection();
+               stc.setCheckConcurrency(true);
+               stc.add(triple1);
+               stc.add(triple2);
+               stc.add(triple3);
+               stc.add(triple4);
+               stc.add(triple5);
+               Iterator<Triple> iter = stc.filter(uriRef1, null, null);
+               while (iter.hasNext()) {
+                       Triple triple = iter.next();
+                       stc.remove(triple);
+               }
+               Assert.assertEquals(3, stc.size());
+       }
 }


Reply via email to