Repository: brooklyn-server Updated Branches: refs/heads/master 374e01f41 -> a36b6412d
Test+fix DeferredSuppliers in $brooklyn:object Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/fed6e511 Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/fed6e511 Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/fed6e511 Branch: refs/heads/master Commit: fed6e511649ba825ce567405dfc758f046139e14 Parents: 374e01f Author: Aled Sage <aled.s...@gmail.com> Authored: Mon Aug 15 12:57:07 2016 +0100 Committer: Aled Sage <aled.s...@gmail.com> Committed: Tue Aug 16 10:45:19 2016 +0100 ---------------------------------------------------------------------- .../spi/dsl/methods/BrooklynDslCommon.java | 51 +++-- .../brooklyn/camp/brooklyn/ObjectsYamlTest.java | 227 +++++++++++++++++++ .../brooklyn/util/javalang/Reflections.java | 7 +- 3 files changed, 261 insertions(+), 24 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fed6e511/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java ---------------------------------------------------------------------- diff --git a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java index d6dfddd..fc8424b 100644 --- a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java +++ b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java @@ -47,6 +47,7 @@ import org.apache.brooklyn.core.mgmt.internal.ExternalConfigSupplierRegistry; import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal; import org.apache.brooklyn.core.mgmt.persist.DeserializingClassRenamesProvider; import org.apache.brooklyn.core.sensor.DependentConfiguration; +import org.apache.brooklyn.util.collections.MutableList; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.core.ClassLoaderUtils; import org.apache.brooklyn.util.core.config.ConfigBag; @@ -68,6 +69,7 @@ import com.google.common.base.Objects; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; /** static import functions which can be used in `$brooklyn:xxx` contexts */ public class BrooklynDslCommon { @@ -350,7 +352,7 @@ public class BrooklynDslCommon { Map<String, Object> config) { this.typeName = checkNotNull(typeName, "typeName"); this.type = null; - this.constructorArgs = constructorArgs; + this.constructorArgs = checkNotNull(constructorArgs, "constructorArgs"); this.factoryMethodName = null; this.factoryMethodArgs = ImmutableList.of(); this.fields = MutableMap.copyOf(fields); @@ -364,7 +366,7 @@ public class BrooklynDslCommon { Map<String, Object> config) { this.typeName = null; this.type = checkNotNull(type, "type"); - this.constructorArgs = constructorArgs; + this.constructorArgs = checkNotNull(constructorArgs, "constructorArgs"); this.factoryMethodName = null; this.factoryMethodArgs = ImmutableList.of(); this.fields = MutableMap.copyOf(fields); @@ -381,7 +383,7 @@ public class BrooklynDslCommon { this.type = null; this.constructorArgs = ImmutableList.of(); this.factoryMethodName = factoryMethodName; - this.factoryMethodArgs = factoryMethodArgs; + this.factoryMethodArgs = checkNotNull(factoryMethodArgs, "factoryMethodArgs"); this.fields = MutableMap.copyOf(fields); this.config = MutableMap.copyOf(config); } @@ -396,7 +398,7 @@ public class BrooklynDslCommon { this.type = checkNotNull(type, "type"); this.constructorArgs = ImmutableList.of(); this.factoryMethodName = factoryMethodName; - this.factoryMethodArgs = factoryMethodArgs; + this.factoryMethodArgs = checkNotNull(factoryMethodArgs, "factoryMethodArgs"); this.fields = MutableMap.copyOf(fields); this.config = MutableMap.copyOf(config); } @@ -416,7 +418,7 @@ public class BrooklynDslCommon { final Class<?> clazz = type; List<TaskAdaptable<Object>> tasks = Lists.newLinkedList(); - for (Object value : Iterables.concat(fields.values(), config.values())) { + for (Object value : Iterables.concat(fields.values(), config.values(), constructorArgs, factoryMethodArgs)) { if (value instanceof TaskAdaptable) { tasks.add((TaskAdaptable<Object>) value); } else if (value instanceof TaskFactory) { @@ -428,28 +430,31 @@ public class BrooklynDslCommon { return DependentConfiguration.transformMultiple(flags, new Function<List<Object>, Object>() { @Override public Object apply(List<Object> input) { - Iterator<Object> values = input.iterator(); - for (String name : fields.keySet()) { - Object value = fields.get(name); - if (value instanceof TaskAdaptable || value instanceof TaskFactory) { - fields.put(name, values.next()); - } else if (value instanceof DeferredSupplier) { - fields.put(name, ((DeferredSupplier<?>) value).get()); + final Iterator<Object> taskValues = input.iterator(); + Function<Object, Object> resolver = new Function<Object, Object>() { + @Override public Object apply(Object value) { + return requiresTask(value) ? taskValues.next() : resolveValue(value); } - } - for (String name : config.keySet()) { - Object value = config.get(name); - if (value instanceof TaskAdaptable || value instanceof TaskFactory) { - config.put(name, values.next()); - } else if (value instanceof DeferredSupplier) { - config.put(name, ((DeferredSupplier<?>) value).get()); - } - } + }; + Map<String, Object> resolvedFields = MutableMap.copyOf(Maps.transformValues(fields, resolver)); + Map<String, Object> resolvedConfig = MutableMap.copyOf(Maps.transformValues(config, resolver)); + List<Object> resolvedConstructorArgs = MutableList.copyOf(Lists.transform(constructorArgs, resolver)); + List<Object> resolvedFactoryMethodArgs = MutableList.copyOf(Lists.transform(factoryMethodArgs, resolver)); + if (factoryMethodName == null) { - return create(clazz, constructorArgs, fields, config); + return create(clazz, resolvedConstructorArgs, resolvedFields, resolvedConfig); } else { - return create(clazz, factoryMethodName, factoryMethodArgs, fields, config); + return create(clazz, factoryMethodName, resolvedFactoryMethodArgs, resolvedFields, resolvedConfig); + } + } + protected boolean requiresTask(Object value) { + return (value instanceof TaskAdaptable || value instanceof TaskFactory); + } + protected Object resolveValue(Object value) { + if (value instanceof DeferredSupplier) { + return ((DeferredSupplier<?>) value).get(); } + return value; } }, tasks); } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fed6e511/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ObjectsYamlTest.java ---------------------------------------------------------------------- diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ObjectsYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ObjectsYamlTest.java index ca4f91b..c372a72 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ObjectsYamlTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ObjectsYamlTest.java @@ -18,6 +18,8 @@ */ package org.apache.brooklyn.camp.brooklyn; +import static org.testng.Assert.assertEquals; + import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; @@ -39,7 +41,10 @@ import org.slf4j.LoggerFactory; import org.testng.Assert; import org.testng.annotations.Test; +import com.google.common.base.Charsets; import com.google.common.collect.Lists; +import com.google.common.hash.HashCode; +import com.google.common.hash.Hashing; @Test public class ObjectsYamlTest extends AbstractYamlTest { @@ -54,6 +59,11 @@ public class ObjectsYamlTest extends AbstractYamlTest { private Object object; // Factory method. + public static TestObject newTestObjectWithNoArgs() { + return new TestObject("myDefaultFirst", 1, "myDefaultThird"); + } + + // Factory method. public static TestObject newTestObject(String string, Integer number, Object object) { return new TestObject(string + "-suffix", number + 1, object); } @@ -84,6 +94,17 @@ public class ObjectsYamlTest extends AbstractYamlTest { } } + // TODO Copy of org.apache.brooklyn.rest.security.PasswordHasher; but this module does not + // have access to brooklyn-rest-resources (and would create a circular reference to do so) + public static class PasswordHasher { + public static String sha256(String salt, String password) { + if (salt == null) salt = ""; + byte[] bytes = (salt + password).getBytes(Charsets.UTF_8); + HashCode hash = Hashing.sha256().hashBytes(bytes); + return hash.toString(); + } + } + public static class ConfigurableObject implements Configurable { public static final ConfigKey<Integer> INTEGER = ConfigKeys.newIntegerConfigKey("config.number"); @SetFromFlag("object") @@ -339,6 +360,212 @@ public class ObjectsYamlTest extends AbstractYamlTest { Assert.assertTrue(testObjectObject instanceof SimpleTestPojo, "Expected a SimpleTestPojo: "+testObjectObject); } + @Test + public void testBrooklynObjectWithFactoryMethodNoArgs() throws Exception { + Entity testEntity = setupAndCheckTestEntityInBasicYamlWith( + " brooklyn.config:", + " test.confObject:", + " $brooklyn:object:", + " type: "+ObjectsYamlTest.class.getName()+"$TestObject", + " factoryMethod.name: newTestObjectWithNoArgs"); + + TestObject testObject = (TestObject) testEntity.getConfig(TestEntity.CONF_OBJECT); + assertEquals(testObject.getString(), "myDefaultFirst"); + assertEquals(testObject.getNumber(), Integer.valueOf(1)); + assertEquals(testObject.getObject(), "myDefaultThird"); + } + + @Test + public void testFieldsAsDeferredSuppliers() throws Exception { + // all fields as deferred suppliers + { + Entity testEntity = setupAndCheckTestEntityInBasicYamlWith( + " brooklyn.config:", + " mystring: myval", + " myint: 123", + " test.confObject:", + " $brooklyn:object:", + " type: "+ObjectsYamlTest.class.getName()+"$TestObject", + " object.fields:", + " number: $brooklyn:config(\"myint\")", + " string: $brooklyn:config(\"mystring\")"); + + TestObject testObject = (TestObject) testEntity.getConfig(TestEntity.CONF_OBJECT); + Assert.assertEquals(testObject.getNumber(), Integer.valueOf(123)); + Assert.assertEquals(testObject.getString(), "myval"); + } + + // Only first field as deferred supplier + { + Entity testEntity = setupAndCheckTestEntityInBasicYamlWith( + " brooklyn.config:", + " mystring: myval", + " myint: 123", + " test.confObject:", + " $brooklyn:object:", + " type: "+ObjectsYamlTest.class.getName()+"$TestObject", + " object.fields:", + " number: $brooklyn:config(\"myint\")", + " string: myval"); + + TestObject testObject = (TestObject) testEntity.getConfig(TestEntity.CONF_OBJECT); + Assert.assertEquals(testObject.getNumber(), Integer.valueOf(123)); + Assert.assertEquals(testObject.getString(), "myval"); + } + + // Only second field as deferred supplier + { + Entity testEntity = setupAndCheckTestEntityInBasicYamlWith( + " brooklyn.config:", + " mystring: myval", + " myint: 123", + " test.confObject:", + " $brooklyn:object:", + " type: "+ObjectsYamlTest.class.getName()+"$TestObject", + " object.fields:", + " number: 7", + " string: $brooklyn:config(\"mystring\")"); + + TestObject testObject = (TestObject) testEntity.getConfig(TestEntity.CONF_OBJECT); + Assert.assertEquals(testObject.getNumber(), Integer.valueOf(7)); + Assert.assertEquals(testObject.getString(), "myval"); + } + } + + @Test + public void testConfigAsDeferredSuppliers() throws Exception { + // all fields as deferred suppliers + { + Entity testEntity = setupAndCheckTestEntityInBasicYamlWith( + " brooklyn.config:", + " mystring: myval", + " myint: 123", + " mydouble: 1.4", + " test.confObject:", + " $brooklyn:object:", + " type: "+ObjectsYamlTest.class.getName()+"$ConfigurableObject", + " object.fields:", + " double: $brooklyn:config(\"mydouble\")", + " brooklyn.config:", + " flag: $brooklyn:config(\"mystring\")", + " config.number: $brooklyn:config(\"myint\")"); + + ConfigurableObject testObject = (ConfigurableObject) testEntity.getConfig(TestEntity.CONF_OBJECT); + assertEquals(testObject.getDouble(), Double.valueOf(1.4)); + assertEquals(testObject.getString(), "myval"); + assertEquals(testObject.getNumber(), Integer.valueOf(123)); + } + + // Only only fields (and not config) as deferred supplier + { + Entity testEntity = setupAndCheckTestEntityInBasicYamlWith( + " brooklyn.config:", + " mystring: myval", + " myint: 123", + " mydouble: 1.4", + " test.confObject:", + " $brooklyn:object:", + " type: "+ObjectsYamlTest.class.getName()+"$ConfigurableObject", + " object.fields:", + " double: $brooklyn:config(\"mydouble\")", + " brooklyn.config:", + " flag: myval", + " config.number: 123"); + + ConfigurableObject testObject = (ConfigurableObject) testEntity.getConfig(TestEntity.CONF_OBJECT); + assertEquals(testObject.getDouble(), Double.valueOf(1.4)); + assertEquals(testObject.getString(), "myval"); + assertEquals(testObject.getNumber(), Integer.valueOf(123)); + } + + // Only config (and not fields) as deferred supplier + { + Entity testEntity = setupAndCheckTestEntityInBasicYamlWith( + " brooklyn.config:", + " mystring: myval", + " myint: 123", + " mydouble: 1.4", + " test.confObject:", + " $brooklyn:object:", + " type: "+ObjectsYamlTest.class.getName()+"$ConfigurableObject", + " object.fields:", + " double: 1.4", + " brooklyn.config:", + " flag: $brooklyn:config(\"mystring\")", + " config.number: $brooklyn:config(\"myint\")"); + + ConfigurableObject testObject = (ConfigurableObject) testEntity.getConfig(TestEntity.CONF_OBJECT); + assertEquals(testObject.getDouble(), Double.valueOf(1.4)); + assertEquals(testObject.getString(), "myval"); + assertEquals(testObject.getNumber(), Integer.valueOf(123)); + } + } + + @Test + public void testConstructorArgsAsDeferredSuppliers() throws Exception { + Entity testEntity = setupAndCheckTestEntityInBasicYamlWith( + " brooklyn.config:", + " mystring: myval", + " myint: 123", + " mydouble: 1.4", + " test.confObject:", + " $brooklyn:object:", + " type: "+ObjectsYamlTest.class.getName()+"$TestObject", + " constructor.args:", + " - $brooklyn:config(\"mystring\")", + " - $brooklyn:config(\"myint\")", + " - myThirdParam"); + + TestObject testObject = (TestObject) testEntity.getConfig(TestEntity.CONF_OBJECT); + assertEquals(testObject.getNumber(), Integer.valueOf(123)); + assertEquals(testObject.getString(), "myval"); + assertEquals(testObject.getObject(), "myThirdParam"); + } + + @Test + public void testFactorArgsAsDeferredSuppliers() throws Exception { + Entity testEntity = setupAndCheckTestEntityInBasicYamlWith( + " brooklyn.config:", + " mystring: myval", + " myint: 123", + " mydouble: 1.4", + " test.confObject:", + " $brooklyn:object:", + " type: "+ObjectsYamlTest.class.getName()+"$TestObject", + " factoryMethod.name: newTestObject", + " factoryMethod.args:", + " - $brooklyn:config(\"mystring\")", + " - $brooklyn:config(\"myint\")", + " - myThirdParam"); + + TestObject testObject = (TestObject) testEntity.getConfig(TestEntity.CONF_OBJECT); + assertEquals(testObject.getNumber(), Integer.valueOf(124)); // factory method adds one + assertEquals(testObject.getString(), "myval-suffix"); + assertEquals(testObject.getObject(), "myThirdParam"); + } + + @Test + public void testCallingPasswordHasher() throws Exception { + Entity testEntity = setupAndCheckTestEntityInBasicYamlWith( + " brooklyn.config:", + " brooklyn.password: mypassword", + " brooklyn.password.sha256:", + " brooklyn.password.salt: $brooklyn:entityId()", + " brooklyn.password.sha256:", + " $brooklyn:object:", + " type: "+PasswordHasher.class.getName(), + " factoryMethod.name: sha256", + " factoryMethod.args:", + " - $brooklyn:config(\"brooklyn.password.salt\")", + " - $brooklyn:config(\"brooklyn.password\")"); + + String salt = (String) testEntity.config().get(ConfigKeys.newConfigKey(Object.class, "brooklyn.password.salt")); + String sha256 = (String) testEntity.config().get(ConfigKeys.newConfigKey(Object.class, "brooklyn.password.sha256")); + + assertEquals(salt, testEntity.getId()); + assertEquals(sha256, PasswordHasher.sha256(salt, "mypassword")); + } + @Override protected Logger getLogger() { return log; http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fed6e511/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Reflections.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Reflections.java b/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Reflections.java index 37f3fe6..5af8ae9 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Reflections.java +++ b/utils/common/src/main/java/org/apache/brooklyn/util/javalang/Reflections.java @@ -57,6 +57,7 @@ import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; import com.google.common.collect.Sets; /** @@ -891,7 +892,11 @@ public class Reflections { } } - return Maybe.absent("Method not found matching given args"); + List<String> argTypes = Lists.newArrayList(); + for (Object arg : args) { + argTypes.add(arg == null ? "<null>" : arg.getClass().getSimpleName()); + } + return Maybe.absent("Method '"+method+"' not found matching given args of type "+argTypes); } /** true iff all args match the corresponding types */