You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by an...@apache.org on 2015/02/03 12:41:35 UTC

[04/17] incubator-brooklyn git commit: refactor RebindManager to have a RebindIteration

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/55b5f65e/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 8556e61..b1a02c1 100644
--- a/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
+++ b/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
@@ -20,105 +20,53 @@ package brooklyn.entity.rebind;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
-import java.util.Collection;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import java.util.concurrent.Callable;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import brooklyn.basic.AbstractBrooklynObject;
 import brooklyn.basic.BrooklynObject;
-import brooklyn.basic.BrooklynObjectInternal;
-import brooklyn.catalog.BrooklynCatalog;
-import brooklyn.catalog.CatalogItem;
-import brooklyn.catalog.CatalogLoadMode;
-import brooklyn.catalog.internal.BasicBrooklynCatalog;
-import brooklyn.catalog.internal.CatalogUtils;
-import brooklyn.config.BrooklynLogging;
-import brooklyn.config.BrooklynLogging.LoggingLevel;
 import brooklyn.config.BrooklynServerConfig;
 import brooklyn.config.ConfigKey;
 import brooklyn.enricher.basic.AbstractEnricher;
 import brooklyn.entity.Application;
-import brooklyn.entity.Entity;
-import brooklyn.entity.Feed;
-import brooklyn.entity.basic.AbstractApplication;
-import brooklyn.entity.basic.AbstractEntity;
 import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.basic.EntityInternal;
-import brooklyn.entity.proxying.InternalEntityFactory;
-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.entity.rebind.persister.BrooklynPersistenceUtils.CreateBackupMode;
 import brooklyn.entity.rebind.persister.PersistenceActivityMetrics;
-import brooklyn.event.feed.AbstractFeed;
 import brooklyn.internal.BrooklynFeatureEnablement;
-import brooklyn.location.Location;
-import brooklyn.location.basic.AbstractLocation;
-import brooklyn.location.basic.LocationInternal;
 import brooklyn.management.ExecutionContext;
 import brooklyn.management.ManagementContext;
 import brooklyn.management.Task;
-import brooklyn.management.classloading.BrooklynClassLoadingContext;
 import brooklyn.management.ha.HighAvailabilityManagerImpl;
 import brooklyn.management.ha.ManagementNodeState;
 import brooklyn.management.ha.MementoCopyMode;
-import brooklyn.management.internal.EntityManagerInternal;
-import brooklyn.management.internal.LocationManagerInternal;
 import brooklyn.management.internal.ManagementContextInternal;
 import brooklyn.management.internal.ManagementTransitionInfo.ManagementTransitionMode;
-import brooklyn.mementos.BrooklynMemento;
-import brooklyn.mementos.BrooklynMementoManifest;
-import brooklyn.mementos.BrooklynMementoManifest.EntityMementoManifest;
 import brooklyn.mementos.BrooklynMementoPersister;
-import brooklyn.mementos.BrooklynMementoPersister.LookupContext;
 import brooklyn.mementos.BrooklynMementoRawData;
-import brooklyn.mementos.CatalogItemMemento;
-import brooklyn.mementos.EnricherMemento;
-import brooklyn.mementos.EntityMemento;
-import brooklyn.mementos.FeedMemento;
-import brooklyn.mementos.LocationMemento;
-import brooklyn.mementos.Memento;
-import brooklyn.mementos.PolicyMemento;
 import brooklyn.mementos.TreeNode;
-import brooklyn.policy.Enricher;
-import brooklyn.policy.Policy;
-import brooklyn.policy.basic.AbstractPolicy;
-import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.QuorumCheck;
 import brooklyn.util.collections.QuorumCheck.QuorumChecks;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.exceptions.RuntimeInterruptedException;
-import brooklyn.util.flags.FlagUtils;
-import brooklyn.util.guava.Maybe;
-import brooklyn.util.javalang.Reflections;
 import brooklyn.util.task.BasicExecutionContext;
 import brooklyn.util.task.ScheduledTask;
 import brooklyn.util.task.Tasks;
-import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;
-import brooklyn.util.time.Time;
 
-import com.google.common.base.Preconditions;
 import com.google.common.annotations.Beta;
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Optional;
-import com.google.common.base.Stopwatch;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
 
 /** Manages the persistence/rebind process.
  * <p>
@@ -129,7 +77,6 @@ import com.google.common.collect.Sets;
 public class RebindManagerImpl implements RebindManager {
 
     // TODO Use ImmediateDeltaChangeListener if the period is set to 0?
-    // But for MultiFile persister, that is still async
     
     public static final ConfigKey<RebindFailureMode> DANGLING_REFERENCE_FAILURE_MODE =
             ConfigKeys.newConfigKey(RebindFailureMode.class, "rebind.failureMode.danglingRef",
@@ -165,14 +112,14 @@ public class RebindManagerImpl implements RebindManager {
     private volatile boolean readOnlyRunning = false;
     private volatile ScheduledTask readOnlyTask = null;
     private transient Semaphore rebindActive = new Semaphore(1);
-    private transient int readOnlyRebindCount = Integer.MIN_VALUE;
+    private transient AtomicInteger readOnlyRebindCount = new AtomicInteger(Integer.MIN_VALUE);
     
     private volatile BrooklynMementoPersister persistenceStoreAccess;
 
-    private final boolean persistPoliciesEnabled;
-    private final boolean persistEnrichersEnabled;
-    private final boolean persistFeedsEnabled;
-    private final boolean persistCatalogItemsEnabled;
+    final boolean persistPoliciesEnabled;
+    final boolean persistEnrichersEnabled;
+    final boolean persistFeedsEnabled;
+    final boolean persistCatalogItemsEnabled;
     
     private RebindFailureMode danglingRefFailureMode;
     private RebindFailureMode rebindFailureMode;
@@ -229,6 +176,10 @@ public class RebindManagerImpl implements RebindManager {
                 new Object[]{this, persistPoliciesEnabled, persistEnrichersEnabled, persistFeedsEnabled, persistCatalogItemsEnabled});
     }
 
+    public ManagementContextInternal getManagementContext() {
+        return managementContext;
+    }
+    
     /**
      * Must be called before setPerister()
      */
@@ -264,6 +215,11 @@ public class RebindManagerImpl implements RebindManager {
         if (persistenceStoreAccess != null && persistenceStoreAccess != val) {
             throw new IllegalStateException("Dynamically changing persister is not supported: old="+persistenceStoreAccess+"; new="+val);
         }
+        if (persistenceRealChangeListener!=null) {
+            // TODO should probably throw here, but previously we have not -- so let's log for now to be sure it's not happening
+            LOG.warn("Persister reset after listeners have been set", new Throwable("Source of persister reset"));
+        }
+        
         this.persistenceStoreAccess = checkNotNull(val, "persister");
         
         this.persistenceRealChangeListener = new PeriodicDeltaChangeListener(managementContext.getServerExecutionContext(), persistenceStoreAccess, exceptionHandler, persistMetrics, periodicPersistPeriod);
@@ -292,7 +248,7 @@ public class RebindManagerImpl implements RebindManager {
             }
         }
         persistenceRunning = true;
-        readOnlyRebindCount = Integer.MIN_VALUE;
+        readOnlyRebindCount.set(Integer.MIN_VALUE);
         persistenceStoreAccess.enableWriteAccess();
         if (persistenceRealChangeListener != null) persistenceRealChangeListener.start();
     }
@@ -326,7 +282,7 @@ public class RebindManagerImpl implements RebindManager {
         if (persistenceStoreAccess != null) persistenceStoreAccess.disableWriteAccess(true);
         
         readOnlyRunning = true;
-        readOnlyRebindCount = 0;
+        readOnlyRebindCount.set(0);
 
         try {
             rebind(null, null, mode);
@@ -533,596 +489,18 @@ public class RebindManagerImpl implements RebindManager {
     }
     
     protected List<Application> rebindImpl(final ClassLoader classLoader, final RebindExceptionHandler exceptionHandler, ManagementNodeState mode) {
-        checkNotNull(classLoader, "classLoader");
-
-        try {
-            rebindActive.acquire();
-        } catch (InterruptedException e1) { Exceptions.propagate(e1); }
-        RebindTracker.setRebinding();
-        if (ManagementNodeState.isHotProxy(mode))
-            readOnlyRebindCount++;
-
-        Stopwatch timer = Stopwatch.createStarted();
-        try {
-            Reflections reflections = new Reflections(classLoader);
-            RebindContextImpl rebindContext = new RebindContextImpl(exceptionHandler, classLoader);
-            
-            exceptionHandler.onStart(rebindContext);
-            
-            if (mode==ManagementNodeState.HOT_STANDBY || mode==ManagementNodeState.HOT_BACKUP) {
-                rebindContext.setAllReadOnly();
-            } else {
-                Preconditions.checkState(mode==ManagementNodeState.MASTER, "Must be either master or read only to rebind (mode "+mode+")");
-            }
-            
-            LookupContext realLookupContext = new RebindContextLookupContext(managementContext, rebindContext, exceptionHandler);
-            rebindContext.setLookupContext(realLookupContext);
-            
-            // Mutli-phase deserialization.
-            //
-            //  1. deserialize just the "manifest" to find all instances (and their types).
-            //  2. instantiate and reconstruct catalog items
-            //  3. instantiate entities+locations so that inter-entity references can subsequently be set during deserialize (and entity config/state is set).
-            //  4. deserialize the memento
-            //  5. instantiate policies+enricherss+feeds (could perhaps merge this with (3), depending how they are implemented)
-            //  6. reconstruct the entities etc (i.e. calling rebind() on the already-instantiated instances)
-            //  7. add policies+enrichers+feeds to all the entities.
-            //  8. manage the entities
-            
-            // TODO if underlying data-store is changed between first and second manifest read (e.g. to add an
-            // entity), then second phase might try to reconstitute an entity that has not been put in
-            // the rebindContext. This should not affect normal production usage, because rebind is run
-            // against a data-store that is not being written to by other brooklyn instance(s).
-
-            // TODO Rebinding to code in OSGi bundles:
-            // Inferring the catalog item id context:
-            //   * most of the time the creator will be passing "my catalog item id" 
-            //     (or API could also take "BrooklynObject me" as a creation context and the 
-            //     receiver query the creator's catalog item id)
-            //   * look at the context entity of Tasks.current() (if set)
-            //   * propagate the catalog item id when doing setEntity, addChild
-            //   * when none of the above work (or they are wrong) let the user specify the catalog item
-            //
-            //  Precedence of setting the catalog item ID:
-            //   1. User-supplied catalog item ID.
-            //   2. Creating from a catalog item - all items resolved during the creation of a spec
-            //      from a catalog item receive the catalog item's ID as context.
-            //   3. When using the Java API for creating specs get the catalog item ID from the
-            //      context entity of the Tasks.current() task.
-            //   4. Propagate the context catalog item ID to children, adjuncts if they don't have one already.
-
-            //
-            // PHASE ONE
-            //
-
-            //The manifest contains full catalog items mementos. Reading them at this stage means that
-            //we don't support references to entities/locations withing tags.
-            
-            LOG.debug("Rebinding ("+mode+
-                (readOnlyRebindCount>Integer.MIN_VALUE ? ", iteration "+readOnlyRebindCount : "")+
-                ") from "+getPersister().getBackingStoreDescription()+"...");
-
-            BrooklynMementoRawData mementoRawData = persistenceStoreAccess.loadMementoRawData(exceptionHandler);
-            BrooklynMementoManifest mementoManifest = persistenceStoreAccess.loadMementoManifest(mementoRawData, exceptionHandler);
-
-            boolean overwritingMaster = false;
-            boolean isEmpty = mementoManifest.isEmpty();
-            if (mode!=ManagementNodeState.HOT_STANDBY && mode!=ManagementNodeState.HOT_BACKUP) {
-                if (!isEmpty) { 
-                    LOG.info("Rebinding from "+getPersister().getBackingStoreDescription()+" for "+Strings.toLowerCase(Strings.toString(mode))+" "+managementContext.getManagementNodeId()+"...");
-                } else {
-                    LOG.info("Rebind check: no existing state; will persist new items to "+getPersister().getBackingStoreDescription());
-                }
-                
-                if (!managementContext.getEntityManager().getEntities().isEmpty() || !managementContext.getLocationManager().getLocations().isEmpty()) {
-                    // this is discouraged if we were already master
-                    Entity anEntity = Iterables.getFirst(managementContext.getEntityManager().getEntities(), null);
-                    if (anEntity!=null && !((EntityInternal)anEntity).getManagementSupport().isReadOnly()) {
-                        overwritingMaster = true;
-                        LOG.warn("Rebind requested for "+mode+" node "+managementContext.getManagementNodeId()+" "
-                            + "when it already has active state; discouraged, "
-                            + "will likely overwrite: "+managementContext.getEntityManager().getEntities()+" and "+managementContext.getLocationManager().getLocations()+" and more");
-                    }
-                }
-            }
-
-            //
-            // PHASE TWO - build catalog so we can load other things
-            //
-            
-            BrooklynObjectInstantiator instantiator = new BrooklynObjectInstantiator(classLoader, rebindContext, reflections);
-            
-            // Instantiate catalog items
-            if (persistCatalogItemsEnabled) {
-                logRebindingDebug("RebindManager instantiating catalog items: {}", mementoManifest.getCatalogItemIds());
-                for (CatalogItemMemento catalogItemMemento : mementoManifest.getCatalogItemMementos().values()) {
-                    if (LOG.isDebugEnabled()) LOG.debug("RebindManager instantiating catalog item {}", catalogItemMemento);
-                    try {
-                        CatalogItem<?, ?> catalogItem = instantiator.newCatalogItem(catalogItemMemento);
-                        rebindContext.registerCatalogItem(catalogItemMemento.getId(), catalogItem);
-                    } catch (Exception e) {
-                        exceptionHandler.onCreateFailed(BrooklynObjectType.CATALOG_ITEM, catalogItemMemento.getId(), catalogItemMemento.getType(), e);
-                    }
-                }
-            } else {
-                logRebindingDebug("Not rebinding catalog; feature disabled: {}", mementoManifest.getCatalogItemIds());
-            }
-
-            // Reconstruct catalog entries
-            if (persistCatalogItemsEnabled) {
-                logRebindingDebug("RebindManager reconstructing catalog items");
-                for (CatalogItemMemento catalogItemMemento : mementoManifest.getCatalogItemMementos().values()) {
-                    CatalogItem<?, ?> item = rebindContext.getCatalogItem(catalogItemMemento.getId());
-                    logRebindingDebug("RebindManager reconstructing catalog item {}", catalogItemMemento);
-                    if (item == null) {
-                        exceptionHandler.onNotFound(BrooklynObjectType.CATALOG_ITEM, catalogItemMemento.getId());
-                    } else {
-                        try {
-                            item.getRebindSupport().reconstruct(rebindContext, catalogItemMemento);
-                            if (item instanceof AbstractBrooklynObject) {
-                                AbstractBrooklynObject.class.cast(item).setManagementContext(managementContext);
-                            }
-                        } catch (Exception e) {
-                            exceptionHandler.onRebindFailed(BrooklynObjectType.CATALOG_ITEM, item, e);
-                        }
-                    }
-                }
-            }
-            
-            // Register catalogue items with the management context. Loads the bundles in the OSGi framework.
-            CatalogLoadMode catalogLoadMode = managementContext.getConfig().getConfig(BrooklynServerConfig.CATALOG_LOAD_MODE);
-            if (persistCatalogItemsEnabled) {
-                boolean shouldResetCatalog = catalogLoadMode == CatalogLoadMode.LOAD_PERSISTED_STATE
-                        || (!isEmpty && catalogLoadMode == CatalogLoadMode.LOAD_BROOKLYN_CATALOG_URL_IF_NO_PERSISTED_STATE);
-                boolean shouldLoadDefaultCatalog = catalogLoadMode == CatalogLoadMode.LOAD_BROOKLYN_CATALOG_URL
-                        || (isEmpty && catalogLoadMode == CatalogLoadMode.LOAD_BROOKLYN_CATALOG_URL_IF_NO_PERSISTED_STATE);
-                if (shouldResetCatalog) {
-                    // Reset catalog with previously persisted state
-                    logRebindingDebug("RebindManager resetting management context catalog to previously persisted state");
-                    managementContext.getCatalog().reset(rebindContext.getCatalogItems());
-                } else if (shouldLoadDefaultCatalog) {
-                    // Load catalogue as normal
-                    // TODO in read-only mode, should do this less frequently than entities etc
-                    logRebindingDebug("RebindManager loading default catalog");
-                    ((BasicBrooklynCatalog) managementContext.getCatalog()).resetCatalogToContentsAtConfiguredUrl();
-                } else {
-                    // Management context should have taken care of loading the catalogue
-                    Collection<CatalogItem<?, ?>> catalogItems = rebindContext.getCatalogItems();
-                    String message = "RebindManager not resetting catalog to persisted state. Catalog load mode is {}.";
-                    if (!catalogItems.isEmpty() && shouldLogRebinding()) {
-                        LOG.info(message + " There {} {} item{} persisted.", new Object[]{
-                                catalogLoadMode, catalogItems.size() == 1 ? "was" : "were", catalogItems.size(), Strings.s(catalogItems)});
-                    } else if (LOG.isDebugEnabled()) {
-                        logRebindingDebug(message, catalogLoadMode);
-                    }
-                }
-                // TODO destroy old (as above)
-            } else {
-                logRebindingDebug("RebindManager not resetting catalog because catalog persistence is disabled");
-            }
-            
-            
-            //
-            // PHASE THREE
-            //
-            
-            // Instantiate locations
-            logRebindingDebug("RebindManager instantiating locations: {}", mementoManifest.getLocationIdToType().keySet());
-            for (Map.Entry<String, String> entry : mementoManifest.getLocationIdToType().entrySet()) {
-                String locId = entry.getKey();
-                String locType = entry.getValue();
-                if (LOG.isTraceEnabled()) LOG.trace("RebindManager instantiating location {}", locId);
-                
-                try {
-                    Location location = instantiator.newLocation(locId, locType);
-                    rebindContext.registerLocation(locId, location);
-                } catch (Exception e) {
-                    exceptionHandler.onCreateFailed(BrooklynObjectType.LOCATION, locId, locType, e);
-                }
-            }
-            
-            // Instantiate entities
-            logRebindingDebug("RebindManager instantiating entities: {}", mementoManifest.getEntityIdToManifest().keySet());
-            for (Map.Entry<String, EntityMementoManifest> entry : mementoManifest.getEntityIdToManifest().entrySet()) {
-                String entityId = entry.getKey();
-                EntityMementoManifest entityManifest = entry.getValue();
-                String catalogItemId = findCatalogItemId(classLoader, mementoManifest.getEntityIdToManifest(), entityManifest);
-                
-                if (LOG.isTraceEnabled()) LOG.trace("RebindManager instantiating entity {}", entityId);
-                
-                try {
-                    Entity entity = (Entity) instantiator.newEntity(entityId, entityManifest.getType(), catalogItemId);
-                    ((EntityInternal)entity).getManagementSupport().setReadOnly( rebindContext.isReadOnly(entity) );
-                    rebindContext.registerEntity(entityId, entity);
-
-                } catch (Exception e) {
-                    exceptionHandler.onCreateFailed(BrooklynObjectType.ENTITY, entityId, entityManifest.getType(), e);
-                }
-            }
-            
-            
-            //
-            // PHASE FOUR
-            //
-            
-            BrooklynMemento memento = persistenceStoreAccess.loadMemento(mementoRawData, realLookupContext, exceptionHandler);
-            
-            
-            //
-            // PHASE FIVE
-            //
-            
-            // Instantiate policies
-            if (persistPoliciesEnabled) {
-                logRebindingDebug("RebindManager instantiating policies: {}", memento.getPolicyIds());
-                for (PolicyMemento policyMemento : memento.getPolicyMementos().values()) {
-                    logRebindingDebug("RebindManager instantiating policy {}", policyMemento);
-                    
-                    try {
-                        Policy policy = instantiator.newPolicy(policyMemento);
-                        rebindContext.registerPolicy(policyMemento.getId(), policy);
-                    } catch (Exception e) {
-                        exceptionHandler.onCreateFailed(BrooklynObjectType.POLICY, policyMemento.getId(), policyMemento.getType(), e);
-                    }
-                }
-            } else {
-                logRebindingDebug("Not rebinding policies; feature disabled: {}", memento.getPolicyIds());
-            }
-            
-            // Instantiate enrichers
-            if (persistEnrichersEnabled) {
-                logRebindingDebug("RebindManager instantiating enrichers: {}", memento.getEnricherIds());
-                for (EnricherMemento enricherMemento : memento.getEnricherMementos().values()) {
-                    logRebindingDebug("RebindManager instantiating enricher {}", enricherMemento);
-
-                    try {
-                        Enricher enricher = instantiator.newEnricher(enricherMemento);
-                        rebindContext.registerEnricher(enricherMemento.getId(), enricher);
-                    } catch (Exception e) {
-                        exceptionHandler.onCreateFailed(BrooklynObjectType.ENRICHER, enricherMemento.getId(), enricherMemento.getType(), e);
-                    }
-                }
-            } else {
-                logRebindingDebug("Not rebinding enrichers; feature disabled: {}", memento.getEnricherIds());
-            } 
-            
-            // Instantiate feeds
-            if (persistFeedsEnabled) {
-                logRebindingDebug("RebindManager instantiating feeds: {}", memento.getFeedIds());
-                for (FeedMemento feedMemento : memento.getFeedMementos().values()) {
-                    if (LOG.isDebugEnabled()) LOG.debug("RebindManager instantiating feed {}", feedMemento);
-
-                    try {
-                        Feed feed = instantiator.newFeed(feedMemento);
-                        rebindContext.registerFeed(feedMemento.getId(), feed);
-                    } catch (Exception e) {
-                        exceptionHandler.onCreateFailed(BrooklynObjectType.FEED, feedMemento.getId(), feedMemento.getType(), e);
-                    }
-                }
-            } else {
-                logRebindingDebug("Not rebinding feeds; feature disabled: {}", memento.getFeedIds());
-            } 
-
-            //
-            // PHASE SIX
-            //
-            
-            // Reconstruct locations
-            logRebindingDebug("RebindManager reconstructing locations");
-            for (LocationMemento locMemento : sortParentFirst(memento.getLocationMementos()).values()) {
-                Location location = rebindContext.getLocation(locMemento.getId());
-                logRebindingDebug("RebindManager reconstructing location {}", locMemento);
-                if (location == null) {
-                    // usually because of creation-failure, when not using fail-fast
-                    exceptionHandler.onNotFound(BrooklynObjectType.LOCATION, locMemento.getId());
-                } else {
-                    try {
-                        ((LocationInternal)location).getRebindSupport().reconstruct(rebindContext, locMemento);
-                    } catch (Exception e) {
-                        exceptionHandler.onRebindFailed(BrooklynObjectType.LOCATION, location, e);
-                    }
-                }
-            }
-
-            // Reconstruct policies
-            if (persistPoliciesEnabled) {
-                logRebindingDebug("RebindManager reconstructing policies");
-                for (PolicyMemento policyMemento : memento.getPolicyMementos().values()) {
-                    Policy policy = rebindContext.getPolicy(policyMemento.getId());
-                    logRebindingDebug("RebindManager reconstructing policy {}", policyMemento);
-    
-                    if (policy == null) {
-                        // usually because of creation-failure, when not using fail-fast
-                        exceptionHandler.onNotFound(BrooklynObjectType.POLICY, policyMemento.getId());
-                    } else {
-                        try {
-                            policy.getRebindSupport().reconstruct(rebindContext, policyMemento);
-                        } catch (Exception e) {
-                            exceptionHandler.onRebindFailed(BrooklynObjectType.POLICY, policy, e);
-                            rebindContext.unregisterPolicy(policy);
-                        }
-                    }
-                }
-            }
-
-            // Reconstruct enrichers
-            if (persistEnrichersEnabled) {
-                logRebindingDebug("RebindManager reconstructing enrichers");
-                for (EnricherMemento enricherMemento : memento.getEnricherMementos().values()) {
-                    Enricher enricher = rebindContext.getEnricher(enricherMemento.getId());
-                    logRebindingDebug("RebindManager reconstructing enricher {}", enricherMemento);
+        RebindIteration iteration = new RebindIteration(this, mode, classLoader, exceptionHandler,
+            rebindActive, readOnlyRebindCount, rebindMetrics, persistenceStoreAccess);
         
-                    if (enricher == null) {
-                        // usually because of creation-failure, when not using fail-fast
-                        exceptionHandler.onNotFound(BrooklynObjectType.ENRICHER, enricherMemento.getId());
-                    } else {
-                        try {
-                            enricher.getRebindSupport().reconstruct(rebindContext, enricherMemento);
-                        } catch (Exception e) {
-                            exceptionHandler.onRebindFailed(BrooklynObjectType.ENRICHER, enricher, e);
-                            rebindContext.unregisterEnricher(enricher);
-                        }
-                    }
-                }
-            }
-    
-            // Reconstruct feeds
-            if (persistFeedsEnabled) {
-                logRebindingDebug("RebindManager reconstructing feeds");
-                for (FeedMemento feedMemento : memento.getFeedMementos().values()) {
-                    Feed feed = rebindContext.getFeed(feedMemento.getId());
-                    logRebindingDebug("RebindManager reconstructing feed {}", feedMemento);
+        iteration.runFullRebind();
         
-                    if (feed == null) {
-                        // usually because of creation-failure, when not using fail-fast
-                        exceptionHandler.onNotFound(BrooklynObjectType.FEED, feedMemento.getId());
-                    } else {
-                        try {
-                            feed.getRebindSupport().reconstruct(rebindContext, feedMemento);
-                        } catch (Exception e) {
-                            exceptionHandler.onRebindFailed(BrooklynObjectType.FEED, feed, e);
-                            rebindContext.unregisterFeed(feed);
-                        }
-                    }
-
-                }
-            }
-    
-            // Reconstruct entities
-            logRebindingDebug("RebindManager reconstructing entities");
-            for (EntityMemento entityMemento : sortParentFirst(memento.getEntityMementos()).values()) {
-                Entity entity = rebindContext.lookup().lookupEntity(entityMemento.getId());
-                logRebindingDebug("RebindManager reconstructing entity {}", entityMemento);
-    
-                if (entity == null) {
-                    // usually because of creation-failure, when not using fail-fast
-                    exceptionHandler.onNotFound(BrooklynObjectType.ENTITY, entityMemento.getId());
-                } else {
-                    try {
-                        entityMemento.injectTypeClass(entity.getClass());
-                        ((EntityInternal)entity).getRebindSupport().reconstruct(rebindContext, entityMemento);
-                    } catch (Exception e) {
-                        exceptionHandler.onRebindFailed(BrooklynObjectType.ENTITY, entity, e);
-                    }
-                }
-            }
-
-            //
-            // PHASE SEVEN
-            //
-            
-            // Associate policies+enrichers+feeds with entities
-            logRebindingDebug("RebindManager reconstructing entities");
-            for (EntityMemento entityMemento : sortParentFirst(memento.getEntityMementos()).values()) {
-                Entity entity = rebindContext.getEntity(entityMemento.getId());
-                logRebindingDebug("RebindManager reconstructing entity {}", entityMemento);
-    
-                if (entity == null) {
-                    // usually because of creation-failure, when not using fail-fast
-                    exceptionHandler.onNotFound(BrooklynObjectType.ENTITY, entityMemento.getId());
-                } else {
-                    try {
-                        entityMemento.injectTypeClass(entity.getClass());
-                        // TODO these call to the entity which in turn sets the entity on the underlying feeds and enrichers;
-                        // that is taken as the cue to start, but it should not be. start should be a separate call.
-                        ((EntityInternal)entity).getRebindSupport().addPolicies(rebindContext, entityMemento);
-                        ((EntityInternal)entity).getRebindSupport().addEnrichers(rebindContext, entityMemento);
-                        ((EntityInternal)entity).getRebindSupport().addFeeds(rebindContext, entityMemento);
-                    } catch (Exception e) {
-                        exceptionHandler.onRebindFailed(BrooklynObjectType.ENTITY, entity, e);
-                    }
-                }
-            }
-            
-            
-            //
-            // PHASE EIGHT
-            //
-
-            logRebindingDebug("RebindManager managing locations");
-            LocationManagerInternal locationManager = (LocationManagerInternal)managementContext.getLocationManager();
-            Set<String> oldLocations = Sets.newLinkedHashSet(locationManager.getLocationIds());
-            for (Location location: rebindContext.getLocations()) {
-                ManagementTransitionMode oldMode = locationManager.getLastManagementTransitionMode(location.getId());
-                locationManager.setManagementTransitionMode(location, computeMode(managementContext, location, oldMode, rebindContext.isReadOnly(location)) );
-                if (oldMode!=null)
-                    oldLocations.remove(location.getId());
-            }
-            for (Location location: rebindContext.getLocations()) {
-                if (location.getParent()==null) {
-                    // manage all root locations
-                    try {
-                        ((LocationManagerInternal)managementContext.getLocationManager()).manageRebindedRoot(location);
-                    } catch (Exception e) {
-                        exceptionHandler.onManageFailed(BrooklynObjectType.LOCATION, location, e);
-                    }
-                }
-            }
-            // destroy old
-            if (!oldLocations.isEmpty()) BrooklynLogging.log(LOG, overwritingMaster ? BrooklynLogging.LoggingLevel.WARN : BrooklynLogging.LoggingLevel.DEBUG, 
-                "Destroying unused locations on rebind: "+oldLocations);
-            for (String oldLocationId: oldLocations) {
-               locationManager.unmanage(locationManager.getLocation(oldLocationId), ManagementTransitionMode.REBINDING_DESTROYED); 
-            }
-            
-            // Manage the top-level apps (causing everything under them to become managed)
-            logRebindingDebug("RebindManager managing entities");
-            EntityManagerInternal entityManager = (EntityManagerInternal)managementContext.getEntityManager();
-            Set<String> oldEntities = Sets.newLinkedHashSet(entityManager.getEntityIds());
-            for (Entity entity: rebindContext.getEntities()) {
-                ManagementTransitionMode oldMode = entityManager.getLastManagementTransitionMode(entity.getId());
-                entityManager.setManagementTransitionMode(entity, computeMode(managementContext,entity, oldMode, rebindContext.isReadOnly(entity)) );
-                if (oldMode!=null)
-                    oldEntities.remove(entity.getId());
-            }
-            List<Application> apps = Lists.newArrayList();
-            for (String appId : memento.getApplicationIds()) {
-                Entity entity = rebindContext.getEntity(appId);
-                if (entity == null) {
-                    // usually because of creation-failure, when not using fail-fast
-                    exceptionHandler.onNotFound(BrooklynObjectType.ENTITY, appId);
-                } else {
-                    try {
-                        entityManager.manageRebindedRoot(entity);
-                    } catch (Exception e) {
-                        exceptionHandler.onManageFailed(BrooklynObjectType.ENTITY, entity, e);
-                    }
-                    apps.add((Application)entity);
-                }
-            }
-            // destroy old
-            if (!oldLocations.isEmpty()) BrooklynLogging.log(LOG, overwritingMaster ? BrooklynLogging.LoggingLevel.WARN : BrooklynLogging.LoggingLevel.DEBUG, 
-                "Destroying unused entities on rebind: "+oldEntities);
-            for (String oldEntityId: oldEntities) {
-               entityManager.unmanage(entityManager.getEntity(oldEntityId), ManagementTransitionMode.REBINDING_DESTROYED); 
-            }
-
-            exceptionHandler.onDone();
-            
-            rebindMetrics.noteSuccess(Duration.of(timer));
-            noteErrors(exceptionHandler, null);
-            if (firstRebindAppCount==null) {
-                firstRebindAppCount = apps.size();
-                firstRebindEntityCount = rebindContext.getEntities().size();
-                firstRebindItemCount = rebindContext.getAllBrooklynObjects().size();
-            }
-
-            if (!isEmpty) {
-                BrooklynLogging.log(LOG, shouldLogRebinding() ? LoggingLevel.INFO : LoggingLevel.DEBUG, 
-                    "Rebind complete " + "("+mode+(readOnlyRebindCount>=0 ? ", iteration "+readOnlyRebindCount : "")+")" +
-                        " in {}: {} app{}, {} entit{}, {} location{}, {} polic{}, {} enricher{}, {} feed{}, {} catalog item{}", new Object[]{
-                    Time.makeTimeStringRounded(timer), apps.size(), Strings.s(apps),
-                    rebindContext.getEntities().size(), Strings.ies(rebindContext.getEntities()),
-                    rebindContext.getLocations().size(), Strings.s(rebindContext.getLocations()),
-                    rebindContext.getPolicies().size(), Strings.ies(rebindContext.getPolicies()),
-                    rebindContext.getEnrichers().size(), Strings.s(rebindContext.getEnrichers()),
-                    rebindContext.getFeeds().size(), Strings.s(rebindContext.getFeeds()),
-                    rebindContext.getCatalogItems().size(), Strings.s(rebindContext.getCatalogItems())
-                });
-            }
-
-            // Return the top-level applications
-            logRebindingDebug("RebindManager complete; apps: {}", memento.getApplicationIds());
-            return apps;
-
-        } catch (Exception e) {
-            rebindMetrics.noteFailure(Duration.of(timer));
-            
-            Exceptions.propagateIfFatal(e);
-            noteErrors(exceptionHandler, e);
-            throw exceptionHandler.onFailed(e);
-            
-        } finally {
-            rebindActive.release();
-            RebindTracker.reset();
-        }
-    }
-
-    private void noteErrors(final RebindExceptionHandler exceptionHandler, Exception primaryException) {
-        List<Exception> exceptions = exceptionHandler.getExceptions();
-        List<String> warnings = exceptionHandler.getWarnings();
-        if (primaryException!=null || !exceptions.isEmpty() || !warnings.isEmpty()) {
-            List<String> messages = MutableList.<String>of();
-            if (primaryException!=null) messages.add(primaryException.toString());
-            for (Exception e: exceptions) messages.add(e.toString());
-            for (String w: warnings) messages.add(w);
-            rebindMetrics.noteError(messages);
-        }
-    }
-    
-    private String findCatalogItemId(ClassLoader cl, Map<String, EntityMementoManifest> entityIdToManifest, EntityMementoManifest entityManifest) {
-        if (entityManifest.getCatalogItemId() != null) {
-            return entityManifest.getCatalogItemId();
-        }
-
-        if (BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_INFER_CATALOG_ITEM_ON_REBIND)) {
-            //First check if any of the parent entities has a catalogItemId set.
-            EntityMementoManifest ptr = entityManifest;
-            while (ptr != null) {
-                if (ptr.getCatalogItemId() != null) {
-                    CatalogItem<?, ?> catalogItem = CatalogUtils.getCatalogItemOptionalVersion(managementContext, ptr.getCatalogItemId());
-                    if (catalogItem != null) {
-                        return catalogItem.getId();
-                    } else {
-                        //Couldn't find a catalog item with this id, but return it anyway and
-                        //let the caller deal with the error.
-                        return ptr.getCatalogItemId();
-                    }
-                }
-                if (ptr.getParent() != null) {
-                    ptr = entityIdToManifest.get(ptr.getParent());
-                } else {
-                    ptr = null;
-                }
-            }
-
-            //If no parent entity has the catalogItemId set try to match them by the type we are trying to load.
-            //The current convention is to set catalog item IDs to the java type (for both plain java or CAMP plan) they represent.
-            //This will be applicable only the first time the store is rebinded, while the catalog items don't have the default
-            //version appended to their IDs, but then we will have catalogItemId set on entities so not neede further anyways.
-            BrooklynCatalog catalog = managementContext.getCatalog();
-            ptr = entityManifest;
-            while (ptr != null) {
-                CatalogItem<?, ?> catalogItem = catalog.getCatalogItem(ptr.getType(), BrooklynCatalog.DEFAULT_VERSION);
-                if (catalogItem != null) {
-                    LOG.debug("Inferred catalog item ID "+catalogItem.getId()+" for "+entityManifest+" from ancestor "+ptr);
-                    return catalogItem.getId();
-                }
-                if (ptr.getParent() != null) {
-                    ptr = entityIdToManifest.get(ptr.getParent());
-                } else {
-                    ptr = null;
-                }
-            }
-
-            //As a last resort go through all catalog items trying to load the type and use the first that succeeds.
-            //But first check if can be loaded from the default classpath
-            try {
-                cl.loadClass(entityManifest.getType());
-                return null;
-            } catch (ClassNotFoundException e) {
-            }
-
-            for (CatalogItem<?, ?> item : catalog.getCatalogItems()) {
-                BrooklynClassLoadingContext loader = CatalogUtils.newClassLoadingContext(managementContext, item);
-                boolean canLoadClass = loader.tryLoadClass(entityManifest.getType()).isPresent();
-                if (canLoadClass) {
-                    LOG.warn("Missing catalog item for "+entityManifest.getId()+", inferring as "+item.getId()+" because that is able to load the item");
-                    return item.getId();
-                }
-            }
+        if (firstRebindAppCount==null) {
+            firstRebindAppCount = iteration.getApplications().size();
+            firstRebindEntityCount = iteration.getRebindContext().getEntities().size();
+            firstRebindItemCount = iteration.getRebindContext().getAllBrooklynObjects().size();
         }
-        return null;
-    }
 
-    private BrooklynClassLoadingContext getLoadingContextFromCatalogItemId(String catalogItemId, ClassLoader classLoader, RebindContext rebindContext) {
-        Preconditions.checkNotNull(catalogItemId, "catalogItemId required (should not be null)");
-        CatalogItem<?, ?> catalogItem = rebindContext.lookup().lookupCatalogItem(catalogItemId);
-        if (catalogItem != null) {
-            return CatalogUtils.newClassLoadingContext(managementContext, catalogItem);
-        } else {
-            throw new IllegalStateException("Failed to load catalog item " + catalogItemId + " required for rebinding.");
-        }
+        return iteration.getApplications();
     }
 
     static ManagementTransitionMode computeMode(ManagementContext mgmt, BrooklynObject item, ManagementTransitionMode oldMode, boolean isNowReadOnly) {
@@ -1159,7 +537,7 @@ public class RebindManagerImpl implements RebindManager {
      * TODO Inefficient implementation!
      */
     @VisibleForTesting
-    <T extends TreeNode> Map<String, T> sortParentFirst(Map<String, T> nodes) {
+    static <T extends TreeNode> Map<String, T> sortParentFirst(Map<String, T> nodes) {
         Map<String, T> result = Maps.newLinkedHashMap();
         for (T node : nodes.values()) {
             List<T> tempchain = Lists.newLinkedList();
@@ -1176,245 +554,6 @@ public class RebindManagerImpl implements RebindManager {
         return result;
     }
 
-    private class BrooklynObjectInstantiator {
-
-        private final ClassLoader classLoader;
-        private final RebindContextImpl rebindContext;
-        private final Reflections reflections;
-        
-        private BrooklynObjectInstantiator(ClassLoader classLoader, RebindContextImpl rebindContext, Reflections reflections) {
-            this.classLoader = classLoader;
-            this.rebindContext = rebindContext;
-            this.reflections = reflections;
-        }
-
-        private Entity newEntity(String entityId, String entityType, String catalogItemId) {
-            Class<? extends Entity> entityClazz = load(Entity.class, entityType, catalogItemId, entityId);
-
-            Entity entity;
-            
-            if (InternalFactory.isNewStyle(entityClazz)) {
-                // Not using entityManager.createEntity(EntitySpec) because don't want init() to be called.
-                // Creates an uninitialized entity, but that has correct id + proxy.
-                InternalEntityFactory entityFactory = managementContext.getEntityFactory();
-                entity = entityFactory.constructEntity(entityClazz, Reflections.getAllInterfaces(entityClazz), entityId);
-
-            } else {
-                LOG.warn("Deprecated rebind of entity without no-arg constructor; this may not be supported in future versions: id="+entityId+"; type="+entityType);
-
-                // There are several possibilities for the constructor; find one that works.
-                // Prefer passing in the flags because required for Application to set the management context
-                // TODO Feels very hacky!
-
-                Map<Object,Object> flags = Maps.newLinkedHashMap();
-                flags.put("id", entityId);
-                if (AbstractApplication.class.isAssignableFrom(entityClazz)) flags.put("mgmt", managementContext);
-
-                // TODO document the multiple sources of flags, and the reason for setting the mgmt context *and* supplying it as the flag
-                // (NB: merge reported conflict as the two things were added separately)
-                entity = (Entity) invokeConstructor(null, entityClazz, new Object[] {flags}, new Object[] {flags, null}, new Object[] {null}, new Object[0]);
-
-                // In case the constructor didn't take the Map arg, then also set it here.
-                // e.g. for top-level app instances such as WebClusterDatabaseExampleApp will (often?) not have
-                // interface + constructor.
-                // TODO On serializing the memento, we should capture which interfaces so can recreate
-                // the proxy+spec (including for apps where there's not an obvious interface).
-                FlagUtils.setFieldsFromFlags(ImmutableMap.of("id", entityId), entity);
-                if (entity instanceof AbstractApplication) {
-                    FlagUtils.setFieldsFromFlags(ImmutableMap.of("mgmt", managementContext), entity);
-                }
-                ((AbstractEntity)entity).setManagementContext(managementContext);
-                managementContext.prePreManage(entity);
-            }
-            
-            setCatalogItemId(entity, catalogItemId);
-            return entity;
-        }
-
-        private void setCatalogItemId(BrooklynObject item, String catalogItemId) {
-            if (catalogItemId!=null) {
-                ((BrooklynObjectInternal)item).setCatalogItemId(catalogItemId);
-            }
-        }
-
-        private <T extends BrooklynObject> Class<? extends T> load(Class<T> bType, Memento memento) {
-            return load(bType, memento.getType(), memento.getCatalogItemId(), memento.getId());
-        }
-        @SuppressWarnings("unchecked")
-        private <T extends BrooklynObject> Class<? extends T> load(Class<T> bType, String jType, String catalogItemId, String contextSuchAsId) {
-            checkNotNull(jType, "Type of %s (%s) must not be null", contextSuchAsId, bType.getSimpleName());
-            if (catalogItemId != null) {
-                BrooklynClassLoadingContext loader = getLoadingContextFromCatalogItemId(catalogItemId, classLoader, rebindContext);
-                return loader.loadClass(jType, bType);
-            } else {
-                // we have previously used reflections; not sure if that's needed?
-                try {
-                    return (Class<T>)reflections.loadClass(jType);
-                } catch (Exception e) {
-                    LOG.warn("Unable to load "+jType+" using reflections; will try standard context");
-                }
-
-                if (BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_INFER_CATALOG_ITEM_ON_REBIND)) {
-                    //Try loading from whichever catalog bundle succeeds.
-                    BrooklynCatalog catalog = managementContext.getCatalog();
-                    for (CatalogItem<?, ?> item : catalog.getCatalogItems()) {
-                        BrooklynClassLoadingContext catalogLoader = CatalogUtils.newClassLoadingContext(managementContext, item);
-                        Maybe<Class<?>> catalogClass = catalogLoader.tryLoadClass(jType);
-                        if (catalogClass.isPresent()) {
-                            return (Class<? extends T>) catalogClass.get();
-                        }
-                    }
-                    throw new IllegalStateException("No catalogItemId specified and can't load class from either classpath of catalog items");
-                } else {
-                    throw new IllegalStateException("No catalogItemId specified and can't load class from classpath");
-                }
-
-            }
-        }
-
-        /**
-         * Constructs a new location, passing to its constructor the location id and all of memento.getFlags().
-         */
-        private Location newLocation(String locationId, String locationType) {
-            Class<? extends Location> locationClazz = reflections.loadClass(locationType, Location.class);
-
-            if (InternalFactory.isNewStyle(locationClazz)) {
-                // Not using loationManager.createLocation(LocationSpec) because don't want init() to be called
-                // TODO Need to rationalise this to move code into methods of InternalLocationFactory.
-                //      But note that we'll change all locations to be entities at some point!
-                // See same code approach used in #newEntity(EntityMemento, Reflections)
-                InternalLocationFactory locationFactory = managementContext.getLocationFactory();
-                Location location = locationFactory.constructLocation(locationClazz);
-                FlagUtils.setFieldsFromFlags(ImmutableMap.of("id", locationId), location);
-                managementContext.prePreManage(location);
-                ((AbstractLocation)location).setManagementContext(managementContext);
-
-                return location;
-            } else {
-                LOG.warn("Deprecated rebind of location without no-arg constructor; this may not be supported in future versions: id="+locationId+"; type="+locationType);
-
-                // There are several possibilities for the constructor; find one that works.
-                // Prefer passing in the flags because required for Application to set the management context
-                // TODO Feels very hacky!
-                Map<String,?> flags = MutableMap.of("id", locationId, "deferConstructionChecks", true);
-
-                return (Location) invokeConstructor(reflections, locationClazz, new Object[] {flags});
-            }
-            // note 'used' config keys get marked in BasicLocationRebindSupport
-        }
-
-        /**
-         * Constructs a new policy, passing to its constructor the policy id and all of memento.getConfig().
-         */
-        private Policy newPolicy(PolicyMemento memento) {
-            String id = memento.getId();
-            Class<? extends Policy> policyClazz = load(Policy.class, memento.getType(), memento.getCatalogItemId(), id);
-            
-            Policy policy;
-            if (InternalFactory.isNewStyle(policyClazz)) {
-                InternalPolicyFactory policyFactory = managementContext.getPolicyFactory();
-                policy = policyFactory.constructPolicy(policyClazz);
-                FlagUtils.setFieldsFromFlags(ImmutableMap.of("id", id), policy);
-                ((AbstractPolicy)policy).setManagementContext(managementContext);
-
-            } else {
-                LOG.warn("Deprecated rebind of policy without no-arg constructor; this may not be supported in future versions: id="+id+"; type="+policyClazz);
-
-                // There are several possibilities for the constructor; find one that works.
-                // Prefer passing in the flags because required for Application to set the management context
-                // TODO Feels very hacky!
-                Map<String, Object> flags = MutableMap.<String, Object>of(
-                    "id", id, 
-                    "deferConstructionChecks", true,
-                    "noConstructionInit", true);
-                flags.putAll(memento.getConfig());
-
-                policy = invokeConstructor(null, policyClazz, new Object[] {flags});
-            }
-            
-            setCatalogItemId(policy, memento.getCatalogItemId());
-            return policy;
-        }
-
-        /**
-         * Constructs a new enricher, passing to its constructor the enricher id and all of memento.getConfig().
-         */
-        private Enricher newEnricher(EnricherMemento memento) {
-            Class<? extends Enricher> enricherClazz = load(Enricher.class, memento);
-            String id = memento.getId();
-
-            Enricher enricher;
-            if (InternalFactory.isNewStyle(enricherClazz)) {
-                InternalPolicyFactory policyFactory = managementContext.getPolicyFactory();
-                enricher = policyFactory.constructEnricher(enricherClazz);
-                FlagUtils.setFieldsFromFlags(ImmutableMap.of("id", id), enricher);
-                ((AbstractEnricher)enricher).setManagementContext(managementContext);
-
-            } else {
-                LOG.warn("Deprecated rebind of enricher without no-arg constructor; this may not be supported in future versions: id="+id+"; type="+enricherClazz);
-
-                // There are several possibilities for the constructor; find one that works.
-                // Prefer passing in the flags because required for Application to set the management context
-                // TODO Feels very hacky!
-                Map<String, Object> flags = MutableMap.<String, Object>of(
-                    "id", id, 
-                    "deferConstructionChecks", true,
-                    "noConstructionInit", true);
-                flags.putAll(memento.getConfig());
-
-                enricher = invokeConstructor(reflections, enricherClazz, new Object[] {flags});
-            }
-            
-            setCatalogItemId(enricher, memento.getCatalogItemId());
-            return enricher;
-        }
-
-        /**
-         * Constructs a new enricher, passing to its constructor the enricher id and all of memento.getConfig().
-         */
-        private Feed newFeed(FeedMemento memento) {
-            Class<? extends Feed> feedClazz = load(Feed.class, memento);
-            String id = memento.getId();
-
-            Feed feed;
-            if (InternalFactory.isNewStyle(feedClazz)) {
-                InternalPolicyFactory policyFactory = managementContext.getPolicyFactory();
-                feed = policyFactory.constructFeed(feedClazz);
-                FlagUtils.setFieldsFromFlags(ImmutableMap.of("id", id), feed);
-                ((AbstractFeed)feed).setManagementContext(managementContext);
-
-            } else {
-                throw new IllegalStateException("rebind of feed without no-arg constructor unsupported: id="+id+"; type="+feedClazz);
-            }
-            
-            setCatalogItemId(feed, memento.getCatalogItemId());
-            return feed;
-        }
-
-        @SuppressWarnings({ "rawtypes" })
-        private CatalogItem<?, ?> newCatalogItem(CatalogItemMemento memento) {
-            String id = memento.getId();
-            // catalog item subtypes are internal to brooklyn, not in osgi
-            String itemType = checkNotNull(memento.getType(), "catalog item type of %s must not be null in memento", id);
-            Class<? extends CatalogItem> clazz = reflections.loadClass(itemType, CatalogItem.class);
-            return invokeConstructor(reflections, clazz, new Object[]{});
-        }
-
-        private <T> T invokeConstructor(Reflections reflections, Class<T> clazz, Object[]... possibleArgs) {
-            for (Object[] args : possibleArgs) {
-                try {
-                    Optional<T> v = Reflections.invokeConstructorWithArgs(clazz, args, true);
-                    if (v.isPresent()) {
-                        return v.get();
-                    }
-                } catch (Exception e) {
-                    throw Exceptions.propagate(e);
-                }
-            }
-            throw new IllegalStateException("Cannot instantiate instance of type "+clazz+"; expected constructor signature not found");
-        }
-    }
-
     /**
      * Wraps a ChangeListener, to log and never propagate any exceptions that it throws.
      * 
@@ -1460,21 +599,8 @@ public class RebindManagerImpl implements RebindManager {
         }
     }
 
-    /** logs at debug, except during subsequent read-only rebinds, in which it logs trace */
-    private void logRebindingDebug(String message, Object... args) {
-        if (shouldLogRebinding()) {
-            LOG.debug(message, args);
-        } else {
-            LOG.trace(message, args);
-        }
-    }
-    
-    protected boolean shouldLogRebinding() {
-        return (readOnlyRebindCount < 5) || (readOnlyRebindCount%1000==0);
-    }
-
     public int getReadOnlyRebindCount() {
-        return readOnlyRebindCount;
+        return readOnlyRebindCount.get();
     }
     
     @Override
@@ -1484,7 +610,7 @@ public class RebindManagerImpl implements RebindManager {
         result.put("rebind", rebindMetrics.asMap());
         result.put("persist", persistMetrics.asMap());
         
-        if (readOnlyRebindCount>=0)
+        if (readOnlyRebindCount.get()>=0)
             result.put("rebindReadOnlyCount", readOnlyRebindCount);
         
         // include first rebind counts, so we know whether we rebinded or not

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/55b5f65e/core/src/main/java/brooklyn/entity/rebind/persister/PersistenceActivityMetrics.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/persister/PersistenceActivityMetrics.java b/core/src/main/java/brooklyn/entity/rebind/persister/PersistenceActivityMetrics.java
index 8315156..1167ce6 100644
--- a/core/src/main/java/brooklyn/entity/rebind/persister/PersistenceActivityMetrics.java
+++ b/core/src/main/java/brooklyn/entity/rebind/persister/PersistenceActivityMetrics.java
@@ -43,7 +43,7 @@ public class PersistenceActivityMetrics {
         count++;
         failureCount++;
         lastFailureTime = System.currentTimeMillis();
-        lastDuration = duration.toMilliseconds();
+        lastDuration = duration!=null ? duration.toMilliseconds() : -1;
     }
 
     public void noteError(String error) {