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 2015/02/09 16:36:28 UTC

[09/22] incubator-brooklyn git commit: Partial rebind - add test and refactor / tidy of new code

Partial rebind - add test and refactor / tidy of new code


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

Branch: refs/heads/master
Commit: be6fd97ec5b318af02a7b5d663a9c7fe1b365c05
Parents: 3f7d750
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Feb 4 12:33:22 2015 +0000
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Feb 6 22:12:13 2015 +0000

----------------------------------------------------------------------
 .../entity/proxying/EntityProxyImpl.java        |   2 +-
 .../rebind/InitialFullRebindIteration.java      |   4 +-
 .../brooklyn/entity/rebind/RebindIteration.java |  51 +-------
 .../ha/HighAvailabilityManagerImpl.java         |   4 +-
 .../internal/BrooklynObjectManagementMode.java  |  30 +++++
 .../internal/BrooklynObjectManagerInternal.java |   1 -
 .../management/internal/LocalEntityManager.java |   2 -
 .../internal/LocalLocationManager.java          |   2 -
 .../internal/ManagementTransitionInfo.java      | 110 -----------------
 .../internal/ManagementTransitionMode.java      | 121 +++++++++++++++++++
 .../internal/NonDeploymentEntityManager.java    |   1 -
 .../internal/NonDeploymentLocationManager.java  |   1 -
 .../entity/rebind/ActivePartialRebindTest.java  |  84 +++++++++++++
 .../rebind/RebindOnlySomeEntitiesTest.java      |  44 -------
 .../brooklyn/util/exceptions/Exceptions.java    |   8 +-
 15 files changed, 250 insertions(+), 215 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/be6fd97e/core/src/main/java/brooklyn/entity/proxying/EntityProxyImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/proxying/EntityProxyImpl.java b/core/src/main/java/brooklyn/entity/proxying/EntityProxyImpl.java
index 611eba3..7e5b009 100644
--- a/core/src/main/java/brooklyn/entity/proxying/EntityProxyImpl.java
+++ b/core/src/main/java/brooklyn/entity/proxying/EntityProxyImpl.java
@@ -44,7 +44,7 @@ import brooklyn.management.ManagementContext;
 import brooklyn.management.TaskAdaptable;
 import brooklyn.management.internal.EffectorUtils;
 import brooklyn.management.internal.EntityManagerInternal;
-import brooklyn.management.internal.ManagementTransitionInfo.ManagementTransitionMode;
+import brooklyn.management.internal.ManagementTransitionMode;
 import brooklyn.util.config.ConfigBag;
 import brooklyn.util.task.DynamicTasks;
 import brooklyn.util.task.TaskTags;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/be6fd97e/core/src/main/java/brooklyn/entity/rebind/InitialFullRebindIteration.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/InitialFullRebindIteration.java b/core/src/main/java/brooklyn/entity/rebind/InitialFullRebindIteration.java
index e416bbc..b045873 100644
--- a/core/src/main/java/brooklyn/entity/rebind/InitialFullRebindIteration.java
+++ b/core/src/main/java/brooklyn/entity/rebind/InitialFullRebindIteration.java
@@ -30,10 +30,10 @@ import brooklyn.entity.Entity;
 import brooklyn.entity.basic.EntityInternal;
 import brooklyn.entity.rebind.persister.PersistenceActivityMetrics;
 import brooklyn.management.ha.ManagementNodeState;
+import brooklyn.management.internal.BrooklynObjectManagementMode;
 import brooklyn.management.internal.EntityManagerInternal;
 import brooklyn.management.internal.LocationManagerInternal;
-import brooklyn.management.internal.ManagementTransitionInfo.ManagementTransitionMode;
-import brooklyn.management.internal.ManagementTransitionInfo.BrooklynObjectManagementMode;
+import brooklyn.management.internal.ManagementTransitionMode;
 import brooklyn.mementos.BrooklynMementoPersister;
 import brooklyn.util.text.Strings;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/be6fd97e/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java b/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java
index d786571..fd4fded 100644
--- a/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java
+++ b/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java
@@ -63,12 +63,12 @@ import brooklyn.location.basic.AbstractLocation;
 import brooklyn.location.basic.LocationInternal;
 import brooklyn.management.classloading.BrooklynClassLoadingContext;
 import brooklyn.management.ha.ManagementNodeState;
+import brooklyn.management.internal.BrooklynObjectManagementMode;
 import brooklyn.management.internal.BrooklynObjectManagerInternal;
 import brooklyn.management.internal.EntityManagerInternal;
 import brooklyn.management.internal.LocationManagerInternal;
 import brooklyn.management.internal.ManagementContextInternal;
-import brooklyn.management.internal.ManagementTransitionInfo.ManagementTransitionMode;
-import brooklyn.management.internal.ManagementTransitionInfo.BrooklynObjectManagementMode;
+import brooklyn.management.internal.ManagementTransitionMode;
 import brooklyn.mementos.BrooklynMemento;
 import brooklyn.mementos.BrooklynMementoManifest;
 import brooklyn.mementos.BrooklynMementoManifest.EntityMementoManifest;
@@ -652,29 +652,16 @@ public abstract class RebindIteration {
     private <T extends BrooklynObject> ManagementTransitionMode updateTransitionMode(BrooklynObjectManagerInternal<T> boManager, T bo) {
         ManagementTransitionMode oldTransitionMode = boManager.getLastManagementTransitionMode(bo.getId());
         
-//        boManager.setManagementTransitionMode(bo, 
-//            RebindManagerImpl.computeMode(managementContext, bo, oldMode, rebindContext.isReadOnly(bo), isRebindingActiveAgain()) );
-
-//        isRebindingActiveAgain();
-        
-        ManagementTransitionMode newTransitionMode;
         Boolean isNowReadOnly = rebindContext.isReadOnly(bo);
         BrooklynObjectManagementMode modeBefore, modeAfter; 
         if (oldTransitionMode==null) {
             modeBefore = BrooklynObjectManagementMode.UNMANAGED_PERSISTED;
-//            // not previously known
-//            if (Boolean.TRUE.equals(isNowReadOnly)) {
-//                newMode = ManagementTransitionMode.REBINDING_READONLY;
-//            } else {
-//                // TODO is this needed?
-//                return ManagementTransitionMode.REBINDING_CREATING;
-//            }
         } else {
             modeBefore = oldTransitionMode.getModeAfter();
         }
 
         if (isRebindingActiveAgain()) {
-            Preconditions.checkState(!Boolean.FALSE.equals(isNowReadOnly));
+            Preconditions.checkState(!Boolean.TRUE.equals(isNowReadOnly));
             Preconditions.checkState(modeBefore==BrooklynObjectManagementMode.MANAGED_PRIMARY);
             modeAfter = BrooklynObjectManagementMode.MANAGED_PRIMARY;
         } else if (isNowReadOnly) {
@@ -682,37 +669,9 @@ public abstract class RebindIteration {
         } else {
             modeAfter = BrooklynObjectManagementMode.MANAGED_PRIMARY;
         }
-        newTransitionMode = ManagementTransitionMode.transitioning(modeBefore, modeAfter);
-
-        boManager.setManagementTransitionMode(bo, newTransitionMode);
-
-        // XXX old logic, from RebindManagerImpl.computeMode, for reference:
-//          if (wasReadOnly==null) {
-//              // not known
-//              if (Boolean.TRUE.equals(isNowReadOnly)) return ManagementTransitionMode.REBINDING_READONLY;
-//              else {
-//                  // TODO is this needed?
-//                  return ManagementTransitionMode.REBINDING_CREATING;
-//              }
-//          } else {
-//              if (isRebindingActiveAgain) {
-//                  if (wasReadOnly || isNowReadOnly)
-//                      throw new IllegalStateException("Cannot be rebinding again to something where read-only before/after is "+wasReadOnly+"/"+isNowReadOnly);
-//                  return ManagementTransitionMode.REBINDING_ACTIVE_AGAIN;
-//              } else if (wasReadOnly && isNowReadOnly)
-//                  return ManagementTransitionMode.REBINDING_READONLY;
-//              else if (wasReadOnly)
-//                  return ManagementTransitionMode.REBINDING_BECOMING_PRIMARY;
-//              else if (isNowReadOnly)
-//                  return ManagementTransitionMode.REBINDING_NO_LONGER_PRIMARY;
-//              else {
-//                  if (isRebindingActiveAgain)
-//                  // for the most part we handle this correctly, although there may be leaks; see HighAvailabilityManagerInMemoryTest.testLocationsStillManagedCorrectlyAfterDoublePromotion
-//                  LOG.warn("Node "+(mgmt!=null ? mgmt.getManagementNodeId() : null)+" rebinding as master when already master (discouraged, may have stale references); for: "+item);
-//                  return ManagementTransitionMode.REBINDING_BECOMING_PRIMARY;
-//              }
-//          }
         
+        ManagementTransitionMode newTransitionMode = ManagementTransitionMode.transitioning(modeBefore, modeAfter);
+        boManager.setManagementTransitionMode(bo, newTransitionMode);
         return oldTransitionMode;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/be6fd97e/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java b/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java
index bf8c390..bc5c398 100644
--- a/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java
+++ b/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java
@@ -54,11 +54,11 @@ import brooklyn.location.Location;
 import brooklyn.management.Task;
 import brooklyn.management.ha.BasicMasterChooser.AlphabeticMasterChooser;
 import brooklyn.management.ha.ManagementPlaneSyncRecordPersister.Delta;
+import brooklyn.management.internal.BrooklynObjectManagementMode;
 import brooklyn.management.internal.LocalEntityManager;
 import brooklyn.management.internal.LocationManagerInternal;
 import brooklyn.management.internal.ManagementContextInternal;
-import brooklyn.management.internal.ManagementTransitionInfo.ManagementTransitionMode;
-import brooklyn.management.internal.ManagementTransitionInfo.BrooklynObjectManagementMode;
+import brooklyn.management.internal.ManagementTransitionMode;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/be6fd97e/core/src/main/java/brooklyn/management/internal/BrooklynObjectManagementMode.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/internal/BrooklynObjectManagementMode.java b/core/src/main/java/brooklyn/management/internal/BrooklynObjectManagementMode.java
new file mode 100644
index 0000000..a005c2d
--- /dev/null
+++ b/core/src/main/java/brooklyn/management/internal/BrooklynObjectManagementMode.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package brooklyn.management.internal;
+
+public enum BrooklynObjectManagementMode {
+    /** item does not exist, not in memory, nor persisted (e.g. creating for first time, or finally destroying) */
+    NONEXISTENT, 
+    /** item exists or existed elsewhere, i.e. there is persisted state, but is not loaded here */
+    UNMANAGED_PERSISTED, 
+    /** item is loaded but read-only (ie not actively managed here) */
+    LOADED_READ_ONLY, 
+    /** item is actively managed here */
+    MANAGED_PRIMARY 
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/be6fd97e/core/src/main/java/brooklyn/management/internal/BrooklynObjectManagerInternal.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/internal/BrooklynObjectManagerInternal.java b/core/src/main/java/brooklyn/management/internal/BrooklynObjectManagerInternal.java
index 912e84b..93045be 100644
--- a/core/src/main/java/brooklyn/management/internal/BrooklynObjectManagerInternal.java
+++ b/core/src/main/java/brooklyn/management/internal/BrooklynObjectManagerInternal.java
@@ -19,7 +19,6 @@
 package brooklyn.management.internal;
 
 import brooklyn.basic.BrooklynObject;
-import brooklyn.management.internal.ManagementTransitionInfo.ManagementTransitionMode;
 
 public interface BrooklynObjectManagerInternal<T extends BrooklynObject> {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/be6fd97e/core/src/main/java/brooklyn/management/internal/LocalEntityManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/internal/LocalEntityManager.java b/core/src/main/java/brooklyn/management/internal/LocalEntityManager.java
index aada104..3e9e4c0 100644
--- a/core/src/main/java/brooklyn/management/internal/LocalEntityManager.java
+++ b/core/src/main/java/brooklyn/management/internal/LocalEntityManager.java
@@ -54,8 +54,6 @@ import brooklyn.entity.trait.Startable;
 import brooklyn.internal.storage.BrooklynStorage;
 import brooklyn.management.AccessController;
 import brooklyn.management.Task;
-import brooklyn.management.internal.ManagementTransitionInfo.ManagementTransitionMode;
-import brooklyn.management.internal.ManagementTransitionInfo.BrooklynObjectManagementMode;
 import brooklyn.policy.Enricher;
 import brooklyn.policy.EnricherSpec;
 import brooklyn.policy.Policy;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/be6fd97e/core/src/main/java/brooklyn/management/internal/LocalLocationManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/internal/LocalLocationManager.java b/core/src/main/java/brooklyn/management/internal/LocalLocationManager.java
index fec09f4..cc44bf8 100644
--- a/core/src/main/java/brooklyn/management/internal/LocalLocationManager.java
+++ b/core/src/main/java/brooklyn/management/internal/LocalLocationManager.java
@@ -42,8 +42,6 @@ import brooklyn.location.basic.AbstractLocation;
 import brooklyn.location.basic.LocationInternal;
 import brooklyn.management.AccessController;
 import brooklyn.management.entitlement.Entitlements;
-import brooklyn.management.internal.ManagementTransitionInfo.ManagementTransitionMode;
-import brooklyn.management.internal.ManagementTransitionInfo.BrooklynObjectManagementMode;
 import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.exceptions.RuntimeInterruptedException;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/be6fd97e/core/src/main/java/brooklyn/management/internal/ManagementTransitionInfo.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/internal/ManagementTransitionInfo.java b/core/src/main/java/brooklyn/management/internal/ManagementTransitionInfo.java
index 6ce714a..550c977 100644
--- a/core/src/main/java/brooklyn/management/internal/ManagementTransitionInfo.java
+++ b/core/src/main/java/brooklyn/management/internal/ManagementTransitionInfo.java
@@ -20,121 +20,11 @@ package brooklyn.management.internal;
 
 import brooklyn.management.ManagementContext;
 
-import com.google.common.base.Preconditions;
-
 public class ManagementTransitionInfo {
 
     final ManagementContext mgmtContext;
     final ManagementTransitionMode mode;
     
-    public enum BrooklynObjectManagementMode {
-        /** item does not exist, not in memory, nor persisted (e.g. creating for first time, or finally destroying) */
-        NONEXISTENT, 
-        /** item exists or existed elsewhere, i.e. there is persisted state, but is not loaded here */
-        UNMANAGED_PERSISTED, 
-        
-        @Deprecated /** @deprecated marking places where we aren't sure */
-        /** either nonexistent or persisted by unmanaged */
-        ITEM_UNKNOWN, 
-        
-        /** item is loaded but read-only (ie not actively managed here) */
-        LOADED_READ_ONLY, 
-        /** item is actively managed here */
-        MANAGED_PRIMARY 
-    }
-    
-    public static class ManagementTransitionMode {
-
-        // XXX
-//-        CREATING(false, false, false),
-//-        DESTROYING(false, false, false),
-//-        REBINDING_READONLY(true, true, true),
-//-        REBINDING_NO_LONGER_PRIMARY(false, true, true), 
-//-        REBINDING_BECOMING_PRIMARY(true, false, true),
-//-        REBINDING_DESTROYED(true, true, true),
-//-        REBINDING_CREATING(false, false, true);
-//-        
-//-        private final boolean wasReadOnly;
-//-        private final boolean isReadOnly;
-//-        private final boolean isRebinding;
-
-//        /** Item is being created fresh, for the first time */ 
-//        CREATING(NONEXISTENT, MANAGED_PRIMARY),
-//        /** Item is being destroyed / stopping permanently */ 
-//        DESTROYING(MANAGED_PRIMARY, NONEXISTENT),
-//        
-//        /** Item is being mirrored (refreshed or created) here from a serialized/specified state */
-//        REBINDING_READONLY(LOADED_READ_ONLY, LOADED_READ_ONLY),
-//        /** Item management is stopping here, going elsewhere */
-//        REBINDING_NO_LONGER_PRIMARY(MANAGED_PRIMARY, LOADED_READ_ONLY), 
-//        /** Item management is starting here, having previously been running elsewhere */
-//        REBINDING_BECOMING_PRIMARY(LOADED_READ_ONLY, MANAGED_PRIMARY),
-//        /** Item has been managed here, and is being re-read for management again (e.g. applying a transform) */
-//        REBINDING_ACTIVE_AGAIN(MANAGED_PRIMARY, MANAGED_PRIMARY),
-//        /** Item was being mirrored but has now been destroyed  */
-//        REBINDING_DESTROYED(LOADED_READ_ONLY, NONEXISTENT),
-//
-//        /** Item management is starting here, from persisted state */
-//        REBINDING_CREATING(NodeManagementMode.UNMANAGED_PERSISTED, NodeManagementMode.MANAGED_PRIMARY);
-        
-//        private final static ManagementTransitionTargetMode NONE = ManagementTransitionTargetMode.NONE;
-        private final BrooklynObjectManagementMode modeBefore, modeAfter;
-
-        private ManagementTransitionMode(BrooklynObjectManagementMode modeBefore, BrooklynObjectManagementMode modeAfter) {
-            this.modeBefore = modeBefore;
-            this.modeAfter = modeAfter;
-        }
-        
-        public static ManagementTransitionMode transitioning(BrooklynObjectManagementMode modeBefore, BrooklynObjectManagementMode modeAfter) {
-            return new ManagementTransitionMode(Preconditions.checkNotNull(modeBefore, "modeBefore"), Preconditions.checkNotNull(modeAfter, "modeAfter"));
-        }
-
-        @Deprecated /** @deprecated marking places where we aren't sure */
-        public static ManagementTransitionMode guessing(BrooklynObjectManagementMode modeBefore, BrooklynObjectManagementMode modeAfter) {
-            return transitioning(modeBefore, modeAfter);
-        }
-
-        public BrooklynObjectManagementMode getModeBefore() {
-            return modeBefore;
-        }
-        
-        public BrooklynObjectManagementMode getModeAfter() {
-            return modeAfter;
-        }
-        
-        public boolean wasNotLoaded() {
-            return getModeBefore()==BrooklynObjectManagementMode.NONEXISTENT || getModeBefore()==BrooklynObjectManagementMode.UNMANAGED_PERSISTED || getModeBefore()==BrooklynObjectManagementMode.ITEM_UNKNOWN;
-        }
-
-        public boolean isNoLongerLoaded() {
-            return getModeAfter()==BrooklynObjectManagementMode.NONEXISTENT || getModeAfter()==BrooklynObjectManagementMode.UNMANAGED_PERSISTED || getModeAfter()==BrooklynObjectManagementMode.ITEM_UNKNOWN;
-        }
-
-        public boolean wasPrimary() {
-            return getModeBefore()==BrooklynObjectManagementMode.MANAGED_PRIMARY;
-        }
-        
-        public boolean isPrimary() {
-            return getModeAfter()==BrooklynObjectManagementMode.MANAGED_PRIMARY;
-        }
-
-        public boolean wasReadOnly() {
-            return getModeBefore()==BrooklynObjectManagementMode.LOADED_READ_ONLY;
-        }
-        
-        public boolean isReadOnly() {
-            return getModeAfter()==BrooklynObjectManagementMode.LOADED_READ_ONLY;
-        }
-
-        public boolean isDestroying() {
-            return getModeAfter()==BrooklynObjectManagementMode.NONEXISTENT;
-        }
-
-        public boolean isCreating() {
-            return getModeBefore()==BrooklynObjectManagementMode.NONEXISTENT;
-        }
-    }
-    
     public ManagementTransitionInfo(ManagementContext mgmtContext, ManagementTransitionMode mode) {
         this.mgmtContext = mgmtContext;
         this.mode = mode;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/be6fd97e/core/src/main/java/brooklyn/management/internal/ManagementTransitionMode.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/internal/ManagementTransitionMode.java b/core/src/main/java/brooklyn/management/internal/ManagementTransitionMode.java
new file mode 100644
index 0000000..3c630e1
--- /dev/null
+++ b/core/src/main/java/brooklyn/management/internal/ManagementTransitionMode.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package brooklyn.management.internal;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+public class ManagementTransitionMode {
+
+    private static final Logger log = LoggerFactory.getLogger(ManagementTransitionMode.class);
+    
+    private final BrooklynObjectManagementMode modeBefore, modeAfter;
+
+    private ManagementTransitionMode(BrooklynObjectManagementMode modeBefore, BrooklynObjectManagementMode modeAfter) {
+        this.modeBefore = modeBefore;
+        this.modeAfter = modeAfter;
+    }
+    
+    public static ManagementTransitionMode transitioning(BrooklynObjectManagementMode modeBefore, BrooklynObjectManagementMode modeAfter) {
+        return new ManagementTransitionMode(Preconditions.checkNotNull(modeBefore, "modeBefore"), Preconditions.checkNotNull(modeAfter, "modeAfter"));
+    }
+
+    @Deprecated /** @deprecated marking places where we aren't sure */
+    public static ManagementTransitionMode guessing(BrooklynObjectManagementMode modeBefore, BrooklynObjectManagementMode modeAfter) {
+        return transitioning(modeBefore, modeAfter);
+    }
+
+    /** @return the mode this object was previously managed as */
+    public BrooklynObjectManagementMode getModeBefore() {
+        return modeBefore;
+    }
+    
+    /** @return the mode this object is now being managed as */
+    public BrooklynObjectManagementMode getModeAfter() {
+        return modeAfter;
+    }
+    
+    /** This management node was previously not loaded here, 
+     * either it did not exist (and is just being created) or it was in persisted state but
+     * not loaded at this node. */
+    public boolean wasNotLoaded() {
+        return getModeBefore()==BrooklynObjectManagementMode.NONEXISTENT || getModeBefore()==BrooklynObjectManagementMode.UNMANAGED_PERSISTED;
+    }
+
+    /** This management node is now not going to be loaded here, either it is being destroyed
+     * (not known anywhere, not even persisted) or simply forgotten here */
+    public boolean isNoLongerLoaded() {
+        return getModeAfter()==BrooklynObjectManagementMode.NONEXISTENT || getModeAfter()==BrooklynObjectManagementMode.UNMANAGED_PERSISTED;
+    }
+
+    /** This management node was the master for the given object */
+    public boolean wasPrimary() {
+        return getModeBefore()==BrooklynObjectManagementMode.MANAGED_PRIMARY;
+    }
+
+    /** This management node is now the master for the given object */
+    public boolean isPrimary() {
+        return getModeAfter()==BrooklynObjectManagementMode.MANAGED_PRIMARY;
+    }
+
+    /** Object was previously loaded as read-only at this management node;
+     * active management was occurring elsewhere (or not at all)
+     */
+    public boolean wasReadOnly() {
+        return getModeBefore()==BrooklynObjectManagementMode.LOADED_READ_ONLY;
+    }
+    
+    /** Object is now being loaded as read-only at this management node;
+     * expect active management to be occurring elsewhere
+     */
+    public boolean isReadOnly() {
+        return getModeAfter()==BrooklynObjectManagementMode.LOADED_READ_ONLY;
+    }
+    
+    /** Object is being created:
+     * previously did not exist (not even in persisted state);
+     * implies that we are the active manager creating it,
+     * i.e. {@link #getModeAfter()} should indicate {@link BrooklynObjectManagementMode#MANAGED_PRIMARY}.
+     * (if we're read-only and the manager has just created it, 
+     * {@link #getModeBefore()} should indicate {@link BrooklynObjectManagementMode#UNMANAGED_PERSISTED})
+     */
+    public boolean isCreating() {
+        if (getModeBefore()!=BrooklynObjectManagementMode.NONEXISTENT)
+            return false;
+        
+        if (getModeAfter()==BrooklynObjectManagementMode.LOADED_READ_ONLY) {
+            log.warn("isCreating set on RO object; highly irregular!");
+        }
+        return true;
+    }
+
+    /** Object is being destroyed:
+     * either destroyed elsewhere and we're catching up (in read-only mode),
+     * or we've been the active manager and are destroying it */
+    public boolean isDestroying() {
+        return getModeAfter()==BrooklynObjectManagementMode.NONEXISTENT;
+    }
+    
+    @Override
+    public String toString() {
+        return ManagementTransitionMode.class.getSimpleName()+"["+getModeBefore()+"->"+getModeAfter()+"]";
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/be6fd97e/core/src/main/java/brooklyn/management/internal/NonDeploymentEntityManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/internal/NonDeploymentEntityManager.java b/core/src/main/java/brooklyn/management/internal/NonDeploymentEntityManager.java
index c3720b1..281a3a4 100644
--- a/core/src/main/java/brooklyn/management/internal/NonDeploymentEntityManager.java
+++ b/core/src/main/java/brooklyn/management/internal/NonDeploymentEntityManager.java
@@ -27,7 +27,6 @@ import brooklyn.entity.Entity;
 import brooklyn.entity.proxying.EntitySpec;
 import brooklyn.entity.proxying.EntityTypeRegistry;
 import brooklyn.management.ManagementContext;
-import brooklyn.management.internal.ManagementTransitionInfo.ManagementTransitionMode;
 import brooklyn.policy.Enricher;
 import brooklyn.policy.EnricherSpec;
 import brooklyn.policy.Policy;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/be6fd97e/core/src/main/java/brooklyn/management/internal/NonDeploymentLocationManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/internal/NonDeploymentLocationManager.java b/core/src/main/java/brooklyn/management/internal/NonDeploymentLocationManager.java
index a11d876..31f9670 100644
--- a/core/src/main/java/brooklyn/management/internal/NonDeploymentLocationManager.java
+++ b/core/src/main/java/brooklyn/management/internal/NonDeploymentLocationManager.java
@@ -25,7 +25,6 @@ import java.util.Map;
 import brooklyn.location.Location;
 import brooklyn.location.LocationSpec;
 import brooklyn.management.ManagementContext;
-import brooklyn.management.internal.ManagementTransitionInfo.ManagementTransitionMode;
 
 public class NonDeploymentLocationManager implements LocationManagerInternal {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/be6fd97e/core/src/test/java/brooklyn/entity/rebind/ActivePartialRebindTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/ActivePartialRebindTest.java b/core/src/test/java/brooklyn/entity/rebind/ActivePartialRebindTest.java
new file mode 100644
index 0000000..52cd3b1
--- /dev/null
+++ b/core/src/test/java/brooklyn/entity/rebind/ActivePartialRebindTest.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package brooklyn.entity.rebind;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import brooklyn.basic.BrooklynObject;
+import brooklyn.entity.Entity;
+import brooklyn.entity.basic.AbstractEntity;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.test.entity.TestEntity;
+import brooklyn.util.text.Strings;
+
+public class ActivePartialRebindTest extends RebindTestFixtureWithApp {
+
+    private static final Logger log = LoggerFactory.getLogger(ActivePartialRebindTest.class);
+    
+    protected void doPartialRebindByObjectById(String ...ids) {
+        RebindManagerImpl rm = (RebindManagerImpl) origManagementContext.getRebindManager();
+        rm.testRebindNodeXXX(ids);        
+    }
+    
+    @Test
+    public void testRebindOneSimple() throws Exception {
+        TestEntity c1 = origApp.addChild(EntitySpec.create(TestEntity.class));
+        Entities.manage(c1);
+        AbstractEntity c1r = Entities.deproxy(c1);
+        
+        doPartialRebindByObjectById(c1.getId());
+        
+        BrooklynObject c2 = origManagementContext.lookup(c1.getId());
+        AbstractEntity c2r = Entities.deproxy((Entity)c2);
+        
+        Assert.assertTrue(c2 == c1, "Proxy instance should be the same: "+c1+" / "+c2);
+        Assert.assertFalse(c2r == c1r, "Real instance should NOT be the same: "+c1r+" / "+c2r);
+    }
+
+    @Test(groups="Integration")
+    public void testRebindCheckingMemoryLeak() throws Exception {
+        TestEntity c1 = origApp.addChild(EntitySpec.create(TestEntity.class));
+        Entities.manage(c1);
+        c1.setConfig(TestEntity.CONF_NAME, Strings.makeRandomId(1000000));
+        
+        gcAndLog("before");
+        long used0 = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
+        for (int i=0; i<500; i++) {
+            doPartialRebindByObjectById(c1.getId());
+            origManagementContext.getGarbageCollector().gcIteration();
+            gcAndLog("iteration "+i);
+            if (i==5) used0 = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); 
+        }
+        gcAndLog("after");
+        long used1 = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
+
+        Assert.assertTrue(used1 - used0 < 5000000, "Expected leak of less than 5M; leak was: from "+Strings.makeJavaSizeString(used0)+" to "+Strings.makeJavaSizeString(used1));
+    }
+
+    private void gcAndLog(String prefix) {
+        origManagementContext.getGarbageCollector().gcIteration();
+        System.gc(); System.gc();
+        log.info(prefix+": "+origManagementContext.getGarbageCollector().getUsageString());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/be6fd97e/core/src/test/java/brooklyn/entity/rebind/RebindOnlySomeEntitiesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindOnlySomeEntitiesTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindOnlySomeEntitiesTest.java
deleted file mode 100644
index a7b54b7..0000000
--- a/core/src/test/java/brooklyn/entity/rebind/RebindOnlySomeEntitiesTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.entity.rebind;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNotSame;
-
-import org.testng.annotations.Test;
-
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.proxying.EntitySpec;
-import brooklyn.test.entity.TestEntity;
-
-public class RebindOnlySomeEntitiesTest extends RebindTestFixtureWithApp {
-
-    @Test
-    public void testRebindOnlySomeSimple() throws Exception {
-        TestEntity c1 = origApp.addChild(EntitySpec.create(TestEntity.class));
-        Entities.manage(c1);
-        
-        // XXX
-        newApp = rebind();
-        
-        assertNotSame(newApp, origApp);
-        assertEquals(newApp.getId(), origApp.getId());
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/be6fd97e/utils/common/src/main/java/brooklyn/util/exceptions/Exceptions.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/exceptions/Exceptions.java b/utils/common/src/main/java/brooklyn/util/exceptions/Exceptions.java
index 10126e3..066ecea 100644
--- a/utils/common/src/main/java/brooklyn/util/exceptions/Exceptions.java
+++ b/utils/common/src/main/java/brooklyn/util/exceptions/Exceptions.java
@@ -57,8 +57,10 @@ public class Exceptions {
     private static List<Class<? extends Throwable>> BORING_PREFIX_THROWABLE_EXACT_TYPES = ImmutableList.<Class<? extends Throwable>>of(
         IllegalStateException.class, RuntimeException.class, CompoundRuntimeException.class);
 
-    /** Returns whether this is throwable either known to be boring or to have an unuseful prefix */
+    /** Returns whether this is throwable either known to be boring or to have an unuseful prefix;
+     * null is *not* boring. */
     public static boolean isPrefixBoring(Throwable t) {
+        if (t==null) return false;
         if (isBoring(t))
             return true;
         for (Class<? extends Throwable> type: BORING_PREFIX_THROWABLE_EXACT_TYPES)
@@ -165,7 +167,7 @@ public class Exceptions {
         }
         // if no messages so far (ie we will be the toString) then remove boring prefixes from the message
         Throwable messagesCause = collapsed;
-        while (isPrefixBoring(messagesCause) && Strings.isBlank(message)) {
+        while (messagesCause!=null && isPrefixBoring(messagesCause) && Strings.isBlank(message)) {
             collapseCount++;
             if (Strings.isNonBlank(messagesCause.getMessage())) {
                 message = messagesCause.getMessage();
@@ -178,7 +180,7 @@ public class Exceptions {
         if (collapseCount==0 && !includeAllCausalMessages)
             return source;
         
-        if (collapseCount==0) {
+        if (collapseCount==0 && messagesCause!=null) {
             message = messagesCause.toString();
             messagesCause = messagesCause.getCause();
         }