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 2022/08/22 09:06:12 UTC
[brooklyn-server] branch master updated: backwards compatibility for `location` singular to auto-flatten / run as has-element check
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 <al...@cloudsoft.io>
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> {
+ }
+
}