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 2016/02/01 18:50:45 UTC

[03/51] [abbrv] [partial] brooklyn-server git commit: move subdir from incubator up a level as it is promoted to its own repo (first non-incubator commit!)

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityChangeListener.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityChangeListener.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityChangeListener.java
deleted file mode 100644
index b7f53a4..0000000
--- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityChangeListener.java
+++ /dev/null
@@ -1,78 +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 org.apache.brooklyn.core.mgmt.internal;
-
-import org.apache.brooklyn.api.effector.Effector;
-import org.apache.brooklyn.api.policy.Policy;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.api.sensor.Enricher;
-import org.apache.brooklyn.api.sensor.Feed;
-import org.apache.brooklyn.config.ConfigKey;
-
-public interface EntityChangeListener {
-
-    // TODO for testing only!
-    public static final EntityChangeListener NOOP = new EntityChangeListener() {
-        @Override public void onChanged() {}
-        @Override public void onAttributeChanged(AttributeSensor<?> attribute) {}
-        @Override public void onConfigChanged(ConfigKey<?> key) {}
-        @Override public void onLocationsChanged() {}
-        @Override public void onMembersChanged() {}
-        @Override public void onTagsChanged() {}
-        @Override public void onChildrenChanged() {}
-        @Override public void onPolicyAdded(Policy policy) {}
-        @Override public void onPolicyRemoved(Policy policy) {}
-        @Override public void onEnricherAdded(Enricher enricher) {}
-        @Override public void onEnricherRemoved(Enricher enricher) {}
-        @Override public void onFeedAdded(Feed feed) {}
-        @Override public void onFeedRemoved(Feed feed) {}
-        @Override public void onEffectorStarting(Effector<?> effector, Object parameters) {}
-        @Override public void onEffectorCompleted(Effector<?> effector) {}
-    };
-    
-    void onChanged();
-
-    void onAttributeChanged(AttributeSensor<?> attribute);
-
-    void onConfigChanged(ConfigKey<?> key);
-
-    void onLocationsChanged();
-    
-    void onTagsChanged();
-
-    void onMembersChanged();
-
-    void onChildrenChanged();
-
-    void onPolicyAdded(Policy policy);
-
-    void onPolicyRemoved(Policy policy);
-
-    void onEnricherAdded(Enricher enricher);
-
-    void onEnricherRemoved(Enricher enricher);
-
-    void onFeedAdded(Feed feed);
-
-    void onFeedRemoved(Feed feed);
-
-    void onEffectorStarting(Effector<?> effector, Object parameters);
-    
-    void onEffectorCompleted(Effector<?> effector);
-}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityManagementSupport.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityManagementSupport.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityManagementSupport.java
deleted file mode 100644
index 3811542..0000000
--- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityManagementSupport.java
+++ /dev/null
@@ -1,480 +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 org.apache.brooklyn.core.mgmt.internal;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.apache.brooklyn.api.effector.Effector;
-import org.apache.brooklyn.api.entity.Application;
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.mgmt.ExecutionContext;
-import org.apache.brooklyn.api.mgmt.ManagementContext;
-import org.apache.brooklyn.api.mgmt.SubscriptionContext;
-import org.apache.brooklyn.api.mgmt.entitlement.EntitlementManager;
-import org.apache.brooklyn.api.policy.Policy;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.api.sensor.Enricher;
-import org.apache.brooklyn.api.sensor.Feed;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.entity.AbstractEntity;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.core.mgmt.entitlement.Entitlements;
-import org.apache.brooklyn.core.mgmt.entitlement.Entitlements.EntityAndItem;
-import org.apache.brooklyn.core.mgmt.entitlement.Entitlements.StringAndArgument;
-import org.apache.brooklyn.core.mgmt.internal.NonDeploymentManagementContext.NonDeploymentManagementContextMode;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Stopwatch;
-
-/**
- * Encapsulates management activities at an entity.
- * <p>
- * On entity deployment, ManagementContext.manage(entity) causes
- * <p>
- * * onManagementStarting(ManagementContext)
- * * onManagementStartingSubscriptions()
- * * onManagementStartingSensorEmissions()
- * * onManagementStartingExecutions()
- * * onManagementStarted() - when all the above is said and done
- * * onManagementStartingHere();
- * <p>
- * on unmanage it hits onManagementStoppingHere() then onManagementStopping().
- * <p>
- * When an entity's management migrates, it invokes onManagementStoppingHere() at the old location,
- * then onManagementStartingHere() at the new location.
- */
-public class EntityManagementSupport {
-
-    private static final Logger log = LoggerFactory.getLogger(EntityManagementSupport.class);
-    
-    public EntityManagementSupport(AbstractEntity entity) {
-        this.entity = entity;
-        nonDeploymentManagementContext = new NonDeploymentManagementContext(entity, NonDeploymentManagementContextMode.PRE_MANAGEMENT);
-    }
-
-    protected transient AbstractEntity entity;
-    NonDeploymentManagementContext nonDeploymentManagementContext;
-    
-    protected transient ManagementContext initialManagementContext;
-    protected transient ManagementContext managementContext;
-    protected transient SubscriptionContext subscriptionContext;
-    protected transient ExecutionContext executionContext;
-    
-    protected final AtomicBoolean managementContextUsable = new AtomicBoolean(false);
-    protected final AtomicBoolean currentlyDeployed = new AtomicBoolean(false);
-    protected final AtomicBoolean everDeployed = new AtomicBoolean(false);
-    protected Boolean readOnly = null;
-    protected final AtomicBoolean managementFailed = new AtomicBoolean(false);
-    
-    private volatile EntityChangeListener entityChangeListener = EntityChangeListener.NOOP;
-
-    /**
-     * Whether this entity is managed (i.e. "onManagementStarting" has been called, so the framework knows about it,
-     * and it has not been unmanaged).
-     */
-    public boolean isDeployed() {
-        return currentlyDeployed.get();
-    }
-
-    public boolean isNoLongerManaged() {
-        return wasDeployed() && !isDeployed();
-    }
-
-    /** whether entity has ever been deployed (managed) */
-    public boolean wasDeployed() {
-        return everDeployed.get();
-    }
-    
-    @Beta
-    public void setReadOnly(boolean isReadOnly) {
-        if (isDeployed())
-            throw new IllegalStateException("Cannot set read only after deployment");
-        this.readOnly = isReadOnly;
-    }
-
-    /** Whether the entity and its adjuncts should be treated as read-only;
-     * may be null briefly when initializing if RO status is unknown. */
-    @Beta
-    public Boolean isReadOnlyRaw() {
-        return readOnly;
-    }
-
-    /** Whether the entity and its adjuncts should be treated as read-only;
-     * error if initializing and RO status is unknown. */
-    @Beta
-    public boolean isReadOnly() {
-        Preconditions.checkNotNull(readOnly, "Read-only status of %s not yet known", entity);
-        return readOnly;
-    }
-
-    /**
-     * Whether the entity's management lifecycle is complete (i.e. both "onManagementStarting" and "onManagementStarted" have
-     * been called, and it is has not been unmanaged). 
-     */
-    public boolean isFullyManaged() {
-        return (nonDeploymentManagementContext == null) && currentlyDeployed.get();
-    }
-
-    public synchronized void setManagementContext(ManagementContextInternal val) {
-        if (initialManagementContext != null) {
-            throw new IllegalStateException("Initial management context is already set for "+entity+"; cannot change");
-        }
-        if (managementContext != null && !managementContext.equals(val)) {
-            throw new IllegalStateException("Management context is already set for "+entity+"; cannot change");
-        }
-        
-        this.initialManagementContext = checkNotNull(val, "managementContext");
-        if (nonDeploymentManagementContext != null) {
-            nonDeploymentManagementContext.setManagementContext(val);
-        }
-    }
-    
-    public void onRebind(ManagementTransitionInfo info) {
-        nonDeploymentManagementContext.setMode(NonDeploymentManagementContextMode.MANAGEMENT_REBINDING);
-    }
-    
-    public void onManagementStarting(ManagementTransitionInfo info) {
-        try {
-            synchronized (this) {
-                boolean alreadyManaging = isDeployed();
-                
-                if (alreadyManaging) {
-                    log.warn("Already managed: "+entity+" ("+nonDeploymentManagementContext+"); onManagementStarting is no-op");
-                } else if (nonDeploymentManagementContext == null || !nonDeploymentManagementContext.getMode().isPreManaged()) {
-                    throw new IllegalStateException("Not in expected pre-managed state: "+entity+" ("+nonDeploymentManagementContext+")");
-                }
-                if (managementContext != null && !managementContext.equals(info.getManagementContext())) {
-                    throw new IllegalStateException("Already has management context: "+managementContext+"; can't set "+info.getManagementContext());
-                }
-                if (initialManagementContext != null && !initialManagementContext.equals(info.getManagementContext())) {
-                    throw new IllegalStateException("Already has different initial management context: "+initialManagementContext+"; can't set "+info.getManagementContext());
-                }
-                if (alreadyManaging) {
-                    return;
-                }
-                
-                this.managementContext = info.getManagementContext();
-                nonDeploymentManagementContext.setMode(NonDeploymentManagementContextMode.MANAGEMENT_STARTING);
-                
-                if (!isReadOnly()) {
-                    nonDeploymentManagementContext.getSubscriptionManager().setDelegate((AbstractSubscriptionManager) managementContext.getSubscriptionManager());
-                    nonDeploymentManagementContext.getSubscriptionManager().startDelegatingForSubscribing();
-                }
-    
-                managementContextUsable.set(true);
-                currentlyDeployed.set(true);
-                everDeployed.set(true);
-                
-                entityChangeListener = new EntityChangeListenerImpl();
-            }
-            
-            /*
-             * TODO framework starting events - phase 1, including rebind
-             *  - establish hierarchy (child, groups, etc; construction if necessary on rebind)
-             *  - set location
-             *  - set local config values
-             *  - set saved sensor values
-             *  - register subscriptions -- BUT nothing is allowed to execute
-             *  [these operations may be done before we invoke starting also; above can happen in any order;
-             *  sensor _publications_ and executor submissions are queued]
-             *  then:  set the management context and the entity is "managed" from the perspective of external viewers (ManagementContext.isManaged(entity) returns true)
-             */
-            
-            if (!isReadOnly()) {
-                entity.onManagementStarting();
-            }
-        } catch (Throwable t) {
-            managementFailed.set(true);
-            throw Exceptions.propagate(t);
-        }
-    }
-
-    @SuppressWarnings("deprecation")
-    public void onManagementStarted(ManagementTransitionInfo info) {
-        try {
-            synchronized (this) {
-                boolean alreadyManaged = isFullyManaged();
-                
-                if (alreadyManaged) {
-                    log.warn("Already managed: "+entity+" ("+nonDeploymentManagementContext+"); onManagementStarted is no-op");
-                } else if (nonDeploymentManagementContext == null || nonDeploymentManagementContext.getMode() != NonDeploymentManagementContextMode.MANAGEMENT_STARTING) {
-                    throw new IllegalStateException("Not in expected \"management starting\" state: "+entity+" ("+nonDeploymentManagementContext+")");
-                }
-                if (managementContext != info.getManagementContext()) {
-                    throw new IllegalStateException("Already has management context: "+managementContext+"; can't set "+info.getManagementContext());
-                }
-                if (alreadyManaged) {
-                    return;
-                }
-                
-                nonDeploymentManagementContext.setMode(NonDeploymentManagementContextMode.MANAGEMENT_STARTED);
-                
-                /*
-                 * - set derived/inherited config values
-                 * - publish all queued sensors
-                 * - start all queued executions (e.g. subscription delivery)
-                 * [above happens in exactly this order, at each entity]
-                 * then: the entity internally knows it fully managed (ManagementSupport.isManaged() returns true -- though not sure we need that);
-                 * subsequent sensor events and executions occur directly (no queueing)
-                 */
-                
-                if (!isReadOnly()) {
-                    nonDeploymentManagementContext.getSubscriptionManager().startDelegatingForPublishing();
-                }
-                
-                // TODO more of the above
-                // TODO custom started activities
-                // (elaborate or remove ^^^ ? -AH, Sept 2014)
-            }
-            
-            if (!isReadOnly()) {
-                entity.onManagementBecomingMaster();
-                entity.onManagementStarted();
-            }
-            
-            synchronized (this) {
-                nonDeploymentManagementContext = null;
-            }
-        } catch (Throwable t) {
-            managementFailed.set(true);
-            throw Exceptions.propagate(t);
-        }
-    }
-    
-    @SuppressWarnings("deprecation")
-    public void onManagementStopping(ManagementTransitionInfo info) {
-        synchronized (this) {
-            if (managementContext != info.getManagementContext()) {
-                throw new IllegalStateException("onManagementStopping encountered different management context for "+entity+
-                    (!wasDeployed() ? " (wasn't deployed)" : !isDeployed() ? " (no longer deployed)" : "")+
-                    ": "+managementContext+"; expected "+info.getManagementContext()+" (may be a pre-registered entity which was never properly managed)");
-            }
-            Stopwatch startTime = Stopwatch.createStarted();
-            while (!managementFailed.get() && nonDeploymentManagementContext!=null && 
-                    nonDeploymentManagementContext.getMode()==NonDeploymentManagementContextMode.MANAGEMENT_STARTING) {
-                // still becoming managed
-                try {
-                    if (startTime.elapsed(TimeUnit.SECONDS) > 30) {
-                        // emergency fix, 30s timeout for management starting
-                        log.error("Management stopping event "+info+" in "+this+" timed out waiting for start; proceeding to stopping");
-                        break;
-                    }
-                    wait(100);
-                } catch (InterruptedException e) {
-                    Exceptions.propagate(e);
-                }
-            }
-            if (nonDeploymentManagementContext==null) {
-                nonDeploymentManagementContext = new NonDeploymentManagementContext(entity, NonDeploymentManagementContextMode.MANAGEMENT_STOPPING);
-            } else {
-                // already stopped? or not started?
-                nonDeploymentManagementContext.setMode(NonDeploymentManagementContextMode.MANAGEMENT_STOPPING);
-            }
-        }
-        // TODO custom stopping activities
-        // TODO framework stopping events - no more sensors, executions, etc
-        // (elaborate or remove ^^^ ? -AH, Sept 2014)
-        
-        if (!isReadOnly() && info.getMode().isDestroying()) {
-            // if we support remote parent of local child, the following call will need to be properly remoted
-            if (entity.getParent()!=null) entity.getParent().removeChild(entity.getProxyIfAvailable());
-        }
-        // new subscriptions will be queued / not allowed
-        nonDeploymentManagementContext.getSubscriptionManager().stopDelegatingForSubscribing();
-        // new publications will be queued / not allowed
-        nonDeploymentManagementContext.getSubscriptionManager().stopDelegatingForPublishing();
-        
-        if (!isReadOnly()) {
-            entity.onManagementNoLongerMaster();
-            entity.onManagementStopped();
-        }
-    }
-    
-    public void onManagementStopped(ManagementTransitionInfo info) {
-        synchronized (this) {
-            if (managementContext == null && nonDeploymentManagementContext.getMode() == NonDeploymentManagementContextMode.MANAGEMENT_STOPPED) {
-                return;
-            }
-            if (managementContext != info.getManagementContext()) {
-                throw new IllegalStateException("Has different management context: "+managementContext+"; expected "+info.getManagementContext());
-            }
-            getSubscriptionContext().unsubscribeAll();
-            entityChangeListener = EntityChangeListener.NOOP;
-            managementContextUsable.set(false);
-            currentlyDeployed.set(false);
-            executionContext = null;
-            subscriptionContext = null;
-        }
-        
-        // TODO framework stopped activities, e.g. serialize state ?
-        entity.invalidateReferences();
-        
-        synchronized (this) {
-            managementContext = null;
-            nonDeploymentManagementContext.setMode(NonDeploymentManagementContextMode.MANAGEMENT_STOPPED);
-        }
-    }
-
-    @VisibleForTesting
-    @Beta
-    public boolean isManagementContextReal() {
-        return managementContextUsable.get();
-    }
-    
-    public synchronized ManagementContext getManagementContext() {
-        return (managementContextUsable.get()) ? managementContext : nonDeploymentManagementContext;
-    }    
-    
-    public synchronized ExecutionContext getExecutionContext() {
-        if (executionContext!=null) return executionContext;
-        if (managementContextUsable.get()) {
-            executionContext = managementContext.getExecutionContext(entity);
-            return executionContext;
-        }
-        return nonDeploymentManagementContext.getExecutionContext(entity);
-    }
-    public synchronized SubscriptionContext getSubscriptionContext() {
-        if (subscriptionContext!=null) return subscriptionContext;
-        if (managementContextUsable.get()) {
-            subscriptionContext = managementContext.getSubscriptionContext(entity);
-            return subscriptionContext;
-        }
-        return nonDeploymentManagementContext.getSubscriptionContext(entity);
-    }
-    public synchronized EntitlementManager getEntitlementManager() {
-        return getManagementContext().getEntitlementManager();
-    }
-
-    public void attemptLegacyAutodeployment(String effectorName) {
-        synchronized (this) {
-            if (managementContext != null) {
-                log.warn("Autodeployment suggested but not required for " + entity + "." + effectorName);
-                return;
-            }
-            if (entity instanceof Application) {
-                log.warn("Autodeployment with new management context triggered for " + entity + "." + effectorName + " -- will not be supported in future. Explicit manage call required.");
-                if (initialManagementContext != null) {
-                    initialManagementContext.getEntityManager().manage(entity);
-                } else {
-                    Entities.startManagement(entity);
-                }
-                return;
-            }
-        }
-        if ("start".equals(effectorName)) {
-            Entity e=entity;
-            if (e.getParent()!=null && ((EntityInternal)e.getParent()).getManagementSupport().isDeployed()) { 
-                log.warn("Autodeployment in parent's management context triggered for "+entity+"."+effectorName+" -- will not be supported in future. Explicit manage call required.");
-                ((EntityInternal)e.getParent()).getManagementContext().getEntityManager().manage(entity);
-                return;
-            }
-        }
-        log.warn("Autodeployment not available for "+entity+"."+effectorName);
-    }
-    
-    public EntityChangeListener getEntityChangeListener() {
-        return entityChangeListener;
-    }
-    
-    private class EntityChangeListenerImpl implements EntityChangeListener {
-        @Override
-        public void onChanged() {
-            getManagementContext().getRebindManager().getChangeListener().onChanged(entity);
-        }
-        @Override
-        public void onChildrenChanged() {
-            getManagementContext().getRebindManager().getChangeListener().onChanged(entity);
-        }
-        @Override
-        public void onLocationsChanged() {
-            getManagementContext().getRebindManager().getChangeListener().onChanged(entity);
-        }
-        @Override
-        public void onTagsChanged() {
-            getManagementContext().getRebindManager().getChangeListener().onChanged(entity);
-        }
-        @Override
-        public void onMembersChanged() {
-            getManagementContext().getRebindManager().getChangeListener().onChanged(entity);
-        }
-        @Override
-        public void onPolicyAdded(Policy policy) {
-            getManagementContext().getRebindManager().getChangeListener().onChanged(entity);
-            getManagementContext().getRebindManager().getChangeListener().onManaged(policy);
-        }
-        @Override
-        public void onEnricherAdded(Enricher enricher) {
-            getManagementContext().getRebindManager().getChangeListener().onChanged(entity);
-            getManagementContext().getRebindManager().getChangeListener().onManaged(enricher);
-        }
-        @Override
-        public void onFeedAdded(Feed feed) {
-            getManagementContext().getRebindManager().getChangeListener().onChanged(entity);
-            getManagementContext().getRebindManager().getChangeListener().onManaged(feed);
-        }
-        @Override
-        public void onPolicyRemoved(Policy policy) {
-            getManagementContext().getRebindManager().getChangeListener().onChanged(entity);
-            getManagementContext().getRebindManager().getChangeListener().onUnmanaged(policy);
-        }
-        @Override
-        public void onEnricherRemoved(Enricher enricher) {
-            getManagementContext().getRebindManager().getChangeListener().onChanged(entity);
-            getManagementContext().getRebindManager().getChangeListener().onUnmanaged(enricher);
-        }
-        @Override
-        public void onFeedRemoved(Feed feed) {
-            getManagementContext().getRebindManager().getChangeListener().onChanged(entity);
-            getManagementContext().getRebindManager().getChangeListener().onUnmanaged(feed);
-        }
-        @Override
-        public void onAttributeChanged(AttributeSensor<?> attribute) {
-            // TODO Could make this more efficient by inspecting the attribute to decide if needs persisted
-            // immediately, or not important, or transient (e.g. do we really need to persist 
-            // request-per-second count for rebind purposes?!)
-            getManagementContext().getRebindManager().getChangeListener().onChanged(entity);
-        }
-        @Override
-        public void onConfigChanged(ConfigKey<?> key) {
-            getManagementContext().getRebindManager().getChangeListener().onChanged(entity);
-        }
-        @Override
-        public void onEffectorStarting(Effector<?> effector, Object parameters) {
-            Entitlements.checkEntitled(getEntitlementManager(), Entitlements.INVOKE_EFFECTOR, EntityAndItem.of(entity, StringAndArgument.of(effector.getName(), parameters)));
-        }
-        @Override
-        public void onEffectorCompleted(Effector<?> effector) {
-            getManagementContext().getRebindManager().getChangeListener().onChanged(entity);
-        }
-    }
-
-    @Override
-    public String toString() {
-        return super.toString()+"["+(entity==null ? "null" : entity.getId())+"]";
-    }
-}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityManagerInternal.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityManagerInternal.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityManagerInternal.java
deleted file mode 100644
index 7bad213..0000000
--- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityManagerInternal.java
+++ /dev/null
@@ -1,32 +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 org.apache.brooklyn.core.mgmt.internal;
-
-import org.apache.brooklyn.api.entity.Application;
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.mgmt.EntityManager;
-
-public interface EntityManagerInternal extends EntityManager, BrooklynObjectManagerInternal<Entity> {
-
-    /** gets all entities currently known to the application, including entities that are not yet managed */
-    Iterable<Entity> getAllEntitiesInApplication(Application application);
-
-    public Iterable<String> getEntityIds();
-    
-}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/ExternalConfigSupplierRegistry.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/ExternalConfigSupplierRegistry.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/ExternalConfigSupplierRegistry.java
deleted file mode 100644
index 81f0ee3..0000000
--- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/ExternalConfigSupplierRegistry.java
+++ /dev/null
@@ -1,45 +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 org.apache.brooklyn.core.mgmt.internal;
-
-import org.apache.brooklyn.core.config.external.ExternalConfigSupplier;
-
-import com.google.common.annotations.Beta;
-
-
-/**
- * Permits a number of {@link ExternalConfigSupplier} instances to be registered, each with a unique name, for future
- * (deferred) lookup of configuration values.
- *
- * @since 0.8.0
- */
-@Beta
-public interface ExternalConfigSupplierRegistry {
-
-    void addProvider(String name, ExternalConfigSupplier provider);
-    void removeProvider(String name);
-
-    /**
-     * Searches the named {@link ExternalConfigSupplier} for the config value associated with the specified key.
-     * Quietly returns <code>null</code> if no config exists for the specified key.
-     * Throws {@link IllegalArgumentException} if no {@link ExternalConfigSupplier} exists for the passed name.
-     */
-    public String getConfig(String providerName, String key);
-
-}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/GroovyObservablesPropertyChangeToCollectionChangeAdapter.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/GroovyObservablesPropertyChangeToCollectionChangeAdapter.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/GroovyObservablesPropertyChangeToCollectionChangeAdapter.java
deleted file mode 100644
index cd13e1c..0000000
--- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/GroovyObservablesPropertyChangeToCollectionChangeAdapter.java
+++ /dev/null
@@ -1,65 +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 org.apache.brooklyn.core.mgmt.internal;
-
-import groovy.util.ObservableList;
-
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-
-public class GroovyObservablesPropertyChangeToCollectionChangeAdapter implements PropertyChangeListener {
-    @SuppressWarnings("rawtypes")
-    private final CollectionChangeListener delegate;
-
-    public GroovyObservablesPropertyChangeToCollectionChangeAdapter(@SuppressWarnings("rawtypes") CollectionChangeListener delegate) {
-        this.delegate = delegate;
-    }
-
-    @SuppressWarnings("unchecked")
-    public void propertyChange(PropertyChangeEvent evt) {
-        if (evt instanceof ObservableList.ElementAddedEvent) {
-            delegate.onItemAdded(evt.getNewValue());
-        } else if (evt instanceof ObservableList.ElementRemovedEvent) {
-            delegate.onItemRemoved(evt.getOldValue());
-        } else if (evt instanceof ObservableList.ElementUpdatedEvent) {
-            delegate.onItemRemoved(evt.getOldValue());
-            delegate.onItemAdded(evt.getNewValue());
-        } else if (evt instanceof ObservableList.ElementClearedEvent) {
-            for (Object value : ((ObservableList.ElementClearedEvent) evt).getValues()) {
-                delegate.onItemAdded(value);
-            }
-        } else if(evt instanceof ObservableList.MultiElementAddedEvent ) {
-            for(Object value: ((ObservableList.MultiElementAddedEvent)evt).getValues()){
-                delegate.onItemAdded(value);
-            }
-        }
-    }
-
-    public int hashCode() {
-        return delegate.hashCode();
-    }
-
-    public boolean equals(Object other) {
-        if (other instanceof GroovyObservablesPropertyChangeToCollectionChangeAdapter)
-            return delegate.equals(((GroovyObservablesPropertyChangeToCollectionChangeAdapter) other).delegate);
-        if (other instanceof CollectionChangeListener)
-            return delegate.equals(other);
-        return false;
-    }
-} 
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalAccessManager.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalAccessManager.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalAccessManager.java
deleted file mode 100644
index 1780972..0000000
--- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalAccessManager.java
+++ /dev/null
@@ -1,111 +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 org.apache.brooklyn.core.mgmt.internal;
-
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.api.mgmt.AccessController;
-
-import com.google.common.annotations.Beta;
-
-@Beta
-public class LocalAccessManager implements AccessManager {
-
-    private volatile boolean locationProvisioningAllowed = true;
-    private volatile boolean locationManagementAllowed = true;
-    private volatile boolean entityManagementAllowed = true;
-
-    private final AtomicReference<AccessControllerImpl> controller = new AtomicReference<AccessControllerImpl>();
-
-    public LocalAccessManager() {
-        updateAccessController();
-    }
-
-    @Override
-    public AccessController getAccessController() {
-        return controller.get();
-    }
-    
-    @Override
-    public boolean isLocationProvisioningAllowed() {
-        return locationProvisioningAllowed;
-    }
-
-    @Override
-    public boolean isLocationManagementAllowed() {
-        return locationManagementAllowed;
-    }
-
-    @Override
-    public boolean isEntityManagementAllowed() {
-        return entityManagementAllowed;
-    }
-
-    @Override
-    public void setLocationProvisioningAllowed(boolean allowed) {
-        locationProvisioningAllowed = allowed;
-        updateAccessController();
-    }
-
-    @Override
-    public void setLocationManagementAllowed(boolean allowed) {
-        locationManagementAllowed = allowed;
-        updateAccessController();
-    }
-
-    @Override
-    public void setEntityManagementAllowed(boolean allowed) {
-        entityManagementAllowed = allowed;
-        updateAccessController();
-    }
-
-    private void updateAccessController() {
-        controller.set(new AccessControllerImpl(locationProvisioningAllowed, locationManagementAllowed, entityManagementAllowed));
-    }
-    
-    private static class AccessControllerImpl implements AccessController {
-        private final boolean locationProvisioningAllowed;
-        private final boolean locationManagementAllowed;
-        private final boolean entityManagementAllowed;
-        
-        public AccessControllerImpl(boolean locationProvisioningAllowed, boolean locationManagementAllowed, 
-                boolean entityManagementAllowed) {
-            this.locationProvisioningAllowed = locationProvisioningAllowed;
-            this.locationManagementAllowed = locationManagementAllowed;
-            this.entityManagementAllowed = entityManagementAllowed;
-        }
-
-        @Override
-        public Response canProvisionLocation(Location provisioner) {
-            return (locationProvisioningAllowed ? Response.allowed() : Response.disallowed("location provisioning disabled"));
-        }
-        
-        @Override
-        public Response canManageLocation(Location loc) {
-            return (locationManagementAllowed ? Response.allowed() : Response.disallowed("location management disabled"));
-        }
-        
-        @Override
-        public Response canManageEntity(Entity entity) {
-            return (entityManagementAllowed ? Response.allowed() : Response.disallowed("entity management disabled"));
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalEntityManager.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalEntityManager.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalEntityManager.java
deleted file mode 100644
index aaa12d5..0000000
--- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalEntityManager.java
+++ /dev/null
@@ -1,820 +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 org.apache.brooklyn.core.mgmt.internal;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import groovy.util.ObservableList;
-
-import java.lang.reflect.Proxy;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.WeakHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-import javax.annotation.Nullable;
-
-import org.apache.brooklyn.api.entity.Application;
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.entity.EntityTypeRegistry;
-import org.apache.brooklyn.api.entity.Group;
-import org.apache.brooklyn.api.mgmt.AccessController;
-import org.apache.brooklyn.api.mgmt.Task;
-import org.apache.brooklyn.api.policy.Policy;
-import org.apache.brooklyn.api.policy.PolicySpec;
-import org.apache.brooklyn.api.sensor.Enricher;
-import org.apache.brooklyn.api.sensor.EnricherSpec;
-import org.apache.brooklyn.core.BrooklynLogging;
-import org.apache.brooklyn.core.entity.AbstractEntity;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.core.entity.EntityPredicates;
-import org.apache.brooklyn.core.entity.trait.Startable;
-import org.apache.brooklyn.core.internal.storage.BrooklynStorage;
-import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
-import org.apache.brooklyn.core.objs.BasicEntityTypeRegistry;
-import org.apache.brooklyn.core.objs.proxy.EntityProxy;
-import org.apache.brooklyn.core.objs.proxy.EntityProxyImpl;
-import org.apache.brooklyn.core.objs.proxy.InternalEntityFactory;
-import org.apache.brooklyn.core.objs.proxy.InternalPolicyFactory;
-import org.apache.brooklyn.util.collections.MutableSet;
-import org.apache.brooklyn.util.collections.SetFromLiveMap;
-import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.apache.brooklyn.util.time.CountdownTimer;
-import org.apache.brooklyn.util.time.Duration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Function;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-
-public class LocalEntityManager implements EntityManagerInternal {
-
-    private static final Logger log = LoggerFactory.getLogger(LocalEntityManager.class);
-
-    private final LocalManagementContext managementContext;
-    private final BasicEntityTypeRegistry entityTypeRegistry;
-    private final InternalEntityFactory entityFactory;
-    private final InternalPolicyFactory policyFactory;
-    
-    /** Entities that have been created, but have not yet begun to be managed */
-    protected final Map<String,Entity> preRegisteredEntitiesById = Collections.synchronizedMap(new WeakHashMap<String, Entity>());
-
-    /** Entities that are in the process of being managed, but where management is not yet complete */
-    protected final Map<String,Entity> preManagedEntitiesById = Collections.synchronizedMap(new WeakHashMap<String, Entity>());
-    
-    /** Proxies of the managed entities */
-    protected final ConcurrentMap<String,Entity> entityProxiesById = Maps.newConcurrentMap();
-    
-    /** Real managed entities */
-    protected final Map<String,Entity> entitiesById = Maps.newLinkedHashMap();
-    
-    /** Management mode for each entity */
-    protected final Map<String,ManagementTransitionMode> entityModesById = Collections.synchronizedMap(Maps.<String,ManagementTransitionMode>newLinkedHashMap());
-
-    /** Proxies of the managed entities */
-    protected final ObservableList entities = new ObservableList();
-    
-    /** Proxies of the managed entities that are applications */
-    protected final Set<Application> applications = Sets.newConcurrentHashSet();
-
-    private final BrooklynStorage storage;
-    private final Map<String,String> entityTypes;
-    private final Set<String> applicationIds;
-
-    public LocalEntityManager(LocalManagementContext managementContext) {
-        this.managementContext = checkNotNull(managementContext, "managementContext");
-        this.storage = managementContext.getStorage();
-        this.entityTypeRegistry = new BasicEntityTypeRegistry();
-        this.policyFactory = new InternalPolicyFactory(managementContext);
-        this.entityFactory = new InternalEntityFactory(managementContext, entityTypeRegistry, policyFactory);
-        
-        entityTypes = storage.getMap("entities");
-        applicationIds = SetFromLiveMap.create(storage.<String,Boolean>getMap("applications"));
-    }
-
-    public InternalEntityFactory getEntityFactory() {
-        if (!isRunning()) throw new IllegalStateException("Management context no longer running");
-        return entityFactory;
-    }
-
-    public InternalPolicyFactory getPolicyFactory() {
-        if (!isRunning()) throw new IllegalStateException("Management context no longer running");
-        return policyFactory;
-    }
-
-    @Override
-    public EntityTypeRegistry getEntityTypeRegistry() {
-        if (!isRunning()) throw new IllegalStateException("Management context no longer running");
-        return entityTypeRegistry;
-    }
-    
-    @SuppressWarnings("unchecked")
-    @Override
-    public <T extends Entity> T createEntity(EntitySpec<T> spec) {
-        try {
-            T entity = entityFactory.createEntity(spec);
-            Entity proxy = ((AbstractEntity)entity).getProxy();
-            checkNotNull(proxy, "proxy for entity %s, spec %s", entity, spec);
-            
-            manage(entity);
-            
-            return (T) proxy;
-        } catch (Throwable e) {
-            log.warn("Failed to create entity using spec "+spec+" (rethrowing)", e);
-            throw Exceptions.propagate(e);
-        }
-    }
-
-    @Override
-    public <T extends Entity> T createEntity(Map<?,?> config, Class<T> type) {
-        return createEntity(EntitySpec.create(config, type));
-    }
-
-    @Override
-    public <T extends Policy> T createPolicy(PolicySpec<T> spec) {
-        try {
-            return policyFactory.createPolicy(spec);
-        } catch (Throwable e) {
-            log.warn("Failed to create policy using spec "+spec+" (rethrowing)", e);
-            throw Exceptions.propagate(e);
-        }
-    }
-
-    @Override
-    public <T extends Enricher> T createEnricher(EnricherSpec<T> spec) {
-        try {
-            return policyFactory.createEnricher(spec);
-        } catch (Throwable e) {
-            log.warn("Failed to create enricher using spec "+spec+" (rethrowing)", e);
-            throw Exceptions.propagate(e);
-        }
-    }
-
-    @Override
-    public Collection<Entity> getEntities() {
-        return ImmutableList.copyOf(entityProxiesById.values());
-    }
-    
-    @Override
-    public Collection<String> getEntityIds() {
-        return ImmutableList.copyOf(entityProxiesById.keySet());
-    }
-    
-    @Override
-    public Collection<Entity> getEntitiesInApplication(Application application) {
-        Predicate<Entity> predicate = EntityPredicates.applicationIdEqualTo(application.getId());
-        return ImmutableList.copyOf(Iterables.filter(entityProxiesById.values(), predicate));
-    }
-
-    @Override
-    public Collection<Entity> findEntities(Predicate<? super Entity> filter) {
-        return ImmutableList.copyOf(Iterables.filter(entityProxiesById.values(), filter));
-    }
-    
-    @Override
-    public Collection<Entity> findEntitiesInApplication(Application application, Predicate<? super Entity> filter) {
-        Predicate<Entity> predicate = Predicates.and(EntityPredicates.applicationIdEqualTo(application.getId()), filter);
-        return ImmutableList.copyOf(Iterables.filter(entityProxiesById.values(), predicate));
-    }
-
-    @Override
-    public Iterable<Entity> getAllEntitiesInApplication(Application application) {
-        Predicate<Entity> predicate = EntityPredicates.applicationIdEqualTo(application.getId());
-        Iterable<Entity> allentities = Iterables.concat(preRegisteredEntitiesById.values(), preManagedEntitiesById.values(), entityProxiesById.values());
-        Iterable<Entity> result = Iterables.filter(allentities, predicate);
-        return ImmutableSet.copyOf(Iterables.transform(result, new Function<Entity, Entity>() {
-            @Override public Entity apply(Entity input) {
-                return Entities.proxy(input);
-            }}));
-    }
-
-    @Override
-    public Entity getEntity(String id) {
-        return entityProxiesById.get(id);
-    }
-    
-    Collection<Application> getApplications() {
-        return ImmutableList.copyOf(applications);
-    }
-    
-    @Override
-    public boolean isManaged(Entity e) {
-        return (isRunning() && getEntity(e.getId()) != null);
-    }
-    
-    boolean isPreRegistered(Entity e) {
-        return preRegisteredEntitiesById.containsKey(e.getId());
-    }
-    
-    void prePreManage(Entity entity) {
-        if (isPreRegistered(entity)) {
-            log.warn(""+this+" redundant call to pre-pre-manage entity "+entity+"; skipping", 
-                    new Exception("source of duplicate pre-pre-manage of "+entity));
-            return;
-        }
-        preRegisteredEntitiesById.put(entity.getId(), entity);
-    }
-    
-    @Override
-    public ManagementTransitionMode getLastManagementTransitionMode(String itemId) {
-        return entityModesById.get(itemId);
-    }
-    
-    @Override
-    public void setManagementTransitionMode(Entity item, ManagementTransitionMode mode) {
-        entityModesById.put(item.getId(), mode);
-    }
-    
-    // TODO synchronization issues here. We guard with isManaged(), but if another thread executing 
-    // concurrently then the managed'ness could be set after our check but before we do 
-    // onManagementStarting etc. However, we can't just synchronize because we're calling alien code 
-    // (the user might override entity.onManagementStarting etc).
-    // 
-    // TODO We need to do some check about isPreManaged - i.e. is there another thread (or is this a
-    // re-entrant call) where the entity is not yet full managed (i.e. isManaged==false) but we're in
-    // the middle of managing it.
-    // 
-    // TODO Also see LocalLocationManager.manage(Entity), if fixing things here
-    @Override
-    public void manage(Entity e) {
-        if (isManaged(e)) {
-            log.warn(""+this+" redundant call to start management of entity (and descendants of) "+e+"; skipping", 
-                    new Exception("source of duplicate management of "+e));
-            return;
-        }
-        manageRecursive(e, ManagementTransitionMode.guessing(BrooklynObjectManagementMode.NONEXISTENT, BrooklynObjectManagementMode.MANAGED_PRIMARY));
-    }
-
-    @Override
-    public void manageRebindedRoot(Entity item) {
-        ManagementTransitionMode mode = getLastManagementTransitionMode(item.getId());
-        Preconditions.checkNotNull(mode, "Mode not set for rebinding %s", item);
-        manageRecursive(item, mode);
-    }
-    
-    protected void checkManagementAllowed(Entity item) {
-        AccessController.Response access = managementContext.getAccessController().canManageEntity(item);
-        if (!access.isAllowed()) {
-            throw new IllegalStateException("Access controller forbids management of "+item+": "+access.getMsg());
-        }
-    }
-    
-    /* TODO we sloppily use "recursive" to ensure ordering of parent-first in many places
-     * (which may not be necessary but seems like a good idea),
-     * and also to collect many entities when doing a big rebind,
-     * ensuring all have #manageNonRecursive called before calling #onManagementStarted.
-     * 
-     * it would be better to have a manageAll(Map<Entity,ManagementTransitionMode> items)
-     * method which did that in two phases, allowing us to selectively rebind, 
-     * esp when we come to want supporting different modes and different brooklyn nodes.
-     * 
-     * the impl of manageAll could sort them with parents before children,
-     * (and manageRecursive could simply populate a map and delegate to manageAll).
-     * 
-     * manageRebindRoot would then go, and the (few) callers would construct the map.
-     * 
-     * similarly we might want an unmanageAll(), 
-     * although possibly all unmanagement should be recursive, if we assume an entity's ancestors are always at least proxied
-     * (and the non-recursive RO path here could maybe be dropped)
-     */
-    
-    /** Applies management lifecycle callbacks (onManagementStarting, for all beforehand, then onManagementStopped, for all after) */
-    protected void manageRecursive(Entity e, final ManagementTransitionMode initialMode) {
-        checkManagementAllowed(e);
-
-        final List<EntityInternal> allEntities = Lists.newArrayList();
-        Predicate<EntityInternal> manageEntity = new Predicate<EntityInternal>() { public boolean apply(EntityInternal it) {
-            ManagementTransitionMode mode = getLastManagementTransitionMode(it.getId());
-            if (mode==null) {
-                setManagementTransitionMode(it, mode = initialMode);
-            }
-            
-            Boolean isReadOnlyFromEntity = it.getManagementSupport().isReadOnlyRaw();
-            if (isReadOnlyFromEntity==null) {
-                if (mode.isReadOnly()) {
-                    // should have been marked by rebinder
-                    log.warn("Read-only entity "+it+" not marked as such on call to manage; marking and continuing");
-                }
-                it.getManagementSupport().setReadOnly(mode.isReadOnly());
-            } else {
-                if (!isReadOnlyFromEntity.equals(mode.isReadOnly())) {
-                    log.warn("Read-only status at entity "+it+" ("+isReadOnlyFromEntity+") not consistent with management mode "+mode);
-                }
-            }
-            
-            if (it.getManagementSupport().isDeployed()) {
-                if (mode.wasNotLoaded()) {
-                    // silently bail out
-                    return false;
-                } else {
-                    if (mode.wasPrimary() && mode.isPrimary()) {
-                        // active partial rebind; continue
-                    } else if (mode.wasReadOnly() && mode.isReadOnly()) {
-                        // reload in RO mode
-                    } else {
-                        // on initial non-RO rebind, should not have any deployed instances
-                        log.warn("Already deployed "+it+" when managing "+mode+"/"+initialMode+"; ignoring this and all descendants");
-                        return false;
-                    }
-                }
-            }
-            
-            // check RO status is consistent
-            boolean isNowReadOnly = Boolean.TRUE.equals( ((EntityInternal)it).getManagementSupport().isReadOnly() );
-            if (mode.isReadOnly()!=isNowReadOnly) {
-                throw new IllegalStateException("Read-only status mismatch for "+it+": "+mode+" / RO="+isNowReadOnly);
-            }
-
-            allEntities.add(it);
-            preManageNonRecursive(it, mode);
-            it.getManagementSupport().onManagementStarting( new ManagementTransitionInfo(managementContext, mode) ); 
-            return manageNonRecursive(it, mode);
-        } };
-        boolean isRecursive = true;
-        if (initialMode.wasPrimary() && initialMode.isPrimary()) {
-            // already managed, so this shouldn't be recursive 
-            // (in ActivePartialRebind we cheat, calling in to this method then skipping recursion).
-            // it also falls through to here when doing a redundant promotion,
-            // in that case we *should* be recursive; determine by checking whether a child exists and is preregistered.
-            // the TODO above removing manageRebindRoot in favour of explicit mgmt list would clean this up a lot!
-            Entity aChild = Iterables.getFirst(e.getChildren(), null);
-            if (aChild!=null && isPreRegistered(aChild)) {
-                log.debug("Managing "+e+" in mode "+initialMode+", doing this recursively because a child is preregistered");
-            } else {
-                log.debug("Managing "+e+" but skipping recursion, as mode is "+initialMode);
-                isRecursive = false;
-            }
-        }
-        if (!isRecursive) {
-            manageEntity.apply( (EntityInternal)e );
-        } else {
-            recursively(e, manageEntity);
-        }
-        
-        for (EntityInternal it : allEntities) {
-            if (!it.getManagementSupport().isFullyManaged()) {
-                ManagementTransitionMode mode = getLastManagementTransitionMode(it.getId());
-                ManagementTransitionInfo info = new ManagementTransitionInfo(managementContext, mode);
-                
-                it.getManagementSupport().onManagementStarted(info);
-                managementContext.getRebindManager().getChangeListener().onManaged(it);
-            }
-        }
-    }
-
-    @Override
-    public void unmanage(final Entity e) {
-        // TODO don't want to guess; should we inspect state of e ?  or maybe it doesn't matter ?
-        unmanage(e, ManagementTransitionMode.guessing(BrooklynObjectManagementMode.MANAGED_PRIMARY, BrooklynObjectManagementMode.NONEXISTENT));
-    }
-    
-    public void unmanage(final Entity e, final ManagementTransitionMode mode) {
-        unmanage(e, mode, false);
-    }
-    
-    private void unmanage(final Entity e, ManagementTransitionMode mode, boolean hasBeenReplaced) {
-        if (shouldSkipUnmanagement(e)) return;
-        final ManagementTransitionInfo info = new ManagementTransitionInfo(managementContext, mode);
-        
-        if (hasBeenReplaced) {
-            // we are unmanaging an old instance after having replaced it
-            // don't unmanage or even clear its fields, because there might be references to it
-            
-            if (mode.wasReadOnly()) {
-                // if coming *from* read only; nothing needed
-            } else {
-                if (!mode.wasPrimary()) {
-                    log.warn("Unexpected mode "+mode+" for unmanage-replace "+e+" (applying anyway)");
-                }
-                // migrating away or in-place active partial rebind:
-                ((EntityInternal)e).getManagementSupport().onManagementStopping(info);
-                stopTasks(e);
-                ((EntityInternal)e).getManagementSupport().onManagementStopped(info);
-            }
-            // do not remove from maps below, bail out now
-            return;
-            
-        } else if (mode.wasReadOnly() && mode.isNoLongerLoaded()) {
-            // we are unmanaging an instance (secondary); either stopping here or primary destroyed elsewhere
-            ((EntityInternal)e).getManagementSupport().onManagementStopping(info);
-            unmanageNonRecursive(e);
-            stopTasks(e);
-            ((EntityInternal)e).getManagementSupport().onManagementStopped(info);
-            managementContext.getRebindManager().getChangeListener().onUnmanaged(e);
-            if (managementContext.getGarbageCollector() != null) managementContext.getGarbageCollector().onUnmanaged(e);
-            
-        } else if (mode.wasPrimary() && mode.isNoLongerLoaded()) {
-            // unmanaging a primary; currently this is done recursively
-            
-            /* TODO tidy up when it is recursive and when it isn't; if something is being unloaded or destroyed,
-             * that probably *is* recursive, but the old mode might be different if in some cases things are read-only.
-             * or maybe nothing needs to be recursive, we just make sure the callers (e.g. HighAvailabilityModeImpl.clearManagedItems)
-             * call in a good order
-             * 
-             * see notes above about recursive/manage/All/unmanageAll
-             */
-            
-            // Need to store all child entities as onManagementStopping removes a child from the parent entity
-            final List<EntityInternal> allEntities =  Lists.newArrayList();        
-            recursively(e, new Predicate<EntityInternal>() { public boolean apply(EntityInternal it) {
-                if (shouldSkipUnmanagement(it)) return false;
-                allEntities.add(it);
-                it.getManagementSupport().onManagementStopping(info);
-                return true;
-            } });
-
-            for (EntityInternal it : allEntities) {
-                if (shouldSkipUnmanagement(it)) continue;
-                unmanageNonRecursive(it);
-                stopTasks(it);
-            }
-            for (EntityInternal it : allEntities) {
-                it.getManagementSupport().onManagementStopped(info);
-                managementContext.getRebindManager().getChangeListener().onUnmanaged(it);
-                if (managementContext.getGarbageCollector() != null) managementContext.getGarbageCollector().onUnmanaged(e);
-            }
-            
-        } else {
-            log.warn("Invalid mode for unmanage: "+mode+" on "+e+" (ignoring)");
-        }
-        
-        preRegisteredEntitiesById.remove(e.getId());
-        preManagedEntitiesById.remove(e.getId());
-        entityProxiesById.remove(e.getId());
-        entitiesById.remove(e.getId());
-        entityModesById.remove(e.getId());
-    }
-    
-    private void stopTasks(Entity entity) {
-        stopTasks(entity, null);
-    }
-    
-    /** stops all tasks (apart from any current one or its descendants) on this entity,
-     * optionally -- if a timeout is given -- waiting for completion and warning on incomplete tasks */
-    @Beta
-    public void stopTasks(Entity entity, @Nullable Duration timeout) {
-        CountdownTimer timeleft = timeout==null ? null : timeout.countdownTimer();
-        // try forcibly interrupting tasks on managed entities
-        Collection<Exception> exceptions = MutableSet.of();
-        try {
-            Set<Task<?>> tasksCancelled = MutableSet.of();
-            for (Task<?> t: managementContext.getExecutionContext(entity).getTasks()) {
-                if (entity.equals(BrooklynTaskTags.getContextEntity(Tasks.current())) && hasTaskAsAncestor(t, Tasks.current())) {
-                    // don't cancel if we are running inside a task on the target entity and
-                    // the task being considered is one we have submitted -- e.g. on "stop" don't cancel ourselves!
-                    // but if our current task is from another entity we probably do want to cancel them (we are probably invoking unmanage)
-                    continue;
-                }
-                
-                if (!t.isDone()) {
-                    try {
-                        log.debug("Cancelling "+t+" on "+entity);
-                        tasksCancelled.add(t);
-                        t.cancel(true);
-                    } catch (Exception e) {
-                        Exceptions.propagateIfFatal(e);
-                        log.debug("Error cancelling "+t+" on "+entity+" (will warn when all tasks are cancelled): "+e, e);
-                        exceptions.add(e);
-                    }
-                }
-            }
-            
-            if (timeleft!=null) {
-                Set<Task<?>> tasksIncomplete = MutableSet.of();
-                // go through all tasks, not just cancelled ones, in case there are previously cancelled ones which are not complete
-                for (Task<?> t: managementContext.getExecutionContext(entity).getTasks()) {
-                    if (hasTaskAsAncestor(t, Tasks.current()))
-                        continue;
-                    if (!Tasks.blockUntilInternalTasksEnded(t, timeleft.getDurationRemaining())) {
-                        tasksIncomplete.add(t);
-                    }
-                }
-                if (!tasksIncomplete.isEmpty()) {
-                    log.warn("Incomplete tasks when stopping "+entity+": "+tasksIncomplete);
-                }
-                if (log.isTraceEnabled())
-                    log.trace("Cancelled "+tasksCancelled+" tasks for "+entity+", with "+
-                            timeleft.getDurationRemaining()+" remaining (of "+timeout+"): "+tasksCancelled);
-            } else {
-                if (log.isTraceEnabled())
-                    log.trace("Cancelled "+tasksCancelled+" tasks for "+entity+": "+tasksCancelled);
-            }
-        } catch (Exception e) {
-            Exceptions.propagateIfFatal(e);
-            log.warn("Error inspecting tasks to cancel on unmanagement: "+e, e);
-        }
-        if (!exceptions.isEmpty())
-            log.warn("Error when cancelling tasks for "+entity+" on unmanagement: "+Exceptions.create(exceptions));
-    }
-
-    private boolean hasTaskAsAncestor(Task<?> t, Task<?> potentialAncestor) {
-        if (t==null || potentialAncestor==null) return false;
-        if (t.equals(potentialAncestor)) return true;
-        return hasTaskAsAncestor(t.getSubmittedByTask(), potentialAncestor);
-    }
-
-    /**
-     * activates management when effector invoked, warning unless context is acceptable
-     * (currently only acceptable context is "start")
-     */
-    void manageIfNecessary(Entity entity, Object context) {
-        if (!isRunning()) {
-            return; // TODO Still a race for terminate being called, and then isManaged below returning false
-        } else if (((EntityInternal)entity).getManagementSupport().wasDeployed()) {
-            return;
-        } else if (isManaged(entity)) {
-            return;
-        } else if (isPreManaged(entity)) {
-            return;
-        } else if (Boolean.TRUE.equals(((EntityInternal)entity).getManagementSupport().isReadOnly())) {
-            return;
-        } else {
-            Entity rootUnmanaged = entity;
-            while (true) {
-                Entity candidateUnmanagedParent = rootUnmanaged.getParent();
-                if (candidateUnmanagedParent == null || isManaged(candidateUnmanagedParent) || isPreManaged(candidateUnmanagedParent))
-                    break;
-                rootUnmanaged = candidateUnmanagedParent;
-            }
-            if (context == Startable.START.getName())
-                log.info("Activating local management for {} on start", rootUnmanaged);
-            else
-                log.warn("Activating local management for {} due to effector invocation on {}: {}", new Object[]{rootUnmanaged, entity, context});
-            manage(rootUnmanaged);
-        }
-    }
-
-    private void recursively(Entity e, Predicate<EntityInternal> action) {
-        Entity otherPreregistered = preRegisteredEntitiesById.get(e.getId());
-        if (otherPreregistered!=null) {
-            // if something has been pre-registered, prefer it
-            // (e.g. if we recursing through children, we might have a proxy from previous iteration;
-            // the most recent will have been pre-registered)
-            e = otherPreregistered;
-        }
-            
-        boolean success = action.apply( (EntityInternal)e );
-        if (!success) {
-            return; // Don't manage children if action false/unnecessary for parent
-        }
-        for (Entity child : e.getChildren()) {
-            recursively(child, action);
-        }
-    }
-
-    /**
-     * Whether the entity is in the process of being managed.
-     */
-    private synchronized boolean isPreManaged(Entity e) {
-        return preManagedEntitiesById.containsKey(e.getId());
-    }
-
-    /**
-     * Should ensure that the entity is now known about, but should not be accessible from other entities yet.
-     * 
-     * Records that the given entity is about to be managed (used for answering {@link #isPreManaged(Entity)}.
-     * Note that refs to the given entity are stored in a a weak hashmap so if the subsequent management
-     * attempt fails then this reference to the entity will eventually be discarded (if no-one else holds 
-     * a reference).
-     */
-    private synchronized boolean preManageNonRecursive(Entity e, ManagementTransitionMode mode) {
-        Entity realE = toRealEntity(e);
-        
-        Object old = preManagedEntitiesById.put(e.getId(), realE);
-        preRegisteredEntitiesById.remove(e.getId());
-        
-        if (old!=null && mode.wasNotLoaded()) {
-            if (old.equals(e)) {
-                log.warn("{} redundant call to pre-start management of entity {}, mode {}; ignoring", new Object[] { this, e, mode });
-            } else {
-                throw new IllegalStateException("call to pre-manage entity "+e+" ("+mode+") but different entity "+old+" already known under that id at "+this);
-            }
-            return false;
-        } else {
-            if (log.isTraceEnabled()) log.trace("{} pre-start management of entity {}, mode {}", 
-                new Object[] { this, e, mode });
-            return true;
-        }
-    }
-
-    /**
-     * Should ensure that the entity is now managed somewhere, and known about in all the lists.
-     * Returns true if the entity has now become managed; false if it was already managed (anything else throws exception)
-     */
-    private synchronized boolean manageNonRecursive(Entity e, ManagementTransitionMode mode) {
-        Entity old = entitiesById.get(e.getId());
-        
-        if (old!=null && mode.wasNotLoaded()) {
-            if (old.equals(e)) {
-                log.warn("{} redundant call to start management of entity {}; ignoring", this, e);
-            } else {
-                throw new IllegalStateException("call to manage entity "+e+" ("+mode+") but different entity "+old+" already known under that id at "+this);
-            }
-            return false;
-        }
-
-        BrooklynLogging.log(log, BrooklynLogging.levelDebugOrTraceIfReadOnly(e),
-            "{} starting management of entity {}", this, e);
-        Entity realE = toRealEntity(e);
-        
-        Entity oldProxy = entityProxiesById.get(e.getId());
-        Entity proxyE;
-        if (oldProxy!=null) {
-            if (mode.wasNotLoaded()) {
-                throw new IllegalStateException("call to manage entity "+e+" from unloaded state ("+mode+") but already had proxy "+oldProxy+" already known under that id at "+this);
-            }
-            // make the old proxy point at this new delegate
-            // (some other tricks done in the call below)
-            ((EntityProxyImpl)(Proxy.getInvocationHandler(oldProxy))).resetDelegate(oldProxy, oldProxy, realE);
-            proxyE = oldProxy;
-        } else {
-            proxyE = toProxyEntityIfAvailable(e);
-        }
-        entityProxiesById.put(e.getId(), proxyE);
-        entityTypes.put(e.getId(), realE.getClass().getName());
-        entitiesById.put(e.getId(), realE);
-
-        preManagedEntitiesById.remove(e.getId());
-        if ((e instanceof Application) && (e.getParent()==null)) {
-            applications.add((Application)proxyE);
-            applicationIds.add(e.getId());
-        }
-        if (!entities.contains(proxyE)) 
-            entities.add(proxyE);
-        
-        if (old!=null && old!=e) {
-            // passing the transition info will ensure the right shutdown steps invoked for old instance
-            unmanage(old, mode, true);
-        }
-        
-        return true;
-    }
-
-    /**
-     * Should ensure that the entity is no longer managed anywhere, remove from all lists.
-     * Returns true if the entity has been removed from management; if it was not previously managed (anything else throws exception) 
-     */
-    private boolean unmanageNonRecursive(Entity e) {
-        /*
-         * When method is synchronized, hit deadlock: 
-         * 1. thread called unmanage() on a member of a group, so we got the lock and called group.removeMember;
-         *    this ties to synchronize on AbstractGroupImpl.members 
-         * 2. another thread was doing AbstractGroupImpl.addMember, which is synchronized on AbstractGroupImpl.members;
-         *    it tries to call Entities.manage(child) which calls LocalEntityManager.getEntity(), which is
-         *    synchronized on this.
-         * 
-         * We MUST NOT call alien code from within the management framework while holding locks. 
-         * The AbstractGroup.removeMember is effectively alien because a user could override it, and because
-         * it is entity specific.
-         * 
-         * TODO Does getting then removing from groups risk this entity being added to other groups while 
-         * this is happening? Should abstractEntity.onManagementStopped or some such remove the entity
-         * from its groups?
-         */
-        
-        if (!getLastManagementTransitionMode(e.getId()).isReadOnly()) {
-            e.clearParent();
-            for (Group group : e.groups()) {
-                if (!Entities.isNoLongerManaged(group)) group.removeMember(e);
-            }
-            if (e instanceof Group) {
-                Collection<Entity> members = ((Group)e).getMembers();
-                for (Entity member : members) {
-                    if (!Entities.isNoLongerManaged(member)) member.removeGroup((Group)e);
-                }
-            }
-        } else {
-            log.debug("No relations being updated on unmanage of read only {}", e);
-        }
-
-        synchronized (this) {
-            Entity proxyE = toProxyEntityIfAvailable(e);
-            if (e instanceof Application) {
-                applications.remove(proxyE);
-                applicationIds.remove(e.getId());
-            }
-
-            entities.remove(proxyE);
-            entityProxiesById.remove(e.getId());
-            entityModesById.remove(e.getId());
-            Object old = entitiesById.remove(e.getId());
-
-            entityTypes.remove(e.getId());
-            if (old==null) {
-                log.warn("{} call to stop management of unknown entity (already unmanaged?) {}; ignoring", this, e);
-                return false;
-            } else if (!old.equals(e)) {
-                // shouldn't happen...
-                log.error("{} call to stop management of entity {} removed different entity {}", new Object[] { this, e, old });
-                return true;
-            } else {
-                if (log.isDebugEnabled()) log.debug("{} stopped management of entity {}", this, e);
-                return true;
-            }
-        }
-    }
-
-    void addEntitySetListener(CollectionChangeListener<Entity> listener) {
-        //must notify listener in a different thread to avoid deadlock (issue #378)
-        AsyncCollectionChangeAdapter<Entity> wrappedListener = new AsyncCollectionChangeAdapter<Entity>(managementContext.getExecutionManager(), listener);
-        entities.addPropertyChangeListener(new GroovyObservablesPropertyChangeToCollectionChangeAdapter(wrappedListener));
-    }
-
-    void removeEntitySetListener(CollectionChangeListener<Entity> listener) {
-        AsyncCollectionChangeAdapter<Entity> wrappedListener = new AsyncCollectionChangeAdapter<Entity>(managementContext.getExecutionManager(), listener);
-        entities.removePropertyChangeListener(new GroovyObservablesPropertyChangeToCollectionChangeAdapter(wrappedListener));
-    }
-    
-    private boolean shouldSkipUnmanagement(Entity e) {
-        if (e==null) {
-            log.warn(""+this+" call to unmanage null entity; skipping",  
-                new IllegalStateException("source of null unmanagement call to "+this));
-            return true;
-        }
-        if (!isManaged(e)) {
-            log.warn("{} call to stop management of unknown entity (already unmanaged?) {}; skipping, and all descendants", this, e);
-            return true;
-        }
-        return false;
-    }
-    
-    private Entity toProxyEntityIfAvailable(Entity e) {
-        checkNotNull(e, "entity");
-        
-        if (e instanceof EntityProxy) {
-            return e;
-        } else if (e instanceof AbstractEntity) {
-            Entity result = ((AbstractEntity)e).getProxy();
-            return (result == null) ? e : result;
-        } else {
-            // If we don't already know about the proxy, then use the real thing; presumably it's 
-            // the legacy way of creating the entity so didn't get a preManage() call
-
-            return e;
-        }
-    }
-    
-    private Entity toRealEntity(Entity e) {
-        checkNotNull(e, "entity");
-        
-        if (e instanceof AbstractEntity) {
-            return e;
-        } else {
-            Entity result = toRealEntityOrNull(e.getId());
-            if (result == null) {
-                throw new IllegalStateException("No concrete entity known for entity "+e+" ("+e.getId()+", "+e.getEntityType().getName()+")");
-            }
-            return result;
-        }
-    }
-
-    public boolean isKnownEntityId(String id) {
-        return entitiesById.containsKey(id) || preManagedEntitiesById.containsKey(id) || preRegisteredEntitiesById.containsKey(id);
-    }
-    
-    private Entity toRealEntityOrNull(String id) {
-        Entity result;
-        // prefer the preRegistered and preManaged entities, during hot proxying, they should be newer
-        result = preRegisteredEntitiesById.get(id);
-        if (result==null)
-            result = preManagedEntitiesById.get(id);
-        if (result==null)
-            entitiesById.get(id);
-        return result;
-    }
-    
-    private boolean isRunning() {
-        return managementContext.isRunning();
-    }
-
-}