You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by ha...@apache.org on 2015/08/15 15:33:12 UTC

[10/33] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/management

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6602f694/core/src/main/java/org/apache/brooklyn/core/management/internal/NonDeploymentManagementContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/management/internal/NonDeploymentManagementContext.java b/core/src/main/java/org/apache/brooklyn/core/management/internal/NonDeploymentManagementContext.java
new file mode 100644
index 0000000..9d98792
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/management/internal/NonDeploymentManagementContext.java
@@ -0,0 +1,639 @@
+/*
+ * 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.management.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.net.URI;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.brooklyn.api.basic.BrooklynObject;
+import org.apache.brooklyn.api.catalog.BrooklynCatalog;
+import org.apache.brooklyn.api.entity.Application;
+import org.apache.brooklyn.api.entity.Effector;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.drivers.EntityDriverManager;
+import org.apache.brooklyn.api.entity.drivers.downloads.DownloadResolverManager;
+import org.apache.brooklyn.api.entity.rebind.ChangeListener;
+import org.apache.brooklyn.api.entity.rebind.PersistenceExceptionHandler;
+import org.apache.brooklyn.api.entity.rebind.RebindExceptionHandler;
+import org.apache.brooklyn.api.entity.rebind.RebindManager;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.location.LocationRegistry;
+import org.apache.brooklyn.api.management.AccessController;
+import org.apache.brooklyn.api.management.EntityManager;
+import org.apache.brooklyn.api.management.ExecutionContext;
+import org.apache.brooklyn.api.management.ExecutionManager;
+import org.apache.brooklyn.api.management.LocationManager;
+import org.apache.brooklyn.api.management.SubscriptionContext;
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.api.management.entitlement.EntitlementManager;
+import org.apache.brooklyn.api.management.ha.HighAvailabilityManager;
+import org.apache.brooklyn.api.management.ha.HighAvailabilityMode;
+import org.apache.brooklyn.api.management.ha.ManagementNodeState;
+import org.apache.brooklyn.api.management.ha.ManagementPlaneSyncRecord;
+import org.apache.brooklyn.api.management.ha.ManagementPlaneSyncRecordPersister;
+import org.apache.brooklyn.api.mementos.BrooklynMementoPersister;
+import org.apache.brooklyn.api.mementos.BrooklynMementoRawData;
+import org.apache.brooklyn.core.management.entitlement.Entitlements;
+import org.apache.brooklyn.core.management.ha.OsgiManager;
+
+import brooklyn.catalog.internal.CatalogInitialization;
+import brooklyn.config.BrooklynProperties;
+import brooklyn.config.StringConfigMap;
+import brooklyn.entity.basic.AbstractEntity;
+import brooklyn.entity.proxying.InternalEntityFactory;
+import brooklyn.entity.proxying.InternalLocationFactory;
+import brooklyn.entity.proxying.InternalPolicyFactory;
+import brooklyn.internal.storage.BrooklynStorage;
+import brooklyn.util.guava.Maybe;
+import brooklyn.util.time.Duration;
+
+import com.google.common.base.Objects;
+
+public class NonDeploymentManagementContext implements ManagementContextInternal {
+
+    private static final Logger log = LoggerFactory.getLogger(NonDeploymentManagementContext.class);
+    
+    public enum NonDeploymentManagementContextMode {
+        PRE_MANAGEMENT,
+        MANAGEMENT_REBINDING,
+        MANAGEMENT_STARTING,
+        MANAGEMENT_STARTED,
+        MANAGEMENT_STOPPING,
+        MANAGEMENT_STOPPED;
+        
+        public boolean isPreManaged() {
+            return this == PRE_MANAGEMENT || this == MANAGEMENT_REBINDING;
+        }
+    }
+    
+    private final AbstractEntity entity;
+    private NonDeploymentManagementContextMode mode;
+    private ManagementContextInternal initialManagementContext;
+    
+    private final QueueingSubscriptionManager qsm;
+    private final BasicSubscriptionContext subscriptionContext;
+    private NonDeploymentEntityManager entityManager;
+    private NonDeploymentLocationManager locationManager;
+    private NonDeploymentAccessManager accessManager;
+    private NonDeploymentUsageManager usageManager;
+    private EntitlementManager entitlementManager;;
+
+    public NonDeploymentManagementContext(AbstractEntity entity, NonDeploymentManagementContextMode mode) {
+        this.entity = checkNotNull(entity, "entity");
+        this.mode = checkNotNull(mode, "mode");
+        qsm = new QueueingSubscriptionManager();
+        subscriptionContext = new BasicSubscriptionContext(qsm, entity);
+        entityManager = new NonDeploymentEntityManager(null);
+        locationManager = new NonDeploymentLocationManager(null);
+        accessManager = new NonDeploymentAccessManager(null);
+        usageManager = new NonDeploymentUsageManager(null);
+        
+        // TODO might need to be some kind of "system" which can see that the system is running at this point
+        // though quite possibly we are entirely behind the auth-wall at this point
+        entitlementManager = Entitlements.minimal();
+    }
+
+    @Override
+    public String getManagementPlaneId() {
+        return (initialManagementContext == null) ? null : initialManagementContext.getManagementPlaneId();
+    }
+    
+    @Override
+    public String getManagementNodeId() {
+        return (initialManagementContext == null) ? null : initialManagementContext.getManagementNodeId();
+    }
+
+    @Override
+    public Maybe<URI> getManagementNodeUri() {
+        return (initialManagementContext == null) ? Maybe.<URI>absent() : initialManagementContext.getManagementNodeUri();
+    }
+
+    public void setManagementContext(ManagementContextInternal val) {
+        this.initialManagementContext = checkNotNull(val, "initialManagementContext");
+        this.entityManager = new NonDeploymentEntityManager(val);
+        this.locationManager = new NonDeploymentLocationManager(val);
+        this.accessManager = new NonDeploymentAccessManager(val);
+        this.usageManager = new NonDeploymentUsageManager(val);
+    }
+
+    @Override
+    public String toString() {
+        return Objects.toStringHelper(this).add("entity", entity.getId()).add("mode", mode).toString();
+    }
+    
+    public void setMode(NonDeploymentManagementContextMode mode) {
+        this.mode = checkNotNull(mode, "mode");
+    }
+    public NonDeploymentManagementContextMode getMode() {
+        return mode;
+    }
+    
+    @Override
+    public Collection<Application> getApplications() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public boolean isRunning() {
+        // Assume that the real management context has not been terminated, so always true
+        return true;
+    }
+    
+    @Override
+    public boolean isStartupComplete() {
+        // This mgmt context is only used by items who are not yet fully started.
+        // It's slightly misleading as this does not refer to the main mgmt context.
+        // OTOH it probably won't be used.  TBC.  -Alex, Apr 2015
+        return false;
+    }
+
+    @Override
+    public InternalEntityFactory getEntityFactory() {
+        checkInitialManagementContextReal();
+        return initialManagementContext.getEntityFactory();
+    }
+
+    @Override
+    public InternalLocationFactory getLocationFactory() {
+        checkInitialManagementContextReal();
+        return initialManagementContext.getLocationFactory();
+    }
+
+    @Override
+    public InternalPolicyFactory getPolicyFactory() {
+        checkInitialManagementContextReal();
+        return initialManagementContext.getPolicyFactory();
+    }
+
+    @Override
+    public EntityManager getEntityManager() {
+        return entityManager;
+    }
+    
+    @Override
+    public LocationManager getLocationManager() {
+        return locationManager;
+    }
+
+    @Override
+    public AccessManager getAccessManager() {
+        return accessManager;
+    }
+
+    @Override
+    public UsageManager getUsageManager() {
+        return usageManager;
+    }
+    
+    @Override
+    public Maybe<OsgiManager> getOsgiManager() {
+        return Maybe.absent();
+    }
+
+    @Override
+    public AccessController getAccessController() {
+        return getAccessManager().getAccessController();
+    }
+
+    @Override
+    public ExecutionManager getExecutionManager() {
+        checkInitialManagementContextReal();
+        return initialManagementContext.getExecutionManager();
+    }
+
+    @Override
+    public QueueingSubscriptionManager getSubscriptionManager() {
+        return qsm;
+    }
+
+    @Override
+    public synchronized SubscriptionContext getSubscriptionContext(Entity entity) {
+        if (!this.entity.equals(entity)) throw new IllegalStateException("Non-deployment context "+this+" can only use a single Entity: has "+this.entity+", but passed "+entity);
+        if (mode==NonDeploymentManagementContextMode.MANAGEMENT_STOPPED)
+            throw new IllegalStateException("Entity "+entity+" is no longer managed; subscription context not available");
+        return subscriptionContext;
+    }
+
+    @Override
+    public ExecutionContext getExecutionContext(Entity entity) {
+        if (!this.entity.equals(entity)) throw new IllegalStateException("Non-deployment context "+this+" can only use a single Entity: has "+this.entity+", but passed "+entity);
+        if (mode==NonDeploymentManagementContextMode.MANAGEMENT_STOPPED)
+            throw new IllegalStateException("Entity "+entity+" is no longer managed; execution context not available");
+        checkInitialManagementContextReal();
+        return initialManagementContext.getExecutionContext(entity);
+    }
+
+    @Override
+    public ExecutionContext getServerExecutionContext() {
+        return initialManagementContext.getServerExecutionContext();
+    }
+
+    // TODO the methods below should delegate to the application?
+    @Override
+    public EntityDriverManager getEntityDriverManager() {
+        checkInitialManagementContextReal();
+        return initialManagementContext.getEntityDriverManager();
+    }
+
+    @Override
+    public DownloadResolverManager getEntityDownloadsManager() {
+        checkInitialManagementContextReal();
+        return initialManagementContext.getEntityDownloadsManager();
+    }
+
+    @Override
+    public StringConfigMap getConfig() {
+        checkInitialManagementContextReal();
+        return initialManagementContext.getConfig();
+    }
+
+    @Override
+    public BrooklynProperties getBrooklynProperties() {
+        checkInitialManagementContextReal();
+        return initialManagementContext.getBrooklynProperties();
+    }
+
+    @Override
+    public BrooklynStorage getStorage() {
+        checkInitialManagementContextReal();
+        return initialManagementContext.getStorage();
+    }
+    
+    @Override
+    public RebindManager getRebindManager() {
+        // There was a race where EffectorUtils on invoking an effector calls:
+        //     mgmtSupport.getEntityChangeListener().onEffectorCompleted(eff);
+        // but where the entity/app may be being unmanaged concurrently (e.g. calling app.stop()).
+        // So now we allow the change-listener to be called.
+        
+        if (isInitialManagementContextReal()) {
+            return initialManagementContext.getRebindManager();
+        } else {
+            return new NonDeploymentRebindManager();
+        }
+    }
+
+    @Override
+    public HighAvailabilityManager getHighAvailabilityManager() {
+        if (isInitialManagementContextReal()) {
+            return initialManagementContext.getHighAvailabilityManager();
+        } else {
+            return new NonDeploymentHighAvailabilityManager();
+        }
+    }
+
+    @Override
+    public LocationRegistry getLocationRegistry() {
+        checkInitialManagementContextReal();
+        return initialManagementContext.getLocationRegistry();
+    }
+
+    @Override
+    public BrooklynCatalog getCatalog() {
+        checkInitialManagementContextReal();
+        return initialManagementContext.getCatalog();
+    }
+    
+    @Override
+    public ClassLoader getCatalogClassLoader() {
+        checkInitialManagementContextReal();
+        return initialManagementContext.getCatalogClassLoader();
+    }
+    
+    @Override
+    public EntitlementManager getEntitlementManager() {
+        return entitlementManager;
+    }
+    
+    @Override
+    public <T> T invokeEffectorMethodSync(final Entity entity, final Effector<T> eff, final Object args) throws ExecutionException {
+        throw new IllegalStateException("Non-deployment context "+this+" is not valid for this operation: cannot invoke effector "+eff+" on entity "+entity);
+    }
+    
+    @Override
+    public <T> Task<T> invokeEffector(final Entity entity, final Effector<T> eff, @SuppressWarnings("rawtypes") final Map parameters) {
+        throw new IllegalStateException("Non-deployment context "+this+" is not valid for this operation: cannot invoke effector "+eff+" on entity "+entity);
+    }
+
+    @Override
+    public ClassLoader getBaseClassLoader() {
+        checkInitialManagementContextReal();
+        return initialManagementContext.getBaseClassLoader();
+    }
+
+    @Override
+    public Iterable<URL> getBaseClassPathForScanning() {
+        checkInitialManagementContextReal();
+        return initialManagementContext.getBaseClassPathForScanning();
+    }
+
+    @Override
+    public void addEntitySetListener(CollectionChangeListener<Entity> listener) {
+        checkInitialManagementContextReal();
+        initialManagementContext.addEntitySetListener(listener);
+    }
+
+    @Override
+    public void removeEntitySetListener(CollectionChangeListener<Entity> listener) {
+        checkInitialManagementContextReal();
+        initialManagementContext.removeEntitySetListener(listener);
+    }
+
+    @Override
+    public void terminate() {
+        if (isInitialManagementContextReal()) {
+            initialManagementContext.terminate();
+        } else {
+            // no-op; the non-deployment management context has nothing needing terminated
+        }
+    }
+
+    @Override
+    public long getTotalEffectorInvocations() {
+        if (isInitialManagementContextReal()) {
+            return initialManagementContext.getTotalEffectorInvocations();
+        } else {
+            return 0;
+        }
+    }
+
+    @Override
+    public void setBaseClassPathForScanning(Iterable<URL> urls) {
+        checkInitialManagementContextReal();
+        initialManagementContext.setBaseClassPathForScanning(urls);
+    }
+
+    @Override
+    public void setManagementNodeUri(URI uri) {
+        checkInitialManagementContextReal();
+        initialManagementContext.setManagementNodeUri(uri);
+    }
+
+    @Override
+    public void prePreManage(Entity entity) {
+        // should throw?  but in 0.7.0-SNAPSHOT it was no-op
+        log.warn("Ignoring call to prePreManage("+entity+") on "+this);
+    }
+
+    @Override
+    public void prePreManage(Location location) {
+        // should throw?  but in 0.7.0-SNAPSHOT it was no-op
+        log.warn("Ignoring call to prePreManage("+location+") on "+this);
+    }
+
+    private boolean isInitialManagementContextReal() {
+        return (initialManagementContext != null && !(initialManagementContext instanceof NonDeploymentManagementContext));
+    }
+    
+    private void checkInitialManagementContextReal() {
+        if (!isInitialManagementContextReal()) {
+            throw new IllegalStateException("Non-deployment context "+this+" is not valid for this operation.");
+        }
+    }
+    
+    @Override
+    public void reloadBrooklynProperties() {
+        checkInitialManagementContextReal();
+        initialManagementContext.reloadBrooklynProperties();
+    }
+    
+    @Override
+    public void addPropertiesReloadListener(PropertiesReloadListener listener) {
+        checkInitialManagementContextReal();
+        initialManagementContext.addPropertiesReloadListener(listener);
+    }
+    
+    @Override
+    public void removePropertiesReloadListener(PropertiesReloadListener listener) {
+        checkInitialManagementContextReal();
+        initialManagementContext.removePropertiesReloadListener(listener);
+    }
+
+    @Override
+    public BrooklynObject lookup(String id) {
+        checkInitialManagementContextReal();
+        return initialManagementContext.lookup(id);
+    }
+
+    @Override
+    public <T extends BrooklynObject> T lookup(String id, Class<T> type) {
+        checkInitialManagementContextReal();
+        return initialManagementContext.lookup(id, type);
+    }
+
+    @Override
+    public List<Throwable> errors() {
+        checkInitialManagementContextReal();
+        return initialManagementContext.errors();
+    }
+
+    @Override
+    public CatalogInitialization getCatalogInitialization() {
+        checkInitialManagementContextReal();
+        return initialManagementContext.getCatalogInitialization();
+    }
+    
+    @Override
+    public void setCatalogInitialization(CatalogInitialization catalogInitialization) {
+        checkInitialManagementContextReal();
+        initialManagementContext.setCatalogInitialization(catalogInitialization);
+    }
+
+    /**
+     * For when the initial management context is not "real"; the changeListener is a no-op, but everything else forbidden.
+     * 
+     * @author aled
+     */
+    private class NonDeploymentRebindManager implements RebindManager {
+
+        @Override
+        public ChangeListener getChangeListener() {
+            return ChangeListener.NOOP;
+        }
+
+        @Override
+        public void setPersister(BrooklynMementoPersister persister) {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+
+        @Override
+        public void setPersister(BrooklynMementoPersister persister, PersistenceExceptionHandler exceptionHandler) {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+
+        @Override
+        public BrooklynMementoPersister getPersister() {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+
+        @Override
+        public List<Application> rebind() {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+
+        @Override
+        public List<Application> rebind(ClassLoader classLoader) {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+
+        @Override
+        public List<Application> rebind(ClassLoader classLoader, RebindExceptionHandler exceptionHandler) {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+        
+        @Override
+        public List<Application> rebind(ClassLoader classLoader, RebindExceptionHandler exceptionHandler, ManagementNodeState mode) {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+
+        @Override
+        public void startPersistence() {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+        
+        @Override
+        public void stopPersistence() {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+
+        @Override
+        public void startReadOnly(ManagementNodeState state) {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+        
+        @Override
+        public void stopReadOnly() {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+
+        @Override
+        public void start() {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+        
+        @Override
+        public void stop() {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+
+        @Override
+        public void waitForPendingComplete(Duration timeout, boolean canTrigger) throws InterruptedException, TimeoutException {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+        @Override
+        public void forcePersistNow() {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+        @Override
+        public void forcePersistNow(boolean full, PersistenceExceptionHandler exceptionHandler) {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+        @Override
+        public BrooklynMementoRawData retrieveMementoRawData() {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+        @Override
+        public boolean isAwaitingInitialRebind() {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+        
+        @Override
+        public Map<String, Object> getMetrics() {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+    }
+
+    /**
+     * For when the initial management context is not "real".
+     * 
+     * @author aled
+     */
+    private class NonDeploymentHighAvailabilityManager implements HighAvailabilityManager {
+        @Override
+        public ManagementNodeState getNodeState() {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+        @Override
+        public boolean isRunning() {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+        @Override
+        public HighAvailabilityManager setPersister(ManagementPlaneSyncRecordPersister persister) {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+        @Override
+        public void disabled() {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+        @Override
+        public void start(HighAvailabilityMode startMode) {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+        @Override
+        public void stop() {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+        @Override
+        public ManagementPlaneSyncRecordPersister getPersister() {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+        @Override
+        public ManagementPlaneSyncRecord getLastManagementPlaneSyncRecord() {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+        @Override
+        public ManagementPlaneSyncRecord loadManagementPlaneSyncRecord(boolean x) {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+        @Override
+        public void changeMode(HighAvailabilityMode startMode) {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+        @Override
+        public void setPriority(long priority) {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+        @Override
+        public long getPriority() {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+        @Override
+        public Map<String, Object> getMetrics() {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+        @Override
+        public void publishClearNonMaster() {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+        @Override
+        public long getLastStateChange() {
+            throw new IllegalStateException("Non-deployment context "+NonDeploymentManagementContext.this+" is not valid for this operation.");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6602f694/core/src/main/java/org/apache/brooklyn/core/management/internal/NonDeploymentUsageManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/management/internal/NonDeploymentUsageManager.java b/core/src/main/java/org/apache/brooklyn/core/management/internal/NonDeploymentUsageManager.java
new file mode 100644
index 0000000..55a4a78
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/management/internal/NonDeploymentUsageManager.java
@@ -0,0 +1,132 @@
+/*
+ * 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.management.internal;
+
+import java.util.Set;
+
+import org.apache.brooklyn.api.entity.Application;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.management.usage.ApplicationUsage;
+import org.apache.brooklyn.core.management.usage.LocationUsage;
+
+import brooklyn.entity.basic.Lifecycle;
+
+import com.google.common.base.Predicate;
+
+
+public class NonDeploymentUsageManager implements UsageManager {
+
+    // TODO All the `isInitialManagementContextReal()` code-checks is a code-smell.
+    // Expect we can delete a lot of this once we guarantee that all entities are 
+    // instantiated via EntitySpec / EntityManager. Until then, we'll live with this.
+    
+    private final ManagementContextInternal initialManagementContext;
+    
+    public NonDeploymentUsageManager(ManagementContextInternal initialManagementContext) {
+        this.initialManagementContext = initialManagementContext;
+    }
+    
+    private boolean isInitialManagementContextReal() {
+        return (initialManagementContext != null && !(initialManagementContext instanceof NonDeploymentManagementContext));
+    }
+
+    @Override
+    public void recordApplicationEvent(Application app, Lifecycle state) {
+        if (isInitialManagementContextReal()) {
+            initialManagementContext.getUsageManager().recordApplicationEvent(app, state);
+        } else {
+            throw new IllegalStateException("Non-deployment context "+this+" is not valid for this operation");
+        }
+    }
+
+    @Override
+    public void recordLocationEvent(Location loc, Lifecycle state) {
+        if (isInitialManagementContextReal()) {
+            initialManagementContext.getUsageManager().recordLocationEvent(loc, state);
+        } else {
+            throw new IllegalStateException("Non-deployment context "+this+" is not valid for this operation");
+        }
+    }
+
+    @Override
+    public LocationUsage getLocationUsage(String locationId) {
+        if (isInitialManagementContextReal()) {
+            return initialManagementContext.getUsageManager().getLocationUsage(locationId);
+        } else {
+            throw new IllegalStateException("Non-deployment context "+this+" is not valid for this operation");
+        }
+    }
+
+    @Override
+    public Set<LocationUsage> getLocationUsage(Predicate<? super LocationUsage> filter) {
+        if (isInitialManagementContextReal()) {
+            return initialManagementContext.getUsageManager().getLocationUsage(filter);
+        } else {
+            throw new IllegalStateException("Non-deployment context "+this+" is not valid for this operation");
+        }
+    }
+
+    @Override
+    public ApplicationUsage getApplicationUsage(String appId) {
+        if (isInitialManagementContextReal()) {
+            return initialManagementContext.getUsageManager().getApplicationUsage(appId);
+        } else {
+            throw new IllegalStateException("Non-deployment context "+this+" is not valid for this operation");
+        }
+    }
+
+    @Override
+    public Set<ApplicationUsage> getApplicationUsage(Predicate<? super ApplicationUsage> filter) {
+        if (isInitialManagementContextReal()) {
+            return initialManagementContext.getUsageManager().getApplicationUsage(filter);
+        } else {
+            throw new IllegalStateException("Non-deployment context "+this+" is not valid for this operation");
+        }
+    }
+
+    @Override
+    @Deprecated
+    public void addUsageListener(org.apache.brooklyn.core.management.internal.UsageManager.UsageListener listener) {
+        addUsageListener(new org.apache.brooklyn.core.management.internal.UsageManager.UsageListener.UsageListenerAdapter(listener));
+    }
+
+    @Override
+    @Deprecated
+    public void removeUsageListener(org.apache.brooklyn.core.management.internal.UsageManager.UsageListener listener) {
+        removeUsageListener(new org.apache.brooklyn.core.management.internal.UsageManager.UsageListener.UsageListenerAdapter(listener));
+    }
+    
+    @Override
+    public void addUsageListener(org.apache.brooklyn.core.management.internal.UsageListener listener) {
+        if (isInitialManagementContextReal()) {
+            initialManagementContext.getUsageManager().addUsageListener(listener);
+        } else {
+            throw new IllegalStateException("Non-deployment context "+this+" is not valid for this operation");
+        }
+    }
+
+    @Override
+    public void removeUsageListener(org.apache.brooklyn.core.management.internal.UsageListener listener) {
+        if (isInitialManagementContextReal()) {
+            initialManagementContext.getUsageManager().removeUsageListener(listener);
+        } else {
+            throw new IllegalStateException("Non-deployment context "+this+" is not valid for this operation");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6602f694/core/src/main/java/org/apache/brooklyn/core/management/internal/QueueingSubscriptionManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/management/internal/QueueingSubscriptionManager.java b/core/src/main/java/org/apache/brooklyn/core/management/internal/QueueingSubscriptionManager.java
new file mode 100644
index 0000000..8f54d95
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/management/internal/QueueingSubscriptionManager.java
@@ -0,0 +1,148 @@
+/*
+ * 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.management.internal;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.event.Sensor;
+import org.apache.brooklyn.api.event.SensorEvent;
+import org.apache.brooklyn.api.management.SubscriptionHandle;
+
+import com.google.common.base.Objects;
+
+@SuppressWarnings("rawtypes")
+public class QueueingSubscriptionManager extends AbstractSubscriptionManager {
+
+    static class QueuedSubscription<T> {
+        Map<String, Object> flags;
+        Subscription<T> s;
+    }
+
+    public AbstractSubscriptionManager delegate = null;
+    public boolean useDelegateForSubscribing = false;
+    public boolean useDelegateForPublishing = false;
+    
+    List<QueuedSubscription> queuedSubscriptions = new ArrayList<QueuedSubscription>();
+    List<SensorEvent> queuedSensorEvents = new ArrayList<SensorEvent>();
+    
+    @Override
+    protected synchronized <T> SubscriptionHandle subscribe(Map<String, Object> flags, Subscription<T> s) {
+        if (useDelegateForSubscribing)
+            return delegate.subscribe(flags, s);
+        
+        QueuedSubscription<T> qs = new QueuedSubscription<T>();
+        qs.flags = flags;
+        s.subscriber = getSubscriber(flags, s);
+        qs.s = s;
+        queuedSubscriptions.add(qs);
+        return s;
+    }
+
+    @Override
+    public synchronized <T> void publish(SensorEvent<T> event) {
+        if (useDelegateForPublishing) {
+            delegate.publish(event);
+            return;
+        }
+        
+        queuedSensorEvents.add(event);
+    }
+
+    public void setDelegate(AbstractSubscriptionManager delegate) {
+        this.delegate = delegate;
+    }
+    
+    @SuppressWarnings("unchecked")
+    public synchronized void startDelegatingForSubscribing() {
+        assert delegate!=null;
+        for (QueuedSubscription s: queuedSubscriptions) {
+            delegate.subscribe(s.flags, s.s);
+        }
+        queuedSubscriptions.clear();
+        useDelegateForSubscribing = true;
+    }
+    
+    @SuppressWarnings("unchecked")
+    public synchronized void startDelegatingForPublishing() {
+        assert delegate!=null;
+        for (SensorEvent evt: queuedSensorEvents) {
+            delegate.publish(evt);
+        }
+        queuedSensorEvents.clear();
+        useDelegateForPublishing = true;
+    }
+    
+    public synchronized void stopDelegatingForSubscribing() {
+        useDelegateForSubscribing = false;
+    }
+    
+    public synchronized void stopDelegatingForPublishing() {
+        useDelegateForPublishing = false;
+    }
+
+    @Override
+    public synchronized boolean unsubscribe(SubscriptionHandle subscriptionId) {
+        if (useDelegateForSubscribing)
+            return delegate.unsubscribe(subscriptionId);
+        
+        Iterator<QueuedSubscription> qi = queuedSubscriptions.iterator();
+        while (qi.hasNext()) {
+            QueuedSubscription q = qi.next();
+            if (Objects.equal(subscriptionId, q.s)) {
+                qi.remove();
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public synchronized Set<SubscriptionHandle> getSubscriptionsForSubscriber(Object subscriber) {
+        if (useDelegateForSubscribing)
+            return delegate.getSubscriptionsForSubscriber(subscriber);
+        
+        Set<SubscriptionHandle> result = new LinkedHashSet<SubscriptionHandle>();
+        for (QueuedSubscription q: queuedSubscriptions) {
+            if (Objects.equal(subscriber, getSubscriber(q.flags, q.s))) result.add(q.s);
+        }
+        return result;
+    }
+
+    @Override
+    public synchronized Set<SubscriptionHandle> getSubscriptionsForEntitySensor(Entity source, Sensor<?> sensor) {
+        if (useDelegateForSubscribing)
+            return delegate.getSubscriptionsForEntitySensor(source, sensor);
+        
+        Set<SubscriptionHandle> result = new LinkedHashSet<SubscriptionHandle>();
+        for (QueuedSubscription q: queuedSubscriptions) {
+            if ((q.s.sensor==null || Objects.equal(q.s.sensor, sensor)) &&
+                    (q.s.producer==null || Objects.equal(q.s.producer, sensor)))
+                result.add(q.s);
+        }
+        return result;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6602f694/core/src/main/java/org/apache/brooklyn/core/management/internal/Subscription.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/management/internal/Subscription.java b/core/src/main/java/org/apache/brooklyn/core/management/internal/Subscription.java
new file mode 100644
index 0000000..acd30c3
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/management/internal/Subscription.java
@@ -0,0 +1,66 @@
+/*
+ * 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.management.internal;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.event.Sensor;
+import org.apache.brooklyn.api.event.SensorEvent;
+import org.apache.brooklyn.api.event.SensorEventListener;
+import org.apache.brooklyn.api.management.SubscriptionHandle;
+
+import brooklyn.util.text.Identifiers;
+
+import com.google.common.base.Predicate;
+
+class Subscription<T> implements SubscriptionHandle {
+    public final String id = Identifiers.makeRandomId(8);
+    
+    public Object subscriber;
+    public Object subscriberExecutionManagerTag;
+    /** whether the tag was supplied by user, in which case we should not clear execution semantics */
+    public boolean subscriberExecutionManagerTagSupplied;
+    public final Entity producer;
+    public final Sensor<T> sensor;
+    public final SensorEventListener<? super T> listener;
+    public Map<String,Object> flags;
+    public Predicate<SensorEvent<T>> eventFilter;
+
+    public Subscription(Entity producer, Sensor<T> sensor, SensorEventListener<? super T> listener) {
+        this.producer = producer;
+        this.sensor = sensor;
+        this.listener = listener;
+    }
+    
+    @Override
+    public boolean equals(Object other) {
+        return (other instanceof Subscription && ((Subscription<?>)other).id==id);
+    }
+
+    @Override
+    public int hashCode() {
+        return id.hashCode();
+    }
+    
+    @Override
+    public String toString() {
+        return "Subscription["+id+";"+subscriber+"@"+LocalSubscriptionManager.makeEntitySensorToken(producer,sensor)+"]";
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6602f694/core/src/main/java/org/apache/brooklyn/core/management/internal/SubscriptionTracker.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/management/internal/SubscriptionTracker.java b/core/src/main/java/org/apache/brooklyn/core/management/internal/SubscriptionTracker.java
new file mode 100644
index 0000000..acc0cb6
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/management/internal/SubscriptionTracker.java
@@ -0,0 +1,137 @@
+/*
+ * 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.management.internal;
+
+import java.util.Collection;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.Group;
+import org.apache.brooklyn.api.event.Sensor;
+import org.apache.brooklyn.api.event.SensorEventListener;
+import org.apache.brooklyn.api.management.SubscriptionContext;
+import org.apache.brooklyn.api.management.SubscriptionHandle;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.SetMultimap;
+
+/**
+ * Tracks subscriptions associated that are registered with particular entities. Gives utilities for unsubscribing from all
+ * subscriptions on a given entity, etc.
+ */
+public class SubscriptionTracker {
+
+    // This class is thread-safe. All modifications to subscriptions are synchronized on the 
+    // "subscriptions" field. However, calls to alien code (i.e. context.subscribe etc) is
+    // done without holding the lock.
+    //
+    // If two threads do subscribe() and unsubscribeAll() concurrently, then it's non-derministic
+    // whether the subscription will be in place at the end (but that's unavoidable). However, it
+    // is guaranteed that the internal state of the SubscriptionTracker will be consistent: if
+    // the "subscriptions" includes the new subscription then that subscription will really exist,
+    // and vice versa.
+    
+    protected SubscriptionContext context;
+    
+    private final SetMultimap<Entity, SubscriptionHandle> subscriptions = HashMultimap.create();
+
+    public SubscriptionTracker(SubscriptionContext subscriptionContext) {
+        this.context = subscriptionContext;
+    }
+    
+    /** @see SubscriptionContext#subscribe(Entity, Sensor, SensorEventListener) */
+    public <T> SubscriptionHandle subscribe(Entity producer, Sensor<T> sensor, SensorEventListener<? super T> listener) {
+        SubscriptionHandle handle = context.subscribe(producer, sensor, listener);
+        synchronized (subscriptions) {
+            subscriptions.put(producer, handle);
+        }
+        return handle;
+    }
+    
+    /** @see SubscriptionContext#subscribeToChildren(Entity, Sensor, SensorEventListener) */
+    public <T> SubscriptionHandle subscribeToChildren(Entity parent, Sensor<T> sensor, SensorEventListener<? super T> listener) {
+        SubscriptionHandle handle = context.subscribeToChildren(parent, sensor, listener);
+        synchronized (subscriptions) {
+            subscriptions.put(parent, handle);
+        }
+        return handle;
+    }
+
+    /**
+     * @see SubscriptionContext#subscribeToMembers(Group, Sensor, SensorEventListener)
+     */
+    public <T> SubscriptionHandle subscribeToMembers(Group parent, Sensor<T> sensor, SensorEventListener<? super T> listener) {
+        SubscriptionHandle handle = context.subscribeToMembers(parent, sensor, listener);
+        synchronized (subscriptions) {
+            subscriptions.put(parent, handle);
+        }
+        return handle;
+    }    
+
+    /**
+     * Unsubscribes the given producer.
+     *
+     * @see SubscriptionContext#unsubscribe(SubscriptionHandle)
+     */
+    public boolean unsubscribe(Entity producer) {
+        Collection<SubscriptionHandle> handles;
+        synchronized (subscriptions) {
+            handles = subscriptions.removeAll(producer);
+        }
+        if (handles != null) {
+            for (SubscriptionHandle handle : handles) {
+                context.unsubscribe(handle);
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+    * Unsubscribes the given producer.
+    *
+    * @see SubscriptionContext#unsubscribe(SubscriptionHandle)
+    */
+   public boolean unsubscribe(Entity producer, SubscriptionHandle handle) {
+       synchronized (subscriptions) {
+           subscriptions.remove(producer, handle);
+       }
+       return context.unsubscribe(handle);
+   }
+
+    /**
+    * @return an ordered list of all subscription handles
+    */
+   public Collection<SubscriptionHandle> getAllSubscriptions() {
+       synchronized (subscriptions) {
+           return ImmutableList.copyOf(subscriptions.values());
+       }
+   }
+   
+   public void unsubscribeAll() {
+       Collection<SubscriptionHandle> subscriptionsSnapshot;
+       synchronized (subscriptions) {
+           subscriptionsSnapshot = ImmutableList.copyOf(subscriptions.values());
+           subscriptions.clear();
+       }
+       for (SubscriptionHandle s: subscriptionsSnapshot) {
+           context.unsubscribe(s);
+       }
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6602f694/core/src/main/java/org/apache/brooklyn/core/management/internal/UsageListener.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/management/internal/UsageListener.java b/core/src/main/java/org/apache/brooklyn/core/management/internal/UsageListener.java
new file mode 100644
index 0000000..566c0f0
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/management/internal/UsageListener.java
@@ -0,0 +1,103 @@
+/*
+ * 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.management.internal;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.Application;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.management.usage.ApplicationUsage.ApplicationEvent;
+import org.apache.brooklyn.core.management.usage.LocationUsage.LocationEvent;
+
+import com.google.common.annotations.Beta;
+
+@Beta
+public interface UsageListener {
+    
+    /**
+     * A no-op implementation of {@link UsageListener}, for users to extend.
+     * 
+     * Users are encouraged to extend this class, which will shield the user 
+     * from the addition of other usage event methods being added. If additional
+     * methods are added in a future release, a no-op implementation will be
+     * added to this class.
+     */
+    @Beta
+    public static class BasicUsageListener implements UsageListener {
+        @Override
+        public void onApplicationEvent(ApplicationMetadata app, ApplicationEvent event) {
+        }
+        
+        @Override public void onLocationEvent(LocationMetadata loc, LocationEvent event) {
+        }
+    }
+    
+    /**
+     * Users should never implement this interface directly; methods may be added in future releases
+     * without notice.
+     */
+    @Beta
+    public interface ApplicationMetadata {
+        /**
+         * Access the application directly with caution: by the time the listener fires, 
+         * the application may no longer be managed.
+         */
+        @Beta
+        Application getApplication();
+        
+        String getApplicationId();
+        
+        String getApplicationName();
+        
+        String getEntityType();
+        
+        String getCatalogItemId();
+        
+        Map<String, String> getMetadata();
+    }
+    
+    /**
+     * Users should never implement this interface directly; methods may be added in future releases
+     * without notice.
+     */
+    @Beta
+    public interface LocationMetadata {
+        /**
+         * Access the location directly with caution: by the time the listener fires, 
+         * the location may no longer be managed.
+         */
+        @Beta
+        Location getLocation();
+        
+        String getLocationId();
+        
+        Map<String, String> getMetadata();
+    }
+    
+    public static final UsageListener NOOP = new UsageListener() {
+        @Override public void onApplicationEvent(ApplicationMetadata app, ApplicationEvent event) {}
+        @Override public void onLocationEvent(LocationMetadata loc, LocationEvent event) {}
+    };
+    
+    @Beta
+    void onApplicationEvent(ApplicationMetadata app, ApplicationEvent event);
+    
+    @Beta
+    void onLocationEvent(LocationMetadata loc, LocationEvent event);
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6602f694/core/src/main/java/org/apache/brooklyn/core/management/internal/UsageManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/management/internal/UsageManager.java b/core/src/main/java/org/apache/brooklyn/core/management/internal/UsageManager.java
new file mode 100644
index 0000000..75c242a
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/management/internal/UsageManager.java
@@ -0,0 +1,166 @@
+/*
+ * 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.management.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.brooklyn.api.entity.Application;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.management.usage.ApplicationUsage;
+import org.apache.brooklyn.core.management.usage.LocationUsage;
+import org.apache.brooklyn.core.management.usage.ApplicationUsage.ApplicationEvent;
+import org.apache.brooklyn.core.management.usage.LocationUsage.LocationEvent;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.Lifecycle;
+import brooklyn.util.time.Duration;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.reflect.TypeToken;
+
+@Beta
+public interface UsageManager {
+
+    @SuppressWarnings("serial")
+    public static final ConfigKey<List<org.apache.brooklyn.core.management.internal.UsageListener>> USAGE_LISTENERS = ConfigKeys.newConfigKey(
+            new TypeToken<List<org.apache.brooklyn.core.management.internal.UsageListener>>() {},
+            "brooklyn.usageManager.listeners", "Optional usage listeners (i.e. for metering)",
+            ImmutableList.<org.apache.brooklyn.core.management.internal.UsageListener>of());
+    
+    public static final ConfigKey<Duration> USAGE_LISTENER_TERMINATION_TIMEOUT = ConfigKeys.newConfigKey(
+            Duration.class,
+            "brooklyn.usageManager.listeners.timeout",
+            "Timeout on termination, to wait for queue of usage listener events to be processed",
+            Duration.TEN_SECONDS);
+
+    /**
+     * @since 0.7.0
+     * @deprecated since 0.7.0; use {@link org.apache.brooklyn.core.management.internal.UsageListener}; see {@link UsageListenerAdapter} 
+     */
+    public interface UsageListener {
+        public static final UsageListener NOOP = new UsageListener() {
+            @Override public void onApplicationEvent(String applicationId, String applicationName, String entityType, 
+                    String catalogItemId, Map<String, String> metadata, ApplicationEvent event) {}
+            @Override public void onLocationEvent(String locationId, Map<String, String> metadata, LocationEvent event) {}
+        };
+        
+        public static class UsageListenerAdapter implements org.apache.brooklyn.core.management.internal.UsageListener {
+            private final UsageListener listener;
+
+            public UsageListenerAdapter(UsageListener listener) {
+                this.listener = checkNotNull(listener, "listener");
+            }
+            
+            @Override
+            public void onApplicationEvent(ApplicationMetadata app, ApplicationEvent event) {
+                listener.onApplicationEvent(app.getApplicationId(), app.getApplicationName(), app.getEntityType(), app.getCatalogItemId(), app.getMetadata(), event);
+            }
+
+            @Override
+            public void onLocationEvent(LocationMetadata loc, LocationEvent event) {
+                listener.onLocationEvent(loc.getLocationId(), loc.getMetadata(), event);
+            }
+            
+            @Override
+            public boolean equals(Object obj) {
+                return (obj instanceof UsageListenerAdapter) && listener.equals(((UsageListenerAdapter)obj).listener);
+            }
+            
+            @Override
+            public int hashCode() {
+                return Objects.hashCode(listener);
+            }
+        }
+        
+        void onApplicationEvent(String applicationId, String applicationName, String entityType, String catalogItemId,
+                Map<String, String> metadata, ApplicationEvent event);
+        
+        void onLocationEvent(String locationId, Map<String, String> metadata, LocationEvent event);
+    }
+
+    /**
+     * Adds this application event to the usage record for the given app (creating the usage 
+     * record if one does not already exist).
+     */
+    void recordApplicationEvent(Application app, Lifecycle state);
+    
+    /**
+     * Adds this location event to the usage record for the given location (creating the usage 
+     * record if one does not already exist).
+     */
+    void recordLocationEvent(Location loc, Lifecycle state);
+
+    /**
+     * Returns the usage info for the location with the given id, or null if unknown.
+     */
+    LocationUsage getLocationUsage(String locationId);
+    
+    /**
+     * Returns the usage info that matches the given predicate.
+     * For example, could be used to find locations used within a given time period.
+     */
+    Set<LocationUsage> getLocationUsage(Predicate<? super LocationUsage> filter);
+    
+    /**
+     * Returns the usage info for the application with the given id, or null if unknown.
+     */
+    ApplicationUsage getApplicationUsage(String appId);
+    
+    /**
+     * Returns the usage info that matches the given predicate.
+     * For example, could be used to find applications used within a given time period.
+     */
+    Set<ApplicationUsage> getApplicationUsage(Predicate<? super ApplicationUsage> filter);
+
+    /**
+     * @since 0.7.0
+     * @deprecated since 0.7.0; use {@link #removeUsageListener(org.apache.brooklyn.core.management.internal.UsageListener)};
+     *             see {@link org.apache.brooklyn.core.management.internal.UsageManager.UsageListener.UsageListenerAdapter} 
+     */
+    void addUsageListener(org.apache.brooklyn.core.management.internal.UsageManager.UsageListener listener);
+
+    /**
+     * @since 0.7.0
+     * @deprecated since 0.7.0; use {@link #removeUsageListener(org.apache.brooklyn.core.management.internal.UsageListener)}
+     */
+    @Deprecated
+    void removeUsageListener(org.apache.brooklyn.core.management.internal.UsageManager.UsageListener listener);
+    
+    /**
+     * Adds the given listener, to be notified on recording of application/location events.
+     * The listener notifications may be asynchronous.
+     * 
+     * As of 0.7.0, the listener is not persisted so will be lost on restart/rebind. This
+     * behaviour may change in a subsequent release. 
+     */
+    void addUsageListener(org.apache.brooklyn.core.management.internal.UsageListener listener);
+
+    /**
+     * Removes the given listener.
+     */
+    void removeUsageListener(org.apache.brooklyn.core.management.internal.UsageListener listener);
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6602f694/core/src/main/java/org/apache/brooklyn/core/management/usage/ApplicationUsage.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/management/usage/ApplicationUsage.java b/core/src/main/java/org/apache/brooklyn/core/management/usage/ApplicationUsage.java
new file mode 100644
index 0000000..8260923
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/management/usage/ApplicationUsage.java
@@ -0,0 +1,126 @@
+/*
+ * 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.management.usage;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import brooklyn.entity.basic.Lifecycle;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+/**
+ */
+public class ApplicationUsage {
+    
+    public static class ApplicationEvent {
+        private final Date date;
+        private final Lifecycle state;
+        private final String user;
+
+        public ApplicationEvent(Lifecycle state, String user) {
+            this(new Date(), state, user);
+        }
+
+        public ApplicationEvent(Date date, Lifecycle state) {
+            this(date,state, null);
+        }
+
+        public ApplicationEvent(Date date, Lifecycle state, String user) {
+            this.date = checkNotNull(date, "date");
+            this.state = checkNotNull(state, "state");
+            this.user = user;
+        }
+
+        public Date getDate() {
+            return date;
+        }
+
+        public Lifecycle getState() {
+            return state;
+        }
+
+        public String getUser() {
+            return user;
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (!(other instanceof ApplicationEvent)) return false;
+            ApplicationEvent o = (ApplicationEvent) other;
+            return Objects.equal(date, o.date) && Objects.equal(state, o.state) && Objects.equal(user, o.user);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hashCode(date, state, user);
+        }
+        
+        @Override
+        public String toString() {
+            return Objects.toStringHelper(this).add("date", date).add("state", state).add("entitlementContext", user).toString();
+        }
+    }
+    
+    private final String applicationId;
+    private final String applicationName;
+    private final String entityType;
+    private final Map<String, String> metadata;
+    private final List<ApplicationEvent> events = Collections.synchronizedList(Lists.<ApplicationEvent>newArrayList());
+
+    public ApplicationUsage(String applicationId, String applicationName, String entityType, Map<String, String> metadata) {
+        this.applicationId = checkNotNull(applicationId, "applicationId");
+        // allow name to be null, happens in certain failed rebind cases
+        this.applicationName = applicationName;
+        this.entityType = checkNotNull(entityType, "entityType");
+        this.metadata = checkNotNull(metadata, "metadata");
+    }
+
+    public String getApplicationId() {
+        return applicationId;
+    }
+
+    public String getApplicationName() {
+        return applicationName;
+    }
+
+    public String getEntityType() {
+        return entityType;
+    }
+
+    public Map<String, String> getMetadata() {
+        return metadata;
+    }
+    
+    public List<ApplicationEvent> getEvents() {
+        synchronized (events) {
+            return ImmutableList.copyOf(events);
+        }
+    }
+
+    public void addEvent(ApplicationEvent event) {
+        events.add(checkNotNull(event, "event"));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6602f694/core/src/main/java/org/apache/brooklyn/core/management/usage/LocationUsage.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/management/usage/LocationUsage.java b/core/src/main/java/org/apache/brooklyn/core/management/usage/LocationUsage.java
new file mode 100644
index 0000000..32bd03b
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/management/usage/LocationUsage.java
@@ -0,0 +1,135 @@
+/*
+ * 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.management.usage;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import brooklyn.entity.basic.Lifecycle;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+/**
+ */
+public class LocationUsage {
+    
+    public static class LocationEvent {
+        private final Date date;
+        private final Lifecycle state;
+        private final String entityId;
+        private final String entityType;
+        private final String applicationId;
+        private final String user;
+
+        public LocationEvent(Lifecycle state, String entityId, String entityType, String applicationId, String user) {
+            this(new Date(), state, entityId, entityType, applicationId, user);
+        }
+        
+        public LocationEvent(Date date, Lifecycle state, String entityId, String entityType, String applicationId, String user) {
+            this.date = checkNotNull(date, "date");
+            this.state = checkNotNull(state, "state");
+            this.entityId = checkNotNull(entityId, "entityId");
+            this.entityType = checkNotNull(entityType, "entityType");
+            this.applicationId = checkNotNull(applicationId, "applicationId (entity "+entityId+")");
+            this.user = user;
+        }
+
+        public Date getDate() {
+            return date;
+        }
+
+        public Lifecycle getState() {
+            return state;
+        }
+
+        public String getEntityId() {
+            return entityId;
+        }
+
+        public String getEntityType() {
+            return entityType;
+        }
+
+        public String getApplicationId() {
+            return applicationId;
+        }
+
+        public String getUser() {
+            return user;
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (!(other instanceof LocationEvent)) return false;
+            LocationEvent o = (LocationEvent) other;
+            return Objects.equal(date, o.date) && Objects.equal(state, o.state) 
+                    && Objects.equal(entityId, o.entityId) && Objects.equal(entityType, o.entityType)
+                    && Objects.equal(applicationId, o.applicationId) && Objects.equal(user, o.user);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hashCode(date, state, entityId, entityType, applicationId, user);
+        }
+        
+        @Override
+        public String toString() {
+            return Objects.toStringHelper(this)
+                    .add("date", date)
+                    .add("state", state)
+                    .add("entityId", entityId)
+                    .add("appId", applicationId)
+                    .add("user", user)
+                    .toString();
+        }
+    }
+    
+    private final String locationId;
+    private final Map<String, String> metadata;
+    private final List<LocationEvent> events = Collections.synchronizedList(Lists.<LocationEvent>newArrayList());
+
+    public LocationUsage(String locationId, Map<String, String> metadata) {
+        this.locationId = checkNotNull(locationId, "locationId");
+        this.metadata = checkNotNull(metadata, "metadata");
+    }
+
+    public String getLocationId() {
+        return locationId;
+    }
+
+    public Map<String, String> getMetadata() {
+        return metadata;
+    }
+    
+    public List<LocationEvent> getEvents() {
+        synchronized (events) {
+            return ImmutableList.copyOf(events);
+        }
+    }
+
+    public void addEvent(LocationEvent event) {
+        events.add(checkNotNull(event, "event"));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6602f694/core/src/main/java/org/apache/brooklyn/location/basic/AbstractLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/basic/AbstractLocation.java b/core/src/main/java/org/apache/brooklyn/location/basic/AbstractLocation.java
index 47dca3e..c5a74a0 100644
--- a/core/src/main/java/org/apache/brooklyn/location/basic/AbstractLocation.java
+++ b/core/src/main/java/org/apache/brooklyn/location/basic/AbstractLocation.java
@@ -35,6 +35,8 @@ import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.api.mementos.LocationMemento;
+import org.apache.brooklyn.core.management.internal.LocalLocationManager;
+import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -53,8 +55,6 @@ import brooklyn.internal.storage.impl.BasicReference;
 import org.apache.brooklyn.location.geo.HasHostGeoInfo;
 import org.apache.brooklyn.location.geo.HostGeoInfo;
 
-import brooklyn.management.internal.LocalLocationManager;
-import brooklyn.management.internal.ManagementContextInternal;
 import brooklyn.util.collections.SetFromLiveMap;
 import brooklyn.util.config.ConfigBag;
 import brooklyn.util.flags.FlagUtils;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6602f694/core/src/main/java/org/apache/brooklyn/location/basic/BasicLocationRegistry.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/basic/BasicLocationRegistry.java b/core/src/main/java/org/apache/brooklyn/location/basic/BasicLocationRegistry.java
index 490335a..9a6466e 100644
--- a/core/src/main/java/org/apache/brooklyn/location/basic/BasicLocationRegistry.java
+++ b/core/src/main/java/org/apache/brooklyn/location/basic/BasicLocationRegistry.java
@@ -40,12 +40,12 @@ import org.apache.brooklyn.api.location.LocationRegistry;
 import org.apache.brooklyn.api.location.LocationResolver;
 import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.core.management.internal.LocalLocationManager;
 
 import brooklyn.catalog.CatalogPredicates;
 import brooklyn.config.ConfigMap;
 import brooklyn.config.ConfigPredicates;
 import brooklyn.config.ConfigUtils;
-import brooklyn.management.internal.LocalLocationManager;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6602f694/core/src/main/java/org/apache/brooklyn/location/basic/ByonLocationResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/basic/ByonLocationResolver.java b/core/src/main/java/org/apache/brooklyn/location/basic/ByonLocationResolver.java
index 127a665..70735e5 100644
--- a/core/src/main/java/org/apache/brooklyn/location/basic/ByonLocationResolver.java
+++ b/core/src/main/java/org/apache/brooklyn/location/basic/ByonLocationResolver.java
@@ -28,6 +28,7 @@ import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.location.LocationRegistry;
 import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.location.MachineLocation;
+import org.apache.brooklyn.core.management.internal.LocalLocationManager;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -40,7 +41,6 @@ import com.google.common.net.HostAndPort;
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.Sanitizer;
-import brooklyn.management.internal.LocalLocationManager;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.config.ConfigBag;
 import brooklyn.util.flags.TypeCoercions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6602f694/core/src/test/java/brooklyn/BrooklynVersionTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/BrooklynVersionTest.java b/core/src/test/java/brooklyn/BrooklynVersionTest.java
index 7fbe976..179e698 100644
--- a/core/src/test/java/brooklyn/BrooklynVersionTest.java
+++ b/core/src/test/java/brooklyn/BrooklynVersionTest.java
@@ -37,8 +37,9 @@ import com.google.common.collect.Lists;
 import brooklyn.catalog.internal.CatalogEntityItemDto;
 import brooklyn.catalog.internal.CatalogItemBuilder;
 import brooklyn.catalog.internal.CatalogItemDtoAbstract;
-import brooklyn.management.internal.LocalManagementContext;
-import brooklyn.management.osgi.OsgiTestResources;
+
+import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.management.osgi.OsgiTestResources;
 import org.apache.brooklyn.test.TestResourceUnavailableException;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6602f694/core/src/test/java/brooklyn/camp/lite/CampYamlLiteTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/camp/lite/CampYamlLiteTest.java b/core/src/test/java/brooklyn/camp/lite/CampYamlLiteTest.java
index 0917b0e..73cf5ce 100644
--- a/core/src/test/java/brooklyn/camp/lite/CampYamlLiteTest.java
+++ b/core/src/test/java/brooklyn/camp/lite/CampYamlLiteTest.java
@@ -49,6 +49,8 @@ import org.apache.brooklyn.api.catalog.CatalogItem.CatalogBundle;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.management.osgi.OsgiStandaloneTest;
 
 import brooklyn.catalog.CatalogPredicates;
 import brooklyn.catalog.internal.BasicBrooklynCatalog;
@@ -59,8 +61,6 @@ import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.effector.AddChildrenEffector;
 import brooklyn.entity.effector.Effectors;
-import brooklyn.management.internal.LocalManagementContext;
-import brooklyn.management.osgi.OsgiStandaloneTest;
 import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.config.ConfigBag;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6602f694/core/src/test/java/brooklyn/catalog/internal/CatalogDtoTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/catalog/internal/CatalogDtoTest.java b/core/src/test/java/brooklyn/catalog/internal/CatalogDtoTest.java
index 731a2d8..25a050e 100644
--- a/core/src/test/java/brooklyn/catalog/internal/CatalogDtoTest.java
+++ b/core/src/test/java/brooklyn/catalog/internal/CatalogDtoTest.java
@@ -28,13 +28,13 @@ import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 import org.apache.brooklyn.api.catalog.CatalogItem.CatalogBundle;
+import org.apache.brooklyn.core.management.internal.LocalManagementContext;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.apache.brooklyn.test.entity.TestEntity;
 
 import brooklyn.catalog.internal.CatalogClasspathDo.CatalogScanningModes;
 import brooklyn.entity.basic.Entities;
-import brooklyn.management.internal.LocalManagementContext;
 import brooklyn.util.BrooklynMavenArtifacts;
 import brooklyn.util.maven.MavenRetriever;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6602f694/core/src/test/java/brooklyn/catalog/internal/CatalogScanTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/catalog/internal/CatalogScanTest.java b/core/src/test/java/brooklyn/catalog/internal/CatalogScanTest.java
index 8630430..c417421 100644
--- a/core/src/test/java/brooklyn/catalog/internal/CatalogScanTest.java
+++ b/core/src/test/java/brooklyn/catalog/internal/CatalogScanTest.java
@@ -30,13 +30,13 @@ import org.apache.brooklyn.api.catalog.BrooklynCatalog;
 import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.entity.Application;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.core.management.internal.LocalManagementContext;
 
 import brooklyn.catalog.CatalogPredicates;
 import brooklyn.catalog.internal.MyCatalogItems.MySillyAppTemplate;
 import brooklyn.config.BrooklynProperties;
 import brooklyn.config.BrooklynServerConfig;
 import brooklyn.entity.basic.Entities;
-import brooklyn.management.internal.LocalManagementContext;
 import brooklyn.util.ResourceUtils;
 import brooklyn.util.net.Urls;
 import brooklyn.util.text.Strings;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6602f694/core/src/test/java/brooklyn/catalog/internal/CatalogVersioningTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/catalog/internal/CatalogVersioningTest.java b/core/src/test/java/brooklyn/catalog/internal/CatalogVersioningTest.java
index 53a0b9c..78c11ea 100644
--- a/core/src/test/java/brooklyn/catalog/internal/CatalogVersioningTest.java
+++ b/core/src/test/java/brooklyn/catalog/internal/CatalogVersioningTest.java
@@ -28,11 +28,11 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 import org.apache.brooklyn.api.catalog.BrooklynCatalog;
 import org.apache.brooklyn.api.catalog.CatalogItem;
+import org.apache.brooklyn.core.management.internal.LocalManagementContext;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 
 import brooklyn.catalog.CatalogPredicates;
 import brooklyn.entity.basic.Entities;
-import brooklyn.management.internal.LocalManagementContext;
 
 import com.google.common.base.Predicates;
 import com.google.common.collect.Iterables;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6602f694/core/src/test/java/brooklyn/entity/BrooklynAppLiveTestSupport.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/BrooklynAppLiveTestSupport.java b/core/src/test/java/brooklyn/entity/BrooklynAppLiveTestSupport.java
index 668a788..626a035 100644
--- a/core/src/test/java/brooklyn/entity/BrooklynAppLiveTestSupport.java
+++ b/core/src/test/java/brooklyn/entity/BrooklynAppLiveTestSupport.java
@@ -18,6 +18,7 @@
  */
 package brooklyn.entity;
 
+import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.slf4j.Logger;
@@ -28,7 +29,6 @@ import org.testng.annotations.BeforeMethod;
 import brooklyn.config.BrooklynProperties;
 import brooklyn.entity.basic.ApplicationBuilder;
 import brooklyn.entity.basic.Entities;
-import brooklyn.management.internal.ManagementContextInternal;
 
 /**
  * To be extended by live tests.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6602f694/core/src/test/java/brooklyn/entity/BrooklynAppUnitTestSupport.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/BrooklynAppUnitTestSupport.java b/core/src/test/java/brooklyn/entity/BrooklynAppUnitTestSupport.java
index 4e23de0..bb7beaf 100644
--- a/core/src/test/java/brooklyn/entity/BrooklynAppUnitTestSupport.java
+++ b/core/src/test/java/brooklyn/entity/BrooklynAppUnitTestSupport.java
@@ -19,6 +19,7 @@
 package brooklyn.entity;
 
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.slf4j.Logger;
@@ -29,7 +30,6 @@ import org.testng.annotations.BeforeMethod;
 import brooklyn.entity.basic.ApplicationBuilder;
 import brooklyn.entity.basic.BrooklynConfigKeys;
 import brooklyn.entity.basic.Entities;
-import brooklyn.management.internal.ManagementContextInternal;
 
 /**
  * To be extended by unit/integration tests.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6602f694/core/src/test/java/brooklyn/entity/EffectorMetadataTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/EffectorMetadataTest.java b/core/src/test/java/brooklyn/entity/EffectorMetadataTest.java
index 66daf0b..337cbfd 100644
--- a/core/src/test/java/brooklyn/entity/EffectorMetadataTest.java
+++ b/core/src/test/java/brooklyn/entity/EffectorMetadataTest.java
@@ -29,6 +29,7 @@ import org.apache.brooklyn.api.entity.ParameterType;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.management.internal.EffectorUtils;
 import org.testng.Assert;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
@@ -39,7 +40,6 @@ import brooklyn.entity.basic.BasicParameterType;
 import brooklyn.entity.basic.MethodEffector;
 import brooklyn.entity.effector.Effectors;
 import brooklyn.entity.trait.Startable;
-import brooklyn.management.internal.EffectorUtils;
 
 import com.google.common.collect.ImmutableList;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6602f694/core/src/test/java/brooklyn/entity/EffectorSayHiGroovyTest.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/EffectorSayHiGroovyTest.groovy b/core/src/test/java/brooklyn/entity/EffectorSayHiGroovyTest.groovy
index 5ce49a2..57362f2 100644
--- a/core/src/test/java/brooklyn/entity/EffectorSayHiGroovyTest.groovy
+++ b/core/src/test/java/brooklyn/entity/EffectorSayHiGroovyTest.groovy
@@ -42,7 +42,7 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.management.ManagementContext
 import org.apache.brooklyn.api.management.Task
 
-import brooklyn.management.internal.EffectorUtils
+import org.apache.brooklyn.core.management.internal.EffectorUtils
 
 import org.apache.brooklyn.test.entity.TestApplication
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6602f694/core/src/test/java/brooklyn/entity/EffectorSayHiTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/EffectorSayHiTest.java b/core/src/test/java/brooklyn/entity/EffectorSayHiTest.java
index 0505456..62579e3 100644
--- a/core/src/test/java/brooklyn/entity/EffectorSayHiTest.java
+++ b/core/src/test/java/brooklyn/entity/EffectorSayHiTest.java
@@ -33,6 +33,7 @@ import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.management.ExecutionContext;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.annotations.BeforeMethod;
@@ -43,7 +44,6 @@ import brooklyn.entity.basic.AbstractEntity;
 import brooklyn.entity.basic.BrooklynTaskTags;
 import brooklyn.entity.basic.MethodEffector;
 import brooklyn.entity.trait.Startable;
-import brooklyn.management.internal.ManagementContextInternal;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.task.BasicTask;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6602f694/core/src/test/java/brooklyn/entity/drivers/downloads/BasicDownloadsRegistryTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/drivers/downloads/BasicDownloadsRegistryTest.java b/core/src/test/java/brooklyn/entity/drivers/downloads/BasicDownloadsRegistryTest.java
index 64bfcd4..472b3d9 100644
--- a/core/src/test/java/brooklyn/entity/drivers/downloads/BasicDownloadsRegistryTest.java
+++ b/core/src/test/java/brooklyn/entity/drivers/downloads/BasicDownloadsRegistryTest.java
@@ -24,6 +24,7 @@ import static org.testng.Assert.fail;
 import org.apache.brooklyn.api.entity.drivers.downloads.DownloadResolver;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.management.internal.LocalManagementContext;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.apache.brooklyn.test.entity.TestEntity;
 import org.testng.annotations.AfterMethod;
@@ -38,8 +39,6 @@ import brooklyn.entity.basic.Entities;
 
 import org.apache.brooklyn.location.basic.SimulatedLocation;
 
-import brooklyn.management.internal.LocalManagementContext;
-
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6602f694/core/src/test/java/brooklyn/entity/drivers/downloads/DownloadProducerFromLocalRepoTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/drivers/downloads/DownloadProducerFromLocalRepoTest.java b/core/src/test/java/brooklyn/entity/drivers/downloads/DownloadProducerFromLocalRepoTest.java
index 2ed52e4..afda43a 100644
--- a/core/src/test/java/brooklyn/entity/drivers/downloads/DownloadProducerFromLocalRepoTest.java
+++ b/core/src/test/java/brooklyn/entity/drivers/downloads/DownloadProducerFromLocalRepoTest.java
@@ -26,6 +26,7 @@ import org.apache.brooklyn.api.entity.drivers.downloads.DownloadResolverManager.
 import org.apache.brooklyn.api.entity.drivers.downloads.DownloadResolverManager.DownloadTargets;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.management.internal.LocalManagementContext;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.apache.brooklyn.test.entity.TestEntity;
 import org.testng.annotations.AfterMethod;
@@ -39,8 +40,6 @@ import brooklyn.entity.basic.Entities;
 
 import org.apache.brooklyn.location.basic.SimulatedLocation;
 
-import brooklyn.management.internal.LocalManagementContext;
-
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;