brooklyn-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From grk...@apache.org
Subject [02/10] brooklyn-server git commit: Clocker pattern: change how LocationRegistry used
Date Tue, 22 Mar 2016 18:06:44 GMT
Clocker pattern: change how LocationRegistry used

Adds DynamicLocation.register() and .deregister()


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

Branch: refs/heads/master
Commit: 453183f1d89336ea793aab2edbe05c3b4070104b
Parents: 292b4cf
Author: Aled Sage <aled.sage@gmail.com>
Authored: Fri Mar 11 20:50:45 2016 +0000
Committer: Aled Sage <aled.sage@gmail.com>
Committed: Sat Mar 19 21:35:41 2016 +0000

----------------------------------------------------------------------
 .../core/location/dynamic/DynamicLocation.java  |  12 ++
 .../core/location/dynamic/LocationOwner.java    |   4 -
 ...ClockerDynamicLocationPatternRebindTest.java |  35 ++++-
 .../ClockerDynamicLocationPatternTest.java      |  22 ++-
 .../dynamic/clocker/StubContainerLocation.java  |  13 +-
 .../core/location/dynamic/clocker/StubHost.java |   4 +-
 .../location/dynamic/clocker/StubHostImpl.java  |  38 +++--
 .../dynamic/clocker/StubHostLocation.java       |  70 ++++++++-
 .../dynamic/clocker/StubInfrastructure.java     |   7 +-
 .../dynamic/clocker/StubInfrastructureImpl.java |  66 +++-----
 .../clocker/StubInfrastructureLocation.java     |  62 +++++++-
 .../location/dynamic/clocker/StubResolver.java  | 157 +++++++------------
 .../dynamic/clocker/StubResolverTest.java       |  82 ++++++++++
 13 files changed, 384 insertions(+), 188 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/453183f1/core/src/main/java/org/apache/brooklyn/core/location/dynamic/DynamicLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/location/dynamic/DynamicLocation.java b/core/src/main/java/org/apache/brooklyn/core/location/dynamic/DynamicLocation.java
index b04ebac..d961cdf 100644
--- a/core/src/main/java/org/apache/brooklyn/core/location/dynamic/DynamicLocation.java
+++ b/core/src/main/java/org/apache/brooklyn/core/location/dynamic/DynamicLocation.java
@@ -20,6 +20,8 @@ package org.apache.brooklyn.core.location.dynamic;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.location.LocationDefinition;
+import org.apache.brooklyn.api.location.LocationRegistry;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
@@ -47,4 +49,14 @@ public interface DynamicLocation<E extends Entity & LocationOwner<L, E>, L exten
 
     E getOwner();
 
+    /**
+     * An opportunity to register this location (e.g. with the {@link LocationRegistry} or the 
+     * catalog, so that it will be persisted).
+     */
+    LocationDefinition register();
+    
+    /**
+     * The complement of {@link #register()}, to deregister this location.
+     */
+    void deregister();
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/453183f1/core/src/main/java/org/apache/brooklyn/core/location/dynamic/LocationOwner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/location/dynamic/LocationOwner.java b/core/src/main/java/org/apache/brooklyn/core/location/dynamic/LocationOwner.java
index 718b97e..2c5a66c 100644
--- a/core/src/main/java/org/apache/brooklyn/core/location/dynamic/LocationOwner.java
+++ b/core/src/main/java/org/apache/brooklyn/core/location/dynamic/LocationOwner.java
@@ -22,7 +22,6 @@ import java.util.Map;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.api.location.LocationDefinition;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
@@ -71,9 +70,6 @@ public interface LocationOwner<L extends Location & DynamicLocation<E, L>, E ext
     AttributeSensor<Boolean> DYNAMIC_LOCATION_STATUS = Sensors.newBooleanSensor(
             "entity.dynamicLocation.status", "The status of the location owned by this entity");
 
-    AttributeSensor<LocationDefinition> LOCATION_DEFINITION = Sensors.newSensor(
-        LocationDefinition.class, "entity.dynamicLocation.definition", "The location definition for the location owned by this entity");
-
     L getDynamicLocation();
 
     L createLocation(Map<String, ?> flags);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/453183f1/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/ClockerDynamicLocationPatternRebindTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/ClockerDynamicLocationPatternRebindTest.java b/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/ClockerDynamicLocationPatternRebindTest.java
index 361ee95..6ccd86c 100644
--- a/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/ClockerDynamicLocationPatternRebindTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/ClockerDynamicLocationPatternRebindTest.java
@@ -29,6 +29,7 @@ import java.util.Map;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.BasicLocationRegistry;
 import org.apache.brooklyn.core.location.Locations;
@@ -41,6 +42,9 @@ import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 
+/**
+ * See explanation of what we're testing in {@link StubInfrastructure}.
+ */
 public class ClockerDynamicLocationPatternRebindTest extends RebindTestFixtureWithApp {
 
     @Override
@@ -59,9 +63,9 @@ public class ClockerDynamicLocationPatternRebindTest extends RebindTestFixtureWi
         return result;
     }
     
-    // To make this fail (with Clocker code as at 2016-03-11) requires several apps - there's a bug
-    // in rebind that only happens when there are several entities, so the order that they rebind
-    // is more interleaved.
+    // To make this fail previously (with Clocker code as at 2016-03-11) required several apps - 
+    // there was a bug in rebind that only happened when there were several entities, so the order 
+    // that they did the rebind was more interleaved.
     @Test
     public void testRebind() throws Exception {
         final int NUM_INFRAS = 10;
@@ -70,26 +74,45 @@ public class ClockerDynamicLocationPatternRebindTest extends RebindTestFixtureWi
         
         // Maps from the infrastructure locSpec to the (potentially many) host locSpecs
         Map<String, List<String>> locSpecs = Maps.newLinkedHashMap();
+        Map<String, List<String>> locNames = Maps.newLinkedHashMap();
         
         for (int i = 0; i < NUM_INFRAS; i++) {
+            String infraLocName = "myname"+i;
             StubInfrastructure infra = mgmt().getEntityManager().createEntity(EntitySpec.create(StubInfrastructure.class)
-                    .configure(StubInfrastructure.LOCATION_NAME, "myname"+i));
+                    .configure(StubInfrastructure.LOCATION_NAME, infraLocName)
+                    .configure(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION, true));
             infra.start(ImmutableList.of(loc));
             infra.getStubHostCluster().resize(HOST_CLUSTER_SIZE);
             assertEquals(infra.getStubHostCluster().getMembers().size(), HOST_CLUSTER_SIZE);
             
             String infraLocSpec = infra.sensors().get(StubInfrastructure.LOCATION_SPEC);
             List<String> hostLocSpecs = Lists.newArrayList();
+            List<String> hostLocNames = Lists.newArrayList();
             for (Entity host : infra.getStubHostCluster().getMembers()) {
-                hostLocSpecs.add(host.sensors().get(StubInfrastructure.LOCATION_SPEC));
+                hostLocSpecs.add(host.sensors().get(StubHost.LOCATION_SPEC));
+                hostLocNames.add(host.sensors().get(StubHost.LOCATION_NAME));
             }
     
             locSpecs.put(infraLocSpec, hostLocSpecs);
+            locNames.put(infraLocName, hostLocNames);
         }
         assertEquals(locSpecs.size(), NUM_INFRAS); // in case the infrastructures all used the same loc name!
+        assertEquals(locNames.size(), NUM_INFRAS); // in case the infrastructures all used the same loc name!
 
         rebind();
-
+        
+        for (Map.Entry<String, List<String>> entry : locNames.entrySet()) {
+            String infraLocName = entry.getKey();
+            List<String> hostLocName = entry.getValue();
+            
+            StubInfrastructureLocation newInfraLoc = (StubInfrastructureLocation) mgmt().getLocationRegistry().resolve(infraLocName);
+            assertNotNull(newInfraLoc);
+            for (String hostLocSpec: hostLocName) {
+                StubHostLocation newHostLoc = (StubHostLocation) mgmt().getLocationRegistry().resolve(hostLocSpec);
+                assertNotNull(newHostLoc);
+            }
+        }
+        
         for (Map.Entry<String, List<String>> entry : locSpecs.entrySet()) {
             String infraLocSpec = entry.getKey();
             List<String> hostLocSpecs = entry.getValue();

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/453183f1/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/ClockerDynamicLocationPatternTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/ClockerDynamicLocationPatternTest.java b/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/ClockerDynamicLocationPatternTest.java
index 618c552..b67b11c 100644
--- a/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/ClockerDynamicLocationPatternTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/ClockerDynamicLocationPatternTest.java
@@ -20,13 +20,16 @@ package org.apache.brooklyn.core.location.dynamic.clocker;
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertSame;
 
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.location.MachineLocation;
+import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.BasicLocationRegistry;
 import org.apache.brooklyn.core.location.Locations;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
@@ -35,6 +38,9 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 
+/**
+ * See explanation of what we're testing in {@link StubInfrastructure}.
+ */
 public class ClockerDynamicLocationPatternTest extends BrooklynAppUnitTestSupport {
 
     private LocalhostMachineProvisioningLocation loc;
@@ -51,7 +57,8 @@ public class ClockerDynamicLocationPatternTest extends BrooklynAppUnitTestSuppor
     
     @Test
     public void testCreateAndReleaseDirectly() throws Exception {
-        StubInfrastructure infra = mgmt.getEntityManager().createEntity(EntitySpec.create(StubInfrastructure.class));
+        StubInfrastructure infra = mgmt.getEntityManager().createEntity(EntitySpec.create(StubInfrastructure.class)
+                .configure(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION, shouldSkipOnBoxBaseDirResolution()));
         infra.start(ImmutableList.of(loc));
         
         StubInfrastructureLocation loc = infra.getDynamicLocation();
@@ -72,17 +79,24 @@ public class ClockerDynamicLocationPatternTest extends BrooklynAppUnitTestSuppor
     
     @Test
     public void testThroughLocationRegistry() throws Exception {
-        StubInfrastructure infra = mgmt.getEntityManager().createEntity(EntitySpec.create(StubInfrastructure.class));
+        StubInfrastructure infra = mgmt.getEntityManager().createEntity(EntitySpec.create(StubInfrastructure.class)
+                .configure(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION, shouldSkipOnBoxBaseDirResolution()));
         infra.start(ImmutableList.of(loc));
         
         String infraLocSpec = infra.sensors().get(StubInfrastructure.LOCATION_SPEC);
+        String infraLocName = infra.sensors().get(StubInfrastructure.LOCATION_NAME);
         StubInfrastructureLocation infraLoc = (StubInfrastructureLocation) mgmt.getLocationRegistry().resolve(infraLocSpec);
-
+        StubInfrastructureLocation infraLoc2 = (StubInfrastructureLocation) mgmt.getLocationRegistry().resolve(infraLocName);
+        assertSame(infraLoc, infraLoc2);
+        
         MachineLocation machine = infraLoc.obtain(ImmutableMap.of());
         
         StubHost host = (StubHost) Iterables.getOnlyElement(infra.getStubHostCluster().getMembers());
-        String hostLocSpec = host.sensors().get(StubInfrastructure.LOCATION_SPEC);
+        String hostLocSpec = host.sensors().get(StubHost.LOCATION_SPEC);
+        String hostLocName = host.sensors().get(StubHost.LOCATION_NAME);
         StubHostLocation hostLoc = (StubHostLocation) mgmt.getLocationRegistry().resolve(hostLocSpec);
+        StubHostLocation hostLoc2 = (StubHostLocation) mgmt.getLocationRegistry().resolve(hostLocName);
+        assertSame(hostLoc, hostLoc2);
 
         StubContainer container = (StubContainer) Iterables.getOnlyElement(host.getDockerContainerCluster().getMembers());
         StubContainerLocation containerLoc = container.getDynamicLocation();

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/453183f1/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubContainerLocation.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubContainerLocation.java b/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubContainerLocation.java
index f4b0345..570cd73 100644
--- a/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubContainerLocation.java
+++ b/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubContainerLocation.java
@@ -18,6 +18,7 @@
  */
 package org.apache.brooklyn.core.location.dynamic.clocker;
 
+import org.apache.brooklyn.api.location.LocationDefinition;
 import org.apache.brooklyn.core.location.dynamic.DynamicLocation;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
@@ -38,4 +39,14 @@ public class StubContainerLocation extends SshMachineLocation implements Dynamic
     public SshMachineLocation getMachine() {
         return machine;
     }
-}
\ No newline at end of file
+
+    @Override
+    public LocationDefinition register() {
+        throw new UnsupportedOperationException("Container location type definition cannot be persisted");
+    }
+
+    @Override
+    public void deregister() {
+        // no-op
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/453183f1/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubHost.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubHost.java b/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubHost.java
index e5b4005..6b2d319 100644
--- a/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubHost.java
+++ b/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubHost.java
@@ -24,10 +24,10 @@ import org.apache.brooklyn.core.location.dynamic.LocationOwner;
 import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
 import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.group.DynamicCluster;
-import org.apache.brooklyn.entity.machine.MachineEntity;
+import org.apache.brooklyn.entity.software.base.EmptySoftwareProcess;
 
 @ImplementedBy(StubHostImpl.class)
-public interface StubHost extends MachineEntity, LocationOwner<StubHostLocation, StubHost> {
+public interface StubHost extends EmptySoftwareProcess, LocationOwner<StubHostLocation, StubHost> {
     AttributeSensorAndConfigKey<StubInfrastructure, StubInfrastructure> DOCKER_INFRASTRUCTURE = StubAttributes.DOCKER_INFRASTRUCTURE;
     
     AttributeSensor<DynamicCluster> DOCKER_CONTAINER_CLUSTER = Sensors.newSensor(DynamicCluster.class,

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/453183f1/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubHostImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubHostImpl.java b/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubHostImpl.java
index 4c2ad36..3139d93 100644
--- a/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubHostImpl.java
+++ b/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubHostImpl.java
@@ -21,23 +21,20 @@ package org.apache.brooklyn.core.location.dynamic.clocker;
 import java.util.Map;
 
 import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.location.LocationDefinition;
+import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.core.feed.ConfigToAttributes;
-import org.apache.brooklyn.core.location.BasicLocationDefinition;
 import org.apache.brooklyn.core.location.Locations;
 import org.apache.brooklyn.core.location.Machines;
 import org.apache.brooklyn.entity.group.Cluster;
 import org.apache.brooklyn.entity.group.DynamicCluster;
-import org.apache.brooklyn.entity.machine.MachineEntityImpl;
+import org.apache.brooklyn.entity.software.base.EmptySoftwareProcessImpl;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.QuorumCheck.QuorumChecks;
-import org.apache.brooklyn.util.guava.Maybe;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class StubHostImpl extends MachineEntityImpl implements StubHost {
+public class StubHostImpl extends EmptySoftwareProcessImpl implements StubHost {
     
     private static final Logger LOG = LoggerFactory.getLogger(StubHostImpl.class);
 
@@ -81,14 +78,7 @@ public class StubHostImpl extends MachineEntityImpl implements StubHost {
         super.preStart();
         ConfigToAttributes.apply(this);
         
-        Maybe<SshMachineLocation> found = Machines.findUniqueMachineLocation(getLocations(), SshMachineLocation.class);
-
-        Map<String, ?> flags = MutableMap.<String, Object>builder()
-                .putAll(config().get(LOCATION_FLAGS))
-                .put("machine", found.get())
-                .build();
-
-        createLocation(flags);
+        createLocation(config().get(LOCATION_FLAGS));
         sensors().get(DOCKER_CONTAINER_CLUSTER).sensors().set(SERVICE_UP, Boolean.TRUE);
     }
 
@@ -96,18 +86,25 @@ public class StubHostImpl extends MachineEntityImpl implements StubHost {
     public StubHostLocation createLocation(Map<String, ?> flags) {
         StubInfrastructure infrastructure = getInfrastructure();
         StubInfrastructureLocation docker = infrastructure.getDynamicLocation();
+        SshMachineLocation machine = Machines.findUniqueMachineLocation(getLocations(), SshMachineLocation.class).get();
         String locationName = docker.getId() + "-" + getId();
 
-        String locationSpec = String.format(StubResolver.DOCKER_HOST_MACHINE_SPEC, infrastructure.getId(), getId()) + String.format(":(name=\"%s\")", locationName);
-        sensors().set(LOCATION_SPEC, locationSpec);
+        StubHostLocation location = getManagementContext().getLocationManager().createLocation(LocationSpec.create(StubHostLocation.class)
+                .parent(infrastructure.getDynamicLocation())
+                .displayName("Docker Host("+getId()+")")
+                .configure(flags)
+                .configure("owner", getProxy())
+                .configure("machine", machine)
+                .configure("locationName", locationName));
+        
+        LocationDefinition definition = location.register();
 
-        LocationDefinition definition = new BasicLocationDefinition(locationName, locationSpec, flags);
-        Location location = getManagementContext().getLocationRegistry().resolve(definition);
+        sensors().set(LOCATION_SPEC, definition.getSpec());
+        sensors().set(LOCATION_NAME, locationName);
         sensors().set(DYNAMIC_LOCATION, location);
-        sensors().set(LOCATION_NAME, location.getId());
 
         LOG.info("New Docker host location {} created", location);
-        return (StubHostLocation) location;
+        return location;
     }
 
     @Override
@@ -119,6 +116,7 @@ public class StubHostImpl extends MachineEntityImpl implements StubHost {
     public void deleteLocation() {
         StubHostLocation loc = (StubHostLocation) sensors().get(DYNAMIC_LOCATION);
         if (loc != null) {
+            loc.deregister();
             Locations.unmanage(loc);
         }
         sensors().set(DYNAMIC_LOCATION, null);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/453183f1/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubHostLocation.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubHostLocation.java b/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubHostLocation.java
index a861220..9c76848 100644
--- a/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubHostLocation.java
+++ b/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubHostLocation.java
@@ -18,16 +18,22 @@
  */
 package org.apache.brooklyn.core.location.dynamic.clocker;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 import java.util.Collection;
 import java.util.Map;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.location.LocationDefinition;
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
 import org.apache.brooklyn.api.location.NoMachinesAvailableException;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.location.AbstractLocation;
+import org.apache.brooklyn.core.location.BasicLocationDefinition;
 import org.apache.brooklyn.core.location.LocationConfigKeys;
 import org.apache.brooklyn.core.location.Locations;
 import org.apache.brooklyn.core.location.dynamic.DynamicLocation;
@@ -46,12 +52,68 @@ public class StubHostLocation extends AbstractLocation implements MachineProvisi
 
     private static final Logger LOG = LoggerFactory.getLogger(StubHostLocation.class);
 
-    @SetFromFlag("machine")
-    private SshMachineLocation machine;
+    public static final ConfigKey<String> LOCATION_NAME = ConfigKeys.newStringConfigKey("locationName");
+
+    public static final ConfigKey<SshMachineLocation> MACHINE = ConfigKeys.newConfigKey(
+            SshMachineLocation.class, 
+            "machine");
+
+    @SetFromFlag("locationRegistrationId")
+    private String locationRegistrationId;
 
-    @SetFromFlag("owner")
-    private StubHost dockerHost;
+    private transient StubHost dockerHost;
+    private transient SshMachineLocation machine;
+    
+    @Override
+    public void init() {
+        super.init();
+        dockerHost = (StubHost) checkNotNull(getConfig(OWNER), "owner");
+        machine = (SshMachineLocation) checkNotNull(getConfig(MACHINE), "machine");
+    }
+    
+    @Override
+    public void rebind() {
+        super.rebind();
 
+        dockerHost = (StubHost) getConfig(OWNER);
+        machine = (SshMachineLocation) getConfig(MACHINE);
+        
+        if (getConfig(LOCATION_NAME) != null) {
+            register();
+        }
+    }
+
+    @Override
+    public LocationDefinition register() {
+        String locationName = checkNotNull(getConfig(LOCATION_NAME), "config %s", LOCATION_NAME.getName());
+
+        LocationDefinition check = getManagementContext().getLocationRegistry().getDefinedLocationByName(locationName);
+        if (check != null) {
+            throw new IllegalStateException("Location " + locationName + " is already defined: " + check);
+        }
+
+        String hostLocId = getId();
+        String infraLocId = (getParent() != null) ? getParent().getId() : "";
+        String locationSpec = String.format(StubResolver.DOCKER_HOST_MACHINE_SPEC, infraLocId, hostLocId) + String.format(":(name=\"%s\")", locationName);
+
+        LocationDefinition definition = new BasicLocationDefinition(locationName, locationSpec, ImmutableMap.<String, Object>of());
+        getManagementContext().getLocationRegistry().updateDefinedLocation(definition);
+        
+        locationRegistrationId = definition.getId();
+        requestPersist();
+        
+        return definition;
+    }
+    
+    @Override
+    public void deregister() {
+        if (locationRegistrationId != null) {
+            getManagementContext().getLocationRegistry().removeDefinedLocation(locationRegistrationId);
+            locationRegistrationId = null;
+            requestPersist();
+        }
+    }
+    
     @Override
     public StubHost getOwner() {
         return (StubHost) getConfig(OWNER);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/453183f1/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubInfrastructure.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubInfrastructure.java b/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubInfrastructure.java
index 3170cf2..f6a9afd 100644
--- a/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubInfrastructure.java
+++ b/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubInfrastructure.java
@@ -29,6 +29,8 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.location.dynamic.LocationOwner;
+import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.group.DynamicCluster;
 import org.apache.brooklyn.entity.group.DynamicGroup;
@@ -81,8 +83,9 @@ import org.apache.brooklyn.entity.group.DynamicMultiGroup;
  */
 @ImplementedBy(StubInfrastructureImpl.class)
 public interface StubInfrastructure extends Application, Startable, LocationOwner<StubInfrastructureLocation, StubInfrastructure> {
-    ConfigKey<String> LOCATION_NAME = ConfigKeys.newConfigKeyWithDefault(LocationOwner.LOCATION_NAME.getConfigKey(), "my-stub-cloud");
-    
+    AttributeSensorAndConfigKey<String, String> LOCATION_NAME = ConfigKeys.newSensorAndConfigKeyWithDefault(LocationOwner.LOCATION_NAME, "my-stub-cloud");
+    ConfigKey<Integer> DOCKER_HOST_CLUSTER_MIN_SIZE = ConfigKeys.newConfigKeyWithPrefix("docker.host.", DynamicCluster.INITIAL_SIZE);
+
     AttributeSensor<DynamicCluster> DOCKER_HOST_CLUSTER = Sensors.newSensor(DynamicCluster.class, "docker.hosts", "Docker host cluster");
     AttributeSensor<DynamicGroup> DOCKER_CONTAINER_FABRIC = Sensors.newSensor(DynamicGroup.class, "docker.fabric", "Docker container fabric");
     AttributeSensor<DynamicMultiGroup> DOCKER_APPLICATIONS = Sensors.newSensor(DynamicMultiGroup.class, "docker.buckets", "Docker applications");

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/453183f1/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubInfrastructureImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubInfrastructureImpl.java b/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubInfrastructureImpl.java
index 0d807fa..0f578bc 100644
--- a/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubInfrastructureImpl.java
+++ b/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubInfrastructureImpl.java
@@ -30,15 +30,13 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.location.LocationDefinition;
-import org.apache.brooklyn.api.mgmt.LocationManager;
-import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.core.entity.AbstractApplication;
-import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityPredicates;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.feed.ConfigToAttributes;
-import org.apache.brooklyn.core.location.BasicLocationDefinition;
+import org.apache.brooklyn.core.location.Locations;
 import org.apache.brooklyn.core.location.dynamic.LocationOwner;
 import org.apache.brooklyn.entity.group.BasicGroup;
 import org.apache.brooklyn.entity.group.Cluster;
@@ -48,11 +46,13 @@ import org.apache.brooklyn.entity.group.DynamicMultiGroup;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.QuorumCheck.QuorumChecks;
+import org.apache.brooklyn.util.text.Strings;
 import org.apache.brooklyn.util.time.Duration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Function;
+import com.google.common.base.Joiner;
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
@@ -73,7 +73,7 @@ public class StubInfrastructureImpl extends AbstractApplication implements StubI
                 .configure(SoftwareProcess.CHILDREN_STARTABLE_MODE, SoftwareProcess.ChildStartableMode.BACKGROUND_LATE);
 
         DynamicCluster hosts = addChild(EntitySpec.create(DynamicCluster.class)
-                .configure(Cluster.INITIAL_SIZE, 1)
+                .configure(Cluster.INITIAL_SIZE, config().get(DOCKER_HOST_CLUSTER_MIN_SIZE))
                 .configure(DynamicCluster.QUARANTINE_FAILED_ENTITIES, true)
                 .configure(DynamicCluster.MEMBER_SPEC, dockerHostSpec)
                 .configure(DynamicCluster.RUNNING_QUORUM_CHECK, QuorumChecks.atLeastOneUnlessEmpty())
@@ -104,17 +104,6 @@ public class StubInfrastructureImpl extends AbstractApplication implements StubI
     }
     
     @Override
-    public void rebind() {
-        super.rebind();
-
-        // Reload our location definition on rebind
-        ManagementContext.PropertiesReloadListener listener = sensors().get(Attributes.PROPERTIES_RELOAD_LISTENER);
-        if (listener != null) {
-            listener.reloaded();
-        }
-    }
-
-    @Override
     public StubInfrastructureLocation getDynamicLocation() {
         return (StubInfrastructureLocation) sensors().get(DYNAMIC_LOCATION);
     }
@@ -178,27 +167,25 @@ public class StubInfrastructureImpl extends AbstractApplication implements StubI
     @Override
     public StubInfrastructureLocation createLocation(Map<String, ?> flags) {
         String locationName = config().get(LOCATION_NAME);
-
-        LocationDefinition check = getManagementContext().getLocationRegistry().getDefinedLocationByName(locationName);
-        if (check != null) {
-            throw new IllegalStateException("Location " + locationName + " is already defined: " + check);
+        if (Strings.isBlank(locationName)) {
+            String prefix = config().get(LOCATION_NAME_PREFIX);
+            String suffix = config().get(LOCATION_NAME_SUFFIX);
+            locationName = Joiner.on("-").skipNulls().join(prefix, getId(), suffix);
         }
 
-        String locationSpec = String.format(StubResolver.DOCKER_INFRASTRUCTURE_SPEC, getId()) + String.format(":(name=\"%s\")", locationName);
-        sensors().set(LOCATION_SPEC, locationSpec);
-        LocationDefinition definition = new BasicLocationDefinition(locationName, locationSpec, flags);
-        Location location = getManagementContext().getLocationRegistry().resolve(definition);
-        getManagementContext().getLocationRegistry().updateDefinedLocation(definition);
-
-        ManagementContext.PropertiesReloadListener listener = StubUtils.reloadLocationListener(getManagementContext(), definition);
-        getManagementContext().addPropertiesReloadListener(listener);
-        sensors().set(Attributes.PROPERTIES_RELOAD_LISTENER, listener);
+        StubInfrastructureLocation location = getManagementContext().getLocationManager().createLocation(LocationSpec.create(StubInfrastructureLocation.class)
+                .displayName("Docker Infrastructure("+getId()+")")
+                .configure(flags)
+                .configure("owner", getProxy())
+                .configure("locationName", locationName));
+        
+        LocationDefinition definition = location.register();
 
-        sensors().set(LocationOwner.LOCATION_DEFINITION, definition);
+        sensors().set(LocationOwner.LOCATION_SPEC, definition.getSpec());
         sensors().set(LocationOwner.DYNAMIC_LOCATION, location);
-        sensors().set(LocationOwner.LOCATION_NAME, location.getId());
+        sensors().set(LocationOwner.LOCATION_NAME, locationName);
         
-        return (StubInfrastructureLocation) location;
+        return location;
     }
 
     @Override
@@ -211,21 +198,10 @@ public class StubInfrastructureImpl extends AbstractApplication implements StubI
         StubInfrastructureLocation location = getDynamicLocation();
 
         if (location != null) {
-            LocationManager mgr = getManagementContext().getLocationManager();
-            if (mgr.isManaged(location)) {
-                mgr.unmanage(location);
-            }
-            final LocationDefinition definition = sensors().get(LocationOwner.LOCATION_DEFINITION);
-            if (definition != null) {
-                getManagementContext().getLocationRegistry().removeDefinedLocation(definition.getId());
-            }
-        }
-        ManagementContext.PropertiesReloadListener listener = sensors().get(Attributes.PROPERTIES_RELOAD_LISTENER);
-        if (listener != null) {
-            getManagementContext().removePropertiesReloadListener(listener);
+            location.deregister();
+            Locations.unmanage(location);
         }
 
-        sensors().set(LocationOwner.LOCATION_DEFINITION, null);
         sensors().set(LocationOwner.DYNAMIC_LOCATION, null);
         sensors().set(LocationOwner.LOCATION_NAME, null);
     }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/453183f1/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubInfrastructureLocation.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubInfrastructureLocation.java b/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubInfrastructureLocation.java
index 05587f1..5d5695c 100644
--- a/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubInfrastructureLocation.java
+++ b/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubInfrastructureLocation.java
@@ -18,14 +18,20 @@
  */
 package org.apache.brooklyn.core.location.dynamic.clocker;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 import java.util.Collection;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.brooklyn.api.location.LocationDefinition;
 import org.apache.brooklyn.api.location.MachineLocation;
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
 import org.apache.brooklyn.api.location.NoMachinesAvailableException;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.location.AbstractLocation;
+import org.apache.brooklyn.core.location.BasicLocationDefinition;
 import org.apache.brooklyn.core.location.dynamic.DynamicLocation;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.slf4j.Logger;
@@ -43,15 +49,65 @@ public class StubInfrastructureLocation extends AbstractLocation implements Mach
     @SuppressWarnings("unused")
     private static final Logger LOG = LoggerFactory.getLogger(StubInfrastructureLocation.class);
 
-    @SetFromFlag("owner")
-    private StubInfrastructure infrastructure;
+    public static final ConfigKey<String> LOCATION_NAME = ConfigKeys.newStringConfigKey("locationName");
+
+    @SetFromFlag("locationRegistrationId")
+    private String locationRegistrationId;
 
     @SetFromFlag("machines")
     private final SetMultimap<StubHostLocation, String> containers = Multimaps.synchronizedSetMultimap(HashMultimap.<StubHostLocation, String>create());
 
+    private transient StubInfrastructure infrastructure;
+
+    @Override
+    public void init() {
+        super.init();
+        infrastructure = (StubInfrastructure) checkNotNull(getConfig(OWNER), "owner");
+    }
+    
+    @Override
+    public void rebind() {
+        super.rebind();
+
+        infrastructure = (StubInfrastructure) getConfig(OWNER);
+        
+        if (getConfig(LOCATION_NAME) != null) {
+            register();
+        }
+    }
+
+    @Override
+    public LocationDefinition register() {
+        String locationName = checkNotNull(getConfig(LOCATION_NAME), "config %s", LOCATION_NAME.getName());
+
+        LocationDefinition check = getManagementContext().getLocationRegistry().getDefinedLocationByName(locationName);
+        if (check != null) {
+            throw new IllegalStateException("Location " + locationName + " is already defined: " + check);
+        }
+
+        String locationSpec = String.format(StubResolver.DOCKER_INFRASTRUCTURE_SPEC, getId()) + String.format(":(name=\"%s\")", locationName);
+
+        LocationDefinition definition = new BasicLocationDefinition(locationName, locationSpec, ImmutableMap.<String, Object>of());
+        getManagementContext().getLocationRegistry().updateDefinedLocation(definition);
+        
+        locationRegistrationId = definition.getId();
+        requestPersist();
+        
+        return definition;
+    }
+    
+    @Override
+    public void deregister() {
+        if (locationRegistrationId != null) {
+            getManagementContext().getLocationRegistry().removeDefinedLocation(locationRegistrationId);
+            locationRegistrationId = null;
+            requestPersist();
+        }
+    }
+    
     @Override
     public StubInfrastructure getOwner() {
-        return infrastructure;
+        return (StubInfrastructure) getConfig(OWNER);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/453183f1/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubResolver.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubResolver.java b/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubResolver.java
index 99fd2b1..8aaf4a8 100644
--- a/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubResolver.java
+++ b/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubResolver.java
@@ -26,21 +26,23 @@ import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.location.LocationRegistry;
-import org.apache.brooklyn.api.location.LocationResolver.EnableableLocationResolver;
+import org.apache.brooklyn.api.location.LocationResolver;
 import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.location.BasicLocationRegistry;
-import org.apache.brooklyn.core.location.LocationPropertiesFromBrooklynProperties;
-import org.apache.brooklyn.core.location.dynamic.DynamicLocation;
-import org.apache.brooklyn.core.location.internal.LocationInternal;
-import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.core.objs.proxy.SpecialBrooklynObjectConstructor;
+import org.apache.brooklyn.core.objs.proxy.SpecialBrooklynObjectConstructor.Config;
 import org.apache.brooklyn.util.text.KeyValueParser;
 import org.apache.brooklyn.util.text.Strings;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.annotations.Beta;
 import com.google.common.base.Joiner;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
@@ -54,17 +56,17 @@ import com.google.common.collect.Sets;
  *     <li>docker:infrastructureId:dockerHostId:(name=dockerHost-brooklyn-1234,user=docker)
  *   </ul>
  */
-public class StubResolver implements EnableableLocationResolver {
+public class StubResolver implements LocationResolver {
 
     private static final Logger LOG = LoggerFactory.getLogger(StubResolver.class);
 
-    public static final String DOCKER = "docker";
+    public static final String DOCKER = "stub";
     public static final Pattern PATTERN = Pattern.compile("("+DOCKER+"|"+DOCKER.toUpperCase()+")" + ":([a-zA-Z0-9]+)" +
             "(:([a-zA-Z0-9]+))?" + "(:\\((.*)\\))?$");
-    public static final Set<String> ACCEPTABLE_ARGS = ImmutableSet.of("name", "displayName");
+    public static final String DOCKER_INFRASTRUCTURE_SPEC = "stub:%s";
+    public static final String DOCKER_HOST_MACHINE_SPEC = "stub:%s:%s";
 
-    public static final String DOCKER_INFRASTRUCTURE_SPEC = "docker:%s";
-    public static final String DOCKER_HOST_MACHINE_SPEC = "docker:%s:%s";
+    private static final Set<String> ACCEPTABLE_ARGS = ImmutableSet.of("name");
 
     private ManagementContext managementContext;
 
@@ -79,118 +81,79 @@ public class StubResolver implements EnableableLocationResolver {
     }
 
     @Override
-    public Location newLocationFromString(Map locationFlags, String spec, LocationRegistry registry) {
-        return newLocationFromString(spec, registry, registry.getProperties(), locationFlags);
+    public boolean accepts(String spec, LocationRegistry registry) {
+        return BasicLocationRegistry.isResolverPrefixForSpec(this, spec, true);
     }
 
-    protected Location newLocationFromString(String spec, LocationRegistry registry, Map properties, Map locationFlags) {
+    @Override
+    public boolean isEnabled() {
+        // TODO Should we base enablement on whether the required location/entity exists?
+        return true;
+    }
+
+    @Override
+    public LocationSpec<? extends Location> newLocationSpecFromString(String spec, Map<?,?> locationFlags, LocationRegistry registry) {
+        Map<?,?> properties = registry.getProperties();
+
         if (LOG.isDebugEnabled()) {
             LOG.debug("Resolving location '" + spec + "' with flags " + Joiner.on(",").withKeyValueSeparator("=").join(locationFlags));
         }
-        String namedLocation = (String) locationFlags.get(LocationInternal.NAMED_SPEC_NAME.getName());
 
         Matcher matcher = PATTERN.matcher(spec);
         if (!matcher.matches()) {
-            throw new IllegalArgumentException("Invalid location '"+spec+"'; must specify something like docker:entityId or docker:entityId:(name=abc)");
+            throw new IllegalArgumentException("Invalid location '"+spec+"'; must specify something like stub:entityId or stub:entityId:(name=abc)");
         }
 
+        String infrastructureLocId = matcher.group(2);
+        if (Strings.isBlank(infrastructureLocId)) {
+            throw new IllegalArgumentException("Invalid location '"+spec+"'; infrastructure location id must be non-empty");
+        }
+        String hostLocId = matcher.group(4);
+
+        // TODO Could validate that the namePart matches the existing loc
         String argsPart = matcher.group(6);
         Map<String, String> argsMap = (argsPart != null) ? KeyValueParser.parseMap(argsPart) : Collections.<String,String>emptyMap();
-        String displayNamePart = argsMap.get("displayName");
+        @SuppressWarnings("unused")
         String namePart = argsMap.get("name");
 
         if (!ACCEPTABLE_ARGS.containsAll(argsMap.keySet())) {
             Set<String> illegalArgs = Sets.difference(argsMap.keySet(), ACCEPTABLE_ARGS);
             throw new IllegalArgumentException("Invalid location '"+spec+"'; illegal args "+illegalArgs+"; acceptable args are "+ACCEPTABLE_ARGS);
         }
-        if (argsMap.containsKey("displayName") && Strings.isEmpty(displayNamePart)) {
-            throw new IllegalArgumentException("Invalid location '"+spec+"'; if displayName supplied then value must be non-empty");
-        }
-        if (argsMap.containsKey("name") && Strings.isEmpty(namePart)) {
-            throw new IllegalArgumentException("Invalid location '"+spec+"'; if name supplied then value must be non-empty");
-        }
 
-        Map<String, Object> filteredProperties = new LocationPropertiesFromBrooklynProperties().getLocationProperties(DOCKER, namedLocation, properties);
-        MutableMap<String, Object> flags = MutableMap.<String, Object>builder().putAll(filteredProperties).putAll(locationFlags).build();
-
-        String infrastructureId = matcher.group(2);
-        if (Strings.isBlank(infrastructureId)) {
-            throw new IllegalArgumentException("Invalid location '"+spec+"'; infrastructure entity id must be non-empty");
+        Location infrastructureLoc = managementContext.getLocationManager().getLocation(infrastructureLocId);
+        if (infrastructureLoc == null) {
+            throw new IllegalArgumentException("Unknown Clocker infrastructure location id "+infrastructureLocId+", spec "+spec);
+        } else if (!(infrastructureLoc instanceof StubInfrastructureLocation)) {
+            throw new IllegalArgumentException("Invalid location id for Clocker infrastructure, spec "+spec+"; instead matches "+infrastructureLoc);
         }
-        String dockerHostId = matcher.group(4);
 
-        // Build the display name
-        StringBuilder name = new StringBuilder();
-        if (displayNamePart != null) {
-            name.append(displayNamePart);
-        } else {
-            name.append("Docker ");
-            if (dockerHostId == null) {
-                name.append("Infrastructure ").append(infrastructureId);
-            } else {
-                name.append("Host ").append(dockerHostId);
+        if (hostLocId != null) {
+            Location hostLoc = managementContext.getLocationManager().getLocation(hostLocId);
+            if (hostLoc == null) {
+                throw new IllegalArgumentException("Unknown Clocker host location id "+hostLocId+", spec "+spec);
+            } else if (!(hostLoc instanceof StubHostLocation)) {
+                throw new IllegalArgumentException("Invalid location id for Clocker host, spec "+spec+"; instead matches "+hostLoc);
             }
-        }
-        final String displayName =  name.toString();
-
-        // Build the location name
-        name = new StringBuilder();
-        if (namePart != null) {
-            name.append(namePart);
+            
+            return LocationSpec.create(StubHostLocation.class)
+                    .configure(StubLocationConstructor.LOCATION, hostLoc)
+                    .configure(Config.SPECIAL_CONSTRUCTOR, StubLocationConstructor.class);
         } else {
-            name.append("docker-");
-            name.append(infrastructureId);
-            if (dockerHostId != null) {
-                name.append("-").append(dockerHostId);
-            }
-        }
-        final String locationName =  name.toString();
-        StubInfrastructure infrastructure = (StubInfrastructure) managementContext.getEntityManager().getEntity(infrastructureId);
-        Iterable<Location> managedLocations = managementContext.getLocationManager().getLocations();
-
-        if (dockerHostId == null) {
-            for (Location location : managedLocations) {
-                if (location instanceof StubInfrastructureLocation) {
-                    if (((StubInfrastructureLocation) location).getOwner().getId().equals(infrastructureId)) {
-                        return location;
-                    }
-                }
-            }
-            LocationSpec<StubInfrastructureLocation> locationSpec = LocationSpec.create(StubInfrastructureLocation.class)
-                    .configure(flags)
-                    .configure(DynamicLocation.OWNER, infrastructure)
-                    .configure(LocationInternal.NAMED_SPEC_NAME, locationName)
-                    .displayName(displayName);
-            return managementContext.getLocationManager().createLocation(locationSpec);
-        } else {
-            StubHost dockerHost = (StubHost) managementContext.getEntityManager().getEntity(dockerHostId);
-            for (Location location : managedLocations) {
-                if (location instanceof StubHostLocation) {
-                    if (((StubHostLocation) location).getOwner().getId().equals(dockerHostId)) {
-                        return location;
-                    }
-                }
-            }
-
-            LocationSpec<StubHostLocation> locationSpec = LocationSpec.create(StubHostLocation.class)
-                    .parent(infrastructure.getDynamicLocation())
-                    .configure(flags)
-                    .configure(DynamicLocation.OWNER, dockerHost)
-                    .configure(LocationInternal.NAMED_SPEC_NAME, locationName)
-                    .displayName(displayName);
-            return managementContext.getLocationManager().createLocation(locationSpec);
+            return LocationSpec.create(StubInfrastructureLocation.class)
+                    .configure(StubLocationConstructor.LOCATION, infrastructureLoc)
+                    .configure(Config.SPECIAL_CONSTRUCTOR, StubLocationConstructor.class);
         }
     }
 
-    @Override
-    public boolean accepts(String spec, LocationRegistry registry) {
-        return BasicLocationRegistry.isResolverPrefixForSpec(this, spec, true);
-    }
-
-    @Override
-    public boolean isEnabled() {
-        return true;
-//        return Iterables.tryFind(managementContext.getEntityManager().getEntities(), Predicates.instanceOf(StubInfrastructure.class)).isPresent();
+    @Beta
+    public static class StubLocationConstructor implements SpecialBrooklynObjectConstructor {
+        public static ConfigKey<Location> LOCATION = ConfigKeys.newConfigKey(Location.class, "stubresolver.location");
+        
+        @SuppressWarnings("unchecked")
+        @Override
+        public <T> T create(ManagementContext mgmt, Class<T> type, AbstractBrooklynObjectSpec<?, ?> spec) {
+            return (T) checkNotNull(spec.getConfig().get(LOCATION), LOCATION.getName());
+        }
     }
-
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/453183f1/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubResolverTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubResolverTest.java b/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubResolverTest.java
new file mode 100644
index 0000000..6ffb387
--- /dev/null
+++ b/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/StubResolverTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.location.dynamic.clocker;
+
+import static org.testng.Assert.assertEquals;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.location.LocationSpec;
+import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
+import org.apache.brooklyn.core.location.BasicLocationRegistry;
+import org.apache.brooklyn.core.location.dynamic.LocationOwner;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+
+public class StubResolverTest extends BrooklynAppUnitTestSupport {
+
+    private StubInfrastructure infrastructure;
+    private Location localhostLoc;
+
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        
+        StubResolver stubResolver = new StubResolver();
+        ((BasicLocationRegistry)mgmt.getLocationRegistry()).registerResolver(stubResolver);
+
+        infrastructure = app.createAndManageChild(EntitySpec.create(StubInfrastructure.class)
+                .configure(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION, shouldSkipOnBoxBaseDirResolution())
+                .configure(StubInfrastructure.DOCKER_HOST_CLUSTER_MIN_SIZE, 1));
+        localhostLoc = mgmt.getLocationManager()
+                .createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class));
+        app.start(ImmutableList.of(localhostLoc));
+    }
+
+    @Test
+    public void testResolveInfrastructure() {
+        String spec = "stub:" + infrastructure.getDynamicLocation().getId();
+        StubInfrastructureLocation loc = (StubInfrastructureLocation) mgmt.getLocationRegistry().resolve(spec);
+        assertEquals(loc, infrastructure.getDynamicLocation());
+        
+        String spec2 = infrastructure.sensors().get(LocationOwner.LOCATION_SPEC);
+        StubInfrastructureLocation loc2 = (StubInfrastructureLocation) mgmt.getLocationRegistry().resolve(spec2);
+        assertEquals(loc2, infrastructure.getDynamicLocation());
+    }
+
+    @Test
+    public void testResolveHost() {
+        StubHost host = (StubHost) Iterables.getOnlyElement(infrastructure.getStubHostCluster().getMembers());
+        
+        String spec = "stub:" + infrastructure.getDynamicLocation().getId() + ":" + host.getDynamicLocation().getId();
+        StubHostLocation loc = (StubHostLocation) mgmt.getLocationRegistry().resolve(spec);
+        assertEquals(loc, host.getDynamicLocation());
+        
+        
+        String spec2 = host.sensors().get(LocationOwner.LOCATION_SPEC);
+        StubHostLocation loc2 = (StubHostLocation) mgmt.getLocationRegistry().resolve(spec2);
+        assertEquals(loc2, host.getDynamicLocation());
+    }
+}


Mime
View raw message