You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2014/08/06 23:16:53 UTC

[01/11] git commit: extract an AbstractBrooklynObjectSpec to combine common spec code

Repository: incubator-brooklyn
Updated Branches:
  refs/heads/master bf627f76a -> 4891355f7


extract an AbstractBrooklynObjectSpec to combine common spec code


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

Branch: refs/heads/master
Commit: 98a37f07a17ae307ecc4f362f47a19cc4119af2e
Parents: 7d2d42b
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Aug 1 15:27:09 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Aug 5 10:40:30 2014 -0400

----------------------------------------------------------------------
 .../basic/AbstractBrooklynObjectSpec.java       | 92 ++++++++++++++++++++
 .../brooklyn/entity/proxying/EntitySpec.java    | 61 ++-----------
 .../java/brooklyn/location/LocationSpec.java    | 63 ++------------
 .../main/java/brooklyn/policy/EnricherSpec.java | 60 ++-----------
 .../main/java/brooklyn/policy/PolicySpec.java   | 60 ++-----------
 5 files changed, 122 insertions(+), 214 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/98a37f07/api/src/main/java/brooklyn/basic/AbstractBrooklynObjectSpec.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/basic/AbstractBrooklynObjectSpec.java b/api/src/main/java/brooklyn/basic/AbstractBrooklynObjectSpec.java
new file mode 100644
index 0000000..d61e016
--- /dev/null
+++ b/api/src/main/java/brooklyn/basic/AbstractBrooklynObjectSpec.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package brooklyn.basic;
+
+import java.io.Serializable;
+import java.lang.reflect.Modifier;
+
+import brooklyn.util.exceptions.Exceptions;
+
+import com.google.common.base.Objects;
+
+public abstract class AbstractBrooklynObjectSpec<T,K extends AbstractBrooklynObjectSpec<T,K>> implements Serializable {
+
+    private static final long serialVersionUID = 3010955277740333030L;
+    
+    private final Class<T> type;
+    private String displayName;
+
+    protected AbstractBrooklynObjectSpec(Class<T> type) {
+        checkValidType(type);
+        this.type = type;
+    }
+    
+    @SuppressWarnings("unchecked")
+    protected final K self() {
+        return (K) this;
+    }
+
+    @Override
+    public String toString() {
+        return Objects.toStringHelper(this).add("type", getType()).toString();
+    }
+
+    protected abstract void checkValidType(Class<T> type);
+    
+    public K displayName(String val) {
+        displayName = val;
+        return self();
+    }
+    
+    /**
+     * @return The type of the enricher
+     */
+    public final Class<T> getType() {
+        return type;
+    }
+    
+    /**
+     * @return The display name of the enricher
+     */
+    public final String getDisplayName() {
+        return displayName;
+    }
+
+    // TODO Duplicates method in BasicEntityTypeRegistry and InternalEntityFactory.isNewStyleEntity
+    protected final void checkIsNewStyleImplementation(Class<?> implClazz) {
+        try {
+            implClazz.getConstructor(new Class[0]);
+        } catch (NoSuchMethodException e) {
+            throw new IllegalStateException("Implementation "+implClazz+" must have a no-argument constructor");
+        } catch (SecurityException e) {
+            throw Exceptions.propagate(e);
+        }
+        
+        if (implClazz.isInterface()) throw new IllegalStateException("Implementation "+implClazz+" is an interface, but must be a non-abstract class");
+        if (Modifier.isAbstract(implClazz.getModifiers())) throw new IllegalStateException("Implementation "+implClazz+" is abstract, but must be a non-abstract class");
+    }
+    
+    // TODO Duplicates method in BasicEntityTypeRegistry
+    protected final void checkIsImplementation(Class<?> val, Class<? super T> requiredInterface) {
+        if (!requiredInterface.isAssignableFrom(val)) throw new IllegalStateException("Implementation "+val+" does not implement "+requiredInterface.getName());
+        if (val.isInterface()) throw new IllegalStateException("Implementation "+val+" is an interface, but must be a non-abstract class");
+        if (Modifier.isAbstract(val.getModifiers())) throw new IllegalStateException("Implementation "+val+" is abstract, but must be a non-abstract class");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/98a37f07/api/src/main/java/brooklyn/entity/proxying/EntitySpec.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/entity/proxying/EntitySpec.java b/api/src/main/java/brooklyn/entity/proxying/EntitySpec.java
index a141d60..daaa6c8 100644
--- a/api/src/main/java/brooklyn/entity/proxying/EntitySpec.java
+++ b/api/src/main/java/brooklyn/entity/proxying/EntitySpec.java
@@ -20,8 +20,6 @@ package brooklyn.entity.proxying;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
-import java.io.Serializable;
-import java.lang.reflect.Modifier;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -32,6 +30,7 @@ import javax.annotation.Nullable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import brooklyn.basic.AbstractBrooklynObjectSpec;
 import brooklyn.config.ConfigKey;
 import brooklyn.config.ConfigKey.HasConfigKey;
 import brooklyn.entity.Entity;
@@ -42,9 +41,7 @@ import brooklyn.policy.Enricher;
 import brooklyn.policy.EnricherSpec;
 import brooklyn.policy.Policy;
 import brooklyn.policy.PolicySpec;
-import brooklyn.util.exceptions.Exceptions;
 
-import com.google.common.base.Objects;
 import com.google.common.base.Throwables;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
@@ -63,7 +60,7 @@ import com.google.common.collect.Sets;
  * 
  * @author aled
  */
-public class EntitySpec<T extends Entity> implements Serializable {
+public class EntitySpec<T extends Entity> extends AbstractBrooklynObjectSpec<T,EntitySpec<T>> {
 
     private static final long serialVersionUID = -2247153452919128990L;
     
@@ -131,9 +128,8 @@ public class EntitySpec<T extends Entity> implements Serializable {
         return new EntitySpec<T>(type);
     }
 
-    private final Class<T> type;
     private String id;
-    private String displayName;
+    
     private Class<? extends T> impl;
     private Entity parent;
     private final Map<String, Object> flags = Maps.newLinkedHashMap();
@@ -151,14 +147,12 @@ public class EntitySpec<T extends Entity> implements Serializable {
     private volatile boolean immutable;
     
     public EntitySpec(Class<T> type) {
-        this.type = type;
+        super(type);
     }
     
-    /**
-     * @return The type of the entity
-     */
-    public Class<T> getType() {
-        return type;
+    @Override
+    protected void checkValidType(Class<T> type) {
+        // EntitySpec does nothing.  Other specs do check it's an implementation etc.
     }
     
     /**
@@ -172,13 +166,6 @@ public class EntitySpec<T extends Entity> implements Serializable {
     }
     
     /**
-     * @return The display name of the entity
-     */
-    public String getDisplayName() {
-        return displayName;
-    }
-    
-    /**
      * @return The implementation of the entity; if not null. this overrides any defaults or other configuration
      * 
      * @see ImplementedBy on the entity interface classes for how defaults are defined.
@@ -266,15 +253,9 @@ public class EntitySpec<T extends Entity> implements Serializable {
         return this;
     }
 
-    public EntitySpec<T> displayName(String val) {
-        checkMutable();
-        displayName = val;
-        return this;
-    }
-
     public EntitySpec<T> impl(Class<? extends T> val) {
         checkMutable();
-        checkIsImplementation(checkNotNull(val, "impl"));
+        checkIsImplementation(checkNotNull(val, "impl"), getType());
         checkIsNewStyleImplementation(val);
         impl = val;
         return this;
@@ -486,34 +467,8 @@ public class EntitySpec<T extends Entity> implements Serializable {
         return this;
     }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).add("type", type).toString();
-    }
-    
     private void checkMutable() {
         if (immutable) throw new IllegalStateException("Cannot modify immutable entity spec "+this);
     }
     
-    // TODO Duplicates method in BasicEntityTypeRegistry
-    private void checkIsImplementation(Class<?> val) {
-        if (!type.isAssignableFrom(val)) throw new IllegalStateException("Implementation "+val+" does not implement "+type);
-        if (val.isInterface()) throw new IllegalStateException("Implementation "+val+" is an interface, but must be a non-abstract class");
-        if (Modifier.isAbstract(val.getModifiers())) throw new IllegalStateException("Implementation "+val+" is abstract, but must be a non-abstract class");
-    }
-
-    // TODO Duplicates method in BasicEntityTypeRegistry, and InternalEntityFactory.isNewStyleEntity
-    private void checkIsNewStyleImplementation(Class<?> implClazz) {
-        try {
-            implClazz.getConstructor(new Class[0]);
-        } catch (NoSuchMethodException e) {
-            throw new IllegalStateException("Implementation "+implClazz+" must have a no-argument constructor");
-        } catch (SecurityException e) {
-            throw Exceptions.propagate(e);
-        }
-        
-        if (implClazz.isInterface()) throw new IllegalStateException("Implementation "+implClazz+" is an interface, but must be a non-abstract class");
-        if (Modifier.isAbstract(implClazz.getModifiers())) throw new IllegalStateException("Implementation "+implClazz+" is abstract, but must be a non-abstract class");
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/98a37f07/api/src/main/java/brooklyn/location/LocationSpec.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/location/LocationSpec.java b/api/src/main/java/brooklyn/location/LocationSpec.java
index ce280c8..f34d1a2 100644
--- a/api/src/main/java/brooklyn/location/LocationSpec.java
+++ b/api/src/main/java/brooklyn/location/LocationSpec.java
@@ -20,20 +20,17 @@ package brooklyn.location;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
-import java.io.Serializable;
-import java.lang.reflect.Modifier;
 import java.util.Collections;
 import java.util.Map;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import brooklyn.basic.AbstractBrooklynObjectSpec;
 import brooklyn.config.ConfigKey;
 import brooklyn.config.ConfigKey.HasConfigKey;
 import brooklyn.management.Task;
-import brooklyn.util.exceptions.Exceptions;
 
-import com.google.common.base.Objects;
 import com.google.common.collect.Maps;
 
 /**
@@ -46,7 +43,7 @@ import com.google.common.collect.Maps;
  * 
  * @author aled
  */
-public class LocationSpec<T extends Location> implements Serializable {
+public class LocationSpec<T extends Location> extends AbstractBrooklynObjectSpec<T,LocationSpec<T>> {
 
     // TODO Would like to add `configure(ConfigBag)`, but `ConfigBag` is in core rather than api
     
@@ -76,18 +73,19 @@ public class LocationSpec<T extends Location> implements Serializable {
         return LocationSpec.create(type).configure(config);
     }
     
-    private final Class<T> type;
     private String id;
-    private String displayName;
     private Location parent;
     private final Map<String, Object> flags = Maps.newLinkedHashMap();
     private final Map<ConfigKey<?>, Object> config = Maps.newLinkedHashMap();
     private final Map<Class<?>, Object> extensions = Maps.newLinkedHashMap();
 
     protected LocationSpec(Class<T> type) {
-        checkIsImplementation(type);
+        super(type);
+    }
+     
+    protected void checkValidType(java.lang.Class<T> type) {
+        checkIsImplementation(type, Location.class);
         checkIsNewStyleImplementation(type);
-        this.type = type;
     }
 
     /**
@@ -99,11 +97,6 @@ public class LocationSpec<T extends Location> implements Serializable {
         return this;
     }
 
-    public LocationSpec<T> displayName(String val) {
-        displayName = val;
-        return this;
-    }
-
     public LocationSpec<T> parent(Location val) {
         parent = checkNotNull(val, "parent");
         return this;
@@ -165,13 +158,6 @@ public class LocationSpec<T extends Location> implements Serializable {
     }
     
     /**
-     * @return The type of the location
-     */
-    public Class<T> getType() {
-        return type;
-    }
-    
-    /**
      * @return The id of the location to be created, or null if brooklyn can auto-generate an id
      * 
      * @deprecated since 0.7.0; instead let the management context pick a random+unique id
@@ -182,13 +168,6 @@ public class LocationSpec<T extends Location> implements Serializable {
     }
     
     /**
-     * @return The display name of the location
-     */
-    public String getDisplayName() {
-        return displayName;
-    }
-    
-    /**
      * @return The location's parent
      */
     public Location getParent() {
@@ -216,31 +195,5 @@ public class LocationSpec<T extends Location> implements Serializable {
     public Map<Class<?>, Object> getExtensions() {
         return Collections.unmodifiableMap(extensions);
     }
-        
-    
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).add("type", type).toString();
-    }
-    
-    // TODO Duplicates method in EntitySpec and BasicEntityTypeRegistry
-    private void checkIsImplementation(Class<?> val) {
-        if (!Location.class.isAssignableFrom(val)) throw new IllegalStateException("Implementation "+val+" does not implement "+Location.class.getName());
-        if (val.isInterface()) throw new IllegalStateException("Implementation "+val+" is an interface, but must be a non-abstract class");
-        if (Modifier.isAbstract(val.getModifiers())) throw new IllegalStateException("Implementation "+val+" is abstract, but must be a non-abstract class");
-    }
-
-    // TODO Duplicates method in EntitySpec, BasicEntityTypeRegistry, and InternalEntityFactory.isNewStyleEntity
-    private void checkIsNewStyleImplementation(Class<?> implClazz) {
-        try {
-            implClazz.getConstructor(new Class[0]);
-        } catch (NoSuchMethodException e) {
-            throw new IllegalStateException("Implementation "+implClazz+" must have a no-argument constructor");
-        } catch (SecurityException e) {
-            throw Exceptions.propagate(e);
-        }
-        
-        if (implClazz.isInterface()) throw new IllegalStateException("Implementation "+implClazz+" is an interface, but must be a non-abstract class");
-        if (Modifier.isAbstract(implClazz.getModifiers())) throw new IllegalStateException("Implementation "+implClazz+" is abstract, but must be a non-abstract class");
-    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/98a37f07/api/src/main/java/brooklyn/policy/EnricherSpec.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/policy/EnricherSpec.java b/api/src/main/java/brooklyn/policy/EnricherSpec.java
index 36851df..43f1a85 100644
--- a/api/src/main/java/brooklyn/policy/EnricherSpec.java
+++ b/api/src/main/java/brooklyn/policy/EnricherSpec.java
@@ -20,20 +20,17 @@ package brooklyn.policy;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
-import java.io.Serializable;
-import java.lang.reflect.Modifier;
 import java.util.Collections;
 import java.util.Map;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import brooklyn.basic.AbstractBrooklynObjectSpec;
 import brooklyn.config.ConfigKey;
 import brooklyn.config.ConfigKey.HasConfigKey;
 import brooklyn.management.Task;
-import brooklyn.util.exceptions.Exceptions;
 
-import com.google.common.base.Objects;
 import com.google.common.collect.Maps;
 
 /**
@@ -46,7 +43,7 @@ import com.google.common.collect.Maps;
  * 
  * @author aled
  */
-public class EnricherSpec<T extends Enricher> implements Serializable {
+public class EnricherSpec<T extends Enricher> extends AbstractBrooklynObjectSpec<T,EnricherSpec<T>> {
 
     private static final Logger log = LoggerFactory.getLogger(EnricherSpec.class);
 
@@ -75,22 +72,18 @@ public class EnricherSpec<T extends Enricher> implements Serializable {
         return EnricherSpec.create(type).configure(config);
     }
     
-    private final Class<T> type;
-    private String displayName;
     private final Map<String, Object> flags = Maps.newLinkedHashMap();
     private final Map<ConfigKey<?>, Object> config = Maps.newLinkedHashMap();
 
     protected EnricherSpec(Class<T> type) {
-        checkIsImplementation(type);
-        checkIsNewStyleImplementation(type);
-        this.type = type;
+        super(type);
     }
     
-    public EnricherSpec<T> displayName(String val) {
-        displayName = val;
-        return this;
+    protected void checkValidType(Class<T> type) {
+        checkIsImplementation(type, Enricher.class);
+        checkIsNewStyleImplementation(type);
     }
-
+    
     public EnricherSpec<T> configure(Map<?,?> val) {
         for (Map.Entry<?, ?> entry: val.entrySet()) {
             if (entry.getKey()==null) throw new NullPointerException("Null key not permitted");
@@ -137,20 +130,6 @@ public class EnricherSpec<T extends Enricher> implements Serializable {
     }
 
     /**
-     * @return The type of the enricher
-     */
-    public Class<T> getType() {
-        return type;
-    }
-    
-    /**
-     * @return The display name of the enricher
-     */
-    public String getDisplayName() {
-        return displayName;
-    }
-    
-    /**
      * @return Read-only construction flags
      * @see SetFromFlag declarations on the enricher type
      */
@@ -164,30 +143,5 @@ public class EnricherSpec<T extends Enricher> implements Serializable {
     public Map<ConfigKey<?>, Object> getConfig() {
         return Collections.unmodifiableMap(config);
     }
-        
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).add("type", type).toString();
-    }
-    
-    // TODO Duplicates method in EntitySpec and BasicEntityTypeRegistry
-    private void checkIsImplementation(Class<?> val) {
-        if (!Enricher.class.isAssignableFrom(val)) throw new IllegalStateException("Implementation "+val+" does not implement "+Enricher.class.getName());
-        if (val.isInterface()) throw new IllegalStateException("Implementation "+val+" is an interface, but must be a non-abstract class");
-        if (Modifier.isAbstract(val.getModifiers())) throw new IllegalStateException("Implementation "+val+" is abstract, but must be a non-abstract class");
-    }
 
-    // TODO Duplicates method in EntitySpec, BasicEntityTypeRegistry, and InternalEntityFactory.isNewStyleEntity
-    private void checkIsNewStyleImplementation(Class<?> implClazz) {
-        try {
-            implClazz.getConstructor(new Class[0]);
-        } catch (NoSuchMethodException e) {
-            throw new IllegalStateException("Implementation "+implClazz+" must have a no-argument constructor");
-        } catch (SecurityException e) {
-            throw Exceptions.propagate(e);
-        }
-        
-        if (implClazz.isInterface()) throw new IllegalStateException("Implementation "+implClazz+" is an interface, but must be a non-abstract class");
-        if (Modifier.isAbstract(implClazz.getModifiers())) throw new IllegalStateException("Implementation "+implClazz+" is abstract, but must be a non-abstract class");
-    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/98a37f07/api/src/main/java/brooklyn/policy/PolicySpec.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/policy/PolicySpec.java b/api/src/main/java/brooklyn/policy/PolicySpec.java
index 310e867..ccce6e0 100644
--- a/api/src/main/java/brooklyn/policy/PolicySpec.java
+++ b/api/src/main/java/brooklyn/policy/PolicySpec.java
@@ -20,20 +20,17 @@ package brooklyn.policy;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
-import java.io.Serializable;
-import java.lang.reflect.Modifier;
 import java.util.Collections;
 import java.util.Map;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import brooklyn.basic.AbstractBrooklynObjectSpec;
 import brooklyn.config.ConfigKey;
 import brooklyn.config.ConfigKey.HasConfigKey;
 import brooklyn.management.Task;
-import brooklyn.util.exceptions.Exceptions;
 
-import com.google.common.base.Objects;
 import com.google.common.collect.Maps;
 
 /**
@@ -46,7 +43,7 @@ import com.google.common.collect.Maps;
  * 
  * @author aled
  */
-public class PolicySpec<T extends Policy> implements Serializable {
+public class PolicySpec<T extends Policy> extends AbstractBrooklynObjectSpec<T,PolicySpec<T>> {
 
     private static final Logger log = LoggerFactory.getLogger(PolicySpec.class);
 
@@ -75,22 +72,18 @@ public class PolicySpec<T extends Policy> implements Serializable {
         return PolicySpec.create(type).configure(config);
     }
     
-    private final Class<T> type;
-    private String displayName;
     private final Map<String, Object> flags = Maps.newLinkedHashMap();
     private final Map<ConfigKey<?>, Object> config = Maps.newLinkedHashMap();
 
     protected PolicySpec(Class<T> type) {
-        checkIsImplementation(type);
-        checkIsNewStyleImplementation(type);
-        this.type = type;
+        super(type);
     }
     
-    public PolicySpec<T> displayName(String val) {
-        displayName = val;
-        return this;
+    protected void checkValidType(Class<T> type) {
+        checkIsImplementation(type, Policy.class);
+        checkIsNewStyleImplementation(type);
     }
-
+    
     public PolicySpec<T> configure(Map<?,?> val) {
         for (Map.Entry<?, ?> entry: val.entrySet()) {
             if (entry.getKey()==null) throw new NullPointerException("Null key not permitted");
@@ -137,20 +130,6 @@ public class PolicySpec<T extends Policy> implements Serializable {
     }
 
     /**
-     * @return The type of the policy
-     */
-    public Class<T> getType() {
-        return type;
-    }
-    
-    /**
-     * @return The display name of the policy
-     */
-    public String getDisplayName() {
-        return displayName;
-    }
-    
-    /**
      * @return Read-only construction flags
      * @see SetFromFlag declarations on the policy type
      */
@@ -165,29 +144,4 @@ public class PolicySpec<T extends Policy> implements Serializable {
         return Collections.unmodifiableMap(config);
     }
         
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).add("type", type).toString();
-    }
-    
-    // TODO Duplicates method in EntitySpec and BasicEntityTypeRegistry
-    private void checkIsImplementation(Class<?> val) {
-        if (!Policy.class.isAssignableFrom(val)) throw new IllegalStateException("Implementation "+val+" does not implement "+Policy.class.getName());
-        if (val.isInterface()) throw new IllegalStateException("Implementation "+val+" is an interface, but must be a non-abstract class");
-        if (Modifier.isAbstract(val.getModifiers())) throw new IllegalStateException("Implementation "+val+" is abstract, but must be a non-abstract class");
-    }
-
-    // TODO Duplicates method in EntitySpec, BasicEntityTypeRegistry, and InternalEntityFactory.isNewStyleEntity
-    private void checkIsNewStyleImplementation(Class<?> implClazz) {
-        try {
-            implClazz.getConstructor(new Class[0]);
-        } catch (NoSuchMethodException e) {
-            throw new IllegalStateException("Implementation "+implClazz+" must have a no-argument constructor");
-        } catch (SecurityException e) {
-            throw Exceptions.propagate(e);
-        }
-        
-        if (implClazz.isInterface()) throw new IllegalStateException("Implementation "+implClazz+" is an interface, but must be a non-abstract class");
-        if (Modifier.isAbstract(implClazz.getModifiers())) throw new IllegalStateException("Implementation "+implClazz+" is abstract, but must be a non-abstract class");
-    }
 }


[11/11] git commit: This closes #109

Posted by he...@apache.org.
This closes #109


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

Branch: refs/heads/master
Commit: 4891355f7d261ef64efaac6b0e0841837c27da23
Parents: 83b0b82 71ea98c
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Aug 6 17:03:51 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Aug 6 17:03:51 2014 -0400

----------------------------------------------------------------------
 .../mementos/BrooklynMementoManifest.java       |  2 ++
 .../mementos/BrooklynMementoPersister.java      |  3 +++
 .../entity/rebind/RebindManagerImpl.java        | 21 +++++++++++++-----
 .../rebind/dto/BrooklynMementoManifestImpl.java |  6 +++++
 .../AbstractBrooklynMementoPersister.java       |  6 +++++
 .../BrooklynMementoPersisterToMultiFile.java    |  6 +++++
 .../BrooklynMementoPersisterToObjectStore.java  |  5 +++++
 .../src/main/java/brooklyn/util/osgi/Osgis.java | 23 ++++++--------------
 8 files changed, 50 insertions(+), 22 deletions(-)
----------------------------------------------------------------------



[02/11] git commit: code tidy of ArchiveBuilder

Posted by he...@apache.org.
code tidy of ArchiveBuilder


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

Branch: refs/heads/master
Commit: 4bbf3b4f075c4e6bb3af284081dc84fe24f13004
Parents: 98a37f0
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Aug 1 16:27:27 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Aug 5 10:40:37 2014 -0400

----------------------------------------------------------------------
 .../java/brooklyn/util/file/ArchiveBuilder.java | 45 ++++++++++----------
 .../brooklyn/util/file/ArchiveBuilderTest.java  |  2 +-
 2 files changed, 24 insertions(+), 23 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4bbf3b4f/core/src/main/java/brooklyn/util/file/ArchiveBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/file/ArchiveBuilder.java b/core/src/main/java/brooklyn/util/file/ArchiveBuilder.java
index b5c98f5..9c01b35 100644
--- a/core/src/main/java/brooklyn/util/file/ArchiveBuilder.java
+++ b/core/src/main/java/brooklyn/util/file/ArchiveBuilder.java
@@ -37,6 +37,7 @@ import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.file.ArchiveUtils.ArchiveType;
 import brooklyn.util.os.Os;
 
+import com.google.common.annotations.Beta;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.LinkedHashMultimap;
 import com.google.common.collect.Multimap;
@@ -50,21 +51,17 @@ import com.google.common.io.Files;
  * specified. The created file must be a Java archive type, with the extension {@code .zip},
  * {@code .jar}, {@code .war} or {@code .ear}.
  * <p>
- * Examples:
+ * Example:
  * <pre> File zip = ArchiveBuilder.archive("data/archive.zip")
- *         .entry("src", applicationDir + "/deploy/" + version + "/src/")
- *         .entry("lib", applicationDir + "/deploy/" + version + "/lib/")
- *         .entry("etc/config.ini", applicationDir + "/config.ini")
+ *         .addAt(new File("./pom.xml"), "")
+ *         .addDirContentsAt(new File("./src"), "src/")
+ *         .addAt(new File("/tmp/Extra.java"), "src/main/java/")
+ *         .addDirContentsAt(new File("/tmp/overlay/"), "")
  *         .create();
  * </pre>
- * <pre> OutputStream remote = ...;
- * Map&lt;String, File&gt; entries = ...;
- * ArchiveBuilder.zip()
- *         .add("resources/data.csv")
- *         .addAll(entries)
- *         .stream(remote);
- * </pre>
+ * <p>
  */
+@Beta
 public class ArchiveBuilder {
 
     /**
@@ -178,28 +175,32 @@ public class ArchiveBuilder {
     }
 
     /**
-     * Add the file located at the {@code filePath}, relative to the {@code baseDir},
+     * Add the file located at the {@code fileSubPath}, relative to the {@code baseDir} on the local system,
      * to the archive.
      * <p>
-     * Uses the {@code filePath} as the name of the file in the archive. Note that the
-     * file is found by concatenating the two path components using {@link Os#mergePaths(String...)}
-     * which may not behave as expected if the {@code filePath} is absolute or points to
-     * a location above the current directory.
+     * Uses the {@code fileSubPath} as the name of the file in the archive. Note that the
+     * file is found by concatenating the two path components using {@link Os#mergePaths(String...)},
+     * thus {@code fileSubPath} should not be absolute or point to a location above the current directory.
      * <p>
      * Use {@link #entry(String, String)} directly or {@link #entries(Map)} for complete
      * control over file locations and names in the archive.
      *
      * @see #entry(String, String)
      */
-    public ArchiveBuilder addRelativeToBaseDir(String baseDir, String filePath) {
+    public ArchiveBuilder addFromLocalBaseDir(File baseDir, String fileSubPath) {
         checkNotNull(baseDir, "baseDir");
-        checkNotNull(filePath, "filePath");
-        return entry(Os.mergePaths(".", filePath), Os.mergePaths(baseDir, filePath));
+        checkNotNull(fileSubPath, "filePath");
+        return entry(Os.mergePaths(".", fileSubPath), Os.mergePaths(baseDir.getPath(), fileSubPath));
+    }
+    /** @deprecated since 0.7.0 use {@link #addFromLocalBaseDir(File, String)}, or
+     * one of the other add methods if adding relative to baseDir was not intended */ @Deprecated
+    public ArchiveBuilder addFromLocalBaseDir(String baseDir, String fileSubPath) {
+        return addFromLocalBaseDir(new File(baseDir), fileSubPath);
     }
-    /** @deprecated since 0.7.0 use {@link #addRelativeToBaseDir(String, String)}, or
+    /** @deprecated since 0.7.0 use {@link #addFromLocalBaseDir(File, String)}, or
      * one of the other add methods if adding relative to baseDir was not intended */ @Deprecated
-    public ArchiveBuilder add(String baseDir, String filePath) {
-        return addRelativeToBaseDir(baseDir, filePath);
+    public ArchiveBuilder add(String baseDir, String fileSubPath) {
+        return addFromLocalBaseDir(baseDir, fileSubPath);
     }
      
     /** adds the given file to the archive, preserving its name but putting under the given directory in the archive (may be <code>""</code> or <code>"./"</code>) */

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4bbf3b4f/core/src/test/java/brooklyn/util/file/ArchiveBuilderTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/file/ArchiveBuilderTest.java b/core/src/test/java/brooklyn/util/file/ArchiveBuilderTest.java
index 222a312..6469f5a 100644
--- a/core/src/test/java/brooklyn/util/file/ArchiveBuilderTest.java
+++ b/core/src/test/java/brooklyn/util/file/ArchiveBuilderTest.java
@@ -167,7 +167,7 @@ public class ArchiveBuilderTest {
         ArchiveBuilder builder = ArchiveBuilder.zip();
         String baseDir = tmpDir.getName();
         for (String fileName : Arrays.asList("data01.txt", "data02.txt", "data03.txt")) {
-            builder.addRelativeToBaseDir(parentDir.getPath(), Os.mergePaths(baseDir, fileName));
+            builder.addFromLocalBaseDir(parentDir, Os.mergePaths(baseDir, fileName));
         }
         File archive = builder.create();
         archive.deleteOnExit();


[04/11] git commit: set uniqueTags for many enrichers and policies

Posted by he...@apache.org.
set uniqueTags for many enrichers and policies


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

Branch: refs/heads/master
Commit: 427d4e1a6889527ce37df94160ebbeaf5227d51b
Parents: 72b52e1
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Sat Aug 2 11:44:49 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Aug 5 10:40:46 2014 -0400

----------------------------------------------------------------------
 .../main/java/brooklyn/enricher/Enrichers.java  | 23 ++++++++++++++++++++
 .../basic/SensorTransformingEnricher.java       | 12 +++++-----
 .../group/AbstractMembershipTrackingPolicy.java |  4 ++++
 .../brooklyn/enricher/HttpLatencyDetector.java  | 11 ++++++++--
 .../brooklyn/enricher/RollingMeanEnricher.java  |  3 +++
 .../enricher/RollingTimeWindowMeanEnricher.java |  4 ++++
 .../enricher/TimeFractionDeltaEnricher.java     |  5 +++++
 .../enricher/TimeWeightedDeltaEnricher.java     |  5 +++++
 .../java/brooklyn/util/guava/TypeTokens.java    |  6 +++++
 9 files changed, 65 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/427d4e1a/core/src/main/java/brooklyn/enricher/Enrichers.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/Enrichers.java b/core/src/main/java/brooklyn/enricher/Enrichers.java
index e6f903e..dab423c 100644
--- a/core/src/main/java/brooklyn/enricher/Enrichers.java
+++ b/core/src/main/java/brooklyn/enricher/Enrichers.java
@@ -36,11 +36,13 @@ import brooklyn.event.Sensor;
 import brooklyn.event.SensorEvent;
 import brooklyn.policy.Enricher;
 import brooklyn.policy.EnricherSpec;
+import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.text.Strings;
 
 import com.google.common.base.Function;
+import com.google.common.base.Joiner;
 import com.google.common.base.Objects;
 import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableList;
@@ -190,6 +192,7 @@ public class Enrichers {
             }
             // FIXME excludingBlank; use valueFilter? exclude means ignored entirely or substituted for defaultMemberValue?
             return EnricherSpec.create(Aggregator.class)
+                    .uniqueTag("aggregator:"+publishing)
                     .configure(MutableMap.builder()
                             .putIfNotNull(Aggregator.PRODUCER, fromEntity)
                             .put(Aggregator.TARGET_SENSOR, publishing)
@@ -288,6 +291,7 @@ public class Enrichers {
         }
         public EnricherSpec<?> build() {
             return EnricherSpec.create(Combiner.class)
+                    .uniqueTag("combiner:"+publishing)
                     .configure(MutableMap.builder()
                             .putIfNotNull(Combiner.PRODUCER, fromEntity)
                             .put(Combiner.TARGET_SENSOR, publishing)
@@ -347,6 +351,7 @@ public class Enrichers {
         }
         public EnricherSpec<?> build() {
             return EnricherSpec.create(Transformer.class)
+                    .uniqueTag("transformer:"+publishing)
                     .configure(MutableMap.builder()
                             .putIfNotNull(Transformer.PRODUCER, fromEntity)
                             .put(Transformer.TARGET_SENSOR, publishing)
@@ -399,7 +404,25 @@ public class Enrichers {
             return self();
         }
         public EnricherSpec<? extends Enricher> build() {
+            List<String> summary = MutableList.of();
+            if (propagating!=null) {
+                for (Map.Entry<? extends Sensor<?>, ? extends Sensor<?>> entry: propagating.entrySet()) {
+                    if (entry.getKey().getName().equals(entry.getValue().getName()))
+                        summary.add(entry.getKey().getName());
+                    else
+                        summary.add(entry.getKey().getName()+"->"+entry.getValue().getName());
+                }
+            }
+            if (Boolean.TRUE.equals(propagatingAll))
+                summary.add("ALL");
+            if (propagatingAllBut!=null && !Iterables.isEmpty(propagatingAllBut)) {
+                List<String> allBut = MutableList.of();
+                for (Sensor<?> s: propagatingAllBut) allBut.add(s.getName());
+                summary.add("ALL_BUT:"+Joiner.on(",").join(allBut));
+            }
+            
             return EnricherSpec.create(Propagator.class)
+                    .uniqueTag("propagating["+fromEntity.getId()+":"+Joiner.on(",").join(summary)+"]")
                     .configure(MutableMap.builder()
                             .putIfNotNull(Propagator.PRODUCER, fromEntity)
                             .putIfNotNull(Propagator.SENSOR_MAPPING, propagating)

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/427d4e1a/core/src/main/java/brooklyn/enricher/basic/SensorTransformingEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/SensorTransformingEnricher.java b/core/src/main/java/brooklyn/enricher/basic/SensorTransformingEnricher.java
index 806b5a7..314e833 100644
--- a/core/src/main/java/brooklyn/enricher/basic/SensorTransformingEnricher.java
+++ b/core/src/main/java/brooklyn/enricher/basic/SensorTransformingEnricher.java
@@ -24,6 +24,8 @@ import brooklyn.event.AttributeSensor;
 import brooklyn.event.Sensor;
 import brooklyn.event.SensorEvent;
 import brooklyn.util.GroovyJavaMethods;
+import brooklyn.util.javalang.JavaClassNames;
+import brooklyn.util.time.Duration;
 
 import com.google.common.base.Function;
 
@@ -38,21 +40,19 @@ public class SensorTransformingEnricher<T,U> extends AbstractTypeTransformingEnr
     public SensorTransformingEnricher(Entity producer, Sensor<T> source, Sensor<U> target, Function<? super T, ? extends U> transformation) {
         super(producer, source, target);
         this.transformation = transformation;
+        this.uniqueTag = JavaClassNames.simpleClassName(getClass())+":"+source.getName()+"*->"+target.getName();;
     }
 
     public SensorTransformingEnricher(Entity producer, Sensor<T> source, Sensor<U> target, Closure transformation) {
-        super(producer, source, target);
-        this.transformation = GroovyJavaMethods.functionFromClosure(transformation);
+        this(producer, source, target, GroovyJavaMethods.functionFromClosure(transformation));
     }
 
     public SensorTransformingEnricher(Sensor<T> source, Sensor<U> target, Function<T,U> transformation) {
-        super(null, source, target);
-        this.transformation = transformation;
+        this(null, source, target, transformation);
     }
 
     public SensorTransformingEnricher(Sensor<T> source, Sensor<U> target, Closure transformation) {
-        super(null, source, target);
-        this.transformation = GroovyJavaMethods.functionFromClosure(transformation);
+        this(null, source, target, GroovyJavaMethods.functionFromClosure(transformation));
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/427d4e1a/core/src/main/java/brooklyn/entity/group/AbstractMembershipTrackingPolicy.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/group/AbstractMembershipTrackingPolicy.java b/core/src/main/java/brooklyn/entity/group/AbstractMembershipTrackingPolicy.java
index e3f0dce..12100cd 100644
--- a/core/src/main/java/brooklyn/entity/group/AbstractMembershipTrackingPolicy.java
+++ b/core/src/main/java/brooklyn/entity/group/AbstractMembershipTrackingPolicy.java
@@ -38,6 +38,7 @@ import brooklyn.event.SensorEvent;
 import brooklyn.event.SensorEventListener;
 import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.util.collections.MutableMap;
+import brooklyn.util.javalang.JavaClassNames;
 
 import com.google.common.base.Objects;
 import com.google.common.base.Preconditions;
@@ -85,6 +86,9 @@ public abstract class AbstractMembershipTrackingPolicy extends AbstractPolicy {
         super.setEntity(entity);
         Group group = getGroup();
         if (group != null) {
+            if (uniqueTag==null) {
+                uniqueTag = JavaClassNames.simpleClassName(this)+":"+group;
+            }
             subscribeToGroup(group);
         } else {
             LOG.warn("Deprecated use of "+AbstractMembershipTrackingPolicy.class.getSimpleName()+"; group should be set as config");

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/427d4e1a/policy/src/main/java/brooklyn/enricher/HttpLatencyDetector.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/enricher/HttpLatencyDetector.java b/policy/src/main/java/brooklyn/enricher/HttpLatencyDetector.java
index 7645980..bd1dd00 100644
--- a/policy/src/main/java/brooklyn/enricher/HttpLatencyDetector.java
+++ b/policy/src/main/java/brooklyn/enricher/HttpLatencyDetector.java
@@ -44,8 +44,10 @@ import brooklyn.event.feed.http.HttpPollConfig;
 import brooklyn.event.feed.http.HttpValueFunctions;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.flags.SetFromFlag;
+import brooklyn.util.guava.TypeTokens;
 import brooklyn.util.javalang.AtomicReferences;
 import brooklyn.util.javalang.Boxing;
+import brooklyn.util.javalang.JavaClassNames;
 import brooklyn.util.math.MathFunctions;
 import brooklyn.util.net.Urls;
 import brooklyn.util.text.StringFunctions;
@@ -72,12 +74,13 @@ public class HttpLatencyDetector extends AbstractEnricher {
     @SetFromFlag("url")
     public static final ConfigKey<String> URL = ConfigKeys.newStringConfigKey("latencyDetector.url");
     
+    @SuppressWarnings("serial")
     @SetFromFlag("urlSensor")
     public static final ConfigKey<AttributeSensor<String>> URL_SENSOR = ConfigKeys.newConfigKey(new TypeToken<AttributeSensor<String>>() {}, "latencyDetector.urlSensor");
 
     @SetFromFlag("urlPostProcessing")
     public static final ConfigKey<Function<String,String>> URL_POST_PROCESSING = ConfigKeys.newConfigKey(
-            new TypeToken<Function<String,String>>() {}, 
+            TypeTokens.functionOf(String.class, String.class), 
             "latencyDetector.urlPostProcessing",
             "Function applied to the urlSensor value, to determine the URL to use");
 
@@ -103,7 +106,7 @@ public class HttpLatencyDetector extends AbstractEnricher {
     public HttpLatencyDetector() { // for rebinding, and for EnricherSpec usage
     }
     
-    protected HttpLatencyDetector(Map flags) {
+    protected HttpLatencyDetector(Map<?,?> flags) {
         super(flags);
     }
     
@@ -139,6 +142,10 @@ public class HttpLatencyDetector extends AbstractEnricher {
                         .setOnException(null))
                 .suspended()
                 .build();
+        
+        if (getUniqueTag()==null) 
+            uniqueTag = JavaClassNames.simpleClassName(getClass())+":"+
+                (getConfig(URL)!=null ? getConfig(URL) : getConfig(URL_SENSOR));
     }
 
     protected void startSubscriptions(EntityLocal entity) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/427d4e1a/policy/src/main/java/brooklyn/enricher/RollingMeanEnricher.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/enricher/RollingMeanEnricher.java b/policy/src/main/java/brooklyn/enricher/RollingMeanEnricher.java
index 8f5452c..49e1241 100644
--- a/policy/src/main/java/brooklyn/enricher/RollingMeanEnricher.java
+++ b/policy/src/main/java/brooklyn/enricher/RollingMeanEnricher.java
@@ -25,6 +25,7 @@ import brooklyn.entity.Entity;
 import brooklyn.event.AttributeSensor;
 import brooklyn.event.SensorEvent;
 import brooklyn.util.flags.SetFromFlag;
+import brooklyn.util.javalang.JavaClassNames;
 
 
 /**
@@ -44,6 +45,8 @@ public class RollingMeanEnricher<T extends Number> extends AbstractTypeTransform
             int windowSize) {
         super(producer, source, target);
         this.windowSize = windowSize;
+        if (source!=null && target!=null)
+            this.uniqueTag = JavaClassNames.simpleClassName(getClass())+":"+source.getName()+"->"+target.getName();
     }
     
     /** @returns null when no data has been received or windowSize is 0 */

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/427d4e1a/policy/src/main/java/brooklyn/enricher/RollingTimeWindowMeanEnricher.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/enricher/RollingTimeWindowMeanEnricher.java b/policy/src/main/java/brooklyn/enricher/RollingTimeWindowMeanEnricher.java
index 2485abc..b196efa 100644
--- a/policy/src/main/java/brooklyn/enricher/RollingTimeWindowMeanEnricher.java
+++ b/policy/src/main/java/brooklyn/enricher/RollingTimeWindowMeanEnricher.java
@@ -29,6 +29,7 @@ import brooklyn.event.AttributeSensor;
 import brooklyn.event.Sensor;
 import brooklyn.event.SensorEvent;
 import brooklyn.util.flags.SetFromFlag;
+import brooklyn.util.javalang.JavaClassNames;
 import brooklyn.util.time.Duration;
 
 /**
@@ -79,6 +80,9 @@ public class RollingTimeWindowMeanEnricher<T extends Number> extends AbstractTyp
         AttributeSensor<Double> target, Duration timePeriod) {
         super(producer, source, target);
         this.timePeriod = Preconditions.checkNotNull(timePeriod, "timePeriod");
+        
+        if (source!=null && target!=null)
+            this.uniqueTag = JavaClassNames.simpleClassName(getClass())+":"+source.getName()+"/"+timePeriod+"->"+target.getName();
     }
 
     /** @deprecated since 0.6.0 use Duration parameter rather than long with millis */

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/427d4e1a/policy/src/main/java/brooklyn/enricher/TimeFractionDeltaEnricher.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/enricher/TimeFractionDeltaEnricher.java b/policy/src/main/java/brooklyn/enricher/TimeFractionDeltaEnricher.java
index f6af440..253cdc6 100644
--- a/policy/src/main/java/brooklyn/enricher/TimeFractionDeltaEnricher.java
+++ b/policy/src/main/java/brooklyn/enricher/TimeFractionDeltaEnricher.java
@@ -29,6 +29,8 @@ import brooklyn.event.AttributeSensor;
 import brooklyn.event.Sensor;
 import brooklyn.event.SensorEvent;
 import brooklyn.util.flags.SetFromFlag;
+import brooklyn.util.javalang.JavaClassNames;
+import brooklyn.util.time.Duration;
 
 /**
  * Converts an absolute measure of time into a fraction of time, based on the delta between consecutive values 
@@ -58,6 +60,9 @@ public class TimeFractionDeltaEnricher<T extends Number> extends AbstractTypeTra
     public TimeFractionDeltaEnricher(Entity producer, Sensor<T> source, Sensor<Double> target, long nanosPerOrigUnit) {
         super(producer, source, target);
         this.nanosPerOrigUnit = nanosPerOrigUnit;
+        
+        if (source!=null && target!=null)
+            this.uniqueTag = JavaClassNames.simpleClassName(getClass())+":"+source.getName()+"*"+Duration.nanos(nanosPerOrigUnit)+"->"+target.getName();
     }
     
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/427d4e1a/policy/src/main/java/brooklyn/enricher/TimeWeightedDeltaEnricher.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/enricher/TimeWeightedDeltaEnricher.java b/policy/src/main/java/brooklyn/enricher/TimeWeightedDeltaEnricher.java
index 73d1389..d344dd4 100644
--- a/policy/src/main/java/brooklyn/enricher/TimeWeightedDeltaEnricher.java
+++ b/policy/src/main/java/brooklyn/enricher/TimeWeightedDeltaEnricher.java
@@ -30,6 +30,8 @@ import brooklyn.event.Sensor;
 import brooklyn.event.SensorEvent;
 import brooklyn.util.GroovyJavaMethods;
 import brooklyn.util.flags.SetFromFlag;
+import brooklyn.util.javalang.JavaClassNames;
+import brooklyn.util.time.Duration;
 
 import com.google.common.base.Function;
 import com.google.common.base.Functions;
@@ -73,6 +75,9 @@ public class TimeWeightedDeltaEnricher<T extends Number> extends AbstractTypeTra
         super(producer, source, target);
         this.unitMillis = unitMillis;
         this.postProcessor = postProcessor;
+        
+        if (source!=null && target!=null)
+            this.uniqueTag = JavaClassNames.simpleClassName(getClass())+":"+source.getName()+"/"+Duration.millis(unitMillis)+"->"+target.getName();
     }
     
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/427d4e1a/utils/common/src/main/java/brooklyn/util/guava/TypeTokens.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/guava/TypeTokens.java b/utils/common/src/main/java/brooklyn/util/guava/TypeTokens.java
index d16d2df..ee7099b 100644
--- a/utils/common/src/main/java/brooklyn/util/guava/TypeTokens.java
+++ b/utils/common/src/main/java/brooklyn/util/guava/TypeTokens.java
@@ -24,6 +24,7 @@ import java.util.Set;
 
 import javax.annotation.Nullable;
 
+import com.google.common.base.Function;
 import com.google.common.reflect.TypeToken;
 
 public class TypeTokens {
@@ -87,5 +88,10 @@ public class TypeTokens {
     public static <T> TypeToken<List<T>> listOf(Class<T> type) {
         return (TypeToken) TypeToken.of(List.class);
     }
+
+    @SuppressWarnings("serial")
+    public static <I,O> TypeToken<Function<I,O>> functionOf(Class<I> input, Class<O> output) {
+        return new TypeToken<Function<I,O>>() {};
+    }
     
 }


[10/11] git commit: This closes #106

Posted by he...@apache.org.
This closes #106


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

Branch: refs/heads/master
Commit: 83b0b82e1130624ce2347d9dacbc241c7720ebd0
Parents: bf627f7 e6ffe2e
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Aug 6 17:03:48 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Aug 6 17:03:48 2014 -0400

----------------------------------------------------------------------
 .../basic/AbstractBrooklynObjectSpec.java       | 112 ++++++++++
 .../java/brooklyn/basic/BrooklynObject.java     |  14 ++
 api/src/main/java/brooklyn/entity/Entity.java   |   4 +-
 .../brooklyn/entity/proxying/EntitySpec.java    |  62 +-----
 .../java/brooklyn/location/LocationSpec.java    |  63 +-----
 .../main/java/brooklyn/policy/EnricherSpec.java |  61 +----
 .../java/brooklyn/policy/EntityAdjunct.java     |  31 ++-
 .../main/java/brooklyn/policy/PolicySpec.java   |  59 +----
 .../brooklyn/basic/AbstractBrooklynObject.java  |  53 +++++
 .../main/java/brooklyn/enricher/Enrichers.java  |  23 ++
 .../enricher/basic/AbstractEnricher.java        |   5 +-
 .../basic/SensorTransformingEnricher.java       |  12 +-
 .../brooklyn/entity/basic/AbstractEntity.java   |  90 ++++----
 .../java/brooklyn/entity/basic/Entities.java    |  48 +++-
 .../group/AbstractMembershipTrackingPolicy.java |   4 +
 .../entity/proxying/InternalEntityFactory.java  |   3 +
 .../proxying/InternalLocationFactory.java       |   4 +-
 .../entity/proxying/InternalPolicyFactory.java  |   4 +
 .../rebind/BasicLocationRebindSupport.java      |   2 +-
 .../location/basic/AbstractLocation.java        |  50 +++--
 .../policy/basic/AbstractEntityAdjunct.java     |  26 ++-
 .../brooklyn/policy/basic/AbstractPolicy.java   |   8 +-
 .../java/brooklyn/util/file/ArchiveBuilder.java |  45 ++--
 .../enricher/basic/BasicEnricherTest.java       | 100 +++++++++
 .../enricher/basic/EnricherConfigTest.java      | 148 +++++++++++++
 .../brooklyn/entity/basic/EntitiesTest.java     |   6 +-
 .../group/MembershipTrackingPolicyTest.java     |   8 +-
 .../entity/rebind/RebindEnricherTest.java       |  35 ++-
 .../entity/rebind/RebindPolicyTest.java         |   9 +
 .../location/basic/AbstractLocationTest.java    |   9 +-
 .../location/basic/LocationConfigTest.java      |   3 +
 .../brooklyn/policy/basic/BasicPolicyTest.java  |  89 ++++++++
 .../policy/basic/EnricherConfigTest.java        | 169 --------------
 .../policy/basic/PolicyConfigMapUsageTest.java  | 222 -------------------
 .../brooklyn/policy/basic/PolicyConfigTest.java | 202 +++++++++++++++++
 .../brooklyn/util/file/ArchiveBuilderTest.java  |   2 +-
 .../brooklyn/enricher/HttpLatencyDetector.java  |   9 +-
 .../brooklyn/enricher/RollingMeanEnricher.java  |   3 +
 .../enricher/RollingTimeWindowMeanEnricher.java |   4 +
 .../enricher/TimeFractionDeltaEnricher.java     |   5 +
 .../enricher/TimeWeightedDeltaEnricher.java     |   5 +
 .../BrooklynAssemblyTemplateInstantiator.java   |   1 +
 42 files changed, 1092 insertions(+), 720 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/83b0b82e/core/src/main/java/brooklyn/entity/basic/Entities.java
----------------------------------------------------------------------


[07/11] git commit: remove de-generifying TypeTokens methods

Posted by he...@apache.org.
remove de-generifying TypeTokens methods


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

Branch: refs/heads/master
Commit: e6ffe2ecfbf38696a03323ca245403dd25c9ce4d
Parents: db7492a
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Aug 5 09:57:18 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Aug 5 10:41:04 2014 -0400

----------------------------------------------------------------------
 .../location/basic/AbstractLocation.java        |  5 ++--
 .../brooklyn/enricher/HttpLatencyDetector.java  |  4 ++--
 .../java/brooklyn/util/guava/TypeTokens.java    | 25 --------------------
 3 files changed, 5 insertions(+), 29 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ffe2ec/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/location/basic/AbstractLocation.java b/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
index e517d10..84259ff 100644
--- a/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
+++ b/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
@@ -57,7 +57,6 @@ import brooklyn.util.collections.SetFromLiveMap;
 import brooklyn.util.config.ConfigBag;
 import brooklyn.util.flags.FlagUtils;
 import brooklyn.util.flags.TypeCoercions;
-import brooklyn.util.guava.TypeTokens;
 import brooklyn.util.stream.Streams;
 
 import com.google.common.base.Objects;
@@ -68,6 +67,7 @@ import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
+import com.google.common.reflect.TypeToken;
 
 /**
  * A basic implementation of the {@link Location} interface.
@@ -238,6 +238,7 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
      * method is invoked.) If you require fields to be initialized you must do that in 
      * this method with a guard (as in FixedListMachineProvisioningLocation).
      */
+    @SuppressWarnings("serial")
     public void configure(Map<?,?> properties) {
         assertNotYetManaged();
         
@@ -276,7 +277,7 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
             if (rawCodes instanceof CharSequence) {
                 codes = ImmutableSet.copyOf(Splitter.on(",").trimResults().split((CharSequence)rawCodes));
             } else {
-                codes = TypeCoercions.coerce(rawCodes, TypeTokens.setOf(String.class));
+                codes = TypeCoercions.coerce(rawCodes, new TypeToken<Set<String>>() {});
             }
             configBag.put(LocationConfigKeys.ISO_3166, codes);
         }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ffe2ec/policy/src/main/java/brooklyn/enricher/HttpLatencyDetector.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/enricher/HttpLatencyDetector.java b/policy/src/main/java/brooklyn/enricher/HttpLatencyDetector.java
index bd1dd00..70502e9 100644
--- a/policy/src/main/java/brooklyn/enricher/HttpLatencyDetector.java
+++ b/policy/src/main/java/brooklyn/enricher/HttpLatencyDetector.java
@@ -44,7 +44,6 @@ import brooklyn.event.feed.http.HttpPollConfig;
 import brooklyn.event.feed.http.HttpValueFunctions;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.flags.SetFromFlag;
-import brooklyn.util.guava.TypeTokens;
 import brooklyn.util.javalang.AtomicReferences;
 import brooklyn.util.javalang.Boxing;
 import brooklyn.util.javalang.JavaClassNames;
@@ -78,9 +77,10 @@ public class HttpLatencyDetector extends AbstractEnricher {
     @SetFromFlag("urlSensor")
     public static final ConfigKey<AttributeSensor<String>> URL_SENSOR = ConfigKeys.newConfigKey(new TypeToken<AttributeSensor<String>>() {}, "latencyDetector.urlSensor");
 
+    @SuppressWarnings("serial")
     @SetFromFlag("urlPostProcessing")
     public static final ConfigKey<Function<String,String>> URL_POST_PROCESSING = ConfigKeys.newConfigKey(
-            TypeTokens.functionOf(String.class, String.class), 
+            new TypeToken<Function<String,String>>() {}, 
             "latencyDetector.urlPostProcessing",
             "Function applied to the urlSensor value, to determine the URL to use");
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ffe2ec/utils/common/src/main/java/brooklyn/util/guava/TypeTokens.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/guava/TypeTokens.java b/utils/common/src/main/java/brooklyn/util/guava/TypeTokens.java
index ee7099b..ca69a97 100644
--- a/utils/common/src/main/java/brooklyn/util/guava/TypeTokens.java
+++ b/utils/common/src/main/java/brooklyn/util/guava/TypeTokens.java
@@ -18,13 +18,8 @@
  */
 package brooklyn.util.guava;
 
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
 import javax.annotation.Nullable;
 
-import com.google.common.base.Function;
 import com.google.common.reflect.TypeToken;
 
 public class TypeTokens {
@@ -73,25 +68,5 @@ public class TypeTokens {
     public static <T> Class<T> getRawRawType(TypeToken<T> token) {
         return (Class)token.getRawType();
     }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    public static <T> TypeToken<Set<T>> setOf(Class<T> type) {
-        return (TypeToken) TypeToken.of(Set.class);
-    }
-    
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    public static <K,V> TypeToken<Map<K,V>> mapOf(Class<K> key, Class<V> value) {
-        return (TypeToken) TypeToken.of(Map.class);
-    }
-    
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    public static <T> TypeToken<List<T>> listOf(Class<T> type) {
-        return (TypeToken) TypeToken.of(List.class);
-    }
-
-    @SuppressWarnings("serial")
-    public static <I,O> TypeToken<Function<I,O>> functionOf(Class<I> input, Class<O> output) {
-        return new TypeToken<Function<I,O>>() {};
-    }
     
 }


[08/11] git commit: improve startup logging, mainly saying where persistence is being done for reference, and moving OSGi timing to debug

Posted by he...@apache.org.
improve startup logging, mainly saying where persistence is being done for reference,
and moving OSGi timing to debug


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

Branch: refs/heads/master
Commit: 560514cdab2b37964d66d8368945f24d2d2ea582
Parents: bf627f7
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Aug 6 13:44:19 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Aug 6 13:44:19 2014 -0400

----------------------------------------------------------------------
 .../mementos/BrooklynMementoManifest.java       |  2 ++
 .../mementos/BrooklynMementoPersister.java      |  3 +++
 .../entity/rebind/RebindManagerImpl.java        | 21 ++++++++++++++------
 .../rebind/dto/BrooklynMementoManifestImpl.java |  6 ++++++
 .../AbstractBrooklynMementoPersister.java       |  6 ++++++
 .../BrooklynMementoPersisterToMultiFile.java    |  6 ++++++
 .../BrooklynMementoPersisterToObjectStore.java  |  5 +++++
 .../src/main/java/brooklyn/util/osgi/Osgis.java |  9 ++++-----
 8 files changed, 47 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/560514cd/api/src/main/java/brooklyn/mementos/BrooklynMementoManifest.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/mementos/BrooklynMementoManifest.java b/api/src/main/java/brooklyn/mementos/BrooklynMementoManifest.java
index 14c1a80..9fbaff3 100644
--- a/api/src/main/java/brooklyn/mementos/BrooklynMementoManifest.java
+++ b/api/src/main/java/brooklyn/mementos/BrooklynMementoManifest.java
@@ -36,4 +36,6 @@ public interface BrooklynMementoManifest extends Serializable {
 
     public Map<String, String> getEnricherIdToType();
 
+    public boolean isEmpty();
+    
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/560514cd/api/src/main/java/brooklyn/mementos/BrooklynMementoPersister.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/mementos/BrooklynMementoPersister.java b/api/src/main/java/brooklyn/mementos/BrooklynMementoPersister.java
index 7755ab6..4b4adcd 100644
--- a/api/src/main/java/brooklyn/mementos/BrooklynMementoPersister.java
+++ b/api/src/main/java/brooklyn/mementos/BrooklynMementoPersister.java
@@ -71,6 +71,8 @@ public interface BrooklynMementoPersister {
     @VisibleForTesting
     void waitForWritesCompleted(long timeout, TimeUnit unit) throws InterruptedException, TimeoutException;
 
+    String getBackingStoreDescription();
+    
     public interface Delta {
         Collection<LocationMemento> locations();
         Collection<EntityMemento> entities();
@@ -81,4 +83,5 @@ public interface BrooklynMementoPersister {
         Collection<String> removedPolicyIds();
         Collection<String> removedEnricherIds();
     }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/560514cd/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java b/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
index 2bd121c..2116ae6 100644
--- a/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
+++ b/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
@@ -301,6 +301,13 @@ public class RebindManagerImpl implements RebindManager {
             //
             
             BrooklynMementoManifest mementoManifest = persister.loadMementoManifest(exceptionHandler);
+            
+            boolean isEmpty = mementoManifest.isEmpty();
+            if (!isEmpty) {
+                LOG.info("Rebinding from "+getPersister().getBackingStoreDescription()+"...");
+            } else {
+                LOG.info("Rebind check: no existing state; will persist new items to "+getPersister().getBackingStoreDescription());
+            }
 
             // Instantiate locations
             LOG.debug("RebindManager instantiating locations: {}", mementoManifest.getLocationIdToType().keySet());
@@ -516,12 +523,14 @@ public class RebindManagerImpl implements RebindManager {
             
             exceptionHandler.onDone();
 
-            LOG.info("Rebind complete: {} app{}, {} entit{}, {} location{}, {} polic{}, {} enricher{}", new Object[]{
-                apps.size(), Strings.s(apps),
-                entities.size(), Strings.ies(entities),
-                locations.size(), Strings.s(locations),
-                policies.size(), Strings.ies(policies),
-                enrichers.size(), Strings.s(enrichers) });
+            if (!isEmpty) {
+                LOG.info("Rebind complete: {} app{}, {} entit{}, {} location{}, {} polic{}, {} enricher{}", new Object[]{
+                    apps.size(), Strings.s(apps),
+                    entities.size(), Strings.ies(entities),
+                    locations.size(), Strings.s(locations),
+                    policies.size(), Strings.ies(policies),
+                    enrichers.size(), Strings.s(enrichers) });
+            }
 
             // Return the top-level applications
             LOG.debug("RebindManager complete; return apps: {}", memento.getApplicationIds());

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/560514cd/core/src/main/java/brooklyn/entity/rebind/dto/BrooklynMementoManifestImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/dto/BrooklynMementoManifestImpl.java b/core/src/main/java/brooklyn/entity/rebind/dto/BrooklynMementoManifestImpl.java
index e08bc86..ca765f3 100644
--- a/core/src/main/java/brooklyn/entity/rebind/dto/BrooklynMementoManifestImpl.java
+++ b/core/src/main/java/brooklyn/entity/rebind/dto/BrooklynMementoManifestImpl.java
@@ -104,4 +104,10 @@ public class BrooklynMementoManifestImpl implements BrooklynMementoManifest, Ser
     public Map<String, String> getEnricherIdToType() {
         return Collections.unmodifiableMap(enricherIdToType);
     }
+    
+    @Override
+    public boolean isEmpty() {
+        return entityIdToType.isEmpty() && locationIdToType.isEmpty() && policyIdToType.isEmpty() && enricherIdToType.isEmpty();
+    }
+    
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/560514cd/core/src/main/java/brooklyn/entity/rebind/persister/AbstractBrooklynMementoPersister.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/persister/AbstractBrooklynMementoPersister.java b/core/src/main/java/brooklyn/entity/rebind/persister/AbstractBrooklynMementoPersister.java
index 6fc080e..3ef5220 100644
--- a/core/src/main/java/brooklyn/entity/rebind/persister/AbstractBrooklynMementoPersister.java
+++ b/core/src/main/java/brooklyn/entity/rebind/persister/AbstractBrooklynMementoPersister.java
@@ -85,4 +85,10 @@ public abstract class AbstractBrooklynMementoPersister implements BrooklynMement
         memento.updatePolicyMementos(delta.policies());
         memento.updateEnricherMementos(delta.enrichers());
     }
+    
+    @Override
+    public String getBackingStoreDescription() {
+        return toString();
+    }
+    
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/560514cd/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToMultiFile.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToMultiFile.java b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToMultiFile.java
index e587964..2e87de3 100644
--- a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToMultiFile.java
+++ b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToMultiFile.java
@@ -489,4 +489,10 @@ public class BrooklynMementoPersisterToMultiFile implements BrooklynMementoPersi
     private File getFileFor(EnricherMemento enricher) {
         return new File(enrichersDir, enricher.getId());
     }
+    
+    @Override
+    public String getBackingStoreDescription() {
+        return toString();
+    }
+    
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/560514cd/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToObjectStore.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToObjectStore.java b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToObjectStore.java
index 838f252..0a62332 100644
--- a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToObjectStore.java
+++ b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToObjectStore.java
@@ -562,5 +562,10 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
     private String getPath(String subPath, String id) {
         return subPath+"/"+id;
     }
+
+    @Override
+    public String getBackingStoreDescription() {
+        return getObjectStore().getSummaryName();
+    }
     
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/560514cd/core/src/main/java/brooklyn/util/osgi/Osgis.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/osgi/Osgis.java b/core/src/main/java/brooklyn/util/osgi/Osgis.java
index c557a92..2df3fbf 100644
--- a/core/src/main/java/brooklyn/util/osgi/Osgis.java
+++ b/core/src/main/java/brooklyn/util/osgi/Osgis.java
@@ -61,12 +61,13 @@ import brooklyn.util.guava.Maybe;
 import brooklyn.util.net.Urls;
 import brooklyn.util.os.Os;
 import brooklyn.util.stream.Streams;
-import brooklyn.util.text.Strings;
+import brooklyn.util.time.Duration;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Joiner;
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
+import com.google.common.base.Stopwatch;
 
 /** 
  * utilities for working with osgi.
@@ -168,7 +169,7 @@ public class Osgis {
         if (felixCacheDir!=null) cfg.put(Constants.FRAMEWORK_STORAGE, felixCacheDir);
         FrameworkFactory factory = newFrameworkFactory();
 
-        long frameworkInitStart = System.currentTimeMillis();
+        Stopwatch timer = Stopwatch.createStarted();
         Framework framework = factory.newFramework(cfg);
         try {
             framework.init();
@@ -178,9 +179,7 @@ public class Osgis {
             // framework bundle start exceptions are not interesting to caller...
             throw Exceptions.propagate(e);
         }
-        long frameworkInitEnd = System.currentTimeMillis();
-        double frameworkInitSeconds = ((double)frameworkInitEnd - frameworkInitStart) / 1000;
-        LOG.info("OSGi framework started in " + Strings.makeRealString(frameworkInitSeconds, -1, 2, -1) + " seconds.");
+        LOG.debug("OSGi framework started in " + Duration.of(timer) + " seconds.");
 
         return framework;
     }


[03/11] git commit: add tags to BrooklynObject and to specs, with tests that they get set and can be queried for all BO subtypes; other cleanup to testing and deprection

Posted by he...@apache.org.
add tags to BrooklynObject and to specs, with tests that they get set and can be queried for all BO subtypes; other cleanup to testing and deprection


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

Branch: refs/heads/master
Commit: 72b52e1d0db028caa654c6169ec829d0bed7af9e
Parents: 4bbf3b4
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Aug 1 17:58:49 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Aug 5 10:40:41 2014 -0400

----------------------------------------------------------------------
 .../basic/AbstractBrooklynObjectSpec.java       |  20 ++
 .../java/brooklyn/basic/BrooklynObject.java     |  14 ++
 .../brooklyn/entity/proxying/EntitySpec.java    |   1 +
 .../main/java/brooklyn/policy/EnricherSpec.java |   5 +
 .../java/brooklyn/policy/EntityAdjunct.java     |  31 ++-
 .../main/java/brooklyn/policy/PolicySpec.java   |   5 +
 .../brooklyn/basic/AbstractBrooklynObject.java  |  53 +++++
 .../enricher/basic/AbstractEnricher.java        |   5 +-
 .../brooklyn/entity/basic/AbstractEntity.java   |  37 +---
 .../entity/proxying/InternalEntityFactory.java  |   3 +
 .../proxying/InternalLocationFactory.java       |   4 +-
 .../entity/proxying/InternalPolicyFactory.java  |   4 +
 .../rebind/BasicLocationRebindSupport.java      |   2 +-
 .../location/basic/AbstractLocation.java        |  49 ++--
 .../policy/basic/AbstractEntityAdjunct.java     |  26 ++-
 .../brooklyn/policy/basic/AbstractPolicy.java   |   8 +-
 .../enricher/basic/BasicEnricherTest.java       |  93 ++++++++
 .../enricher/basic/EnricherConfigTest.java      | 148 +++++++++++++
 .../brooklyn/entity/basic/EntitiesTest.java     |   6 +-
 .../location/basic/AbstractLocationTest.java    |   9 +-
 .../location/basic/LocationConfigTest.java      |   3 +
 .../brooklyn/policy/basic/BasicPolicyTest.java  |  89 ++++++++
 .../policy/basic/EnricherConfigTest.java        | 169 --------------
 .../policy/basic/PolicyConfigMapUsageTest.java  | 222 -------------------
 .../brooklyn/policy/basic/PolicyConfigTest.java | 202 +++++++++++++++++
 .../BrooklynAssemblyTemplateInstantiator.java   |   1 +
 .../java/brooklyn/util/guava/TypeTokens.java    |  19 ++
 27 files changed, 776 insertions(+), 452 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b52e1d/api/src/main/java/brooklyn/basic/AbstractBrooklynObjectSpec.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/basic/AbstractBrooklynObjectSpec.java b/api/src/main/java/brooklyn/basic/AbstractBrooklynObjectSpec.java
index d61e016..dc6642f 100644
--- a/api/src/main/java/brooklyn/basic/AbstractBrooklynObjectSpec.java
+++ b/api/src/main/java/brooklyn/basic/AbstractBrooklynObjectSpec.java
@@ -20,10 +20,14 @@ package brooklyn.basic;
 
 import java.io.Serializable;
 import java.lang.reflect.Modifier;
+import java.util.Set;
 
+import brooklyn.util.collections.MutableSet;
 import brooklyn.util.exceptions.Exceptions;
 
 import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
 
 public abstract class AbstractBrooklynObjectSpec<T,K extends AbstractBrooklynObjectSpec<T,K>> implements Serializable {
 
@@ -31,6 +35,7 @@ public abstract class AbstractBrooklynObjectSpec<T,K extends AbstractBrooklynObj
     
     private final Class<T> type;
     private String displayName;
+    private Set<Object> tags = MutableSet.of();
 
     protected AbstractBrooklynObjectSpec(Class<T> type) {
         checkValidType(type);
@@ -54,6 +59,17 @@ public abstract class AbstractBrooklynObjectSpec<T,K extends AbstractBrooklynObj
         return self();
     }
     
+    public K tag(Object tag) {
+        tags.add(tag);
+        return self();
+    }
+
+    /** adds the given tags */
+    public K tags(Iterable<Object> tagsToAdd) {
+        Iterables.addAll(this.tags, tagsToAdd);
+        return self();
+    }
+
     /**
      * @return The type of the enricher
      */
@@ -68,6 +84,10 @@ public abstract class AbstractBrooklynObjectSpec<T,K extends AbstractBrooklynObj
         return displayName;
     }
 
+    public final Set<Object> getTags() {
+        return ImmutableSet.copyOf(tags);
+    }
+
     // TODO Duplicates method in BasicEntityTypeRegistry and InternalEntityFactory.isNewStyleEntity
     protected final void checkIsNewStyleImplementation(Class<?> implClazz) {
         try {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b52e1d/api/src/main/java/brooklyn/basic/BrooklynObject.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/basic/BrooklynObject.java b/api/src/main/java/brooklyn/basic/BrooklynObject.java
index 9e22f96..dd26528 100644
--- a/api/src/main/java/brooklyn/basic/BrooklynObject.java
+++ b/api/src/main/java/brooklyn/basic/BrooklynObject.java
@@ -18,14 +18,28 @@
  */
 package brooklyn.basic;
 
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+
 import brooklyn.entity.trait.Identifiable;
 
 /**
  * Super-type of entity, location, policy and enricher.
  */
 public interface BrooklynObject extends Identifiable {
+    
     /**
      * A display name; recommended to be a concise single-line description.
      */
     String getDisplayName();
+    
+    /**
+     * A set of tags associated to this adjunct.
+     */
+    @Nonnull Set<Object> getTags();
+
+    /** whether the given object is contained as a tag */
+    boolean containsTag(Object tag);
+    
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b52e1d/api/src/main/java/brooklyn/entity/proxying/EntitySpec.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/entity/proxying/EntitySpec.java b/api/src/main/java/brooklyn/entity/proxying/EntitySpec.java
index daaa6c8..7410266 100644
--- a/api/src/main/java/brooklyn/entity/proxying/EntitySpec.java
+++ b/api/src/main/java/brooklyn/entity/proxying/EntitySpec.java
@@ -106,6 +106,7 @@ public class EntitySpec<T extends Entity> extends AbstractBrooklynObjectSpec<T,E
     public static <T extends Entity> EntitySpec<T> create(EntitySpec<T> spec) {
         EntitySpec<T> result = create(spec.getType())
                 .displayName(spec.getDisplayName())
+                .tags(spec.getTags())
                 .additionalInterfaces(spec.getAdditionalInterfaces())
                 .configure(spec.getConfig())
                 .configure(spec.getFlags())

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b52e1d/api/src/main/java/brooklyn/policy/EnricherSpec.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/policy/EnricherSpec.java b/api/src/main/java/brooklyn/policy/EnricherSpec.java
index 43f1a85..f2cfdd4 100644
--- a/api/src/main/java/brooklyn/policy/EnricherSpec.java
+++ b/api/src/main/java/brooklyn/policy/EnricherSpec.java
@@ -84,6 +84,11 @@ public class EnricherSpec<T extends Enricher> extends AbstractBrooklynObjectSpec
         checkIsNewStyleImplementation(type);
     }
     
+    public EnricherSpec<T> uniqueTag(String uniqueTag) {
+        flags.put("uniqueTag", uniqueTag);
+        return this;
+    }
+    
     public EnricherSpec<T> configure(Map<?,?> val) {
         for (Map.Entry<?, ?> entry: val.entrySet()) {
             if (entry.getKey()==null) throw new NullPointerException("Null key not permitted");

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b52e1d/api/src/main/java/brooklyn/policy/EntityAdjunct.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/policy/EntityAdjunct.java b/api/src/main/java/brooklyn/policy/EntityAdjunct.java
index fa05a2a..97acc08 100644
--- a/api/src/main/java/brooklyn/policy/EntityAdjunct.java
+++ b/api/src/main/java/brooklyn/policy/EntityAdjunct.java
@@ -18,15 +18,20 @@
  */
 package brooklyn.policy;
 
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
 import brooklyn.basic.BrooklynObject;
 
 /**
- * EntityAdjuncts are supplementary logic that can be attached to Entities, providing sensor enrichment
- * or enabling policy
+ * EntityAdjuncts are supplementary logic that can be attached to Entities, 
+ * such as providing sensor enrichment or event-driven policy behavior
  */
 public interface EntityAdjunct extends BrooklynObject {
     /**
-     * A unique id for this adjunct
+     * A unique id for this adjunct, typically created by the system with no meaning
      */
     @Override
     String getId();
@@ -43,7 +48,25 @@ public interface EntityAdjunct extends BrooklynObject {
     boolean isDestroyed();
     
     /**
-     * Whether the adjunct is available
+     * Whether the adjunct is available/active
      */
     boolean isRunning();
+    
+    /**
+     * An optional tag used to identify adjuncts with a specific purpose, typically created by the caller.
+     * This is used to prevent multiple instances with the same purpose from being created,
+     * and to access and customize adjuncts so created.
+     * <p>
+     * This will be included in the call to {@link #getTags()}.
+     */
+    @Nullable String getUniqueTag();
+    
+    /**
+     * A set of tags associated to this adjunct.
+     * <p>
+     * This will include {@link #getUniqueTag()} if that is set.
+     */
+    @Override
+    @Nonnull Set<Object> getTags();
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b52e1d/api/src/main/java/brooklyn/policy/PolicySpec.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/policy/PolicySpec.java b/api/src/main/java/brooklyn/policy/PolicySpec.java
index ccce6e0..13206cf 100644
--- a/api/src/main/java/brooklyn/policy/PolicySpec.java
+++ b/api/src/main/java/brooklyn/policy/PolicySpec.java
@@ -84,6 +84,11 @@ public class PolicySpec<T extends Policy> extends AbstractBrooklynObjectSpec<T,P
         checkIsNewStyleImplementation(type);
     }
     
+    public PolicySpec<T> uniqueTag(String uniqueTag) {
+        flags.put("uniqueTag", uniqueTag);
+        return this;
+    }
+
     public PolicySpec<T> configure(Map<?,?> val) {
         for (Map.Entry<?, ?> entry: val.entrySet()) {
             if (entry.getKey()==null) throw new NullPointerException("Null key not permitted");

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b52e1d/core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java b/core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java
index b64db51..e977fec 100644
--- a/core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java
+++ b/core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java
@@ -18,16 +18,69 @@
  */
 package brooklyn.basic;
 
+import java.util.Set;
+
 import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.text.Identifiers;
 
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+
 public abstract class AbstractBrooklynObject implements BrooklynObjectInternal {
 
     @SetFromFlag(value="id")
     private String id = Identifiers.makeRandomId(8);
     
+    /** subclasses should synchronize on this for all access */
+    @SetFromFlag(value="tags")
+    protected Set<Object> tags = Sets.newLinkedHashSet();
+    
     @Override
     public String getId() {
         return id;
     }
+    
+    @Override
+    public Set<Object> getTags() {
+        synchronized (tags) {
+            return ImmutableSet.copyOf(tags);
+        }
+    }
+
+    public boolean addTag(Object tag) {
+        boolean result;
+        synchronized (tags) {
+            result = tags.add(tag);
+        }
+        onTagsChanged();
+        return result;
+    }    
+
+    public boolean addTags(Iterable<Object> tags) {
+        boolean result;
+        synchronized (tags) {
+            result = Iterables.addAll(this.tags, tags);
+        }
+        onTagsChanged();
+        return result;
+    }    
+
+    public boolean removeTag(Object tag) {
+        boolean result;
+        synchronized (tags) {
+            result = tags.remove(tag);
+        }
+        onTagsChanged();
+        return result;
+    }    
+
+    public boolean containsTag(Object tag) {
+        synchronized (tags) {
+            return tags.contains(tag);
+        }
+    }    
+
+    protected abstract void onTagsChanged();
+    
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b52e1d/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java b/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
index 6368866..df6a370 100644
--- a/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
+++ b/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
@@ -41,7 +41,7 @@ public abstract class AbstractEnricher extends AbstractEntityAdjunct implements
         this(Maps.newLinkedHashMap());
     }
     
-    public AbstractEnricher(Map flags) {
+    public AbstractEnricher(Map<?,?> flags) {
         super(flags);
         enricherType = new EnricherTypeImpl(getAdjunctType());
         
@@ -62,9 +62,10 @@ public abstract class AbstractEnricher extends AbstractEntityAdjunct implements
 
     @Override
     protected void onChanged() {
-        // TODO Could add EnricherChangeListener, similar to EntityChangeListener; should we do that?
+        // currently changes simply trigger re-persistence; there is no intermediate listener as we do for EntityChangeListener
         if (getManagementContext() != null) {
             getManagementContext().getRebindManager().getChangeListener().onChanged(this);
         }
     }
+    
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b52e1d/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
index 9ebb62f..19bbea1 100644
--- a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
+++ b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
@@ -34,7 +34,6 @@ import brooklyn.basic.AbstractBrooklynObject;
 import brooklyn.config.ConfigKey;
 import brooklyn.config.ConfigKey.HasConfigKey;
 import brooklyn.enricher.basic.AbstractEnricher;
-import brooklyn.enricher.basic.Aggregator;
 import brooklyn.entity.Application;
 import brooklyn.entity.Effector;
 import brooklyn.entity.Entity;
@@ -71,7 +70,6 @@ import brooklyn.management.internal.SubscriptionTracker;
 import brooklyn.mementos.EntityMemento;
 import brooklyn.policy.Enricher;
 import brooklyn.policy.EnricherSpec;
-import brooklyn.policy.EntityAdjunct;
 import brooklyn.policy.Policy;
 import brooklyn.policy.PolicySpec;
 import brooklyn.policy.basic.AbstractEntityAdjunct;
@@ -91,7 +89,6 @@ import com.google.common.base.Objects;
 import com.google.common.base.Objects.ToStringHelper;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
@@ -175,7 +172,6 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E
     Map<String,Object> presentationAttributes = Maps.newLinkedHashMap();
     Collection<AbstractPolicy> policies = Lists.newCopyOnWriteArrayList();
     Collection<AbstractEnricher> enrichers = Lists.newCopyOnWriteArrayList();
-    Set<Object> tags = Sets.newLinkedHashSet();
 
     // FIXME we do not currently support changing parents, but to implement a cluster that can shrink we need to support at least
     // orphaning (i.e. removing ownership). This flag notes if the entity has previously had a parent, and if an attempt is made to
@@ -1330,38 +1326,9 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E
     }
 
     @Override
-    public Set<Object> getTags() {
-        synchronized (tags) {
-            return ImmutableSet.copyOf(tags);
-        }
-    }
-
-    @Override
-    public boolean addTag(Object tag) {
-        boolean result;
-        synchronized (tags) {
-            result = tags.add(tag);
-        }
+    protected void onTagsChanged() {
         getManagementSupport().getEntityChangeListener().onTagsChanged();
-        return result;
-    }    
-
-    @Override
-    public boolean removeTag(Object tag) {
-        boolean result;
-        synchronized (tags) {
-            result = tags.remove(tag);
-        }
-        getManagementSupport().getEntityChangeListener().onTagsChanged();
-        return result;
-    }    
-
-    @Override
-    public boolean containsTag(Object tag) {
-        synchronized (tags) {
-            return tags.contains(tag);
-        }
-    }    
+    }
     
     @Override
     protected void finalize() throws Throwable {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b52e1d/core/src/main/java/brooklyn/entity/proxying/InternalEntityFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/proxying/InternalEntityFactory.java b/core/src/main/java/brooklyn/entity/proxying/InternalEntityFactory.java
index b5d7c0a..9cc05c3 100644
--- a/core/src/main/java/brooklyn/entity/proxying/InternalEntityFactory.java
+++ b/core/src/main/java/brooklyn/entity/proxying/InternalEntityFactory.java
@@ -169,6 +169,7 @@ public class InternalEntityFactory extends InternalFactory {
         return entity;
     }
     
+    @SuppressWarnings("deprecation")
     protected <T extends Entity> T createEntityAndDescendantsUninitialized(EntitySpec<T> spec, Map<String,Entity> entitiesByEntityId, Map<String,EntitySpec<?>> specsByEntityId) {
         if (spec.getFlags().containsKey("parent") || spec.getFlags().containsKey("owner")) {
             throw new IllegalArgumentException("Spec's flags must not contain parent or owner; use spec.parent() instead for "+spec);
@@ -230,6 +231,7 @@ public class InternalEntityFactory extends InternalFactory {
             if (spec.getDisplayName()!=null)
                 ((AbstractEntity)entity).setDisplayName(spec.getDisplayName());
             
+            ((AbstractEntity)entity).addTags(spec.getTags());
             ((AbstractEntity)entity).configure(MutableMap.copyOf(spec.getFlags()));
             
             for (Map.Entry<ConfigKey<?>, Object> entry : spec.getConfig().entrySet()) {
@@ -320,6 +322,7 @@ public class InternalEntityFactory extends InternalFactory {
      * but that behaviour is deprecated.
      */
     public <T extends Entity> T constructEntity(Class<? extends T> clazz, EntitySpec<T> spec) {
+        @SuppressWarnings("deprecation")
         T entity = constructEntityImpl(clazz, spec.getFlags(), spec.getId());
         if (((AbstractEntity)entity).getProxy() == null) ((AbstractEntity)entity).setProxy(createEntityProxy(spec, entity));
         return entity;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b52e1d/core/src/main/java/brooklyn/entity/proxying/InternalLocationFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/proxying/InternalLocationFactory.java b/core/src/main/java/brooklyn/entity/proxying/InternalLocationFactory.java
index 804b5d5..6a7b599 100644
--- a/core/src/main/java/brooklyn/entity/proxying/InternalLocationFactory.java
+++ b/core/src/main/java/brooklyn/entity/proxying/InternalLocationFactory.java
@@ -95,7 +95,9 @@ public class InternalLocationFactory extends InternalFactory {
             managementContext.prePreManage(loc);
 
             if (spec.getDisplayName()!=null)
-                ((AbstractLocation)loc).setName(spec.getDisplayName());
+                ((AbstractLocation)loc).setDisplayName(spec.getDisplayName());
+            
+            ((AbstractLocation)loc).addTags(spec.getTags());
             
             if (isNewStyleLocation(clazz)) {
                 ((AbstractLocation)loc).setManagementContext(managementContext);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b52e1d/core/src/main/java/brooklyn/entity/proxying/InternalPolicyFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/proxying/InternalPolicyFactory.java b/core/src/main/java/brooklyn/entity/proxying/InternalPolicyFactory.java
index ebf13dd..76dd312 100644
--- a/core/src/main/java/brooklyn/entity/proxying/InternalPolicyFactory.java
+++ b/core/src/main/java/brooklyn/entity/proxying/InternalPolicyFactory.java
@@ -94,6 +94,8 @@ public class InternalPolicyFactory extends InternalFactory {
             if (spec.getDisplayName()!=null)
                 ((AbstractPolicy)pol).setDisplayName(spec.getDisplayName());
             
+            ((AbstractPolicy)pol).addTags(spec.getTags());
+            
             if (isNewStylePolicy(clazz)) {
                 ((AbstractPolicy)pol).setManagementContext(managementContext);
                 Map<String, Object> config = ConfigBag.newInstance().putAll(spec.getFlags()).putAll(spec.getConfig()).getAllConfig();
@@ -129,6 +131,8 @@ public class InternalPolicyFactory extends InternalFactory {
             if (spec.getDisplayName()!=null)
                 ((AbstractEnricher)enricher).setDisplayName(spec.getDisplayName());
             
+            ((AbstractEnricher)enricher).addTags(spec.getTags());
+            
             if (isNewStyleEnricher(clazz)) {
                 ((AbstractEnricher)enricher).setManagementContext(managementContext);
                 Map<String, Object> config = ConfigBag.newInstance().putAll(spec.getFlags()).putAll(spec.getConfig()).getAllConfig();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b52e1d/core/src/main/java/brooklyn/entity/rebind/BasicLocationRebindSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/BasicLocationRebindSupport.java b/core/src/main/java/brooklyn/entity/rebind/BasicLocationRebindSupport.java
index 7e930ef..157ccca 100644
--- a/core/src/main/java/brooklyn/entity/rebind/BasicLocationRebindSupport.java
+++ b/core/src/main/java/brooklyn/entity/rebind/BasicLocationRebindSupport.java
@@ -69,7 +69,7 @@ public class BasicLocationRebindSupport implements RebindSupport<LocationMemento
     	
     	// Note that the flags have been set in the constructor
         // FIXME Relies on location.getLocalConfigBag being mutable (to modify the location's own config)
-        location.setName(memento.getDisplayName());
+        location.setDisplayName(memento.getDisplayName());
         
         location.getLocalConfigBag().putAll(memento.getLocationConfig()).markAll(
                 Sets.difference(memento.getLocationConfig().keySet(), memento.getLocationConfigUnused())).

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b52e1d/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/location/basic/AbstractLocation.java b/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
index 651a46b..e517d10 100644
--- a/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
+++ b/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
@@ -57,6 +57,7 @@ import brooklyn.util.collections.SetFromLiveMap;
 import brooklyn.util.config.ConfigBag;
 import brooklyn.util.flags.FlagUtils;
 import brooklyn.util.flags.TypeCoercions;
+import brooklyn.util.guava.TypeTokens;
 import brooklyn.util.stream.Streams;
 
 import com.google.common.base.Objects;
@@ -78,6 +79,8 @@ import com.google.common.collect.Sets;
  */
 public abstract class AbstractLocation extends AbstractBrooklynObject implements LocationInternal, HasHostGeoInfo, Configurable {
     
+    private static final long serialVersionUID = -7495805474138619830L;
+
     /** @deprecated since 0.7.0 shouldn't be public */
     @Deprecated
     public static final Logger LOG = LoggerFactory.getLogger(AbstractLocation.class);
@@ -138,7 +141,8 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
      * <li>abbreviatedName
      * </ul>
      */
-    public AbstractLocation(Map properties) {
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public AbstractLocation(Map<?,?> properties) {
         inConstruction = true;
         _legacyConstruction = !InternalFactory.FactoryConstructionTracker.isConstructing();
         if (!_legacyConstruction && properties!=null && !properties.isEmpty()) {
@@ -233,8 +237,8 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
      * in this class, so initializers in subclasses will not have run when this overridden 
      * method is invoked.) If you require fields to be initialized you must do that in 
      * this method with a guard (as in FixedListMachineProvisioningLocation).
-     */ 
-    public void configure(Map properties) {
+     */
+    public void configure(Map<?,?> properties) {
         assertNotYetManaged();
         
         boolean firstTime = !configured.getAndSet(true);
@@ -272,7 +276,7 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
             if (rawCodes instanceof CharSequence) {
                 codes = ImmutableSet.copyOf(Splitter.on(",").trimResults().split((CharSequence)rawCodes));
             } else {
-                codes = TypeCoercions.coerce(rawCodes, Set.class);
+                codes = TypeCoercions.coerce(rawCodes, TypeTokens.setOf(String.class));
             }
             configBag.put(LocationConfigKeys.ISO_3166, codes);
         }
@@ -280,7 +284,7 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
 
     // TODO ensure no callers rely on 'remove' semantics, and don't remove;
     // or perhaps better use a config bag so we know what is used v unused
-    private static Object removeIfPossible(Map map, Object key) {
+    private static Object removeIfPossible(Map<?,?> map, Object key) {
         try {
             return map.remove(key);
         } catch (Exception e) {
@@ -385,6 +389,8 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
             parent.set(newParent);
             ((AbstractLocation)parent.get()).addChild(this); // FIXME Nasty cast
         }
+        
+        onChanged();
     }
 
     @Override
@@ -399,6 +405,7 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
         
         // In case this entity class has overridden the given key (e.g. to set default), then retrieve this entity's key
         // TODO when locations become entities, the duplication of this compared to EntityConfigMap.getConfig will disappear.
+        @SuppressWarnings("unchecked")
         ConfigKey<T> ownKey = (ConfigKey<T>) elvis(entityType.getConfigKey(key.getName()), key);
 
         return ownKey.getDefaultValue();
@@ -442,18 +449,15 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
     
     @Override
     public <T> T setConfig(ConfigKey<T> key, T value) {
-        return configBag.put(key, value);
-    }
-
-    /** @since 0.6.0 (?) - use getDisplayName */
-    public void setName(String newName) {
-        setDisplayName(newName);
-        displayNameAutoGenerated = false;
+        T result = configBag.put(key, value);
+        onChanged();
+        return result;
     }
 
     public void setDisplayName(String newName) {
         name.set(newName);
         displayNameAutoGenerated = false;
+        onChanged();
     }
 
     @Override
@@ -487,6 +491,7 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
         return child;
     }
     
+    @SuppressWarnings("deprecation")
     public void addChild(Location child) {
     	// Previously, setParent delegated to addChildLocation and we sometimes ended up with
     	// duplicate entries here. Instead this now uses a similar scheme to 
@@ -508,7 +513,10 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
         }
         
         if (isManaged()) {
-            Locations.manage(child, managementContext);
+            if (!managementContext.getLocationManager().isManaged(child)) {
+                // this deprecated call should be replaced with an internal interface call?
+                managementContext.getLocationManager().manage(child);
+            }
         } else if (managementContext != null) {
             if (((LocalLocationManager)managementContext.getLocationManager()).getLocationEvenIfPreManaged(child.getId()) == null) {
                 ((ManagementContextInternal)managementContext).prePreManage(child);
@@ -517,6 +525,8 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
 
         children.add(child);
         child.setParent(this);
+        
+        onChanged();
     }
     
     public boolean removeChild(Location child) {
@@ -534,9 +544,22 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
                 managementContext.getLocationManager().unmanage(child);
             }
         }
+        onChanged();
         return removed;
     }
 
+    @Override
+    protected void onTagsChanged() {
+        onChanged();
+    }
+
+    protected void onChanged() {
+        // currently changes simply trigger re-persistence; there is no intermediate listener as we do for EntityChangeListener
+        if (getManagementContext() != null) {
+            getManagementContext().getRebindManager().getChangeListener().onChanged(this);
+        }
+    }
+
     /** Default String representation is simplified name of class, together with selected fields. */
     @Override
     public String toString() {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b52e1d/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java b/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
index 9ca0e91..a53d9a5 100644
--- a/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
+++ b/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
@@ -26,6 +26,7 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.slf4j.Logger;
@@ -59,6 +60,7 @@ import brooklyn.util.flags.TypeCoercions;
 import com.google.common.annotations.Beta;
 import com.google.common.base.Objects;
 import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Maps;
 
 
@@ -97,6 +99,9 @@ public abstract class AbstractEntityAdjunct extends AbstractBrooklynObject imple
     protected transient SubscriptionTracker _subscriptionTracker;
     
     private AtomicBoolean destroyed = new AtomicBoolean(false);
+    
+    @SetFromFlag(value="uniqueTag")
+    protected String uniqueTag;
 
     public AbstractEntityAdjunct() {
         this(Collections.emptyMap());
@@ -262,6 +267,11 @@ public abstract class AbstractEntityAdjunct extends AbstractBrooklynObject imple
         throw new UnsupportedOperationException("reconfiguring "+key+" unsupported for "+this);
     }
     
+    @Override
+    protected void onTagsChanged() {
+        onChanged();
+    }
+    
     protected abstract void onChanged();
     
     protected AdjunctType getAdjunctType() {
@@ -397,11 +407,25 @@ public abstract class AbstractEntityAdjunct extends AbstractBrooklynObject imple
     public boolean isRunning() {
         return !isDestroyed();
     }
+
+    @Override
+    public String getUniqueTag() {
+        return uniqueTag;
+    }
+    
+    @Override
+    public Set<Object> getTags() {
+        if (getUniqueTag()==null) return super.getTags();
+        synchronized (tags) {
+            return ImmutableSet.builder().addAll(tags).add(getUniqueTag()).build();
+        }
+    }
     
     @Override
     public String toString() {
-        return Objects.toStringHelper(getClass())
+        return Objects.toStringHelper(getClass()).omitNullValues()
                 .add("name", name)
+                .add("uniqueTag", uniqueTag)
                 .add("running", isRunning())
                 .add("id", getId())
                 .toString();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b52e1d/core/src/main/java/brooklyn/policy/basic/AbstractPolicy.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/policy/basic/AbstractPolicy.java b/core/src/main/java/brooklyn/policy/basic/AbstractPolicy.java
index 70fa44b..79269c6 100644
--- a/core/src/main/java/brooklyn/policy/basic/AbstractPolicy.java
+++ b/core/src/main/java/brooklyn/policy/basic/AbstractPolicy.java
@@ -54,7 +54,7 @@ public abstract class AbstractPolicy extends AbstractEntityAdjunct implements Po
         this(Collections.emptyMap());
     }
     
-    public AbstractPolicy(Map flags) {
+    public AbstractPolicy(Map<?,?> flags) {
         super(flags);
         policyType = new PolicyTypeImpl(getAdjunctType());
         
@@ -80,6 +80,10 @@ public abstract class AbstractPolicy extends AbstractEntityAdjunct implements Po
 
     @Override
     public boolean isSuspended() {
+        if (suspended==null) {
+            // only if accessed during construction in super, e.g. by a call to toString in configure
+            return true;
+        }
         return suspended.get();
     }
 
@@ -96,7 +100,7 @@ public abstract class AbstractPolicy extends AbstractEntityAdjunct implements Po
 
     @Override
     protected void onChanged() {
-        // TODO Could add PolicyChangeListener, similar to EntityChangeListener; should we do that?
+        // currently changes simply trigger re-persistence; there is no intermediate listener as we do for EntityChangeListener
         if (getManagementContext() != null) {
             getManagementContext().getRebindManager().getChangeListener().onChanged(this);
         }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b52e1d/core/src/test/java/brooklyn/enricher/basic/BasicEnricherTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/enricher/basic/BasicEnricherTest.java b/core/src/test/java/brooklyn/enricher/basic/BasicEnricherTest.java
new file mode 100644
index 0000000..9d0fcf2
--- /dev/null
+++ b/core/src/test/java/brooklyn/enricher/basic/BasicEnricherTest.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package brooklyn.enricher.basic;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.Map;
+
+import org.testng.annotations.Test;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.enricher.basic.AbstractEnricher;
+import brooklyn.entity.BrooklynAppUnitTestSupport;
+import brooklyn.event.basic.BasicConfigKey;
+import brooklyn.policy.EnricherSpec;
+import brooklyn.util.collections.MutableSet;
+import brooklyn.util.flags.SetFromFlag;
+
+/**
+ * Test that enricher can be created and accessed, by construction and by spec
+ */
+public class BasicEnricherTest extends BrooklynAppUnitTestSupport {
+    
+    // TODO These tests are a copy of BasicPolicyTest, which is a code smell.
+    // However, the src/main/java code does not contain as much duplication.
+    
+    public static class MyEnricher extends AbstractEnricher {
+        @SetFromFlag("intKey")
+        public static final BasicConfigKey<Integer> INT_KEY = new BasicConfigKey<Integer>(Integer.class, "bkey", "b key");
+        
+        @SetFromFlag("strKey")
+        public static final ConfigKey<String> STR_KEY = new BasicConfigKey<String>(String.class, "akey", "a key");
+        public static final ConfigKey<Integer> INT_KEY_WITH_DEFAULT = new BasicConfigKey<Integer>(Integer.class, "ckey", "c key", 1);
+        public static final ConfigKey<String> STR_KEY_WITH_DEFAULT = new BasicConfigKey<String>(String.class, "strKey", "str key", "str key default");
+        
+        MyEnricher(Map<?,?> flags) {
+            super(flags);
+        }
+        
+        public MyEnricher() {
+            super();
+        }
+    }
+    
+    @Test
+    public void testAddInstance() throws Exception {
+        MyEnricher enricher = new MyEnricher();
+        enricher.setDisplayName("Bob");
+        enricher.setConfig(MyEnricher.STR_KEY, "aval");
+        enricher.setConfig(MyEnricher.INT_KEY, 2);
+        app.addEnricher(enricher);
+        
+        assertEquals(enricher.getDisplayName(), "Bob");
+        assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "aval");
+        assertEquals(enricher.getConfig(MyEnricher.INT_KEY), (Integer)2);
+    }
+    
+    @Test
+    public void testAddSpec() throws Exception {
+        MyEnricher enricher = app.addEnricher(EnricherSpec.create(MyEnricher.class)
+            .displayName("Bob")
+            .configure(MyEnricher.STR_KEY, "aval").configure(MyEnricher.INT_KEY, 2));
+        
+        assertEquals(enricher.getDisplayName(), "Bob");
+        assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "aval");
+        assertEquals(enricher.getConfig(MyEnricher.INT_KEY), (Integer)2);
+    }
+        
+    @Test
+    public void testTagsFromSpec() throws Exception {
+        MyEnricher enricher = app.addEnricher(EnricherSpec.create(MyEnricher.class).tag(99).uniqueTag("x"));
+
+        assertEquals(enricher.getTags(), MutableSet.of("x", 99));
+        assertEquals(enricher.getUniqueTag(), "x");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b52e1d/core/src/test/java/brooklyn/enricher/basic/EnricherConfigTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/enricher/basic/EnricherConfigTest.java b/core/src/test/java/brooklyn/enricher/basic/EnricherConfigTest.java
new file mode 100644
index 0000000..03677d9
--- /dev/null
+++ b/core/src/test/java/brooklyn/enricher/basic/EnricherConfigTest.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 brooklyn.enricher.basic;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+import org.testng.annotations.Test;
+
+import brooklyn.enricher.basic.BasicEnricherTest.MyEnricher;
+import brooklyn.entity.BrooklynAppUnitTestSupport;
+import brooklyn.event.basic.BasicConfigKey;
+import brooklyn.util.collections.MutableMap;
+
+/**
+ * Test that configuration properties are usable and inherited correctly.
+ */
+public class EnricherConfigTest extends BrooklynAppUnitTestSupport {
+    
+    // TODO These tests are a copy of PolicyConfigTest, which is a code smell.
+    // However, the src/main/java code does not contain as much duplication.
+    
+    private BasicConfigKey<String> differentKey = new BasicConfigKey<String>(String.class, "differentkey", "diffval");
+
+    @Test
+    public void testConfigFlagsPassedInAtConstructionIsAvailable() throws Exception {
+        MyEnricher enricher = new MyEnricher(MutableMap.builder()
+                .put("strKey", "aval")
+                .put("intKey", 2)
+                .build());
+        app.addEnricher(enricher);
+        
+        assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "aval");
+        assertEquals(enricher.getConfig(MyEnricher.INT_KEY), (Integer)2);
+        // this is set, because key name matches annotation on STR_KEY
+        assertEquals(enricher.getConfig(MyEnricher.STR_KEY_WITH_DEFAULT), "aval");
+    }
+    
+    @Test
+    public void testUnknownConfigPassedInAtConstructionIsWarnedAndIgnored() throws Exception {
+        // TODO Also assert it's warned
+        MyEnricher enricher = new MyEnricher(MutableMap.builder()
+                .put(differentKey, "aval")
+                .build());
+        app.addEnricher(enricher);
+        
+        assertEquals(enricher.getConfig(differentKey), null);
+        assertEquals(enricher.getEnricherType().getConfigKey(differentKey.getName()), null);
+    }
+    
+    @Test
+    public void testConfigPassedInAtConstructionIsAvailable() throws Exception {
+        MyEnricher enricher = new MyEnricher(MutableMap.builder()
+                .put(MyEnricher.STR_KEY, "aval")
+                .put(MyEnricher.INT_KEY, 2)
+                .build());
+        app.addEnricher(enricher);
+        
+        assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "aval");
+        assertEquals(enricher.getConfig(MyEnricher.INT_KEY), (Integer)2);
+        // this is not set (contrast with above)
+        assertEquals(enricher.getConfig(MyEnricher.STR_KEY_WITH_DEFAULT), MyEnricher.STR_KEY_WITH_DEFAULT.getDefaultValue());
+    }
+    
+    @Test
+    public void testConfigSetToGroovyTruthFalseIsAvailable() throws Exception {
+        MyEnricher enricher = new MyEnricher(MutableMap.builder()
+                .put(MyEnricher.INT_KEY_WITH_DEFAULT, 0)
+                .build());
+        app.addEnricher(enricher);
+        
+        assertEquals(enricher.getConfig(MyEnricher.INT_KEY_WITH_DEFAULT), (Integer)0);
+    }
+    
+    @Test
+    public void testConfigSetToNullIsAvailable() throws Exception {
+        MyEnricher enricher = new MyEnricher(MutableMap.builder()
+                .put(MyEnricher.STR_KEY_WITH_DEFAULT, null)
+                .build());
+        app.addEnricher(enricher);
+        
+        assertEquals(enricher.getConfig(MyEnricher.STR_KEY_WITH_DEFAULT), null);
+    }
+    
+    @Test
+    public void testConfigCanBeSetOnEnricher() throws Exception {
+        MyEnricher enricher = new MyEnricher();
+        enricher.setConfig(MyEnricher.STR_KEY, "aval");
+        enricher.setConfig(MyEnricher.INT_KEY, 2);
+        app.addEnricher(enricher);
+        
+        assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "aval");
+        assertEquals(enricher.getConfig(MyEnricher.INT_KEY), (Integer)2);
+    }
+    
+    @Test
+    public void testConfigSetterOverridesConstructorValue() throws Exception {
+        MyEnricher enricher = new MyEnricher(MutableMap.builder()
+                .put(MyEnricher.STR_KEY, "aval")
+                .build());
+        enricher.setConfig(MyEnricher.STR_KEY, "diffval");
+        app.addEnricher(enricher);
+        
+        assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "diffval");
+    }
+
+    @Test
+    public void testConfigCannotBeSetAfterApplicationIsStarted() throws Exception {
+        MyEnricher enricher = new MyEnricher(MutableMap.builder()
+                .put(MyEnricher.STR_KEY, "origval")
+                .build());
+        app.addEnricher(enricher);
+        
+        try {
+            enricher.setConfig(MyEnricher.STR_KEY,"newval");
+            fail();
+        } catch (UnsupportedOperationException e) {
+            // success
+        }
+        
+        assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "origval");
+    }
+    
+    @Test
+    public void testConfigReturnsDefaultValueIfNotSet() throws Exception {
+        MyEnricher enricher = new MyEnricher();
+        app.addEnricher(enricher);
+        
+        assertEquals(enricher.getConfig(MyEnricher.STR_KEY_WITH_DEFAULT), "str key default");
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b52e1d/core/src/test/java/brooklyn/entity/basic/EntitiesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/basic/EntitiesTest.java b/core/src/test/java/brooklyn/entity/basic/EntitiesTest.java
index 8acdf72..e9b3399 100644
--- a/core/src/test/java/brooklyn/entity/basic/EntitiesTest.java
+++ b/core/src/test/java/brooklyn/entity/basic/EntitiesTest.java
@@ -107,14 +107,17 @@ public class EntitiesTest extends BrooklynAppUnitTestSupport {
     @Test
     public void testCreateGetContainsAndRemoveTags() throws Exception {
         entity = app.createAndManageChild(EntitySpec.create(TestEntity.class)
+            .tag(2)
             .addInitializer(EntityInitializers.addingTags("foo")));
         
         entity.addTag(app);
         
+        Assert.assertTrue(entity.containsTag(app));
         Assert.assertTrue(entity.containsTag("foo"));
+        Assert.assertTrue(entity.containsTag(2));
         Assert.assertFalse(entity.containsTag("bar"));
         
-        Assert.assertEquals(entity.getTags(), MutableSet.of(app, "foo"));
+        Assert.assertEquals(entity.getTags(), MutableSet.of(app, "foo", 2));
         
         entity.removeTag("foo");
         Assert.assertFalse(entity.containsTag("foo"));
@@ -122,6 +125,7 @@ public class EntitiesTest extends BrooklynAppUnitTestSupport {
         Assert.assertTrue(entity.containsTag(entity.getParent()));
         Assert.assertFalse(entity.containsTag(entity));
         
+        entity.removeTag(2);
         Assert.assertEquals(entity.getTags(), MutableSet.of(app));
     }
     

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b52e1d/core/src/test/java/brooklyn/location/basic/AbstractLocationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/location/basic/AbstractLocationTest.java b/core/src/test/java/brooklyn/location/basic/AbstractLocationTest.java
index 4993486..97fb633 100644
--- a/core/src/test/java/brooklyn/location/basic/AbstractLocationTest.java
+++ b/core/src/test/java/brooklyn/location/basic/AbstractLocationTest.java
@@ -36,6 +36,7 @@ import brooklyn.location.LocationSpec;
 import brooklyn.management.ManagementContext;
 import brooklyn.test.entity.LocalManagementContextForTests;
 import brooklyn.util.collections.MutableMap;
+import brooklyn.util.collections.MutableSet;
 import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.collect.ImmutableList;
@@ -172,5 +173,11 @@ public class AbstractLocationTest {
         ConcreteLocation loc = createConcrete();
         assertEquals(loc.myfield, "mydefault");
     }
-    
+
+    @Test
+    public void testLocationTags() throws Exception {
+        LocationInternal loc = mgmt.getLocationManager().createLocation(LocationSpec.create(ConcreteLocation.class).tag("x"));
+        assertEquals(loc.getTags(), MutableSet.of("x"));
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b52e1d/core/src/test/java/brooklyn/location/basic/LocationConfigTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/location/basic/LocationConfigTest.java b/core/src/test/java/brooklyn/location/basic/LocationConfigTest.java
index 3db4743..69f18a1 100644
--- a/core/src/test/java/brooklyn/location/basic/LocationConfigTest.java
+++ b/core/src/test/java/brooklyn/location/basic/LocationConfigTest.java
@@ -176,6 +176,7 @@ public class LocationConfigTest {
         assertEquals(subloc.getConfig(MyLocation.MY_CONFIG_WITH_DEFAULT), "mysubdefault");
     }
     
+    @SuppressWarnings("serial")
     public static class MyLocation extends AbstractLocation {
         public static final ConfigKey<String> MY_CONFIG = ConfigKeys.newStringConfigKey("mylocation.myconfig");
 
@@ -185,6 +186,7 @@ public class LocationConfigTest {
         public static final ConfigKey<String> MY_CONFIG_WITH_DEFAULT = ConfigKeys.newStringConfigKey("mylocation.myconfigwithdefault", "", "mydefault");
     }
     
+    @SuppressWarnings("serial")
     public static class MyChildLocation extends AbstractLocation {
         public static final ConfigKey<String> MY_CHILD_CONFIG = ConfigKeys.newStringConfigKey("mychildlocation.myconfig");
 
@@ -192,6 +194,7 @@ public class LocationConfigTest {
         public static final ConfigKey<String> MY_CHILD_CONFIG_WITH_FLAGNAME = ConfigKeys.newStringConfigKey("mychildlocation.myconfigwithflagname");
     }
     
+    @SuppressWarnings("serial")
     public static class MySubLocation extends MyLocation {
         public static final ConfigKey<String> MY_CONFIG_WITH_DEFAULT = ConfigKeys.newConfigKeyWithDefault(MyLocation.MY_CONFIG_WITH_DEFAULT, "mysubdefault");
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b52e1d/core/src/test/java/brooklyn/policy/basic/BasicPolicyTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/policy/basic/BasicPolicyTest.java b/core/src/test/java/brooklyn/policy/basic/BasicPolicyTest.java
new file mode 100644
index 0000000..1072bc8
--- /dev/null
+++ b/core/src/test/java/brooklyn/policy/basic/BasicPolicyTest.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package brooklyn.policy.basic;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.Map;
+
+import org.testng.annotations.Test;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.BrooklynAppUnitTestSupport;
+import brooklyn.event.basic.BasicConfigKey;
+import brooklyn.policy.PolicySpec;
+import brooklyn.util.collections.MutableSet;
+import brooklyn.util.flags.SetFromFlag;
+
+/**
+ * Test that policy can be created and accessed, by construction and by spec
+ */
+public class BasicPolicyTest extends BrooklynAppUnitTestSupport {
+    
+    public static class MyPolicy extends AbstractPolicy {
+        @SetFromFlag("intKey")
+        public static final BasicConfigKey<Integer> INT_KEY = new BasicConfigKey<Integer>(Integer.class, "bkey", "b key");
+        
+        @SetFromFlag("strKey")
+        public static final ConfigKey<String> STR_KEY = new BasicConfigKey<String>(String.class, "akey", "a key");
+        public static final ConfigKey<Integer> INT_KEY_WITH_DEFAULT = new BasicConfigKey<Integer>(Integer.class, "ckey", "c key", 1);
+        public static final ConfigKey<String> STR_KEY_WITH_DEFAULT = new BasicConfigKey<String>(String.class, "strKey", "str key", "str key default");
+        
+        MyPolicy(Map<?,?> flags) {
+            super(flags);
+        }
+        
+        public MyPolicy() {
+            super();
+        }
+    }
+    
+    @Test
+    public void testAddInstance() throws Exception {
+        MyPolicy policy = new MyPolicy();
+        policy.setDisplayName("Bob");
+        policy.setConfig(MyPolicy.STR_KEY, "aval");
+        policy.setConfig(MyPolicy.INT_KEY, 2);
+        app.addPolicy(policy);
+        
+        assertEquals(policy.getDisplayName(), "Bob");
+        assertEquals(policy.getConfig(MyPolicy.STR_KEY), "aval");
+        assertEquals(policy.getConfig(MyPolicy.INT_KEY), (Integer)2);
+    }
+    
+    @Test
+    public void testAddSpec() throws Exception {
+        MyPolicy policy = app.addPolicy(PolicySpec.create(MyPolicy.class)
+            .displayName("Bob")
+            .configure(MyPolicy.STR_KEY, "aval").configure(MyPolicy.INT_KEY, 2));
+        
+        assertEquals(policy.getDisplayName(), "Bob");
+        assertEquals(policy.getConfig(MyPolicy.STR_KEY), "aval");
+        assertEquals(policy.getConfig(MyPolicy.INT_KEY), (Integer)2);
+    }
+        
+    @Test
+    public void testTagsFromSpec() throws Exception {
+        MyPolicy policy = app.addPolicy(PolicySpec.create(MyPolicy.class).tag(99).uniqueTag("x"));
+
+        assertEquals(policy.getTags(), MutableSet.of("x", 99));
+        assertEquals(policy.getUniqueTag(), "x");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b52e1d/core/src/test/java/brooklyn/policy/basic/EnricherConfigTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/policy/basic/EnricherConfigTest.java b/core/src/test/java/brooklyn/policy/basic/EnricherConfigTest.java
deleted file mode 100644
index c8dced8..0000000
--- a/core/src/test/java/brooklyn/policy/basic/EnricherConfigTest.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.policy.basic;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.fail;
-
-import java.util.Map;
-
-import org.testng.annotations.Test;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.enricher.basic.AbstractEnricher;
-import brooklyn.entity.BrooklynAppUnitTestSupport;
-import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.flags.SetFromFlag;
-
-/**
- * Test that configuration properties are usable and inherited correctly.
- */
-public class EnricherConfigTest extends BrooklynAppUnitTestSupport {
-    
-    // TODO These tests are a copy of PolicyConfigMapUsageTest, which is a code smell.
-    // However, the src/main/java code does not contain as much duplication.
-    
-    public static class MyEnricher extends AbstractEnricher {
-        @SetFromFlag("intKey")
-        public static final BasicConfigKey<Integer> INT_KEY = new BasicConfigKey<Integer>(Integer.class, "bkey", "b key");
-        
-        @SetFromFlag("strKey")
-        public static final ConfigKey<String> STR_KEY = new BasicConfigKey<String>(String.class, "akey", "a key");
-        public static final ConfigKey<Integer> INT_KEY_WITH_DEFAULT = new BasicConfigKey<Integer>(Integer.class, "ckey", "c key", 1);
-        public static final ConfigKey<String> STR_KEY_WITH_DEFAULT = new BasicConfigKey<String>(String.class, "strKey", "str key", "str key default");
-        
-        MyEnricher(Map flags) {
-            super(flags);
-        }
-        
-        MyEnricher() {
-            super();
-        }
-    }
-    
-    private BasicConfigKey<String> differentKey = new BasicConfigKey<String>(String.class, "differentkey", "diffval");
-
-    @Test
-    public void testConfigFlagsPassedInAtConstructionIsAvailable() throws Exception {
-        MyEnricher enricher = new MyEnricher(MutableMap.builder()
-                .put("strKey", "aval")
-                .put("intKey", 2)
-                .build());
-        app.addEnricher(enricher);
-        
-        assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "aval");
-        assertEquals(enricher.getConfig(MyEnricher.INT_KEY), (Integer)2);
-        // this is set, because key name matches annotation on STR_KEY
-        assertEquals(enricher.getConfig(MyEnricher.STR_KEY_WITH_DEFAULT), "aval");
-    }
-    
-    @Test
-    public void testUnknownConfigPassedInAtConstructionIsWarnedAndIgnored() throws Exception {
-        // TODO Also assert it's warned
-        MyEnricher enricher = new MyEnricher(MutableMap.builder()
-                .put(differentKey, "aval")
-                .build());
-        app.addEnricher(enricher);
-        
-        assertEquals(enricher.getConfig(differentKey), null);
-        assertEquals(enricher.getEnricherType().getConfigKey(differentKey.getName()), null);
-    }
-    
-    @Test
-    public void testConfigPassedInAtConstructionIsAvailable() throws Exception {
-        MyEnricher enricher = new MyEnricher(MutableMap.builder()
-                .put(MyEnricher.STR_KEY, "aval")
-                .put(MyEnricher.INT_KEY, 2)
-                .build());
-        app.addEnricher(enricher);
-        
-        assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "aval");
-        assertEquals(enricher.getConfig(MyEnricher.INT_KEY), (Integer)2);
-        // this is not set (contrast with above)
-        assertEquals(enricher.getConfig(MyEnricher.STR_KEY_WITH_DEFAULT), MyEnricher.STR_KEY_WITH_DEFAULT.getDefaultValue());
-    }
-    
-    @Test
-    public void testConfigSetToGroovyTruthFalseIsAvailable() throws Exception {
-        MyEnricher enricher = new MyEnricher(MutableMap.builder()
-                .put(MyEnricher.INT_KEY_WITH_DEFAULT, 0)
-                .build());
-        app.addEnricher(enricher);
-        
-        assertEquals(enricher.getConfig(MyEnricher.INT_KEY_WITH_DEFAULT), (Integer)0);
-    }
-    
-    @Test
-    public void testConfigSetToNullIsAvailable() throws Exception {
-        MyEnricher enricher = new MyEnricher(MutableMap.builder()
-                .put(MyEnricher.STR_KEY_WITH_DEFAULT, null)
-                .build());
-        app.addEnricher(enricher);
-        
-        assertEquals(enricher.getConfig(MyEnricher.STR_KEY_WITH_DEFAULT), null);
-    }
-    
-    @Test
-    public void testConfigCanBeSetOnEnricher() throws Exception {
-        MyEnricher enricher = new MyEnricher();
-        enricher.setConfig(MyEnricher.STR_KEY, "aval");
-        enricher.setConfig(MyEnricher.INT_KEY, 2);
-        app.addEnricher(enricher);
-        
-        assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "aval");
-        assertEquals(enricher.getConfig(MyEnricher.INT_KEY), (Integer)2);
-    }
-    
-    @Test
-    public void testConfigSetterOverridesConstructorValue() throws Exception {
-        MyEnricher enricher = new MyEnricher(MutableMap.builder()
-                .put(MyEnricher.STR_KEY, "aval")
-                .build());
-        enricher.setConfig(MyEnricher.STR_KEY, "diffval");
-        app.addEnricher(enricher);
-        
-        assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "diffval");
-    }
-
-    @Test
-    public void testConfigCannotBeSetAfterApplicationIsStarted() throws Exception {
-        MyEnricher enricher = new MyEnricher(MutableMap.builder()
-                .put(MyEnricher.STR_KEY, "origval")
-                .build());
-        app.addEnricher(enricher);
-        
-        try {
-            enricher.setConfig(MyEnricher.STR_KEY,"newval");
-            fail();
-        } catch (UnsupportedOperationException e) {
-            // success
-        }
-        
-        assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "origval");
-    }
-    
-    @Test
-    public void testConfigReturnsDefaultValueIfNotSet() throws Exception {
-        MyEnricher enricher = new MyEnricher();
-        app.addEnricher(enricher);
-        
-        assertEquals(enricher.getConfig(MyEnricher.STR_KEY_WITH_DEFAULT), "str key default");
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b52e1d/core/src/test/java/brooklyn/policy/basic/PolicyConfigMapUsageTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/policy/basic/PolicyConfigMapUsageTest.java b/core/src/test/java/brooklyn/policy/basic/PolicyConfigMapUsageTest.java
deleted file mode 100644
index 05611d2..0000000
--- a/core/src/test/java/brooklyn/policy/basic/PolicyConfigMapUsageTest.java
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.policy.basic;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
-import static org.testng.Assert.fail;
-
-import java.util.Map;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CountDownLatch;
-
-import org.testng.annotations.Test;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.BrooklynAppUnitTestSupport;
-import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.event.basic.DependentConfiguration;
-import brooklyn.test.entity.TestEntity;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.SetFromFlag;
-
-import com.google.common.util.concurrent.Callables;
-
-/**
- * Test that configuration properties are usable and inherited correctly.
- */
-public class PolicyConfigMapUsageTest extends BrooklynAppUnitTestSupport {
-    private static final int EARLY_RETURN_GRACE = 10;
-
-    public static class MyPolicy extends AbstractPolicy {
-        @SetFromFlag("intKey")
-        public static final BasicConfigKey<Integer> INT_KEY = new BasicConfigKey<Integer>(Integer.class, "bkey", "b key");
-        
-        @SetFromFlag("strKey")
-        public static final ConfigKey<String> STR_KEY = new BasicConfigKey<String>(String.class, "akey", "a key");
-        public static final ConfigKey<Integer> INT_KEY_WITH_DEFAULT = new BasicConfigKey<Integer>(Integer.class, "ckey", "c key", 1);
-        public static final ConfigKey<String> STR_KEY_WITH_DEFAULT = new BasicConfigKey<String>(String.class, "strKey", "str key", "str key default");
-        
-        MyPolicy(Map flags) {
-            super(flags);
-        }
-        
-        MyPolicy() {
-            super();
-        }
-    }
-    
-    private BasicConfigKey<String> differentKey = new BasicConfigKey<String>(String.class, "differentkey", "diffval");
-
-    @Test
-    public void testConfigFlagsPassedInAtConstructionIsAvailable() throws Exception {
-        MyPolicy policy = new MyPolicy(MutableMap.builder()
-                .put("strKey", "aval")
-                .put("intKey", 2)
-                .build());
-        app.addPolicy(policy);
-        
-        assertEquals(policy.getConfig(MyPolicy.STR_KEY), "aval");
-        assertEquals(policy.getConfig(MyPolicy.INT_KEY), (Integer)2);
-        // this is set, because key name matches annotation on STR_KEY
-        assertEquals(policy.getConfig(MyPolicy.STR_KEY_WITH_DEFAULT), "aval");
-    }
-    
-    @Test
-    public void testUnknownConfigPassedInAtConstructionIsWarnedAndIgnored() throws Exception {
-        // TODO Also assert it's warned
-        MyPolicy policy = new MyPolicy(MutableMap.builder()
-                .put(differentKey, "aval")
-                .build());
-        app.addPolicy(policy);
-        
-        assertEquals(policy.getConfig(differentKey), null);
-        assertEquals(policy.getPolicyType().getConfigKey(differentKey.getName()), null);
-    }
-    
-    @Test
-    public void testConfigPassedInAtConstructionIsAvailable() throws Exception {
-        MyPolicy policy = new MyPolicy(MutableMap.builder()
-                .put(MyPolicy.STR_KEY, "aval")
-                .put(MyPolicy.INT_KEY, 2)
-                .build());
-        app.addPolicy(policy);
-        
-        assertEquals(policy.getConfig(MyPolicy.STR_KEY), "aval");
-        assertEquals(policy.getConfig(MyPolicy.INT_KEY), (Integer)2);
-        // this is not set (contrast with above)
-        assertEquals(policy.getConfig(MyPolicy.STR_KEY_WITH_DEFAULT), MyPolicy.STR_KEY_WITH_DEFAULT.getDefaultValue());
-    }
-    
-    @Test
-    public void testConfigSetToGroovyTruthFalseIsAvailable() throws Exception {
-        MyPolicy policy = new MyPolicy(MutableMap.builder()
-                .put(MyPolicy.INT_KEY_WITH_DEFAULT, 0)
-                .build());
-        app.addPolicy(policy);
-        
-        assertEquals(policy.getConfig(MyPolicy.INT_KEY_WITH_DEFAULT), (Integer)0);
-    }
-    
-    @Test
-    public void testConfigSetToNullIsAvailable() throws Exception {
-        MyPolicy policy = new MyPolicy(MutableMap.builder()
-                .put(MyPolicy.STR_KEY_WITH_DEFAULT, null)
-                .build());
-        app.addPolicy(policy);
-        
-        assertEquals(policy.getConfig(MyPolicy.STR_KEY_WITH_DEFAULT), null);
-    }
-    
-    @Test
-    public void testConfigCanBeSetOnPolicy() throws Exception {
-        MyPolicy policy = new MyPolicy();
-        policy.setConfig(MyPolicy.STR_KEY, "aval");
-        policy.setConfig(MyPolicy.INT_KEY, 2);
-        app.addPolicy(policy);
-        
-        assertEquals(policy.getConfig(MyPolicy.STR_KEY), "aval");
-        assertEquals(policy.getConfig(MyPolicy.INT_KEY), (Integer)2);
-    }
-    
-    @Test
-    public void testConfigSetterOverridesConstructorValue() throws Exception {
-        MyPolicy policy = new MyPolicy(MutableMap.builder()
-                .put(MyPolicy.STR_KEY, "aval")
-                .build());
-        policy.setConfig(MyPolicy.STR_KEY, "diffval");
-        app.addPolicy(policy);
-        
-        assertEquals(policy.getConfig(MyPolicy.STR_KEY), "diffval");
-    }
-
-    @Test
-    public void testConfigCannotBeSetAfterApplicationIsStarted() throws Exception {
-        MyPolicy policy = new MyPolicy(MutableMap.builder()
-                .put(MyPolicy.STR_KEY, "origval")
-                .build());
-        app.addPolicy(policy);
-        
-        try {
-            policy.setConfig(MyPolicy.STR_KEY,"newval");
-            fail();
-        } catch (UnsupportedOperationException e) {
-            // success
-        }
-        
-        assertEquals(policy.getConfig(MyPolicy.STR_KEY), "origval");
-    }
-    
-    @Test
-    public void testConfigReturnsDefaultValueIfNotSet() throws Exception {
-        MyPolicy policy = new MyPolicy();
-        app.addPolicy(policy);
-        
-        assertEquals(policy.getConfig(MyPolicy.STR_KEY_WITH_DEFAULT), "str key default");
-    }
-    
-    // FIXME Should we support this now?
-    @Test(enabled=false)
-    public void testGetFutureConfigWhenReady() throws Exception {
-        MyPolicy policy = new MyPolicy(MutableMap.builder()
-                .put(TestEntity.CONF_NAME, DependentConfiguration.whenDone(Callables.returning("aval")))
-                .build());
-        app.addPolicy(policy);
-        
-        assertEquals(policy.getConfig(TestEntity.CONF_NAME), "aval");
-    }
-    
-    // FIXME Should we support this now?
-    @Test(enabled=false)
-    public void testGetFutureConfigBlocksUntilReady() throws Exception {
-        final CountDownLatch latch = new CountDownLatch(1);
-        MyPolicy policy = new MyPolicy(MutableMap.builder()
-                .put(TestEntity.CONF_NAME, DependentConfiguration.whenDone(new Callable<String>() {
-                        public String call() {
-                            try {
-                                latch.await(); return "aval";
-                            } catch (InterruptedException e) {
-                                throw Exceptions.propagate(e);
-                            }
-                        }}))
-                .build());
-        app.addPolicy(policy);
-        
-        Thread t = new Thread(new Runnable() {
-                public void run() {
-                    try {
-                        Thread.sleep(10+EARLY_RETURN_GRACE); latch.countDown();
-                    } catch (InterruptedException e) {
-                        throw Exceptions.propagate(e);
-                    }
-                }});
-        try {
-            long starttime = System.currentTimeMillis();
-            t.start();
-            assertEquals(policy.getConfig(TestEntity.CONF_NAME), "aval");
-            long endtime = System.currentTimeMillis();
-            
-            assertTrue((endtime - starttime) >= 10, "starttime="+starttime+"; endtime="+endtime);
-            
-        } finally {
-            t.interrupt();
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b52e1d/core/src/test/java/brooklyn/policy/basic/PolicyConfigTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/policy/basic/PolicyConfigTest.java b/core/src/test/java/brooklyn/policy/basic/PolicyConfigTest.java
new file mode 100644
index 0000000..502881b
--- /dev/null
+++ b/core/src/test/java/brooklyn/policy/basic/PolicyConfigTest.java
@@ -0,0 +1,202 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package brooklyn.policy.basic;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+
+import org.testng.annotations.Test;
+
+import brooklyn.entity.BrooklynAppUnitTestSupport;
+import brooklyn.event.basic.BasicConfigKey;
+import brooklyn.event.basic.DependentConfiguration;
+import brooklyn.policy.basic.BasicPolicyTest.MyPolicy;
+import brooklyn.test.entity.TestEntity;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.exceptions.Exceptions;
+
+import com.google.common.util.concurrent.Callables;
+
+/**
+ * Test that configuration properties are usable and inherited correctly.
+ */
+public class PolicyConfigTest extends BrooklynAppUnitTestSupport {
+    private static final int EARLY_RETURN_GRACE = 10;
+
+    private BasicConfigKey<String> differentKey = new BasicConfigKey<String>(String.class, "differentkey", "diffval");
+
+    @Test
+    public void testConfigFlagsPassedInAtConstructionIsAvailable() throws Exception {
+        MyPolicy policy = new MyPolicy(MutableMap.builder()
+                .put("strKey", "aval")
+                .put("intKey", 2)
+                .build());
+        app.addPolicy(policy);
+        
+        assertEquals(policy.getConfig(MyPolicy.STR_KEY), "aval");
+        assertEquals(policy.getConfig(MyPolicy.INT_KEY), (Integer)2);
+        // this is set, because key name matches annotation on STR_KEY
+        assertEquals(policy.getConfig(MyPolicy.STR_KEY_WITH_DEFAULT), "aval");
+    }
+    
+    @Test
+    public void testUnknownConfigPassedInAtConstructionIsWarnedAndIgnored() throws Exception {
+        // TODO Also assert it's warned
+        MyPolicy policy = new MyPolicy(MutableMap.builder()
+                .put(differentKey, "aval")
+                .build());
+        app.addPolicy(policy);
+        
+        assertEquals(policy.getConfig(differentKey), null);
+        assertEquals(policy.getPolicyType().getConfigKey(differentKey.getName()), null);
+    }
+    
+    @Test
+    public void testConfigPassedInAtConstructionIsAvailable() throws Exception {
+        MyPolicy policy = new MyPolicy(MutableMap.builder()
+                .put(MyPolicy.STR_KEY, "aval")
+                .put(MyPolicy.INT_KEY, 2)
+                .build());
+        app.addPolicy(policy);
+        
+        assertEquals(policy.getConfig(MyPolicy.STR_KEY), "aval");
+        assertEquals(policy.getConfig(MyPolicy.INT_KEY), (Integer)2);
+        // this is not set (contrast with above)
+        assertEquals(policy.getConfig(MyPolicy.STR_KEY_WITH_DEFAULT), MyPolicy.STR_KEY_WITH_DEFAULT.getDefaultValue());
+    }
+    
+    @Test
+    public void testConfigSetToGroovyTruthFalseIsAvailable() throws Exception {
+        MyPolicy policy = new MyPolicy(MutableMap.builder()
+                .put(MyPolicy.INT_KEY_WITH_DEFAULT, 0)
+                .build());
+        app.addPolicy(policy);
+        
+        assertEquals(policy.getConfig(MyPolicy.INT_KEY_WITH_DEFAULT), (Integer)0);
+    }
+    
+    @Test
+    public void testConfigSetToNullIsAvailable() throws Exception {
+        MyPolicy policy = new MyPolicy(MutableMap.builder()
+                .put(MyPolicy.STR_KEY_WITH_DEFAULT, null)
+                .build());
+        app.addPolicy(policy);
+        
+        assertEquals(policy.getConfig(MyPolicy.STR_KEY_WITH_DEFAULT), null);
+    }
+    
+    @Test
+    public void testConfigCanBeSetOnPolicy() throws Exception {
+        MyPolicy policy = new MyPolicy();
+        policy.setConfig(MyPolicy.STR_KEY, "aval");
+        policy.setConfig(MyPolicy.INT_KEY, 2);
+        app.addPolicy(policy);
+        
+        assertEquals(policy.getConfig(MyPolicy.STR_KEY), "aval");
+        assertEquals(policy.getConfig(MyPolicy.INT_KEY), (Integer)2);
+    }
+    
+    @Test
+    public void testConfigSetterOverridesConstructorValue() throws Exception {
+        MyPolicy policy = new MyPolicy(MutableMap.builder()
+                .put(MyPolicy.STR_KEY, "aval")
+                .build());
+        policy.setConfig(MyPolicy.STR_KEY, "diffval");
+        app.addPolicy(policy);
+        
+        assertEquals(policy.getConfig(MyPolicy.STR_KEY), "diffval");
+    }
+
+    @Test
+    public void testConfigCannotBeSetAfterApplicationIsStarted() throws Exception {
+        MyPolicy policy = new MyPolicy(MutableMap.builder()
+                .put(MyPolicy.STR_KEY, "origval")
+                .build());
+        app.addPolicy(policy);
+        
+        try {
+            policy.setConfig(MyPolicy.STR_KEY,"newval");
+            fail();
+        } catch (UnsupportedOperationException e) {
+            // success
+        }
+        
+        assertEquals(policy.getConfig(MyPolicy.STR_KEY), "origval");
+    }
+    
+    @Test
+    public void testConfigReturnsDefaultValueIfNotSet() throws Exception {
+        MyPolicy policy = new MyPolicy();
+        app.addPolicy(policy);
+        
+        assertEquals(policy.getConfig(MyPolicy.STR_KEY_WITH_DEFAULT), "str key default");
+    }
+    
+    // FIXME Should we support this now?
+    @Test(enabled=false)
+    public void testGetFutureConfigWhenReady() throws Exception {
+        MyPolicy policy = new MyPolicy(MutableMap.builder()
+                .put(TestEntity.CONF_NAME, DependentConfiguration.whenDone(Callables.returning("aval")))
+                .build());
+        app.addPolicy(policy);
+        
+        assertEquals(policy.getConfig(TestEntity.CONF_NAME), "aval");
+    }
+    
+    // FIXME Should we support this now?
+    @Test(enabled=false)
+    public void testGetFutureConfigBlocksUntilReady() throws Exception {
+        final CountDownLatch latch = new CountDownLatch(1);
+        MyPolicy policy = new MyPolicy(MutableMap.builder()
+                .put(TestEntity.CONF_NAME, DependentConfiguration.whenDone(new Callable<String>() {
+                        public String call() {
+                            try {
+                                latch.await(); return "aval";
+                            } catch (InterruptedException e) {
+                                throw Exceptions.propagate(e);
+                            }
+                        }}))
+                .build());
+        app.addPolicy(policy);
+        
+        Thread t = new Thread(new Runnable() {
+                public void run() {
+                    try {
+                        Thread.sleep(10+EARLY_RETURN_GRACE); latch.countDown();
+                    } catch (InterruptedException e) {
+                        throw Exceptions.propagate(e);
+                    }
+                }});
+        try {
+            long starttime = System.currentTimeMillis();
+            t.start();
+            assertEquals(policy.getConfig(TestEntity.CONF_NAME), "aval");
+            long endtime = System.currentTimeMillis();
+            
+            assertTrue((endtime - starttime) >= 10, "starttime="+starttime+"; endtime="+endtime);
+            
+        } finally {
+            t.interrupt();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b52e1d/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java
index 2457812..53e31e0 100644
--- a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java
+++ b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java
@@ -142,6 +142,7 @@ public class BrooklynAssemblyTemplateInstantiator implements AssemblyTemplateSpe
             // if promoted, apply the transformations done to the app
             // (normally this will be done by the resolveSpec call above)
             if (app.getDisplayName()==null) app.displayName(oldApp.getDisplayName());
+            app.tags(oldApp.getTags());
             app.locations(oldApp.getLocations());
         }
         

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b52e1d/utils/common/src/main/java/brooklyn/util/guava/TypeTokens.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/guava/TypeTokens.java b/utils/common/src/main/java/brooklyn/util/guava/TypeTokens.java
index ca69a97..d16d2df 100644
--- a/utils/common/src/main/java/brooklyn/util/guava/TypeTokens.java
+++ b/utils/common/src/main/java/brooklyn/util/guava/TypeTokens.java
@@ -18,6 +18,10 @@
  */
 package brooklyn.util.guava;
 
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
 import javax.annotation.Nullable;
 
 import com.google.common.reflect.TypeToken;
@@ -68,5 +72,20 @@ public class TypeTokens {
     public static <T> Class<T> getRawRawType(TypeToken<T> token) {
         return (Class)token.getRawType();
     }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public static <T> TypeToken<Set<T>> setOf(Class<T> type) {
+        return (TypeToken) TypeToken.of(Set.class);
+    }
+    
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public static <K,V> TypeToken<Map<K,V>> mapOf(Class<K> key, Class<V> value) {
+        return (TypeToken) TypeToken.of(Map.class);
+    }
+    
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public static <T> TypeToken<List<T>> listOf(Class<T> type) {
+        return (TypeToken) TypeToken.of(List.class);
+    }
     
 }


[09/11] git commit: some more tidying following emergency fix in https://github.com/apache/incubator-brooklyn/commit/bf627f76a7ad959a3beb7095e409a90e4cfa6e06

Posted by he...@apache.org.
some more tidying following emergency fix in https://github.com/apache/incubator-brooklyn/commit/bf627f76a7ad959a3beb7095e409a90e4cfa6e06


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

Branch: refs/heads/master
Commit: 71ea98c0496b1c901d7d5455e75875371d1a4c8d
Parents: 560514c
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Aug 6 13:47:31 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Aug 6 13:47:31 2014 -0400

----------------------------------------------------------------------
 core/src/main/java/brooklyn/util/osgi/Osgis.java | 14 +++-----------
 1 file changed, 3 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/71ea98c0/core/src/main/java/brooklyn/util/osgi/Osgis.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/osgi/Osgis.java b/core/src/main/java/brooklyn/util/osgi/Osgis.java
index 2df3fbf..6b0d99f 100644
--- a/core/src/main/java/brooklyn/util/osgi/Osgis.java
+++ b/core/src/main/java/brooklyn/util/osgi/Osgis.java
@@ -213,16 +213,8 @@ public class Osgis {
         if("felix.extensions".equals(manifestUrl.getHost())) return;
 
         try {
-            Manifest manifest;
-            try {
-                manifest = readManifest(manifestUrl);
-                if (!isValidBundle(manifest)) return;
-            } catch (Exception e) {
-                Exceptions.propagateIfFatal(e);
-                // assume invalid manifest (however it normally follows the above path)
-                LOG.warn("Not able to install extension bundle from " + manifestUrl + "; probably it is not a bundle, ignoring: "+e, e);
-                return;
-            }
+            Manifest manifest = readManifest(manifestUrl);
+            if (!isValidBundle(manifest)) return;
             
             String versionedId = getVersionedId(manifest);
             URL bundleUrl = ResourceUtils.getContainerUrl(manifestUrl, MANIFEST_PATH);
@@ -232,7 +224,7 @@ public class Osgis {
                 if (!bundleUrl.equals(existingBundle.getLocation()) &&
                         //the framework bundle is always pre-installed, don't display duplicate info
                         !versionedId.equals(frameworkVersionedId)) {
-                    LOG.warn("Ignoring duplicate " + versionedId + " from manifest " + manifestUrl + ", already loaded from " + existingBundle.getLocation());
+                    LOG.info("Ignoring duplicate " + versionedId + " from manifest " + manifestUrl + ", already loaded from " + existingBundle.getLocation());
                 }
                 return;
             }


[05/11] git commit: use uniqueTag when checking for duplicate addition

Posted by he...@apache.org.
use uniqueTag when checking for duplicate addition


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

Branch: refs/heads/master
Commit: fdb4c0a282818fe001a3966dbf7202d9bd79f4a0
Parents: 427d4e1
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Aug 4 23:38:44 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Aug 5 10:40:52 2014 -0400

----------------------------------------------------------------------
 api/src/main/java/brooklyn/entity/Entity.java   |  4 +-
 .../brooklyn/entity/basic/AbstractEntity.java   | 55 ++++++++++++++------
 .../enricher/basic/BasicEnricherTest.java       |  9 +++-
 .../group/MembershipTrackingPolicyTest.java     |  8 ++-
 4 files changed, 55 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fdb4c0a2/api/src/main/java/brooklyn/entity/Entity.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/entity/Entity.java b/api/src/main/java/brooklyn/entity/Entity.java
index c792067..8d0d663 100644
--- a/api/src/main/java/brooklyn/entity/Entity.java
+++ b/api/src/main/java/brooklyn/entity/Entity.java
@@ -216,7 +216,7 @@ public interface Entity extends BrooklynObject {
     /**
      * Adds the given policy to this entity. Also calls policy.setEntity if available.
      */
-    void addPolicy(Policy policy);
+    Policy addPolicy(Policy policy);
     
     /**
      * Adds the given policy to this entity. Also calls policy.setEntity if available.
@@ -232,7 +232,7 @@ public interface Entity extends BrooklynObject {
     /**
      * Adds the given enricher to this entity. Also calls enricher.setEntity if available.
      */
-    void addEnricher(Enricher enricher);
+    Enricher addEnricher(Enricher enricher);
     
     /**
      * Adds the given enricher to this entity. Also calls enricher.setEntity if available.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fdb4c0a2/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
index 19bbea1..68846aa 100644
--- a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
+++ b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
@@ -70,6 +70,7 @@ import brooklyn.management.internal.SubscriptionTracker;
 import brooklyn.mementos.EntityMemento;
 import brooklyn.policy.Enricher;
 import brooklyn.policy.EnricherSpec;
+import brooklyn.policy.EntityAdjunct;
 import brooklyn.policy.Policy;
 import brooklyn.policy.PolicySpec;
 import brooklyn.policy.basic.AbstractEntityAdjunct;
@@ -1075,7 +1076,7 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E
     }
 
     @Override
-    public void addPolicy(Policy policy) {
+    public Policy addPolicy(Policy policy) {
         List<Policy> old = MutableList.<Policy>copyOf(policies);
 
         policies.add((AbstractPolicy)policy);
@@ -1084,21 +1085,26 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E
         getManagementSupport().getEntityChangeListener().onPolicyAdded(policy);
         emit(AbstractEntity.POLICY_ADDED, new PolicyDescriptor(policy));
         
-        if (hasApparentlyEqualsAndWarn(old, policy)) removePolicy(policy);
+        Policy actual = findApparentlyEqualsAndWarn(old, policy);
+        if (actual!=null) {
+            removePolicy(policy);
+            return actual;
+        }
+        return policy;
     }
 
+    @SuppressWarnings("unchecked")
     @Override
     public <T extends Policy> T addPolicy(PolicySpec<T> spec) {
         T policy = getManagementContext().getEntityManager().createPolicy(spec);
-        addPolicy(policy);
-        return policy;
+        return (T) addPolicy(policy);
     }
 
+    @SuppressWarnings("unchecked")
     @Override
     public <T extends Enricher> T addEnricher(EnricherSpec<T> spec) {
         T enricher = getManagementContext().getEntityManager().createEnricher(spec);
-        addEnricher(enricher);
-        return enricher;
+        return (T) addEnricher(enricher);
     }
 
     @Override
@@ -1129,7 +1135,7 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E
     }
 
     @Override
-    public void addEnricher(Enricher enricher) {
+    public Enricher addEnricher(Enricher enricher) {
         List<Enricher> old = MutableList.<Enricher>copyOf(enrichers);
         
         enrichers.add((AbstractEnricher) enricher);
@@ -1138,26 +1144,39 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E
         getManagementSupport().getEntityChangeListener().onEnricherAdded(enricher);
         // TODO Could add equivalent of AbstractEntity.POLICY_ADDED for enrichers; no use-case for that yet
         
-        if (hasApparentlyEqualsAndWarn(old, enricher)) removeEnricher(enricher);
+        Enricher actual = findApparentlyEqualsAndWarn(old, enricher);
+        if (actual!=null) {
+            removeEnricher(enricher);
+            return actual;
+        }
+        return enricher;
     }
     
-    private <T> boolean hasApparentlyEqualsAndWarn(Collection<? extends T> items, T newItem) {
+    private <T extends EntityAdjunct> T findApparentlyEqualsAndWarn(Collection<? extends T> items, T newItem) {
         T oldItem = findApparentlyEquals(items, newItem);
+        
         if (oldItem!=null) {
+            String newItemTag = newItem.getUniqueTag();
+            if (newItemTag!=null) {
+                // old item has same tag; don't add
+                LOG.warn("Adding to "+this+", "+newItem+" has identical uniqueTag as existing "+oldItem+"; will remove after adding. "
+                    + "Underlying addition should be modified so it is not added twice.");
+                return oldItem;
+            }
             if (isRebinding()) {
                 LOG.warn("Adding to "+this+", "+newItem+" appears identical to existing "+oldItem+"; will remove after adding. "
-                    + "Underlying addition should be checked as this behavior will likely be removed without further notice.");
-                return true;
+                    + "Underlying addition should be modified so it is not added twice during rebind.");
+                return oldItem;
             } else {
                 LOG.warn("Adding to "+this+", "+newItem+" appears identical to existing "+oldItem+"; may get removed on rebind. "
-                    + "If unintended, addition should be removed. If intended, enricher should be modified so difference is apparent.");
-                return false;
+                    + "Underlying addition should be modified so it is not added twice.");
+                return null;
             }
         } else {
-            return false;
+            return null;
         }
     }
-    private <T> T findApparentlyEquals(Collection<? extends T> itemsCopy, T newItem) {
+    private <T extends EntityAdjunct> T findApparentlyEquals(Collection<? extends T> itemsCopy, T newItem) {
         // FIXME workaround for issue where enrichers can get added multiple times on rebind,
         // if it's added in onBecomingManager or connectSensors; the right fix will be more disciplined about how/where these are added
         // (easier done when sensor feeds are persisted)
@@ -1165,8 +1184,12 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E
         while (beforeEntityAdjunct.getSuperclass()!=null && !beforeEntityAdjunct.getSuperclass().equals(AbstractEntityAdjunct.class))
             beforeEntityAdjunct = beforeEntityAdjunct.getSuperclass();
         
+        String newItemTag = newItem.getUniqueTag();
         for (T oldItem: itemsCopy) {
-            if (oldItem.getClass().equals(newItem.getClass())) {
+            if (oldItem.getUniqueTag()!=null) {
+                if ((oldItem.getUniqueTag().equals(newItemTag)))
+                    return oldItem;
+            } else if (newItemTag==null && oldItem.getClass().equals(newItem.getClass())) {
                 if (EqualsBuilder.reflectionEquals(oldItem, newItem, false,
                         // internal admin in 'beforeEntityAdjunct' should be ignored
                         beforeEntityAdjunct,

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fdb4c0a2/core/src/test/java/brooklyn/enricher/basic/BasicEnricherTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/enricher/basic/BasicEnricherTest.java b/core/src/test/java/brooklyn/enricher/basic/BasicEnricherTest.java
index 9d0fcf2..b62b9c9 100644
--- a/core/src/test/java/brooklyn/enricher/basic/BasicEnricherTest.java
+++ b/core/src/test/java/brooklyn/enricher/basic/BasicEnricherTest.java
@@ -25,7 +25,6 @@ import java.util.Map;
 import org.testng.annotations.Test;
 
 import brooklyn.config.ConfigKey;
-import brooklyn.enricher.basic.AbstractEnricher;
 import brooklyn.entity.BrooklynAppUnitTestSupport;
 import brooklyn.event.basic.BasicConfigKey;
 import brooklyn.policy.EnricherSpec;
@@ -90,4 +89,12 @@ public class BasicEnricherTest extends BrooklynAppUnitTestSupport {
         assertEquals(enricher.getUniqueTag(), "x");
     }
 
+    @Test
+    public void testSameUniqueTagEnricherNotAddedTwice() throws Exception {
+        MyEnricher enricher1 = app.addEnricher(EnricherSpec.create(MyEnricher.class).tag(99).uniqueTag("x"));
+        MyEnricher enricher2 = app.addEnricher(EnricherSpec.create(MyEnricher.class).tag(94).uniqueTag("x"));
+        assertEquals(enricher2, enricher1);
+        assertEquals(app.getEnrichers().size(), 1);
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fdb4c0a2/core/src/test/java/brooklyn/entity/group/MembershipTrackingPolicyTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/group/MembershipTrackingPolicyTest.java b/core/src/test/java/brooklyn/entity/group/MembershipTrackingPolicyTest.java
index 8fe0e19..c9d2552 100644
--- a/core/src/test/java/brooklyn/entity/group/MembershipTrackingPolicyTest.java
+++ b/core/src/test/java/brooklyn/entity/group/MembershipTrackingPolicyTest.java
@@ -138,6 +138,7 @@ public class MembershipTrackingPolicyTest extends BrooklynAppUnitTestSupport {
     public void testNotifiedOfExtraTrackedSensors() throws Exception {
         TestEntity e1 = createAndManageChildOf(group);
 
+        app.removeAllPolicies();
         RecordingMembershipTrackingPolicy policy2 = app.addPolicy(PolicySpec.create(RecordingMembershipTrackingPolicy.class)
                 .configure("group", group)
                 .configure("sensorsToTrack", ImmutableSet.of(TestEntity.NAME)));
@@ -164,6 +165,7 @@ public class MembershipTrackingPolicyTest extends BrooklynAppUnitTestSupport {
     public void testNotNotifiedOfExtraTrackedSensorsIfNonDuplicate() throws Exception {
         TestEntity e1 = createAndManageChildOf(group);
         
+        app.removeAllPolicies();
         RecordingMembershipTrackingPolicy nonDuplicateTrackingPolicy = app.addPolicy(PolicySpec.create(RecordingMembershipTrackingPolicy.class)
                 .configure(AbstractMembershipTrackingPolicy.SENSORS_TO_TRACK, ImmutableSet.<Sensor<?>>of(TestEntity.NAME))
                 .configure(AbstractMembershipTrackingPolicy.NOTIFY_ON_DUPLICATES, false)
@@ -183,7 +185,8 @@ public class MembershipTrackingPolicyTest extends BrooklynAppUnitTestSupport {
     @Test
     public void testDefaultNotNotifiedOfExtraTrackedSensorsIfDuplicate() throws Exception {
         TestEntity e1 = createAndManageChildOf(group);
-        
+
+        app.removeAllPolicies();
         RecordingMembershipTrackingPolicy nonDuplicateTrackingPolicy = app.addPolicy(PolicySpec.create(RecordingMembershipTrackingPolicy.class)
                 .configure(AbstractMembershipTrackingPolicy.SENSORS_TO_TRACK, ImmutableSet.<Sensor<?>>of(TestEntity.NAME))
                 .configure(AbstractMembershipTrackingPolicy.GROUP, group));
@@ -201,7 +204,8 @@ public class MembershipTrackingPolicyTest extends BrooklynAppUnitTestSupport {
     @Test
     public void testNotifiedOfExtraTrackedSensorsIfDuplicate() throws Exception {
         TestEntity e1 = createAndManageChildOf(group);
-        
+
+        app.removeAllPolicies();
         RecordingMembershipTrackingPolicy nonDuplicateTrackingPolicy = app.addPolicy(PolicySpec.create(RecordingMembershipTrackingPolicy.class)
                 .configure(AbstractMembershipTrackingPolicy.SENSORS_TO_TRACK, ImmutableSet.<Sensor<?>>of(TestEntity.NAME))
                 .configure(AbstractMembershipTrackingPolicy.NOTIFY_ON_DUPLICATES, true)


[06/11] git commit: add tests confirming that rebind works with tags and unique tags for entities and policies (no work needed because it is @SetFromFlag)

Posted by he...@apache.org.
add tests confirming that rebind works with tags and unique tags for entities and policies (no work needed because it is @SetFromFlag)


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

Branch: refs/heads/master
Commit: db7492ac1735d995dac0660fcc60e2ef49c1d02b
Parents: fdb4c0a
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Aug 5 00:12:41 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Aug 5 10:40:57 2014 -0400

----------------------------------------------------------------------
 .../java/brooklyn/entity/basic/Entities.java    | 48 ++++++++++++++++++--
 .../entity/rebind/RebindEnricherTest.java       | 35 +++++++++++---
 .../entity/rebind/RebindPolicyTest.java         |  9 ++++
 3 files changed, 82 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/db7492ac/core/src/main/java/brooklyn/entity/basic/Entities.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/Entities.java b/core/src/main/java/brooklyn/entity/basic/Entities.java
index 8cca783..9e1108f 100644
--- a/core/src/main/java/brooklyn/entity/basic/Entities.java
+++ b/core/src/main/java/brooklyn/entity/basic/Entities.java
@@ -42,6 +42,7 @@ import org.slf4j.LoggerFactory;
 import brooklyn.config.BrooklynProperties;
 import brooklyn.config.ConfigKey;
 import brooklyn.config.ConfigKey.HasConfigKey;
+import brooklyn.enricher.basic.AbstractEnricher;
 import brooklyn.entity.Application;
 import brooklyn.entity.Effector;
 import brooklyn.entity.Entity;
@@ -68,6 +69,7 @@ import brooklyn.management.internal.EffectorUtils;
 import brooklyn.management.internal.LocalManagementContext;
 import brooklyn.management.internal.ManagementContextInternal;
 import brooklyn.management.internal.NonDeploymentManagementContext;
+import brooklyn.policy.Enricher;
 import brooklyn.policy.Policy;
 import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.util.ResourceUtils;
@@ -335,9 +337,18 @@ public class Entities {
             out.append(currentIndentation+tab+tab+"Members: "+members.toString()+"\n");
         }
 
-        out.append(currentIndentation+tab+tab+"Policies:\n");
-        for (Policy policy : e.getPolicies()) {
-            dumpInfo(policy, out, currentIndentation+tab+tab+tab, tab);
+        if (!e.getPolicies().isEmpty()) {
+            out.append(currentIndentation+tab+tab+"Policies:\n");
+            for (Policy policy : e.getPolicies()) {
+                dumpInfo(policy, out, currentIndentation+tab+tab+tab, tab);
+            }
+        }
+
+        if (!e.getEnrichers().isEmpty()) {
+            out.append(currentIndentation+tab+tab+"Enrichers:\n");
+            for (Enricher enricher : e.getEnrichers()) {
+                dumpInfo(enricher, out, currentIndentation+tab+tab+tab, tab);
+            }
         }
 
         for (Entity it : e.getChildren()) {
@@ -403,6 +414,37 @@ public class Entities {
         out.flush();
     }
 
+    public static void dumpInfo(Enricher enr) {
+        try {
+            dumpInfo(enr, new PrintWriter(System.out), "", "  ");
+        } catch (IOException exc) {
+            // system.out throwing an exception is odd, so don't have IOException on signature
+            throw new RuntimeException(exc);
+        }
+    }
+    public static void dumpInfo(Enricher enr, Writer out) throws IOException {
+        dumpInfo(enr, out, "", "  ");
+    }
+    public static void dumpInfo(Enricher enr, String currentIndentation, String tab) throws IOException {
+        dumpInfo(enr, new PrintWriter(System.out), currentIndentation, tab);
+    }
+    public static void dumpInfo(Enricher enr, Writer out, String currentIndentation, String tab) throws IOException {
+        out.append(currentIndentation+enr.toString()+"\n");
+
+        for (ConfigKey<?> key : sortConfigKeys(enr.getEnricherType().getConfigKeys())) {
+            Maybe<Object> val = ((AbstractEnricher)enr).getConfigMap().getConfigRaw(key, true);
+            if (!isTrivial(val)) {
+                out.append(currentIndentation+tab+tab+key);
+                out.append(" = ");
+                if (isSecret(key.getName())) out.append("xxxxxxxx");
+                else out.append(""+val.get());
+                out.append("\n");
+            }
+        }
+
+        out.flush();
+    }
+
     public static void dumpInfo(Policy pol) {
         try {
             dumpInfo(pol, new PrintWriter(System.out), "", "  ");

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/db7492ac/core/src/test/java/brooklyn/entity/rebind/RebindEnricherTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindEnricherTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindEnricherTest.java
index a2bdbb7..d23e2d2 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindEnricherTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindEnricherTest.java
@@ -51,7 +51,9 @@ import brooklyn.test.EntityTestUtils;
 import brooklyn.test.entity.TestApplication;
 import brooklyn.test.entity.TestEntity;
 import brooklyn.test.entity.TestEntityImpl;
+import brooklyn.util.collections.MutableSet;
 import brooklyn.util.flags.SetFromFlag;
+import brooklyn.util.text.Identifiers;
 import brooklyn.util.text.StringFunctions;
 
 import com.google.common.base.Predicates;
@@ -121,6 +123,7 @@ public class RebindEnricherTest extends RebindTestFixtureWithApp {
         EntityTestUtils.assertAttributeEqualsEventually(newApp, METRIC2, "myval");
     }
 
+    @SuppressWarnings("unchecked")
     @Test
     public void testCombiningEnricher() throws Exception {
         origApp.addEnricher(Enrichers.builder()
@@ -165,6 +168,8 @@ public class RebindEnricherTest extends RebindTestFixtureWithApp {
     public void testRestoresConfig() throws Exception {
         origApp.addEnricher(EnricherSpec.create(MyEnricher.class)
                 .displayName("My Enricher")
+                .uniqueTag("tagU")
+                .tag("tag1").tag("tag2")
                 .configure(MyEnricher.MY_CONFIG_WITH_SETFROMFLAG_NO_SHORT_NAME, "myVal for with setFromFlag noShortName")
                 .configure(MyEnricher.MY_CONFIG_WITH_SETFROMFLAG_WITH_SHORT_NAME, "myVal for setFromFlag withShortName")
                 .configure(MyEnricher.MY_CONFIG_WITHOUT_SETFROMFLAG, "myVal for witout setFromFlag"));
@@ -172,7 +177,11 @@ public class RebindEnricherTest extends RebindTestFixtureWithApp {
         newApp = (TestApplication) rebind();
         MyEnricher newEnricher = (MyEnricher) Iterables.getOnlyElement(newApp.getEnrichers());
         
-        assertEquals(newEnricher.getName(), "My Enricher");
+        assertEquals(newEnricher.getDisplayName(), "My Enricher");
+        
+        assertEquals(newEnricher.getUniqueTag(), "tagU");
+        assertEquals(newEnricher.getTags(), MutableSet.of("tagU", "tag1", "tag2"));
+        
         assertEquals(newEnricher.getConfig(MyEnricher.MY_CONFIG_WITH_SETFROMFLAG_NO_SHORT_NAME), "myVal for with setFromFlag noShortName");
         assertEquals(newEnricher.getConfig(MyEnricher.MY_CONFIG_WITH_SETFROMFLAG_WITH_SHORT_NAME), "myVal for setFromFlag withShortName");
         assertEquals(newEnricher.getConfig(MyEnricher.MY_CONFIG_WITHOUT_SETFROMFLAG), "myVal for witout setFromFlag");
@@ -265,26 +274,38 @@ public class RebindEnricherTest extends RebindTestFixtureWithApp {
         @Override
         public void init() {
             super.init();
+            addEnricher(EnricherSpec.create(MyEnricher.class).uniqueTag("x").tag(Identifiers.makeRandomId(8)));
             addEnricher(EnricherSpec.create(MyEnricher.class));
         }
+        @Override
+        public void onManagementStarting() {
+            super.onManagementStarted();
+            addEnricher(EnricherSpec.create(MyEnricher.class).uniqueTag("y").tag(Identifiers.makeRandomId(8)));
+        }
+        @Override
+        public void onManagementStarted() {
+            super.onManagementStarted();
+            addEnricher(EnricherSpec.create(MyEnricher.class).uniqueTag("z").tag(Identifiers.makeRandomId(8)));
+            // all the enrichers above should not be added on rebind, but this one will be:
+            addEnricher(EnricherSpec.create(MyEnricher.class).uniqueTag( Identifiers.makeRandomId(8) ).tag(Identifiers.makeRandomId(8)));
+        }
     }
 
     @Test
-    // this was never a problem, but wanted to confirm
-    // we were seeing enrichers and policies added multiple times, but that was due to 
-    // SoftwareProcessImpl.callRebindHooks calling connectSensors an extra time
-    // as a workaround for when sensors, enrichers, and policies were not being persisted
-    public void testEntityCreatingItsEnricherDoesNotReCreateIt() throws Exception {
+    public void testEntityCreatingItsEnricherDoesNotReCreateItUnlessUniqueTagDifferent() throws Exception {
         TestEntity e1 = origApp.createAndManageChild(EntitySpec.create(TestEntity.class, MyTestEntityWithEnricher.class));
         Collection<Enricher> e1e = e1.getEnrichers();
         log.info("enrichers1: "+e1e);
+        Entities.dumpInfo(e1);
+        assertEquals(e1e.size(), 5);
 
         newApp = (TestApplication) rebind();
         Entity e2 = Iterables.getOnlyElement( Entities.descendants(newApp, EntityPredicates.idEqualTo(e1.getId())) );
         Collection<Enricher> e2e = e2.getEnrichers();
         log.info("enrichers2: "+e2e);
+        Entities.dumpInfo(e2);
         
-        assertEquals(e1e.size(), e2e.size());
+        assertEquals(e2e.size(), e1e.size()+1);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/db7492ac/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java
index 35acb2e..bc4e845 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java
@@ -45,6 +45,7 @@ import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.test.entity.TestApplication;
 import brooklyn.test.entity.TestEntity;
 import brooklyn.util.collections.MutableMap;
+import brooklyn.util.collections.MutableSet;
 import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.base.Predicates;
@@ -103,6 +104,9 @@ public class RebindPolicyTest extends RebindTestFixtureWithApp {
     @Test
     public void testRestoresConfig() throws Exception {
         origApp.addPolicy(PolicySpec.create(MyPolicy.class)
+                .displayName("My Policy")
+                .uniqueTag("tagU")
+                .tag("tag1").tag("tag2")
                 .configure(MyPolicy.MY_CONFIG_WITH_SETFROMFLAG_NO_SHORT_NAME, "myVal for with setFromFlag noShortName")
                 .configure(MyPolicy.MY_CONFIG_WITH_SETFROMFLAG_WITH_SHORT_NAME, "myVal for setFromFlag withShortName")
                 .configure(MyPolicy.MY_CONFIG_WITHOUT_SETFROMFLAG, "myVal for witout setFromFlag"));
@@ -110,6 +114,11 @@ public class RebindPolicyTest extends RebindTestFixtureWithApp {
         newApp = (TestApplication) rebind();
         MyPolicy newPolicy = (MyPolicy) Iterables.getOnlyElement(newApp.getPolicies());
         
+        assertEquals(newPolicy.getDisplayName(), "My Policy");
+        
+        assertEquals(newPolicy.getUniqueTag(), "tagU");
+        assertEquals(newPolicy.getTags(), MutableSet.of("tagU", "tag1", "tag2"));
+        
         assertEquals(newPolicy.getConfig(MyPolicy.MY_CONFIG_WITH_SETFROMFLAG_NO_SHORT_NAME), "myVal for with setFromFlag noShortName");
         assertEquals(newPolicy.getConfig(MyPolicy.MY_CONFIG_WITH_SETFROMFLAG_WITH_SHORT_NAME), "myVal for setFromFlag withShortName");
         assertEquals(newPolicy.getConfig(MyPolicy.MY_CONFIG_WITHOUT_SETFROMFLAG), "myVal for witout setFromFlag");