You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by cz...@apache.org on 2014/01/03 16:22:50 UTC

svn commit: r1555126 - in /sling/trunk/bundles/api/src: main/java/org/apache/sling/api/resource/ResourceMetadata.java test/java/org/apache/sling/api/resource/ResourceMetadataTest.java

Author: cziegeler
Date: Fri Jan  3 15:22:50 2014
New Revision: 1555126

URL: http://svn.apache.org/r1555126
Log:
SLING-2786 : ResourceMetadata contains stale unmodifiableMap cache after clone()

Modified:
    sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/ResourceMetadata.java
    sling/trunk/bundles/api/src/test/java/org/apache/sling/api/resource/ResourceMetadataTest.java

Modified: sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/ResourceMetadata.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/ResourceMetadata.java?rev=1555126&r1=1555125&r2=1555126&view=diff
==============================================================================
--- sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/ResourceMetadata.java (original)
+++ sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/ResourceMetadata.java Fri Jan  3 15:22:50 2014
@@ -334,11 +334,20 @@ public class ResourceMetadata extends Ha
         this.checkReadOnly();
         return super.remove(key);
     }
+    
+    @Override
+    public Object clone() {
+        ResourceMetadata result = (ResourceMetadata) super.clone();
+        result.lockedEntrySet = null;
+        result.lockedKeySet = null;
+        result.lockedValues = null;
+        return result;
+    }
 
-    // volatile for correct double-checked locking in getLockedData()
-    private volatile Set<Map.Entry<String, Object>> lockedEntrySet;
-    private Set<String> lockedKeySet;
-    private Collection<Object> lockedValues;
+	// volatile for correct double-checked locking in getLockedData()
+    private transient volatile Set<Map.Entry<String, Object>> lockedEntrySet;
+    private transient Set<String> lockedKeySet;
+    private transient Collection<Object> lockedValues;
 
     private void getLockedData() {
         if(isReadOnly && lockedEntrySet == null) {

Modified: sling/trunk/bundles/api/src/test/java/org/apache/sling/api/resource/ResourceMetadataTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/api/src/test/java/org/apache/sling/api/resource/ResourceMetadataTest.java?rev=1555126&r1=1555125&r2=1555126&view=diff
==============================================================================
--- sling/trunk/bundles/api/src/test/java/org/apache/sling/api/resource/ResourceMetadataTest.java (original)
+++ sling/trunk/bundles/api/src/test/java/org/apache/sling/api/resource/ResourceMetadataTest.java Fri Jan  3 15:22:50 2014
@@ -18,21 +18,28 @@
  */
 package org.apache.sling.api.resource;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.fail;
 
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
 
 import org.junit.Test;
 
 public class ResourceMetadataTest {
-    
+
     private static final Map<String, Object> TEST_MAP = new HashMap<String, Object>();
     static {
         TEST_MAP.put("first", "one");
         TEST_MAP.put("second", Integer.MAX_VALUE);
     }
-    
+
     @Test
     public void testLockedPut() {
         final ResourceMetadata m = new ResourceMetadata();
@@ -44,7 +51,7 @@ public class ResourceMetadataTest {
             // all good
         }
     }
-    
+
     @Test
     public void testLockedClear() {
         final ResourceMetadata m = new ResourceMetadata();
@@ -56,7 +63,7 @@ public class ResourceMetadataTest {
             // all good
         }
     }
-    
+
     @Test
     public void testLockedPutAll() {
         final ResourceMetadata m = new ResourceMetadata();
@@ -68,7 +75,7 @@ public class ResourceMetadataTest {
             // all good
         }
     }
-    
+
     @Test
     public void testLockedRemove() {
         final ResourceMetadata m = new ResourceMetadata();
@@ -80,25 +87,76 @@ public class ResourceMetadataTest {
             // all good
         }
     }
-    
+
     @Test
     public void testLockedEntrySet() {
         final ResourceMetadata m = new ResourceMetadata();
         m.lock();
         m.entrySet().toString();
     }
-    
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testLockedEntrySetRemove() {
+        final ResourceMetadata m = new ResourceMetadata();
+        m.put("key", "value");
+        m.lock();
+        Set<Entry<String, Object>> values = m.entrySet();
+        Iterator<Entry<String, Object>> it = values.iterator();
+        it.next();
+        it.remove();
+    }
+
     @Test
     public void testLockedKeySet() {
         final ResourceMetadata m = new ResourceMetadata();
         m.lock();
         m.keySet().toString();
     }
-    
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testLockedKeySetRemove() {
+        final ResourceMetadata m = new ResourceMetadata();
+        m.put("key", "value");
+        m.lock();
+        Set<String> keys = m.keySet();
+        keys.remove("key1");
+    }
+
     @Test
     public void testLockedValues() {
         final ResourceMetadata m = new ResourceMetadata();
         m.lock();
         m.values().toString();
     }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testLockedValuesRemove() {
+        final ResourceMetadata m = new ResourceMetadata();
+        m.put("key", "value");
+        m.lock();
+        Collection<Object> values = m.values();
+        values.remove("value");
+    }
+
+    @Test
+    public void testLockedClone() {
+        final ResourceMetadata m1 = new ResourceMetadata();
+        m1.put("key", "value");
+        m1.lock();
+
+        // Force caching of the internal views
+        m1.keySet();
+        final ResourceMetadata m2 = (ResourceMetadata) m1.clone();
+
+        assertNotSame(m1, m2);
+        assertEquals(m1, m2);
+        assertNotSame(m1.keySet(), m2.keySet());
+        assertEquals(m1.keySet(), m2.keySet());
+        assertNotSame(m1.entrySet(), m2.entrySet());
+        assertEquals(m1.entrySet(), m2.entrySet());
+        assertNotSame(m1.values(), m2.values());
+
+        // Collections.UnmodifiableCollection doesn't implement equals()
+        assertEquals(new ArrayList<Object>(m1.values()), new ArrayList<Object>(m2.values()));
+    }
 }