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 b96795f7ae55f440d3e8c44ab155922571498307 Author: Alex Heneveld <[email protected]> AuthorDate: Thu Feb 2 13:52:07 2023 +0000 add type info support for effector parameters --- .../apache/brooklyn/core/config/ConfigKeys.java | 31 +++++++++++++++++----- .../AddEffectorInitializerAbstractProto.java | 4 ++- .../apache/brooklyn/core/effector/Effectors.java | 24 +++++++++-------- .../brooklyn/core/typereg/RegisteredTypes.java | 16 +++++++++++ .../core/workflow/WorkflowExecutionContext.java | 3 ++- .../core/flags/BrooklynTypeNameResolution.java | 18 ++++++++----- 6 files changed, 70 insertions(+), 26 deletions(-) diff --git a/core/src/main/java/org/apache/brooklyn/core/config/ConfigKeys.java b/core/src/main/java/org/apache/brooklyn/core/config/ConfigKeys.java index dc7dabb2a2..8982196e88 100644 --- a/core/src/main/java/org/apache/brooklyn/core/config/ConfigKeys.java +++ b/core/src/main/java/org/apache/brooklyn/core/config/ConfigKeys.java @@ -22,6 +22,7 @@ import java.util.Map; import javax.annotation.Nonnull; +import org.apache.brooklyn.api.mgmt.classloading.BrooklynClassLoadingContext; import org.apache.brooklyn.config.ConfigInheritance.ConfigInheritanceContext; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.config.BasicConfigKey.BasicConfigKeyOverwriting; @@ -30,6 +31,7 @@ import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey; import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey; import org.apache.brooklyn.core.sensor.TemplatedStringAttributeSensorAndConfigKey; import org.apache.brooklyn.util.core.config.ConfigBag; +import org.apache.brooklyn.util.core.flags.BrooklynTypeNameResolution; import org.apache.brooklyn.util.text.Strings; import org.apache.brooklyn.util.time.Duration; import org.slf4j.Logger; @@ -255,22 +257,34 @@ public class ConfigKeys { public static class DynamicKeys { - // TODO see below -// public static final ConfigKey<String> TYPE = ConfigKeys.newStringConfigKey("type"); + public static final ConfigKey<Object> TYPE = ConfigKeys.newConfigKey(Object.class, "type", "type of this key or parameter, as a string or class or TypeToken"); public static final ConfigKey<String> NAME = ConfigKeys.newStringConfigKey("name"); public static final ConfigKey<String> DESCRIPTION = ConfigKeys.newStringConfigKey("description"); public static final ConfigKey<Object> DEFAULT_VALUE = ConfigKeys.newConfigKey(Object.class, "defaultValue"); public static ConfigKey<?> newInstance(ConfigBag keyDefs) { - String typeName = Strings.toString(keyDefs.getStringKey("type")); - if (Strings.isNonBlank(typeName)) { + return newInstance(keyDefs, null); + } + public static ConfigKey<?> newInstance(ConfigBag keyDefs, BrooklynClassLoadingContext loader) { + Object typeName = keyDefs.getStringKey("type"); + TypeToken type = TypeToken.of(Object.class); + if (typeName!=null) { + if (typeName instanceof String) { + type = new BrooklynTypeNameResolution.BrooklynTypeNameResolver("dynamic config key", loader, true, true) + .getTypeToken((String) typeName); + } else if (typeName instanceof TypeToken) { + type = (TypeToken) typeName; + } else if (typeName instanceof Class) { + type = TypeToken.of((Class)typeName); + } else { + throw new IllegalArgumentException("Invalid type definition for config key"); + } // could do dynamic typing - see TYPE key commented out above; also see AddSensor.getType for type lookup // but we don't want that, because the rules for this are subtle (not universal), and // it is implemented on jackson conversion instead, which coercion will do in some cases // log.warn("Setting 'type' is not currently supported for dynamic config keys; ignoring in definition of "+keyDefs); } - - Class<Object> type = Object.class; + String name = keyDefs.get(NAME); String description = keyDefs.get(DESCRIPTION); Object defaultValue = keyDefs.get(DEFAULT_VALUE); @@ -284,11 +298,14 @@ public class ConfigKeys { /** creates a new {@link ConfigKey} given a name (e.g. as a key in a larger map) and a map of other definition attributes */ public static ConfigKey<?> newNamedInstance(String name, Map<?,?> keyDefs) { + return newNamedInstance(name, keyDefs, null); + } + public static ConfigKey<?> newNamedInstance(String name, Map<?,?> keyDefs, BrooklynClassLoadingContext loader) { ConfigBag defs = ConfigBag.newInstance(keyDefs); String oldName = defs.put(NAME, name); if (oldName!=null && !oldName.equals(name)) log.warn("Dynamic key '"+oldName+"' being overridden as key '"+name+"' in "+keyDefs); - return newInstance(defs); + return newInstance(defs, loader); } } diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/AddEffectorInitializerAbstractProto.java b/core/src/main/java/org/apache/brooklyn/core/effector/AddEffectorInitializerAbstractProto.java index 7dce0e0cb7..e0940f902a 100644 --- a/core/src/main/java/org/apache/brooklyn/core/effector/AddEffectorInitializerAbstractProto.java +++ b/core/src/main/java/org/apache/brooklyn/core/effector/AddEffectorInitializerAbstractProto.java @@ -25,6 +25,7 @@ import org.apache.brooklyn.api.effector.Effector; import org.apache.brooklyn.api.effector.ParameterType; import org.apache.brooklyn.api.entity.EntityInitializer; import org.apache.brooklyn.api.entity.EntityLocal; +import org.apache.brooklyn.api.mgmt.classloading.BrooklynClassLoadingContext; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.config.ConfigKeys; import org.apache.brooklyn.core.config.MapConfigKey; @@ -78,7 +79,8 @@ public abstract class AddEffectorInitializerAbstractProto extends EntityInitiali EffectorBuilder<T> eff = Effectors.effector(type, name); eff.description(params.get(EFFECTOR_DESCRIPTION)); - Effectors.parseParameters(params.get(EFFECTOR_PARAMETER_DEFS)).forEach(p -> eff.parameter(p)); + BrooklynClassLoadingContext loader = null; // we need an entity or mgmt context to get a loader, but we don't need to resolve the types so no big deal + Effectors.parseParameters(params.get(EFFECTOR_PARAMETER_DEFS), loader).forEach(p -> eff.parameter(p)); return eff; } diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/Effectors.java b/core/src/main/java/org/apache/brooklyn/core/effector/Effectors.java index 2daeb87159..670a7b5f2e 100644 --- a/core/src/main/java/org/apache/brooklyn/core/effector/Effectors.java +++ b/core/src/main/java/org/apache/brooklyn/core/effector/Effectors.java @@ -18,15 +18,16 @@ */ package org.apache.brooklyn.core.effector; -import java.util.*; -import java.util.function.Consumer; - -import javax.annotation.Nullable; - +import com.google.common.base.Objects; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.reflect.TypeToken; import org.apache.brooklyn.api.effector.Effector; import org.apache.brooklyn.api.effector.ParameterType; import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.mgmt.TaskAdaptable; +import org.apache.brooklyn.api.mgmt.classloading.BrooklynClassLoadingContext; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.config.ConfigKeys; import org.apache.brooklyn.core.effector.EffectorTasks.EffectorBodyTaskFactory; @@ -44,11 +45,9 @@ import org.apache.brooklyn.util.text.Strings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.base.Objects; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.reflect.TypeToken; +import javax.annotation.Nullable; +import java.util.*; +import java.util.function.Consumer; public class Effectors { @@ -248,6 +247,9 @@ public class Effectors { } public static Collection<ParameterType<?>> parseParameters(Map<String,Object> paramDefs) { + return parseParameters(paramDefs, null); + } + public static Collection<ParameterType<?>> parseParameters(Map<String,Object> paramDefs, BrooklynClassLoadingContext loader) { Set<ParameterType<?>> result = MutableSet.of(); if (paramDefs==null) return result; @@ -263,7 +265,7 @@ public class Effectors { if (!(value instanceof Map)) throw new IllegalArgumentException("Illegal argument of type "+value.getClass()+" value '"+value+"' supplied as parameter definition " + "'"+paramName); - result.add(Effectors.asParameterType(ConfigKeys.DynamicKeys.newNamedInstance(paramName, (Map<?, ?>) value))); + result.add(Effectors.asParameterType(ConfigKeys.DynamicKeys.newNamedInstance(paramName, (Map<?, ?>) value, loader))); } } return result; diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypes.java b/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypes.java index ec88e89ae6..572cc26e9a 100644 --- a/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypes.java +++ b/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypes.java @@ -38,6 +38,7 @@ import org.apache.brooklyn.api.mgmt.classloading.BrooklynClassLoadingContext; import org.apache.brooklyn.api.mgmt.rebind.RebindSupport; import org.apache.brooklyn.api.mgmt.rebind.mementos.CatalogItemMemento; import org.apache.brooklyn.api.objs.BrooklynObject; +import org.apache.brooklyn.api.objs.EntityAdjunct; import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry; import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry.RegisteredTypeKind; import org.apache.brooklyn.api.typereg.ManagedBundle; @@ -48,6 +49,7 @@ import org.apache.brooklyn.api.typereg.RegisteredTypeLoadingContext; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.catalog.internal.CatalogUtils; import org.apache.brooklyn.core.config.ConfigKeys; +import org.apache.brooklyn.core.entity.EntityAdjuncts; import org.apache.brooklyn.core.mgmt.BrooklynTags; import org.apache.brooklyn.core.mgmt.BrooklynTags.NamedStringTag; import org.apache.brooklyn.core.mgmt.BrooklynTaskTags; @@ -796,6 +798,20 @@ public class RegisteredTypes { return CatalogUtils.getClassLoadingContext(entity); } + /** gets the loading context for the entity associated with a brooklyn object; + * throws if not possible. + * + * in future it might look at an adjunct's origin also, preferring that. */ + public static Maybe<BrooklynClassLoadingContext> getClassLoadingContextMaybe(BrooklynObject bo) { + if (bo instanceof EntityAdjuncts.EntityAdjunctProxyable) { + bo = ((EntityAdjuncts.EntityAdjunctProxyable)bo).getEntity(); + } + if (!(bo instanceof Entity)) { + return Maybe.absent("Unable to get loading context for "+bo); + } + return Maybe.of(CatalogUtils.getClassLoadingContext((Entity) bo)); + } + public static BrooklynClassLoadingContext getClassLoadingContext(ManagementContext mgmt, Entity optionalEntity) { return optionalEntity!=null ? CatalogUtils.getClassLoadingContext(optionalEntity) : JavaBrooklynClassLoadingContext.create(mgmt); } diff --git a/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowExecutionContext.java b/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowExecutionContext.java index 2e9e0581d8..c05562c97e 100644 --- a/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowExecutionContext.java +++ b/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowExecutionContext.java @@ -227,7 +227,8 @@ public class WorkflowExecutionContext { // parameter defs Map<String,ConfigKey<?>> parameters = MutableMap.of(); - Effectors.parseParameters(paramsDefiningWorkflow.get(WorkflowCommonConfig.PARAMETER_DEFS)).forEach(p -> parameters.put(p.getName(), Effectors.asConfigKey(p))); + Maybe<BrooklynClassLoadingContext> loader = RegisteredTypes.getClassLoadingContextMaybe(entityOrAdjunctWhereRunning); + Effectors.parseParameters(paramsDefiningWorkflow.get(WorkflowCommonConfig.PARAMETER_DEFS), loader.orNull()).forEach(p -> parameters.put(p.getName(), Effectors.asConfigKey(p))); if (extraConfigKeys!=null) extraConfigKeys.forEach(p -> parameters.put(p.getName(), p)); // inputs, unresolved first diff --git a/core/src/main/java/org/apache/brooklyn/util/core/flags/BrooklynTypeNameResolution.java b/core/src/main/java/org/apache/brooklyn/util/core/flags/BrooklynTypeNameResolution.java index 2be8992791..bd77e37e91 100644 --- a/core/src/main/java/org/apache/brooklyn/util/core/flags/BrooklynTypeNameResolution.java +++ b/core/src/main/java/org/apache/brooklyn/util/core/flags/BrooklynTypeNameResolution.java @@ -51,6 +51,8 @@ import org.apache.commons.lang3.reflect.TypeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.Nullable; + public class BrooklynTypeNameResolution { private static Logger LOG = LoggerFactory.getLogger(BrooklynTypeNameResolution.class); @@ -133,13 +135,13 @@ public class BrooklynTypeNameResolution { this(context, mgmt, null, false, mgmt != null); } /** resolver supporting configurable sources of types */ - public BrooklynTypeNameResolver(String context, BrooklynClassLoadingContext loader, boolean allowJavaType, boolean allowRegisteredTypes) { - this(context, loader.getManagementContext(), loader, allowJavaType, allowRegisteredTypes); + public BrooklynTypeNameResolver(String context, @Nullable BrooklynClassLoadingContext loader, boolean allowJavaType, boolean allowRegisteredTypes) { + this(context, loader==null ? null : loader.getManagementContext(), loader, allowJavaType, allowRegisteredTypes); } - private BrooklynTypeNameResolver(String context, ManagementContext mgmt, BrooklynClassLoadingContext loader, boolean allowJavaType, boolean allowRegisteredTypes) { + private BrooklynTypeNameResolver(String context, @Nullable ManagementContext mgmt, BrooklynClassLoadingContext loader, boolean allowJavaType, boolean allowRegisteredTypes) { this.context = context; this.mgmt = mgmt; - this.loader = loader==null ? JavaBrooklynClassLoadingContext.create(mgmt) : loader; + this.loader = loader==null ? mgmt==null ? null : JavaBrooklynClassLoadingContext.create(mgmt) : loader; this.allowJavaType = allowJavaType; this.allowRegisteredTypes = allowRegisteredTypes; @@ -152,8 +154,12 @@ public class BrooklynTypeNameResolution { } if (allowRegisteredTypes) { - rules.put("Brooklyn registered types", - s -> mgmt.getTypeRegistry().getMaybe(s, RegisteredTypeLoadingContexts.loader(loader)).map(BrooklynJacksonType::asTypeToken)); + if (mgmt==null) { + // registered types not available if no mgmt context supplied + } else { + rules.put("Brooklyn registered types", + s -> mgmt.getTypeRegistry().getMaybe(s, RegisteredTypeLoadingContexts.loader(loader)).map(BrooklynJacksonType::asTypeToken)); + } } }
