Author: asanso
Date: Mon Jul 27 07:17:54 2015
New Revision: 1692825

URL: http://svn.apache.org/r1692825
Log:
SLING-4903 - ConcurrentModificationException in MapEntries

Modified:
    
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntries.java
    
sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/mapping/MapEntriesTest.java

Modified: 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntries.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntries.java?rev=1692825&r1=1692824&r2=1692825&view=diff
==============================================================================
--- 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntries.java
 (original)
+++ 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntries.java
 Mon Jul 27 07:17:54 2015
@@ -1020,17 +1020,25 @@ public class MapEntries implements Event
      * Add an entry to the resolve map.
      */
     private boolean addEntry(final Map<String, List<MapEntry>> entryMap, final 
String key, final MapEntry entry) {
+        
         if (entry==null){
             return false;
         }
+        
         List<MapEntry> entries = entryMap.get(key);
         if (entries == null) {
             entries = new ArrayList<MapEntry>();
+            entries.add(entry);
+            // and finally sort list
+            Collections.sort(entries);
             entryMap.put(key, entries);
+        } else {
+            List<MapEntry> entriesCopy =new ArrayList<MapEntry>(entries);
+            entriesCopy.add(entry);
+            // and finally sort list
+            Collections.sort( entriesCopy);
+            entryMap.put(key, entriesCopy);
         }
-        entries.add(entry);
-        // and finally sort list
-        Collections.sort(entries);
         return true;
     }
 

Modified: 
sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/mapping/MapEntriesTest.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/mapping/MapEntriesTest.java?rev=1692825&r1=1692824&r2=1692825&view=diff
==============================================================================
--- 
sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/mapping/MapEntriesTest.java
 (original)
+++ 
sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/mapping/MapEntriesTest.java
 Mon Jul 27 07:17:54 2015
@@ -40,7 +40,12 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
 import java.util.concurrent.atomic.AtomicLong;
+
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.resource.ResourceUtil;
@@ -1801,4 +1806,66 @@ public class MapEntriesTest {
         assertEquals(2, counter.longValue());
     }
     
+    @Test
+    //SLING-4883
+    public void test_concutrrent_getResolveMapsIterator() throws Exception {
+        ExecutorService pool = Executors.newFixedThreadPool(10);
+        
+        final Resource justVanityPath = mock(Resource.class, "justVanityPath");
+        
when(resourceResolver.getResource("/justVanityPath")).thenReturn(justVanityPath);
+        when(justVanityPath.getPath()).thenReturn("/justVanityPath");          
       
+        when(justVanityPath.getName()).thenReturn("justVanityPath");
+        
when(justVanityPath.adaptTo(ValueMap.class)).thenReturn(buildValueMap("sling:vanityPath",
 "/target/justVanityPath"));
+        
+        
+        when(resourceResolver.findResources(anyString(), 
eq("sql"))).thenAnswer(new Answer<Iterator<Resource>>() {
+
+            public Iterator<Resource> answer(InvocationOnMock invocation) 
throws Throwable {
+                if 
(invocation.getArguments()[0].toString().contains("sling:vanityPath")) {
+                    return Collections.singleton(justVanityPath).iterator();
+                } else {
+                    return Collections.<Resource> emptySet().iterator();
+                }
+            }
+        });
+        
+        
+        Field field1 = 
MapEntries.class.getDeclaredField("maxCachedVanityPathEntries");
+        field1.setAccessible(true);  
+        field1.set(mapEntries, 2);
+        
+        ArrayList<DataFuture> list = new ArrayList<DataFuture>();
+        for (int i =0;i<10;i++) {
+            list.add(createDataFuture(pool, mapEntries));
+ 
+        }
+ 
+       for (DataFuture df : list) {
+           df.future.get();           
+        }
+  
+    }
+    
+    // -------------------------- private methods ----------
+    private DataFuture createDataFuture(ExecutorService pool, final MapEntries 
mapEntries) {
+
+        Future<Iterator> future = pool.submit(new Callable<Iterator>() {
+            @Override
+            public Iterator call() throws Exception {
+                return 
mapEntries.getResolveMapsIterator("http/localhost.8080/target/justVanityPath"); 
                    
+            }
+        });
+        return new DataFuture(future);
+    }    
+    
+    // -------------------------- inner classes ------------
+
+    private static class DataFuture {
+        public Future<Iterator> future;
+
+        public DataFuture(Future<Iterator> future) {
+            super();
+            this.future = future;
+        }
+    }    
 }


Reply via email to