You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by sv...@apache.org on 2015/10/27 15:48:26 UTC

[4/8] incubator-brooklyn git commit: address most review comments on relations

address most review comments on relations


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

Branch: refs/heads/master
Commit: ed113a348dbf214a2d8977e6179d5c0ebbf8c439
Parents: 1b71134
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Oct 27 11:29:00 2015 +0000
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Oct 27 11:51:42 2015 +0000

----------------------------------------------------------------------
 .../org/apache/brooklyn/api/entity/Entity.java  |  8 +-
 .../apache/brooklyn/api/location/Location.java  |  7 --
 .../api/mgmt/rebind/RebindExceptionHandler.java |  5 ++
 .../mementos/BrooklynMementoPersister.java      |  5 +-
 .../api/mgmt/rebind/mementos/Memento.java       |  3 +-
 .../brooklyn/api/objs/BrooklynObject.java       |  4 +-
 .../apache/brooklyn/api/objs/Configurable.java  |  3 +-
 .../org/apache/brooklyn/api/policy/Policy.java  |  5 --
 .../core/catalog/internal/CatalogItemDo.java    |  6 +-
 .../brooklyn/core/entity/EntityRelations.java   |  8 +-
 .../AbstractBrooklynObjectRebindSupport.java    | 14 +++-
 .../mgmt/rebind/RebindContextLookupContext.java | 18 +++++
 .../mgmt/rebind/RebindExceptionHandlerImpl.java | 17 ++++-
 .../core/mgmt/rebind/dto/AbstractMemento.java   | 19 +++--
 .../mgmt/rebind/dto/MementosGenerators.java     | 15 ++--
 .../relations/AbstractBasicRelationSupport.java |  8 +-
 .../relations/ByObjectBasicRelationSupport.java |  7 +-
 .../core/relations/EmptyRelationSupport.java    | 60 +++++++++++++++
 .../mgmt/persist/XmlMementoSerializerTest.java  | 18 +++++
 .../rebind/RebindClassInitializationTest.java   | 78 ++++++++++++++++++++
 .../core/mgmt/rebind/RebindEntityTest.java      |  3 +-
 21 files changed, 254 insertions(+), 57 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ed113a34/api/src/main/java/org/apache/brooklyn/api/entity/Entity.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/entity/Entity.java b/api/src/main/java/org/apache/brooklyn/api/entity/Entity.java
index a15f4e1..3b333e0 100644
--- a/api/src/main/java/org/apache/brooklyn/api/entity/Entity.java
+++ b/api/src/main/java/org/apache/brooklyn/api/entity/Entity.java
@@ -216,15 +216,9 @@ public interface Entity extends BrooklynObject {
      * via code like {@code sensors().get(key)}.
      */
     <T> T getAttribute(AttributeSensor<T> sensor);
-
-    /**
-     * Convenience for calling {@link ConfigurationSupport#get(ConfigKey)},
-     * via code like {@code config().get(key)}.
-     */
-    <T> T getConfig(ConfigKey<T> key);
     
     /**
-     * @see #getConfig(ConfigKey)}
+     * @see {@link #getConfig(ConfigKey)}
      */
     <T> T getConfig(HasConfigKey<T> key);
     

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ed113a34/api/src/main/java/org/apache/brooklyn/api/location/Location.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/location/Location.java b/api/src/main/java/org/apache/brooklyn/api/location/Location.java
index 392af13..84e371b 100644
--- a/api/src/main/java/org/apache/brooklyn/api/location/Location.java
+++ b/api/src/main/java/org/apache/brooklyn/api/location/Location.java
@@ -89,13 +89,6 @@ public interface Location extends Serializable, BrooklynObject {
      */
     boolean containsLocation(Location potentialDescendent);
 
-    /** 
-     * Returns configuration set at this location or inherited or default.
-     * 
-     * Convenience method for {@code config().get(key)}
-     */
-    <T> T getConfig(ConfigKey<T> key);
-
     /**
      * Convenience method for {@code config().get(key)}
      * 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ed113a34/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/RebindExceptionHandler.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/RebindExceptionHandler.java b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/RebindExceptionHandler.java
index 48bb07f..9660930 100644
--- a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/RebindExceptionHandler.java
+++ b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/RebindExceptionHandler.java
@@ -80,6 +80,11 @@ public interface RebindExceptionHandler {
      */
     CatalogItem<?, ?> onDanglingCatalogItemRef(String id);
 
+    /**
+     * @return the item to use in place of the missing one
+     */
+    BrooklynObject onDanglingUntypedItemRef(String id);
+
     void onCreateFailed(BrooklynObjectType type, String id, String instanceType, Exception e);
 
     void onNotFound(BrooklynObjectType type, String id);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ed113a34/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoPersister.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoPersister.java b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoPersister.java
index e554e08..03673fd 100644
--- a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoPersister.java
+++ b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoPersister.java
@@ -57,9 +57,10 @@ public interface BrooklynMementoPersister {
         Feed lookupFeed(String id);
         CatalogItem<?, ?> lookupCatalogItem(String id);
         
-        BrooklynObject lookup(BrooklynObjectType type, String objectId);
+        /** retrieve the item with the given ID, optionally ensuring it is of the indicated type; null if not found */
+        BrooklynObject lookup(@Nullable BrooklynObjectType type, String objectId);
         /** like {@link #lookup(BrooklynObjectType, String)} but doesn't record an exception if not found */
-        BrooklynObject peek(BrooklynObjectType type, String objectId);
+        BrooklynObject peek(@Nullable BrooklynObjectType type, String objectId);
     }
     
     /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ed113a34/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/Memento.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/Memento.java b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/Memento.java
index b57780d..5911f28 100644
--- a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/Memento.java
+++ b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/Memento.java
@@ -25,7 +25,6 @@ import java.util.Set;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.mgmt.rebind.RebindSupport;
-import org.apache.brooklyn.api.objs.BrooklynObject;
 import org.apache.brooklyn.api.objs.EntityAdjunct;
 
 /**
@@ -79,7 +78,7 @@ public interface Memento extends Serializable {
 
     public Collection<Object> getTags();
     
-    Map<String, Set<BrooklynObject>> getRelations();
+    public Map<String,Set<String>> getRelations();
     
     /** Null for {@link Entity}, but important for adjuncts; see {@link EntityAdjunct#getUniqueTag()} */
     public String getUniqueTag();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ed113a34/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObject.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObject.java b/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObject.java
index 8648491..9e1640f 100644
--- a/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObject.java
+++ b/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObject.java
@@ -151,8 +151,8 @@ public interface BrooklynObject extends Identifiable, Configurable {
     }
     
     public interface RelationSupport<T extends BrooklynObject> {
-        public <U extends BrooklynObject> void add(Relationship<? super T,U> relationship, U target);
-        public <U extends BrooklynObject> void remove(Relationship<? super T,U> relationship, U target);
+        public <U extends BrooklynObject> void add(Relationship<? super T,? super U> relationship, U target);
+        public <U extends BrooklynObject> void remove(Relationship<? super T,? super U> relationship, U target);
         public Set<Relationship<? super T,? extends BrooklynObject>> getRelationships();
         public <U extends BrooklynObject> Set<U> getRelations(Relationship<? super T,U> relationship);
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ed113a34/api/src/main/java/org/apache/brooklyn/api/objs/Configurable.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/objs/Configurable.java b/api/src/main/java/org/apache/brooklyn/api/objs/Configurable.java
index 5f1b294..84b1fcb 100644
--- a/api/src/main/java/org/apache/brooklyn/api/objs/Configurable.java
+++ b/api/src/main/java/org/apache/brooklyn/api/objs/Configurable.java
@@ -42,7 +42,8 @@ public interface Configurable {
     public <T> T setConfig(ConfigKey<T> key, T val);
 
     /**
-     * Convenience method for {@code config().get(key)}
+     * Convenience for calling {@link ConfigurationSupport#get(ConfigKey)},
+     * via code like {@code config().get(key)}.
      */
     <T> T getConfig(ConfigKey<T> key);
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ed113a34/api/src/main/java/org/apache/brooklyn/api/policy/Policy.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/policy/Policy.java b/api/src/main/java/org/apache/brooklyn/api/policy/Policy.java
index 957da0a..0235bac 100644
--- a/api/src/main/java/org/apache/brooklyn/api/policy/Policy.java
+++ b/api/src/main/java/org/apache/brooklyn/api/policy/Policy.java
@@ -60,11 +60,6 @@ public interface Policy extends EntityAdjunct, Rebindable, Configurable {
     boolean isSuspended();
     
     /**
-     * Convenience method for {@code config().get(key)}
-     */
-    <T> T getConfig(ConfigKey<T> key);
-    
-    /**
      * @deprecated since 0.7.0; use {@link #config()}, such as {@code policy.config().set(key, val)}
      */
     @Deprecated

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ed113a34/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java
index 7f3a54a..a3ae36e 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java
@@ -29,6 +29,7 @@ import org.apache.brooklyn.api.mgmt.rebind.RebindSupport;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.CatalogItemMemento;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.objs.BrooklynObjectInternal;
+import org.apache.brooklyn.core.relations.EmptyRelationSupport;
 
 import com.google.common.base.Preconditions;
 
@@ -65,11 +66,12 @@ public class CatalogItemDo<T,SpecT> implements CatalogItem<T,SpecT>, BrooklynObj
     }
     
     /**
-     * @throws UnsupportedOperationException; relations are not supported for catalog items
+     * @return an immutable empty relation support object; relations are not supported,
+     * but we do not throw on access to enable reads in a consistent manner
      */
     @Override
     public RelationSupportInternal<CatalogItem<T,SpecT>> relations() {
-        throw new UnsupportedOperationException();
+        return new EmptyRelationSupport<CatalogItem<T,SpecT>>(this);
     }
     
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ed113a34/core/src/main/java/org/apache/brooklyn/core/entity/EntityRelations.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/EntityRelations.java b/core/src/main/java/org/apache/brooklyn/core/entity/EntityRelations.java
index 7b20845..7dfa93e 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/EntityRelations.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/EntityRelations.java
@@ -136,23 +136,23 @@ public class EntityRelations<T extends BrooklynObject> {
     }
     
     @SuppressWarnings({ "rawtypes", "unchecked" })
-    public static <T extends BrooklynObject> Set<Relationship<? super T,? extends BrooklynObject>> getRelations(T source) {
+    public static <T extends BrooklynObject> Set<Relationship<? super T,? extends BrooklynObject>> getRelationships(T source) {
         return ((BrooklynObjectInternal)source).relations().getLocalBackingStore().getRelationships();
     }
 
     @SuppressWarnings({ "rawtypes", "unchecked" })
-    public static <T extends BrooklynObject,U extends BrooklynObject> Set<U> getRelationships(Relationship<? super T,U> relationship, T source) {
+    public static <T extends BrooklynObject,U extends BrooklynObject> Set<U> getRelations(Relationship<? super T,U> relationship, T source) {
         return ((BrooklynObjectInternal)source).relations().getLocalBackingStore().getRelations(relationship);
     }
 
     @SuppressWarnings({ "rawtypes", "unchecked" })
-    public static <T extends BrooklynObject,U extends BrooklynObject> void add(T source, Relationship<? super T,U> relationship, U target) {
+    public static <T extends BrooklynObject,U extends BrooklynObject> void add(T source, Relationship<? super T,? super U> relationship, U target) {
         ((BrooklynObjectInternal)source).relations().getLocalBackingStore().add(relationship, target);
         ((BrooklynObjectInternal)target).relations().getLocalBackingStore().add(relationship.getInverseRelationship(), source);
     }
 
     @SuppressWarnings({ "rawtypes", "unchecked" })
-    public static <T extends BrooklynObject,U extends BrooklynObject> void remove(T source, Relationship<? super T,U> relationship, U target) {
+    public static <T extends BrooklynObject,U extends BrooklynObject> void remove(T source, Relationship<? super T,? super U> relationship, U target) {
         ((BrooklynObjectInternal)source).relations().getLocalBackingStore().remove(relationship, target);
         ((BrooklynObjectInternal)target).relations().getLocalBackingStore().remove(relationship.getInverseRelationship(), source);
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ed113a34/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/AbstractBrooklynObjectRebindSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/AbstractBrooklynObjectRebindSupport.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/AbstractBrooklynObjectRebindSupport.java
index 74a7dca..414cdbe 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/AbstractBrooklynObjectRebindSupport.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/AbstractBrooklynObjectRebindSupport.java
@@ -86,11 +86,19 @@ public abstract class AbstractBrooklynObjectRebindSupport<T extends Memento> imp
 
     @SuppressWarnings({ "unchecked", "rawtypes" })
     protected void addRelations(RebindContext rebindContext, T memento) {
-        for (Map.Entry<String,Set<BrooklynObject>> rEntry : memento.getRelations().entrySet()) {
+        for (Map.Entry<String,Set<String>> rEntry : memento.getRelations().entrySet()) {
             Relationship<? extends BrooklynObject, ? extends BrooklynObject> r = EntityRelations.lookup(instance.getManagementContext(), rEntry.getKey());
             if (r==null) throw new IllegalStateException("Unsupported relationship -- "+rEntry.getKey() + " -- in "+memento);
-            for (BrooklynObject item: rEntry.getValue())
-                instance.relations().add((Relationship)r, item);
+            for (String itemId: rEntry.getValue()) {
+                BrooklynObject item = rebindContext.lookup().lookup(null, itemId);
+                if (item != null) {
+                    instance.relations().add((Relationship)r, item);
+                } else {
+                    LOG.warn("Item not found; discarding item {} relation {} of entity {}({})",
+                            new Object[] {itemId, r, memento.getType(), memento.getId()});
+                    rebindContext.getExceptionHandler().onDanglingUntypedItemRef(itemId);
+                }
+            }
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ed113a34/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindContextLookupContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindContextLookupContext.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindContextLookupContext.java
index 550f376..1faaa1c 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindContextLookupContext.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindContextLookupContext.java
@@ -18,6 +18,8 @@
  */
 package org.apache.brooklyn.core.mgmt.rebind;
 
+import java.util.NoSuchElementException;
+
 import javax.annotation.Nullable;
 
 import org.slf4j.Logger;
@@ -127,6 +129,14 @@ public class RebindContextLookupContext implements LookupContext {
     
     @Override
     public BrooklynObject lookup(BrooklynObjectType type, String id) {
+        if (type==null) {
+            BrooklynObject result = peek(null, id);
+            if (result==null) {
+                exceptionHandler.onDanglingUntypedItemRef(id);
+            }
+            type = BrooklynObjectType.of(result);
+        }
+        
         switch (type) {
         case CATALOG_ITEM: return lookupCatalogItem(id);
         case ENRICHER: return lookupEnricher(id);
@@ -141,6 +151,14 @@ public class RebindContextLookupContext implements LookupContext {
     
     @Override
     public BrooklynObject peek(BrooklynObjectType type, String id) {
+        if (type==null) {
+            for (BrooklynObjectType typeX: BrooklynObjectType.values()) {
+                BrooklynObject result = peek(typeX, id);
+                if (result!=null) return result;
+            }
+            return null;
+        }
+        
         switch (type) {
         case CATALOG_ITEM: return rebindContext.getCatalogItem(id);
         case ENRICHER: return rebindContext.getEnricher(id);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ed113a34/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindExceptionHandlerImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindExceptionHandlerImpl.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindExceptionHandlerImpl.java
index b6b7fc4..7b4cd00 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindExceptionHandlerImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindExceptionHandlerImpl.java
@@ -65,6 +65,7 @@ public class RebindExceptionHandlerImpl implements RebindExceptionHandler {
     protected final Set<String> missingEnrichers = Sets.newConcurrentHashSet();
     protected final Set<String> missingFeeds = Sets.newConcurrentHashSet();
     protected final Set<String> missingCatalogItems = Sets.newConcurrentHashSet();
+    protected final Set<String> missingUntypedItems = Sets.newConcurrentHashSet();
     protected final Set<String> creationFailedIds = Sets.newConcurrentHashSet();
     
     protected final Set<Exception> addPolicyFailures = Sets.newConcurrentHashSet();
@@ -237,6 +238,17 @@ public class RebindExceptionHandlerImpl implements RebindExceptionHandler {
     }
 
     @Override
+    public CatalogItem<?, ?> onDanglingUntypedItemRef(String id) {
+        missingUntypedItems.add(id);
+        if (danglingRefFailureMode == RebindManager.RebindFailureMode.FAIL_FAST) {
+            throw new IllegalStateException("No item found with id "+id);
+        } else {
+            warn("No item found with id "+id+"; dangling reference on rebind");
+            return null;
+        }
+    }
+
+    @Override
     public void onCreateFailed(BrooklynObjectType type, String id, String instanceType, Exception e) {
         Exceptions.propagateIfFatal(e);
         String errmsg = "problem creating "+type+" "+id+" of type "+instanceType;
@@ -395,7 +407,7 @@ public class RebindExceptionHandlerImpl implements RebindExceptionHandler {
         }
         done = true;
         
-        List<String> danglingIds = MutableList.copyOf(missingEntities).appendAll(missingLocations).appendAll(missingPolicies).appendAll(missingEnrichers).appendAll(missingFeeds).appendAll(missingCatalogItems);
+        List<String> danglingIds = MutableList.copyOf(missingEntities).appendAll(missingLocations).appendAll(missingPolicies).appendAll(missingEnrichers).appendAll(missingFeeds).appendAll(missingCatalogItems).appendAll(missingUntypedItems);
         int totalDangling = danglingIds.size();
         if (totalDangling>0) {
             int totalFound = context.getAllBrooklynObjects().size();
@@ -441,6 +453,9 @@ public class RebindExceptionHandlerImpl implements RebindExceptionHandler {
             if (!missingCatalogItems.isEmpty()) {
                 allExceptions.add(new IllegalStateException("Missing referenced catalog item" + Strings.s(missingCatalogItems) + ": " + missingCatalogItems));
             }
+            if (!missingUntypedItems.isEmpty()) {
+                allExceptions.add(new IllegalStateException("Missing referenced untyped items" + Strings.s(missingUntypedItems) + ": " + missingUntypedItems));
+            }
         }
         if (rebindFailureMode != RebindManager.RebindFailureMode.CONTINUE) {
             allExceptions.addAll(exceptions);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ed113a34/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/AbstractMemento.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/AbstractMemento.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/AbstractMemento.java
index 1fae585..6fae7f5 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/AbstractMemento.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/AbstractMemento.java
@@ -25,14 +25,15 @@ import java.util.Map;
 import java.util.Set;
 
 import org.apache.brooklyn.api.mgmt.rebind.mementos.Memento;
-import org.apache.brooklyn.api.objs.BrooklynObject;
 import org.apache.brooklyn.core.BrooklynVersion;
 import org.apache.brooklyn.core.config.Sanitizer;
 
 import com.google.common.base.Objects;
 import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.collect.ImmutableMultimap;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
 
 public abstract class AbstractMemento implements Memento, Serializable {
 
@@ -47,8 +48,8 @@ public abstract class AbstractMemento implements Memento, Serializable {
         protected String catalogItemId;
         protected Map<String, Object> customFields = Maps.newLinkedHashMap();
         protected List<Object> tags = Lists.newArrayList();
-        protected Map<String,Set<BrooklynObject>> relations = Maps.newLinkedHashMap();
-        
+        protected Map<String,Set<String>> relations = Maps.newLinkedHashMap();
+
         // only supported for EntityAdjuncts
         protected String uniqueTag;
 
@@ -86,7 +87,7 @@ public abstract class AbstractMemento implements Memento, Serializable {
     private String displayName;
     private String catalogItemId;
     private List<Object> tags;
-    private Map<String, Set<BrooklynObject>> relations;
+    private Map<String,Set<String>> relations;
     
     // for EntityAdjuncts; not used for entity
     private String uniqueTag;
@@ -156,7 +157,7 @@ public abstract class AbstractMemento implements Memento, Serializable {
     }
 
     @Override
-    public Map<String, Set<BrooklynObject>> getRelations() {
+    public Map<String,Set<String>> getRelations() {
         return fromPersistedMap(relations);
     }
     
@@ -218,4 +219,12 @@ public abstract class AbstractMemento implements Memento, Serializable {
         if (m==null || m.isEmpty()) return null;
         return m;
     }
+    protected <K,V> Multimap<K,V> fromPersistedMultimap(Multimap<K,V> m) {
+        if (m==null) return ImmutableMultimap.of();
+        return ImmutableMultimap.copyOf(m);
+    }
+    protected <K,V> Multimap<K,V> toPersistedMultimap(Multimap<K,V> m) {
+        if (m==null || m.isEmpty()) return null;
+        return m;
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ed113a34/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
index 6cfda79..918278c 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
@@ -66,6 +66,7 @@ import org.apache.brooklyn.util.core.flags.FlagUtils;
 import com.google.common.annotations.Beta;
 import com.google.common.base.Function;
 import com.google.common.base.Predicates;
+import com.google.common.collect.Sets;
 
 import brooklyn.basic.relations.Relationship;
 
@@ -431,7 +432,6 @@ public class MementosGenerators {
         return builder.build();
     }
     
-    @SuppressWarnings({ "unchecked", "rawtypes" })
     private static void populateBrooklynObjectMementoBuilder(BrooklynObject instance, AbstractMemento.Builder<?> builder) {
         if (Proxy.isProxyClass(instance.getClass())) {
             throw new IllegalStateException("Attempt to create memento from proxy "+instance+" (would fail with wrong type)");
@@ -448,12 +448,13 @@ public class MementosGenerators {
         for (Object tag : instance.tags().getTags()) {
             builder.tags.add(tag); 
         }
-        if (!(instance instanceof CatalogItem)) {
-            // CatalogItem is a BrooklynObject so it can be persisted
-            // but it does not support relations
-            for (Relationship<?,? extends BrooklynObject> relationship: instance.relations().getRelationships()) {
-                builder.relations.put(relationship.getRelationshipTypeName(), instance.relations().getRelations((Relationship)relationship));
-            }
+        // CatalogItems return empty support, so this is safe even through they don't support relations
+        for (Relationship<?,? extends BrooklynObject> relationship: instance.relations().getRelationships()) {
+            @SuppressWarnings({ "unchecked", "rawtypes" })
+            Set relations = instance.relations().getRelations((Relationship)relationship);
+            Set<String> relationIds = Sets.newLinkedHashSet();
+            for (Object r: relations) relationIds.add( ((BrooklynObject)r).getId() );
+            builder.relations.put(relationship.getRelationshipTypeName(), relationIds);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ed113a34/core/src/main/java/org/apache/brooklyn/core/relations/AbstractBasicRelationSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/relations/AbstractBasicRelationSupport.java b/core/src/main/java/org/apache/brooklyn/core/relations/AbstractBasicRelationSupport.java
index e87d0ea..3694fa8 100644
--- a/core/src/main/java/org/apache/brooklyn/core/relations/AbstractBasicRelationSupport.java
+++ b/core/src/main/java/org/apache/brooklyn/core/relations/AbstractBasicRelationSupport.java
@@ -34,21 +34,21 @@ public abstract class AbstractBasicRelationSupport<SourceType extends BrooklynOb
         
     @Override
     public Set<Relationship<? super SourceType, ? extends BrooklynObject>> getRelationships() {
-        return EntityRelations.getRelations(source);
+        return EntityRelations.getRelationships(source);
     }
     
     @Override
     public <U extends BrooklynObject> Set<U> getRelations(Relationship<? super SourceType, U> relationship) {
-        return EntityRelations.getRelationships(relationship, source);
+        return EntityRelations.getRelations(relationship, source);
     }
 
     @Override
-    public <U extends BrooklynObject> void add(Relationship<? super SourceType, U> relationship, U target) {
+    public <U extends BrooklynObject> void add(Relationship<? super SourceType, ? super U> relationship, U target) {
         EntityRelations.add(source, relationship, target);
     }
 
     @Override
-    public <U extends BrooklynObject> void remove(Relationship<? super SourceType, U> relationship, U target) {
+    public <U extends BrooklynObject> void remove(Relationship<? super SourceType, ? super U> relationship, U target) {
         EntityRelations.remove(source, relationship, target);
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ed113a34/core/src/main/java/org/apache/brooklyn/core/relations/ByObjectBasicRelationSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/relations/ByObjectBasicRelationSupport.java b/core/src/main/java/org/apache/brooklyn/core/relations/ByObjectBasicRelationSupport.java
index 1152e85..3600640 100644
--- a/core/src/main/java/org/apache/brooklyn/core/relations/ByObjectBasicRelationSupport.java
+++ b/core/src/main/java/org/apache/brooklyn/core/relations/ByObjectBasicRelationSupport.java
@@ -78,17 +78,18 @@ public class ByObjectBasicRelationSupport<SourceType extends BrooklynObject> ext
             }
         }
 
+        @SuppressWarnings({ "unchecked", "rawtypes" })
         @Override
-        public <U extends BrooklynObject> void add(Relationship<? super T,U> relationship, U target) {
+        public <U extends BrooklynObject> void add(Relationship<? super T,? super U> relationship, U target) {
             synchronized (relations) {
-                relationships.put(relationship.getRelationshipTypeName(), relationship);
+                relationships.put(relationship.getRelationshipTypeName(), (Relationship)relationship);
                 relations.put(relationship.getRelationshipTypeName(), target);
             }
             onRelationsChanged();
         }
 
         @Override
-        public <U extends BrooklynObject> void remove(Relationship<? super T,U> relationship, U target) {
+        public <U extends BrooklynObject> void remove(Relationship<? super T,? super U> relationship, U target) {
             synchronized (relations) {
                 relations.remove(relationship.getRelationshipTypeName(), target);
             }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ed113a34/core/src/main/java/org/apache/brooklyn/core/relations/EmptyRelationSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/relations/EmptyRelationSupport.java b/core/src/main/java/org/apache/brooklyn/core/relations/EmptyRelationSupport.java
new file mode 100644
index 0000000..40b001a
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/relations/EmptyRelationSupport.java
@@ -0,0 +1,60 @@
+/*
+ * 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.brooklyn.core.relations;
+
+import java.util.Collections;
+import java.util.Set;
+
+import org.apache.brooklyn.api.objs.BrooklynObject;
+import org.apache.brooklyn.api.objs.BrooklynObject.RelationSupport;
+import org.apache.brooklyn.core.objs.BrooklynObjectInternal.RelationSupportInternal;
+
+import brooklyn.basic.relations.Relationship;
+
+public final class EmptyRelationSupport<SourceType extends BrooklynObject> implements RelationSupportInternal<SourceType> {
+
+    final SourceType source;
+    
+    public EmptyRelationSupport(SourceType source) { this.source = source; }
+        
+    @Override
+    public Set<Relationship<? super SourceType, ? extends BrooklynObject>> getRelationships() {
+        return Collections.emptySet();
+    }
+    
+    @Override
+    public <U extends BrooklynObject> Set<U> getRelations(Relationship<? super SourceType, U> relationship) {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public <U extends BrooklynObject> void add(Relationship<? super SourceType, ? super U> relationship, U target) {
+        throw new UnsupportedOperationException("Relations not available on "+source);
+    }
+
+    @Override
+    public <U extends BrooklynObject> void remove(Relationship<? super SourceType, ? super U> relationship, U target) {
+    }
+
+    @Override
+    public RelationSupport<SourceType> getLocalBackingStore() {
+        throw new UnsupportedOperationException("Relations not available on "+source);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ed113a34/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 246e214..3ed5486 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
@@ -516,6 +516,16 @@ System.out.println("XXX: "+x);
         
         @Override
         public BrooklynObject lookup(BrooklynObjectType type, String id) {
+            if (type==null) {
+                BrooklynObject result = peek(null, id);
+                if (result==null) {
+                    if (failOnDangling) {
+                        throw new NoSuchElementException("no brooklyn object with id "+id+"; type not specified");
+                    }                    
+                }
+                type = BrooklynObjectType.of(result);
+            }
+            
             switch (type) {
             case CATALOG_ITEM: return lookupCatalogItem(id);
             case ENRICHER: return lookupEnricher(id);
@@ -529,6 +539,14 @@ System.out.println("XXX: "+x);
         }
         @Override
         public BrooklynObject peek(BrooklynObjectType type, String id) {
+            if (type==null) {
+                for (BrooklynObjectType typeX: BrooklynObjectType.values()) {
+                    BrooklynObject result = peek(typeX, id);
+                    if (result!=null) return result;
+                }
+                return null;
+            }
+            
             switch (type) {
             case CATALOG_ITEM: return catalogItems.get(id);
             case ENRICHER: return enrichers.get(id);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ed113a34/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindClassInitializationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindClassInitializationTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindClassInitializationTest.java
new file mode 100644
index 0000000..a5105cc
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindClassInitializationTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.brooklyn.core.mgmt.rebind;
+
+import java.util.List;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.core.entity.AbstractEntity;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.text.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class RebindClassInitializationTest extends RebindTestFixtureWithApp {
+
+    private static final Logger log = LoggerFactory.getLogger(RebindClassInitializationTest.class);
+    static List<String> messages = MutableList.of();
+    
+    @Test
+    public void testRestoresSimpleApp() throws Exception {
+        messages.clear();
+        messages.add("creating");
+        origApp.createAndManageChild(EntitySpec.create(Entity.class, MyEntityForClassInitializationTesting.class));
+        messages.add("created");
+        messages.add("rebinding");
+        newApp = rebind();
+        messages.add("rebinded");
+        
+        log.debug("Create and rebind message sequence is:\n- "+Strings.join(messages, "\n- "));
+        Assert.assertEquals(messages, MutableList.of(
+            "creating", "ME.static_initializer", "ME.initializer", 
+            "WIM.static_initializer", "WIM.initializer", "WIM.constructor", 
+            "ME.constructor", "created", 
+            "rebinding", "ME.initializer", "WIM.initializer", "WIM.constructor", 
+            "ME.constructor", "rebinded"));
+    }
+    
+    public static class MyEntityForClassInitializationTesting extends AbstractEntity {
+        
+        { messages.add("ME.initializer"); }
+        
+        static { messages.add("ME.static_initializer"); }
+        
+        @SuppressWarnings("unused")
+        private final Object dummy = new WriteInitMessage();
+
+        public MyEntityForClassInitializationTesting() {
+            messages.add("ME.constructor");
+        }
+    }
+
+    private static class WriteInitMessage {
+        public WriteInitMessage() { messages.add("WIM.constructor"); }
+        
+        { messages.add("WIM.initializer"); }
+        
+        static { messages.add("WIM.static_initializer"); }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ed113a34/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEntityTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEntityTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEntityTest.java
index 900b492..7c726e4 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEntityTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEntityTest.java
@@ -49,9 +49,9 @@ import org.apache.brooklyn.api.mgmt.rebind.RebindSupport;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoManifest;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.EntityMemento;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.api.sensor.AttributeSensor.SensorPersistenceMode;
 import org.apache.brooklyn.api.sensor.SensorEvent;
 import org.apache.brooklyn.api.sensor.SensorEventListener;
-import org.apache.brooklyn.api.sensor.AttributeSensor.SensorPersistenceMode;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.BasicConfigKey;
 import org.apache.brooklyn.core.entity.AbstractEntity;
@@ -61,7 +61,6 @@ import org.apache.brooklyn.core.entity.trait.Resizable;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.location.LocationConfigTest.MyLocation;
 import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
-import org.apache.brooklyn.core.mgmt.rebind.BasicEntityRebindSupport;
 import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
 import org.apache.brooklyn.core.sensor.BasicSensorEvent;
 import org.apache.brooklyn.core.sensor.DependentConfiguration;