You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2014/11/15 01:05:15 UTC

[06/21] incubator-brooklyn git commit: more persistence, mainly tidying code to treat all BrooklynObject instances the same

more persistence, mainly tidying code to treat all BrooklynObject instances the same


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

Branch: refs/heads/master
Commit: 38a756b2bb08f2baa80dddb53faa51cc645f988b
Parents: 3e793cd
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Nov 10 21:26:42 2014 +0000
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Thu Nov 13 23:38:52 2014 +0000

----------------------------------------------------------------------
 .../entity/rebind/BrooklynObjectType.java       |  38 ++-
 .../brooklyn/entity/rebind/RebindManager.java   |  15 +-
 .../java/brooklyn/mementos/BrooklynMemento.java |  16 --
 .../mementos/BrooklynMementoPersister.java      |  20 +-
 .../brooklyn/basic/BrooklynObjectInternal.java  |   6 +-
 .../catalog/internal/CatalogItemDo.java         |  10 +-
 .../rebind/ImmediateDeltaChangeListener.java    |   1 -
 .../rebind/PeriodicDeltaChangeListener.java     | 229 ++++++++-----------
 .../rebind/PersistenceExceptionHandlerImpl.java |   8 +-
 .../entity/rebind/PersisterDeltaImpl.java       | 147 +++++-------
 .../entity/rebind/RebindManagerImpl.java        |  17 +-
 .../AbstractBrooklynMementoPersister.java       |   8 +-
 .../BrooklynMementoPersisterInMemory.java       |   2 +-
 .../BrooklynMementoPersisterToMultiFile.java    |   6 +
 .../BrooklynMementoPersisterToObjectStore.java  |  35 ++-
 .../persister/BrooklynPersistenceUtils.java     |  10 +
 .../NonDeploymentManagementContext.java         |   4 +
 .../entity/rebind/RebindCatalogItemTest.java    |   4 +-
 18 files changed, 296 insertions(+), 280 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/38a756b2/api/src/main/java/brooklyn/entity/rebind/BrooklynObjectType.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/entity/rebind/BrooklynObjectType.java b/api/src/main/java/brooklyn/entity/rebind/BrooklynObjectType.java
index b00d3b3..ce30c75 100644
--- a/api/src/main/java/brooklyn/entity/rebind/BrooklynObjectType.java
+++ b/api/src/main/java/brooklyn/entity/rebind/BrooklynObjectType.java
@@ -18,22 +18,32 @@
  */
 package brooklyn.entity.rebind;
 
+import brooklyn.basic.BrooklynObject;
+import brooklyn.catalog.CatalogItem;
+import brooklyn.entity.Entity;
+import brooklyn.entity.Feed;
+import brooklyn.location.Location;
+import brooklyn.policy.Enricher;
+import brooklyn.policy.Policy;
+
 import com.google.common.annotations.Beta;
 import com.google.common.base.CaseFormat;
 
 @Beta
 public enum BrooklynObjectType {
-    ENTITY("entities"),
-    LOCATION("locations"),
-    POLICY("policies"),
-    ENRICHER("enrichers"),
-    FEED("feeds"),
-    CATALOG_ITEM("catalog"),
-    UNKNOWN("unknown");
+    ENTITY(Entity.class, "entities"),
+    LOCATION(Location.class, "locations"),
+    POLICY(Policy.class, "policies"),
+    ENRICHER(Enricher.class, "enrichers"),
+    FEED(Feed.class, "feeds"),
+    CATALOG_ITEM(CatalogItem.class, "catalog"),
+    UNKNOWN(null, "unknown");
     
+    private Class<? extends BrooklynObject> interfaceType;
     private final String subPathName;
     
-    BrooklynObjectType(String subPathName) {
+    BrooklynObjectType(Class<? extends BrooklynObject> interfaceType, String subPathName) {
+        this.interfaceType = interfaceType;
         this.subPathName = subPathName;
     }
     public String toCamelCase() {
@@ -43,4 +53,16 @@ public enum BrooklynObjectType {
     public String getSubPathName() {
         return subPathName;
     }
+    
+    public Class<? extends BrooklynObject> getInterfaceType() {
+        return interfaceType;
+    }
+    
+    public static BrooklynObjectType of(BrooklynObject instance) {
+        for (BrooklynObjectType t: values()) {
+            if (t.getInterfaceType()!=null && t.getInterfaceType().isInstance(instance))
+                return t;
+        }
+        return UNKNOWN;
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/38a756b2/api/src/main/java/brooklyn/entity/rebind/RebindManager.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/entity/rebind/RebindManager.java b/api/src/main/java/brooklyn/entity/rebind/RebindManager.java
index 8995aae..e5001a6 100644
--- a/api/src/main/java/brooklyn/entity/rebind/RebindManager.java
+++ b/api/src/main/java/brooklyn/entity/rebind/RebindManager.java
@@ -18,11 +18,12 @@
  */
 package brooklyn.entity.rebind;
 
-import java.io.IOException;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
+import javax.annotation.Nullable;
+
 import brooklyn.entity.Application;
 import brooklyn.management.ha.ManagementNodeState;
 import brooklyn.mementos.BrooklynMementoPersister;
@@ -110,7 +111,17 @@ public interface RebindManager {
     /** waits for any needed or pending writes to complete */
     @VisibleForTesting
     public void waitForPendingComplete(Duration duration) throws InterruptedException, TimeoutException;
-    /** Forcibly performs persistence, in the foreground */
+    /** Forcibly performs persistence, in the foreground 
+     * @deprecated since 0.7.0; use {@link #forcePersistNow(boolean)}, 
+     * default parameter here is false to mean incremental, with  */
     @VisibleForTesting
     public void forcePersistNow();
+    /** Forcibly performs persistence, in the foreground, either full (all entities) or incremental;
+     * if no exception handler specified, the default one from the persister is used.
+     * <p>
+     * Note that full persistence does *not* delete items; incremental should normally be sufficient.
+     * (A clear then full persistence would have the same effect, but that is risky in a production
+     * setting if the process fails after the clear!) */
+    @VisibleForTesting
+    public void forcePersistNow(boolean full, @Nullable PersistenceExceptionHandler exceptionHandler);
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/38a756b2/api/src/main/java/brooklyn/mementos/BrooklynMemento.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/mementos/BrooklynMemento.java b/api/src/main/java/brooklyn/mementos/BrooklynMemento.java
index 538c670..4aa36c6 100644
--- a/api/src/main/java/brooklyn/mementos/BrooklynMemento.java
+++ b/api/src/main/java/brooklyn/mementos/BrooklynMemento.java
@@ -38,43 +38,27 @@ import java.util.Map;
 public interface BrooklynMemento extends Serializable {
 
     public EntityMemento getEntityMemento(String id);
-
     public LocationMemento getLocationMemento(String id);
-    
     public PolicyMemento getPolicyMemento(String id);
-    
     public EnricherMemento getEnricherMemento(String id);
-
     public FeedMemento getFeedMemento(String id);
-    
     public CatalogItemMemento getCatalogItemMemento(String id);
 
     public Collection<String> getApplicationIds();
-    
     public Collection<String> getTopLevelLocationIds();
 
     public Collection<String> getEntityIds();
-    
     public Collection<String> getLocationIds();
-
     public Collection<String> getPolicyIds();
-
     public Collection<String> getEnricherIds();
-
     public Collection<String> getFeedIds();
-    
     public Collection<String> getCatalogItemIds();
 
     public Map<String, EntityMemento> getEntityMementos();
-
     public Map<String, LocationMemento> getLocationMementos();
-
     public Map<String, PolicyMemento> getPolicyMementos();
-
     public Map<String, EnricherMemento> getEnricherMementos();
-
     public Map<String, FeedMemento> getFeedMementos();
-    
     public Map<String, CatalogItemMemento> getCatalogItemMementos();
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/38a756b2/api/src/main/java/brooklyn/mementos/BrooklynMementoPersister.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/mementos/BrooklynMementoPersister.java b/api/src/main/java/brooklyn/mementos/BrooklynMementoPersister.java
index ed649fa..a9eb65f 100644
--- a/api/src/main/java/brooklyn/mementos/BrooklynMementoPersister.java
+++ b/api/src/main/java/brooklyn/mementos/BrooklynMementoPersister.java
@@ -20,6 +20,7 @@ package brooklyn.mementos;
 
 import java.io.IOException;
 import java.util.Collection;
+import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
@@ -39,6 +40,7 @@ import brooklyn.policy.Enricher;
 import brooklyn.policy.Policy;
 import brooklyn.util.time.Duration;
 
+import com.google.common.annotations.Beta;
 import com.google.common.annotations.VisibleForTesting;
 
 /**
@@ -91,9 +93,12 @@ public interface BrooklynMementoPersister {
       * Note that this method is *not* thread safe.
       */
     BrooklynMemento loadMemento(@Nullable BrooklynMementoRawData mementoData, LookupContext lookupContext, RebindExceptionHandler exceptionHandler) throws IOException;
-    
-    // TODO can this be deprecated? not used much, and cumbersome
+
+    /** @deprecated since 0.7.0, use {@link #checkpoint(BrooklynMementoRawData, PersistenceExceptionHandler)} 
+     * and javadoc on implementations of that */ @Deprecated  // pretty sure this is not used outwith deprecated code
     void checkpoint(BrooklynMemento memento, PersistenceExceptionHandler exceptionHandler);
+    
+    void checkpoint(BrooklynMementoRawData newMemento, PersistenceExceptionHandler exceptionHandler);
 
     void delta(Delta delta, PersistenceExceptionHandler exceptionHandler);
 
@@ -113,6 +118,8 @@ public interface BrooklynMementoPersister {
 
     String getBackingStoreDescription();
     
+    /** All methods on this interface are unmodifiable by the caller. Sub-interfaces may introduce modifiers. */
+    // NB: the type-specific methods aren't actually used anymore; we could remove them to simplify the impl (and use a multiset there)
     public interface Delta {
         Collection<LocationMemento> locations();
         Collection<EntityMemento> entities();
@@ -129,7 +136,14 @@ public interface BrooklynMementoPersister {
         Collection<String> removedCatalogItemIds();
         
         Collection<? extends Memento> getObjectsOfType(BrooklynObjectType type);
-        Collection<String> getRemovedObjectsOfType(BrooklynObjectType type);
+        Collection<String> getRemovedIdsOfType(BrooklynObjectType type);
+    }
+    
+    @Beta
+    public interface MutableDelta extends Delta {
+        void add(BrooklynObjectType type, Memento memento);
+        void addAll(BrooklynObjectType type, Iterable<? extends Memento> memento);
+        void removed(BrooklynObjectType type, Set<String> removedIdsOfType);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/38a756b2/core/src/main/java/brooklyn/basic/BrooklynObjectInternal.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/basic/BrooklynObjectInternal.java b/core/src/main/java/brooklyn/basic/BrooklynObjectInternal.java
index 84a0a58..26e75c9 100644
--- a/core/src/main/java/brooklyn/basic/BrooklynObjectInternal.java
+++ b/core/src/main/java/brooklyn/basic/BrooklynObjectInternal.java
@@ -18,10 +18,14 @@
  */
 package brooklyn.basic;
 
+import brooklyn.entity.rebind.RebindSupport;
 import brooklyn.entity.rebind.Rebindable;
 
 public interface BrooklynObjectInternal extends BrooklynObject, Rebindable {
     
-    public void setCatalogItemId(String id);
+    void setCatalogItemId(String id);
+    
+    @SuppressWarnings("rawtypes")  // subclasses typically apply stronger typing
+    RebindSupport getRebindSupport();
     
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/38a756b2/core/src/main/java/brooklyn/catalog/internal/CatalogItemDo.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/catalog/internal/CatalogItemDo.java b/core/src/main/java/brooklyn/catalog/internal/CatalogItemDo.java
index f40a49b..fdac692 100644
--- a/core/src/main/java/brooklyn/catalog/internal/CatalogItemDo.java
+++ b/core/src/main/java/brooklyn/catalog/internal/CatalogItemDo.java
@@ -23,6 +23,7 @@ import java.util.Collection;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import brooklyn.basic.BrooklynObjectInternal;
 import brooklyn.catalog.CatalogItem;
 import brooklyn.entity.rebind.RebindSupport;
 import brooklyn.management.ManagementContext;
@@ -30,7 +31,7 @@ import brooklyn.mementos.CatalogItemMemento;
 
 import com.google.common.base.Preconditions;
 
-public class CatalogItemDo<T,SpecT> implements CatalogItem<T,SpecT> {
+public class CatalogItemDo<T,SpecT> implements CatalogItem<T,SpecT>, BrooklynObjectInternal {
 
     protected final CatalogDo catalog;
     protected final CatalogItemDtoAbstract<T,SpecT> itemDto;
@@ -63,7 +64,12 @@ public class CatalogItemDo<T,SpecT> implements CatalogItem<T,SpecT> {
 
     @Override
     public String getCatalogItemId() {
-        return null;
+        return itemDto.getCatalogItemId();
+    }
+    
+    @Override
+    public void setCatalogItemId(String id) {
+        itemDto.setCatalogItemId(id);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/38a756b2/core/src/main/java/brooklyn/entity/rebind/ImmediateDeltaChangeListener.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/ImmediateDeltaChangeListener.java b/core/src/main/java/brooklyn/entity/rebind/ImmediateDeltaChangeListener.java
index a668a37..d7ddeea 100644
--- a/core/src/main/java/brooklyn/entity/rebind/ImmediateDeltaChangeListener.java
+++ b/core/src/main/java/brooklyn/entity/rebind/ImmediateDeltaChangeListener.java
@@ -92,7 +92,6 @@ public class ImmediateDeltaChangeListener implements ChangeListener {
         if (running && persister != null) {
             PersisterDeltaImpl delta = new PersisterDeltaImpl();
             Memento memento = ((BrooklynObjectInternal)instance).getRebindSupport().getMemento();
-            // XXX use switch statement, and above, and in MementosGenerator
             if (instance instanceof Entity) {
                 delta.entities.add((EntityMemento) memento);
                 addEntityAdjuncts((Entity)instance, delta);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/38a756b2/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java b/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java
index b104365..08ca53c 100644
--- a/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java
+++ b/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java
@@ -31,14 +31,15 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.basic.BrooklynObject;
+import brooklyn.basic.BrooklynObjectInternal;
 import brooklyn.catalog.CatalogItem;
 import brooklyn.entity.Entity;
 import brooklyn.entity.Feed;
 import brooklyn.entity.basic.BrooklynTaskTags;
 import brooklyn.entity.basic.EntityInternal;
+import brooklyn.entity.rebind.persister.BrooklynPersistenceUtils;
 import brooklyn.internal.BrooklynFeatureEnablement;
 import brooklyn.location.Location;
-import brooklyn.location.basic.LocationInternal;
 import brooklyn.management.ExecutionContext;
 import brooklyn.management.ExecutionManager;
 import brooklyn.management.Task;
@@ -79,18 +80,19 @@ public class PeriodicDeltaChangeListener implements ChangeListener {
     private static final Logger LOG = LoggerFactory.getLogger(PeriodicDeltaChangeListener.class);
 
     private static class DeltaCollector {
-        Set<Location> locations = Sets.newLinkedHashSet();
-        Set<Entity> entities = Sets.newLinkedHashSet();
-        Set<Policy> policies = Sets.newLinkedHashSet();
-        Set<Enricher> enrichers = Sets.newLinkedHashSet();
-        Set<Feed> feeds = Sets.newLinkedHashSet();
-        Set<CatalogItem<?, ?>> catalogItems = Sets.newLinkedHashSet();
-        Set<String> removedLocationIds = Sets.newLinkedHashSet();
-        Set<String> removedEntityIds = Sets.newLinkedHashSet();
-        Set<String> removedPolicyIds = Sets.newLinkedHashSet();
-        Set<String> removedEnricherIds = Sets.newLinkedHashSet();
-        Set<String> removedFeedIds = Sets.newLinkedHashSet();
-        Set<String> removedCatalogItemIds = Sets.newLinkedHashSet();
+        private Set<Location> locations = Sets.newLinkedHashSet();
+        private Set<Entity> entities = Sets.newLinkedHashSet();
+        private Set<Policy> policies = Sets.newLinkedHashSet();
+        private Set<Enricher> enrichers = Sets.newLinkedHashSet();
+        private Set<Feed> feeds = Sets.newLinkedHashSet();
+        private Set<CatalogItem<?, ?>> catalogItems = Sets.newLinkedHashSet();
+        
+        private Set<String> removedLocationIds = Sets.newLinkedHashSet();
+        private Set<String> removedEntityIds = Sets.newLinkedHashSet();
+        private Set<String> removedPolicyIds = Sets.newLinkedHashSet();
+        private Set<String> removedEnricherIds = Sets.newLinkedHashSet();
+        private Set<String> removedFeedIds = Sets.newLinkedHashSet();
+        private Set<String> removedCatalogItemIds = Sets.newLinkedHashSet();
 
         public boolean isEmpty() {
             return locations.isEmpty() && entities.isEmpty() && policies.isEmpty() && 
@@ -100,6 +102,56 @@ public class PeriodicDeltaChangeListener implements ChangeListener {
                     removedEnricherIds.isEmpty() && removedFeedIds.isEmpty() &&
                     removedCatalogItemIds.isEmpty();
         }
+        
+        public void add(BrooklynObject instance) {
+            BrooklynObjectType type = BrooklynObjectType.of(instance);
+            getUnsafeCollectionOfType(type).add(instance);
+        }
+        
+        public void addIfNotRemoved(BrooklynObject instance) {
+            BrooklynObjectType type = BrooklynObjectType.of(instance);
+            if (!getRemovedIdsOfType(type).contains(instance.getId())) {
+                getUnsafeCollectionOfType(type).add(instance);
+            }
+        }
+
+        public void remove(BrooklynObject instance) {
+            BrooklynObjectType type = BrooklynObjectType.of(instance);
+            getUnsafeCollectionOfType(type).remove(instance);
+            getRemovedIdsOfType(type).add(instance.getId());
+        }
+
+        @SuppressWarnings("unchecked")
+        private Set<BrooklynObject> getUnsafeCollectionOfType(BrooklynObjectType type) {
+            return (Set<BrooklynObject>)getCollectionOfType(type);
+        }
+
+        private Set<? extends BrooklynObject> getCollectionOfType(BrooklynObjectType type) {
+            switch (type) {
+            case ENTITY: return entities;
+            case LOCATION: return locations;
+            case ENRICHER: return enrichers;
+            case FEED: return feeds;
+            case POLICY: return policies;
+            case CATALOG_ITEM: return catalogItems;
+            case UNKNOWN: break;
+            }
+            throw new IllegalStateException("No collection for type "+type);
+        }
+        
+        private Set<String> getRemovedIdsOfType(BrooklynObjectType type) {
+            switch (type) {
+            case ENTITY: return removedEntityIds;
+            case LOCATION: return removedLocationIds;
+            case ENRICHER: return removedEnricherIds;
+            case FEED: return removedFeedIds;
+            case POLICY: return removedPolicyIds;
+            case CATALOG_ITEM: return removedCatalogItemIds;
+            case UNKNOWN: break;
+            }
+            throw new IllegalStateException("No removed ids for type "+type);
+        }
+
     }
     
     private final ExecutionContext executionContext;
@@ -262,47 +314,28 @@ public class PeriodicDeltaChangeListener implements ChangeListener {
     }
     
     private void addReferencedObjects(DeltaCollector deltaCollector) {
-        Set<Location> referencedLocations = Sets.newLinkedHashSet();
-        Set<Policy> referencedPolicies = Sets.newLinkedHashSet();
-        Set<Enricher> referencedEnrichers = Sets.newLinkedHashSet();
-        Set<Feed> referencedFeeds = Sets.newLinkedHashSet();
+        Set<BrooklynObject> referencedObjects = Sets.newLinkedHashSet();
         
+        // collect references
         for (Entity entity : deltaCollector.entities) {
             // FIXME How to let the policy/location tell us about changes? Don't do this every time!
             for (Location location : entity.getLocations()) {
                 Collection<Location> findLocationsInHierarchy = TreeUtils.findLocationsInHierarchy(location);
-                referencedLocations.addAll(findLocationsInHierarchy);
+                referencedObjects.addAll(findLocationsInHierarchy);
             }
             if (persistPoliciesEnabled) {
-                referencedPolicies.addAll(entity.getPolicies());
+                referencedObjects.addAll(entity.getPolicies());
             }
             if (persistEnrichersEnabled) {
-                referencedEnrichers.addAll(entity.getEnrichers());
+                referencedObjects.addAll(entity.getEnrichers());
             }
             if (persistFeedsEnabled) {
-                referencedFeeds.addAll(((EntityInternal)entity).feeds().getFeeds());
+                referencedObjects.addAll(((EntityInternal)entity).feeds().getFeeds());
             }
         }
         
-        for (Location loc : referencedLocations) {
-            if (!deltaCollector.removedLocationIds.contains(loc.getId())) {
-                deltaCollector.locations.add(loc);
-            }
-        }
-        for (Policy pol : referencedPolicies) {
-            if (!deltaCollector.removedPolicyIds.contains(pol.getId())) {
-                deltaCollector.policies.add(pol);
-            }
-        }
-        for (Enricher enr : referencedEnrichers) {
-            if (!deltaCollector.removedEnricherIds.contains(enr.getId())) {
-                deltaCollector.enrichers.add(enr);
-            }
-        }
-        for (Feed feed : referencedFeeds) {
-            if (!deltaCollector.removedFeedIds.contains(feed.getId())) {
-                deltaCollector.feeds.add(feed);
-            }
+        for (BrooklynObject instance : referencedObjects) {
+            deltaCollector.addIfNotRemoved(instance);
         }
     }
     
@@ -344,54 +377,19 @@ public class PeriodicDeltaChangeListener implements ChangeListener {
                 if (LOG.isTraceEnabled()) LOG.trace("No changes to persist since last delta");
             } else {
                 PersisterDeltaImpl persisterDelta = new PersisterDeltaImpl();
-                for (Location location : prevDeltaCollector.locations) {
-                    try {
-                        persisterDelta.locations.add(((LocationInternal)location).getRebindSupport().getMemento());
-                    } catch (Exception e) {
-                        exceptionHandler.onGenerateMementoFailed(BrooklynObjectType.LOCATION, location, e);
-                    }
-                }
-                for (Entity entity : prevDeltaCollector.entities) {
-                    try {
-                        persisterDelta.entities.add(((EntityInternal)entity).getRebindSupport().getMemento());
-                    } catch (Exception e) {
-                        exceptionHandler.onGenerateMementoFailed(BrooklynObjectType.ENTITY, entity, e);
-                    }
-                }
-                for (Policy policy : prevDeltaCollector.policies) {
-                    try {
-                        persisterDelta.policies.add(policy.getRebindSupport().getMemento());
-                    } catch (Exception e) {
-                        exceptionHandler.onGenerateMementoFailed(BrooklynObjectType.POLICY, policy, e);
-                    }
-                }
-                for (Enricher enricher : prevDeltaCollector.enrichers) {
-                    try {
-                        persisterDelta.enrichers.add(enricher.getRebindSupport().getMemento());
-                    } catch (Exception e) {
-                        exceptionHandler.onGenerateMementoFailed(BrooklynObjectType.ENRICHER, enricher, e);
-                    }
-                }
-                for (Feed feed : prevDeltaCollector.feeds) {
-                    try {
-                        persisterDelta.feeds.add(feed.getRebindSupport().getMemento());
-                    } catch (Exception e) {
-                        exceptionHandler.onGenerateMementoFailed(BrooklynObjectType.FEED, feed, e);
+                
+                for (BrooklynObjectType type: BrooklynPersistenceUtils.STANDARD_BROOKLYN_OBJECT_TYPE_PERSISTENCE_ORDER) {
+                    for (BrooklynObject instance: prevDeltaCollector.getCollectionOfType(type)) {
+                        try {
+                            persisterDelta.add(type, ((BrooklynObjectInternal)instance).getRebindSupport().getMemento());
+                        } catch (Exception e) {
+                            exceptionHandler.onGenerateMementoFailed(type, instance, e);
+                        }
                     }
                 }
-                for (CatalogItem<?, ?> catalogItem : prevDeltaCollector.catalogItems) {
-                    try {
-                        persisterDelta.catalogItems.add(catalogItem.getRebindSupport().getMemento());
-                    } catch (Exception e) {
-                        exceptionHandler.onGenerateMementoFailed(BrooklynObjectType.CATALOG_ITEM, catalogItem, e);
-                    }
+                for (BrooklynObjectType type: BrooklynPersistenceUtils.STANDARD_BROOKLYN_OBJECT_TYPE_PERSISTENCE_ORDER) {
+                    persisterDelta.removed(type, prevDeltaCollector.getRemovedIdsOfType(type));
                 }
-                persisterDelta.removedLocationIds = prevDeltaCollector.removedLocationIds;
-                persisterDelta.removedEntityIds = prevDeltaCollector.removedEntityIds;
-                persisterDelta.removedPolicyIds = prevDeltaCollector.removedPolicyIds;
-                persisterDelta.removedEnricherIds = prevDeltaCollector.removedEnricherIds;
-                persisterDelta.removedFeedIds = prevDeltaCollector.removedFeedIds;
-                persisterDelta.removedCatalogItemIds = prevDeltaCollector.removedCatalogItemIds;
 
                 /*
                  * Need to guarantee "happens before", with any thread that subsequently reads
@@ -441,63 +439,30 @@ public class PeriodicDeltaChangeListener implements ChangeListener {
     public synchronized void onUnmanaged(BrooklynObject instance) {
         if (LOG.isTraceEnabled()) LOG.trace("onUnmanaged: {}", instance);
         if (!isStopped()) {
+            removeFromCollector(instance);
             if (instance instanceof Entity) {
                 Entity entity = (Entity) instance;
-                deltaCollector.removedEntityIds.add(entity.getId());
-                deltaCollector.entities.remove(entity);
-                
-                for (Policy policy : entity.getPolicies()) {
-                    deltaCollector.removedPolicyIds.add(policy.getId());
-                    deltaCollector.policies.remove(policy);
-                }
-                for (Enricher enricher : entity.getEnrichers()) {
-                    deltaCollector.removedEnricherIds.add(enricher.getId());
-                    deltaCollector.enrichers.remove(enricher);
-                }
-                for (Feed feed : ((EntityInternal)entity).feeds().getFeeds()) {
-                    deltaCollector.removedFeedIds.add(feed.getId());
-                    deltaCollector.feeds.remove(feed);
-                }
-            } else if (instance instanceof Location) {
-                deltaCollector.removedLocationIds.add(instance.getId());
-                deltaCollector.locations.remove(instance);
-            } else if (instance instanceof Policy) {
-                deltaCollector.removedPolicyIds.add(instance.getId());
-                deltaCollector.policies.remove(instance);
-            } else if (instance instanceof Enricher) {
-                deltaCollector.removedEnricherIds.add(instance.getId());
-                deltaCollector.enrichers.remove(instance);
-            } else if (instance instanceof Feed) {
-                deltaCollector.removedFeedIds.add(instance.getId());
-                deltaCollector.feeds.remove(instance);
-            } else if (instance instanceof CatalogItem) {
-                deltaCollector.removedCatalogItemIds.add(instance.getId());
-                deltaCollector.catalogItems.remove(instance);
-            } else {
-                throw new IllegalStateException("Unexpected brooklyn type: "+instance);
+                for (BrooklynObject adjunct : entity.getPolicies()) removeFromCollector(adjunct);
+                for (BrooklynObject adjunct : entity.getEnrichers()) removeFromCollector(adjunct);
+                for (BrooklynObject adjunct : ((EntityInternal)entity).feeds().getFeeds()) removeFromCollector(adjunct);
             }
         }
     }
+    
+    private void removeFromCollector(BrooklynObject instance) {
+        deltaCollector.remove(instance);
+    }
 
     @Override
     public synchronized void onChanged(BrooklynObject instance) {
         if (LOG.isTraceEnabled()) LOG.trace("onChanged: {}", instance);
         if (!isStopped()) {
-            if (instance instanceof Entity) {
-                deltaCollector.entities.add((Entity)instance);
-            } else if (instance instanceof Location) {
-                deltaCollector.locations.add((Location) instance);
-            } else if (instance instanceof Policy) {
-                deltaCollector.policies.add((Policy) instance);
-            } else if (instance instanceof Enricher) {
-                deltaCollector.enrichers.add((Enricher) instance);
-            } else if (instance instanceof Feed) {
-                deltaCollector.feeds.add((Feed) instance);
-            } else if (instance instanceof CatalogItem) {
-                deltaCollector.catalogItems.add((CatalogItem<?,?>) instance);
-            } else {
-                throw new IllegalStateException("Unexpected brooklyn type: "+instance);
-            }
+            deltaCollector.add(instance);
         }
     }
+    
+    public PersistenceExceptionHandler getExceptionHandler() {
+        return exceptionHandler;
+    }
+    
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/38a756b2/core/src/main/java/brooklyn/entity/rebind/PersistenceExceptionHandlerImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/PersistenceExceptionHandlerImpl.java b/core/src/main/java/brooklyn/entity/rebind/PersistenceExceptionHandlerImpl.java
index aa16710..bce5c83 100644
--- a/core/src/main/java/brooklyn/entity/rebind/PersistenceExceptionHandlerImpl.java
+++ b/core/src/main/java/brooklyn/entity/rebind/PersistenceExceptionHandlerImpl.java
@@ -82,16 +82,18 @@ public class PersistenceExceptionHandlerImpl implements PersistenceExceptionHand
         onErrorImpl(errmsg, e, prevFailedPersisters.add(id));
     }
     
-    protected void onErrorImpl(String errmsg, Exception e, boolean isRepeat) {
+    protected void onErrorImpl(String errmsg, Exception e, boolean isNew) {
+        // TODO the default behaviour is simply to warn; we should have a "fail_at_end" behaviour,
+        // and a way for other subsystems to tune in to such failures
         Exceptions.propagateIfFatal(e);
         if (isActive()) {
-            if (isRepeat) {
+            if (!isNew) {
                 if (LOG.isDebugEnabled()) LOG.debug("Repeating problem: "+errmsg, e);
             } else {
                 LOG.warn("Problem: "+errmsg, e);
             }
         } else {
-            if (isRepeat) {
+            if (!isNew) {
                 if (LOG.isTraceEnabled()) LOG.trace("Repeating problem: "+errmsg+"; but no longer active (ignoring)", e);
             } else {
                 if (LOG.isDebugEnabled()) LOG.debug("Problem: "+errmsg+"; but no longer active (ignoring)", e);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/38a756b2/core/src/main/java/brooklyn/entity/rebind/PersisterDeltaImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/PersisterDeltaImpl.java b/core/src/main/java/brooklyn/entity/rebind/PersisterDeltaImpl.java
index c971a2f..891e9db 100644
--- a/core/src/main/java/brooklyn/entity/rebind/PersisterDeltaImpl.java
+++ b/core/src/main/java/brooklyn/entity/rebind/PersisterDeltaImpl.java
@@ -19,8 +19,11 @@
 package brooklyn.entity.rebind;
 
 import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
 
 import brooklyn.mementos.BrooklynMementoPersister.Delta;
+import brooklyn.mementos.BrooklynMementoPersister.MutableDelta;
 import brooklyn.mementos.CatalogItemMemento;
 import brooklyn.mementos.EnricherMemento;
 import brooklyn.mementos.EntityMemento;
@@ -29,69 +32,13 @@ import brooklyn.mementos.LocationMemento;
 import brooklyn.mementos.Memento;
 import brooklyn.mementos.PolicyMemento;
 
+import com.google.common.annotations.Beta;
+import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
 
-public class PersisterDeltaImpl implements Delta {
+public class PersisterDeltaImpl implements Delta, MutableDelta {
     
-    public static Builder builder() {
-        return new Builder();
-    }
-    
-    public static class Builder {
-        private final PersisterDeltaImpl delta = new PersisterDeltaImpl();
-
-        public Builder locations(Collection<? extends LocationMemento> vals) {
-            delta.locations.addAll(vals);
-            return this;
-        }
-        public Builder entities(Collection<? extends EntityMemento> vals) {
-            delta.entities.addAll(vals);
-            return this;
-        }
-        public Builder policies(Collection<? extends PolicyMemento> vals) {
-            delta.policies.addAll(vals);
-            return this;
-        }
-        public Builder enrichers(Collection<? extends EnricherMemento> vals) {
-            delta.enrichers.addAll(vals);
-            return this;
-        }
-        public Builder feeds(Collection<? extends FeedMemento> vals) {
-            delta.feeds.addAll(vals);
-            return this;
-        }
-        public Builder catalogItems(Collection<? extends CatalogItemMemento> vals) {
-            delta.catalogItems.addAll(vals);
-            return this;
-        }
-        public Builder removedLocationIds(Collection<String> vals) {
-            delta.removedLocationIds.addAll(vals);
-            return this;
-        }
-        public Builder removedEntityIds(Collection<String> vals) {
-            delta.removedEntityIds.addAll(vals);
-            return this;
-        }
-        public Builder removedPolicyIds(Collection<String> vals) {
-            delta.removedPolicyIds.addAll(vals);
-            return this;
-        }
-        public Builder removedEnricherIds(Collection<String> vals) {
-            delta.removedEnricherIds.addAll(vals);
-            return this;
-        }
-        public Builder removedFeedIds(Collection<String> vals) {
-            delta.removedFeedIds.addAll(vals);
-            return this;
-        }
-        public Builder removedCatalogItemIds(Collection<String> vals) {
-            delta.removedCatalogItemIds.addAll(vals);
-            return this;
-        }
-        public Delta build() {
-            return delta;
-        }
-    }
+    // use multiset?
     
     Collection<LocationMemento> locations = Sets.newLinkedHashSet();
     Collection<EntityMemento> entities = Sets.newLinkedHashSet();
@@ -99,6 +46,7 @@ public class PersisterDeltaImpl implements Delta {
     Collection<EnricherMemento> enrichers = Sets.newLinkedHashSet();
     Collection<FeedMemento> feeds = Sets.newLinkedHashSet();
     Collection<CatalogItemMemento> catalogItems = Sets.newLinkedHashSet();
+    
     Collection<String> removedLocationIds = Sets.newLinkedHashSet();
     Collection<String> removedEntityIds = Sets.newLinkedHashSet();
     Collection<String> removedPolicyIds = Sets.newLinkedHashSet();
@@ -108,73 +56,82 @@ public class PersisterDeltaImpl implements Delta {
 
     @Override
     public Collection<LocationMemento> locations() {
-        return locations;
+        return Collections.unmodifiableCollection(locations);
     }
 
     @Override
     public Collection<EntityMemento> entities() {
-        return entities;
+        return Collections.unmodifiableCollection(entities);
     }
 
     @Override
     public Collection<PolicyMemento> policies() {
-        return policies;
+        return Collections.unmodifiableCollection(policies);
     }
 
     @Override
     public Collection<EnricherMemento> enrichers() {
-        return enrichers;
+        return Collections.unmodifiableCollection(enrichers);
     }
     
     @Override
     public Collection<FeedMemento> feeds() {
-        return feeds;
+        return Collections.unmodifiableCollection(feeds);
     }
 
     @Override
     public Collection<CatalogItemMemento> catalogItems() {
-        return catalogItems;
+        return Collections.unmodifiableCollection(catalogItems);
     }
 
     @Override
     public Collection<String> removedLocationIds() {
-        return removedLocationIds;
+        return Collections.unmodifiableCollection(removedLocationIds);
     }
 
     @Override
     public Collection<String> removedEntityIds() {
-        return removedEntityIds;
+        return Collections.unmodifiableCollection(removedEntityIds);
     }
     
     @Override
     public Collection<String> removedPolicyIds() {
-        return removedPolicyIds;
+        return Collections.unmodifiableCollection(removedPolicyIds);
     }
     
     @Override
     public Collection<String> removedEnricherIds() {
-        return removedEnricherIds;
+        return Collections.unmodifiableCollection(removedEnricherIds);
     }
     
     @Override
     public Collection<String> removedFeedIds() {
-        return removedFeedIds;
+        return Collections.unmodifiableCollection(removedFeedIds);
     }
 
     @Override
     public Collection<String> removedCatalogItemIds() {
-        return removedCatalogItemIds;
+        return Collections.unmodifiableCollection(removedCatalogItemIds);
     }
-    
+
     @Override
     public Collection<? extends Memento> getObjectsOfType(BrooklynObjectType type) {
+        return Collections.unmodifiableCollection(getMutableObjectsOfType(type));
+    }
+    
+    @SuppressWarnings("unchecked")
+    @Beta
+    private Collection<Memento> getMutableUncheckedObjectsOfType(BrooklynObjectType type) {
+        return (Collection<Memento>)getMutableObjectsOfType(type);
+    }
+    private Collection<? extends Memento> getMutableObjectsOfType(BrooklynObjectType type) {
         switch (type) {
-        case ENTITY: return entities();
-        case LOCATION: return locations();
-        case POLICY: return policies();
-        case ENRICHER: return enrichers();
-        case FEED: return feeds();
-        case CATALOG_ITEM: return catalogItems();
+        case ENTITY: return entities;
+        case LOCATION: return locations;
+        case POLICY: return policies;
+        case ENRICHER: return enrichers;
+        case FEED: return feeds;
+        case CATALOG_ITEM: return catalogItems;
         case UNKNOWN: 
         default:
             throw new IllegalArgumentException(type+" not supported");
@@ -182,17 +139,35 @@ public class PersisterDeltaImpl implements Delta {
     }
     
     @Override
-    public Collection<String> getRemovedObjectsOfType(BrooklynObjectType type) {
+    public Collection<String> getRemovedIdsOfType(BrooklynObjectType type) {
+        return Collections.unmodifiableCollection(getRemovedIdsOfTypeMutable(type));
+    }
+    
+    private Collection<String> getRemovedIdsOfTypeMutable(BrooklynObjectType type) {
         switch (type) {
-        case ENTITY: return removedEntityIds();
-        case LOCATION: return removedLocationIds();
-        case POLICY: return removedPolicyIds();
-        case ENRICHER: return removedEnricherIds();
-        case FEED: return removedFeedIds();
-        case CATALOG_ITEM: return removedCatalogItemIds();
+        case ENTITY: return removedEntityIds;
+        case LOCATION: return removedLocationIds;
+        case POLICY: return removedPolicyIds;
+        case ENRICHER: return removedEnricherIds;
+        case FEED: return removedFeedIds;
+        case CATALOG_ITEM: return removedCatalogItemIds;
         case UNKNOWN: 
         default:
             throw new IllegalArgumentException(type+" not supported");
         }
     }
+
+    public void add(BrooklynObjectType type, Memento memento) {
+        getMutableUncheckedObjectsOfType(type).add(memento);
+    }
+
+    @Override
+    public void addAll(BrooklynObjectType type, Iterable<? extends Memento> mementos) {
+        Iterables.addAll(getMutableUncheckedObjectsOfType(type), mementos);
+    }
+    
+    public void removed(BrooklynObjectType type, Set<String> removedIdsOfType) {
+        getRemovedIdsOfTypeMutable(type).addAll(removedIdsOfType);    
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/38a756b2/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java b/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
index 67263c7..23bbf26 100644
--- a/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
+++ b/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
@@ -57,6 +57,7 @@ import brooklyn.entity.proxying.InternalFactory;
 import brooklyn.entity.proxying.InternalLocationFactory;
 import brooklyn.entity.proxying.InternalPolicyFactory;
 import brooklyn.entity.rebind.persister.BrooklynMementoPersisterToObjectStore;
+import brooklyn.entity.rebind.persister.BrooklynPersistenceUtils;
 import brooklyn.event.feed.AbstractFeed;
 import brooklyn.internal.BrooklynFeatureEnablement;
 import brooklyn.location.Location;
@@ -396,8 +397,20 @@ public class RebindManagerImpl implements RebindManager {
     @Override
     @VisibleForTesting
     public void forcePersistNow() {
-//        XXX persistenceStoreAccess.checkpoint(memento, exceptionHandler);
-        persistenceRealChangeListener.persistNow();
+        forcePersistNow(false, null);
+    }
+    @Override
+    @VisibleForTesting
+    public void forcePersistNow(boolean full, PersistenceExceptionHandler exceptionHandler) {
+        if (full) {
+            BrooklynMementoRawData memento = BrooklynPersistenceUtils.newFullMemento(managementContext);
+            if (exceptionHandler==null) {
+                exceptionHandler = persistenceRealChangeListener.getExceptionHandler();
+            }
+            persistenceStoreAccess.checkpoint(memento, exceptionHandler);
+        } else {
+            persistenceRealChangeListener.persistNow();
+        }
     }
     
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/38a756b2/core/src/main/java/brooklyn/entity/rebind/persister/AbstractBrooklynMementoPersister.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/persister/AbstractBrooklynMementoPersister.java b/core/src/main/java/brooklyn/entity/rebind/persister/AbstractBrooklynMementoPersister.java
index 42643ab..d296e35 100644
--- a/core/src/main/java/brooklyn/entity/rebind/persister/AbstractBrooklynMementoPersister.java
+++ b/core/src/main/java/brooklyn/entity/rebind/persister/AbstractBrooklynMementoPersister.java
@@ -34,8 +34,7 @@ import brooklyn.mementos.LocationMemento;
 import brooklyn.mementos.PolicyMemento;
 
 /**
- * @deprecated since 0.7.0 for production use {@link BrooklynMementoPersisterToMultiFile} instead; 
- *             this class will be merged with {@link BrooklynMementoPersisterInMemory} in test code.
+ * @deprecated since 0.7.0 for production use {@link BrooklynMementoPersisterToObjectStore} instead 
  */
 @Deprecated
 public abstract class AbstractBrooklynMementoPersister implements BrooklynMementoPersister {
@@ -92,6 +91,11 @@ public abstract class AbstractBrooklynMementoPersister implements BrooklynMement
     public void checkpoint(BrooklynMemento newMemento, PersistenceExceptionHandler exceptionHandler) {
         memento.reset(checkNotNull(newMemento, "memento"));
     }
+    
+    public void checkpoint(BrooklynMementoRawData newMemento, PersistenceExceptionHandler exceptionHandler) {
+        throw new IllegalStateException("Not supported; use "+BrooklynMementoPersisterToObjectStore.class);
+    }
+    
 
     @Override
     public void delta(Delta delta, PersistenceExceptionHandler exceptionHanlder) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/38a756b2/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterInMemory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterInMemory.java b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterInMemory.java
index 902b57e..dbb1e52 100644
--- a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterInMemory.java
+++ b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterInMemory.java
@@ -59,7 +59,7 @@ import com.google.common.base.Optional;
 import com.google.common.base.Throwables;
 
 /**
- * @deprecated since 0.7.0 for production use {@link BrooklynMementoPersisterToMultiFile} instead; class be moved to tests
+ * @deprecated since 0.7.0 for production use {@link BrooklynMementoPersisterToObjectStore} instead; class be moved to tests
  * <code>
  * new BrooklynMementoPersisterToObjectStore(new InMemoryObjectStore(), classLoader)
  * </code>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/38a756b2/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToMultiFile.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToMultiFile.java b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToMultiFile.java
index 74817c5..d3318b3 100644
--- a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToMultiFile.java
+++ b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToMultiFile.java
@@ -390,6 +390,12 @@ public class BrooklynMementoPersisterToMultiFile implements BrooklynMementoPersi
         for (CatalogItemMemento m : newMemento.getCatalogItemMementos().values()) {
             persist(m);
         }
+        LOG.warn("Using legacy persister; feeds will not be persisted");
+    }
+    
+    @Override
+    public void checkpoint(BrooklynMementoRawData newMemento, PersistenceExceptionHandler exceptionHandler) {
+        throw new IllegalStateException("Not supported; use "+BrooklynMementoPersisterToObjectStore.class);
     }
     
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/38a756b2/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToObjectStore.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToObjectStore.java b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToObjectStore.java
index cbf6ccb..115fecc 100644
--- a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToObjectStore.java
+++ b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToObjectStore.java
@@ -71,7 +71,6 @@ import com.google.common.annotations.Beta;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Objects;
 import com.google.common.base.Stopwatch;
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
 import com.google.common.util.concurrent.Futures;
@@ -100,10 +99,6 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
             "Maximum number of attempts to serialize a memento (e.g. if first attempts fail because of concurrent modifications of an entity)", 
             5);
 
-    static final List<BrooklynObjectType> PERSISTED_OBJECT_TYPES_IN_ORDER = ImmutableList.of( 
-        BrooklynObjectType.ENTITY, BrooklynObjectType.LOCATION, BrooklynObjectType.POLICY,
-        BrooklynObjectType.ENRICHER, BrooklynObjectType.FEED, BrooklynObjectType.CATALOG_ITEM);
-
     private final PersistenceObjectStore objectStore;
     private final MementoSerializer<Object> serializerWithStandardClassLoader;
 
@@ -251,7 +246,7 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
 
         Stopwatch stopwatch = Stopwatch.createStarted();
         try {
-            for (BrooklynObjectType type: PERSISTED_OBJECT_TYPES_IN_ORDER)
+            for (BrooklynObjectType type: BrooklynPersistenceUtils.STANDARD_BROOKLYN_OBJECT_TYPE_PERSISTENCE_ORDER)
                 subPathDataBuilder.putAll(type, makeIdSubPathMap(objectStore.listContentsWithSubPath(type.getSubPathName())));
             
         } catch (Exception e) {
@@ -459,7 +454,7 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
             }
         }
         
-        for (BrooklynObjectType type: PERSISTED_OBJECT_TYPES_IN_ORDER) {
+        for (BrooklynObjectType type: BrooklynPersistenceUtils.STANDARD_BROOKLYN_OBJECT_TYPE_PERSISTENCE_ORDER) {
             for (final Map.Entry<String,String> entry : rawData.getObjectsOfType(type).entrySet()) {
                 futures.add(executor.submit(new VisitorWrapper(type, entry)));
             }
@@ -501,6 +496,8 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
         }
     }
     
+    /** See {@link BrooklynPersistenceUtils} for conveniences for using this method. */
+    @Override
     @Beta
     public void checkpoint(BrooklynMementoRawData newMemento, PersistenceExceptionHandler exceptionHandler) {
         checkWritesAllowed();
@@ -516,7 +513,7 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
             Stopwatch stopwatch = Stopwatch.createStarted();
             List<ListenableFuture<?>> futures = Lists.newArrayList();
             
-            for (BrooklynObjectType type: PERSISTED_OBJECT_TYPES_IN_ORDER) {
+            for (BrooklynObjectType type: BrooklynPersistenceUtils.STANDARD_BROOKLYN_OBJECT_TYPE_PERSISTENCE_ORDER) {
                 for (Map.Entry<String, String> entry : newMemento.getObjectsOfType(type).entrySet()) {
                     futures.add(asyncPersist(type.getSubPathName(), type, entry.getKey(), entry.getValue(), exceptionHandler));
                 }
@@ -541,14 +538,14 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
     public void checkpoint(BrooklynMemento newMemento, PersistenceExceptionHandler exceptionHandler) {
         checkWritesAllowed();
 
-        Delta delta = PersisterDeltaImpl.builder()
-                .entities(newMemento.getEntityMementos().values())
-                .locations(newMemento.getLocationMementos().values())
-                .policies(newMemento.getPolicyMementos().values())
-                .enrichers(newMemento.getEnricherMementos().values())
-                .feeds(newMemento.getFeedMementos().values())
-                .catalogItems(newMemento.getCatalogItemMementos().values())
-                .build();
+        MutableDelta delta = new PersisterDeltaImpl();
+        delta.addAll(BrooklynObjectType.ENTITY, newMemento.getEntityMementos().values());
+        delta.addAll(BrooklynObjectType.LOCATION, newMemento.getLocationMementos().values());
+        delta.addAll(BrooklynObjectType.POLICY, newMemento.getPolicyMementos().values());
+        delta.addAll(BrooklynObjectType.ENRICHER, newMemento.getEnricherMementos().values());
+        delta.addAll(BrooklynObjectType.FEED, newMemento.getFeedMementos().values());
+        delta.addAll(BrooklynObjectType.CATALOG_ITEM, newMemento.getCatalogItemMementos().values());
+        
         Stopwatch stopwatch = deltaImpl(delta, exceptionHandler);
         
         if (LOG.isDebugEnabled()) LOG.debug("Checkpointed entire memento in {}", Time.makeTimeStringRounded(stopwatch));
@@ -587,13 +584,13 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
             Stopwatch stopwatch = Stopwatch.createStarted();
             List<ListenableFuture<?>> futures = Lists.newArrayList();
             
-            for (BrooklynObjectType type: PERSISTED_OBJECT_TYPES_IN_ORDER) {
+            for (BrooklynObjectType type: BrooklynPersistenceUtils.STANDARD_BROOKLYN_OBJECT_TYPE_PERSISTENCE_ORDER) {
                 for (Memento entity : delta.getObjectsOfType(type)) {
                     futures.add(asyncPersist(type.getSubPathName(), entity, exceptionHandler));
                 }
             }
-            for (BrooklynObjectType type: PERSISTED_OBJECT_TYPES_IN_ORDER) {
-                for (String id : delta.getRemovedObjectsOfType(type)) {
+            for (BrooklynObjectType type: BrooklynPersistenceUtils.STANDARD_BROOKLYN_OBJECT_TYPE_PERSISTENCE_ORDER) {
+                for (String id : delta.getRemovedIdsOfType(type)) {
                     futures.add(asyncDelete(type.getSubPathName(), id, exceptionHandler));
                 }
             }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/38a756b2/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynPersistenceUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynPersistenceUtils.java b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynPersistenceUtils.java
index e8bd336..373ce1d 100644
--- a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynPersistenceUtils.java
+++ b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynPersistenceUtils.java
@@ -18,6 +18,8 @@
  */
 package brooklyn.entity.rebind.persister;
 
+import java.util.List;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -27,6 +29,7 @@ import brooklyn.config.BrooklynServerConfig;
 import brooklyn.entity.Entity;
 import brooklyn.entity.Feed;
 import brooklyn.entity.basic.EntityInternal;
+import brooklyn.entity.rebind.BrooklynObjectType;
 import brooklyn.entity.rebind.PersistenceExceptionHandler;
 import brooklyn.entity.rebind.PersistenceExceptionHandlerImpl;
 import brooklyn.entity.rebind.dto.MementosGenerators;
@@ -51,12 +54,19 @@ import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;
 import brooklyn.util.time.Time;
 
+import com.google.common.annotations.Beta;
 import com.google.common.base.Stopwatch;
+import com.google.common.collect.ImmutableList;
 
 public class BrooklynPersistenceUtils {
 
     private static final Logger log = LoggerFactory.getLogger(BrooklynPersistenceUtils.class);
     
+    @Beta
+    public static final List<BrooklynObjectType> STANDARD_BROOKLYN_OBJECT_TYPE_PERSISTENCE_ORDER = ImmutableList.of( 
+        BrooklynObjectType.ENTITY, BrooklynObjectType.LOCATION, BrooklynObjectType.POLICY,
+        BrooklynObjectType.ENRICHER, BrooklynObjectType.FEED, BrooklynObjectType.CATALOG_ITEM);
+
     /** Creates a {@link PersistenceObjectStore} for general-purpose use. */
     public static PersistenceObjectStore newPersistenceObjectStore(ManagementContext managementContext,
             String locationSpec, String locationContainer) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/38a756b2/core/src/main/java/brooklyn/management/internal/NonDeploymentManagementContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/internal/NonDeploymentManagementContext.java b/core/src/main/java/brooklyn/management/internal/NonDeploymentManagementContext.java
index 1343e90..20755dd 100644
--- a/core/src/main/java/brooklyn/management/internal/NonDeploymentManagementContext.java
+++ b/core/src/main/java/brooklyn/management/internal/NonDeploymentManagementContext.java
@@ -523,6 +523,10 @@ public class NonDeploymentManagementContext implements ManagementContextInternal
             throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
         }
         @Override
+        public void forcePersistNow(boolean full, PersistenceExceptionHandler exceptionHandler) {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+        @Override
         public BrooklynMementoRawData retrieveMementoRawData() {
             throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
         }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/38a756b2/core/src/test/java/brooklyn/entity/rebind/RebindCatalogItemTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindCatalogItemTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindCatalogItemTest.java
index 8d44e3d..93460dc 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindCatalogItemTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindCatalogItemTest.java
@@ -56,9 +56,9 @@ public class RebindCatalogItemTest extends RebindTestFixtureWithApp {
     @BeforeMethod(alwaysRun = true)
     @Override
     public void setUp() throws Exception {
-        super.setUp();
         catalogPersistenceWasEnabled = BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_CATALOG_PERSISTENCE_PROPERTY);
         BrooklynFeatureEnablement.enable(BrooklynFeatureEnablement.FEATURE_CATALOG_PERSISTENCE_PROPERTY);
+        super.setUp();
         BasicCampPlatform platform = new CampPlatformWithJustBrooklynMgmt(origManagementContext);
         MockWebPlatform.populate(platform, TestAppAssemblyInstantiator.class);
         origApp.createAndManageChild(EntitySpec.create(TestEntity.class));
@@ -149,7 +149,7 @@ public class RebindCatalogItemTest extends RebindTestFixtureWithApp {
         // Must make sure that the original catalogue item is not managed and unmanaged in the same
         // persistence window. Because BrooklynMementoPersisterToObjectStore applies writes/deletes
         // asynchronously the winner is down to a race and the test might pass or fail.
-        origManagementContext.getRebindManager().forcePersistNow();
+        origManagementContext.getRebindManager().forcePersistNow(false, null);
         origManagementContext.getCatalog().deleteCatalogItem(toRemove.getSymbolicName(), toRemove.getVersion());
         assertEquals(Iterables.size(origManagementContext.getCatalog().getCatalogItems()), 0);
         rebindAndAssertCatalogsAreEqual();