blob: 602baa3e96e2989f48d2825271d6171d2bdd088c [file] [log] [blame]
/*
* 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 com.google.common.collect.Iterables;
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.mgmt.classloading.BrooklynClassLoadingContext;
import org.apache.brooklyn.api.policy.Policy;
import org.apache.brooklyn.api.typereg.RegisteredType;
import org.apache.brooklyn.api.typereg.RegisteredTypeLoadingContext;
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.typereg.RegisteredTypes;
import org.apache.brooklyn.util.collections.MutableSet;
import org.apache.brooklyn.util.text.Strings;
import com.google.common.collect.ImmutableSet;
class CampResolver {
private ManagementContext mgmt;
private RegisteredType type;
private RegisteredTypeLoadingContext context;
// TODO we have a few different modes, detailed below; this logic should be moved to the new transformer
// and allow specifying which modes are permitted to be in effect?
// /** 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, RegisteredTypeLoadingContext context) {
this.mgmt = mgmt;
this.type = type;
this.context = context;
}
public AbstractBrooklynObjectSpec<?, ?> createSpec() {
// TODO new-style approach:
// AbstractBrooklynObjectSpec<?, ?> spec = RegisteredTypes.newSpecInstance(mgmt, /* 'type' key */);
// spec.configure(keysAndValues);
return createSpecFromFull(mgmt, type, context.getExpectedJavaSuperType(), context.getAlreadyEncounteredTypes(), context.getLoader());
}
static AbstractBrooklynObjectSpec<?, ?> createSpecFromFull(ManagementContext mgmt, RegisteredType item, Class<?> expectedType, 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);
MutableSet<Object> supers = MutableSet.copyOf(item.getSuperTypes());
supers.addIfNotNull(expectedType);
if (RegisteredTypes.isAnyTypeSubtypeOf(supers, Policy.class)) {
spec = CampInternalUtils.createPolicySpec(planYaml, loader, encounteredTypes);
} else if (RegisteredTypes.isAnyTypeSubtypeOf(supers, Location.class)) {
spec = CampInternalUtils.createLocationSpec(planYaml, loader, encounteredTypes);
} else if (RegisteredTypes.isAnyTypeSubtypeOf(supers, Application.class)) {
spec = createEntitySpecFromServicesBlock(planYaml, loader, encounteredTypes, true);
} else if (RegisteredTypes.isAnyTypeSubtypeOf(supers, Entity.class)) {
spec = createEntitySpecFromServicesBlock(planYaml, loader, encounteredTypes, false);
} else {
throw new IllegalStateException("Cannot detect spec type from "+item.getSuperTypes()+" for "+item+"\n"+planYaml);
}
if (expectedType!=null && !expectedType.isAssignableFrom(spec.getType())) {
throw new IllegalStateException("Creating spec from "+item+", got "+spec.getType()+" which is incompatible with expected "+expectedType);
}
((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);
if (!isApplication && EntityManagementUtils.canPromoteChildrenInWrappedApplication(appSpec)) {
EntitySpec<?> childSpec = Iterables.getOnlyElement(appSpec.getChildren());
EntityManagementUtils.mergeWrapperParentSpecToChildEntity(appSpec, childSpec);
return childSpec;
}
return appSpec;
} else {
throw new IllegalStateException("Unable to instantiate YAML; incompatible instantiator "+instantiator+" for "+at);
}
}
}