Repository: brooklyn-server
Updated Branches:
  refs/heads/master b8211ed17 -> 43a8816c8


XML SpecResolver: use context instead of thread-local


Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/3a2c4cb5
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/3a2c4cb5
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/3a2c4cb5

Branch: refs/heads/master
Commit: 3a2c4cb580ecf368740fe8c52b9aa37339f9cd0e
Parents: b8211ed
Author: Aled Sage <[email protected]>
Authored: Tue Mar 22 18:36:54 2016 +0000
Committer: Aled Sage <[email protected]>
Committed: Tue Mar 22 18:57:37 2016 +0000

----------------------------------------------------------------------
 .../internal/AbstractBrooklynObjectSpec.java    |  2 ++
 .../core/mgmt/persist/XmlMementoSerializer.java | 18 +++++-----
 .../mgmt/persist/XmlMementoSerializerTest.java  | 37 +++++++++++++++++++-
 3 files changed, 46 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/3a2c4cb5/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java
----------------------------------------------------------------------
diff --git 
a/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java
 
b/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java
index 3f95342..ef99a27 100644
--- 
a/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java
+++ 
b/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java
@@ -235,6 +235,8 @@ public abstract class AbstractBrooklynObjectSpec<T,SpecT 
extends AbstractBrookly
         if (!Objects.equal(getCatalogItemId(), other.getCatalogItemId())) 
return false;
         if (!Objects.equal(getType(), other.getType())) return false;
         if (!Objects.equal(getTags(), other.getTags())) return false;
+        if (!Objects.equal(getConfig(), other.getConfig())) return false;
+        if (!Objects.equal(getFlags(), other.getFlags())) return false;
         if (!Objects.equal(getParameters(), other.getParameters())) return 
false;
         return true;
     }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/3a2c4cb5/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java
 
b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java
index 0df2340..00693d9 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java
@@ -393,12 +393,6 @@ public class XmlMementoSerializer<T> extends 
XmlSerializer<T> implements Memento
         }
     }
 
-    // Would prefer this as a field of SpecConverter, but can't do that 
because the class is not static.
-    // Must use thread-local storage because a single instance of the 
SpecConverter is used by this 
-    // XmlMementoSerializer. In 
BrooklynMementoPersisterToObjectStore.visitMemento, it uses a thread-pool
-    // for concurrently deserializing multiple objects.
-    private static final ThreadLocal<Object> SpecConverterLocalInstance = new 
ThreadLocal<Object>();
-
     /** When reading/writing specs, it checks whether there is a catalog item 
id set and uses it to load */
     public class SpecConverter extends ReflectionConverter {
         SpecConverter() {
@@ -460,7 +454,7 @@ public class XmlMementoSerializer<T> extends 
XmlSerializer<T> implements Memento
                 result.catalogItemId(catalogItemId);
                 return result;
             } finally {
-                SpecConverterLocalInstance.remove();
+                context.put("SpecConverter.instance", null);
                 if (customLoaderSet) {
                     popXstreamCustomClassLoader();
                 }
@@ -470,15 +464,19 @@ public class XmlMementoSerializer<T> extends 
XmlSerializer<T> implements Memento
         @Override
         protected Object instantiateNewInstance(HierarchicalStreamReader 
reader, UnmarshallingContext context) {
             // the super calls getAttribute which requires that we have not 
yet done moveDown,
-            // so we do this earlier and cache it for when we call 
super.unmarshal
-            Object instance = SpecConverterLocalInstance.get();
+            // so we do this earlier and cache it for when we call 
super.unmarshal.
+            // Store this in the UnmarshallingContext. Note that we *must not* 
use a field of SpecConverter,
+            // because that same instance is used by everything calling 
XmlMementoSerializer (including multiple
+            // threads).
+            Object instance = context.get("SpecConverter.instance");
             if (instance==null)
                 throw new IllegalStateException("Instance should be created 
and cached");
             return instance;
         }
+        
         protected void 
instantiateNewInstanceSettingCache(HierarchicalStreamReader reader, 
UnmarshallingContext context) {
             Object instance = super.instantiateNewInstance(reader, context);
-            SpecConverterLocalInstance.set(instance);
+            context.put("SpecConverter.instance", instance);
         }
     }
     

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/3a2c4cb5/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializerTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializerTest.java
 
b/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializerTest.java
index 662e78d..aefd623 100644
--- 
a/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializerTest.java
+++ 
b/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializerTest.java
@@ -30,6 +30,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
 
 import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.entity.Entity;
@@ -70,7 +72,12 @@ import com.google.common.base.Objects;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
 
 public class XmlMementoSerializerTest {
 
@@ -300,6 +307,34 @@ public class XmlMementoSerializerTest {
     }
     
     @Test
+    public void testEntitySpecNested() throws Exception {
+        EntitySpec<?> obj = EntitySpec.create(TestEntity.class)
+                .configure("nest1", EntitySpec.create(TestEntity.class)
+                        .configure("nest2", 
EntitySpec.create(TestEntity.class)));
+        assertSerializeAndDeserialize(obj);
+    }
+    
+    @Test
+    public void testEntitySpecManyConcurrently() throws Exception {
+        ListeningExecutorService executor = 
MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
+        List<ListenableFuture<Void>> futures = Lists.newArrayList();
+        try {
+            for (int i = 0; i < 100; i++) {
+                futures.add(executor.submit(new Callable<Void>() {
+                    @Override public Void call() throws Exception {
+                        EntitySpec<?> obj = 
EntitySpec.create(TestEntity.class);
+                        assertSerializeAndDeserialize(obj);
+                        return null;
+                    }}));
+            }
+            Futures.allAsList(futures).get();
+            
+        } finally {
+            executor.shutdownNow();
+        }
+    }
+    
+    @Test
     public void testEntitySpecFromOsgi() throws Exception {
         
TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), 
OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_V1_PATH);
         ManagementContext mgmt = 
LocalManagementContextForTests.builder(true).disableOsgi(false).build();
@@ -612,4 +647,4 @@ public class XmlMementoSerializerTest {
             return Objects.hashCode(myStaticInnerField);
         }
     }
-}
+}
\ No newline at end of file

Reply via email to