Repository: brooklyn-server
Updated Branches:
  refs/heads/master ad8574f5a -> 04c3283f6


Adds constraint (required|forbidden)unlessAnyOf


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

Branch: refs/heads/master
Commit: 554b9f7e560269b797220ba231ddf9f4f139f4f6
Parents: c3d71a2
Author: Aled Sage <[email protected]>
Authored: Mon Oct 8 23:15:16 2018 +0100
Committer: Aled Sage <[email protected]>
Committed: Mon Oct 8 19:52:16 2018 -0700

----------------------------------------------------------------------
 .../brooklyn/core/config/ConfigConstraints.java | 56 +++++++++++++++++---
 .../core/objs/ConstraintSerialization.java      | 12 ++++-
 .../core/config/ConfigKeyConstraintTest.java    | 40 +++++++++++++-
 .../core/objs/ConstraintSerializationTest.java  |  3 ++
 4 files changed, 101 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/554b9f7e/core/src/main/java/org/apache/brooklyn/core/config/ConfigConstraints.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/config/ConfigConstraints.java 
b/core/src/main/java/org/apache/brooklyn/core/config/ConfigConstraints.java
index 67d8aef..b0ed3f8 100644
--- a/core/src/main/java/org/apache/brooklyn/core/config/ConfigConstraints.java
+++ b/core/src/main/java/org/apache/brooklyn/core/config/ConfigConstraints.java
@@ -19,10 +19,12 @@
 
 package org.apache.brooklyn.core.config;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
+import java.util.stream.Collectors;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.Location;
@@ -44,6 +46,8 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 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;
 
@@ -255,18 +259,34 @@ public abstract class ConfigConstraints<T extends 
BrooklynObject> {
         }
     }
     
-    private static abstract class OtherKeyPredicate implements 
BrooklynObjectPredicate<Object> {
-        private final String otherKeyName;
-
+    private static abstract class OtherKeyPredicate extends OtherKeysPredicate 
{
         public OtherKeyPredicate(String otherKeyName) {
-            this.otherKeyName = otherKeyName;
+            super(ImmutableList.of(otherKeyName));
+        }
+
+        @Override
+        public boolean test(Object thisValue, List<Object> otherValues) {
+            return test(thisValue, Iterables.getOnlyElement(otherValues));
+        }
+
+        public abstract boolean test(Object thisValue, Object otherValue);
+    }
+    
+    private static abstract class OtherKeysPredicate implements 
BrooklynObjectPredicate<Object> {
+        private final List<String> otherKeyNames;
+
+        public OtherKeysPredicate(List<String> otherKeyNames) {
+            this.otherKeyNames = otherKeyNames;
         }
 
         public abstract String predicateName();
         
         @Override
         public String toString() {
-            return 
predicateName()+"("+JavaStringEscapes.wrapJavaString(otherKeyName)+")";
+            String params = otherKeyNames.stream()
+                    .map(k -> JavaStringEscapes.wrapJavaString(k))
+                    .collect(Collectors.joining(", "));
+            return predicateName()+"("+params+")";
         }
         
         @Override
@@ -278,11 +298,14 @@ public abstract class ConfigConstraints<T extends 
BrooklynObject> {
         public boolean apply(Object input, BrooklynObject context) {
             if (context==null) return true;
             // would be nice to offer an explanation, but that will need a 
richer API or a thread local
-            return test(input, 
context.config().get(ConfigKeys.newConfigKey(Object.class, otherKeyName)));
+            List<Object> vals = new ArrayList<>();
+            for (String otherKeyName : otherKeyNames) {
+                
vals.add(context.config().get(ConfigKeys.newConfigKey(Object.class, 
otherKeyName)));
+            }
+            return test(input, vals);
         }
         
-        public abstract boolean test(Object thisValue, Object otherValue);
-        
+        public abstract boolean test(Object thisValue, List<Object> 
otherValues);
     }
     
     public static Predicate<Object> forbiddenIf(String otherKeyName) { return 
new ForbiddenIfPredicate(otherKeyName); }
@@ -321,4 +344,21 @@ public abstract class ConfigConstraints<T extends 
BrooklynObject> {
         } 
     }
     
+    public static Predicate<Object> forbiddenUnlessAnyOf(List<String> 
otherKeyNames) { return new ForbiddenUnlessAnyOfPredicate(otherKeyNames); }
+    protected static class ForbiddenUnlessAnyOfPredicate extends 
OtherKeysPredicate {
+        public ForbiddenUnlessAnyOfPredicate(List<String> otherKeyNames) { 
super(otherKeyNames); }
+        @Override public String predicateName() { return 
"forbiddenUnlessAnyOf"; }
+        @Override public boolean test(Object thisValue, List<Object> 
otherValue) {
+            return (thisValue==null) || (otherValue!=null && 
Iterables.tryFind(otherValue, Predicates.notNull()).isPresent());
+        } 
+    }
+    
+    public static Predicate<Object> requiredUnlessAnyOf(List<String> 
otherKeyNames) { return new RequiredUnlessAnyOfPredicate(otherKeyNames); }
+    protected static class RequiredUnlessAnyOfPredicate extends 
OtherKeysPredicate {
+        public RequiredUnlessAnyOfPredicate(List<String> otherKeyNames) { 
super(otherKeyNames); }
+        @Override public String predicateName() { return 
"requiredUnlessAnyOf"; }
+        @Override public boolean test(Object thisValue, List<Object> 
otherValue) { 
+            return (thisValue!=null) || (otherValue!=null && 
Iterables.tryFind(otherValue, Predicates.notNull()).isPresent());
+        } 
+    }
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/554b9f7e/core/src/main/java/org/apache/brooklyn/core/objs/ConstraintSerialization.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/objs/ConstraintSerialization.java 
b/core/src/main/java/org/apache/brooklyn/core/objs/ConstraintSerialization.java
index 32b71f0..2cb8ea0 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/objs/ConstraintSerialization.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/objs/ConstraintSerialization.java
@@ -28,6 +28,7 @@ import java.util.function.Function;
 import java.util.function.Supplier;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigConstraints;
@@ -35,6 +36,7 @@ import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.core.ResourcePredicates;
+import org.apache.brooklyn.util.core.flags.TypeCoercions;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.text.StringEscapes.JavaStringEscapes;
 import org.apache.brooklyn.util.text.StringPredicates;
@@ -65,8 +67,8 @@ public class ConstraintSerialization {
         ConstraintSerialization serialization;
         
         public PredicateSerializationRuleAdder(Function<T, Predicate<?>> 
constructor, Function<List<?>, T> constructorArgsFromList, T 
constructorSampleInput) {
-            this.constructorArgsFromList = constructorArgsFromList;
             this.constructor = constructor;
+            this.constructorArgsFromList = constructorArgsFromList;
             this.constructorSampleInput = constructorSampleInput;
         }
         
@@ -82,6 +84,12 @@ public class ConstraintSerialization {
                 o -> Strings.toString(Iterables.getOnlyElement(o)), "");
         }
         
+        public static PredicateSerializationRuleAdder<List<String>> 
listConstructor(Function<List<String>,Predicate<?>> constructor) {
+            Function<Object, String> cooercer = (o) -> TypeCoercions.coerce(o, 
String.class);
+            Function<List<?>, List<String>> constructorArgsFromList = (o) -> 
o.stream().map(cooercer).collect(Collectors.toList());
+            return new 
PredicateSerializationRuleAdder<List<String>>(constructor, 
constructorArgsFromList, ImmutableList.of());
+        }
+        
         public static PredicateSerializationRuleAdder<Void> 
noArgConstructor(Supplier<Predicate<?>> constructor) {
             return new PredicateSerializationRuleAdder<Void>(
                 (o) -> constructor.get(), o -> null, null);
@@ -185,6 +193,8 @@ public class ConstraintSerialization {
         
PredicateSerializationRuleAdder.stringConstructor(ConfigConstraints::forbiddenUnless).add(this);
         
PredicateSerializationRuleAdder.stringConstructor(ConfigConstraints::requiredIf).add(this);
         
PredicateSerializationRuleAdder.stringConstructor(ConfigConstraints::requiredUnless).add(this);
+        
PredicateSerializationRuleAdder.listConstructor(ConfigConstraints::requiredUnlessAnyOf).add(this);
+        
PredicateSerializationRuleAdder.listConstructor(ConfigConstraints::forbiddenUnlessAnyOf).add(this);
     }
     
     public final static ConstraintSerialization INSTANCE = new 
ConstraintSerialization();

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/554b9f7e/core/src/test/java/org/apache/brooklyn/core/config/ConfigKeyConstraintTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/brooklyn/core/config/ConfigKeyConstraintTest.java
 
b/core/src/test/java/org/apache/brooklyn/core/config/ConfigKeyConstraintTest.java
index 16f2f77..656ca3e 100644
--- 
a/core/src/test/java/org/apache/brooklyn/core/config/ConfigKeyConstraintTest.java
+++ 
b/core/src/test/java/org/apache/brooklyn/core/config/ConfigKeyConstraintTest.java
@@ -350,6 +350,8 @@ public class ConfigKeyConstraintTest extends 
BrooklynAppUnitTestSupport {
     public static interface 
EntityForForbiddenAndRequiredConditionalConstraints extends TestEntity {
         ConfigKey<Object> X = ConfigKeys.builder(Object.class).name("x")
                 .build();
+        ConfigKey<Object> Y = ConfigKeys.builder(Object.class).name("y")
+                .build();
     }
     
@ImplementedBy(EntityForForbiddenAndRequiredConditionalConstraintsForbiddenIfImpl.class)
     public static interface 
EntityForForbiddenAndRequiredConditionalConstraintsForbiddenIf extends 
EntityForForbiddenAndRequiredConditionalConstraints {
@@ -379,6 +381,20 @@ public class ConfigKeyConstraintTest extends 
BrooklynAppUnitTestSupport {
     }
     public static class 
EntityForForbiddenAndRequiredConditionalConstraintsRequiredUnlessImpl extends 
TestEntityImpl implements 
EntityForForbiddenAndRequiredConditionalConstraintsRequiredUnless {}
 
+    
@ImplementedBy(EntityForForbiddenAndRequiredConditionalConstraintsRequiredUnlessAnyOfImpl.class)
+    public static interface 
EntityForForbiddenAndRequiredConditionalConstraintsRequiredUnlessAnyOf extends 
EntityForForbiddenAndRequiredConditionalConstraints {
+        static ConfigKey<Object> RUAO = 
ConfigKeys.builder(Object.class).name("requiredUnlessAnyOfXY")
+                
.constraint(ConfigConstraints.requiredUnlessAnyOf(ImmutableList.of("x", 
"y"))).build();
+    }
+    public static class 
EntityForForbiddenAndRequiredConditionalConstraintsRequiredUnlessAnyOfImpl 
extends TestEntityImpl implements 
EntityForForbiddenAndRequiredConditionalConstraintsRequiredUnlessAnyOf {}
+
+    
@ImplementedBy(EntityForForbiddenAndRequiredConditionalConstraintsForbiddenUnlessAnyOfImpl.class)
+    public static interface 
EntityForForbiddenAndRequiredConditionalConstraintsForbiddenUnlessAnyOf extends 
EntityForForbiddenAndRequiredConditionalConstraints {
+        static ConfigKey<Object> FUAO = 
ConfigKeys.builder(Object.class).name("forbiddenUnlessAnyOfXY")
+                
.constraint(ConfigConstraints.forbiddenUnlessAnyOf(ImmutableList.of("x", 
"y"))).build();
+    }
+    public static class 
EntityForForbiddenAndRequiredConditionalConstraintsForbiddenUnlessAnyOfImpl 
extends TestEntityImpl implements 
EntityForForbiddenAndRequiredConditionalConstraintsForbiddenUnlessAnyOf {}
+
     @Test
     public void testForbiddenAndRequiredConditionalConstraintsForbiddenIf() {
         
assertKeyBehaviour(EntityForForbiddenAndRequiredConditionalConstraintsForbiddenIf.class,
 EntityForForbiddenAndRequiredConditionalConstraintsForbiddenIf.FI,
@@ -398,11 +414,33 @@ public class ConfigKeyConstraintTest extends 
BrooklynAppUnitTestSupport {
     }
 
     @Test
-    public void 
testForbiddenAndRequiredConditionalConstraintsRequiredUnlelss() {
+    public void testForbiddenAndRequiredConditionalConstraintsRequiredUnless() 
{
         
assertKeyBehaviour(EntityForForbiddenAndRequiredConditionalConstraintsRequiredUnless.class,
 EntityForForbiddenAndRequiredConditionalConstraintsRequiredUnless.RU,
                 true, true, true, false);
     }
 
+    @Test
+    public void 
testForbiddenAndRequiredConditionalConstraintsRequiredUnlessAnyOf() {
+        
Class<EntityForForbiddenAndRequiredConditionalConstraintsRequiredUnlessAnyOf> 
clazz = 
EntityForForbiddenAndRequiredConditionalConstraintsRequiredUnlessAnyOf.class;
+        ConfigKey<Object> key = 
EntityForForbiddenAndRequiredConditionalConstraintsRequiredUnlessAnyOf.RUAO;
+        assertKeyBehaviour(clazz, key,
+                true, true, true, false);
+        assertKeyBehaviour("only other key set", clazz, MutableMap.of("y", 
"myval"), true);
+        assertKeyBehaviour("both set", clazz, MutableMap.of("y", "myval", key, 
"myval"), true);
+        assertKeyBehaviour("both set", clazz, MutableMap.of("x", "myval", "y", 
"myval", key, "myval"), true);
+    }
+
+    @Test
+    public void 
testForbiddenAndRequiredConditionalConstraintsForbiddenUnlessAnyOf() {
+        
Class<EntityForForbiddenAndRequiredConditionalConstraintsForbiddenUnlessAnyOf> 
clazz = 
EntityForForbiddenAndRequiredConditionalConstraintsForbiddenUnlessAnyOf.class;
+        ConfigKey<Object> key = 
EntityForForbiddenAndRequiredConditionalConstraintsForbiddenUnlessAnyOf.FUAO;
+        assertKeyBehaviour(clazz, key,
+                true, true, false, true);
+        assertKeyBehaviour("only other key set", clazz, MutableMap.of("y", 
"myval"), true);
+        assertKeyBehaviour("both set", clazz, MutableMap.of("y", "myval", key, 
"myval"), true);
+        assertKeyBehaviour("both set", clazz, MutableMap.of("x", "myval", "y", 
"myval", key, "myval"), true);
+    }
+
     private void assertKeyBehaviour(Class<? extends Entity> clazz, 
ConfigKey<Object> key, boolean ifBoth, boolean ifJustX, boolean ifJustThis, 
boolean ifNone) {
         assertKeyBehaviour("both set", clazz, MutableMap.of("x", "myval", key, 
"myval"), ifBoth);
         assertKeyBehaviour("only other key set", clazz, MutableMap.of("x", 
"myval"), ifJustX);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/554b9f7e/core/src/test/java/org/apache/brooklyn/core/objs/ConstraintSerializationTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/brooklyn/core/objs/ConstraintSerializationTest.java
 
b/core/src/test/java/org/apache/brooklyn/core/objs/ConstraintSerializationTest.java
index 0882325..66747ac 100644
--- 
a/core/src/test/java/org/apache/brooklyn/core/objs/ConstraintSerializationTest.java
+++ 
b/core/src/test/java/org/apache/brooklyn/core/objs/ConstraintSerializationTest.java
@@ -31,6 +31,7 @@ import org.testng.annotations.Test;
 
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableList;
 import com.google.gson.Gson;
 
 public class ConstraintSerializationTest extends BrooklynMgmtUnitTestSupport {
@@ -48,6 +49,8 @@ public class ConstraintSerializationTest extends 
BrooklynMgmtUnitTestSupport {
         assertPredJsonBidi(ConfigConstraints.forbiddenUnless("myother"), 
MutableList.of(MutableMap.of("forbiddenUnless", "myother")));
         assertPredJsonBidi(ConfigConstraints.requiredIf("myother"), 
MutableList.of(MutableMap.of("requiredIf", "myother")));
         assertPredJsonBidi(ConfigConstraints.requiredUnless("myother"), 
MutableList.of(MutableMap.of("requiredUnless", "myother")));
+        
assertPredJsonBidi(ConfigConstraints.requiredUnlessAnyOf(ImmutableList.of("myother1",
 "myother2")), MutableList.of(MutableMap.of("requiredUnlessAnyOf", 
ImmutableList.of("myother1", ("myother2")))));
+        
assertPredJsonBidi(ConfigConstraints.forbiddenUnlessAnyOf(ImmutableList.of("myother1",
 "myother2")), MutableList.of(MutableMap.of("forbiddenUnlessAnyOf", 
ImmutableList.of("myother1", ("myother2")))));
     }
     
     @Test

Reply via email to