This is an automated email from the ASF dual-hosted git repository.

heneveld pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brooklyn-server.git

commit 55f1c81c39082cb201c9b47552ef459a763d243a
Author: Alex Heneveld <[email protected]>
AuthorDate: Wed Feb 13 13:42:22 2019 +0000

    allow the types of parameters to be extended programmatically
    
    and misc comments to clarify some immediate resolution semantics
---
 .../brooklyn/core/config/ConfigConstraints.java    |  5 +++
 .../brooklyn/core/objs/BasicSpecParameter.java     | 43 ++++++++++++++++------
 .../brooklyn/core/objs/BrooklynObjectInternal.java |  5 +++
 3 files changed, 41 insertions(+), 12 deletions(-)

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 bcc9a25..a47c79a 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
@@ -156,6 +156,11 @@ public abstract class ConfigConstraints<T extends 
BrooklynObject> {
                 if (!isValueValid(ck, maybeValue.get())) {
                     violating.add(configKey);
                 }
+            } else {
+                // absent means did not resolve in time or not coercible;
+                // code will return `Maybe.of(null)` if it is unset,
+                // and coercion errors are handled when the value is _set_ or 
_needed_
+                // (this allows us to deal with edge cases where we can't 
*immediately* coerce)
             }
         }
         return violating;
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 b2c24aa..640d6dd 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
@@ -27,6 +27,7 @@ import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.BiFunction;
 
 import org.apache.brooklyn.api.catalog.CatalogConfig;
 import org.apache.brooklyn.api.entity.Entity;
@@ -53,6 +54,7 @@ import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.text.Strings;
 import org.apache.brooklyn.util.time.Duration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -73,7 +75,7 @@ public class BasicSpecParameter<T> implements 
SpecParameter<T>{
     private static final long serialVersionUID = -4728186276307619778L;
 
     private static final Logger log = 
LoggerFactory.getLogger(BasicSpecParameter.class);
-    
+        
     private final String label;
 
     /** pinning may become a priority or other more expansive indicator */
@@ -197,6 +199,15 @@ public class BasicSpecParameter<T> implements 
SpecParameter<T>{
         return type;
     }
 
+    /** Allows extensions to define additional types that are supported for 
parameters in YAML.
+     * Rules should return a TypeToken if the given name is known, null if not 
handled, or 
+     * throw if the name is decisively problematic. Handlers will throw if no 
rules match. 
+     */
+    @Beta
+    public static void addCustomTypeNameInference(String ruleName, 
BiFunction<String,BrooklynClassLoadingContext,TypeToken<?>> rule) {
+        ParseYamlInputs.customTypeNameInferencing.put(ruleName, rule);
+    }
+    
     private static final class ParseYamlInputs {
         private static final String DEFAULT_TYPE = "string";
         private static final Map<String, Class<?>> BUILT_IN_TYPES = 
ImmutableMap.<String, Class<?>>builder()
@@ -217,6 +228,19 @@ public class BasicSpecParameter<T> implements 
SpecParameter<T>{
                 .put("port", PortRange.class)
                 .build();
 
+        /** Map of rule-name to rule; see {@link 
BasicSpecParameter#addCustomTypeNameInference(String, BiFunction)} */
+        public static 
Map<String,BiFunction<String,BrooklynClassLoadingContext,TypeToken<?>>> 
customTypeNameInferencing = MutableMap.of();
+        static {
+            customTypeNameInferencing.put("simple types 
("+Strings.join(BUILT_IN_TYPES.keySet(), ", ")+")", 
+                (name, loaderContext) -> 
BUILT_IN_TYPES.containsKey(name.toLowerCase()) ? 
+                    TypeToken.of(BUILT_IN_TYPES.get(name.toLowerCase())) : 
null);
+            customTypeNameInferencing.put("Java types", (name, loaderContext) 
-> {
+                // Assume it's a Java type
+                Maybe<Class<?>> inputType = loaderContext.tryLoadClass(name);
+                return inputType.isPresent() ? TypeToken.of(inputType.get()) : 
null;
+            });
+        }
+
         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());
@@ -319,21 +343,16 @@ public class BasicSpecParameter<T> implements 
SpecParameter<T>{
             }
         }
         
-        @SuppressWarnings({ "rawtypes" })
         private static TypeToken inferType(String typeRaw, 
BrooklynClassLoadingContext loader) {
             if (typeRaw == null) return TypeToken.of(String.class);
             String type = typeRaw.trim();
-            if (BUILT_IN_TYPES.containsKey(type.toLowerCase())) {
-                return TypeToken.of(BUILT_IN_TYPES.get(type.toLowerCase()));
-            } else {
-                // Assume it's a Java type
-                Maybe<Class<?>> inputType = loader.tryLoadClass(type);
-                if (inputType.isPresent()) {
-                    return TypeToken.of(inputType.get());
-                } else {
-                    throw new IllegalArgumentException("The type '" + type + 
"' for a catalog input not recognised as a built-in (" + 
BUILT_IN_TYPES.keySet() + ") or a java type");
-                }
+            for (BiFunction<String,BrooklynClassLoadingContext,TypeToken<?>> 
f: customTypeNameInferencing.values()) {
+                TypeToken<?> result = f.apply(type, loader);
+                if (result!=null) return result;
             }
+            throw new IllegalArgumentException("The type '" + type + "' for a 
parameter is not recognised; supported items are: "
+                + Strings.join(customTypeNameInferencing.keySet(), ", "));
+
         }
 
         @SuppressWarnings({ "unchecked", "rawtypes" })
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java 
b/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java
index 972612b..7446030 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java
@@ -132,6 +132,11 @@ public interface BrooklynObjectInternal extends 
BrooklynObject, Rebindable {
          * including returning a default if the config key is unset,
          * returning a {@link Maybe#absent absent} if the uncoerced
          * does not support immediate resolution.
+         * This also returns {@link Maybe#absent absent} if the value 
+         * or default value cannot be coerced to the type required by the key,
+         * with coercion errors typically handled when setting or when getting
+         * the "really needed" values, not when validating constraints which
+         * is one of the main use cases of this method.
          * <p>
          * Note: if no value for the key is available, not even as a default,
          * this returns a {@link Maybe#isPresent()} containing 
<code>null</code>

Reply via email to