You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by al...@apache.org on 2018/09/24 11:30:23 UTC

[1/7] brooklyn-server git commit: proper serialization and deserialization for constraints

Repository: brooklyn-server
Updated Branches:
  refs/heads/master e27cc7b6d -> a3d0ea06e


proper serialization and deserialization for constraints


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

Branch: refs/heads/master
Commit: bd34655c81400f8228c329ecec31ce6e378f78b0
Parents: e27cc7b
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Thu Sep 20 22:34:25 2018 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Thu Sep 20 22:34:25 2018 +0100

----------------------------------------------------------------------
 .../brooklyn/core/config/ConfigConstraints.java |  25 ++
 .../core/objs/ConstraintSerialization.java      | 354 +++++++++++++++++++
 .../core/objs/ConstraintSerializationTest.java  |  84 +++++
 .../brooklyn/rest/domain/ConfigSummary.java     |  17 +-
 .../brooklyn/util/text/StringPredicates.java    |  11 +-
 .../org/apache/brooklyn/util/text/Strings.java  |  22 +-
 .../org/apache/brooklyn/test/AssertsTest.java   |   2 +-
 7 files changed, 497 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/bd34655c/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 17b7c9d..35f672e 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
@@ -33,6 +33,7 @@ import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.objs.AbstractEntityAdjunct;
 import org.apache.brooklyn.core.objs.BrooklynObjectInternal;
 import org.apache.brooklyn.core.objs.BrooklynObjectPredicate;
+import org.apache.brooklyn.core.objs.ConstraintSerialization;
 import org.apache.brooklyn.util.core.task.Tasks;
 import org.apache.brooklyn.util.exceptions.ReferenceWithError;
 import org.apache.brooklyn.util.guava.Maybe;
@@ -185,6 +186,13 @@ public abstract class ConfigConstraints<T extends BrooklynObject> {
         return brooklynObject;
     }
 
+    /**
+     * Convenience method to get the serialization routines.
+     */
+    public static ConstraintSerialization serialization() {
+        return ConstraintSerialization.INSTANCE;
+    }
+    
     private static class EntityConfigConstraints extends ConfigConstraints<Entity> {
         public EntityConfigConstraints(Entity brooklynObject) {
             super(brooklynObject);
@@ -218,4 +226,21 @@ public abstract class ConfigConstraints<T extends BrooklynObject> {
         }
     }
 
+    public static <T> Predicate<T> required() {
+        return new RequiredPredicate<T>();
+    }
+    
+    /** Predicate indicating a field is required:  it must not be null and if a string it must not be empty */
+    public static class RequiredPredicate<T> implements Predicate<T> {
+        @Override
+        public boolean apply(T input) {
+            if (input==null) return false;
+            if (input instanceof CharSequence && ((CharSequence)input).length()==0) return false;
+            return true;
+        }
+        @Override
+        public String toString() {
+            return "required()";
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/bd34655c/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
new file mode 100644
index 0000000..a6b7039
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/objs/ConstraintSerialization.java
@@ -0,0 +1,354 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.core.objs;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigConstraints;
+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.exceptions.Exceptions;
+import org.apache.brooklyn.util.text.StringEscapes.JavaStringEscapes;
+import org.apache.brooklyn.util.text.StringPredicates;
+import org.apache.brooklyn.util.text.Strings;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+
+public class ConstraintSerialization {
+
+    private final Map<String, String> predicateToStringToPreferredName = MutableMap.of();
+    private final Map<String, Function<List<?>,Predicate<?>>> predicatePreferredNameToConstructor = MutableMap.of();
+
+    public static class PredicateSerializationRuleAdder<T> {
+        private String preferredName;
+        private Function<List<?>, T> constructorArgsFromList;
+        private Function<T, Predicate<?>> constructor;
+        private Predicate<?> predicateSample;
+        private T constructorSampleInput;
+        private Set<String> equivalentNames = MutableSet.of();
+        private Set<Predicate<?>> equivalentPredicateSamples = MutableSet.of();
+
+        ConstraintSerialization serialization;
+        
+        public PredicateSerializationRuleAdder(Function<T, Predicate<?>> constructor, Function<List<?>, T> constructorArgsFromList, T constructorSampleInput) {
+            this.constructorArgsFromList = constructorArgsFromList;
+            this.constructor = constructor;
+            this.constructorSampleInput = constructorSampleInput;
+        }
+        
+        public static PredicateSerializationRuleAdder<List<Predicate<?>>> predicateListConstructor(Function<List<Predicate<?>>,Predicate<?>> constructor) {
+            PredicateSerializationRuleAdder<List<Predicate<?>>> result = new PredicateSerializationRuleAdder<List<Predicate<?>>>(constructor,
+                null, MutableList.of());
+            result.constructorArgsFromList = o -> result.serialization.toPredicateListFromJsonList(o);
+            return result;
+        }
+        
+        public static PredicateSerializationRuleAdder<String> stringConstructor(Function<String,Predicate<?>> constructor) {
+            return new PredicateSerializationRuleAdder<String>(constructor, 
+                o -> Strings.toString(Iterables.getOnlyElement(o)), "");
+        }
+        
+        public static PredicateSerializationRuleAdder<Void> noArgConstructor(Supplier<Predicate<?>> constructor) {
+            return new PredicateSerializationRuleAdder<Void>(
+                (o) -> constructor.get(), o -> null, null);
+        }
+        
+        /** Preferred name for predicate when serializing. Defaults to the predicate name in the output of the {@link #sample(Predicate)}. */
+        public PredicateSerializationRuleAdder<T> preferredName(String preferredName) {
+            this.preferredName = preferredName;
+            return this;
+        }
+
+        /** Other predicates which are different to the type indicated by {@link #sample(Predicate)} but equivalent,
+         * and after serialization will be represented by {@link #preferredName} and after deserialization 
+         * will result in the {@link Predicate} produced by {@link #constructor}. */
+        public PredicateSerializationRuleAdder<T> equivalentNames(String ...equivs) {
+            for (String equiv: equivs) equivalentNames.add(equiv);
+            return this;
+        }
+
+        /** Sample of what the {@link #constructor} will produce, used to recognise this rule when parsing. 
+         * Can be omitted if {@link #sampleArg(Object)} supplied or its default is accepted. */
+        public PredicateSerializationRuleAdder<T> sample(Predicate<?> samplePreferredPredicate) {
+            predicateSample = samplePreferredPredicate;
+            return this;
+        }
+
+        /** This should supply args accepted by {@link #constructor} to generate a {@link #sample(Predicate)}. 
+         * At most one of this or {@link #sample(Predicate)} should be supplied.
+         * If the constructor accepts a default empty list/string/null then these can be omitted. */
+        public PredicateSerializationRuleAdder<T> sampleArg(T arg) {
+            constructorSampleInput = arg;
+            return this;
+        }
+
+        /** Other predicates which are different to the type indicated by {@link #sample(Predicate)} but equivalent,
+         * and after serialization will be represented by {@link #preferredName} and after deserialization 
+         * will result in the {@link Predicate} produced by {@link #constructor}. */
+        public PredicateSerializationRuleAdder<T> equivalentPredicates(Predicate<?> ...equivs) {
+            for (Predicate<?> equiv: equivs) equivalentPredicateSamples.add(equiv);
+            return this;
+        }
+
+        public void add(ConstraintSerialization constraintSerialization) {
+            this.serialization = constraintSerialization;
+            if (predicateSample==null) predicateSample = constructor.apply(constructorSampleInput);
+            String toStringName = Strings.removeAfter(Preconditions.checkNotNull(predicateSample, "sample or sampleArg must be supplied").toString(), "(", false);
+            if (preferredName==null) {
+                preferredName = toStringName;
+            } else {
+                constraintSerialization.predicateToStringToPreferredName.put(preferredName, preferredName);
+            }
+            constraintSerialization.predicateToStringToPreferredName.put(toStringName, preferredName);
+            
+            for (String equiv: equivalentNames) {
+                constraintSerialization.predicateToStringToPreferredName.put(equiv, preferredName);
+            }
+            
+            constraintSerialization.predicatePreferredNameToConstructor.put(preferredName, constructor.compose(constructorArgsFromList));
+            
+            for (Predicate<?> equiv: equivalentPredicateSamples) {
+                String equivToStringName = Strings.removeAfter(equiv.toString(), "(", false);                
+                constraintSerialization.predicateToStringToPreferredName.put(equivToStringName, preferredName);
+            }
+        }
+    }
+    
+    private static String GROUP(String in) { return "("+in+")"; }
+    private static String NOT_CHARSET(String ...in) { return "[^"+Strings.join(in, "")+"]"; }
+    private static String OR_GROUP(String ...in) { return GROUP(Strings.join(in, "|")); }
+    private static String ZERO_OR_MORE(String in) { return in + "*"; }
+    
+    private static String DOUBLE_QUOTED_STRING = "\""+GROUP(ZERO_OR_MORE(OR_GROUP(NOT_CHARSET("\\", "\""), "\\.")))+"\"";
+    private static String SINGLE_QUOTED_STRING = "\'"+GROUP(ZERO_OR_MORE(OR_GROUP(NOT_CHARSET("\\", "\'"), "\\.")))+"\'";
+    
+    private static String PREDICATE = "[A-Za-z0-9_\\-\\.]+";
+    
+    private static Pattern PATTERN_START_WITH_QUOTED_STRING = Pattern.compile("^"+OR_GROUP(DOUBLE_QUOTED_STRING, SINGLE_QUOTED_STRING));
+    private static Pattern PATTERN_START_WITH_PREDICATE = Pattern.compile("^"+GROUP(PREDICATE));
+
+    {
+        init();
+    }
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    private void init() {
+        PredicateSerializationRuleAdder.predicateListConstructor((o) -> ConfigConstraints.required()).
+            equivalentPredicates(Predicates.notNull(), StringPredicates.isNonBlank()).add(this);
+
+        PredicateSerializationRuleAdder.predicateListConstructor((o) -> Predicates.or((Iterable)o)).preferredName("any").equivalentNames("or").add(this);
+        PredicateSerializationRuleAdder.predicateListConstructor((o) -> /* and predicate is default when given list */ toPredicateFromJson(o)).preferredName("all").sample(Predicates.and(Collections.emptyList())).equivalentNames("and").add(this);
+        PredicateSerializationRuleAdder.noArgConstructor(() -> Predicates.alwaysFalse()).add(this);
+        PredicateSerializationRuleAdder.noArgConstructor(() -> Predicates.alwaysTrue()).add(this);
+        
+        PredicateSerializationRuleAdder.stringConstructor(StringPredicates::matchesRegex).preferredName("regex").add(this);
+        PredicateSerializationRuleAdder.stringConstructor(StringPredicates::matchesGlob).preferredName("glob").add(this);
+    }
+    
+    public static ConstraintSerialization INSTANCE = new ConstraintSerialization();
+    
+    private ConstraintSerialization() {}
+
+    public List<Object> toJsonList(ConfigKey<?> config) {
+        return toJsonList(config.getConstraint());
+    }
+    
+    public List<Object> toJsonList(Predicate<?> constraint) {
+        // map twice to clean it (flatten "and" lists, etc)
+        // but if not possible go with progressively simpler items
+        try {
+            return toExactJsonList(toPredicateFromJson(toExactJsonList(constraint)));
+        } catch (Exception e) {
+            Exceptions.propagateIfFatal(e);
+            try {
+                return toExactJsonList(constraint);
+            } catch (Exception e2) {
+                Exceptions.propagateIfFatal(e);
+                return Collections.singletonList(constraint.toString());
+            }
+        }
+    }
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public List<Object> toExactJsonList(Predicate<?> constraint) {
+        StringConstraintParser parser = StringConstraintParser.forConstraint(this, Strings.toString(constraint));
+        if (!parser.parse()) throw new IllegalStateException("cannot match: "+constraint);
+        if (parser.result instanceof Map && ((Map)parser.result).size()==1 && ((Map)parser.result).containsKey("all")) {
+            return (List<Object>) ((Map)parser.result).get("all");
+        }
+        return ImmutableList.of(parser.result);
+    }
+    
+    private static class StringConstraintParser {
+        ConstraintSerialization serialization;
+        String remaining;
+        Object result;
+        List<Object> resultList = MutableList.of();
+        boolean list = false;
+        
+        static StringConstraintParser forConstraint(ConstraintSerialization serialization, String in) {
+            StringConstraintParser result = new StringConstraintParser();
+            result.serialization = serialization;
+            result.remaining = in;
+            return result;
+        }
+
+        static StringConstraintParser forArgsInternal(ConstraintSerialization serialization, String in) {
+            StringConstraintParser result = forConstraint(serialization, in);
+            result.list = true;
+            return result;
+        }
+
+        boolean parse() {
+            remaining = remaining.trim();
+            Matcher m = PATTERN_START_WITH_PREDICATE.matcher(remaining);
+            if (!m.find()) {
+                if (!list) return false;
+                // when looking at args,
+                // allow empty list
+                if (remaining.startsWith(")")) {
+                    result = resultList;
+                    return true;
+                }
+                // and allow strings
+                m = PATTERN_START_WITH_QUOTED_STRING.matcher(remaining);
+                if (!m.find()) {
+                    return false;
+                }
+                result = JavaStringEscapes.unwrapJavaString(m.group());
+                remaining = remaining.substring(m.end());
+            } else {
+                String p1 = m.group(1);
+                String p2 = serialization.predicateToStringToPreferredName.get(p1);
+                if (p2==null) p2 = p1;
+                remaining = remaining.substring(m.end()).trim();
+                
+                if (!remaining.startsWith("(")) {
+                    result = p2;
+                } else {
+                    remaining = remaining.substring(1).trim();
+                    StringConstraintParser args = forArgsInternal(serialization, remaining);
+                    if (!args.parse()) return false;
+                    if (args.resultList.isEmpty()) {
+                        result = p2;
+                    } else if (args.resultList.size()==1) {
+                        result = MutableMap.of(p2, Iterables.getOnlyElement(args.resultList));
+                    } else { 
+                        result = MutableMap.of(p2, args.result);
+                    }
+                    remaining = args.remaining;
+                    if (!remaining.startsWith(")")) return false;
+                    remaining = remaining.substring(1).trim();
+                }
+                if (!list) return remaining.isEmpty();
+            }
+            resultList.add(result);
+            if (remaining.isEmpty() || remaining.startsWith(")")) {
+                result = resultList;
+                return true;
+            }
+            if (!remaining.startsWith(",")) return false;
+            remaining = remaining.substring(1);
+            return parse();
+        }
+    }
+
+    private void collectPredicateListFromJson(Object o, List<Predicate<?>> result) {
+        if (o instanceof Collection) {
+            ((Collection<?>)o).stream().forEach(i -> collectPredicateListFromJson(i, result));
+            return;
+        }
+        Predicate<?> p = toPredicateFromJson(o);
+        if (Predicates.alwaysTrue().equals(p)) {
+            // no point in keeping this one
+            return;
+        }
+        result.add(p);
+    }
+    public Predicate<?> toPredicateFromJson(Object o) {
+        if (o instanceof Collection) {
+            @SuppressWarnings({ "rawtypes", "unchecked" })
+            Predicate<?> result2 = and((List)toPredicateListFromJsonList((Collection<?>)o));
+            return result2;
+        }
+        
+        String key;
+        List<Object> args;
+        if (o instanceof String) {
+            key = (String)o;
+            args = MutableList.of();
+        } else if (o instanceof Map) {
+            if (((Map<?,?>)o).size()!=1) {
+                throw new IllegalArgumentException("Unsupported constraint; map input should have a single key: "+o);
+            }
+            // we only support single-key maps with string as key and value as list (of args) or other type as single arg, as in predicateName(args)
+            key = (String) Iterables.getOnlyElement( ((Map<?,?>)o).keySet() );
+            Object v = Iterables.getOnlyElement( ((Map<?,?>)o).values() );
+            if (v instanceof Iterable) {
+                args = MutableList.copyOf((Iterable<?>)v);
+            } else {
+                args = Collections.singletonList(v);
+            }
+        } else if (o instanceof Predicate) {
+            return (Predicate<?>)o;
+        } else {
+            throw new IllegalArgumentException("Unsupported constraint; constraint should be string, list, or single-key map: "+o);
+        }
+        Function<List<?>, Predicate<?>> constructor = predicatePreferredNameToConstructor.get(key);
+        if (constructor==null) {
+            String preferredName = predicateToStringToPreferredName.get(key);
+            if (preferredName!=null) {
+                constructor = predicatePreferredNameToConstructor.get(preferredName);
+                if (constructor==null) {
+                    throw new IllegalArgumentException("Incomplete constraint: "+key+", maps to "+preferredName+", but no constructor known");
+                }
+            } else {
+                throw new IllegalArgumentException("Unsupported constraint: "+key);
+            }
+        }
+        return constructor.apply(args);
+    }
+    
+    private <T> Predicate<?> and(Iterable<Predicate<? super T>> preds) {
+        Iterator<Predicate<? super T>> pi = preds.iterator();
+        if (!pi.hasNext()) return Predicates.alwaysTrue();
+        Predicate<?> first = pi.next();
+        if (!pi.hasNext()) return first;
+        return Predicates.and(preds);
+    }
+    public List<Predicate<?>> toPredicateListFromJsonList(Collection<?> o) {
+        List<Predicate<?>> result = MutableList.of();
+        collectPredicateListFromJson(o, result);
+        return result;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/bd34655c/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
new file mode 100644
index 0000000..2065044
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/objs/ConstraintSerializationTest.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.core.objs;
+
+import java.util.List;
+
+import org.apache.brooklyn.core.config.ConfigConstraints;
+import org.apache.brooklyn.core.test.BrooklynMgmtUnitTestSupport;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.text.StringPredicates;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+
+public class ConstraintSerializationTest extends BrooklynMgmtUnitTestSupport {
+
+    @Test
+    public void testSimple() {
+        assertPredJsonBidi(ConfigConstraints.required(), MutableList.of("required"));
+    }
+
+    @Test
+    public void testInteresting() {
+        assertPredJsonBidi(Predicates.and(ConfigConstraints.required(), StringPredicates.matchesRegex(".*")),
+            MutableList.of("required", MutableMap.of("regex", ".*")));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testNestedAnd() {
+        Predicate<String> p = Predicates.<String>and(
+            ConfigConstraints.required(), 
+            Predicates.and(Predicates.alwaysTrue()),
+            Predicates.<String>and(StringPredicates.matchesRegex(".*")));
+        Assert.assertEquals(ConstraintSerialization.INSTANCE.toJsonList(p), 
+            MutableList.of("required", MutableMap.of("regex", ".*")));
+    }
+
+    @Test
+    public void testAltName() {
+        Predicate<String> p = StringPredicates.matchesGlob("???*");
+        Assert.assertEquals(ConstraintSerialization.INSTANCE.toPredicateFromJson(
+            MutableList.of(MutableMap.of("matchesGlob", "???*"))).toString(), p.toString());
+        Assert.assertEquals(ConstraintSerialization.INSTANCE.toPredicateFromJson(
+            MutableList.of(MutableMap.of("glob", "???*"))).toString(), p.toString());
+        Assert.assertEquals(ConstraintSerialization.INSTANCE.toJsonList(p),
+            MutableList.of(MutableMap.of("glob", "???*")));
+    }
+
+    @Test
+    public void testAltPred() {
+        Predicate<?> p = Predicates.notNull();
+        Assert.assertEquals(ConstraintSerialization.INSTANCE.toJsonList(p),
+            MutableList.of("required"));
+        Assert.assertEquals(ConstraintSerialization.INSTANCE.toPredicateFromJson("required").toString(),
+            ConfigConstraints.required().toString());
+    }
+
+    private void assertPredJsonBidi(Predicate<?> pred, List<?> json) {
+        Assert.assertEquals(ConstraintSerialization.INSTANCE.toJsonList(pred), json);
+        // some predicates don't support equals, but all (the ones we use) must support toString
+        Assert.assertEquals(ConstraintSerialization.INSTANCE.toPredicateFromJson(json).toString(), pred.toString());
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/bd34655c/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ConfigSummary.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ConfigSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ConfigSummary.java
index 49aa2fe..c6f1ec6 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ConfigSummary.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ConfigSummary.java
@@ -28,17 +28,14 @@ import java.util.Objects;
 import javax.annotation.Nullable;
 
 import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.objs.ConstraintSerialization;
 import org.apache.brooklyn.util.collections.Jsonya;
-import org.apache.brooklyn.util.core.flags.TypeCoercions;
-import org.apache.brooklyn.util.javalang.coerce.TypeCoercer;
-import org.apache.brooklyn.util.text.StringPredicates;
 
 import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonInclude.Include;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.google.common.base.Function;
-import com.google.common.base.Predicates;
 import com.google.common.collect.FluentIterable;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
@@ -64,7 +61,7 @@ public class ConfigSummary implements HasName, Serializable {
     @JsonInclude(Include.NON_NULL)
     private final Boolean pinned;
     @JsonInclude(Include.NON_NULL)
-    private final List<String> constraints;
+    private final List<Object> constraints;
 
     @JsonInclude(Include.NON_NULL)
     private final Map<String, URI> links;
@@ -84,7 +81,7 @@ public class ConfigSummary implements HasName, Serializable {
             @JsonProperty("priority") Double priority,
             @JsonProperty("possibleValues") List<Map<String, String>> possibleValues,
             @JsonProperty("pinned") Boolean pinned,
-            @JsonProperty("constraints") List<String> constraints,
+            @JsonProperty("constraints") List<?> constraints,
             @JsonProperty("links") Map<String, URI> links) {
         this.name = name;
         this.type = type;
@@ -95,7 +92,7 @@ public class ConfigSummary implements HasName, Serializable {
         this.priority = priority;
         this.possibleValues = possibleValues;
         this.pinned = pinned;
-        this.constraints = (constraints == null) ? ImmutableList.<String>of() : ImmutableList.copyOf(constraints);
+        this.constraints = (constraints == null) ? ImmutableList.<Object>of() : ImmutableList.copyOf(constraints);
         this.links = (links == null) ? ImmutableMap.<String, URI>of() : ImmutableMap.copyOf(links);
     }
 
@@ -111,9 +108,7 @@ public class ConfigSummary implements HasName, Serializable {
         this.label = label;
         this.priority = priority;
         this.pinned = pinned;
-        this.constraints = !config.getConstraint().equals(Predicates.alwaysTrue())
-                ? ImmutableList.of((config.getConstraint().getClass().equals(StringPredicates.isNonBlank().getClass()) ? "required" : config.getConstraint().toString()))
-                : ImmutableList.<String>of();
+        this.constraints = ConstraintSerialization.INSTANCE.toJsonList(config);
         if (config.getType().isEnum()) {
             this.type = Enum.class.getName();
             this.defaultValue = config.getDefaultValue() instanceof Enum? ((Enum<?>) config.getDefaultValue()).name() : 
@@ -175,7 +170,7 @@ public class ConfigSummary implements HasName, Serializable {
         return pinned;
     }
 
-    public List<String> getConstraints() {
+    public List<Object> getConstraints() {
         return constraints;
     }
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/bd34655c/utils/common/src/main/java/org/apache/brooklyn/util/text/StringPredicates.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/text/StringPredicates.java b/utils/common/src/main/java/org/apache/brooklyn/util/text/StringPredicates.java
index 2006e65..b57b1db 100644
--- a/utils/common/src/main/java/org/apache/brooklyn/util/text/StringPredicates.java
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/text/StringPredicates.java
@@ -26,6 +26,7 @@ import java.util.Set;
 import javax.annotation.Nullable;
 
 import org.apache.brooklyn.util.collections.MutableSet;
+import org.apache.brooklyn.util.text.StringEscapes.JavaStringEscapes;
 
 import com.google.common.base.Function;
 import com.google.common.base.Predicate;
@@ -109,7 +110,7 @@ public class StringPredicates {
 
         @Override
         public String toString() {
-            return "containsLiteralCaseInsensitive("+fragment+")";
+            return "containsLiteralCaseInsensitive("+JavaStringEscapes.wrapJavaString(fragment)+")";
         }
     }
 
@@ -131,7 +132,7 @@ public class StringPredicates {
 
         @Override
         public String toString() {
-            return "containsLiteral("+fragment+")";
+            return "containsLiteral("+JavaStringEscapes.wrapJavaString(fragment)+")";
         }
     }
 
@@ -210,7 +211,7 @@ public class StringPredicates {
         }
         @Override
         public String toString() {
-            return "startsWith("+prefix+")";
+            return "startsWith("+JavaStringEscapes.wrapJavaString(prefix)+")";
         }
     }
 
@@ -284,7 +285,7 @@ public class StringPredicates {
         }
         @Override
         public String toString() {
-            return "matchesRegex("+regex+")";
+            return "matchesRegex("+JavaStringEscapes.wrapJavaString(regex)+")";
         }
     }
     
@@ -303,7 +304,7 @@ public class StringPredicates {
         }
         @Override
         public String toString() {
-            return "matchesGlob("+glob+")";
+            return "matchesGlob("+JavaStringEscapes.wrapJavaString(glob)+")";
         }
     }
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/bd34655c/utils/common/src/main/java/org/apache/brooklyn/util/text/Strings.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/text/Strings.java b/utils/common/src/main/java/org/apache/brooklyn/util/text/Strings.java
index d7ffd4b..1eb1435 100644
--- a/utils/common/src/main/java/org/apache/brooklyn/util/text/Strings.java
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/text/Strings.java
@@ -193,7 +193,27 @@ public class Strings {
         }
         return string.substring(index);
     }
-
+    
+    /**
+     * Removes everything after the marker, optionally also removing the marker.
+     * If marker not found the string is unchanged.
+     */
+    public static String removeAfter(String string, String marker, boolean includeMarker) {
+        int i = string.indexOf(marker);
+        if (i==-1) return string;
+        return string.substring(0, i + (includeMarker ? marker.length() : 0));
+    }
+    
+    /**
+     * Removes everything before the marker, optionally also removing the marker.
+     * If marker not found the string is unchanged.
+     */
+    public static String removeBefore(String string, String marker, boolean includeMarker) {
+        int i = string.indexOf(marker);
+        if (i==-1) return string;
+        return string.substring(i + (includeMarker ? 0 : marker.length()));
+    }
+    
     /** convenience for {@link com.google.common.base.Joiner} */
     public static String join(Iterable<? extends Object> list, String separator) {
         if (list==null) return null;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/bd34655c/utils/common/src/test/java/org/apache/brooklyn/test/AssertsTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/test/AssertsTest.java b/utils/common/src/test/java/org/apache/brooklyn/test/AssertsTest.java
index 1105acd..96e31fd 100644
--- a/utils/common/src/test/java/org/apache/brooklyn/test/AssertsTest.java
+++ b/utils/common/src/test/java/org/apache/brooklyn/test/AssertsTest.java
@@ -128,7 +128,7 @@ public class AssertsTest {
         try {
             Asserts.assertStringMatchesRegex("hello", "hello", "he");
             Asserts.shouldHaveFailedPreviously();
-        } catch (AssertionError e) { Asserts.expectedFailureContains(e, "hello", "matchesRegex(he)"); }
+        } catch (AssertionError e) { Asserts.expectedFailureContains(e, "hello", "matchesRegex(\"he\")"); }
     }
 
     @Test


[3/7] brooklyn-server git commit: accept toStrings in/as json

Posted by al...@apache.org.
accept toStrings in/as json


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

Branch: refs/heads/master
Commit: 5fec2756f61b6bba1f37d96a04c07ef9229ec4de
Parents: 0d6f572
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Sep 21 12:32:55 2018 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Sep 21 12:32:55 2018 +0100

----------------------------------------------------------------------
 .../brooklyn/core/objs/ConstraintSerialization.java     |  6 ++++++
 .../brooklyn/core/objs/ConstraintSerializationTest.java | 12 ++++++++++++
 2 files changed, 18 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/5fec2756/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 57258bc..6844a72 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
@@ -314,6 +314,12 @@ public class ConstraintSerialization {
         List<Object> args;
         if (o instanceof String) {
             key = (String)o;
+            if (key.indexOf("(")>=0) {
+                // it wasn't json; delegate to the parser again
+                StringConstraintParser parser = StringConstraintParser.forConstraint(this, key);
+                if (!parser.parse()) throw new IllegalStateException("cannot match: "+key);
+                return toPredicateFromJson(parser.result);
+            }
             args = MutableList.of();
         } else if (o instanceof Map) {
             if (((Map<?,?>)o).size()!=1) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/5fec2756/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 2065044..539fc87 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
@@ -67,6 +67,18 @@ public class ConstraintSerializationTest extends BrooklynMgmtUnitTestSupport {
     }
 
     @Test
+    public void testAcceptsMap() {
+        Predicate<String> p = StringPredicates.matchesGlob("???*");
+        Assert.assertEquals(ConstraintSerialization.INSTANCE.toPredicateFromJson(MutableMap.of("matchesGlob", "???*")).toString(), p.toString());
+    }
+
+    @Test
+    public void testAcceptsString() {
+        Predicate<String> p = StringPredicates.matchesGlob("???*");
+        Assert.assertEquals(ConstraintSerialization.INSTANCE.toPredicateFromJson("matchesGlob(\"???*\")").toString(), p.toString());
+    }
+    
+    @Test
     public void testAltPred() {
         Predicate<?> p = Predicates.notNull();
         Assert.assertEquals(ConstraintSerialization.INSTANCE.toJsonList(p),


[2/7] brooklyn-server git commit: add {forbidden, required}{If, Unless} constraints

Posted by al...@apache.org.
add {forbidden,required}{If,Unless} constraints


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

Branch: refs/heads/master
Commit: 0d6f57219bd7ce36c912fddd26f37a46c6f8dbc2
Parents: bd34655
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Sep 21 11:49:47 2018 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Sep 21 11:49:47 2018 +0100

----------------------------------------------------------------------
 .../brooklyn/core/config/ConfigConstraints.java |  69 ++++++++++
 .../core/objs/ConstraintSerialization.java      |  13 +-
 .../brooklyn/util/core/ResourcePredicates.java  |   6 +-
 .../core/config/ConfigKeyConstraintTest.java    | 133 ++++++++++++++-----
 .../java/org/apache/brooklyn/test/Asserts.java  |  16 ++-
 5 files changed, 195 insertions(+), 42 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0d6f5721/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 35f672e..4ee584d 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
@@ -30,6 +30,7 @@ import org.apache.brooklyn.api.objs.BrooklynObject;
 import org.apache.brooklyn.api.objs.EntityAdjunct;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
 import org.apache.brooklyn.core.objs.AbstractEntityAdjunct;
 import org.apache.brooklyn.core.objs.BrooklynObjectInternal;
 import org.apache.brooklyn.core.objs.BrooklynObjectPredicate;
@@ -37,6 +38,7 @@ import org.apache.brooklyn.core.objs.ConstraintSerialization;
 import org.apache.brooklyn.util.core.task.Tasks;
 import org.apache.brooklyn.util.exceptions.ReferenceWithError;
 import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.text.StringEscapes.JavaStringEscapes;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -243,4 +245,71 @@ public abstract class ConfigConstraints<T extends BrooklynObject> {
             return "required()";
         }
     }
+    
+    private static abstract class OtherKeyPredicate implements BrooklynObjectPredicate<Object> {
+        private String otherKeyName;
+
+        public OtherKeyPredicate(String otherKeyName) {
+            this.otherKeyName = otherKeyName;
+        }
+
+        public abstract String predicateName();
+        
+        @Override
+        public String toString() {
+            return predicateName()+"("+JavaStringEscapes.wrapJavaString(otherKeyName)+")";
+        }
+        
+        @Override
+        public boolean apply(Object input) {
+            return apply(input, BrooklynTaskTags.getContextEntity(Tasks.current()));
+        }
+
+        @Override
+        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)));
+        }
+        
+        public abstract boolean test(Object thisValue, Object otherValue);
+        
+    }
+    
+    public static Predicate<Object> forbiddenIf(String otherKeyName) { return new ForbiddenIfPredicate(otherKeyName); }
+    public static class ForbiddenIfPredicate extends OtherKeyPredicate {
+        public ForbiddenIfPredicate(String otherKeyName) { super(otherKeyName); }
+        @Override public String predicateName() { return "forbiddenIf"; }
+        @Override public boolean test(Object thisValue, Object otherValue) { 
+            return (thisValue==null) || (otherValue==null);
+        } 
+    }
+    
+    public static Predicate<Object> forbiddenUnless(String otherKeyName) { return new ForbiddenUnlessPredicate(otherKeyName); }
+    public static class ForbiddenUnlessPredicate extends OtherKeyPredicate {
+        public ForbiddenUnlessPredicate(String otherKeyName) { super(otherKeyName); }
+        @Override public String predicateName() { return "forbiddenUnless"; }
+        @Override public boolean test(Object thisValue, Object otherValue) { 
+            return (thisValue==null) || (otherValue!=null);
+        } 
+    }
+    
+    public static Predicate<Object> requiredIf(String otherKeyName) { return new RequiredIfPredicate(otherKeyName); }
+    public static class RequiredIfPredicate extends OtherKeyPredicate {
+        public RequiredIfPredicate(String otherKeyName) { super(otherKeyName); }
+        @Override public String predicateName() { return "requiredIf"; }
+        @Override public boolean test(Object thisValue, Object otherValue) { 
+            return (thisValue!=null) || (otherValue==null);
+        } 
+    }
+    
+    public static Predicate<Object> requiredUnless(String otherKeyName) { return new RequiredUnlessPredicate(otherKeyName); }
+    public static class RequiredUnlessPredicate extends OtherKeyPredicate {
+        public RequiredUnlessPredicate(String otherKeyName) { super(otherKeyName); }
+        @Override public String predicateName() { return "requiredUnless"; }
+        @Override public boolean test(Object thisValue, Object otherValue) { 
+            return (thisValue!=null) || (otherValue!=null);
+        } 
+    }
+    
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0d6f5721/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 a6b7039..57258bc 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
@@ -34,6 +34,7 @@ import org.apache.brooklyn.core.config.ConfigConstraints;
 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.exceptions.Exceptions;
 import org.apache.brooklyn.util.text.StringEscapes.JavaStringEscapes;
 import org.apache.brooklyn.util.text.StringPredicates;
@@ -168,11 +169,19 @@ public class ConstraintSerialization {
 
         PredicateSerializationRuleAdder.predicateListConstructor((o) -> Predicates.or((Iterable)o)).preferredName("any").equivalentNames("or").add(this);
         PredicateSerializationRuleAdder.predicateListConstructor((o) -> /* and predicate is default when given list */ toPredicateFromJson(o)).preferredName("all").sample(Predicates.and(Collections.emptyList())).equivalentNames("and").add(this);
-        PredicateSerializationRuleAdder.noArgConstructor(() -> Predicates.alwaysFalse()).add(this);
-        PredicateSerializationRuleAdder.noArgConstructor(() -> Predicates.alwaysTrue()).add(this);
+        PredicateSerializationRuleAdder.noArgConstructor(Predicates::alwaysFalse).add(this);
+        PredicateSerializationRuleAdder.noArgConstructor(Predicates::alwaysTrue).add(this);
+        
+        PredicateSerializationRuleAdder.noArgConstructor(ResourcePredicates::urlExists).preferredName("urlExists").add(this);
+        PredicateSerializationRuleAdder.noArgConstructor(StringPredicates::isBlank).add(this);
         
         PredicateSerializationRuleAdder.stringConstructor(StringPredicates::matchesRegex).preferredName("regex").add(this);
         PredicateSerializationRuleAdder.stringConstructor(StringPredicates::matchesGlob).preferredName("glob").add(this);
+        
+        PredicateSerializationRuleAdder.stringConstructor(ConfigConstraints::forbiddenIf).add(this);
+        PredicateSerializationRuleAdder.stringConstructor(ConfigConstraints::forbiddenUnless).add(this);
+        PredicateSerializationRuleAdder.stringConstructor(ConfigConstraints::requiredIf).add(this);
+        PredicateSerializationRuleAdder.stringConstructor(ConfigConstraints::requiredUnless).add(this);
     }
     
     public static ConstraintSerialization INSTANCE = new ConstraintSerialization();

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0d6f5721/core/src/main/java/org/apache/brooklyn/util/core/ResourcePredicates.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/ResourcePredicates.java b/core/src/main/java/org/apache/brooklyn/util/core/ResourcePredicates.java
index 439aaae..240ab52 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/ResourcePredicates.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/ResourcePredicates.java
@@ -22,7 +22,9 @@ package org.apache.brooklyn.util.core;
 import javax.annotation.Nullable;
 
 import org.apache.brooklyn.api.objs.BrooklynObject;
+import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
 import org.apache.brooklyn.core.objs.BrooklynObjectPredicate;
+import org.apache.brooklyn.util.core.task.Tasks;
 import org.apache.brooklyn.util.text.StringPredicates;
 import org.apache.brooklyn.util.text.Strings;
 
@@ -54,7 +56,7 @@ public class ResourcePredicates {
 
         @Override
         public boolean apply(@Nullable String resource) {
-            return apply(resource, null);
+            return apply(resource, BrooklynTaskTags.getContextEntity(Tasks.current()));
         }
 
         @Override
@@ -64,7 +66,7 @@ public class ResourcePredicates {
 
         @Override
         public String toString() {
-            return "ResourcePredicates.exists()";
+            return "ResourcePredicates.urlExists()";
         }
 
     }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0d6f5721/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 46710fb..a251cbc 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
@@ -20,11 +20,10 @@
 package org.apache.brooklyn.core.config;
 
 import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertNotNull;
-import static org.testng.Assert.fail;
 
 import java.util.concurrent.Callable;
 
+import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.location.Location;
@@ -45,7 +44,6 @@ import org.apache.brooklyn.core.test.entity.TestEntityImpl;
 import org.apache.brooklyn.core.test.policy.TestPolicy;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.javalang.JavaClassNames;
 import org.apache.brooklyn.util.net.Networking;
 import org.apache.brooklyn.util.time.Duration;
@@ -154,10 +152,9 @@ public class ConfigKeyConstraintTest extends BrooklynAppUnitTestSupport {
     public void testExceptionWhenEntityHasNullConfig() {
         try {
             app.createAndManageChild(EntitySpec.create(EntityWithNonNullConstraint.class));
-            fail("Expected exception when managing entity with missing config");
+            Asserts.shouldHaveFailedPreviously("Expected exception when managing entity with missing config");
         } catch (Exception e) {
-            Throwable t = Exceptions.getFirstThrowableOfType(e, ConstraintViolationException.class);
-            assertNotNull(t);
+            Asserts.expectedFailureOfType(e, ConstraintViolationException.class);
         }
     }
 
@@ -176,10 +173,9 @@ public class ConfigKeyConstraintTest extends BrooklynAppUnitTestSupport {
     public void testExceptionWhenSubclassSetsInvalidDefaultValue() {
         try {
             app.createAndManageChild(EntitySpec.create(EntityProvidingDefaultValueForConfigKeyInRange.class));
-            fail("Expected exception when managing entity setting invalid default value");
+            Asserts.shouldHaveFailedPreviously("Expected exception when managing entity setting invalid default value");
         } catch (Exception e) {
-            Throwable t = Exceptions.getFirstThrowableOfType(e, ConstraintViolationException.class);
-            assertNotNull(t, "Original exception was: " + Exceptions.collapseText(e));
+            Asserts.expectedFailureOfType(e, ConstraintViolationException.class);
         }
     }
 
@@ -188,10 +184,9 @@ public class ConfigKeyConstraintTest extends BrooklynAppUnitTestSupport {
         try {
             app.createAndManageChild(EntitySpec.create(EntityWithNonNullConstraintWithNonNullDefault.class)
                     .configure(EntityWithNonNullConstraintWithNonNullDefault.NON_NULL_WITH_DEFAULT, (Object) null));
-            fail("Expected exception when config key set to null");
+            Asserts.shouldHaveFailedPreviously("Expected exception when config key set to null");
         } catch (Exception e) {
-            Throwable t = Exceptions.getFirstThrowableOfType(e, ConstraintViolationException.class);
-            assertNotNull(t, "Original exception was: " + Exceptions.collapseText(e));
+            Asserts.expectedFailureOfType(e, ConstraintViolationException.class);
         }
     }
 
@@ -200,10 +195,9 @@ public class ConfigKeyConstraintTest extends BrooklynAppUnitTestSupport {
         try {
             app.createAndManageChild(EntitySpec.create(EntityRequiringConfigKeyInRange.class)
                     .configure(ImmutableMap.of("test.conf.range", -1)));
-            fail("Expected exception when managing entity with invalid config");
+            Asserts.shouldHaveFailedPreviously("Expected exception when managing entity with invalid config");
         } catch (Exception e) {
-            Throwable t = Exceptions.getFirstThrowableOfType(e, ConstraintViolationException.class);
-            assertNotNull(t, "Original exception was: " + Exceptions.collapseText(e));
+            Asserts.expectedFailureOfType(e, ConstraintViolationException.class);
         }
     }
 
@@ -214,10 +208,9 @@ public class ConfigKeyConstraintTest extends BrooklynAppUnitTestSupport {
         try {
             testEntity.addChild(EntitySpec.create(EntityRequiringConfigKeyInRange.class)
                 .configure(EntityRequiringConfigKeyInRange.RANGE, -1));
-            fail("Expected exception when managing child with invalid config");
+            Asserts.shouldHaveFailedPreviously("Expected exception when managing child with invalid config");
         } catch (Exception e) {
-            Throwable t = Exceptions.getFirstThrowableOfType(e, ConstraintViolationException.class);
-            assertNotNull(t, "Original exception was: " + Exceptions.collapseText(e));
+            Asserts.expectedFailureOfType(e, ConstraintViolationException.class);
         }
     }
 
@@ -228,10 +221,9 @@ public class ConfigKeyConstraintTest extends BrooklynAppUnitTestSupport {
                 .configure(EntityWithNonNullConstraint.NON_NULL_CONFIG, (Object) null));
         try {
             ConfigConstraints.assertValid(p);
-            fail("Expected exception when validating policy with missing config");
+            Asserts.shouldHaveFailedPreviously("Expected exception when validating policy with missing config");
         } catch (Exception e) {
-            Throwable t = Exceptions.getFirstThrowableOfType(e, ConstraintViolationException.class);
-            assertNotNull(t, "Original exception was: " + Exceptions.collapseText(e));
+            Asserts.expectedFailureOfType(e, ConstraintViolationException.class);
         }
     }
 
@@ -240,10 +232,9 @@ public class ConfigKeyConstraintTest extends BrooklynAppUnitTestSupport {
         try {
             mgmt.getEntityManager().createPolicy(PolicySpec.create(PolicyWithConfigConstraint.class)
                     .configure(PolicyWithConfigConstraint.NON_NULL_CONFIG, (Object) null));
-            fail("Expected exception when creating policy with missing config");
+            Asserts.shouldHaveFailedPreviously("Expected exception when creating policy with missing config");
         } catch (Exception e) {
-            Throwable t = Exceptions.getFirstThrowableOfType(e, ConstraintViolationException.class);
-            assertNotNull(t, "Original exception was: " + Exceptions.collapseText(e));
+            Asserts.expectedFailureOfType(e, ConstraintViolationException.class);
         }
     }
 
@@ -252,10 +243,9 @@ public class ConfigKeyConstraintTest extends BrooklynAppUnitTestSupport {
         try {
             mgmt.getEntityManager().createEnricher(EnricherSpec.create(EnricherWithConfigConstraint.class)
                     .configure(EnricherWithConfigConstraint.PATTERN, "123.123.256.10"));
-            fail("Expected exception when creating enricher with invalid config");
+            Asserts.shouldHaveFailedPreviously("Expected exception when config key set to null");
         } catch (Exception e) {
-            Throwable t = Exceptions.getFirstThrowableOfType(e, ConstraintViolationException.class);
-            assertNotNull(t, "Original exception was: " + Exceptions.collapseText(e));
+            Asserts.expectedFailureOfType(e, ConstraintViolationException.class);
         }
     }
 
@@ -289,7 +279,7 @@ public class ConfigKeyConstraintTest extends BrooklynAppUnitTestSupport {
             app.createAndManageChild(EntitySpec.create(EntityWithContextAwareConstraint.class)
                     .displayName("Mr. Big")
                     .configure("must-be-display-name", "Mr. Bag"));
-            fail("Expected exception when managing entity with incorrect config");
+            Asserts.shouldHaveFailedPreviously("Expected exception when managing entity with incorrect config");
         } catch (Exception e) {
             Asserts.expectedFailureOfType(e, ConstraintViolationException.class);
         }
@@ -306,7 +296,7 @@ public class ConfigKeyConstraintTest extends BrooklynAppUnitTestSupport {
             // NB the call above does not currently/necessarily apply validation
             log.debug(JavaClassNames.niceClassAndMethod()+" got "+value+" for "+EntityRequiringConfigKeyInRange.RANGE+", now explicitly validating");
             ConfigConstraints.assertValid(child);
-            fail("Expected exception when managing entity with incorrect config; instead passed assertion and got: "+value);
+            Asserts.shouldHaveFailedPreviously("Expected exception when managing entity with incorrect config; instead passed assertion and got: "+value);
         } catch (Exception e) {
             Asserts.expectedFailureOfType(e, ConstraintViolationException.class);
         }
@@ -349,11 +339,90 @@ public class ConfigKeyConstraintTest extends BrooklynAppUnitTestSupport {
     public void testCannotUpdateConfigToInvalidValue(BrooklynObject object) {
         try {
             object.config().set(EntityRequiringConfigKeyInRange.RANGE, -1);
-            fail("Expected exception when calling config().set with invalid value on " + object);
+            Asserts.shouldHaveFailedPreviously("Expected exception when calling config().set with invalid value on " + object);
         } catch (Exception e) {
-            Throwable t = Exceptions.getFirstThrowableOfType(e, ConstraintViolationException.class);
-            assertNotNull(t, "Original exception was: " + Exceptions.collapseText(e));
+            Asserts.expectedFailureOfType(e, ConstraintViolationException.class);
         }
     }
 
+    public static interface EntityForForbiddenAndRequiredConditionalConstraints extends TestEntity {
+        ConfigKey<Object> X = ConfigKeys.builder(Object.class).name("x")
+                .build();
+    }
+    @ImplementedBy(EntityForForbiddenAndRequiredConditionalConstraintsForbiddenIfImpl.class)
+    public static interface EntityForForbiddenAndRequiredConditionalConstraintsForbiddenIf extends EntityForForbiddenAndRequiredConditionalConstraints {
+        static ConfigKey<Object> FI = ConfigKeys.builder(Object.class).name("forbiddenIfX")
+            .constraint(ConfigConstraints.forbiddenIf("x")).build();
+    }
+    public static class EntityForForbiddenAndRequiredConditionalConstraintsForbiddenIfImpl extends TestEntityImpl implements EntityForForbiddenAndRequiredConditionalConstraintsForbiddenIf {}
+    
+    @ImplementedBy(EntityForForbiddenAndRequiredConditionalConstraintsForbiddenUnlessImpl.class)
+    public static interface EntityForForbiddenAndRequiredConditionalConstraintsForbiddenUnless extends EntityForForbiddenAndRequiredConditionalConstraints {
+        static ConfigKey<Object> FU = ConfigKeys.builder(Object.class).name("forbiddenUnlessX")
+            .constraint(ConfigConstraints.forbiddenUnless("x")).build();
+    }
+    public static class EntityForForbiddenAndRequiredConditionalConstraintsForbiddenUnlessImpl extends TestEntityImpl implements EntityForForbiddenAndRequiredConditionalConstraintsForbiddenUnless {}
+    
+    @ImplementedBy(EntityForForbiddenAndRequiredConditionalConstraintsRequiredIfImpl.class)
+    public static interface EntityForForbiddenAndRequiredConditionalConstraintsRequiredIf extends EntityForForbiddenAndRequiredConditionalConstraints {
+        static ConfigKey<Object> RI = ConfigKeys.builder(Object.class).name("requiredIfX")
+            .constraint(ConfigConstraints.requiredIf("x")).build();
+    }
+    public static class EntityForForbiddenAndRequiredConditionalConstraintsRequiredIfImpl extends TestEntityImpl implements EntityForForbiddenAndRequiredConditionalConstraintsRequiredIf {}
+    
+    @ImplementedBy(EntityForForbiddenAndRequiredConditionalConstraintsRequiredUnlessImpl.class)
+    public static interface EntityForForbiddenAndRequiredConditionalConstraintsRequiredUnless extends EntityForForbiddenAndRequiredConditionalConstraints {
+        static ConfigKey<Object> RU = ConfigKeys.builder(Object.class).name("requiredUnlessX")
+            .constraint(ConfigConstraints.requiredUnless("x")).build();
+    }
+    public static class EntityForForbiddenAndRequiredConditionalConstraintsRequiredUnlessImpl extends TestEntityImpl implements EntityForForbiddenAndRequiredConditionalConstraintsRequiredUnless {}
+
+    @Test
+    public void testForbiddenAndRequiredConditionalConstraintsForbiddenIf() {
+        assertKeyBehaviour(EntityForForbiddenAndRequiredConditionalConstraintsForbiddenIf.class, EntityForForbiddenAndRequiredConditionalConstraintsForbiddenIf.FI,
+            false, true, true, true);
+    }
+
+    @Test
+    public void testForbiddenAndRequiredConditionalConstraintsForbiddenUnless() {
+        assertKeyBehaviour(EntityForForbiddenAndRequiredConditionalConstraintsForbiddenUnless.class, EntityForForbiddenAndRequiredConditionalConstraintsForbiddenUnless.FU,
+            true, true, false, true);
+    }
+
+    @Test
+    public void testForbiddenAndRequiredConditionalConstraintsRequiredIf() {
+        assertKeyBehaviour(EntityForForbiddenAndRequiredConditionalConstraintsRequiredIf.class, EntityForForbiddenAndRequiredConditionalConstraintsRequiredIf.RI,
+            true, false, true, true);
+    }
+
+    @Test
+    public void testForbiddenAndRequiredConditionalConstraintsRequiredUnlelss() {
+        assertKeyBehaviour(EntityForForbiddenAndRequiredConditionalConstraintsRequiredUnless.class, EntityForForbiddenAndRequiredConditionalConstraintsRequiredUnless.RU,
+            true, true, true, false);
+    }
+
+    private void assertKeyBehaviour(Class<? extends Entity> clazz, ConfigKey<Object> key, boolean ifBoth, boolean ifJustX, boolean ifJustThis, boolean ifNone) {
+        assertKeyBehaviour("both set", clazz, true, key, true, ifBoth);
+        assertKeyBehaviour("only other key set", clazz, true, key, false, ifJustX);
+        assertKeyBehaviour("only this key set", clazz, false, key, true, ifJustThis);
+        assertKeyBehaviour("neither key set", clazz, false, key, false, ifNone);
+    }
+    
+    private void assertKeyBehaviour(String description, Class<? extends Entity> clazz, boolean isXSet, ConfigKey<Object> key, boolean isKeySet, boolean shouldSucceed) {
+        try {
+            EntitySpec<?> spec = EntitySpec.create(clazz);
+            if (isXSet) spec.configure(EntityForForbiddenAndRequiredConditionalConstraints.X, "set");
+            if (isKeySet) spec.configure(key, "set");
+            app.createAndManageChild(spec);
+            if (!shouldSucceed) {
+                Asserts.shouldHaveFailedPreviously("Expected failure when testing "+key.getName()+" - "+description);
+            }
+        } catch (Exception e) {
+            if (!shouldSucceed) {
+                Asserts.expectedFailureOfType("Expected ConstraintViolationException when testing "+key.getName()+" - "+description, e, ConstraintViolationException.class);
+            } else {
+                throw new AssertionError("Expected success when testing "+key.getName()+" - "+description+"; instead got "+e, e);
+            }
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0d6f5721/utils/common/src/main/java/org/apache/brooklyn/test/Asserts.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/org/apache/brooklyn/test/Asserts.java b/utils/common/src/main/java/org/apache/brooklyn/test/Asserts.java
index 6975139..eb9275a 100644
--- a/utils/common/src/main/java/org/apache/brooklyn/test/Asserts.java
+++ b/utils/common/src/main/java/org/apache/brooklyn/test/Asserts.java
@@ -1261,17 +1261,21 @@ public class Asserts {
      * or more usually the test failure of this method is thrown, 
      * with detail of the original {@link Throwable} logged and included in the caused-by.
      */
-    @SuppressWarnings("unchecked")
     public static void expectedFailureOfType(Throwable e, Class<?> permittedSupertype, Class<?> ...permittedSupertypes) {
+        expectedFailureOfType(null, e, permittedSupertype, permittedSupertypes);
+    }
+    @SuppressWarnings("unchecked")
+    public static void expectedFailureOfType(String message, Throwable e, Class<?> permittedSupertype, Class<?> ...permittedSupertypeExtras) {
+        @SuppressWarnings("rawtypes")
+        List<Class<?>> permittedSupertypes = MutableList.of(permittedSupertype).appendAll((List)Arrays.asList(permittedSupertypeExtras));
         if (e instanceof ShouldHaveFailedPreviouslyAssertionError) throw (Error) e;
-        Throwable match = Exceptions.getFirstThrowableOfType(e, (Class<? extends Throwable>) permittedSupertype);
-        if (match != null) return;
         for (Class<?> clazz: permittedSupertypes) {
-            match = Exceptions.getFirstThrowableOfType(e, (Class<? extends Throwable>)clazz);
-            if (match != null) return;
+            if (Exceptions.getFirstThrowableOfType(e, (Class<? extends Throwable>)clazz) != null) {
+                return;
+            }
         }
         rethrowPreferredException(e, 
-            new AssertionError("Error "+JavaClassNames.simpleClassName(e)+" is not any of the expected types: " + Arrays.asList(permittedSupertypes), e));
+            new AssertionError((message!=null ? message+": " : "") + "Error "+JavaClassNames.simpleClassName(e)+" is not any of the expected types: " + permittedSupertypes, e));
     }
     
     /** Tests {@link #expectedFailure(Throwable)} and that the <code>toString</code>


[4/7] brooklyn-server git commit: forgot to use deserialization routines when parsing catalog input

Posted by al...@apache.org.
forgot to use deserialization routines when parsing catalog input

also test and fix for some edge-cases in serializing


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

Branch: refs/heads/master
Commit: fdb2784a8bdc7a3bc53508a381b258539f7aafc0
Parents: 5fec275
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Sat Sep 22 01:24:09 2018 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Sat Sep 22 01:24:09 2018 +0100

----------------------------------------------------------------------
 .../brooklyn/core/config/ConfigConstraints.java |  9 ++++
 .../brooklyn/core/objs/BasicSpecParameter.java  | 51 +-------------------
 .../core/objs/ConstraintSerialization.java      |  9 ++--
 .../brooklyn/util/core/ResourcePredicates.java  |  2 +-
 .../core/objs/ConstraintSerializationTest.java  | 45 +++++++++++++----
 5 files changed, 52 insertions(+), 64 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fdb2784a/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 4ee584d..c234aae 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
@@ -22,6 +22,7 @@ package org.apache.brooklyn.core.config;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Objects;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.Location;
@@ -244,6 +245,14 @@ public abstract class ConfigConstraints<T extends BrooklynObject> {
         public String toString() {
             return "required()";
         }
+        @Override
+        public boolean equals(Object obj) {
+            return (obj instanceof RequiredPredicate) && obj.getClass().equals(getClass());
+        }
+        @Override
+        public int hashCode() {
+            return Objects.hash(toString());
+        }
     }
     
     private static abstract class OtherKeyPredicate implements BrooklynObjectPredicate<Object> {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fdb2784a/core/src/main/java/org/apache/brooklyn/core/objs/BasicSpecParameter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/BasicSpecParameter.java b/core/src/main/java/org/apache/brooklyn/core/objs/BasicSpecParameter.java
index 7c1bde0..7c777f8 100644
--- a/core/src/main/java/org/apache/brooklyn/core/objs/BasicSpecParameter.java
+++ b/core/src/main/java/org/apache/brooklyn/core/objs/BasicSpecParameter.java
@@ -18,8 +18,6 @@
  */
 package org.apache.brooklyn.core.objs;
 
-import static com.google.common.base.Preconditions.checkArgument;
-
 import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -55,7 +53,6 @@ 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.guava.Maybe;
-import org.apache.brooklyn.util.text.StringPredicates;
 import org.apache.brooklyn.util.time.Duration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -70,7 +67,6 @@ import com.google.common.base.Predicates;
 import com.google.common.collect.FluentIterable;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
 import com.google.common.reflect.TypeToken;
 
 public class BasicSpecParameter<T> implements SpecParameter<T>{
@@ -221,18 +217,6 @@ public class BasicSpecParameter<T> implements SpecParameter<T>{
                 .put("port", PortRange.class)
                 .build();
 
-        private static final Map<String, Predicate<?>> BUILT_IN_CONSTRAINTS = ImmutableMap.<String, Predicate<?>>of(
-                "required", StringPredicates.isNonBlank());
-        
-        private static final Map<String, Function<Object, Predicate<?>>> BUILT_IN_CONSTRAINT_FACTORIES = ImmutableMap.<String, Function<Object, Predicate<?>>>of(
-                "regex", new Function<Object, Predicate<?>>() {
-                    @Override public Predicate<?> apply(Object input) {
-                        // TODO Could try to handle deferred supplier as well?
-                        checkArgument(input instanceof String, "Constraint regex value must be a string, but got %s (%s)",
-                                (input == null ? "null" : input.getClass().getName()), input);
-                        return StringPredicates.matchesRegex((String)input);
-                    }});
-        
         private static List<SpecParameter<?>> parseParameters(List<?> inputsRaw, Function<Object, Object> specialFlagTransformer, BrooklynClassLoadingContext loader) {
             if (inputsRaw == null) return ImmutableList.of();
             List<SpecParameter<?>> inputs = new ArrayList<>(inputsRaw.size());
@@ -381,40 +365,7 @@ public class BasicSpecParameter<T> implements SpecParameter<T>{
         }
 
         private static Predicate<?> parseConstraint(Object untypedConstraint, BrooklynClassLoadingContext loader) {
-            // TODO Could try to handle deferred supplier as well?
-            if (untypedConstraint instanceof Predicate) {
-                // An explicit predicate (e.g. via "$brooklyn:object: ...")
-                return (Predicate<?>) untypedConstraint;
-            } else if (untypedConstraint instanceof String) {
-                // build-in simple declaration, such as "required"
-                String constraint = (String)untypedConstraint;
-                if (BUILT_IN_CONSTRAINTS.containsKey(constraint)) {
-                    return BUILT_IN_CONSTRAINTS.get(constraint);
-                } else {
-                    throw new IllegalArgumentException("The constraint '" + constraint + "' for a catalog input is not "
-                            + "recognized as a built-in (" + BUILT_IN_CONSTRAINTS.keySet() + " or " 
-                            + BUILT_IN_CONSTRAINT_FACTORIES.keySet() + ")");
-                }
-            } else if (untypedConstraint instanceof Map) {
-                // For example "regex: foo.*"
-                Map<?,?> constraint = (Map<?,?>)untypedConstraint;
-                if (constraint.size() == 1) {
-                    Object key = Iterables.getOnlyElement(constraint.keySet());
-                    Object val = constraint.get(key);
-                    if (BUILT_IN_CONSTRAINT_FACTORIES.containsKey(key)) {
-                        Function<Object, Predicate<?>> factory = BUILT_IN_CONSTRAINT_FACTORIES.get(key);
-                        return factory.apply(val);
-                    } else {
-                        throw new IllegalArgumentException("The constraint '" + constraint + "' for a catalog input is not "
-                                + "recognized as a built-in (" + BUILT_IN_CONSTRAINTS.keySet() + ")");
-                    }
-                } else {
-                    throw new IllegalArgumentException("The config key constraint '" + constraint + "' is not supported - "
-                            + "it can handle only single key:value constraint.");
-                }
-            } else {
-                throw new IllegalArgumentException("The constraint '" + untypedConstraint + "' for a catalog input is not recognized");
-            }
+            return ConstraintSerialization.INSTANCE.toPredicateFromJson(untypedConstraint);
         }
         
         private static ConfigInheritance parseInheritance(Object obj, BrooklynClassLoadingContext loader) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fdb2784a/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 6844a72..2fef0e8 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
@@ -214,6 +214,9 @@ public class ConstraintSerialization {
         if (parser.result instanceof Map && ((Map)parser.result).size()==1 && ((Map)parser.result).containsKey("all")) {
             return (List<Object>) ((Map)parser.result).get("all");
         }
+        if ("Predicates.alwaysTrue".equals(parser.result)) {
+            return Collections.emptyList(); 
+        }
         return ImmutableList.of(parser.result);
     }
     
@@ -291,7 +294,7 @@ public class ConstraintSerialization {
         }
     }
 
-    private void collectPredicateListFromJson(Object o, List<Predicate<?>> result) {
+    private void collectPredicateListFromJson(Object o, Collection<Predicate<?>> result) {
         if (o instanceof Collection) {
             ((Collection<?>)o).stream().forEach(i -> collectPredicateListFromJson(i, result));
             return;
@@ -361,9 +364,9 @@ public class ConstraintSerialization {
         return Predicates.and(preds);
     }
     public List<Predicate<?>> toPredicateListFromJsonList(Collection<?> o) {
-        List<Predicate<?>> result = MutableList.of();
+        Set<Predicate<?>> result = MutableSet.of();
         collectPredicateListFromJson(o, result);
-        return result;
+        return MutableList.copyOf(result);
     }
     
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fdb2784a/core/src/main/java/org/apache/brooklyn/util/core/ResourcePredicates.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/ResourcePredicates.java b/core/src/main/java/org/apache/brooklyn/util/core/ResourcePredicates.java
index 240ab52..effed58 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/ResourcePredicates.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/ResourcePredicates.java
@@ -66,7 +66,7 @@ public class ResourcePredicates {
 
         @Override
         public String toString() {
-            return "ResourcePredicates.urlExists()";
+            return "ResourcePredicates.exists()";
         }
 
     }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fdb2784a/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 539fc87..a8fdb02 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
@@ -58,10 +58,10 @@ public class ConstraintSerializationTest extends BrooklynMgmtUnitTestSupport {
     @Test
     public void testAltName() {
         Predicate<String> p = StringPredicates.matchesGlob("???*");
-        Assert.assertEquals(ConstraintSerialization.INSTANCE.toPredicateFromJson(
-            MutableList.of(MutableMap.of("matchesGlob", "???*"))).toString(), p.toString());
-        Assert.assertEquals(ConstraintSerialization.INSTANCE.toPredicateFromJson(
-            MutableList.of(MutableMap.of("glob", "???*"))).toString(), p.toString());
+        assertSamePredicate(ConstraintSerialization.INSTANCE.toPredicateFromJson(
+            MutableList.of(MutableMap.of("matchesGlob", "???*"))), p);
+        assertSamePredicate(ConstraintSerialization.INSTANCE.toPredicateFromJson(
+            MutableList.of(MutableMap.of("glob", "???*"))), p);
         Assert.assertEquals(ConstraintSerialization.INSTANCE.toJsonList(p),
             MutableList.of(MutableMap.of("glob", "???*")));
     }
@@ -69,13 +69,19 @@ public class ConstraintSerializationTest extends BrooklynMgmtUnitTestSupport {
     @Test
     public void testAcceptsMap() {
         Predicate<String> p = StringPredicates.matchesGlob("???*");
-        Assert.assertEquals(ConstraintSerialization.INSTANCE.toPredicateFromJson(MutableMap.of("matchesGlob", "???*")).toString(), p.toString());
+        assertSamePredicate(ConstraintSerialization.INSTANCE.toPredicateFromJson(MutableMap.of("matchesGlob", "???*")), p);
+    }
+
+    @Test
+    public void testAcceptsForbiddenIfMap() {
+        Predicate<Object> p = ConfigConstraints.forbiddenIf("x");
+        assertSamePredicate(ConstraintSerialization.INSTANCE.toPredicateFromJson(MutableMap.of("forbiddenIf", "x")), p);
     }
 
     @Test
     public void testAcceptsString() {
         Predicate<String> p = StringPredicates.matchesGlob("???*");
-        Assert.assertEquals(ConstraintSerialization.INSTANCE.toPredicateFromJson("matchesGlob(\"???*\")").toString(), p.toString());
+        assertSamePredicate(ConstraintSerialization.INSTANCE.toPredicateFromJson("matchesGlob(\"???*\")"), p);
     }
     
     @Test
@@ -83,14 +89,33 @@ public class ConstraintSerializationTest extends BrooklynMgmtUnitTestSupport {
         Predicate<?> p = Predicates.notNull();
         Assert.assertEquals(ConstraintSerialization.INSTANCE.toJsonList(p),
             MutableList.of("required"));
-        Assert.assertEquals(ConstraintSerialization.INSTANCE.toPredicateFromJson("required").toString(),
-            ConfigConstraints.required().toString());
+        assertSamePredicate(ConstraintSerialization.INSTANCE.toPredicateFromJson("required"),
+            ConfigConstraints.required());
+    }
+
+    @Test
+    public void testFlattens() {
+        assertSamePredicate(ConstraintSerialization.INSTANCE.toPredicateFromJson(MutableList.of("required", "required")),
+            ConfigConstraints.required());
+    }
+    
+    @Test
+    public void testEmpty() {
+        assertSamePredicate(ConstraintSerialization.INSTANCE.toPredicateFromJson(MutableList.of()),
+            Predicates.alwaysTrue());
+        Assert.assertEquals(ConstraintSerialization.INSTANCE.toJsonList(Predicates.alwaysTrue()), 
+            MutableList.of());
     }
 
     private void assertPredJsonBidi(Predicate<?> pred, List<?> json) {
         Assert.assertEquals(ConstraintSerialization.INSTANCE.toJsonList(pred), json);
+        assertSamePredicate(ConstraintSerialization.INSTANCE.toPredicateFromJson(json), pred);
+    }
+
+    private static void assertSamePredicate(Predicate<?> p1, Predicate<?> p2) {
         // some predicates don't support equals, but all (the ones we use) must support toString
-        Assert.assertEquals(ConstraintSerialization.INSTANCE.toPredicateFromJson(json).toString(), pred.toString());
+        Assert.assertEquals(p1.toString(), p2.toString());
+        Assert.assertEquals(p1.getClass(), p2.getClass());
     }
-    
+
 }


[5/7] brooklyn-server git commit: address further PR comments

Posted by al...@apache.org.
address further PR comments


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

Branch: refs/heads/master
Commit: fc1c588381029a3623c155d88a76185d7e01f696
Parents: fdb2784
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Sat Sep 22 01:45:00 2018 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Sat Sep 22 01:45:00 2018 +0100

----------------------------------------------------------------------
 .../apache/brooklyn/core/config/ConfigConstraints.java    | 10 +++++-----
 .../brooklyn/core/objs/ConstraintSerialization.java       |  4 +++-
 .../org/apache/brooklyn/util/core/ResourcePredicates.java |  2 +-
 3 files changed, 9 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fc1c5883/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 c234aae..67d8aef 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
@@ -256,7 +256,7 @@ public abstract class ConfigConstraints<T extends BrooklynObject> {
     }
     
     private static abstract class OtherKeyPredicate implements BrooklynObjectPredicate<Object> {
-        private String otherKeyName;
+        private final String otherKeyName;
 
         public OtherKeyPredicate(String otherKeyName) {
             this.otherKeyName = otherKeyName;
@@ -286,7 +286,7 @@ public abstract class ConfigConstraints<T extends BrooklynObject> {
     }
     
     public static Predicate<Object> forbiddenIf(String otherKeyName) { return new ForbiddenIfPredicate(otherKeyName); }
-    public static class ForbiddenIfPredicate extends OtherKeyPredicate {
+    protected static class ForbiddenIfPredicate extends OtherKeyPredicate {
         public ForbiddenIfPredicate(String otherKeyName) { super(otherKeyName); }
         @Override public String predicateName() { return "forbiddenIf"; }
         @Override public boolean test(Object thisValue, Object otherValue) { 
@@ -295,7 +295,7 @@ public abstract class ConfigConstraints<T extends BrooklynObject> {
     }
     
     public static Predicate<Object> forbiddenUnless(String otherKeyName) { return new ForbiddenUnlessPredicate(otherKeyName); }
-    public static class ForbiddenUnlessPredicate extends OtherKeyPredicate {
+    protected static class ForbiddenUnlessPredicate extends OtherKeyPredicate {
         public ForbiddenUnlessPredicate(String otherKeyName) { super(otherKeyName); }
         @Override public String predicateName() { return "forbiddenUnless"; }
         @Override public boolean test(Object thisValue, Object otherValue) { 
@@ -304,7 +304,7 @@ public abstract class ConfigConstraints<T extends BrooklynObject> {
     }
     
     public static Predicate<Object> requiredIf(String otherKeyName) { return new RequiredIfPredicate(otherKeyName); }
-    public static class RequiredIfPredicate extends OtherKeyPredicate {
+    protected static class RequiredIfPredicate extends OtherKeyPredicate {
         public RequiredIfPredicate(String otherKeyName) { super(otherKeyName); }
         @Override public String predicateName() { return "requiredIf"; }
         @Override public boolean test(Object thisValue, Object otherValue) { 
@@ -313,7 +313,7 @@ public abstract class ConfigConstraints<T extends BrooklynObject> {
     }
     
     public static Predicate<Object> requiredUnless(String otherKeyName) { return new RequiredUnlessPredicate(otherKeyName); }
-    public static class RequiredUnlessPredicate extends OtherKeyPredicate {
+    protected static class RequiredUnlessPredicate extends OtherKeyPredicate {
         public RequiredUnlessPredicate(String otherKeyName) { super(otherKeyName); }
         @Override public String predicateName() { return "requiredUnless"; }
         @Override public boolean test(Object thisValue, Object otherValue) { 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fc1c5883/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 2fef0e8..984e2e7 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
@@ -40,12 +40,14 @@ import org.apache.brooklyn.util.text.StringEscapes.JavaStringEscapes;
 import org.apache.brooklyn.util.text.StringPredicates;
 import org.apache.brooklyn.util.text.Strings;
 
+import com.google.common.annotations.Beta;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 
+@Beta
 public class ConstraintSerialization {
 
     private final Map<String, String> predicateToStringToPreferredName = MutableMap.of();
@@ -184,7 +186,7 @@ public class ConstraintSerialization {
         PredicateSerializationRuleAdder.stringConstructor(ConfigConstraints::requiredUnless).add(this);
     }
     
-    public static ConstraintSerialization INSTANCE = new ConstraintSerialization();
+    public final static ConstraintSerialization INSTANCE = new ConstraintSerialization();
     
     private ConstraintSerialization() {}
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fc1c5883/core/src/main/java/org/apache/brooklyn/util/core/ResourcePredicates.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/ResourcePredicates.java b/core/src/main/java/org/apache/brooklyn/util/core/ResourcePredicates.java
index effed58..240ab52 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/ResourcePredicates.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/ResourcePredicates.java
@@ -66,7 +66,7 @@ public class ResourcePredicates {
 
         @Override
         public String toString() {
-            return "ResourcePredicates.exists()";
+            return "ResourcePredicates.urlExists()";
         }
 
     }


[7/7] brooklyn-server git commit: This closes #999

Posted by al...@apache.org.
This closes #999


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

Branch: refs/heads/master
Commit: a3d0ea06edcd15362688107f0afd9b153048c7e6
Parents: e27cc7b 3d214b8
Author: Aled Sage <al...@gmail.com>
Authored: Mon Sep 24 12:30:11 2018 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Mon Sep 24 12:30:11 2018 +0100

----------------------------------------------------------------------
 .../brooklyn/core/config/ConfigConstraints.java | 103 +++++
 .../brooklyn/core/objs/BasicSpecParameter.java  |  51 +--
 .../core/objs/ConstraintSerialization.java      | 375 +++++++++++++++++++
 .../brooklyn/util/core/ResourcePredicates.java  |   6 +-
 .../core/config/ConfigKeyConstraintTest.java    | 133 +++++--
 .../objs/BasicSpecParameterFromListTest.java    |   5 +-
 .../core/objs/ConstraintSerializationTest.java  | 121 ++++++
 .../brooklyn/rest/domain/ConfigSummary.java     |  17 +-
 .../java/org/apache/brooklyn/test/Asserts.java  |  16 +-
 .../brooklyn/util/text/StringPredicates.java    |  11 +-
 .../org/apache/brooklyn/util/text/Strings.java  |  22 +-
 .../org/apache/brooklyn/test/AssertsTest.java   |   2 +-
 12 files changed, 752 insertions(+), 110 deletions(-)
----------------------------------------------------------------------



[6/7] brooklyn-server git commit: split out notNull as different to required=nonBlank, fix tests

Posted by al...@apache.org.
split out notNull as different to required=nonBlank, fix tests


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

Branch: refs/heads/master
Commit: 3d214b89fc5308451e5078ee4651f878eab6d081
Parents: fc1c588
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Sat Sep 22 02:19:42 2018 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Sat Sep 22 02:48:58 2018 +0100

----------------------------------------------------------------------
 .../org/apache/brooklyn/core/objs/ConstraintSerialization.java  | 3 ++-
 .../brooklyn/core/objs/BasicSpecParameterFromListTest.java      | 5 +++--
 .../apache/brooklyn/core/objs/ConstraintSerializationTest.java  | 2 +-
 3 files changed, 6 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/3d214b89/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 984e2e7..32b71f0 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
@@ -167,12 +167,13 @@ public class ConstraintSerialization {
     @SuppressWarnings({ "unchecked", "rawtypes" })
     private void init() {
         PredicateSerializationRuleAdder.predicateListConstructor((o) -> ConfigConstraints.required()).
-            equivalentPredicates(Predicates.notNull(), StringPredicates.isNonBlank()).add(this);
+            equivalentPredicates(StringPredicates.isNonBlank()).add(this);
 
         PredicateSerializationRuleAdder.predicateListConstructor((o) -> Predicates.or((Iterable)o)).preferredName("any").equivalentNames("or").add(this);
         PredicateSerializationRuleAdder.predicateListConstructor((o) -> /* and predicate is default when given list */ toPredicateFromJson(o)).preferredName("all").sample(Predicates.and(Collections.emptyList())).equivalentNames("and").add(this);
         PredicateSerializationRuleAdder.noArgConstructor(Predicates::alwaysFalse).add(this);
         PredicateSerializationRuleAdder.noArgConstructor(Predicates::alwaysTrue).add(this);
+        PredicateSerializationRuleAdder.noArgConstructor(Predicates::notNull).add(this);
         
         PredicateSerializationRuleAdder.noArgConstructor(ResourcePredicates::urlExists).preferredName("urlExists").add(this);
         PredicateSerializationRuleAdder.noArgConstructor(StringPredicates::isBlank).add(this);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/3d214b89/core/src/test/java/org/apache/brooklyn/core/objs/BasicSpecParameterFromListTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/objs/BasicSpecParameterFromListTest.java b/core/src/test/java/org/apache/brooklyn/core/objs/BasicSpecParameterFromListTest.java
index 887e054..3ce8d9c 100644
--- a/core/src/test/java/org/apache/brooklyn/core/objs/BasicSpecParameterFromListTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/objs/BasicSpecParameterFromListTest.java
@@ -28,6 +28,7 @@ import java.util.List;
 import org.apache.brooklyn.api.mgmt.classloading.BrooklynClassLoadingContext;
 import org.apache.brooklyn.api.objs.SpecParameter;
 import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigConstraints;
 import org.apache.brooklyn.core.mgmt.classloading.JavaBrooklynClassLoadingContext;
 import org.apache.brooklyn.core.test.BrooklynMgmtUnitTestSupport;
 import org.apache.brooklyn.util.text.StringPredicates;
@@ -99,7 +100,7 @@ public class BasicSpecParameterFromListTest extends BrooklynMgmtUnitTestSupport
         assertEquals(type.getDefaultValue(), defaultValue);
         assertEquals(type.getDescription(), description);
         assertTrue(type.getInheritanceByContext().values().isEmpty(), "Unexpected inheritance: "+type.getInheritanceByContext());
-        assertConstraint(type.getConstraint(), StringPredicates.isNonBlank());
+        assertConstraint(type.getConstraint(), ConfigConstraints.required());
     }
 
     @Test
@@ -132,7 +133,7 @@ public class BasicSpecParameterFromListTest extends BrooklynMgmtUnitTestSupport
                 "name", name,
                 "constraints", ImmutableList.of(constraint)));
         ConfigKey<?> type = input.getConfigKey();
-        assertConstraint(type.getConstraint(), StringPredicates.isNonBlank());
+        assertConstraint(type.getConstraint(), ConfigConstraints.required());
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class)

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/3d214b89/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 a8fdb02..bdbc5ad 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
@@ -86,7 +86,7 @@ public class ConstraintSerializationTest extends BrooklynMgmtUnitTestSupport {
     
     @Test
     public void testAltPred() {
-        Predicate<?> p = Predicates.notNull();
+        Predicate<?> p = StringPredicates.isNonBlank();
         Assert.assertEquals(ConstraintSerialization.INSTANCE.toJsonList(p),
             MutableList.of("required"));
         assertSamePredicate(ConstraintSerialization.INSTANCE.toPredicateFromJson("required"),