This is an automated email from the ASF dual-hosted git repository.
heneveld pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brooklyn-server.git
The following commit(s) were added to refs/heads/master by this push:
new bd7db292cc backwards compatibility for `location` singular to
auto-flatten / run as has-element check
bd7db292cc is described below
commit bd7db292cc4eb3ffc45c8fc18669655f4c726371
Author: Alex Heneveld <[email protected]>
AuthorDate: Mon Aug 22 09:43:49 2022 +0100
backwards compatibility for `location` singular to auto-flatten / run as
has-element check
plus same for child, tag
---
.../brooklyn/spi/dsl/DslPredicateYamlTest.java | 196 ++++++++++++++++++---
.../util/core/predicates/DslPredicates.java | 81 +++++++--
2 files changed, 244 insertions(+), 33 deletions(-)
diff --git
a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslPredicateYamlTest.java
b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslPredicateYamlTest.java
index 4688964004..db25f2433e 100644
---
a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslPredicateYamlTest.java
+++
b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslPredicateYamlTest.java
@@ -15,41 +15,19 @@
*/
package org.apache.brooklyn.camp.brooklyn.spi.dsl;
-import com.google.common.base.Function;
-import com.google.common.collect.Iterables;
import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.api.entity.EntitySpec;
import org.apache.brooklyn.camp.brooklyn.AbstractYamlTest;
-import
org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.DslTestObjects.DslTestCallable;
-import
org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.DslTestObjects.DslTestSupplierWrapper;
-import
org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.DslTestObjects.TestDslSupplier;
-import
org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.DslTestObjects.TestDslSupplierValue;
-import
org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.custom.UserSuppliedPackageType;
-import org.apache.brooklyn.config.ConfigKey;
import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.entity.Dumper;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.core.sensor.Sensors;
-import org.apache.brooklyn.core.test.entity.TestApplication;
import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.entity.group.DynamicCluster;
import org.apache.brooklyn.entity.stock.BasicApplication;
import org.apache.brooklyn.entity.stock.BasicEntity;
-import org.apache.brooklyn.entity.stock.BasicStartable;
import org.apache.brooklyn.test.Asserts;
import org.apache.brooklyn.util.collections.MutableMap;
import org.apache.brooklyn.util.core.flags.TypeCoercions;
import org.apache.brooklyn.util.core.predicates.DslPredicates;
-import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.guava.Maybe;
import org.testng.annotations.Test;
-import java.util.concurrent.ExecutionException;
-
-import static org.testng.Assert.assertEquals;
-
public class DslPredicateYamlTest extends AbstractYamlTest {
@Test
@@ -117,4 +95,176 @@ public class DslPredicateYamlTest extends AbstractYamlTest
{
Asserts.assertTrue( predicate.apply(app) );
}
+ @Test
+ public void testDslTargetLocationRetargets() throws Exception {
+ Entity app = createAndStartApplication(
+ "services:",
+ "- type: " + BasicApplication.class.getName(),
+ " location: localhost",
+ " brooklyn.config:",
+ " test.confPredicate:",
+ " target: location",
+ " tag: yes!");
+ // 'location' can be expanded as list
+ DslPredicates.DslPredicate predicate =
app.config().get(TestEntity.CONF_PREDICATE);
+ Asserts.assertFalse( predicate.apply(app) );
+ app.getLocations().iterator().next().tags().addTag("yes!");
+ Asserts.assertTrue( predicate.apply(app) );
+
+ app = createAndStartApplication(
+ "services:",
+ "- type: " + BasicApplication.class.getName(),
+ " location: localhost",
+ " brooklyn.config:",
+ " test.confPredicate:",
+ " target: locations",
+ " tag: yes!");
+ // 'locations' requires has-element, cannot be auto-expanded
+ predicate = app.config().get(TestEntity.CONF_PREDICATE);
+ app.getLocations().iterator().next().tags().addTag("yes!");
+ Asserts.assertFalse( predicate.apply(app) );
+
+ app = createAndStartApplication(
+ "services:",
+ "- type: " + BasicApplication.class.getName(),
+ " location: localhost",
+ " brooklyn.config:",
+ " test.confPredicate:",
+ " target: locations",
+ " has-element:",
+ " tag: yes!");
+ // 'locations' works if has-element specified
+ predicate = app.config().get(TestEntity.CONF_PREDICATE);
+ Asserts.assertFalse( predicate.apply(app) );
+ app.getLocations().iterator().next().tags().addTag("yes!");
+ Asserts.assertTrue( predicate.apply(app) );
+
+ app = createAndStartApplication(
+ "services:",
+ "- type: " + BasicApplication.class.getName(),
+ " location: localhost",
+ " brooklyn.config:",
+ " test.confPredicate:",
+ " target: location",
+ " has-element:",
+ " tag: yes!");
+ // 'location' also _accepts_ has-element (skips expanding)
+ predicate = app.config().get(TestEntity.CONF_PREDICATE);
+ Asserts.assertFalse( predicate.apply(app) );
+ app.getLocations().iterator().next().tags().addTag("yes!");
+ Asserts.assertTrue( predicate.apply(app) );
+ }
+
+ @Test
+ public void testDslTargetTagRetargets() throws Exception {
+ Entity app = createAndStartApplication(
+ "services:",
+ "- type: " + BasicApplication.class.getName(),
+ " brooklyn.config:",
+ " test.confPredicate:",
+ " target: tag",
+ " equals: yes!");
+ // 'tag' can be expanded as list
+ DslPredicates.DslPredicate predicate =
app.config().get(TestEntity.CONF_PREDICATE);
+// Asserts.assertFalse( predicate.apply(app) );
+ app.tags().addTag("yes!");
+ Asserts.assertTrue( predicate.apply(app) );
+
+ app = createAndStartApplication(
+ "services:",
+ "- type: " + BasicApplication.class.getName(),
+ " brooklyn.config:",
+ " test.confPredicate:",
+ " target: tags",
+ " equals: yes!");
+ // 'tags' requires has-element, cannot be auto-expanded
+ predicate = app.config().get(TestEntity.CONF_PREDICATE);
+ app.tags().addTag("yes!");
+ Asserts.assertFalse( predicate.apply(app) );
+
+ app = createAndStartApplication(
+ "services:",
+ "- type: " + BasicApplication.class.getName(),
+ " brooklyn.config:",
+ " test.confPredicate:",
+ " target: tags",
+ " has-element:",
+ " equals: yes!");
+ // 'tags' works if has-element specified
+ predicate = app.config().get(TestEntity.CONF_PREDICATE);
+ Asserts.assertFalse( predicate.apply(app) );
+ app.tags().addTag("yes!");
+ Asserts.assertTrue( predicate.apply(app) );
+
+ app = createAndStartApplication(
+ "services:",
+ "- type: " + BasicApplication.class.getName(),
+ " brooklyn.config:",
+ " test.confPredicate:",
+ " target: tag",
+ " has-element:",
+ " equals: yes!");
+ // 'tag' also _accepts_ has-element (skips expanding)
+ predicate = app.config().get(TestEntity.CONF_PREDICATE);
+ Asserts.assertFalse( predicate.apply(app) );
+ app.tags().addTag("yes!");
+ Asserts.assertTrue( predicate.apply(app) );
+ }
+
+ @Test
+ public void testDslTargetChildRetargets() throws Exception {
+ Entity app = createAndStartApplication(
+ "services:",
+ "- type: " + BasicApplication.class.getName(),
+ " brooklyn.config:",
+ " test.confPredicate:",
+ " target: child",
+ " tag: yes!");
+ // 'child' can be expanded as list
+ DslPredicates.DslPredicate predicate =
app.config().get(TestEntity.CONF_PREDICATE);
+ Asserts.assertFalse( predicate.apply(app) );
+ app.addChild(EntitySpec.create(BasicEntity.class).tag("yes!"));
+ Asserts.assertTrue( predicate.apply(app) );
+
+ app = createAndStartApplication(
+ "services:",
+ "- type: " + BasicApplication.class.getName(),
+ " brooklyn.config:",
+ " test.confPredicate:",
+ " target: children",
+ " tag: yes!");
+ // 'children' requires has-element, cannot be auto-expanded
+ predicate = app.config().get(TestEntity.CONF_PREDICATE);
+ app.addChild(EntitySpec.create(BasicEntity.class).tag("yes!"));
+ Asserts.assertFalse( predicate.apply(app) );
+
+ app = createAndStartApplication(
+ "services:",
+ "- type: " + BasicApplication.class.getName(),
+ " brooklyn.config:",
+ " test.confPredicate:",
+ " target: children",
+ " has-element:",
+ " tag: yes!");
+ // 'children' works if has-element specified
+ predicate = app.config().get(TestEntity.CONF_PREDICATE);
+ Asserts.assertFalse( predicate.apply(app) );
+ app.addChild(EntitySpec.create(BasicEntity.class).tag("yes!"));
+ Asserts.assertTrue( predicate.apply(app) );
+
+ app = createAndStartApplication(
+ "services:",
+ "- type: " + BasicApplication.class.getName(),
+ " brooklyn.config:",
+ " test.confPredicate:",
+ " target: child",
+ " has-element:",
+ " tag: yes!");
+ // 'child' also _accepts_ has-element (skips expanding)
+ predicate = app.config().get(TestEntity.CONF_PREDICATE);
+ Asserts.assertFalse( predicate.apply(app) );
+ app.addChild(EntitySpec.create(BasicEntity.class).tag("yes!"));
+ Asserts.assertTrue( predicate.apply(app) );
+ }
+
}
diff --git
a/core/src/main/java/org/apache/brooklyn/util/core/predicates/DslPredicates.java
b/core/src/main/java/org/apache/brooklyn/util/core/predicates/DslPredicates.java
index d027292fd9..a2f2b72d2e 100644
---
a/core/src/main/java/org/apache/brooklyn/util/core/predicates/DslPredicates.java
+++
b/core/src/main/java/org/apache/brooklyn/util/core/predicates/DslPredicates.java
@@ -21,7 +21,6 @@ package org.apache.brooklyn.util.core.predicates;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.util.TokenBuffer;
@@ -32,6 +31,7 @@ import com.google.common.collect.Iterables;
import com.google.common.reflect.TypeToken;
import com.jayway.jsonpath.JsonPath;
import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.location.Location;
import org.apache.brooklyn.api.objs.BrooklynObject;
import org.apache.brooklyn.api.objs.Configurable;
import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
@@ -42,14 +42,12 @@ import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
import org.apache.brooklyn.core.resolve.jackson.BeanWithTypeUtils;
import
org.apache.brooklyn.core.resolve.jackson.BrooklynJacksonSerializationUtils;
import
org.apache.brooklyn.core.resolve.jackson.JsonSymbolDependentDeserializer;
-import org.apache.brooklyn.core.resolve.jackson.WrappedValue;
import org.apache.brooklyn.core.sensor.Sensors;
import org.apache.brooklyn.util.JavaGroovyEquivalents;
import org.apache.brooklyn.util.collections.MutableList;
import org.apache.brooklyn.util.collections.MutableMap;
import org.apache.brooklyn.util.core.flags.BrooklynTypeNameResolution;
import org.apache.brooklyn.util.core.flags.TypeCoercions;
-import org.apache.brooklyn.util.core.json.BrooklynObjectsJsonMapper;
import org.apache.brooklyn.util.core.task.DeferredSupplier;
import org.apache.brooklyn.util.core.task.Tasks;
import org.apache.brooklyn.util.core.task.ValueResolver;
@@ -256,6 +254,9 @@ public class DslPredicates {
public boolean apply(T input) {
Maybe<Object> result = resolveTargetAgainstInput(input);
+ if (result.isPresent() && result.get() instanceof
RetargettedPredicateEvaluation) {
+ return
((RetargettedPredicateEvaluation)result.get()).apply(input);
+ }
return applyToResolved(result);
}
@@ -310,7 +311,7 @@ public class DslPredicates {
String jsonpathTidied = jsonpath;
if (jsonpathTidied!=null && !jsonpathTidied.startsWith("$")) {
if (jsonpathTidied.startsWith("@") ||
jsonpathTidied.startsWith(".") || jsonpathTidied.startsWith("[")) {
- jsonpathTidied = "$" + jsonpathTidied;
+ jsonpathTidied = '$' + jsonpathTidied;
} else {
jsonpathTidied = "$." + jsonpathTidied;
}
@@ -330,6 +331,8 @@ public class DslPredicates {
});
}
+ /** returns the resolved, possibly redirected target for this test
wrapped in a maybe, or absent if there is no valid value/target.
+ * may also return {@link RetargettedPredicateEvaluation} predicate if
a different predicate should be run on the same input */
protected Maybe<Object> resolveTargetAgainstInput(Object input) {
Map<String,Function<Object,Maybe<Object>>> specialResolvers =
MutableMap.of();
collectApplicableSpecialFieldTargetResolvers(specialResolvers);
@@ -452,7 +455,7 @@ public class DslPredicates {
}
@Beta
- public static class DslPredicateDefault<T2> extends DslPredicateBase<T2>
implements DslPredicate<T2> {
+ public static class DslPredicateDefault<T2> extends DslPredicateBase<T2>
implements DslPredicate<T2>, Cloneable {
public DslPredicateDefault() {}
// allow a string or int to be an implicit equality target
@@ -465,6 +468,15 @@ public class DslPredicates {
public String sensor;
public DslPredicate tag;
+ @Override
+ protected DslPredicateDefault<T2> clone() {
+ try {
+ return (DslPredicateDefault<T2>) super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw Exceptions.propagate(e);
+ }
+ }
+
protected void
collectApplicableSpecialFieldTargetResolvers(Map<String,Function<Object,
Maybe<Object>>> resolvers) {
super.collectApplicableSpecialFieldTargetResolvers(resolvers);
@@ -509,14 +521,61 @@ public class DslPredicates {
}
protected Maybe<Object> resolveTargetStringAgainstInput(String target,
Object input) {
- if ("location".equals(target) && input instanceof Entity) return
Maybe.of( Locations.getLocationsCheckingAncestors(null, (Entity)input) );
- if ("locations".equals(target) && input instanceof Entity) return
Maybe.of( Locations.getLocationsCheckingAncestors(null, (Entity)input) );
- if ("children".equals(target) && input instanceof Entity) return
Maybe.of( ((Entity)input).getChildren() );
- if ("tags".equals(target) && input instanceof BrooklynObject)
return Maybe.of( ((BrooklynObject)input).tags().getTags() );
+ Maybe<Object> candidate;
+ candidate =
resolvePluralNormallyOrSingularAsHasElementRetargettedPredicate(target, input,
+ "locations", x -> x instanceof Entity, x ->
Maybe.of(Locations.getLocationsCheckingAncestors(null, (Entity) x)),
+ "location", x -> x instanceof Location);
+ if (candidate!=null) return candidate;
+ candidate =
resolvePluralNormallyOrSingularAsHasElementRetargettedPredicate(target, input,
+ "tags", x -> x instanceof BrooklynObject, x -> Maybe.of(
((BrooklynObject)x).tags().getTags() ),
+ "tag", x -> false);
+ if (candidate!=null) return candidate;
+ candidate =
resolvePluralNormallyOrSingularAsHasElementRetargettedPredicate(target, input,
+ "children", x -> x instanceof Entity, x ->
Maybe.of(((Entity) x).getChildren()),
+ "child", x -> false);
+ if (candidate!=null) return candidate;
return Maybe.absent("Unsupported target '"+target+"' on input
"+input);
}
+ protected Maybe<Object> resolveAsHasElementRetargettedPredicate(String
target, Object inputValue, Predicate<Object>
checkPredicateRetargettingNotNeeded, Predicate<Object> checkValueRetargettable,
Function<Object,Maybe<Object>> retargetValue) {
+ if (inputValue == null ||
checkPredicateRetargettingNotNeeded.test(inputValue)) {
+ // already processsed
+ return Maybe.of(inputValue);
+ }
+ if (hasElement!=null) {
+ // caller is already asking for a member of this list, don't
rewrite
+ return retargetValue.apply(inputValue);
+ }
+ if (!checkValueRetargettable.test(inputValue)) {
+ return Maybe.absent("Target " + target + " not applicable to "
+ inputValue);
+ }
+
+ // keyword 'location' means to re-run checking any element
+ RetargettedPredicateEvaluation retargetPredicate = new
RetargettedPredicateEvaluation();
+ retargetPredicate.target = target;
+ retargetPredicate.hasElement = this.clone();
+ ((DslPredicateDefault)retargetPredicate.hasElement).target = null;
+ return Maybe.of(retargetPredicate);
+ }
+
+ protected Maybe<Object>
resolvePluralNormallyOrSingularAsHasElementRetargettedPredicate(String target,
Object inputValue, String plural, Predicate<Object> checkValueRetargettable,
Function<Object,Maybe<Object>> retargetValue,
+
String singular, Predicate<Object>
checkSingularTargetPredicateRetargettingNotNeeded) {
+ if (plural.equals(target)) {
+ if (!checkValueRetargettable.test(inputValue)) {
+ return Maybe.absent("Target " + target + " not applicable
to " + inputValue);
+ }
+ return retargetValue.apply(inputValue);
+ }
+
+ if (singular.equals(target)) {
+ return resolveAsHasElementRetargettedPredicate(target,
inputValue, checkSingularTargetPredicateRetargettingNotNeeded,
checkValueRetargettable, retargetValue);
+ }
+
+ // checks didn't apply
+ return null;
+ }
+
@Override
public void applyToResolved(Maybe<Object> result, CheckCounts checker)
{
super.applyToResolved(result, checker);
@@ -543,7 +602,6 @@ public class DslPredicates {
public static class DslEntityPredicateDefault extends
DslPredicateDefault<Entity> implements DslEntityPredicate {
public DslEntityPredicateDefault() { super(); }
public DslEntityPredicateDefault(String implicitEquals) {
super(implicitEquals); }
-
}
@Beta
@@ -675,4 +733,7 @@ public class DslPredicates {
return result;
}
+ static class RetargettedPredicateEvaluation<T> extends
DslPredicateDefault<T> {
+ }
+
}