You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2016/02/01 18:49:11 UTC
[07/50] brooklyn-server git commit: Adds EnricherSpec
Adds EnricherSpec
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/b8216c5e
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/b8216c5e
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/b8216c5e
Branch: refs/heads/0.6.0
Commit: b8216c5e5e076160f23d4f8e869e0b3f4d024cd8
Parents: 9f591ed
Author: Aled Sage <al...@gmail.com>
Authored: Mon Nov 4 23:22:58 2013 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Tue Nov 5 13:05:47 2013 +0000
----------------------------------------------------------------------
.../brooklyn/entity/proxying/EntitySpec.java | 41 ++++-
.../main/java/brooklyn/policy/EnricherSpec.java | 175 +++++++++++++++++++
.../main/java/brooklyn/policy/EnricherType.java | 38 ++++
.../entity/proxying/InternalEntityFactory.java | 10 ++
.../entity/proxying/InternalPolicyFactory.java | 71 +++++++-
.../brooklyn/entity/basic/EntitySpecTest.java | 42 ++++-
6 files changed, 371 insertions(+), 6 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b8216c5e/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 d654be0..28476a5 100644
--- a/api/src/main/java/brooklyn/entity/proxying/EntitySpec.java
+++ b/api/src/main/java/brooklyn/entity/proxying/EntitySpec.java
@@ -19,6 +19,8 @@ import brooklyn.config.ConfigKey;
import brooklyn.config.ConfigKey.HasConfigKey;
import brooklyn.entity.Entity;
import brooklyn.management.Task;
+import brooklyn.policy.Enricher;
+import brooklyn.policy.EnricherSpec;
import brooklyn.policy.Policy;
import brooklyn.policy.PolicySpec;
import brooklyn.util.exceptions.Exceptions;
@@ -112,6 +114,8 @@ public class EntitySpec<T extends Entity> implements Serializable {
private final Map<ConfigKey<?>, Object> config = Maps.newLinkedHashMap();
private final List<Policy> policies = Lists.newArrayList();
private final List<PolicySpec<?>> policySpecs = Lists.newArrayList();
+ private final List<Enricher> enrichers = Lists.newArrayList();
+ private final List<EnricherSpec<?>> enricherSpecs = Lists.newArrayList();
private final Set<Class<?>> additionalInterfaces = Sets.newLinkedHashSet();
private final List<EntityInitializer> entityInitializers = Lists.newArrayList();
private volatile boolean immutable;
@@ -188,6 +192,14 @@ public class EntitySpec<T extends Entity> implements Serializable {
return policies;
}
+ public List<EnricherSpec<?>> getEnricherSpecs() {
+ return enricherSpecs;
+ }
+
+ public List<Enricher> getEnrichers() {
+ return enrichers;
+ }
+
public EntitySpec<T> displayName(String val) {
checkMutable();
displayName = val;
@@ -313,7 +325,6 @@ public class EntitySpec<T extends Entity> implements Serializable {
return this;
}
-
/** adds the supplied policies to the spec */
public <V> EntitySpec<T> policies(Iterable<? extends Policy> val) {
checkMutable();
@@ -321,6 +332,34 @@ public class EntitySpec<T extends Entity> implements Serializable {
return this;
}
+ /** adds a policy to the spec */
+ public <V> EntitySpec<T> enricher(Enricher val) {
+ checkMutable();
+ enrichers.add(checkNotNull(val, "enricher"));
+ return this;
+ }
+
+ /** adds a policy to the spec */
+ public <V> EntitySpec<T> enricher(EnricherSpec<?> val) {
+ checkMutable();
+ enricherSpecs.add(checkNotNull(val, "enricherSpec"));
+ return this;
+ }
+
+ /** adds the supplied policies to the spec */
+ public <V> EntitySpec<T> enricherSpecs(Iterable<? extends EnricherSpec<?>> val) {
+ checkMutable();
+ enricherSpecs.addAll(Sets.newLinkedHashSet(checkNotNull(val, "enricherSpecs")));
+ return this;
+ }
+
+ /** adds the supplied policies to the spec */
+ public <V> EntitySpec<T> enrichers(Iterable<? extends Enricher> val) {
+ checkMutable();
+ enrichers.addAll(Sets.newLinkedHashSet(checkNotNull(val, "enrichers")));
+ return this;
+ }
+
/** "seals" this spec, preventing any future changes */
public EntitySpec<T> immutable() {
immutable = true;
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b8216c5e/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
new file mode 100644
index 0000000..d25f832
--- /dev/null
+++ b/api/src/main/java/brooklyn/policy/EnricherSpec.java
@@ -0,0 +1,175 @@
+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.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;
+
+/**
+ * Gives details of an enricher to be created. It describes the enricher's configuration, and is
+ * reusable to create multiple enrichers with the same configuration.
+ *
+ * To create an EnricherSpec, it is strongly encouraged to use {@code create(...)} methods.
+ *
+ * @param <T> The type of enricher to be created
+ *
+ * @author aled
+ */
+public class EnricherSpec<T extends Enricher> implements Serializable {
+
+ private static final Logger log = LoggerFactory.getLogger(EnricherSpec.class);
+
+ private final static long serialVersionUID = 1L;
+
+
+ /**
+ * Creates a new {@link EnricherSpec} instance for an enricher of the given type. The returned
+ * {@link EnricherSpec} can then be customized.
+ *
+ * @param type A {@link Enricher} class
+ */
+ public static <T extends Enricher> EnricherSpec<T> create(Class<T> type) {
+ return new EnricherSpec<T>(type);
+ }
+
+ /**
+ * Creates a new {@link EnricherSpec} instance with the given config, for an enricher of the given type.
+ *
+ * This is primarily for groovy code; equivalent to {@code EnricherSpec.create(type).configure(config)}.
+ *
+ * @param config The spec's configuration (see {@link EnricherSpec#configure(Map)}).
+ * @param type An {@link Enricher} class
+ */
+ public static <T extends Enricher> EnricherSpec<T> create(Map<?,?> config, Class<T> type) {
+ 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;
+ }
+
+ public EnricherSpec<T> displayName(String val) {
+ displayName = val;
+ 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");
+ if (entry.getKey() instanceof CharSequence)
+ flags.put(entry.getKey().toString(), entry.getValue());
+ else if (entry.getKey() instanceof ConfigKey<?>)
+ config.put((ConfigKey<?>)entry.getKey(), entry.getValue());
+ else if (entry.getKey() instanceof HasConfigKey<?>)
+ config.put(((HasConfigKey<?>)entry.getKey()).getConfigKey(), entry.getValue());
+ else {
+ log.warn("Spec "+this+" ignoring unknown config key "+entry.getKey());
+ }
+ }
+ return this;
+ }
+
+ public EnricherSpec<T> configure(CharSequence key, Object val) {
+ flags.put(checkNotNull(key, "key").toString(), val);
+ return this;
+ }
+
+ public <V> EnricherSpec<T> configure(ConfigKey<V> key, V val) {
+ config.put(checkNotNull(key, "key"), val);
+ return this;
+ }
+
+ public <V> EnricherSpec<T> configureIfNotNull(ConfigKey<V> key, V val) {
+ return (val != null) ? configure(key, val) : this;
+ }
+
+ public <V> EnricherSpec<T> configure(ConfigKey<V> key, Task<? extends V> val) {
+ config.put(checkNotNull(key, "key"), val);
+ return this;
+ }
+
+ public <V> EnricherSpec<T> configure(HasConfigKey<V> key, V val) {
+ config.put(checkNotNull(key, "key").getConfigKey(), val);
+ return this;
+ }
+
+ public <V> EnricherSpec<T> configure(HasConfigKey<V> key, Task<? extends V> val) {
+ config.put(checkNotNull(key, "key").getConfigKey(), val);
+ return this;
+ }
+
+ /**
+ * @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
+ */
+ public Map<String, ?> getFlags() {
+ return Collections.unmodifiableMap(flags);
+ }
+
+ /**
+ * @return Read-only configuration values
+ */
+ 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/brooklyn-server/blob/b8216c5e/api/src/main/java/brooklyn/policy/EnricherType.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/policy/EnricherType.java b/api/src/main/java/brooklyn/policy/EnricherType.java
new file mode 100644
index 0000000..43fb6ea
--- /dev/null
+++ b/api/src/main/java/brooklyn/policy/EnricherType.java
@@ -0,0 +1,38 @@
+package brooklyn.policy;
+
+import java.io.Serializable;
+import java.util.Set;
+
+import brooklyn.config.ConfigKey;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Gives type information for an {@link Enricher}. It is immutable.
+ *
+ * For enrichers that can support config keys etc being added on-the-fly,
+ * then this EnricherType will be a snapshot and subsequent snapshots will
+ * include the changes.
+ *
+ * @since 0.6
+ */
+@Beta
+public interface EnricherType extends Serializable {
+
+ // TODO Consider merging this with PolicyType? Have a common super-type? It also has overlap with EntityType.
+
+ /**
+ * The type name of this policy (normally the fully qualified class name).
+ */
+ String getName();
+
+ /**
+ * ConfigKeys available on this policy.
+ */
+ Set<ConfigKey<?>> getConfigKeys();
+
+ /**
+ * The ConfigKey with the given name, or null if not found.
+ */
+ ConfigKey<?> getConfigKey(String name);
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b8216c5e/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 b8e870a..6bc4791 100644
--- a/core/src/main/java/brooklyn/entity/proxying/InternalEntityFactory.java
+++ b/core/src/main/java/brooklyn/entity/proxying/InternalEntityFactory.java
@@ -16,6 +16,8 @@ import brooklyn.entity.basic.EntityInternal;
import brooklyn.entity.basic.EntityLocal;
import brooklyn.management.ManagementContext;
import brooklyn.management.internal.ManagementContextInternal;
+import brooklyn.policy.Enricher;
+import brooklyn.policy.EnricherSpec;
import brooklyn.policy.Policy;
import brooklyn.policy.PolicySpec;
import brooklyn.policy.basic.AbstractPolicy;
@@ -154,6 +156,14 @@ public class InternalEntityFactory {
for (EntityInitializer initializer: spec.getInitializers())
initializer.apply((EntityInternal)entity);
+ for (Enricher enricher : spec.getEnrichers()) {
+ entity.addEnricher(enricher);
+ }
+
+ for (EnricherSpec<?> enricherSpec : spec.getEnricherSpecs()) {
+ entity.addEnricher(policyFactory.createEnricher(enricherSpec));
+ }
+
for (Policy policy : spec.getPolicies()) {
entity.addPolicy((AbstractPolicy)policy);
}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b8216c5e/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 c4d4358..c51144d 100644
--- a/core/src/main/java/brooklyn/entity/proxying/InternalPolicyFactory.java
+++ b/core/src/main/java/brooklyn/entity/proxying/InternalPolicyFactory.java
@@ -6,8 +6,11 @@ import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import brooklyn.config.ConfigKey;
+import brooklyn.enricher.basic.AbstractEnricher;
import brooklyn.management.ManagementContext;
import brooklyn.management.internal.ManagementContextInternal;
+import brooklyn.policy.Enricher;
+import brooklyn.policy.EnricherSpec;
import brooklyn.policy.Policy;
import brooklyn.policy.PolicySpec;
import brooklyn.policy.basic.AbstractPolicy;
@@ -73,7 +76,20 @@ public class InternalPolicyFactory {
public static boolean isNewStylePolicy(Class<?> clazz) {
if (!Policy.class.isAssignableFrom(clazz)) {
- throw new IllegalArgumentException("Class "+clazz+" is not an policy");
+ throw new IllegalArgumentException("Class "+clazz+" is not a policy");
+ }
+
+ try {
+ clazz.getConstructor(new Class[0]);
+ return true;
+ } catch (NoSuchMethodException e) {
+ return false;
+ }
+ }
+
+ public static boolean isNewStyleEnricher(Class<?> clazz) {
+ if (!Enricher.class.isAssignableFrom(clazz)) {
+ throw new IllegalArgumentException("Class "+clazz+" is not an enricher");
}
try {
@@ -129,6 +145,47 @@ public class InternalPolicyFactory {
}
}
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public <T extends Enricher> T createEnricher(EnricherSpec<T> spec) {
+ if (spec.getFlags().containsKey("parent")) {
+ throw new IllegalArgumentException("Spec's flags must not contain parent; use spec.parent() instead for "+spec);
+ }
+
+ try {
+ Class<? extends T> clazz = spec.getType();
+
+ FactoryConstructionTracker.setConstructing();
+ T enricher;
+ try {
+ enricher = construct(clazz, spec);
+ } finally {
+ FactoryConstructionTracker.reset();
+ }
+
+ if (spec.getDisplayName()!=null)
+ ((AbstractEnricher)enricher).setName(spec.getDisplayName());
+
+ if (isNewStyleEnricher(clazz)) {
+ ((AbstractEnricher)enricher).setManagementContext(managementContext);
+ Map<String, Object> config = ConfigBag.newInstance().putAll(spec.getFlags()).putAll(spec.getConfig()).getAllConfig();
+ ((AbstractEnricher)enricher).configure(MutableMap.copyOf(config)); // TODO AbstractEnricher.configure modifies the map
+ }
+
+ // TODO Can we avoid this for "new-style policies"? Should we just trust the configure() method,
+ // which the user may have overridden?
+ // Also see InternalLocationFactory for same issue, which this code is based on.
+ for (Map.Entry<ConfigKey<?>, Object> entry : spec.getConfig().entrySet()) {
+ ((AbstractEnricher)enricher).setConfig((ConfigKey)entry.getKey(), entry.getValue());
+ }
+ ((AbstractEnricher)enricher).init();
+
+ return enricher;
+
+ } catch (Exception e) {
+ throw Exceptions.propagate(e);
+ }
+ }
+
private <T extends Policy> T construct(Class<? extends T> clazz, PolicySpec<T> spec) throws InstantiationException, IllegalAccessException, InvocationTargetException {
if (isNewStylePolicy(clazz)) {
return clazz.newInstance();
@@ -137,8 +194,16 @@ public class InternalPolicyFactory {
}
}
- private <T extends Policy> T constructOldStyle(Class<? extends T> clazz, Map<String,?> flags) throws InstantiationException, IllegalAccessException, InvocationTargetException {
- Optional<? extends T> v = Reflections.invokeConstructorWithArgs(clazz, new Object[] {MutableMap.copyOf(flags)}, true);
+ private <T extends Enricher> T construct(Class<? extends T> clazz, EnricherSpec<T> spec) throws InstantiationException, IllegalAccessException, InvocationTargetException {
+ if (isNewStyleEnricher(clazz)) {
+ return clazz.newInstance();
+ } else {
+ return constructOldStyle(clazz, MutableMap.copyOf(spec.getFlags()));
+ }
+ }
+
+ private <T> T constructOldStyle(Class<T> clazz, Map<String,?> flags) throws InstantiationException, IllegalAccessException, InvocationTargetException {
+ Optional<T> v = Reflections.invokeConstructorWithArgs(clazz, new Object[] {MutableMap.copyOf(flags)}, true);
if (v.isPresent()) {
return v.get();
} else {
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b8216c5e/core/src/test/java/brooklyn/entity/basic/EntitySpecTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/basic/EntitySpecTest.java b/core/src/test/java/brooklyn/entity/basic/EntitySpecTest.java
index 3d5f05d..19e4842 100644
--- a/core/src/test/java/brooklyn/entity/basic/EntitySpecTest.java
+++ b/core/src/test/java/brooklyn/entity/basic/EntitySpecTest.java
@@ -3,13 +3,20 @@ package brooklyn.entity.basic;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
+import java.util.Map;
+
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
+import brooklyn.config.ConfigKey;
+import brooklyn.enricher.basic.AbstractEnricher;
import brooklyn.entity.proxying.EntitySpec;
import brooklyn.event.basic.BasicConfigKey;
import brooklyn.location.basic.SimulatedLocation;
+import brooklyn.policy.Enricher;
+import brooklyn.policy.EnricherSpec;
+import brooklyn.policy.EnricherType;
import brooklyn.policy.Policy;
import brooklyn.policy.PolicySpec;
import brooklyn.policy.basic.AbstractPolicy;
@@ -69,9 +76,40 @@ public class EntitySpecTest {
assertEquals(Iterables.getOnlyElement(entity.getPolicies()), policy);
}
+ @Test
+ public void testAddsEnricherSpec() throws Exception {
+ entity = app.createAndManageChild(EntitySpec.create(TestEntity.class)
+ .enricher(EnricherSpec.create(MyEnricher.class)
+ .displayName("myenrichername")
+ .configure(MyEnricher.CONF1, "myconf1val")
+ .configure("myfield", "myfieldval")));
+
+ Enricher enricher = Iterables.getOnlyElement(entity.getEnrichers());
+ assertTrue(enricher instanceof MyEnricher, "enricher="+enricher);
+ assertEquals(enricher.getName(), "myenrichername");
+ assertEquals(enricher.getConfig(MyEnricher.CONF1), "myconf1val");
+ }
+
+ @Test
+ public void testAddsEnricher() throws Exception {
+ MyEnricher enricher = new MyEnricher();
+ entity = app.createAndManageChild(EntitySpec.create(TestEntity.class)
+ .enricher(enricher));
+
+ assertEquals(Iterables.getOnlyElement(entity.getEnrichers()), enricher);
+ }
+
public static class MyPolicy extends AbstractPolicy {
- public static final BasicConfigKey<String> CONF1 = new BasicConfigKey<String>(String.class, "test.conf1", "my descr, conf1", "defaultval1");
- public static final BasicConfigKey<Integer> CONF2 = new BasicConfigKey<Integer>(Integer.class, "test.conf2", "my descr, conf2", 2);
+ public static final BasicConfigKey<String> CONF1 = new BasicConfigKey<String>(String.class, "testpolicy.conf1", "my descr, conf1", "defaultval1");
+ public static final BasicConfigKey<Integer> CONF2 = new BasicConfigKey<Integer>(Integer.class, "testpolicy.conf2", "my descr, conf2", 2);
+
+ @SetFromFlag
+ public String myfield;
+ }
+
+ public static class MyEnricher extends AbstractEnricher {
+ public static final BasicConfigKey<String> CONF1 = new BasicConfigKey<String>(String.class, "testenricher.conf1", "my descr, conf1", "defaultval1");
+ public static final BasicConfigKey<Integer> CONF2 = new BasicConfigKey<Integer>(Integer.class, "testenricher.conf2", "my descr, conf2", 2);
@SetFromFlag
public String myfield;