Split BrooklynComponentTemplateResolver into independent ServiceSpecResolver
ServiceSpecResolver is not specific to CAMP, it deals with converting a type (i.e. a catalog item, a java class, chef declaration) to a spec. BrooklynComponentTemplateResolver then takes the spec and applies the CAMP config on it. Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/4485fe5c Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/4485fe5c Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/4485fe5c Branch: refs/heads/master Commit: 4485fe5c212ee5fddf4e6452c9fb17b77429b5b5 Parents: c71d722 Author: Svetoslav Neykov <[email protected]> Authored: Wed Oct 14 15:02:26 2015 +0300 Committer: Svetoslav Neykov <[email protected]> Committed: Wed Oct 14 17:11:07 2015 +0300 ---------------------------------------------------------------------- .../internal/JavaCatalogToSpecTransformer.java | 13 +- .../core/mgmt/EntityManagementUtils.java | 4 +- .../brooklyn/core/plan/PlanToSpecFactory.java | 2 +- .../BrooklynAssemblyTemplateInstantiator.java | 12 +- .../BrooklynComponentTemplateResolver.java | 264 ++++--------------- .../spi/creation/CampToSpecTransformer.java | 17 +- .../service/AbstractServiceSpecResolver.java | 65 +++++ .../service/BrooklynServiceTypeResolver.java | 80 ------ .../service/CatalogServiceSpecResolver.java | 110 ++++++++ .../service/CatalogServiceTypeResolver.java | 77 ------ .../service/ChefServiceSpecResolver.java | 41 +++ .../service/ChefServiceTypeResolver.java | 61 ----- .../service/DefaultServiceTypeResolver.java | 23 -- .../service/DelegatingServiceSpecResolver.java | 127 +++++++++ .../HardcodedCatalogServiceSpecResolver.java | 95 +++++++ .../service/JavaServiceSpecResolver.java | 91 +++++++ .../service/JavaServiceTypeResolver.java | 38 --- .../creation/service/ServiceSpecResolver.java | 56 ++++ .../creation/service/ServiceTypeResolver.java | 3 + .../service/ServiceTypeResolverAdaptor.java | 62 +++++ .../service/UrlServiceSpecResolver.java | 70 +++++ ...lyn.spi.creation.service.ServiceSpecResolver | 23 ++ ...lyn.spi.creation.service.ServiceTypeResolver | 22 -- .../brooklyn/catalog/CatalogXmlOsgiTest.java | 16 +- .../brooklyn/catalog/CatalogYamlEntityTest.java | 49 +++- .../rest/resources/ApplicationResource.java | 4 +- 26 files changed, 882 insertions(+), 543 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java index 9b4a83c..a6a8e3a 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java @@ -34,6 +34,11 @@ import org.apache.brooklyn.core.plan.PlanToSpecTransformer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * Old-style catalog items (can be defined in catalog.xml only) don't have structure, only a single type, so + * they are loaded as a simple java type, only taking the class name from the catalog item instead of the + * type value in the YAML. Classpath entries in the item are also used (through the catalog root classloader). + */ public class JavaCatalogToSpecTransformer implements PlanToSpecTransformer { private static final Logger log = LoggerFactory.getLogger(JavaCatalogToSpecTransformer.class); @@ -64,8 +69,12 @@ public class JavaCatalogToSpecTransformer implements PlanToSpecTransformer { CatalogItem<T, SpecT> item, Set<String> encounteredTypes) throws PlanNotRecognizedException { if (item.getJavaType() != null) { log.warn("Deprecated functionality (since 0.9.0). Using old-style xml catalog items with java type attribute for " + item); - BrooklynClassLoadingContext loader = CatalogUtils.newClassLoadingContext(mgmt, item); - Class<?> type = loader.loadClass(item.getJavaType()); + Class<?> type; + try { + type = mgmt.getCatalogClassLoader().loadClass(item.getJavaType()); + } catch (ClassNotFoundException e) { + throw new IllegalStateException("Unable to load old-style java catalog item type " + item.getJavaType() + " for item " + item, e); + } AbstractBrooklynObjectSpec<?,?> spec; if (Entity.class.isAssignableFrom(type)) { @SuppressWarnings("unchecked") http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java index 0dca83c..cda3f5b 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java @@ -44,6 +44,7 @@ import org.apache.brooklyn.core.plan.PlanToSpecTransformer; import org.apache.brooklyn.entity.stock.BasicApplication; import org.apache.brooklyn.util.collections.MutableList; import org.apache.brooklyn.util.collections.MutableMap; +import org.apache.brooklyn.util.collections.MutableSet; import org.apache.brooklyn.util.core.task.TaskBuilder; import org.apache.brooklyn.util.core.task.Tasks; import org.apache.brooklyn.util.text.Strings; @@ -56,7 +57,6 @@ import com.google.common.base.Function; import com.google.common.base.Predicates; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; @@ -99,7 +99,7 @@ public class EntityManagementUtils { } public static <T,SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT createCatalogSpec(ManagementContext mgmt, CatalogItem<T, SpecT> item) { - return createCatalogSpec(mgmt, item, ImmutableSet.<String>of()); + return createCatalogSpec(mgmt, item, MutableSet.<String>of()); } public static <T,SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT createCatalogSpec(ManagementContext mgmt, final CatalogItem<T, SpecT> item, final Set<String> encounteredTypes) { http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/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 3328545..1b49170 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 @@ -117,7 +117,7 @@ public class PlanToSpecFactory { // at least one thought he could do it log.debug("Plan could not be transformed; failure will be propagated (other transformers tried = "+transformersWhoDontSupport+"): "+otherProblemsFromTransformers); result = otherProblemsFromTransformers.size()==1 ? Exceptions.create(null, otherProblemsFromTransformers) : - Exceptions.create("Plan transformers all failed", otherProblemsFromTransformers); + Exceptions.create("All plan transformers failed", otherProblemsFromTransformers); } else { result = new PlanNotRecognizedException("Invalid plan; format could not be recognized, trying with: "+transformersWhoDontSupport); } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/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 e54e2ef..19aa100 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 @@ -39,6 +39,7 @@ 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.entity.stock.BasicApplicationImpl; +import org.apache.brooklyn.util.collections.MutableSet; import org.apache.brooklyn.util.core.flags.TypeCoercions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -71,10 +72,11 @@ public class BrooklynAssemblyTemplateInstantiator implements AssemblyTemplateSpe } @Override - public List<EntitySpec<?>> createServiceSpecs(AssemblyTemplate template, + public List<EntitySpec<?>> createServiceSpecs( + AssemblyTemplate template, CampPlatform platform, BrooklynClassLoadingContext itemLoader, Set<String> encounteredCatalogTypes) { - return buildTemplateServicesAsSpecs(itemLoader, template, platform, encounteredCatalogTypes, true); + return buildTemplateServicesAsSpecs(itemLoader, template, platform, encounteredCatalogTypes); } @Override @@ -88,7 +90,7 @@ public class BrooklynAssemblyTemplateInstantiator implements AssemblyTemplateSpe BrooklynComponentTemplateResolver resolver = BrooklynComponentTemplateResolver.Factory.newInstance( loader, buildWrapperAppTemplate(template)); - EntitySpec<? extends Application> app = resolver.resolveSpec(null, false); + EntitySpec<? extends Application> app = resolver.resolveSpec(MutableSet.<String>of()); app.configure(EntityManagementUtils.WRAPPER_APP_MARKER, Boolean.TRUE); // first build the children into an empty shell app @@ -124,13 +126,13 @@ public class BrooklynAssemblyTemplateInstantiator implements AssemblyTemplateSpe return EntityManagementUtils.canPromoteWrappedApplication(app); } - private List<EntitySpec<?>> buildTemplateServicesAsSpecs(BrooklynClassLoadingContext loader, AssemblyTemplate template, CampPlatform platform, Set<String> encounteredCatalogTypes, boolean canUseOtherTransformers) { + private List<EntitySpec<?>> buildTemplateServicesAsSpecs(BrooklynClassLoadingContext loader, AssemblyTemplate template, CampPlatform platform, Set<String> encounteredCatalogTypes) { List<EntitySpec<?>> result = Lists.newArrayList(); for (ResolvableLink<PlatformComponentTemplate> ctl: template.getPlatformComponentTemplates().links()) { PlatformComponentTemplate appChildComponentTemplate = ctl.resolve(); BrooklynComponentTemplateResolver entityResolver = BrooklynComponentTemplateResolver.Factory.newInstance(loader, appChildComponentTemplate); - EntitySpec<?> spec = entityResolver.resolveSpec(encounteredCatalogTypes, canUseOtherTransformers); + EntitySpec<?> spec = entityResolver.resolveSpec(encounteredCatalogTypes); result.add(spec); } return result; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java index f42145d..05252f5 100644 --- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java @@ -18,6 +18,7 @@ */ package org.apache.brooklyn.camp.brooklyn.spi.creation; +import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; @@ -28,17 +29,16 @@ import java.util.concurrent.atomic.AtomicBoolean; import javax.annotation.Nullable; -import org.apache.brooklyn.api.catalog.CatalogItem; -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.camp.brooklyn.BrooklynCampConstants; import org.apache.brooklyn.camp.brooklyn.BrooklynCampReservedKeys; -import org.apache.brooklyn.camp.brooklyn.spi.creation.service.DefaultServiceTypeResolver; +import org.apache.brooklyn.camp.brooklyn.spi.creation.service.DelegatingServiceSpecResolver; +import org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceSpecResolver; import org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceTypeResolver; +import org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceTypeResolverAdaptor; import org.apache.brooklyn.camp.spi.AbstractResource; import org.apache.brooklyn.camp.spi.ApplicationComponentTemplate; import org.apache.brooklyn.camp.spi.AssemblyTemplate; @@ -46,21 +46,17 @@ import org.apache.brooklyn.camp.spi.PlatformComponentTemplate; 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.mgmt.BrooklynTags; import org.apache.brooklyn.core.mgmt.BrooklynTaskTags; -import org.apache.brooklyn.core.mgmt.EntityManagementUtils; import org.apache.brooklyn.core.mgmt.ManagementContextInjectable; import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext; import org.apache.brooklyn.core.mgmt.classloading.JavaBrooklynClassLoadingContext; import org.apache.brooklyn.util.collections.MutableList; import org.apache.brooklyn.util.collections.MutableSet; -import org.apache.brooklyn.util.core.ResourceUtils; import org.apache.brooklyn.util.core.config.ConfigBag; import org.apache.brooklyn.util.core.flags.FlagUtils; import org.apache.brooklyn.util.core.flags.FlagUtils.FlagConfigKeyAndValueRecord; import org.apache.brooklyn.util.core.task.Tasks; import org.apache.brooklyn.util.guava.Maybe; -import org.apache.brooklyn.util.javalang.Reflections; import org.apache.brooklyn.util.net.Urls; import org.apache.brooklyn.util.text.Strings; import org.slf4j.Logger; @@ -75,6 +71,7 @@ import com.google.common.collect.Maps; * This generates instances of a template resolver that use a {@link ServiceTypeResolver} * to parse the {@code serviceType} line in the template. */ +@SuppressWarnings("deprecation") // Because of ServiceTypeResolver public class BrooklynComponentTemplateResolver { private static final Logger log = LoggerFactory.getLogger(BrooklynComponentTemplateResolver.class); @@ -85,47 +82,29 @@ public class BrooklynComponentTemplateResolver { private final Maybe<AbstractResource> template; private final BrooklynYamlTypeInstantiator.Factory yamlLoader; private final String type; - private final ServiceTypeResolver typeResolver; private final AtomicBoolean alreadyBuilt = new AtomicBoolean(false); + private final ServiceSpecResolver serviceSpecResolver; - private BrooklynComponentTemplateResolver(BrooklynClassLoadingContext loader, ConfigBag attrs, AbstractResource optionalTemplate, String type, ServiceTypeResolver typeResolver) { + private BrooklynComponentTemplateResolver(BrooklynClassLoadingContext loader, ConfigBag attrs, AbstractResource optionalTemplate, String type) { this.loader = loader; this.mgmt = loader.getManagementContext(); this.attrs = ConfigBag.newInstanceCopying(attrs); this.template = Maybe.fromNullable(optionalTemplate); this.yamlLoader = new BrooklynYamlTypeInstantiator.Factory(loader, this); this.type = type; - this.typeResolver = typeResolver; + this.serviceSpecResolver = new DelegatingServiceSpecResolver(mgmt, getServiceTypeResolverOverrides()); } - public ManagementContext getManagementContext() { return mgmt; } - public ConfigBag getAttrs() { return attrs; } - public BrooklynYamlTypeInstantiator.Factory getYamlLoader() { return yamlLoader; } - public String getDeclaredType() { return type; } + // Deprecated because want to keep as much of the state private as possible + // Can't remove them because used by ServiceTypeResolver implementations + /** @deprecated since 0.9.0 */ + @Deprecated public ManagementContext getManagementContext() { return mgmt; } + @Deprecated public ConfigBag getAttrs() { return attrs; } + @Deprecated public BrooklynYamlTypeInstantiator.Factory getYamlLoader() { return yamlLoader; } + @Deprecated public String getDeclaredType() { return type; } public static class Factory { - /** returns resolver type based on the service type, inspecting the arguments in order to determine the service type */ - private static ServiceTypeResolver computeResolverType(BrooklynClassLoadingContext context, String knownServiceType, AbstractResource optionalTemplate, ConfigBag attrs) { - String type = getDeclaredType(knownServiceType, optionalTemplate, attrs); - return findService(context, type); - } - - // TODO This could be extended to support multiple prefixes per resolver and a 'best-match' algorithm - private static ServiceTypeResolver findService(BrooklynClassLoadingContext context, String type) { - if (type.indexOf(':') != -1) { - String prefix = Splitter.on(":").splitToList(type).get(0); - ServiceLoader<ServiceTypeResolver> loader = ServiceLoader.load(ServiceTypeResolver.class, - context.getManagementContext().getCatalogClassLoader()); - for (ServiceTypeResolver resolver : loader) { - if (prefix.equals(resolver.getTypePrefix())) { - return resolver; - } - } - } - return null; - } - public static BrooklynComponentTemplateResolver newInstance(BrooklynClassLoadingContext context, Map<String, ?> childAttrs) { return newInstance(context, ConfigBag.newInstance(childAttrs), null); } @@ -139,11 +118,8 @@ public class BrooklynComponentTemplateResolver { } private static BrooklynComponentTemplateResolver newInstance(BrooklynClassLoadingContext context, ConfigBag attrs, AbstractResource optionalTemplate) { - ServiceTypeResolver typeResolver = computeResolverType(context, null, optionalTemplate, attrs); String type = getDeclaredType(null, optionalTemplate, attrs); - if (typeResolver == null) // use default - typeResolver = new DefaultServiceTypeResolver(); - return new BrooklynComponentTemplateResolver(context, attrs, optionalTemplate, type, typeResolver); + return new BrooklynComponentTemplateResolver(context, attrs, optionalTemplate, type); } private static String getDeclaredType(String knownServiceType, AbstractResource optionalTemplate, @Nullable ConfigBag attrs) { @@ -164,185 +140,49 @@ public class BrooklynComponentTemplateResolver { } public boolean canResolve() { - if (!(typeResolver instanceof DefaultServiceTypeResolver)) { - return true; - } - - CatalogItem<Entity, EntitySpec<?>> item = typeResolver.getCatalogItem(this, type); - if (item != null) { - if (item.isDisabled()) { - log.warn("Disallowed attempt to use disabled catalog item "+item.getId()); - return false; - } else if (item.isDeprecated()) { - log.warn("Use of deprecated catalog item "+item.getId()); - } - return true; - } - - if (tryLoadEntityClass().isPresent()) { - return true; - } - - String protocol = Urls.getProtocol(type); - if (protocol != null) { - if (BrooklynCampConstants.YAML_URL_PROTOCOL_WHITELIST.contains(protocol)) { - return true; - } else { - log.debug("The reference '" + type + "' looks like a URL (running the CAMP Brooklyn entity-matcher) but the protocol '" + - protocol + "' isn't white listed " + BrooklynCampConstants.YAML_URL_PROTOCOL_WHITELIST + ". " + - "Not recognized as catalog item or java item as well!"); - } - } - - return true; - } - - /** returns the entity class, if needed in contexts which scan its statics for example */ - private Class<? extends Entity> loadEntityClass() { - Maybe<Class<? extends Entity>> result = tryLoadEntityClass(); - if (result.isAbsent()) - throw new IllegalStateException("Could not find "+typeResolver.getBrooklynType(type), ((Maybe.Absent<?>)result).getException()); - return result.get(); - } - - /** tries to load the Java entity class */ - private Maybe<Class<? extends Entity>> tryLoadEntityClass() { - return loader.tryLoadClass(getJavaType(), Entity.class); - } - - // TODO Generalise to have other prefixes (e.g. explicit "catalog:" etc)? - private boolean isJavaTypePrefix() { - return type != null && (type.toLowerCase().startsWith("java:") || type.toLowerCase().startsWith("brooklyn:java:")); - } - - private String getJavaType() { - return typeResolver.getBrooklynType(type); + return serviceSpecResolver.accepts(type, loader); } - public <T extends Entity> EntitySpec<T> resolveSpec(Set<String> encounteredCatalogTypes, boolean canUseOtherTransformers) { + public <T extends Entity> EntitySpec<T> resolveSpec(Set<String> encounteredCatalogTypes) { if (alreadyBuilt.getAndSet(true)) throw new IllegalStateException("Spec can only be used once: "+this); - String brooklynType = typeResolver.getBrooklynType(type); - CatalogItem<Entity, EntitySpec<?>> item = typeResolver.getCatalogItem(this, type); - - if (log.isTraceEnabled()) log.trace("Building CAMP template services: type="+brooklynType+"; item="+item+"; loader="+loader+"; encounteredCatalogTypes="+encounteredCatalogTypes); - - // TODO implement as service type - EntitySpec<T> spec = null; - String protocol = Urls.getProtocol(brooklynType); - if (protocol != null) { - if (BrooklynCampConstants.YAML_URL_PROTOCOL_WHITELIST.contains(protocol)) { - spec = tryResolveYamlUrlReferenceSpec(brooklynType, encounteredCatalogTypes); - if (spec != null) { - populateSpec(spec); - } - } else { - // TODO this will probably be logged if we refer to chef:cookbook or other service types which BCTR accepts; - // better would be to have BCTR supporting the calls above - log.debug("The reference " + brooklynType + " looks like a URL (running the CAMP Brooklyn assembly-template instantiator) but the protocol " + - protocol + " isn't white listed (" + BrooklynCampConstants.YAML_URL_PROTOCOL_WHITELIST + "). " + - "Will try to load it as catalog item or java type."); - } - } + EntitySpec<?> spec = serviceSpecResolver.resolve(type, loader, encounteredCatalogTypes); if (spec == null) { - // load from java or yaml - spec = resolveLocalSpec(encounteredCatalogTypes, canUseOtherTransformers); + String proto = Urls.getProtocol(type); + if (proto != null) { + log.debug("The reference " + type + " looks like a URL (running the CAMP Brooklyn assembly-template instantiator) but the protocol " + + proto + " isn't white listed (" + BrooklynCampConstants.YAML_URL_PROTOCOL_WHITELIST + "). " + + "Not a catalog item or java type as well."); + } + throw new IllegalStateException("Unable to create spec for type " + type + ". No resolver knew how to handle it."); } - return spec; - } + populateSpec(spec, encounteredCatalogTypes); - @SuppressWarnings("unchecked") - private <T extends Entity> EntitySpec<T> tryResolveYamlUrlReferenceSpec(String brooklynType, Set<String> encounteredCatalogTypes) { - String yaml; - try { - yaml = ResourceUtils.create(this).getResourceAsString(brooklynType); - } catch (Exception e) { - log.warn("AssemblyTemplate type " + brooklynType + " which looks like a URL can't be fetched.", e); - return null; - } - // Referenced specs are expected to be CAMP format as well. - List<EntitySpec<?>> serviceSpecs = CampUtils.createServiceSpecs(yaml, loader, encounteredCatalogTypes); - if (serviceSpecs.size() > 1) { - throw new UnsupportedOperationException("Only supporting single service in remotely referenced plans: got "+serviceSpecs); - } - return (EntitySpec<T>) serviceSpecs.get(0); + @SuppressWarnings("unchecked") + EntitySpec<T> typedSpec = (EntitySpec<T>) spec; + return typedSpec; } - private <T extends Entity> EntitySpec<T> resolveLocalSpec(Set<String> encounteredCatalogTypes, boolean canUseOtherTransformers) { - CatalogItem<Entity, EntitySpec<?>> item = typeResolver.getCatalogItem(this, type); - EntitySpec<T> spec = createSpec(item, encounteredCatalogTypes); - populateSpec(spec); - return spec; - } - - @SuppressWarnings({ "unchecked" }) - private <T extends Entity,SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> EntitySpec<T> createSpec(CatalogItem<Entity, EntitySpec<?>> item, Set<String> encounteredCatalogTypes) { - if (item == null) { - // ignore; presumably a java type or some such? - } else if (item.isDisabled()) { - throw new IllegalStateException("Illegal use of disabled catalog item "+item.getSymbolicName()+":"+item.getVersion()); - } else if (item.isDeprecated()) { - log.warn("Use of deprecated catalog item "+item.getSymbolicName()+":"+item.getVersion()); - } - - if (encounteredCatalogTypes==null) encounteredCatalogTypes = MutableSet.of(); - - //Take the symbolicName part of the catalog item only for recursion detection to prevent - //cross referencing of different versions. Not interested in non-catalog item types. - //Prevent catalog items self-referencing even if explicitly different version. - boolean firstOccurrence = (item == null || encounteredCatalogTypes.add(item.getSymbolicName())); - boolean recursiveButTryJava = !firstOccurrence; - - // Load a java class from current loader if explicit java prefix, or if no item, or if item is legacy / - // old-style catalog item (item != null && item.getJavaType() != null). - // Old-style catalog items (can be defined in catalog.xml only) don't have structure, only a single type, so - // they are loaded as a simple java type, only taking the class name from the catalog item instead of the - // type value in the YAML. Classpath entries in the item are also used (through the catalog root classloader). - if (isJavaTypePrefix() || item == null) { - return createSpecFromJavaType(); - - // Same as above case, but this time force java type loading (either as plain class or through an old-style - // catalog item, since we have already loaded a class item with the same name as the type value. - } else if (recursiveButTryJava) { - if (tryLoadEntityClass().isAbsent()) { - throw new IllegalStateException("Recursive reference to " + item + " (and cannot be resolved as a Java type)"); + private List<ServiceSpecResolver> getServiceTypeResolverOverrides() { + List<ServiceSpecResolver> overrides = new ArrayList<>(); + if (type.indexOf(':') != -1) { + String prefix = Splitter.on(":").splitToList(type).get(0); + ServiceLoader<ServiceTypeResolver> loader = ServiceLoader.load(ServiceTypeResolver.class, + mgmt.getCatalogClassLoader()); + for (ServiceTypeResolver resolver : loader) { + if (prefix.equals(resolver.getTypePrefix())) { + overrides.add(new ServiceTypeResolverAdaptor(this, resolver)); + } } - return createSpecFromJavaType(); - - // Only case that's left is a catalog item with CAMP YAML content - try to parse it recursively - // including its OSGi bundles in the loader classpath. - } else { - return (EntitySpec<T>) EntityManagementUtils.createCatalogSpec(mgmt, (CatalogItem<T,SpecT>)item, encounteredCatalogTypes); } - } - - @SuppressWarnings("unchecked") - private <T extends Entity> EntitySpec<T> createSpecFromJavaType() { - Class<T> type = (Class<T>) loadEntityClass(); - - EntitySpec<T> spec; - if (type.isInterface()) { - spec = EntitySpec.create(type); - } else { - // If this is a concrete class, particularly for an Application class, we want the proxy - // to expose all interfaces it implements. - @SuppressWarnings("rawtypes") - Class interfaceclazz = (Application.class.isAssignableFrom(type)) ? Application.class : Entity.class; - List<Class<?>> additionalInterfaceClazzes = Reflections.getAllInterfaces(type); - spec = EntitySpec.create(interfaceclazz).impl(type).additionalInterfaces(additionalInterfaceClazzes); - } - spec.catalogItemId(CatalogUtils.getCatalogItemIdFromLoader(loader)); - if (template.isPresent() && template.get().getSourceCode()!=null) - spec.tag(BrooklynTags.newYamlSpecTag(template.get().getSourceCode())); - - return spec; + return overrides; } @SuppressWarnings("unchecked") - private <T extends Entity> void populateSpec(EntitySpec<T> spec) { + private <T extends Entity> void populateSpec(EntitySpec<T> spec, Set<String> encounteredCatalogTypes) { String name, templateId=null, planId=null; if (template.isPresent()) { name = template.get().getName(); @@ -356,15 +196,12 @@ public class BrooklynComponentTemplateResolver { Object childrenObj = attrs.getStringKey(BrooklynCampReservedKeys.BROOKLYN_CHILDREN); if (childrenObj != null) { - // Creating a new set of encounteredCatalogTypes means that this won't check things recursively; - // but we are looking at children so we probably *should* be resetting the recursive list we've looked at; - // (but see also, a previous comment here which suggested otherwise? - Apr 2015) - Set<String> encounteredCatalogTypes = MutableSet.of(); - Iterable<Map<String,?>> children = (Iterable<Map<String,?>>)childrenObj; for (Map<String,?> childAttrs : children) { BrooklynComponentTemplateResolver entityResolver = BrooklynComponentTemplateResolver.Factory.newInstance(loader, childAttrs); - EntitySpec<? extends Entity> childSpec = entityResolver.resolveSpec(encounteredCatalogTypes, true); + // encounteredCatalogTypes must contain the items currently being loaded (the dependency chain), + // but not parent items in this catalog item already resolved. + EntitySpec<? extends Entity> childSpec = entityResolver.resolveSpec(encounteredCatalogTypes); spec.child(childSpec); } } @@ -379,7 +216,14 @@ public class BrooklynComponentTemplateResolver { if (childLocations != null) spec.locations(childLocations); - typeResolver.decorateSpec(this, spec); + decoreateSpec(spec); + } + + private <T extends Entity> void decoreateSpec(EntitySpec<T> spec) { + new BrooklynEntityDecorationResolver.PolicySpecResolver(yamlLoader).decorate(spec, attrs); + new BrooklynEntityDecorationResolver.EnricherSpecResolver(yamlLoader).decorate(spec, attrs); + new BrooklynEntityDecorationResolver.InitializerResolver(yamlLoader).decorate(spec, attrs); + configureEntityConfig(spec); } @@ -508,7 +352,7 @@ public class BrooklynComponentTemplateResolver { @SuppressWarnings("unchecked") Map<String, Object> resolvedConfig = (Map<String, Object>)transformSpecialFlags(specConfig.getSpecConfiguration()); specConfig.setSpecConfiguration(resolvedConfig); - return Factory.newInstance(getLoader(), specConfig.getSpecConfiguration()).resolveLocalSpec(null, false); + return Factory.newInstance(getLoader(), specConfig.getSpecConfiguration()).resolveSpec(MutableSet.<String>of()); } if (flag instanceof ManagementContextInjectable) { log.debug("Injecting Brooklyn management context info object: {}", flag); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java index dd0a6f4..9104f8f 100644 --- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java @@ -76,19 +76,15 @@ public class CampToSpecTransformer implements PlanToSpecTransformer { if (at.getPlatformComponentTemplates()==null || at.getPlatformComponentTemplates().isEmpty()) { if (at.getCustomAttributes().containsKey("brooklyn.catalog")) throw new IllegalArgumentException("Unrecognized application blueprint format: expected an application, not a brooklyn.catalog"); - throw new IllegalArgumentException("Unrecognized application blueprint format: no services defined"); + throw new PlanNotRecognizedException("Unrecognized application blueprint format: no services defined"); } // map this (expected) error to a nicer message - throw new IllegalArgumentException("Unrecognized application blueprint format"); + throw new PlanNotRecognizedException("Unrecognized application blueprint format"); } } catch (Exception e) { - if (e instanceof PlanNotRecognizedException) { - if (log.isTraceEnabled()) - log.debug("Failed to create entity from CAMP spec:\n" + plan, e); - } else { - if (log.isDebugEnabled()) - log.debug("Failed to create entity from CAMP spec:\n" + plan, e); - } + // TODO how do we figure out that the plan is not supported vs. invalid to wrap in a PlanNotRecognizedException? + if (log.isDebugEnabled()) + log.debug("Failed to create entity from CAMP spec:\n" + plan, e); throw Exceptions.propagate(e); } } @@ -96,6 +92,9 @@ public class CampToSpecTransformer implements PlanToSpecTransformer { @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public <T, SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT createCatalogSpec(CatalogItem<T, SpecT> item, Set<String> encounteredTypes) { + // Ignore old-style java type catalog items + if (item.getPlanYaml() == null) return null; + // Not really clear what should happen to the top-level attributes, ignored until a good use case appears. return (SpecT) CampCatalogUtils.createSpec(mgmt, (CatalogItem)item, encounteredTypes); } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/AbstractServiceSpecResolver.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/AbstractServiceSpecResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/AbstractServiceSpecResolver.java new file mode 100644 index 0000000..3fb3c89 --- /dev/null +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/AbstractServiceSpecResolver.java @@ -0,0 +1,65 @@ +/* + * 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.service; + +import java.util.Set; + +import org.apache.brooklyn.api.entity.EntitySpec; +import org.apache.brooklyn.api.mgmt.ManagementContext; +import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext; +import org.apache.brooklyn.util.text.Strings; + +public abstract class AbstractServiceSpecResolver implements ServiceSpecResolver { + private static final String PREFIX_DELIMITER = ":"; + protected final String name; + protected final String prefix; + protected ManagementContext mgmt; + + public AbstractServiceSpecResolver(String name) { + this.name = name; + this.prefix = name + PREFIX_DELIMITER; + } + + @Override + public String getName() { + return name; + } + + @Override + public boolean accepts(String type, BrooklynClassLoadingContext loader) { + return type.startsWith(prefix) && canResolve(type, loader); + } + + protected boolean canResolve(String type, BrooklynClassLoadingContext loader) { + return true; + } + + protected String getLocalType(String type) { + return Strings.removeFromStart(type, prefix); + } + + @Override + public void injectManagementContext(ManagementContext mgmt) { + this.mgmt = mgmt; + } + + @Override + public abstract EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes); + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/BrooklynServiceTypeResolver.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/BrooklynServiceTypeResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/BrooklynServiceTypeResolver.java deleted file mode 100644 index e0d2e9e..0000000 --- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/BrooklynServiceTypeResolver.java +++ /dev/null @@ -1,80 +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.camp.brooklyn.spi.creation.service; - -import javax.annotation.Nullable; - -import org.apache.brooklyn.api.catalog.CatalogItem; -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.entity.EntitySpec; -import org.apache.brooklyn.api.mgmt.ManagementContext; -import org.apache.brooklyn.camp.brooklyn.spi.creation.BrooklynComponentTemplateResolver; -import org.apache.brooklyn.camp.brooklyn.spi.creation.BrooklynEntityDecorationResolver; -import org.apache.brooklyn.camp.spi.PlatformComponentTemplate; -import org.apache.brooklyn.core.catalog.internal.CatalogUtils; -import org.apache.brooklyn.core.mgmt.persist.DeserializingClassRenamesProvider; -import org.apache.brooklyn.util.text.Strings; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This converts {@link PlatformComponentTemplate} instances whose type is prefixed {@code brooklyn:} - * to Brooklyn {@link EntitySpec} instances. - */ -public class BrooklynServiceTypeResolver implements ServiceTypeResolver { - - @SuppressWarnings("unused") - private static final Logger LOG = LoggerFactory.getLogger(ServiceTypeResolver.class); - - public BrooklynServiceTypeResolver() { - } - - @Override - public String getTypePrefix() { return DEFAULT_TYPE_PREFIX; } - - @Override - public String getBrooklynType(String serviceType) { - String type = Strings.removeFromStart(serviceType, getTypePrefix() + ":").trim(); - if (type == null) return null; - return type; - } - - @Nullable - @Override - public CatalogItem<Entity,EntitySpec<?>> getCatalogItem(BrooklynComponentTemplateResolver resolver, String serviceType) { - String type = getBrooklynType(serviceType); - if (type != null) { - return getCatalogItemImpl(resolver.getManagementContext(), type); - } else { - return null; - } - } - - @Override - public <T extends Entity> void decorateSpec(BrooklynComponentTemplateResolver resolver, EntitySpec<T> spec) { - new BrooklynEntityDecorationResolver.PolicySpecResolver(resolver.getYamlLoader()).decorate(spec, resolver.getAttrs()); - new BrooklynEntityDecorationResolver.EnricherSpecResolver(resolver.getYamlLoader()).decorate(spec, resolver.getAttrs()); - new BrooklynEntityDecorationResolver.InitializerResolver(resolver.getYamlLoader()).decorate(spec, resolver.getAttrs()); - } - - protected CatalogItem<Entity,EntitySpec<?>> getCatalogItemImpl(ManagementContext mgmt, String brooklynType) { - brooklynType = DeserializingClassRenamesProvider.findMappedName(brooklynType); - return CatalogUtils.getCatalogItemOptionalVersion(mgmt, Entity.class, brooklynType); - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CatalogServiceSpecResolver.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CatalogServiceSpecResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CatalogServiceSpecResolver.java new file mode 100644 index 0000000..19a76b3 --- /dev/null +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CatalogServiceSpecResolver.java @@ -0,0 +1,110 @@ +/* + * 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.service; + +import java.util.Set; + +import org.apache.brooklyn.api.catalog.CatalogItem; +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.mgmt.ManagementContext; +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.mgmt.persist.DeserializingClassRenamesProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CatalogServiceSpecResolver extends AbstractServiceSpecResolver { + private static final Logger log = LoggerFactory.getLogger(CatalogServiceSpecResolver.class); + + private static final String RESOLVER_NAME = "catalog"; + private final ServiceSpecResolver hardcodedResolver; + + public CatalogServiceSpecResolver() { + super(RESOLVER_NAME); + hardcodedResolver = new HardcodedCatalogServiceSpecResolver(); + } + + @Override + protected boolean canResolve(String type, BrooklynClassLoadingContext loader) { + String localType = getLocalType(type); + CatalogItem<Entity, EntitySpec<?>> item = getCatalogItem(mgmt, localType); + if (item != null) { + try { + //Keeps behaviour of previous functionality, but probably should throw instead when using disabled items. + checkUsable(item); + return true; + } catch (IllegalStateException e) { + return false; + } + } else { + return false; + } + } + + @Override + public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) { + String localType = getLocalType(type); + CatalogItem<Entity, EntitySpec<?>> item = getCatalogItem(mgmt, localType); + if (item != null) { + checkUsable(item); + + //Take the symbolicName part of the catalog item only for recursion detection to prevent + //cross referencing of different versions. Not interested in non-catalog item types. + //Prevent catalog items self-referencing even if explicitly different version. + boolean firstOccurrence = encounteredTypes.add(item.getSymbolicName()); + boolean nonRecursiveCall = firstOccurrence; + if (nonRecursiveCall) { + // CatalogItem generics are just getting in the way, better get rid of them, we + // are casting anyway. + @SuppressWarnings({ "rawtypes" }) + CatalogItem rawItem = item; + @SuppressWarnings({ "rawtypes", "unchecked" }) + AbstractBrooklynObjectSpec rawSpec = EntityManagementUtils.createCatalogSpec(mgmt, rawItem, encounteredTypes); + return (EntitySpec<?>) rawSpec; + } else { + return null; + } + } else { + return hardcodedResolver.resolve(type, loader, encounteredTypes); + } + } + + private void checkUsable(CatalogItem<Entity, EntitySpec<?>> item) { + if (item.isDisabled()) { + throw new IllegalStateException("Illegal use of disabled catalog item "+item.getSymbolicName()+":"+item.getVersion()); + } else if (item.isDeprecated()) { + log.warn("Use of deprecated catalog item "+item.getSymbolicName()+":"+item.getVersion()); + } + } + + protected CatalogItem<Entity,EntitySpec<?>> getCatalogItem(ManagementContext mgmt, String brooklynType) { + brooklynType = DeserializingClassRenamesProvider.findMappedName(brooklynType); + return CatalogUtils.getCatalogItemOptionalVersion(mgmt, Entity.class, brooklynType); + } + + @Override + public void injectManagementContext(ManagementContext mgmt) { + super.injectManagementContext(mgmt); + hardcodedResolver.injectManagementContext(mgmt); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CatalogServiceTypeResolver.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CatalogServiceTypeResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CatalogServiceTypeResolver.java deleted file mode 100644 index 94aa8fc..0000000 --- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/CatalogServiceTypeResolver.java +++ /dev/null @@ -1,77 +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.camp.brooklyn.spi.creation.service; - -import java.util.Map; - -import org.apache.brooklyn.api.entity.EntitySpec; -import org.apache.brooklyn.camp.spi.PlatformComponentTemplate; -import org.apache.brooklyn.entity.brooklynnode.BrooklynNode; -import org.apache.brooklyn.entity.group.DynamicCluster; -import org.apache.brooklyn.entity.group.DynamicRegionsFabric; -import org.apache.brooklyn.entity.java.VanillaJavaApp; -import org.apache.brooklyn.entity.software.base.VanillaSoftwareProcess; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.CaseFormat; -import com.google.common.base.Converter; -import com.google.common.collect.ImmutableMap; - -/** - * This converts {@link PlatformComponentTemplate} instances whose type is prefixed {@code catalog:} - * to Brooklyn {@link EntitySpec} instances. - */ -public class CatalogServiceTypeResolver extends BrooklynServiceTypeResolver { - - @SuppressWarnings("unused") - private static final Logger LOG = LoggerFactory.getLogger(ServiceTypeResolver.class); - - // TODO currently a hardcoded list of aliases; would like that to come from mgmt somehow - private static final Map<String, String> CATALOG_TYPES = ImmutableMap.<String, String>builder() - .put("cluster", DynamicCluster.class.getName()) - .put("fabric", DynamicRegionsFabric.class.getName()) - .put("vanilla", VanillaSoftwareProcess.class.getName()) - .put("software-process", VanillaSoftwareProcess.class.getName()) - .put("java-app", VanillaJavaApp.class.getName()) - .put("brooklyn-node", BrooklynNode.class.getName()) - .put("web-app-cluster","org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster") - .build(); - - // Allow catalog-type or CatalogType as service type string - private static final Converter<String, String> FMT = CaseFormat.LOWER_HYPHEN.converterTo(CaseFormat.UPPER_CAMEL); - - @Override - public String getTypePrefix() { return "catalog"; } - - @Override - public String getBrooklynType(String serviceType) { - String type = super.getBrooklynType(serviceType); - if (type == null) return null; - - for (String check : CATALOG_TYPES.keySet()) { - if (type.equals(check) || type.equals(FMT.convert(check))) { - return CATALOG_TYPES.get(check); - } - } - - return type; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ChefServiceSpecResolver.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ChefServiceSpecResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ChefServiceSpecResolver.java new file mode 100644 index 0000000..1910971 --- /dev/null +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ChefServiceSpecResolver.java @@ -0,0 +1,41 @@ +/* + * 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.service; + +import java.util.Set; + +import org.apache.brooklyn.api.entity.EntitySpec; +import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext; +import org.apache.brooklyn.entity.chef.ChefConfig; +import org.apache.brooklyn.entity.chef.ChefEntity; + +public class ChefServiceSpecResolver extends AbstractServiceSpecResolver { + private static final String RESOLVER_NAME = "chef"; + + public ChefServiceSpecResolver() { + super(RESOLVER_NAME); + } + + @Override + public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) { + return EntitySpec.create(ChefEntity.class) + .configure(ChefConfig.CHEF_COOKBOOK_PRIMARY_NAME, getLocalType(type)); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ChefServiceTypeResolver.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ChefServiceTypeResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ChefServiceTypeResolver.java deleted file mode 100644 index b44deb7..0000000 --- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ChefServiceTypeResolver.java +++ /dev/null @@ -1,61 +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.camp.brooklyn.spi.creation.service; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.apache.brooklyn.api.catalog.CatalogItem; -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.entity.EntitySpec; -import org.apache.brooklyn.camp.brooklyn.spi.creation.BrooklynComponentTemplateResolver; -import org.apache.brooklyn.camp.spi.PlatformComponentTemplate; -import org.apache.brooklyn.entity.chef.ChefConfig; -import org.apache.brooklyn.entity.chef.ChefEntity; -import org.apache.brooklyn.util.text.Strings; - -/** - * This converts {@link PlatformComponentTemplate} instances whose type is prefixed {@code chef:} - * to Brooklyn {@link EntitySpec} instances. - */ -public class ChefServiceTypeResolver extends BrooklynServiceTypeResolver { - - @SuppressWarnings("unused") - private static final Logger LOG = LoggerFactory.getLogger(ServiceTypeResolver.class); - - @Override - public String getTypePrefix() { return "chef"; } - - @Override - public String getBrooklynType(String serviceType) { - return ChefEntity.class.getName(); - } - - /** Chef items are not in the catalog. */ - @Override - public CatalogItem<Entity, EntitySpec<?>> getCatalogItem(BrooklynComponentTemplateResolver resolver, String serviceType) { - return null; - } - - @Override - public <T extends Entity> void decorateSpec(BrooklynComponentTemplateResolver resolver, EntitySpec<T> spec) { - spec.configure(ChefConfig.CHEF_COOKBOOK_PRIMARY_NAME, Strings.removeFromStart(resolver.getDeclaredType(), "chef:")); - super.decorateSpec(resolver, spec); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/DefaultServiceTypeResolver.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/DefaultServiceTypeResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/DefaultServiceTypeResolver.java deleted file mode 100644 index fdd57d5..0000000 --- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/DefaultServiceTypeResolver.java +++ /dev/null @@ -1,23 +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.camp.brooklyn.spi.creation.service; - -public class DefaultServiceTypeResolver extends BrooklynServiceTypeResolver { - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/DelegatingServiceSpecResolver.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/DelegatingServiceSpecResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/DelegatingServiceSpecResolver.java new file mode 100644 index 0000000..e1a2f19 --- /dev/null +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/DelegatingServiceSpecResolver.java @@ -0,0 +1,127 @@ +/* + * 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.service; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.ServiceLoader; +import java.util.Set; + +import javax.annotation.Nonnull; + +import org.apache.brooklyn.api.entity.EntitySpec; +import org.apache.brooklyn.api.mgmt.ManagementContext; +import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext; +import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.brooklyn.util.exceptions.PropagatedRuntimeException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.collect.ImmutableList; + +public class DelegatingServiceSpecResolver extends AbstractServiceSpecResolver { + private static final String RESOLVER_PREFIX_CATALOG = "catalog:"; + + private static final String RESOLVER_PREFIX_JAVA = "java:"; + + private static final Logger log = LoggerFactory.getLogger(DelegatingServiceSpecResolver.class); + + private static final String RESOLVER_NAME = "brooklyn"; + + private Collection<ServiceSpecResolver> resolvers; + + public DelegatingServiceSpecResolver(@Nonnull ManagementContext mgmt, @Nonnull List<ServiceSpecResolver> overridingResolvers) { + super(RESOLVER_NAME); + this.resolvers = ImmutableList.<ServiceSpecResolver>builder() + .addAll(overridingResolvers) + .addAll(ServiceLoader.load(ServiceSpecResolver.class)) + .build(); + for (ServiceSpecResolver resolver : resolvers) { + resolver.injectManagementContext(mgmt); + } + + injectManagementContext(mgmt); + } + + @Override + public boolean accepts(String type, BrooklynClassLoadingContext loader) { + return accepts("", type, loader) || + accepts(RESOLVER_PREFIX_CATALOG, type, loader) || + accepts(RESOLVER_PREFIX_JAVA, type, loader); + } + + private boolean accepts(String prefix, String type, BrooklynClassLoadingContext loader) { + for (ServiceSpecResolver resolver : resolvers) { + String localType = getLocalType(type); + if (resolver.accepts(prefix + localType, loader)) { + return true; + } + } + return false; + } + + @Override + public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) { + String localType = getLocalType(type); + + EntitySpec<?> spec = resolve(resolvers, localType, loader, encounteredTypes); + if (spec != null) { + return spec; + } + spec = resolve(resolvers, RESOLVER_PREFIX_CATALOG + localType, loader, encounteredTypes); + if (spec != null) { + return spec; + } + return resolve(resolvers, RESOLVER_PREFIX_JAVA + localType, loader, encounteredTypes); + } + + private EntitySpec<?> resolve( + Collection<ServiceSpecResolver> resolvers, + String localType, + BrooklynClassLoadingContext loader, + Set<String> encounteredTypes) { + Collection<String> resolversWhoDontSupport = new ArrayList<String>(); + Collection<Exception> otherProblemsFromResolvers = new ArrayList<Exception>(); + + for (ServiceSpecResolver resolver : resolvers) { + if (resolver.accepts(localType, loader)) { + try { + EntitySpec<?> spec = resolver.resolve(localType, loader, encounteredTypes); + if (spec != null) { + return spec; + } else { + resolversWhoDontSupport.add(resolver.getName() + " (returned null)"); + } + } catch (Exception e) { + otherProblemsFromResolvers.add(new PropagatedRuntimeException("Transformer for "+resolver.getName()+" gave an error creating this plan: "+ + Exceptions.collapseText(e), e)); + } + } + } + if (!otherProblemsFromResolvers.isEmpty()) { + // at least one thought he could do it + log.debug("Type " + localType + " could not be resolved; failure will be propagated (other transformers tried = "+resolversWhoDontSupport+"): "+otherProblemsFromResolvers); + throw otherProblemsFromResolvers.size()==1 ? Exceptions.create(null, otherProblemsFromResolvers) : + Exceptions.create("ServiceSpecResolvers all failed", otherProblemsFromResolvers); + } + return null; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/HardcodedCatalogServiceSpecResolver.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/HardcodedCatalogServiceSpecResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/HardcodedCatalogServiceSpecResolver.java new file mode 100644 index 0000000..2a3d7cd --- /dev/null +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/HardcodedCatalogServiceSpecResolver.java @@ -0,0 +1,95 @@ +/* + * 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.service; + +import java.util.Map; +import java.util.Set; + +import org.apache.brooklyn.api.entity.Entity; +import org.apache.brooklyn.api.entity.EntitySpec; +import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext; +import org.apache.brooklyn.entity.brooklynnode.BrooklynNode; +import org.apache.brooklyn.entity.group.DynamicCluster; +import org.apache.brooklyn.entity.group.DynamicRegionsFabric; +import org.apache.brooklyn.entity.java.VanillaJavaApp; +import org.apache.brooklyn.entity.software.base.VanillaSoftwareProcess; + +import com.google.common.base.CaseFormat; +import com.google.common.base.Converter; +import com.google.common.collect.ImmutableMap; + +public class HardcodedCatalogServiceSpecResolver extends AbstractServiceSpecResolver { + private static final String RESOLVER_NAME = "catalog"; + + private static final Map<String, String> CATALOG_TYPES = ImmutableMap.<String, String>builder() + .put("cluster", DynamicCluster.class.getName()) + .put("fabric", DynamicRegionsFabric.class.getName()) + .put("vanilla", VanillaSoftwareProcess.class.getName()) + .put("software-process", VanillaSoftwareProcess.class.getName()) + .put("java-app", VanillaJavaApp.class.getName()) + .put("brooklyn-node", BrooklynNode.class.getName()) + .put("web-app-cluster","org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster") + .build(); + + // Allow catalog-type or CatalogType as service type string + private static final Converter<String, String> FMT = CaseFormat.UPPER_CAMEL.converterTo(CaseFormat.LOWER_HYPHEN); + + public HardcodedCatalogServiceSpecResolver() { + super(RESOLVER_NAME); + } + + @Override + protected boolean canResolve(String type, BrooklynClassLoadingContext loader) { + String localType = getLocalType(type); + String specType = getImplementation(localType); + return specType != null; + } + + @Override + public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) { + String localType = getLocalType(type); + String specType = getImplementation(localType); + if (specType != null) { + return buildSpec(specType); + } else { + return null; + } + } + + private String getImplementation(String type) { + String specType = CATALOG_TYPES.get(type); + if (specType != null) { + return specType; + } else { + return CATALOG_TYPES.get(FMT.convert(type)); + } + } + + private EntitySpec<?> buildSpec(String specType) { + // TODO is this hardcoded list deprecated? If so log a warning. + try { + @SuppressWarnings("unchecked") + Class<Entity> specClass = (Class<Entity>)mgmt.getCatalogClassLoader().loadClass(specType); + return EntitySpec.create(specClass); + } catch (ClassNotFoundException e) { + throw new IllegalStateException("Unable to load hardcoded catalog type " + specType, e); + } + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/JavaServiceSpecResolver.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/JavaServiceSpecResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/JavaServiceSpecResolver.java new file mode 100644 index 0000000..fa0f9e5 --- /dev/null +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/JavaServiceSpecResolver.java @@ -0,0 +1,91 @@ +/* + * 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.service; + +import java.util.List; +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.core.catalog.internal.CatalogUtils; +import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext; +import org.apache.brooklyn.util.guava.Maybe; +import org.apache.brooklyn.util.javalang.Reflections; + +public class JavaServiceSpecResolver extends AbstractServiceSpecResolver{ + private static final String RESOLVER_NAME = "java"; + + public JavaServiceSpecResolver() { + super(RESOLVER_NAME); + } + + @Override + protected boolean canResolve(String type, BrooklynClassLoadingContext loader) { + String localType = getLocalType(type); + Maybe<?> javaType = tryLoadJavaType(localType, loader); + return javaType.isPresent(); + } + + @Override + public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) { + String localType = getLocalType(type); + try { + return resolveInternal(localType, loader); + } catch (Exception e) { + boolean firstOccurrence = encounteredTypes.add(localType); + boolean recursiveButTryJava = !firstOccurrence; + if (recursiveButTryJava) { + throw new IllegalStateException("Recursive reference to " + localType + " (and cannot be resolved as a Java type)", e); + } else { + throw e; + } + } + } + + private EntitySpec<?> resolveInternal(String localType, BrooklynClassLoadingContext loader) { + Maybe<Class<? extends Entity>> javaTypeMaybe = tryLoadJavaType(localType, loader); + if (javaTypeMaybe.isAbsent()) + throw new IllegalStateException("Could not find "+localType, ((Maybe.Absent<?>)javaTypeMaybe).getException()); + Class<? extends Entity> javaType = javaTypeMaybe.get(); + + EntitySpec<? extends Entity> spec; + if (javaType.isInterface()) { + spec = EntitySpec.create(javaType); + } else { + // If this is a concrete class, particularly for an Application class, we want the proxy + // to expose all interfaces it implements. + Class<? extends Entity> interfaceclazz = (Application.class.isAssignableFrom(javaType)) ? Application.class : Entity.class; + List<Class<?>> additionalInterfaceClazzes = Reflections.getAllInterfaces(javaType); + @SuppressWarnings({ "rawtypes", "unchecked" }) + EntitySpec<?> rawSpec = EntitySpec.create(interfaceclazz) + .impl((Class) javaType) + .additionalInterfaces(additionalInterfaceClazzes); + spec = rawSpec; + } + spec.catalogItemId(CatalogUtils.getCatalogItemIdFromLoader(loader)); + + return spec; + } + + private Maybe<Class<? extends Entity>> tryLoadJavaType(String localType, BrooklynClassLoadingContext loader) { + return loader.tryLoadClass(localType, Entity.class); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/JavaServiceTypeResolver.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/JavaServiceTypeResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/JavaServiceTypeResolver.java deleted file mode 100644 index d6c52f4..0000000 --- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/JavaServiceTypeResolver.java +++ /dev/null @@ -1,38 +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.camp.brooklyn.spi.creation.service; - -import org.apache.brooklyn.api.entity.EntitySpec; -import org.apache.brooklyn.camp.spi.PlatformComponentTemplate; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This converts {@link PlatformComponentTemplate} instances whose type is prefixed {@code java:} - * to Brooklyn {@link EntitySpec} instances. - */ -public class JavaServiceTypeResolver extends BrooklynServiceTypeResolver { - - @SuppressWarnings("unused") - private static final Logger LOG = LoggerFactory.getLogger(ServiceTypeResolver.class); - - @Override - public String getTypePrefix() { return "java"; } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceSpecResolver.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceSpecResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceSpecResolver.java new file mode 100644 index 0000000..00d6dd5 --- /dev/null +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceSpecResolver.java @@ -0,0 +1,56 @@ +/* + * 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.service; + +import java.util.ServiceLoader; +import java.util.Set; + +import javax.annotation.Nullable; + +import org.apache.brooklyn.api.entity.EntitySpec; +import org.apache.brooklyn.core.mgmt.ManagementContextInjectable; +import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext; + +/** + * Resolves and decorates {@link EntitySpec entity specifications} based on the {@code serviceType} in a template. + * <p> + * The resolver implementation will use the rest of the local part of the service type information + * to create and decorate an appropriate {@link EntitySpec entity}. + * <p> + * The resolvers are loaded using the {@link ServiceLoader} mechanism, allowing external libraries + * to add extra service type implementations that will be picked up at runtime. + */ +// TODO Not CAMP specific, move to core, to be reused by other parsers +public interface ServiceSpecResolver extends ManagementContextInjectable { + /** + * Uniquely identifies the resolver, can be used to address the same resolver at a later point in time. + * For implementations: this usually matches the service type prefix, but not required. + */ + String getName(); + + /** + * @return if the resolver can create a spec for the service type + */ + boolean accepts(String type, BrooklynClassLoadingContext loader); + + /** + * Create a spec for the service type + */ + @Nullable EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes); +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolver.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolver.java index dcbd971..c1399ff 100644 --- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolver.java +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolver.java @@ -37,7 +37,10 @@ import org.apache.brooklyn.camp.brooklyn.spi.creation.BrooklynComponentTemplateR * * @see BrooklynServiceTypeResolver * @see ChefServiceTypeResolver + * + * @deprecated since 0.9.0, {@link ServiceSpecResolver} instead. */ +@Deprecated public interface ServiceTypeResolver { String DEFAULT_TYPE_PREFIX = "brooklyn"; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4485fe5c/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolverAdaptor.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolverAdaptor.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolverAdaptor.java new file mode 100644 index 0000000..60abd40 --- /dev/null +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/service/ServiceTypeResolverAdaptor.java @@ -0,0 +1,62 @@ +/* + * 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.service; + +import java.util.Set; + +import org.apache.brooklyn.api.entity.EntitySpec; +import org.apache.brooklyn.camp.brooklyn.spi.creation.BrooklynComponentTemplateResolver; +import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import groovy.xml.Entity; + +@SuppressWarnings("deprecation") +public class ServiceTypeResolverAdaptor extends AbstractServiceSpecResolver { + private static final Logger log = LoggerFactory.getLogger(ServiceTypeResolverAdaptor.class); + private ServiceTypeResolver serviceTypeResolver; + private BrooklynComponentTemplateResolver resolver; + + public ServiceTypeResolverAdaptor(BrooklynComponentTemplateResolver resolver, ServiceTypeResolver serviceTypeResolver) { + super(serviceTypeResolver.getTypePrefix()); + this.serviceTypeResolver = serviceTypeResolver; + this.resolver = resolver; + } + + @Override + public boolean accepts(String type, BrooklynClassLoadingContext loader) { + return true; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) { + // Assume this is interface! Only known implementation is DockerServiceTypeResolver. + String brooklynType = serviceTypeResolver.getBrooklynType(type); + Class<? extends Entity> javaType = loader.loadClass(brooklynType, Entity.class); + if (!javaType.isInterface()) { + log.warn("Using " + ServiceTypeResolver.class.getSimpleName() + " with a non-interface type - this usage is not supported. Use " + ServiceSpecResolver.class.getSimpleName() + " instead."); + } + EntitySpec<?> spec = EntitySpec.create((Class)javaType); + serviceTypeResolver.decorateSpec(resolver, spec); + return spec; + } + +}
