$brooklyn:object: handle osgi classes If canât load immediately, then defer until we know the entity thus the catalog (and libraries).
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/25605cae Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/25605cae Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/25605cae Branch: refs/heads/master Commit: 25605caee4a2b2313eb3dc31759967f65be67b87 Parents: a4930f0 Author: Aled Sage <[email protected]> Authored: Thu Jul 7 00:07:25 2016 +0100 Committer: Aled Sage <[email protected]> Committed: Sat Jul 9 10:58:36 2016 +0100 ---------------------------------------------------------------------- .../spi/dsl/methods/BrooklynDslCommon.java | 63 ++++++++++++++------ 1 file changed, 45 insertions(+), 18 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/25605cae/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java ---------------------------------------------------------------------- diff --git a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java index d496fd7..23cc3a3 100644 --- a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java +++ b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java @@ -18,6 +18,8 @@ */ package org.apache.brooklyn.camp.brooklyn.spi.dsl.methods; +import static com.google.common.base.Preconditions.checkNotNull; + import java.util.Arrays; import java.util.Iterator; import java.util.List; @@ -39,7 +41,9 @@ import org.apache.brooklyn.camp.brooklyn.spi.dsl.BrooklynDslDeferredSupplier; import org.apache.brooklyn.camp.brooklyn.spi.dsl.DslUtils; import org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.DslComponent.Scope; import org.apache.brooklyn.core.config.external.ExternalConfigSupplier; +import org.apache.brooklyn.core.entity.AbstractEntity; import org.apache.brooklyn.core.entity.EntityDynamicType; +import org.apache.brooklyn.core.entity.EntityInternal; import org.apache.brooklyn.core.mgmt.internal.ExternalConfigSupplierRegistry; import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal; import org.apache.brooklyn.core.mgmt.persist.DeserializingClassRenamesProvider; @@ -57,6 +61,8 @@ import org.apache.brooklyn.util.javalang.coerce.ClassCoercionException; import org.apache.brooklyn.util.text.StringEscapes.JavaStringEscapes; import org.apache.brooklyn.util.text.Strings; import org.apache.commons.beanutils.BeanUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.common.base.Function; import com.google.common.base.Objects; @@ -66,6 +72,8 @@ import com.google.common.collect.Lists; /** static import functions which can be used in `$brooklyn:xxx` contexts */ public class BrooklynDslCommon { + private static final Logger LOG = LoggerFactory.getLogger(BrooklynDslCommon.class); + // Access specific entities public static DslComponent self() { @@ -162,8 +170,9 @@ public class BrooklynDslCommon { /** * Return an instance of the specified class with its fields set according - * to the {@link Map} or a {@link BrooklynDslDeferredSupplier} if the arguments are not - * yet fully resolved. + * to the {@link Map}. Or a {@link BrooklynDslDeferredSupplier} if either the arguments are + * not yet fully resolved, or the class cannot be loaded yet (e.g. needs the catalog's OSGi + * bundles). */ @SuppressWarnings("unchecked") public static Object object(Map<String, Object> arguments) { @@ -171,22 +180,24 @@ public class BrooklynDslCommon { String typeName = BrooklynYamlTypeInstantiator.InstantiatorFromKey.extractTypeName("object", config).orNull(); Map<String,Object> objectFields = (Map<String, Object>) config.getStringKeyMaybe("object.fields").or(MutableMap.of()); Map<String,Object> brooklynConfig = (Map<String, Object>) config.getStringKeyMaybe(BrooklynCampReservedKeys.BROOKLYN_CONFIG).or(MutableMap.of()); + + String mappedTypeName = DeserializingClassRenamesProvider.findMappedName(typeName); + Class<?> type; try { - // TODO Should use catalog's classloader, rather than ClassLoaderUtils; how to get that? Should we return a future?! - String mappedTypeName = DeserializingClassRenamesProvider.findMappedName(typeName); - Class<?> type = new ClassLoaderUtils(BrooklynDslCommon.class).loadClass(mappedTypeName); - - if (!Reflections.hasNoArgConstructor(type)) { - throw new IllegalStateException(String.format("Cannot construct %s bean: No public no-arg constructor available", type)); - } - if ((objectFields.isEmpty() || DslUtils.resolved(objectFields.values())) && - (brooklynConfig.isEmpty() || DslUtils.resolved(brooklynConfig.values()))) { - return DslObject.create(type, objectFields, brooklynConfig); - } else { - return new DslObject(type, objectFields, brooklynConfig); - } + type = new ClassLoaderUtils(BrooklynDslCommon.class).loadClass(mappedTypeName); } catch (ClassNotFoundException e) { - throw Exceptions.propagate(e); + LOG.debug("Cannot load class " + typeName + " for DLS object; assuming it is in OSGi bundle; will defer its loading"); + return new DslObject(mappedTypeName, objectFields, brooklynConfig); + } + + if (!Reflections.hasNoArgConstructor(type)) { + throw new IllegalStateException(String.format("Cannot construct %s bean: No public no-arg constructor available", type)); + } + if ((objectFields.isEmpty() || DslUtils.resolved(objectFields.values())) && + (brooklynConfig.isEmpty() || DslUtils.resolved(brooklynConfig.values()))) { + return DslObject.create(type, objectFields, brooklynConfig); + } else { + return new DslObject(type, objectFields, brooklynConfig); } } @@ -316,11 +327,18 @@ public class BrooklynDslCommon { private static final long serialVersionUID = 8878388748085419L; + private String typeName; private Class<?> type; private Map<String,Object> fields, config; + public DslObject(String typeName, Map<String,Object> fields, Map<String,Object> config) { + this.typeName = checkNotNull(typeName, "typeName"); + this.fields = MutableMap.copyOf(fields); + this.config = MutableMap.copyOf(config); + } + public DslObject(Class<?> type, Map<String,Object> fields, Map<String,Object> config) { - this.type = type; + this.type = checkNotNull(type, "type"); this.fields = MutableMap.copyOf(fields); this.config = MutableMap.copyOf(config); } @@ -328,6 +346,14 @@ public class BrooklynDslCommon { @SuppressWarnings("unchecked") @Override public Task<Object> newTask() { + if (type == null) { + EntityInternal entity = entity(); + try { + type = new ClassLoaderUtils(BrooklynDslCommon.class, entity).loadClass(typeName); + } catch (ClassNotFoundException e) { + throw Exceptions.propagate(e); + } + } List<TaskAdaptable<Object>> tasks = Lists.newLinkedList(); for (Object value : Iterables.concat(fields.values(), config.values())) { if (value instanceof TaskAdaptable) { @@ -336,6 +362,7 @@ public class BrooklynDslCommon { tasks.add(((TaskFactory<TaskAdaptable<Object>>) value).newTask()); } } + Map<String,?> flags = MutableMap.<String,String>of("displayName", "building '"+type+"' with "+tasks.size()+" task"+(tasks.size()!=1?"s":"")); return DependentConfiguration.transformMultiple(flags, new Function<List<Object>, Object>() { @Override @@ -399,7 +426,7 @@ public class BrooklynDslCommon { @Override public String toString() { - return "$brooklyn:object(\""+type.getName()+"\")"; + return "$brooklyn:object(\""+(type != null ? type.getName() : typeName)+"\")"; } }
