Working CampTypePlanTransformer
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/904c45e9 Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/904c45e9 Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/904c45e9 Branch: refs/heads/master Commit: 904c45e961f5e6b596e6c7238ebf86ee7a6ce7bc Parents: 817e9bd Author: Alex Heneveld <[email protected]> Authored: Wed Nov 4 10:47:22 2015 -0500 Committer: Alex Heneveld <[email protected]> Committed: Tue Nov 10 17:13:02 2015 +0000 ---------------------------------------------------------------------- .../apache/brooklyn/api/entity/EntitySpec.java | 2 - .../internal/AbstractBrooklynObjectSpec.java | 16 ++ .../brooklyn/api/typereg/RegisteredType.java | 20 +- .../api/typereg/RegisteredTypeConstraint.java | 5 + .../core/catalog/internal/CatalogUtils.java | 17 +- .../brooklyn/core/plan/PlanToSpecFactory.java | 2 +- .../entity/DelegatingEntitySpecResolver.java | 2 +- .../core/typereg/BasicBrooklynTypeRegistry.java | 8 +- .../core/typereg/BasicRegisteredType.java | 27 +- .../JavaClassNameTypePlanTransformer.java | 90 +++++++ .../core/typereg/JavaTypePlanTransformer.java | 112 -------- .../core/typereg/RegisteredTypeConstraints.java | 59 +++- .../core/typereg/RegisteredTypePredicates.java | 32 ++- .../brooklyn/core/typereg/RegisteredTypes.java | 143 +++++++++- ...lyn.core.typereg.BrooklynTypePlanTransformer | 19 ++ .../brooklyn/core/sensor/StaticSensorTest.java | 8 +- .../core/test/entity/TestEntityImpl.java | 1 - .../typereg/JavaTypePlanTransformerTest.java | 6 +- .../api/AssemblyTemplateSpecInstantiator.java | 6 +- .../BrooklynAssemblyTemplateInstantiator.java | 17 +- .../brooklyn/spi/creation/CampCatalogUtils.java | 54 +--- .../spi/creation/CampInternalUtils.java | 247 +++++++++++++++++ .../brooklyn/spi/creation/CampResolver.java | 142 ++++++++++ .../spi/creation/CampToSpecTransformer.java | 15 +- .../spi/creation/CampTypePlanTransformer.java | 90 +++++++ .../camp/brooklyn/spi/creation/CampUtils.java | 267 ------------------- .../service/UrlServiceSpecResolver.java | 19 +- ...lyn.core.typereg.BrooklynTypePlanTransformer | 19 ++ .../camp/brooklyn/AbstractYamlTest.java | 42 ++- .../camp/brooklyn/EntitiesYamlTest.java | 2 + .../camp/brooklyn/ReferencedYamlTest.java | 1 + .../CatalogOsgiVersionMoreEntityTest.java | 18 +- .../catalog/CatalogYamlLocationTest.java | 3 +- .../test/lite/TestAppAssemblyInstantiator.java | 10 +- .../rest/util/BrooklynRestResourceUtils.java | 2 +- .../exceptions/PropagatedRuntimeException.java | 6 + 36 files changed, 995 insertions(+), 534 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/api/src/main/java/org/apache/brooklyn/api/entity/EntitySpec.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/entity/EntitySpec.java b/api/src/main/java/org/apache/brooklyn/api/entity/EntitySpec.java index a38e52e..500952d 100644 --- a/api/src/main/java/org/apache/brooklyn/api/entity/EntitySpec.java +++ b/api/src/main/java/org/apache/brooklyn/api/entity/EntitySpec.java @@ -337,8 +337,6 @@ public class EntitySpec<T extends Entity> extends AbstractBrooklynObjectSpec<T,E return this; } - /** strings inserted as flags, config keys inserted as config keys; - * if you want to force one or the other, create a ConfigBag and convert to the appropriate map type */ public EntitySpec<T> configure(Map<?,?> val) { checkMutable(); for (Map.Entry<?, ?> entry: val.entrySet()) { http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java b/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java index 6ba5a3c..de2954d 100644 --- a/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java +++ b/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java @@ -23,8 +23,11 @@ import static com.google.common.base.Preconditions.checkNotNull; import java.io.Serializable; import java.lang.reflect.Modifier; import java.util.List; +import java.util.Map; import java.util.Set; +import org.apache.brooklyn.api.mgmt.EntityManager; +import org.apache.brooklyn.api.objs.BrooklynObject; import org.apache.brooklyn.api.objs.SpecParameter; import org.apache.brooklyn.util.collections.MutableSet; import org.apache.brooklyn.util.exceptions.Exceptions; @@ -34,6 +37,15 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; +/** Defines a spec for creating a {@link BrooklynObject}. + * <p> + * In addition to the contract defined by the code, + * subclasses should provide a public static <code>create(Class)</code> + * method to create an instance of the spec for the target type indicated by the argument. + * <p> + * The spec is then passed to type-specific methods, + * e.g. {@link EntityManager#createEntity(org.apache.brooklyn.api.entity.EntitySpec)} + * to create a managed instance of the target type. */ public abstract class AbstractBrooklynObjectSpec<T,SpecT extends AbstractBrooklynObjectSpec<T,SpecT>> implements Serializable { private static final long serialVersionUID = 3010955277740333030L; @@ -160,5 +172,9 @@ public abstract class AbstractBrooklynObjectSpec<T,SpecT extends AbstractBrookly public int hashCode() { return Objects.hashCode(getCatalogItemId(), getDisplayName(), getType(), getTags()); } + + /** strings inserted as flags, config keys inserted as config keys; + * if you want to force one or the other, create a ConfigBag and convert to the appropriate map type */ + public abstract SpecT configure(Map<?,?> val); } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/api/src/main/java/org/apache/brooklyn/api/typereg/RegisteredType.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/typereg/RegisteredType.java b/api/src/main/java/org/apache/brooklyn/api/typereg/RegisteredType.java index a1fc5cf..ed84179 100644 --- a/api/src/main/java/org/apache/brooklyn/api/typereg/RegisteredType.java +++ b/api/src/main/java/org/apache/brooklyn/api/typereg/RegisteredType.java @@ -19,11 +19,13 @@ package org.apache.brooklyn.api.typereg; import java.util.Collection; +import java.util.Set; import javax.annotation.Nullable; import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.entity.EntitySpec; +import org.apache.brooklyn.api.objs.BrooklynObject; import org.apache.brooklyn.api.objs.Identifiable; import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry.RegisteredTypeKind; @@ -44,22 +46,24 @@ public interface RegisteredType extends Identifiable { String getDescription(); String getIconUrl(); - /** @return the java type or a supertype thereof that this registered type represents. + /** @return all declared supertypes or super-interfaces of this registered type, + * consisting of a collection of {@link Class} or {@link RegisteredType} * <p> - * For beans, this is the type that the {@link BrooklynTypeRegistry} will create. - * For specs, this is what the spec that will be created points at - * (e.g. the concrete {@link Entity}, not the {@link EntitySpec}); + * This should normally include at least one {@link Class} object: + * For beans, this should include the java type that the {@link BrooklynTypeRegistry} will create. + * For specs, this should refer to the {@link BrooklynObject} type that the created spec will point at + * (e.g. the concrete {@link Entity}, not the {@link EntitySpec}). * <p> - * In some cases this may return an interface or a super-type of what will actually be created, + * This may not necessarily return the most specific java class or classes; * such as if the concrete type is private and callers should know only about a particular public interface, * or if precise type details are unavailable and all that is known at creation is some higher level interface/supertype * (e.g. this may return {@link Entity} even though the spec points at a specific subclass, * for instance because the YAML has not yet been parsed or OSGi bundles downloaded). * <p> - * If nothing is known, this will return null, and the item will not participate in type filtering. + * This may include other registered types such as marker interfaces. */ @Beta - @Nullable Class<?> getJavaType(); + @Nullable Set<Object> getSuperTypes(); /** * @return True if the item has been deprecated (i.e. its use is discouraged) @@ -84,5 +88,5 @@ public interface RegisteredType extends Identifiable { /** data for the implementation; may be more specific */ Object getPlanData(); } - + } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/api/src/main/java/org/apache/brooklyn/api/typereg/RegisteredTypeConstraint.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/typereg/RegisteredTypeConstraint.java b/api/src/main/java/org/apache/brooklyn/api/typereg/RegisteredTypeConstraint.java index 851d88a..8bcff38 100644 --- a/api/src/main/java/org/apache/brooklyn/api/typereg/RegisteredTypeConstraint.java +++ b/api/src/main/java/org/apache/brooklyn/api/typereg/RegisteredTypeConstraint.java @@ -42,4 +42,9 @@ public interface RegisteredTypeConstraint { * if we have already attempted to resolve a given type, * the instantiator can avoid recursive cycles */ @Nonnull public Set<String> getEncounteredTypes(); + + /** A special loader to use, if available. + * For internal use only; implementations should be a BrooklynClassLoadingContext */ + @Nullable public Object getLoader(); + } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java index db4b72a..2955895 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java @@ -69,7 +69,11 @@ public class CatalogUtils { } public static BrooklynClassLoadingContext newClassLoadingContext(ManagementContext mgmt, RegisteredType item) { - return newClassLoadingContext(mgmt, item.getId(), item.getLibraries()); + return newClassLoadingContext(mgmt, item.getId(), item.getLibraries(), null); + } + + public static BrooklynClassLoadingContext newClassLoadingContext(ManagementContext mgmt, RegisteredType item, BrooklynClassLoadingContext loader) { + return newClassLoadingContext(mgmt, item.getId(), item.getLibraries(), loader); } public static BrooklynClassLoadingContext getClassLoadingContext(Entity entity) { @@ -85,16 +89,23 @@ public class CatalogUtils { } public static BrooklynClassLoadingContext newClassLoadingContext(@Nullable ManagementContext mgmt, String catalogItemId, Collection<? extends OsgiBundleWithUrl> libraries) { + return newClassLoadingContext(mgmt, catalogItemId, libraries, null); + } + + public static BrooklynClassLoadingContext newClassLoadingContext(@Nullable ManagementContext mgmt, String catalogItemId, Collection<? extends OsgiBundleWithUrl> libraries, BrooklynClassLoadingContext loader) { BrooklynClassLoadingContextSequential result = new BrooklynClassLoadingContextSequential(mgmt); if (libraries!=null && !libraries.isEmpty()) { result.add(new OsgiBrooklynClassLoadingContext(mgmt, catalogItemId, libraries)); } - BrooklynClassLoadingContext loader = BrooklynLoaderTracker.getLoader(); - if (loader != null) { + if (loader !=null) { result.add(loader); } + BrooklynClassLoadingContext threadLocalLoader = BrooklynLoaderTracker.getLoader(); + if (threadLocalLoader != null) { + result.add(threadLocalLoader); + } result.addSecondary(JavaBrooklynClassLoadingContext.create(mgmt)); return result; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/core/src/main/java/org/apache/brooklyn/core/plan/PlanToSpecFactory.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/plan/PlanToSpecFactory.java b/core/src/main/java/org/apache/brooklyn/core/plan/PlanToSpecFactory.java index 5614b97..7aef313 100644 --- a/core/src/main/java/org/apache/brooklyn/core/plan/PlanToSpecFactory.java +++ b/core/src/main/java/org/apache/brooklyn/core/plan/PlanToSpecFactory.java @@ -111,7 +111,7 @@ public class PlanToSpecFactory { (Strings.isNonBlank(e.getMessage()) ? " ("+e.getMessage()+")" : "")); } catch (Throwable e) { Exceptions.propagateIfFatal(e); - otherProblemsFromTransformers.add(new PropagatedRuntimeException("Transformer for "+t.getShortDescription()+" gave an error creating this plan: "+ + otherProblemsFromTransformers.add(new PropagatedRuntimeException("Transformer for "+t.getShortDescription()+" gave an error creating this plan: ", Exceptions.collapseText(e), e)); } } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/core/src/main/java/org/apache/brooklyn/core/resolve/entity/DelegatingEntitySpecResolver.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/resolve/entity/DelegatingEntitySpecResolver.java b/core/src/main/java/org/apache/brooklyn/core/resolve/entity/DelegatingEntitySpecResolver.java index 2ccc468..415f209 100644 --- a/core/src/main/java/org/apache/brooklyn/core/resolve/entity/DelegatingEntitySpecResolver.java +++ b/core/src/main/java/org/apache/brooklyn/core/resolve/entity/DelegatingEntitySpecResolver.java @@ -105,7 +105,7 @@ public class DelegatingEntitySpecResolver extends AbstractEntitySpecResolver { resolversWhoDontSupport.add(resolver.getName() + " (returned null)"); } } catch (Exception e) { - otherProblemsFromResolvers.add(new PropagatedRuntimeException("Transformer for "+resolver.getName()+" gave an error creating this plan: "+ + otherProblemsFromResolvers.add(new PropagatedRuntimeException("Transformer for "+resolver.getName()+" gave an error creating this plan: ", Exceptions.collapseText(e), e)); } } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/core/src/main/java/org/apache/brooklyn/core/typereg/BasicBrooklynTypeRegistry.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/BasicBrooklynTypeRegistry.java b/core/src/main/java/org/apache/brooklyn/core/typereg/BasicBrooklynTypeRegistry.java index 08b6103..0ca8bc7 100644 --- a/core/src/main/java/org/apache/brooklyn/core/typereg/BasicBrooklynTypeRegistry.java +++ b/core/src/main/java/org/apache/brooklyn/core/typereg/BasicBrooklynTypeRegistry.java @@ -112,7 +112,7 @@ public class BasicBrooklynTypeRegistry implements BrooklynTypeRegistry { // TODO implement using java if permitted } } - constraint = RegisteredTypeConstraints.extendedWithSpecSuperType(constraint, specSuperType); + constraint = RegisteredTypeConstraints.withSpecSuperType(constraint, specSuperType); Maybe<Object> result = TypePlanTransformers.transform(mgmt, type, constraint); if (result.isPresent()) return (SpecT) result.get(); @@ -120,6 +120,10 @@ public class BasicBrooklynTypeRegistry implements BrooklynTypeRegistry { // fallback: look up in (legacy) catalog // TODO remove once all transformers are available in the new style CatalogItem item = (CatalogItem) mgmt.getCatalog().getCatalogItem(type.getSymbolicName(), type.getVersion()); + if (item==null) { + // if not in catalog (because loading new one?) then throw original + result.get(); + } try { return (SpecT) BasicBrooklynCatalog.internalCreateSpecWithTransformers(mgmt, item, constraint.getEncounteredTypes()); } catch (Exception e) { @@ -127,7 +131,7 @@ public class BasicBrooklynTypeRegistry implements BrooklynTypeRegistry { // for now, combine this failure with the original try { result.get(); - // won't come here + // above will throw -- so won't come here throw new IllegalStateException("should have failed getting type resolution for "+type); } catch (Exception e0) { // prefer older exception, until the new transformer is the primary pathway http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/core/src/main/java/org/apache/brooklyn/core/typereg/BasicRegisteredType.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/BasicRegisteredType.java b/core/src/main/java/org/apache/brooklyn/core/typereg/BasicRegisteredType.java index ac0b266..54b04a3 100644 --- a/core/src/main/java/org/apache/brooklyn/core/typereg/BasicRegisteredType.java +++ b/core/src/main/java/org/apache/brooklyn/core/typereg/BasicRegisteredType.java @@ -20,19 +20,27 @@ package org.apache.brooklyn.core.typereg; import java.util.Collection; import java.util.List; +import java.util.Set; import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry.RegisteredTypeKind; import org.apache.brooklyn.api.typereg.OsgiBundleWithUrl; import org.apache.brooklyn.api.typereg.RegisteredType; +import org.apache.brooklyn.util.collections.MutableList; +import org.apache.brooklyn.util.collections.MutableSet; +import org.apache.brooklyn.util.core.config.ConfigBag; import org.apache.brooklyn.util.javalang.JavaClassNames; +import com.google.common.collect.ImmutableSet; + +/** Instances are usually created by methods in {@link RegisteredTypes}. */ public class BasicRegisteredType implements RegisteredType { final String symbolicName; final String version; final RegisteredTypeKind kind; - List<OsgiBundleWithUrl> bundles; + Set<Object> superTypes = MutableSet.of(); + List<OsgiBundleWithUrl> bundles = MutableList.of(); String displayName; String description; String iconUrl; @@ -41,14 +49,12 @@ public class BasicRegisteredType implements RegisteredType { TypeImplementationPlan implementationPlan; - // TODO ensure this is re-populated on rebind? or remove? - transient Class<?> javaType; + private transient ConfigBag cache = new ConfigBag(); - public BasicRegisteredType(RegisteredTypeKind kind, String symbolicName, String version, Class<?> javaType, TypeImplementationPlan implementationPlan) { + BasicRegisteredType(RegisteredTypeKind kind, String symbolicName, String version, TypeImplementationPlan implementationPlan) { this.kind = kind; this.symbolicName = symbolicName; this.version = version; - this.javaType = javaType; this.implementationPlan = implementationPlan; } @@ -74,7 +80,7 @@ public class BasicRegisteredType implements RegisteredType { @Override public Collection<OsgiBundleWithUrl> getLibraries() { - return bundles; + return ImmutableSet.copyOf(bundles); } @Override @@ -103,8 +109,12 @@ public class BasicRegisteredType implements RegisteredType { } @Override - public Class<?> getJavaType() { - return javaType; + public Set<Object> getSuperTypes() { + return ImmutableSet.copyOf(superTypes); + } + + public ConfigBag getCache() { + return cache; } @Override @@ -117,6 +127,7 @@ public class BasicRegisteredType implements RegisteredType { return JavaClassNames.simpleClassName(this)+"["+getId()+ (isDisabled() ? ";DISABLED" : "")+ (isDeprecated() ? ";deprecated" : "")+ + (getPlan()!=null ? ";"+getPlan().getPlanFormat() : "")+ "]"; } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/core/src/main/java/org/apache/brooklyn/core/typereg/JavaClassNameTypePlanTransformer.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/JavaClassNameTypePlanTransformer.java b/core/src/main/java/org/apache/brooklyn/core/typereg/JavaClassNameTypePlanTransformer.java new file mode 100644 index 0000000..a84c9f5 --- /dev/null +++ b/core/src/main/java/org/apache/brooklyn/core/typereg/JavaClassNameTypePlanTransformer.java @@ -0,0 +1,90 @@ +/* + * 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.typereg; + +import java.util.List; + +import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec; +import org.apache.brooklyn.api.objs.BrooklynObject; +import org.apache.brooklyn.api.typereg.RegisteredType; +import org.apache.brooklyn.api.typereg.RegisteredTypeConstraint; +import org.apache.brooklyn.util.text.Identifiers; + +/** + * Instantiates classes from a registered type which simply + * defines the java class name and OSGi bundles to use. + * <p> + * This is used where a {@link RegisteredType} is defined simply with the name of a java class + * e.g. with a no-arg constructor -- no YAML etc just the name of the class. + */ +public class JavaClassNameTypePlanTransformer extends AbstractTypePlanTransformer { + + public static final String FORMAT = "java-type-name"; + + public static class JavaTypeNameImplementation extends AbstractCustomImplementationPlan<String> { + public JavaTypeNameImplementation(String javaType) { super(FORMAT, javaType); } + } + + public JavaClassNameTypePlanTransformer() { + super(FORMAT, "Java type name", "Expects a java type name in a format suitable for use with ClassLoader.loadClass"); + } + + @Override + protected double scoreForNullFormat(Object planData, RegisteredType type, RegisteredTypeConstraint context) { + if (type.getPlan().getPlanData() instanceof String && + ((String)type.getPlan().getPlanData()).matches(Identifiers.JAVA_BINARY_REGEX)) { + return 0.1; + } + return 0; + } + + @Override + protected double scoreForNonmatchingNonnullFormat(String planFormat, Object planData, RegisteredType type, RegisteredTypeConstraint context) { + return 0; + } + + @SuppressWarnings({ "unchecked" }) + @Override + protected AbstractBrooklynObjectSpec<?,?> createSpec(RegisteredType type, RegisteredTypeConstraint context) throws Exception { + return RegisteredTypes.newSpecInstance(mgmt, (Class<? extends BrooklynObject>) getType(type, context)); + } + + @Override + protected Object createBean(RegisteredType type, RegisteredTypeConstraint context) throws Exception { + return getType(type, context).newInstance(); + } + + private Class<?> getType(RegisteredType type, RegisteredTypeConstraint context) throws Exception { + return RegisteredTypes.loadActualJavaType((String)type.getPlan().getPlanData(), mgmt, type, context); + } + + + // not supported as a catalog format (yet? should we?) + + @Override + public double scoreForTypeDefinition(String formatCode, Object catalogData) { + return 0; + } + + @Override + public List<RegisteredType> createFromTypeDefinition(String formatCode, Object catalogData) { + throw new UnsupportedTypePlanException("this transformer does not support YAML catalog additions"); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/core/src/main/java/org/apache/brooklyn/core/typereg/JavaTypePlanTransformer.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/JavaTypePlanTransformer.java b/core/src/main/java/org/apache/brooklyn/core/typereg/JavaTypePlanTransformer.java deleted file mode 100644 index febf52a..0000000 --- a/core/src/main/java/org/apache/brooklyn/core/typereg/JavaTypePlanTransformer.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * 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.typereg; - -import java.util.List; - -import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec; -import org.apache.brooklyn.api.typereg.RegisteredType; -import org.apache.brooklyn.api.typereg.RegisteredTypeConstraint; -import org.apache.brooklyn.core.catalog.internal.CatalogUtils; -import org.apache.brooklyn.util.text.Identifiers; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Instantiates classes from a registered type which simply - * defines the java class name and OSGi bundles to use. - * <p> - * This is used where a {@link RegisteredType} is defined simply with the name of a java class - * e.g. with a no-arg constructor -- no YAML etc just the name of the class. - */ -public class JavaTypePlanTransformer extends AbstractTypePlanTransformer { - - private static final Logger log = LoggerFactory.getLogger(JavaTypePlanTransformer.class); - public static final String FORMAT = "java-type-name"; - - public static class JavaTypeNameImplementation extends AbstractCustomImplementationPlan<String> { - private transient Class<?> cachedType; - public JavaTypeNameImplementation(String javaType) { - super(FORMAT, javaType); - } - public Class<?> getCachedType() { - return cachedType; - } - } - - public JavaTypePlanTransformer() { - super(FORMAT, "Java type name", "Expects a java type name in a format suitable for use with ClassLoader.loadClass"); - } - - @Override - protected double scoreForNullFormat(Object planData, RegisteredType type, RegisteredTypeConstraint context) { - if (type.getPlan().getPlanData() instanceof String && - ((String)type.getPlan().getPlanData()).matches(Identifiers.JAVA_BINARY_REGEX)) { - return 0.1; - } - return 0; - } - - @Override - protected double scoreForNonmatchingNonnullFormat(String planFormat, Object planData, RegisteredType type, RegisteredTypeConstraint context) { - return 0; - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Override - protected AbstractBrooklynObjectSpec<?,?> createSpec(RegisteredType type, RegisteredTypeConstraint context) throws Exception { - Class targetType = getType(type, context); - Class specType = RegisteredTypeConstraints.spec((Class)targetType).getJavaSuperType(); - AbstractBrooklynObjectSpec result = (AbstractBrooklynObjectSpec) specType.getConstructor(Class.class).newInstance(targetType); - return result; - } - - @Override - protected Object createBean(RegisteredType type, RegisteredTypeConstraint context) throws Exception { - return getType(type, context).newInstance(); - } - - private Class<?> getType(RegisteredType type, RegisteredTypeConstraint context) { - if (type.getPlan() instanceof JavaTypeNameImplementation) { - Class<?> cachedType = ((JavaTypeNameImplementation)type.getPlan()).getCachedType(); - if (cachedType==null) { - log.debug("Storing cached type "+cachedType+" for "+type); - cachedType = loadType(type, context); - } - return cachedType; - } - return loadType(type, context); - } - private Class<?> loadType(RegisteredType type, RegisteredTypeConstraint context) { - return CatalogUtils.newClassLoadingContext(mgmt, type).loadClass( ((String)type.getPlan().getPlanData()) ); - } - - - // TODO not supported as a catalog format (yet) - @Override - public double scoreForTypeDefinition(String formatCode, Object catalogData) { - return 0; - } - - @Override - public List<RegisteredType> createFromTypeDefinition(String formatCode, Object catalogData) { - throw new UnsupportedTypePlanException("this transformer does not support YAML catalog additions"); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypeConstraints.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypeConstraints.java b/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypeConstraints.java index c880b7e..5b4c0cf 100644 --- a/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypeConstraints.java +++ b/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypeConstraints.java @@ -31,7 +31,9 @@ import org.apache.brooklyn.api.objs.BrooklynObject; import org.apache.brooklyn.api.objs.BrooklynObjectType; import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry.RegisteredTypeKind; import org.apache.brooklyn.api.typereg.RegisteredTypeConstraint; +import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext; import org.apache.brooklyn.util.collections.MutableSet; +import org.apache.brooklyn.util.javalang.JavaClassNames; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -46,6 +48,7 @@ public class RegisteredTypeConstraints { @Nullable private RegisteredTypeKind kind; @Nullable private Class<?> javaSuperType; @Nonnull private Set<String> encounteredTypes = ImmutableSet.of(); + @Nullable BrooklynClassLoadingContext loader; private BasicRegisteredTypeConstraint() {} @@ -55,6 +58,7 @@ public class RegisteredTypeConstraints { this.kind = source.getKind(); this.javaSuperType = source.getJavaSuperType(); this.encounteredTypes = source.getEncounteredTypes(); + this.loader = (BrooklynClassLoadingContext) source.getLoader(); } @Override @@ -75,8 +79,13 @@ public class RegisteredTypeConstraints { } @Override + public BrooklynClassLoadingContext getLoader() { + return loader; + } + + @Override public String toString() { - return super.toString()+"["+kind+","+javaSuperType+","+encounteredTypes+"]"; + return JavaClassNames.cleanSimpleClassName(this)+"["+kind+","+javaSuperType+","+encounteredTypes+"]"; } } @@ -97,7 +106,11 @@ public class RegisteredTypeConstraints { result.encounteredTypes = encounteredTypes.asUnmodifiable(); return result; } - + + public static RegisteredTypeConstraint alreadyVisited(Set<String> encounteredTypeSymbolicNames, BrooklynClassLoadingContext loader) { + return withLoader(alreadyVisited(encounteredTypeSymbolicNames), loader); + } + private static RegisteredTypeConstraint of(RegisteredTypeKind kind, Class<? extends BrooklynObject> javaSuperType) { BasicRegisteredTypeConstraint result = new BasicRegisteredTypeConstraint(); result.kind = kind; @@ -109,7 +122,7 @@ public class RegisteredTypeConstraints { return of(RegisteredTypeKind.SPEC, javaSuperType); } - public static <T extends AbstractBrooklynObjectSpec<?,?>> RegisteredTypeConstraint extendedWithSpecSuperType(@Nullable RegisteredTypeConstraint source, @Nullable Class<T> specSuperType) { + public static <T extends AbstractBrooklynObjectSpec<?,?>> RegisteredTypeConstraint withSpecSuperType(@Nullable RegisteredTypeConstraint source, @Nullable Class<T> specSuperType) { Class<?> superType = lookupTargetTypeForSpec(specSuperType); BasicRegisteredTypeConstraint constraint = new BasicRegisteredTypeConstraint(source); if (source==null) source = constraint; @@ -131,8 +144,9 @@ public class RegisteredTypeConstraints { return source; } - /** given a spec, returns the class of the item it targets, for instance {@link EntitySpec} for {@link Entity} */ - private static <T extends AbstractBrooklynObjectSpec<?,?>> Class<? extends BrooklynObject> lookupTargetTypeForSpec(Class<T> specSuperType) { + /** given a spec, returns the class of the item it targets, for instance returns {@link Entity} given {@link EntitySpec}; + * see also {@link #lookupSpecTypeForTarget(Class)} */ + static <T extends AbstractBrooklynObjectSpec<?,?>> Class<? extends BrooklynObject> lookupTargetTypeForSpec(Class<T> specSuperType) { if (specSuperType==null) return BrooklynObject.class; BrooklynObjectType best = null; @@ -154,4 +168,39 @@ public class RegisteredTypeConstraints { return best.getInterfaceType(); } + /** given a {@link BrooklynObject}, returns the spec class which would generate it, for instance returns {@link EntitySpec} given {@link Entity}, + * or null if not known */ + static <BO extends BrooklynObject> Class<? extends AbstractBrooklynObjectSpec<?,?>> lookupSpecTypeForTarget(Class<BO> targetSuperType) { + if (targetSuperType==null) return null; + BrooklynObjectType best = null; + + for (BrooklynObjectType t: BrooklynObjectType.values()) { + if (t.getSpecType()==null) continue; + if (!t.getInterfaceType().isAssignableFrom(targetSuperType)) continue; + // on equality, exit immediately + if (t.getInterfaceType().equals(targetSuperType)) return t.getSpecType(); + // else pick which is best + if (best==null) { best = t; continue; } + // if t is more specific, it is better (handles case when e.g. a Policy is a subclass of Entity) + if (best.getSpecType().isAssignableFrom(t.getSpecType())) { best = t; continue; } + } + if (best==null) { + log.warn("Unexpected target supertype ("+targetSuperType+"); unable to infer spec type"); + return null; + } + // the spec is more specific, but we're not familiar with it here; return the best + return best.getSpecType(); + } + + public static RegisteredTypeConstraint loader(BrooklynClassLoadingContext loader) { + BasicRegisteredTypeConstraint result = new BasicRegisteredTypeConstraint(); + result.loader = loader; + return result; + } + + public static RegisteredTypeConstraint withLoader(RegisteredTypeConstraint constraint, BrooklynClassLoadingContext loader) { + ((BasicRegisteredTypeConstraint)constraint).loader = loader; + return constraint; + } + } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypePredicates.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypePredicates.java b/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypePredicates.java index 3560e47..2e7c038 100644 --- a/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypePredicates.java +++ b/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypePredicates.java @@ -109,36 +109,46 @@ public class RegisteredTypePredicates { } } - public static <T> Predicate<RegisteredType> javaType(final Predicate<Class<T>> filter) { - return new JavaTypeMatches(filter); + public static <T> Predicate<RegisteredType> anySuperType(final Predicate<Class<T>> filter) { + return new AnySuperTypeMatches(filter); } @SuppressWarnings({ "unchecked", "rawtypes" }) - public static Predicate<RegisteredType> javaTypeAssignableFrom(final Class<?> filter) { - return javaType((Predicate)Predicates.assignableFrom(filter)); + public static Predicate<RegisteredType> assignableFrom(final Class<?> filter) { + return anySuperType((Predicate)Predicates.assignableFrom(filter)); } - private static class JavaTypeMatches implements Predicate<RegisteredType> { + private static class AnySuperTypeMatches implements Predicate<RegisteredType> { private final Predicate<Class<?>> filter; @SuppressWarnings({ "rawtypes", "unchecked" }) - private <T> JavaTypeMatches(Predicate filter) { + private <T> AnySuperTypeMatches(Predicate filter) { this.filter = filter; } @Override public boolean apply(@Nullable RegisteredType item) { if (item==null) return false; - return (item != null) && filter.apply(item.getJavaType()); + for (Object o: item.getSuperTypes()) { + if (o instanceof Class) { + if (filter.apply((Class<?>)o)) return true; + } + } + for (Object o: item.getSuperTypes()) { + if (o instanceof RegisteredType) { + if (apply((RegisteredType)o)) return true; + } + } + return false; } } - public static final Predicate<RegisteredType> IS_APPLICATION = javaTypeAssignableFrom(Application.class); + public static final Predicate<RegisteredType> IS_APPLICATION = assignableFrom(Application.class); // TODO do we need this? introduced already deprecated in 0.9.0 so can be removed, or enabled @Deprecated public static final Predicate<RegisteredType> IS_TEMPLATE = IS_APPLICATION; - public static final Predicate<RegisteredType> IS_ENTITY = javaTypeAssignableFrom(Entity.class); - public static final Predicate<RegisteredType> IS_LOCATION = javaTypeAssignableFrom(Location.class); - public static final Predicate<RegisteredType> IS_POLICY = javaTypeAssignableFrom(Policy.class); + public static final Predicate<RegisteredType> IS_ENTITY = assignableFrom(Entity.class); + public static final Predicate<RegisteredType> IS_LOCATION = assignableFrom(Location.class); + public static final Predicate<RegisteredType> IS_POLICY = assignableFrom(Policy.class); public static Predicate<RegisteredType> entitledToSee(final ManagementContext mgmt) { return new EntitledToSee(mgmt); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypes.java ---------------------------------------------------------------------- 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 7e35084..0ebbdcd 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 @@ -18,19 +18,50 @@ */ package org.apache.brooklyn.core.typereg; +import java.lang.reflect.Method; +import java.util.Iterator; +import java.util.Map; + +import javax.annotation.Nullable; + import org.apache.brooklyn.api.catalog.CatalogItem; +import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec; +import org.apache.brooklyn.api.mgmt.ManagementContext; +import org.apache.brooklyn.api.objs.BrooklynObject; import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry.RegisteredTypeKind; import org.apache.brooklyn.api.typereg.OsgiBundleWithUrl; import org.apache.brooklyn.api.typereg.RegisteredType; import org.apache.brooklyn.api.typereg.RegisteredType.TypeImplementationPlan; -import org.apache.brooklyn.core.typereg.JavaTypePlanTransformer.JavaTypeNameImplementation; +import org.apache.brooklyn.api.typereg.RegisteredTypeConstraint; +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.typereg.JavaClassNameTypePlanTransformer.JavaTypeNameImplementation; +import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.brooklyn.util.guava.Maybe; +import org.apache.brooklyn.util.yaml.Yamls; import com.google.common.annotations.Beta; import com.google.common.base.Function; +import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; +import com.google.common.reflect.TypeToken; +/** + * Utility and preferred creation mechanisms for working with {@link RegisteredType} instances. + * <p> + * Use {@link #bean(String, String, TypeImplementationPlan, Class)} and {@link #spec(String, String, TypeImplementationPlan, Class)} + * to create {@link RegisteredType} instances. + * <p> + * See {@link #isSubTypeOf(RegisteredType, Class)} or {@link #isSubTypeOf(RegisteredType, RegisteredType)} to + * inspect the type hierarchy. + */ public class RegisteredTypes { + @SuppressWarnings("serial") + static ConfigKey<Class<?>> ACTUAL_JAVA_TYPE = ConfigKeys.newConfigKey(new TypeToken<Class<?>>() {}, "java.type.actual", + "The actual Java type which will be instantiated (bean) or pointed at (spec)"); + /** @deprecated since it was introduced in 0.9.0; for backwards compatibility only, may be removed at any point */ @Deprecated static final Function<CatalogItem<?,?>,RegisteredType> CI_TO_RT = new Function<CatalogItem<?,?>, RegisteredType>() { @@ -53,7 +84,7 @@ public class RegisteredTypes { throw new IllegalStateException("Unsupported catalog item "+item+" when trying to create RegisteredType"); } - BasicRegisteredType type = (BasicRegisteredType) spec(item.getSymbolicName(), item.getVersion(), item.getCatalogItemJavaType(), impl); + BasicRegisteredType type = (BasicRegisteredType) spec(item.getSymbolicName(), item.getVersion(), impl, item.getCatalogItemJavaType()); type.bundles = item.getLibraries()==null ? ImmutableList.<OsgiBundleWithUrl>of() : ImmutableList.<OsgiBundleWithUrl>copyOf(item.getLibraries()); type.displayName = item.getDisplayName(); type.description = item.getDescription(); @@ -66,13 +97,49 @@ public class RegisteredTypes { // maybe: tags ? return type; } - - public static RegisteredType bean(String symbolicName, String version, Class<?> javaType, TypeImplementationPlan plan) { - return new BasicRegisteredType(RegisteredTypeKind.BEAN, symbolicName, version, javaType, plan); + + /** Preferred mechanism for defining a bean {@link RegisteredType} */ + public static RegisteredType bean(String symbolicName, String version, TypeImplementationPlan plan, @Nullable Class<?> superType) { + return addSuperType(new BasicRegisteredType(RegisteredTypeKind.BEAN, symbolicName, version, plan), superType); } - public static RegisteredType spec(String symbolicName, String version, Class<?> javaType, TypeImplementationPlan plan) { - return new BasicRegisteredType(RegisteredTypeKind.SPEC, symbolicName, version, javaType, plan); + public static RegisteredType spec(String symbolicName, String version, TypeImplementationPlan plan, @Nullable Class<?> superType) { + return addSuperType(new BasicRegisteredType(RegisteredTypeKind.SPEC, symbolicName, version, plan), superType); + } + + /** returns the {@link Class} object corresponding to the given java type name, + * using the cache on the type and the loader defined on the type + * @param mgmt */ + @Beta + // TODO should this be on the AbstractTypePlanTransformer ? + public static Class<?> loadActualJavaType(String javaTypeName, ManagementContext mgmt, RegisteredType type, RegisteredTypeConstraint constraint) throws Exception { + Class<?> result = ((BasicRegisteredType)type).getCache().get(ACTUAL_JAVA_TYPE); + if (result!=null) return result; + + result = CatalogUtils.newClassLoadingContext(mgmt, type).loadClass( javaTypeName ); + Preconditions.checkNotNull(result, "Could not load class "+javaTypeName+"; returned null (should have thrown a different exception!)"); + + ((BasicRegisteredType)type).getCache().put(ACTUAL_JAVA_TYPE, result); + return result; + } + + @Beta + public static RegisteredType addSuperType(RegisteredType type, @Nullable Class<?> superType) { + if (superType!=null) { + ((BasicRegisteredType)type).superTypes.add(superType); + } + return type; + } + + @Beta + public static RegisteredType addSuperType(RegisteredType type, @Nullable RegisteredType superType) { + if (superType!=null) { + if (isSubTypeOf(superType, type)) { + throw new IllegalStateException(superType+" declares "+type+" as a supertype; cannot set "+superType+" as a supertype of "+type); + } + ((BasicRegisteredType)type).superTypes.add(superType); + } + return type; } /** returns the implementation data for a spec if it is a string (e.g. plan yaml or java class name); else false */ @@ -84,4 +151,66 @@ public class RegisteredTypes { return (String)data; } + /** returns an implementation of the spec class corresponding to the given target type; + * for use in {@link BrooklynTypePlanTransformer#create(RegisteredType, RegisteredTypeConstraint)} + * implementations when dealing with a spec; returns null if none found + * @param mgmt */ + @Beta + public static AbstractBrooklynObjectSpec<?,?> newSpecInstance(ManagementContext mgmt, Class<? extends BrooklynObject> targetType) throws Exception { + Class<? extends AbstractBrooklynObjectSpec<?, ?>> specType = RegisteredTypeConstraints.lookupSpecTypeForTarget(targetType); + if (specType==null) return null; + Method createMethod = specType.getMethod("create", Class.class); + return (AbstractBrooklynObjectSpec<?, ?>) createMethod.invoke(null, targetType); + } + + /** Returns a wrapped map, if the object is YAML which parses as a map; + * otherwise returns absent capable of throwing an error with more details */ + @SuppressWarnings("unchecked") + public static Maybe<Map<Object,Object>> getAsYamlMap(Object planData) { + if (!(planData instanceof String)) return Maybe.absent("not a string"); + Iterable<Object> result; + try { + result = Yamls.parseAll((String)planData); + } catch (Exception e) { + Exceptions.propagateIfFatal(e); + return Maybe.absent(e); + } + Iterator<Object> ri = result.iterator(); + if (!ri.hasNext()) return Maybe.absent("YAML has no elements in it"); + Object r1 = ri.next(); + if (!ri.hasNext()) return Maybe.absent("YAML has multiple elements in it"); + if (r1 instanceof Map) return Maybe.of((Map<Object,Object>)r1); + return Maybe.absent("YAML does not contain a map"); + } + + /** + * Queries recursively the supertypes of {@link RegisteredType} to see whether it + * declares a supertype compatible with the given {@link Class} */ + public static boolean isSubTypeOf(RegisteredType type, Class<?> superType) { + for (Object st: type.getSuperTypes()) { + if (st instanceof Class) { + if (superType.isAssignableFrom((Class<?>)st)) return true; + } + } + for (Object st: type.getSuperTypes()) { + if (st instanceof RegisteredType) { + if (isSubTypeOf((RegisteredType)st, superType)) return true; + } + } + return false; + } + + /** + * Queries recursively the supertypes of {@link RegisteredType} to see whether it + * declares a supertype compatible with the given {@link Class} */ + public static boolean isSubTypeOf(RegisteredType type, RegisteredType superType) { + if (type.equals(superType)) return true; + for (Object st: type.getSuperTypes()) { + if (st instanceof RegisteredType) { + if (isSubTypeOf((RegisteredType)st, superType)) return true; + } + } + return false; + } + } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/core/src/main/resources/META-INF/services/org.apache.brooklyn.core.typereg.BrooklynTypePlanTransformer ---------------------------------------------------------------------- diff --git a/core/src/main/resources/META-INF/services/org.apache.brooklyn.core.typereg.BrooklynTypePlanTransformer b/core/src/main/resources/META-INF/services/org.apache.brooklyn.core.typereg.BrooklynTypePlanTransformer new file mode 100644 index 0000000..48c4a9d --- /dev/null +++ b/core/src/main/resources/META-INF/services/org.apache.brooklyn.core.typereg.BrooklynTypePlanTransformer @@ -0,0 +1,19 @@ +# +# 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. +# +org.apache.brooklyn.core.typereg.JavaClassNameTypePlanTransformer http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/core/src/test/java/org/apache/brooklyn/core/sensor/StaticSensorTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/core/sensor/StaticSensorTest.java b/core/src/test/java/org/apache/brooklyn/core/sensor/StaticSensorTest.java index 1e6efb1..a574aeb 100644 --- a/core/src/test/java/org/apache/brooklyn/core/sensor/StaticSensorTest.java +++ b/core/src/test/java/org/apache/brooklyn/core/sensor/StaticSensorTest.java @@ -19,11 +19,9 @@ package org.apache.brooklyn.core.sensor; import org.apache.brooklyn.api.entity.EntitySpec; -import org.apache.brooklyn.core.sensor.Sensors; -import org.apache.brooklyn.core.sensor.StaticSensor; +import org.apache.brooklyn.core.entity.EntityAsserts; import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport; import org.apache.brooklyn.entity.stock.BasicEntity; -import org.apache.brooklyn.test.EntityTestUtils; import org.apache.brooklyn.util.core.config.ConfigBag; import org.testng.annotations.Test; @@ -39,7 +37,7 @@ public class StaticSensorTest extends BrooklynAppUnitTestSupport { StaticSensor.SENSOR_TYPE, String.class.getName(), StaticSensor.STATIC_VALUE, "myval"))))); - EntityTestUtils.assertAttributeEquals(entity, Sensors.newSensor(String.class, "myname"), "myval"); + EntityAsserts.assertAttributeEquals(entity, Sensors.newSensor(String.class, "myname"), "myval"); } @Test @@ -50,6 +48,6 @@ public class StaticSensorTest extends BrooklynAppUnitTestSupport { StaticSensor.SENSOR_TYPE, Integer.class.getName(), StaticSensor.STATIC_VALUE, "1"))))); - EntityTestUtils.assertAttributeEquals(entity, Sensors.newSensor(Integer.class, "myname"), 1); + EntityAsserts.assertAttributeEquals(entity, Sensors.newSensor(Integer.class, "myname"), 1); } } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/core/src/test/java/org/apache/brooklyn/core/test/entity/TestEntityImpl.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/core/test/entity/TestEntityImpl.java b/core/src/test/java/org/apache/brooklyn/core/test/entity/TestEntityImpl.java index 6c3b913..77d4672 100644 --- a/core/src/test/java/org/apache/brooklyn/core/test/entity/TestEntityImpl.java +++ b/core/src/test/java/org/apache/brooklyn/core/test/entity/TestEntityImpl.java @@ -157,7 +157,6 @@ public class TestEntityImpl extends AbstractEntity implements TestEntity { public <T extends Entity> T createAndManageChild(EntitySpec<T> spec) { if (!getManagementSupport().isDeployed()) throw new IllegalStateException("Entity "+this+" not managed"); T child = createChild(spec); - getEntityManager().manage(child); return child; } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/core/src/test/java/org/apache/brooklyn/core/typereg/JavaTypePlanTransformerTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/core/typereg/JavaTypePlanTransformerTest.java b/core/src/test/java/org/apache/brooklyn/core/typereg/JavaTypePlanTransformerTest.java index c4d8038..def79d8 100644 --- a/core/src/test/java/org/apache/brooklyn/core/typereg/JavaTypePlanTransformerTest.java +++ b/core/src/test/java/org/apache/brooklyn/core/typereg/JavaTypePlanTransformerTest.java @@ -37,16 +37,16 @@ public class JavaTypePlanTransformerTest extends BrooklynMgmtUnitTestSupport { @Override public void setUp() throws Exception { super.setUp(); - type = newNoArgRegisteredType(JavaTypePlanTransformer.FORMAT); + type = newNoArgRegisteredType(JavaClassNameTypePlanTransformer.FORMAT); transformer = newTransformer(); } protected RegisteredType newNoArgRegisteredType(String format) { - return RegisteredTypes.bean("no-arg", "1.0", null, new BasicTypeImplementationPlan(format, NoArg.class.getName())); + return RegisteredTypes.bean("no-arg", "1.0", new BasicTypeImplementationPlan(format, NoArg.class.getName()), null); } protected BrooklynTypePlanTransformer newTransformer() { - BrooklynTypePlanTransformer xf = new JavaTypePlanTransformer(); + BrooklynTypePlanTransformer xf = new JavaClassNameTypePlanTransformer(); xf.injectManagementContext(mgmt); return xf; } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/api/AssemblyTemplateSpecInstantiator.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/api/AssemblyTemplateSpecInstantiator.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/api/AssemblyTemplateSpecInstantiator.java index 1dfc351..8fb7164 100644 --- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/api/AssemblyTemplateSpecInstantiator.java +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/api/AssemblyTemplateSpecInstantiator.java @@ -30,12 +30,16 @@ import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext; public interface AssemblyTemplateSpecInstantiator extends AssemblyTemplateInstantiator { + @Deprecated /** @deprecaed since 0.9.0 include encountered types */ + EntitySpec<? extends Application> createApplicationSpec(AssemblyTemplate template, CampPlatform platform, BrooklynClassLoadingContext loader); + /** * Gets the single item returned by {@link #createServiceSpecs} * and wraps it in an Application if needed, applying top-level * attributes and locations to the root entity. */ - EntitySpec<? extends Application> createApplicationSpec(AssemblyTemplate template, CampPlatform platform, BrooklynClassLoadingContext loader); + EntitySpec<? extends Application> createApplicationSpec(AssemblyTemplate template, CampPlatform platform, BrooklynClassLoadingContext loader, Set<String> encounteredCatalogTypes); + /** Returns specs for each item in the services list */ List<EntitySpec<?>> createServiceSpecs(AssemblyTemplate template, CampPlatform platform, BrooklynClassLoadingContext itemLoader, Set<String> encounteredCatalogTypes); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java index a400758..5070777 100644 --- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java @@ -35,12 +35,12 @@ import org.apache.brooklyn.core.mgmt.EntityManagementUtils.CreationResult; import org.apache.brooklyn.core.mgmt.HasBrooklynManagementContext; import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext; import org.apache.brooklyn.core.mgmt.classloading.JavaBrooklynClassLoadingContext; +import org.apache.brooklyn.util.collections.MutableSet; import org.apache.brooklyn.util.core.flags.TypeCoercions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; public class BrooklynAssemblyTemplateInstantiator implements AssemblyTemplateSpecInstantiator { @@ -59,7 +59,7 @@ public class BrooklynAssemblyTemplateInstantiator implements AssemblyTemplateSpe private Application create(AssemblyTemplate template, CampPlatform platform) { ManagementContext mgmt = getManagementContext(platform); BrooklynClassLoadingContext loader = JavaBrooklynClassLoadingContext.create(mgmt); - EntitySpec<? extends Application> spec = createApplicationSpec(template, platform, loader); + EntitySpec<? extends Application> spec = createApplicationSpec(template, platform, loader, MutableSet.<String>of()); Application instance = mgmt.getEntityManager().createEntity(spec); log.info("CAMP created '{}'", instance); return instance; @@ -78,15 +78,24 @@ public class BrooklynAssemblyTemplateInstantiator implements AssemblyTemplateSpe AssemblyTemplate template, CampPlatform platform, BrooklynClassLoadingContext loader) { + return createApplicationSpec(template, platform, loader, MutableSet.<String>of()); + } + + @Override + public EntitySpec<? extends Application> createApplicationSpec( + AssemblyTemplate template, + CampPlatform platform, + BrooklynClassLoadingContext loader, + Set<String> encounteredTypeSymbolicNames) { log.debug("CAMP creating application instance for {} ({})", template.getId(), template); // AssemblyTemplates created via PDP, _specifying_ then entities to put in - EntitySpec<? extends Application> app = CampUtils.createWrapperApp(template, loader); + EntitySpec<? extends Application> app = CampInternalUtils.createWrapperApp(template, loader); app.configure(EntityManagementUtils.WRAPPER_APP_MARKER, Boolean.TRUE); // first build the children into an empty shell app - List<EntitySpec<?>> childSpecs = createServiceSpecs(template, platform, loader, Sets.<String>newLinkedHashSet()); + List<EntitySpec<?>> childSpecs = createServiceSpecs(template, platform, loader, encounteredTypeSymbolicNames); for (EntitySpec<?> childSpec : childSpecs) { app.child(childSpec); } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampCatalogUtils.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampCatalogUtils.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampCatalogUtils.java index d4c5142..32f7c0e 100644 --- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampCatalogUtils.java +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampCatalogUtils.java @@ -24,61 +24,17 @@ import org.apache.brooklyn.api.catalog.CatalogItem; import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec; import org.apache.brooklyn.api.mgmt.ManagementContext; import org.apache.brooklyn.camp.CampPlatform; -import org.apache.brooklyn.core.catalog.internal.CatalogUtils; -import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext; -import org.apache.brooklyn.util.text.Strings; - -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableSet; +import org.apache.brooklyn.core.typereg.RegisteredTypes; +@Deprecated /** @deprecated since 0.9.0 use RegisteredType and CampResolver */ public class CampCatalogUtils { public static AbstractBrooklynObjectSpec<?, ?> createSpec(ManagementContext mgmt, CatalogItem<?, ?> item, Set<String> parentEncounteredTypes) { - // preferred way is to parse the yaml, to resolve references late; - // the parsing on load is to populate some fields, but it is optional. - // TODO messy for location and policy that we need brooklyn.{locations,policies} root of the yaml, but it works; - // see related comment when the yaml is set, in addAbstractCatalogItems - // (not sure if anywhere else relies on that syntax; if not, it should be easy to fix!) - BrooklynClassLoadingContext loader = CatalogUtils.newClassLoadingContext(mgmt, item); - Preconditions.checkNotNull(item.getCatalogItemType(), "catalog item type for "+item.getPlanYaml()); - - Set<String> encounteredTypes; - // symbolicName could be null if coming from the catalog parser where it tries to load before knowing the id - if (item.getSymbolicName() != null) { - encounteredTypes = ImmutableSet.<String>builder() - .addAll(parentEncounteredTypes) - .add(item.getSymbolicName()) - .build(); - } else { - encounteredTypes = parentEncounteredTypes; - } - - AbstractBrooklynObjectSpec<?, ?> spec; - switch (item.getCatalogItemType()) { - case TEMPLATE: - case ENTITY: - spec = CampUtils.createRootServiceSpec(item.getPlanYaml(), loader, encounteredTypes); - break; - case LOCATION: - spec = CampUtils.createLocationSpec(item.getPlanYaml(), loader, encounteredTypes); - break; - case POLICY: - spec = CampUtils.createPolicySpec(item.getPlanYaml(), loader, encounteredTypes); - break; - default: - throw new IllegalStateException("Unknown CI Type "+item.getCatalogItemType()+" for "+item.getPlanYaml()); - } - - ((AbstractBrooklynObjectSpec<?, ?>)spec).catalogItemId(item.getId()); - - if (Strings.isBlank( ((AbstractBrooklynObjectSpec<?, ?>)spec).getDisplayName() )) - ((AbstractBrooklynObjectSpec<?, ?>)spec).displayName(item.getDisplayName()); - - return spec; + return CampResolver.createSpecFromFull(mgmt, RegisteredTypes.of(item), parentEncounteredTypes, null); } - + public static CampPlatform getCampPlatform(ManagementContext mgmt) { - return CampUtils.getCampPlatform(mgmt); + return CampInternalUtils.getCampPlatform(mgmt); } } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampInternalUtils.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampInternalUtils.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampInternalUtils.java new file mode 100644 index 0000000..abd32c6 --- /dev/null +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampInternalUtils.java @@ -0,0 +1,247 @@ +/* + * 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.camp.brooklyn.spi.creation; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.io.StringReader; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.apache.brooklyn.api.entity.Application; +import org.apache.brooklyn.api.entity.EntitySpec; +import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec; +import org.apache.brooklyn.api.location.Location; +import org.apache.brooklyn.api.location.LocationSpec; +import org.apache.brooklyn.api.mgmt.ManagementContext; +import org.apache.brooklyn.api.objs.SpecParameter; +import org.apache.brooklyn.api.policy.Policy; +import org.apache.brooklyn.api.policy.PolicySpec; +import org.apache.brooklyn.api.typereg.RegisteredType; +import org.apache.brooklyn.camp.CampPlatform; +import org.apache.brooklyn.camp.brooklyn.BrooklynCampConstants; +import org.apache.brooklyn.camp.brooklyn.BrooklynCampReservedKeys; +import org.apache.brooklyn.camp.spi.AssemblyTemplate; +import org.apache.brooklyn.camp.spi.AssemblyTemplate.Builder; +import org.apache.brooklyn.camp.spi.instantiate.AssemblyTemplateInstantiator; +import org.apache.brooklyn.camp.spi.pdp.DeploymentPlan; +import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog; +import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog.BrooklynLoaderTracker; +import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext; +import org.apache.brooklyn.core.objs.BasicSpecParameter; +import org.apache.brooklyn.core.objs.BrooklynObjectInternal.ConfigurationSupportInternal; +import org.apache.brooklyn.entity.stock.BasicApplicationImpl; +import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.brooklyn.util.guava.Maybe; +import org.apache.brooklyn.util.stream.Streams; +import org.apache.brooklyn.util.yaml.Yamls; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; + +/** package-private; as {@link RegisteredType} becomes standard hopefully we can remove this */ +class CampInternalUtils { + + static EntitySpec<? extends Application> createWrapperApp(AssemblyTemplate template, BrooklynClassLoadingContext loader) { + BrooklynComponentTemplateResolver resolver = BrooklynComponentTemplateResolver.Factory.newInstance( + loader, buildWrapperAppTemplate(template)); + EntitySpec<Application> wrapperSpec = resolver.resolveSpec(ImmutableSet.<String>of()); + resetSpecIfTemplateHasNoExplicitParameters(template, wrapperSpec); + // caller always sets WRAPPER_APP config; should we do it here? + return wrapperSpec; + } + + static void resetSpecIfTemplateHasNoExplicitParameters(AssemblyTemplate template, EntitySpec<? extends Application> wrapperSpec) { + if (!template.getCustomAttributes().containsKey(BrooklynCampReservedKeys.BROOKLYN_PARAMETERS)) { + // Clear out default parameters (coming from the wrapper app's class) so they don't overwrite the entity's params on unwrap. + wrapperSpec.parameters(ImmutableList.<SpecParameter<?>>of()); + } + } + + private static AssemblyTemplate buildWrapperAppTemplate(AssemblyTemplate template) { + Builder<? extends AssemblyTemplate> builder = AssemblyTemplate.builder(); + builder.type("brooklyn:" + BasicApplicationImpl.class.getName()); + builder.id(template.getId()); + builder.name(template.getName()); + builder.sourceCode(template.getSourceCode()); + for (Entry<String, Object> entry : template.getCustomAttributes().entrySet()) { + builder.customAttribute(entry.getKey(), entry.getValue()); + } + builder.instantiator(template.getInstantiator()); + AssemblyTemplate wrapTemplate = builder.build(); + return wrapTemplate; + } + + static AssemblyTemplateInstantiator getInstantiator(AssemblyTemplate at) { + try { + return at.getInstantiator().newInstance(); + } catch (Exception e) { + throw Exceptions.propagate(e); + } + } + + static AssemblyTemplate registerDeploymentPlan(String plan, BrooklynClassLoadingContext loader, CampPlatform camp) { + BrooklynLoaderTracker.setLoader(loader); + try { + return camp.pdp().registerDeploymentPlan(new StringReader(plan)); + } finally { + BrooklynLoaderTracker.unsetLoader(loader); + } + } + + static PolicySpec<?> createPolicySpec(String yamlPlan, BrooklynClassLoadingContext loader, Set<String> encounteredCatalogTypes) { + DeploymentPlan plan = makePlanFromYaml(loader.getManagementContext(), yamlPlan); + + //Would ideally re-use the PolicySpecResolver + //but it is CAMP specific and there is no easy way to get hold of it. + Object policies = checkNotNull(plan.getCustomAttributes().get(BasicBrooklynCatalog.POLICIES_KEY), "policy config"); + if (!(policies instanceof Iterable<?>)) { + throw new IllegalStateException("The value of " + BasicBrooklynCatalog.POLICIES_KEY + " must be an Iterable."); + } + + Object policy = Iterables.getOnlyElement((Iterable<?>)policies); + + return createPolicySpec(loader, policy, encounteredCatalogTypes); + } + + @SuppressWarnings("unchecked") + static PolicySpec<?> createPolicySpec(BrooklynClassLoadingContext loader, Object policy, Set<String> encounteredCatalogTypes) { + Map<String, Object> itemMap; + if (policy instanceof String) { + itemMap = ImmutableMap.<String, Object>of("type", policy); + } else if (policy instanceof Map) { + itemMap = (Map<String, Object>) policy; + } else { + throw new IllegalStateException("Policy expected to be string or map. Unsupported object type " + policy.getClass().getName() + " (" + policy.toString() + ")"); + } + + String versionedId = (String) checkNotNull(Yamls.getMultinameAttribute(itemMap, "policy_type", "policyType", "type"), "policy type"); + PolicySpec<? extends Policy> spec = resolvePolicySpec(versionedId, loader, encounteredCatalogTypes); + Map<String, Object> brooklynConfig = (Map<String, Object>) itemMap.get(BrooklynCampReservedKeys.BROOKLYN_CONFIG); + if (brooklynConfig != null) { + spec.configure(brooklynConfig); + } + List<?> parameters = (List<?>) itemMap.get(BrooklynCampReservedKeys.BROOKLYN_PARAMETERS); + initParameters(parameters, spec, loader); + return spec; + } + + static LocationSpec<?> createLocationSpec(String yamlPlan, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) { + DeploymentPlan plan = makePlanFromYaml(loader.getManagementContext(), yamlPlan); + Object locations = checkNotNull(plan.getCustomAttributes().get(BasicBrooklynCatalog.LOCATIONS_KEY), "location config"); + if (!(locations instanceof Iterable<?>)) { + throw new IllegalStateException("The value of " + BasicBrooklynCatalog.LOCATIONS_KEY + " must be an Iterable."); + } + + Object location = Iterables.getOnlyElement((Iterable<?>)locations); + return createLocationSpec(loader, location); + } + + @SuppressWarnings("unchecked") + private static LocationSpec<?> createLocationSpec(BrooklynClassLoadingContext loader, Object location) { + Map<String, Object> itemMap; + if (location instanceof String) { + itemMap = ImmutableMap.<String, Object>of("type", location); + } else if (location instanceof Map) { + itemMap = (Map<String, Object>) location; + } else { + throw new IllegalStateException("Location expected to be string or map. Unsupported object type " + location.getClass().getName() + " (" + location.toString() + ")"); + } + + String type = (String) checkNotNull(Yamls.getMultinameAttribute(itemMap, "location_type", "locationType", "type"), "location type"); + Map<String, Object> brooklynConfig = (Map<String, Object>) itemMap.get("brooklyn.config"); + LocationSpec<?> locationSpec = resolveLocationSpec(type, brooklynConfig, loader); + List<?> explicitParams = (List<?>) itemMap.get(BrooklynCampReservedKeys.BROOKLYN_PARAMETERS); + initParameters(explicitParams, locationSpec, loader); + return locationSpec; + } + + private static void initParameters(List<?> explicitParams, AbstractBrooklynObjectSpec<?, ?> spec, BrooklynClassLoadingContext loader) { + if (explicitParams != null) { + spec.parameters(BasicSpecParameter.fromConfigList(explicitParams, loader)); + } else { + spec.parameters(BasicSpecParameter.fromSpec(loader.getManagementContext(), spec)); + } + } + + public static DeploymentPlan makePlanFromYaml(ManagementContext mgmt, String yaml) { + CampPlatform camp = getCampPlatform(mgmt); + return camp.pdp().parseDeploymentPlan(Streams.newReaderWithContents(yaml)); + } + + public static CampPlatform getCampPlatform(ManagementContext mgmt) { + CampPlatform result = mgmt.getConfig().getConfig(BrooklynCampConstants.CAMP_PLATFORM); + if (result!=null) { + return result; + } else { + throw new IllegalStateException("No CAMP Platform is registered with this Brooklyn management context."); + } + } + + @SuppressWarnings("unchecked") + private static PolicySpec<? extends Policy> resolvePolicySpec( + String versionedId, + BrooklynClassLoadingContext loader, + Set<String> encounteredCatalogTypes) { + + PolicySpec<? extends Policy> spec; + RegisteredType item = loader.getManagementContext().getTypeRegistry().get(versionedId); + if (item != null && !encounteredCatalogTypes.contains(item.getSymbolicName())) { + return loader.getManagementContext().getTypeRegistry().createSpec(item, null, PolicySpec.class); + } else { + // TODO-type-registry pass the loader in to the above, and allow it to load with the loader + spec = PolicySpec.create(loader.loadClass(versionedId, Policy.class)); + } + return spec; + } + + private static LocationSpec<?> resolveLocationSpec( + String type, + Map<String, Object> brooklynConfig, + BrooklynClassLoadingContext loader) { + Maybe<Class<? extends Location>> javaClass = loader.tryLoadClass(type, Location.class); + if (javaClass.isPresent()) { + LocationSpec<?> spec = LocationSpec.create(javaClass.get()); + if (brooklynConfig != null) { + spec.configure(brooklynConfig); + } + return spec; + } else { + Maybe<Location> loc = loader.getManagementContext().getLocationRegistry().resolve(type, false, brooklynConfig); + if (loc.isPresent()) { + // TODO extensions? + Map<String, Object> locConfig = ((ConfigurationSupportInternal)loc.get().config()).getBag().getAllConfig(); + Class<? extends Location> locType = loc.get().getClass(); + Set<Object> locTags = loc.get().tags().getTags(); + String locDisplayName = loc.get().getDisplayName(); + return LocationSpec.create(locType) + .configure(locConfig) + .displayName(locDisplayName) + .tags(locTags); + } else { + throw new IllegalStateException("No class or resolver found for location type "+type); + } + } + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/904c45e9/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java new file mode 100644 index 0000000..1fc6eaf --- /dev/null +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java @@ -0,0 +1,142 @@ +/* + * 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.camp.brooklyn.spi.creation; + +import java.util.Set; + +import org.apache.brooklyn.api.entity.Application; +import org.apache.brooklyn.api.entity.Entity; +import org.apache.brooklyn.api.entity.EntitySpec; +import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec; +import org.apache.brooklyn.api.location.Location; +import org.apache.brooklyn.api.mgmt.ManagementContext; +import org.apache.brooklyn.api.policy.Policy; +import org.apache.brooklyn.api.typereg.RegisteredType; +import org.apache.brooklyn.api.typereg.RegisteredTypeConstraint; +import org.apache.brooklyn.camp.CampPlatform; +import org.apache.brooklyn.camp.brooklyn.api.AssemblyTemplateSpecInstantiator; +import org.apache.brooklyn.camp.spi.AssemblyTemplate; +import org.apache.brooklyn.camp.spi.instantiate.AssemblyTemplateInstantiator; +import org.apache.brooklyn.core.catalog.internal.CatalogUtils; +import org.apache.brooklyn.core.mgmt.EntityManagementUtils; +import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext; +import org.apache.brooklyn.core.typereg.RegisteredTypes; +import org.apache.brooklyn.util.text.Strings; + +import com.google.common.collect.ImmutableSet; + +class CampResolver { + + private ManagementContext mgmt; + private RegisteredType type; + private RegisteredTypeConstraint context; + + /** whether to allow parsing of the 'full' syntax for applications, + * where items are wrapped in a "services:" block, and if the wrapper is an application, + * to promote it */ + boolean allowApplicationFullSyntax = true; + + /** whether to allow parsing of the legacy 'full' syntax, + * where a non-application items are wrapped: + * <li> in a "services:" block for entities, + * <li> in a "brooklyn.locations" or "brooklyn.policies" block for locations and policies */ + boolean allowLegacyFullSyntax = true; + + /** whether to allow parsing of the type syntax, where an item is a map with a "type:" field, + * i.e. not wrapped in any "services:" or "brooklyn.{locations,policies}" block */ + boolean allowTypeSyntax = true; + + public CampResolver(ManagementContext mgmt, RegisteredType type, RegisteredTypeConstraint context) { + this.mgmt = mgmt; + this.type = type; + this.context = context; + } + + public AbstractBrooklynObjectSpec<?, ?> createSpec() { + // TODO modern approach + // AbstractBrooklynObjectSpec<?, ?> spec = RegisteredTypes.newSpecInstance(mgmt, /* 'type' key */); + // spec.configure(keysAndValues); + return createSpecFromFull(mgmt, type, + context.getEncounteredTypes(), (BrooklynClassLoadingContext) context.getLoader()); + } + + static AbstractBrooklynObjectSpec<?, ?> createSpecFromFull(ManagementContext mgmt, RegisteredType item, Set<String> parentEncounteredTypes, BrooklynClassLoadingContext loaderO) { + // for this method, a prefix "services" or "brooklyn.{location,policies}" is required at the root; + // we now prefer items to come in "{ type: .. }" format, except for application roots which + // should have a "services: [ ... ]" block (and which may subsequently be unwrapped) + BrooklynClassLoadingContext loader = CatalogUtils.newClassLoadingContext(mgmt, item, loaderO); + + Set<String> encounteredTypes; + // symbolicName could be null if coming from the catalog parser where it tries to load before knowing the id + if (item.getSymbolicName() != null) { + encounteredTypes = ImmutableSet.<String>builder() + .addAll(parentEncounteredTypes) + .add(item.getSymbolicName()) + .build(); + } else { + encounteredTypes = parentEncounteredTypes; + } + + AbstractBrooklynObjectSpec<?, ?> spec; + String planYaml = RegisteredTypes.getImplementationDataStringForSpec(item); + if (RegisteredTypes.isSubTypeOf(item, Policy.class)) { + spec = CampInternalUtils.createPolicySpec(planYaml, loader, encounteredTypes); + } else if (RegisteredTypes.isSubTypeOf(item, Location.class)) { + spec = CampInternalUtils.createLocationSpec(planYaml, loader, encounteredTypes); + } else if (RegisteredTypes.isSubTypeOf(item, Application.class)) { + spec = createEntitySpecFromServicesBlock(planYaml, loader, encounteredTypes, true); + } else if (RegisteredTypes.isSubTypeOf(item, Entity.class)) { + spec = createEntitySpecFromServicesBlock(planYaml, loader, encounteredTypes, false); + } else { + // try any of them??? + + throw new IllegalStateException("Cannot detect spec type from "+item.getSuperTypes()+" for "+item+"\n"+planYaml); + } + + ((AbstractBrooklynObjectSpec<?, ?>)spec).catalogItemId(item.getId()); + + if (Strings.isBlank( ((AbstractBrooklynObjectSpec<?, ?>)spec).getDisplayName() )) + ((AbstractBrooklynObjectSpec<?, ?>)spec).displayName(item.getDisplayName()); + + return spec; + } + + private static EntitySpec<?> createEntitySpecFromServicesBlock(String plan, BrooklynClassLoadingContext loader, Set<String> encounteredTypes, boolean isApplication) { + CampPlatform camp = CampInternalUtils.getCampPlatform(loader.getManagementContext()); + + AssemblyTemplate at = CampInternalUtils.registerDeploymentPlan(plan, loader, camp); + AssemblyTemplateInstantiator instantiator = CampInternalUtils.getInstantiator(at); + if (instantiator instanceof AssemblyTemplateSpecInstantiator) { + EntitySpec<? extends Application> appSpec = ((AssemblyTemplateSpecInstantiator)instantiator).createApplicationSpec(at, camp, loader, encounteredTypes); + CampInternalUtils.resetSpecIfTemplateHasNoExplicitParameters(at, appSpec); + + if (!isApplication && EntityManagementUtils.canPromoteChildrenInWrappedApplication(appSpec) && appSpec.getChildren().size()==1) { + EntitySpec<?> childSpec = appSpec.getChildren().get(0); + EntityManagementUtils.mergeWrapperParentSpecToChildEntity(appSpec, childSpec); + return childSpec; + } + return appSpec; + + } else { + throw new IllegalStateException("Unable to instantiate YAML; incompatible instantiator "+instantiator+" for "+at); + } + + } + +} \ No newline at end of file
