http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e406d1ad/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/BrooklynDslInterpreter.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/BrooklynDslInterpreter.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/BrooklynDslInterpreter.java new file mode 100644 index 0000000..e30f7f2 --- /dev/null +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/BrooklynDslInterpreter.java @@ -0,0 +1,188 @@ +/* + * 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.dsl; + +import io.brooklyn.camp.spi.resolve.PlanInterpreter; +import io.brooklyn.camp.spi.resolve.PlanInterpreter.PlanInterpreterAdapter; +import io.brooklyn.camp.spi.resolve.interpret.PlanInterpretationNode; +import io.brooklyn.camp.spi.resolve.interpret.PlanInterpretationNode.Role; + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.BrooklynDslCommon; +import org.apache.brooklyn.camp.brooklyn.spi.dsl.parse.DslParser; +import org.apache.brooklyn.camp.brooklyn.spi.dsl.parse.FunctionWithArgs; +import org.apache.brooklyn.camp.brooklyn.spi.dsl.parse.QuotedString; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import brooklyn.util.exceptions.Exceptions; +import brooklyn.util.javalang.Reflections; +import brooklyn.util.text.Strings; + +import com.google.common.base.Optional; + +/** + * {@link PlanInterpreter} which understands the $brooklyn DSL + */ +public class BrooklynDslInterpreter extends PlanInterpreterAdapter { + + private static final Logger log = LoggerFactory.getLogger(BrooklynDslInterpreter.class); + + @Override + public boolean isInterestedIn(PlanInterpretationNode node) { + return node.matchesPrefix("$brooklyn:") || node.getNewValue() instanceof FunctionWithArgs; + } + + private static ThreadLocal<PlanInterpretationNode> currentNode = new ThreadLocal<PlanInterpretationNode>(); + /** returns the current node, stored in a thread-local, to populate the dsl field of {@link BrooklynDslDeferredSupplier} instances */ + public static PlanInterpretationNode currentNode() { + return currentNode.get(); + } + /** sets the current node */ + public static void currentNode(PlanInterpretationNode node) { + currentNode.set(node); + } + public static void currentNodeClear() { + currentNode.set(null); + } + + @Override + public void applyYamlPrimitive(PlanInterpretationNode node) { + String expression = node.getNewValue().toString(); + + try { + currentNode.set(node); + Object parsedNode = new DslParser(expression).parse(); + if ((parsedNode instanceof FunctionWithArgs) && ((FunctionWithArgs)parsedNode).getArgs()==null) { + if (node.getRoleInParent() == Role.MAP_KEY) { + node.setNewValue(parsedNode); + // will be handled later + } else { + throw new IllegalStateException("Invalid function-only expression '"+((FunctionWithArgs)parsedNode).getFunction()+"'"); + } + } else { + node.setNewValue( evaluate(parsedNode, true) ); + } + } catch (Exception e) { + log.warn("Error evaluating node (rethrowing) '"+expression+"': "+e); + Exceptions.propagateIfFatal(e); + throw new IllegalArgumentException("Error evaluating node '"+expression+"'", e); + } finally { + currentNodeClear(); + } + } + + @Override + public boolean applyMapEntry(PlanInterpretationNode node, Map<Object, Object> mapIn, Map<Object, Object> mapOut, + PlanInterpretationNode key, PlanInterpretationNode value) { + if (key.getNewValue() instanceof FunctionWithArgs) { + try { + currentNode.set(node); + + FunctionWithArgs f = (FunctionWithArgs) key.getNewValue(); + if (f.getArgs()!=null) + throw new IllegalStateException("Invalid map key function "+f.getFunction()+"; should not have arguments if taking arguments from map"); + + // means evaluation acts on values + List<Object> args = new ArrayList<Object>(); + if (value.getNewValue() instanceof Iterable<?>) { + for (Object vi: (Iterable<?>)value.getNewValue()) + args.add(vi); + } else { + args.add(value.getNewValue()); + } + + try { + // TODO in future we should support functions of the form 'Maps.clear', 'Maps.reset', 'Maps.remove', etc; + // default approach only supported if mapIn has single item and mapOut is empty + if (mapIn.size()!=1) + throw new IllegalStateException("Map-entry DSL syntax only supported with single item in map, not "+mapIn); + if (mapOut.size()!=0) + throw new IllegalStateException("Map-entry DSL syntax only supported with empty output map-so-far, not "+mapOut); + + node.setNewValue( evaluate(new FunctionWithArgs(f.getFunction(), args), false) ); + return false; + } catch (Exception e) { + log.warn("Error evaluating map-entry (rethrowing) '"+f.getFunction()+args+"': "+e); + Exceptions.propagateIfFatal(e); + throw new IllegalArgumentException("Error evaluating map-entry '"+f.getFunction()+args+"'", e); + } + + } finally { + currentNodeClear(); + } + } + return super.applyMapEntry(node, mapIn, mapOut, key, value); + } + + public Object evaluate(Object f, boolean deepEvaluation) { + if (f instanceof FunctionWithArgs) { + return evaluateOn(BrooklynDslCommon.class, (FunctionWithArgs) f, deepEvaluation); + } + + if (f instanceof List) { + Object o = BrooklynDslCommon.class; + for (Object i: (List<?>)f) { + o = evaluateOn( o, (FunctionWithArgs)i, deepEvaluation ); + } + return o; + } + + if (f instanceof QuotedString) { + return ((QuotedString)f).unwrapped(); + } + + throw new IllegalArgumentException("Unexpected element in parse tree: '"+f+"' (type "+(f!=null ? f.getClass() : null)+")"); + } + + public Object evaluateOn(Object o, FunctionWithArgs f, boolean deepEvaluation) { + if (f.getArgs()==null) + throw new IllegalStateException("Invalid function-only expression '"+f.getFunction()+"'"); + + Class<?> clazz; + if (o instanceof Class) { + clazz = (Class<?>)o; + } else { + clazz = o.getClass(); + } + if (!(clazz.getPackage().getName().startsWith(BrooklynDslCommon.class.getPackage().getName()))) + throw new IllegalArgumentException("Not permitted to invoke function on '"+clazz+"' (outside allowed package scope)"); + + String fn = f.getFunction(); + fn = Strings.removeFromStart(fn, "$brooklyn:"); + try { + List<Object> args = new ArrayList<Object>(); + for (Object arg: f.getArgs()) { + args.add( deepEvaluation ? evaluate(arg, true) : arg ); + } + Optional<Object> v = Reflections.invokeMethodWithArgs(o, fn, args); + if (v.isPresent()) return v.get(); + } catch (Exception e) { + Exceptions.propagateIfFatal(e); + throw Exceptions.propagate(new InvocationTargetException(e, "Error invoking '"+fn+"' on '"+o+"'")); + } + + throw new IllegalArgumentException("No such function '"+fn+"' on "+o); + } + +}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e406d1ad/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslUtils.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslUtils.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslUtils.java new file mode 100644 index 0000000..e5194bf --- /dev/null +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslUtils.java @@ -0,0 +1,44 @@ +/* + * 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.dsl; + +import brooklyn.util.task.DeferredSupplier; + +import com.google.common.collect.Iterables; + +public class DslUtils { + + /** true iff none of the args are deferred / tasks */ + public static boolean resolved(Iterable<Object> args) { + return resolved(Iterables.toArray(args, Object.class)); + } + + /** true iff none of the args are deferred / tasks */ + public static boolean resolved(final Object... args) { + boolean allResolved = true; + for (Object arg: args) { + if (arg instanceof DeferredSupplier<?>) { + allResolved = false; + break; + } + } + return allResolved; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e406d1ad/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java new file mode 100644 index 0000000..37bc043 --- /dev/null +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java @@ -0,0 +1,301 @@ +/* + * 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.dsl.methods; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.brooklyn.camp.brooklyn.BrooklynCampReservedKeys; +import org.apache.brooklyn.camp.brooklyn.spi.creation.BrooklynYamlTypeInstantiator; +import org.apache.brooklyn.camp.brooklyn.spi.creation.EntitySpecConfiguration; +import org.apache.brooklyn.camp.brooklyn.spi.dsl.BrooklynDslDeferredSupplier; +import org.apache.brooklyn.camp.brooklyn.spi.dsl.DslUtils; +import org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.DslComponent.Scope; +import org.apache.commons.beanutils.BeanUtils; + +import brooklyn.entity.Entity; +import brooklyn.entity.basic.EntityDynamicType; +import brooklyn.entity.trait.Configurable; +import brooklyn.event.Sensor; +import brooklyn.event.basic.DependentConfiguration; +import brooklyn.management.Task; +import brooklyn.management.TaskAdaptable; +import brooklyn.management.TaskFactory; +import brooklyn.util.collections.MutableMap; +import brooklyn.util.config.ConfigBag; +import brooklyn.util.exceptions.Exceptions; +import brooklyn.util.flags.ClassCoercionException; +import brooklyn.util.flags.FlagUtils; +import brooklyn.util.flags.TypeCoercions; +import brooklyn.util.javalang.Reflections; +import brooklyn.util.task.DeferredSupplier; +import brooklyn.util.text.StringEscapes.JavaStringEscapes; +import brooklyn.util.text.Strings; + +import com.google.common.base.Function; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; + +/** static import functions which can be used in `$brooklyn:xxx` contexts */ +public class BrooklynDslCommon { + + // Access specific entities + + public static DslComponent entity(String id) { + return new DslComponent(Scope.GLOBAL, id); + } + public static DslComponent parent() { + return new DslComponent(Scope.PARENT, null); + } + public static DslComponent child(String id) { + return new DslComponent(Scope.CHILD, id); + } + public static DslComponent sibling(String id) { + return new DslComponent(Scope.SIBLING, id); + } + public static DslComponent descendant(String id) { + return new DslComponent(Scope.DESCENDANT, id); + } + public static DslComponent ancestor(String id) { + return new DslComponent(Scope.ANCESTOR, id); + } + // prefer the syntax above to the below now, but not deprecating the below + public static DslComponent component(String id) { + return component("global", id); + } + public static DslComponent component(String scope, String id) { + if (!DslComponent.Scope.isValid(scope)) { + throw new IllegalArgumentException(scope + " is not a valid scope"); + } + return new DslComponent(DslComponent.Scope.fromString(scope), id); + } + + // Access things on entities + + public static BrooklynDslDeferredSupplier<?> config(String keyName) { + return new DslComponent(Scope.THIS, "").config(keyName); + } + + public static BrooklynDslDeferredSupplier<?> attributeWhenReady(String sensorName) { + return new DslComponent(Scope.THIS, "").attributeWhenReady(sensorName); + } + + /** Returns a {@link Sensor}, looking up the sensor on the context if available and using that, + * or else defining an untyped (Object) sensor */ + public static BrooklynDslDeferredSupplier<Sensor<?>> sensor(String sensorName) { + return new DslComponent(Scope.THIS, "").sensor(sensorName); + } + + /** Returns a {@link Sensor} declared on the type (e.g. entity class) declared in the first argument. */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static Sensor<?> sensor(String clazzName, String sensorName) { + try { + // TODO Should use catalog's classloader, rather than Class.forName; how to get that? Should we return a future?! + Class<?> clazz = Class.forName(clazzName); + Sensor<?> sensor; + if (Entity.class.isAssignableFrom(clazz)) { + sensor = new EntityDynamicType((Class<? extends Entity>) clazz).getSensor(sensorName); + } else { + // Some non-entity classes (e.g. ServiceRestarter policy) declare sensors that other + // entities/policies/enrichers may wish to reference. + Map<String,Sensor<?>> sensors = EntityDynamicType.findSensors((Class)clazz, null); + sensor = sensors.get(sensorName); + } + if (sensor == null) { + // TODO could extend API to return a sensor of the given type; useful but makes API ambiguous in theory (unlikely in practise, but still...) + throw new IllegalArgumentException("Sensor " + sensorName + " not found on class " + clazzName); + } + return sensor; + } catch (ClassNotFoundException e) { + throw Exceptions.propagate(e); + } + } + + // Build complex things + + public static EntitySpecConfiguration entitySpec(Map<String, Object> arguments) { + return new EntitySpecConfiguration(arguments); + } + + /** + * Return an instance of the specified class with its fields set according + * to the {@link Map} or a {@link BrooklynDslDeferredSupplier} if the arguments are not + * yet fully resolved. + */ + @SuppressWarnings("unchecked") + public static Object object(Map<String, Object> arguments) { + ConfigBag config = ConfigBag.newInstance(arguments); + String typeName = BrooklynYamlTypeInstantiator.InstantiatorFromKey.extractTypeName("object", config).orNull(); + Map<String,Object> objectFields = (Map<String, Object>) config.getStringKeyMaybe("object.fields").or(MutableMap.of()); + Map<String,Object> brooklynConfig = (Map<String, Object>) config.getStringKeyMaybe(BrooklynCampReservedKeys.BROOKLYN_CONFIG).or(MutableMap.of()); + try { + // TODO Should use catalog's classloader, rather than Class.forName; how to get that? Should we return a future?! + Class<?> type = Class.forName(typeName); + if (!Reflections.hasNoArgConstructor(type)) { + throw new IllegalStateException(String.format("Cannot construct %s bean: No public no-arg constructor available", type)); + } + if ((objectFields.isEmpty() || DslUtils.resolved(objectFields.values())) && + (brooklynConfig.isEmpty() || DslUtils.resolved(brooklynConfig.values()))) { + return DslObject.create(type, objectFields, brooklynConfig); + } else { + return new DslObject(type, objectFields, brooklynConfig); + } + } catch (ClassNotFoundException e) { + throw Exceptions.propagate(e); + } + } + + // String manipulation + + /** Return the expression as a literal string without any further parsing. */ + public static Object literal(Object expression) { + return expression; + } + + /** + * Returns a formatted string or a {@link BrooklynDslDeferredSupplier} if the arguments + * are not yet fully resolved. + */ + public static Object formatString(final String pattern, final Object...args) { + if (DslUtils.resolved(args)) { + // if all args are resolved, apply the format string now + return String.format(pattern, args); + } else { + return new DslFormatString(pattern, args); + } + } + + /** + * Deferred execution of String formatting. + * + * @see DependentConfiguration#formatString(String, Object...) + */ + protected static class DslFormatString extends BrooklynDslDeferredSupplier<String> { + + private static final long serialVersionUID = -4849297712650560863L; + + private String pattern; + private Object[] args; + + public DslFormatString(String pattern, Object ...args) { + this.pattern = pattern; + this.args = args; + } + + @Override + public Task<String> newTask() { + return DependentConfiguration.formatString(pattern, args); + } + + @Override + public String toString() { + return "$brooklyn:formatString("+ + JavaStringEscapes.wrapJavaString(pattern)+ + (args==null || args.length==0 ? "" : ","+Strings.join(args, ","))+")"; + } + } + + /** @deprecated since 0.7.0; use {@link DslFormatString} */ + @SuppressWarnings("serial") + @Deprecated + protected static class FormatString extends DslFormatString { + public FormatString(String pattern, Object[] args) { + super(pattern, args); + } + } + + /** Deferred execution of Object creation. */ + protected static class DslObject extends BrooklynDslDeferredSupplier<Object> { + + private static final long serialVersionUID = 8878388748085419L; + + private Class<?> type; + private Map<String,Object> fields, config; + + public DslObject(Class<?> type, Map<String,Object> fields, Map<String,Object> config) { + this.type = type; + this.fields = MutableMap.copyOf(fields); + this.config = MutableMap.copyOf(config); + } + + @SuppressWarnings("unchecked") + @Override + public Task<Object> newTask() { + List<TaskAdaptable<Object>> tasks = Lists.newLinkedList(); + for (Object value : Iterables.concat(fields.values(), config.values())) { + if (value instanceof TaskAdaptable) { + tasks.add((TaskAdaptable<Object>) value); + } else if (value instanceof TaskFactory) { + tasks.add(((TaskFactory<TaskAdaptable<Object>>) value).newTask()); + } + } + Map<String,?> flags = MutableMap.<String,String>of("displayName", "building '"+type+"' with "+tasks.size()+" task"+(tasks.size()!=1?"s":"")); + return DependentConfiguration.transformMultiple(flags, new Function<List<Object>, Object>() { + @Override + public Object apply(List<Object> input) { + Iterator<Object> values = input.iterator(); + for (String name : fields.keySet()) { + Object value = fields.get(name); + if (value instanceof TaskAdaptable || value instanceof TaskFactory) { + fields.put(name, values.next()); + } else if (value instanceof DeferredSupplier) { + fields.put(name, ((DeferredSupplier<?>) value).get()); + } + } + for (String name : config.keySet()) { + Object value = config.get(name); + if (value instanceof TaskAdaptable || value instanceof TaskFactory) { + config.put(name, values.next()); + } else if (value instanceof DeferredSupplier) { + config.put(name, ((DeferredSupplier<?>) value).get()); + } + } + return create(type, fields, config); + } + }, tasks); + } + + public static <T> T create(Class<T> type, Map<String,?> fields, Map<String,?> config) { + try { + T bean; + try { + bean = (T) TypeCoercions.coerce(fields, type); + } catch (ClassCoercionException ex) { + bean = Reflections.invokeConstructorWithArgs(type).get(); + BeanUtils.populate(bean, fields); + } + if (bean instanceof Configurable && config.size() > 0) { + ConfigBag brooklyn = ConfigBag.newInstance(config); + FlagUtils.setFieldsFromFlags(bean, brooklyn); + FlagUtils.setAllConfigKeys((Configurable) bean, brooklyn, true); + } + return bean; + } catch (Exception e) { + throw Exceptions.propagate(e); + } + } + + @Override + public String toString() { + return "$brooklyn:object(\""+type.getName()+"\")"; + } + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e406d1ad/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java new file mode 100644 index 0000000..4801a41 --- /dev/null +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java @@ -0,0 +1,320 @@ +/* + * 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.dsl.methods; + +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.concurrent.Callable; + +import org.apache.brooklyn.camp.brooklyn.BrooklynCampConstants; +import org.apache.brooklyn.camp.brooklyn.spi.dsl.BrooklynDslDeferredSupplier; + +import brooklyn.entity.Entity; +import brooklyn.entity.basic.BrooklynTaskTags; +import brooklyn.entity.basic.ConfigKeys; +import brooklyn.entity.basic.Entities; +import brooklyn.entity.basic.EntityInternal; +import brooklyn.entity.basic.EntityPredicates; +import brooklyn.event.AttributeSensor; +import brooklyn.event.Sensor; +import brooklyn.event.basic.DependentConfiguration; +import brooklyn.event.basic.Sensors; +import brooklyn.management.Task; +import brooklyn.management.internal.EntityManagerInternal; +import brooklyn.util.guava.Maybe; +import brooklyn.util.task.TaskBuilder; +import brooklyn.util.task.Tasks; +import brooklyn.util.text.StringEscapes.JavaStringEscapes; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; + +public class DslComponent extends BrooklynDslDeferredSupplier<Entity> { + + private static final long serialVersionUID = -7715984495268724954L; + + private final String componentId; + private final DslComponent scopeComponent; + private final Scope scope; + + public DslComponent(String componentId) { + this(Scope.GLOBAL, componentId); + } + + public DslComponent(Scope scope, String componentId) { + this(null, scope, componentId); + } + + public DslComponent(DslComponent scopeComponent, Scope scope, String componentId) { + Preconditions.checkNotNull(scope, "scope"); + this.scopeComponent = scopeComponent; + this.componentId = componentId; + this.scope = scope; + } + + // --------------------------- + + @Override + public Task<Entity> newTask() { + return TaskBuilder.<Entity>builder().name(toString()).tag(BrooklynTaskTags.TRANSIENT_TASK_TAG) + .body(new EntityInScopeFinder(scopeComponent, scope, componentId)).build(); + } + + protected static class EntityInScopeFinder implements Callable<Entity> { + protected final DslComponent scopeComponent; + protected final Scope scope; + protected final String componentId; + + public EntityInScopeFinder(DslComponent scopeComponent, Scope scope, String componentId) { + this.scopeComponent = scopeComponent; + this.scope = scope; + this.componentId = componentId; + } + + protected EntityInternal getEntity() { + if (scopeComponent!=null) { + return (EntityInternal)scopeComponent.get(); + } else { + return entity(); + } + } + + @Override + public Entity call() throws Exception { + Iterable<Entity> entitiesToSearch = null; + switch (scope) { + case THIS: + return getEntity(); + case PARENT: + return getEntity().getParent(); + case GLOBAL: + entitiesToSearch = ((EntityManagerInternal)getEntity().getManagementContext().getEntityManager()) + .getAllEntitiesInApplication( entity().getApplication() ); + break; + case DESCENDANT: + entitiesToSearch = Entities.descendants(getEntity()); + break; + case ANCESTOR: + entitiesToSearch = Entities.ancestors(getEntity()); + break; + case SIBLING: + entitiesToSearch = getEntity().getParent().getChildren(); + break; + case CHILD: + entitiesToSearch = getEntity().getChildren(); + break; + default: + throw new IllegalStateException("Unexpected scope "+scope); + } + + Optional<Entity> result = Iterables.tryFind(entitiesToSearch, EntityPredicates.configEqualTo(BrooklynCampConstants.PLAN_ID, componentId)); + + if (result.isPresent()) + return result.get(); + + // TODO may want to block and repeat on new entities joining? + throw new NoSuchElementException("No entity matching id " + componentId+ + (scope==Scope.GLOBAL ? "" : ", in scope "+scope+" wrt "+getEntity()+ + (scopeComponent!=null ? " ("+scopeComponent+" from "+entity()+")" : ""))); + } + } + + // ------------------------------- + + // DSL words which move to a new component + + public DslComponent entity(String scopeOrId) { + return new DslComponent(this, Scope.GLOBAL, scopeOrId); + } + public DslComponent child(String scopeOrId) { + return new DslComponent(this, Scope.CHILD, scopeOrId); + } + public DslComponent sibling(String scopeOrId) { + return new DslComponent(this, Scope.SIBLING, scopeOrId); + } + public DslComponent descendant(String scopeOrId) { + return new DslComponent(this, Scope.DESCENDANT, scopeOrId); + } + public DslComponent ancestor(String scopeOrId) { + return new DslComponent(this, Scope.ANCESTOR, scopeOrId); + } + + @Deprecated /** @deprecated since 0.7.0 */ + public DslComponent component(String scopeOrId) { + return new DslComponent(this, Scope.GLOBAL, scopeOrId); + } + + public DslComponent parent() { + return new DslComponent(this, Scope.PARENT, ""); + } + + public DslComponent component(String scope, String id) { + if (!DslComponent.Scope.isValid(scope)) { + throw new IllegalArgumentException(scope + " is not a vlaid scope"); + } + return new DslComponent(this, DslComponent.Scope.fromString(scope), id); + } + + // DSL words which return things + + public BrooklynDslDeferredSupplier<?> attributeWhenReady(final String sensorName) { + return new AttributeWhenReady(this, sensorName); + } + // class simply makes the memento XML files nicer + protected static class AttributeWhenReady extends BrooklynDslDeferredSupplier<Object> { + private static final long serialVersionUID = 1740899524088902383L; + private final DslComponent component; + private final String sensorName; + public AttributeWhenReady(DslComponent component, String sensorName) { + this.component = Preconditions.checkNotNull(component); + this.sensorName = sensorName; + } + @SuppressWarnings("unchecked") + @Override + public Task<Object> newTask() { + Entity targetEntity = component.get(); + Sensor<?> targetSensor = targetEntity.getEntityType().getSensor(sensorName); + if (!(targetSensor instanceof AttributeSensor<?>)) { + targetSensor = Sensors.newSensor(Object.class, sensorName); + } + return (Task<Object>) DependentConfiguration.attributeWhenReady(targetEntity, (AttributeSensor<?>)targetSensor); + } + @Override + public String toString() { + return (component.scope==Scope.THIS ? "" : component.toString()+".") + + "attributeWhenReady("+JavaStringEscapes.wrapJavaString(sensorName)+")"; + } + } + + public BrooklynDslDeferredSupplier<?> config(final String keyName) { + return new DslConfigSupplier(this, keyName); + } + protected final static class DslConfigSupplier extends BrooklynDslDeferredSupplier<Object> { + private final DslComponent component; + private final String keyName; + private static final long serialVersionUID = -4735177561947722511L; + + public DslConfigSupplier(DslComponent component, String keyName) { + this.component = Preconditions.checkNotNull(component); + this.keyName = keyName; + } + + @Override + public Task<Object> newTask() { + return Tasks.builder().name("retrieving config for "+keyName).tag(BrooklynTaskTags.TRANSIENT_TASK_TAG).dynamic(false).body(new Callable<Object>() { + @Override + public Object call() throws Exception { + Entity targetEntity = component.get(); + return targetEntity.getConfig(ConfigKeys.newConfigKey(Object.class, keyName)); + } + }).build(); + } + + @Override + public String toString() { + return (component.scope==Scope.THIS ? "" : component.toString()+".") + + "config("+JavaStringEscapes.wrapJavaString(keyName)+")"; + } + } + + public BrooklynDslDeferredSupplier<Sensor<?>> sensor(final String sensorName) { + return new DslSensorSupplier(this, sensorName); + } + protected final static class DslSensorSupplier extends BrooklynDslDeferredSupplier<Sensor<?>> { + private final DslComponent component; + private final String sensorName; + private static final long serialVersionUID = -4735177561947722511L; + + public DslSensorSupplier(DslComponent component, String sensorName) { + this.component = Preconditions.checkNotNull(component); + this.sensorName = sensorName; + } + + @Override + public Task<Sensor<?>> newTask() { + return Tasks.<Sensor<?>>builder().name("looking up sensor for "+sensorName).dynamic(false).body(new Callable<Sensor<?>>() { + @Override + public Sensor<?> call() throws Exception { + Entity targetEntity = component.get(); + Sensor<?> result = null; + if (targetEntity!=null) { + result = targetEntity.getEntityType().getSensor(sensorName); + } + if (result!=null) return result; + return Sensors.newSensor(Object.class, sensorName); + } + }).build(); + } + + @Override + public String toString() { + return (component.scope==Scope.THIS ? "" : component.toString()+".") + + "sensor("+JavaStringEscapes.wrapJavaString(sensorName)+")"; + } + } + + public static enum Scope { + GLOBAL ("global"), + CHILD ("child"), + PARENT ("parent"), + SIBLING ("sibling"), + DESCENDANT ("descendant"), + ANCESTOR("ancestor"), + THIS ("this"); + + public static final Set<Scope> VALUES = ImmutableSet.of(GLOBAL, CHILD, PARENT, SIBLING, DESCENDANT, ANCESTOR, THIS); + + private final String name; + + private Scope(String name) { + this.name = name; + } + + public static Scope fromString(String name) { + return tryFromString(name).get(); + } + + public static Maybe<Scope> tryFromString(String name) { + for (Scope scope : VALUES) + if (scope.name.toLowerCase().equals(name.toLowerCase())) + return Maybe.of(scope); + return Maybe.absent(new IllegalArgumentException(name + " is not a valid scope")); + } + + public static boolean isValid(String name) { + for (Scope scope : VALUES) + if (scope.name.toLowerCase().equals(name.toLowerCase())) + return true; + return false; + } + } + + + @Override + public String toString() { + return "$brooklyn:entity("+ + (scopeComponent==null ? "" : JavaStringEscapes.wrapJavaString(scopeComponent.toString())+", ")+ + (scope==Scope.GLOBAL ? "" : JavaStringEscapes.wrapJavaString(scope.toString())+", ")+ + JavaStringEscapes.wrapJavaString(componentId)+ + ")"; + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e406d1ad/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/parse/DslParser.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/parse/DslParser.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/parse/DslParser.java new file mode 100644 index 0000000..345de05 --- /dev/null +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/parse/DslParser.java @@ -0,0 +1,144 @@ +/* + * 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.dsl.parse; + +import java.util.Collection; +import java.util.List; + +import brooklyn.util.collections.MutableList; + +public class DslParser { + private final String expression; + int index = -1; + + public DslParser(String expression) { + this.expression = expression; + } + + public synchronized Object parse() { + if (index>=0) + throw new IllegalStateException("Parser can only be used once"); + + index++; + Object result = next(); + + if (index < expression.length()) + throw new IllegalStateException("Unexpected character at position "+index+" in "+expression); + + return result; + } + + @SuppressWarnings("unchecked") + public Object next() { + int start = index; + + skipWhitespace(); + if (index >= expression.length()) + throw new IllegalStateException("Unexpected end of expression to parse, looking for content since position "+start); + + if (expression.charAt(index)=='"') { + // assume a string + int stringStart = index; + index++; + do { + if (index >= expression.length()) + throw new IllegalStateException("Unexpected end of expression to parse, looking for close quote since position "+stringStart); + char c = expression.charAt(index); + if (c=='"') break; + if (c=='\\') index++; + index++; + } while (true); + index++; + return new QuotedString(expression.substring(stringStart, index)); + } + + // not a string, must be a function (or chain thereof) + List<FunctionWithArgs> result = new MutableList<FunctionWithArgs>(); + + int fnStart = index; + do { + if (index >= expression.length()) + break; + char c = expression.charAt(index); + if (Character.isJavaIdentifierPart(c)) ; + // these chars also permitted + else if (".:".indexOf(c)>=0) ; + // other things e.g. whitespace, parentheses, etc, skip + else break; + index++; + } while (true); + String fn = expression.substring(fnStart, index); + if (fn.length()==0) + throw new IllegalStateException("Expected a function name at position "+start); + skipWhitespace(); + + if (index < expression.length() && expression.charAt(index)=='(') { + // collect arguments + int parenStart = index; + List<Object> args = new MutableList<Object>(); + index ++; + do { + skipWhitespace(); + if (index >= expression.length()) + throw new IllegalStateException("Unexpected end of arguments to function '"+fn+"', no close parenthesis matching character at position "+parenStart); + char c = expression.charAt(index); + if (c==')') break; + if (c==',') { + if (args.isEmpty()) + throw new IllegalStateException("Invalid character at position"+index); + index++; + } else { + if (!args.isEmpty()) + throw new IllegalStateException("Expected , before position"+index); + } + args.add(next()); + } while (true); + result.add(new FunctionWithArgs(fn, args)); + index++; + skipWhitespace(); + if (index >= expression.length()) + return result; + char c = expression.charAt(index); + if (c=='.') { + // chained expression + int chainStart = index; + index++; + Object next = next(); + if (next instanceof List) { + result.addAll((Collection<? extends FunctionWithArgs>) next); + return result; + } else { + throw new IllegalStateException("Expected functions following position"+chainStart); + } + } else { + // following word not something handled at this level; assume parent will handle (or throw) - e.g. a , or extra ) + return result; + } + } else { + // it is just a word; return it with args as null + return new FunctionWithArgs(fn, null); + } + } + + private void skipWhitespace() { + while (index<expression.length() && Character.isWhitespace(expression.charAt(index))) + index++; + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e406d1ad/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/parse/FunctionWithArgs.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/parse/FunctionWithArgs.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/parse/FunctionWithArgs.java new file mode 100644 index 0000000..41bc837 --- /dev/null +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/parse/FunctionWithArgs.java @@ -0,0 +1,57 @@ +/* + * 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.dsl.parse; + +import java.util.List; + +import com.google.common.collect.ImmutableList; + +public class FunctionWithArgs { + private final String function; + private final List<Object> args; + + public FunctionWithArgs(String function, List<Object> args) { + this.function = function; + this.args = args==null ? null : ImmutableList.copyOf(args); + } + + public String getFunction() { + return function; + } + + /** + * arguments (typically {@link QuotedString} or more {@link FunctionWithArgs}). + * + * null means it is a function in a map key which expects map value to be the arguments -- specified without parentheses; + * empty means parentheses already applied, with 0 args. + */ + public List<Object> getArgs() { + return args; + } + + @Override + public String toString() { + return function+(args==null ? "" : args); + } + + public Object arg(int i) { + return args.get(i); + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e406d1ad/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/parse/QuotedString.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/parse/QuotedString.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/parse/QuotedString.java new file mode 100644 index 0000000..8076bfb --- /dev/null +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/parse/QuotedString.java @@ -0,0 +1,49 @@ +/* + * 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.dsl.parse; + +import static com.google.common.base.Preconditions.checkNotNull; +import brooklyn.util.text.StringEscapes.JavaStringEscapes; + +import com.google.common.base.Objects; + +public class QuotedString { + private final String s; + + public QuotedString(String s) { + this.s = checkNotNull(s, "string"); + } + @Override + public String toString() { + return s; + } + public String unwrapped() { + return JavaStringEscapes.unwrapJavaString(s); + } + + @Override + public boolean equals(Object obj) { + return (obj instanceof QuotedString) && ((QuotedString)obj).toString().equals(toString()); + } + + @Override + public int hashCode() { + return Objects.hashCode(s); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e406d1ad/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/lookup/AbstractBrooklynResourceLookup.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/lookup/AbstractBrooklynResourceLookup.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/lookup/AbstractBrooklynResourceLookup.java new file mode 100644 index 0000000..6f4670d --- /dev/null +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/lookup/AbstractBrooklynResourceLookup.java @@ -0,0 +1,36 @@ +/* + * 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.lookup; + +import io.brooklyn.camp.spi.AbstractResource; +import io.brooklyn.camp.spi.PlatformRootSummary; +import io.brooklyn.camp.spi.collection.AbstractResourceLookup; +import brooklyn.management.ManagementContext; + +public abstract class AbstractBrooklynResourceLookup<T extends AbstractResource> extends AbstractResourceLookup<T> { + + protected final PlatformRootSummary root; + protected final ManagementContext bmc; + + public AbstractBrooklynResourceLookup(PlatformRootSummary root, ManagementContext bmc) { + this.root = root; + this.bmc = bmc; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e406d1ad/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/lookup/AbstractTemplateBrooklynLookup.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/lookup/AbstractTemplateBrooklynLookup.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/lookup/AbstractTemplateBrooklynLookup.java new file mode 100644 index 0000000..b7a276c --- /dev/null +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/lookup/AbstractTemplateBrooklynLookup.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.lookup; + +import io.brooklyn.camp.spi.AbstractResource; +import io.brooklyn.camp.spi.PlatformRootSummary; +import io.brooklyn.camp.spi.collection.ResolvableLink; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.brooklyn.catalog.CatalogItem; +import brooklyn.catalog.internal.CatalogUtils; +import brooklyn.entity.Entity; +import brooklyn.entity.proxying.EntitySpec; +import brooklyn.management.ManagementContext; + +public abstract class AbstractTemplateBrooklynLookup<T extends AbstractResource> extends AbstractBrooklynResourceLookup<T> { + + private static final Logger log = LoggerFactory.getLogger(AbstractTemplateBrooklynLookup.class); + + public AbstractTemplateBrooklynLookup(PlatformRootSummary root, ManagementContext bmc) { + super(root, bmc); + } + + @Override + public T get(String id) { + CatalogItem<?,?> item = getCatalogItem(id); + if (item==null) { + log.warn("Could not find item '"+id+"' in Brooklyn catalog; returning null"); + return null; + } + return adapt(item); + } + + private CatalogItem<?, ?> getCatalogItem(String versionedId) { + return CatalogUtils.getCatalogItemOptionalVersion(bmc, versionedId); + } + + public abstract T adapt(CatalogItem<?,?> item); + + protected ResolvableLink<T> newLink(CatalogItem<? extends Entity,EntitySpec<?>> li) { + return newLink(li.getId(), li.getDisplayName()); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e406d1ad/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/lookup/AssemblyBrooklynLookup.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/lookup/AssemblyBrooklynLookup.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/lookup/AssemblyBrooklynLookup.java new file mode 100644 index 0000000..e3130e0 --- /dev/null +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/lookup/AssemblyBrooklynLookup.java @@ -0,0 +1,69 @@ +/* + * 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.lookup; + +import io.brooklyn.camp.spi.Assembly; +import io.brooklyn.camp.spi.PlatformRootSummary; +import io.brooklyn.camp.spi.collection.ResolvableLink; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import brooklyn.entity.Application; +import brooklyn.entity.Entity; +import brooklyn.management.ManagementContext; + + +public class AssemblyBrooklynLookup extends AbstractBrooklynResourceLookup<Assembly> { + + private PlatformComponentBrooklynLookup pcs; + + public AssemblyBrooklynLookup(PlatformRootSummary root, ManagementContext bmc, PlatformComponentBrooklynLookup pcs) { + super(root, bmc); + this.pcs = pcs; + } + + @Override + public Assembly get(String id) { + Entity entity = bmc.getEntityManager().getEntity(id); + if (!(entity instanceof Application)) + throw new IllegalArgumentException("Element for "+id+" is not an Application ("+entity+")"); + Assembly.Builder<? extends Assembly> builder = Assembly.builder() + .created(new Date(entity.getCreationTime())) + .id(entity.getId()) + .name(entity.getDisplayName()); + + builder.customAttribute("externalManagementUri", BrooklynUrlLookup.getUrl(bmc, entity)); + + for (Entity child: entity.getChildren()) + // FIXME this walks the whole damn tree! + builder.add( pcs.get(child.getId() )); + return builder.build(); + } + + @Override + public List<ResolvableLink<Assembly>> links() { + List<ResolvableLink<Assembly>> result = new ArrayList<ResolvableLink<Assembly>>(); + for (Application app: bmc.getApplications()) + result.add(newLink(app.getId(), app.getDisplayName())); + return result; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e406d1ad/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/lookup/AssemblyTemplateBrooklynLookup.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/lookup/AssemblyTemplateBrooklynLookup.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/lookup/AssemblyTemplateBrooklynLookup.java new file mode 100644 index 0000000..1e0d6a1 --- /dev/null +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/lookup/AssemblyTemplateBrooklynLookup.java @@ -0,0 +1,70 @@ +/* + * 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.lookup; + +import io.brooklyn.camp.spi.AssemblyTemplate; +import io.brooklyn.camp.spi.PlatformRootSummary; +import io.brooklyn.camp.spi.collection.ResolvableLink; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.brooklyn.camp.brooklyn.spi.creation.BrooklynAssemblyTemplateInstantiator; +import org.apache.brooklyn.catalog.CatalogItem; +import brooklyn.catalog.CatalogPredicates; +import brooklyn.entity.Application; +import brooklyn.entity.Entity; +import brooklyn.entity.proxying.EntitySpec; +import brooklyn.management.ManagementContext; + +public class AssemblyTemplateBrooklynLookup extends AbstractTemplateBrooklynLookup<AssemblyTemplate> { + + public AssemblyTemplateBrooklynLookup(PlatformRootSummary root, ManagementContext bmc) { + super(root, bmc); + } + + @Override + public AssemblyTemplate adapt(CatalogItem<?,?> item) { + return AssemblyTemplate.builder(). + name(item.getDisplayName()). + id(item.getId()). + description(item.getDescription()). + created(root.getCreated()). + instantiator(BrooklynAssemblyTemplateInstantiator.class). + build(); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + // why can I not pass an EntitySpec<? extends Application> to newLink(EntitySpec<?> spec) ? + // feels to me (alexheneveld) that `? extends Application` should be both covariant and contravariant to `?` .. + // but it's not, so we introduce this conversion method + protected ResolvableLink<AssemblyTemplate> newApplicationLink(CatalogItem<? extends Entity, EntitySpec<? extends Application>> li) { + return super.newLink((CatalogItem)li); + } + + @Override + public List<ResolvableLink<AssemblyTemplate>> links() { + Iterable<CatalogItem<Application,EntitySpec<? extends Application>>> l = bmc.getCatalog().getCatalogItems(CatalogPredicates.IS_TEMPLATE); + List<ResolvableLink<AssemblyTemplate>> result = new ArrayList<ResolvableLink<AssemblyTemplate>>(); + for (CatalogItem<Application,EntitySpec<? extends Application>> li: l) + result.add(newApplicationLink(li)); + return result; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e406d1ad/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/lookup/BrooklynUrlLookup.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/lookup/BrooklynUrlLookup.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/lookup/BrooklynUrlLookup.java new file mode 100644 index 0000000..f9bc390 --- /dev/null +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/lookup/BrooklynUrlLookup.java @@ -0,0 +1,38 @@ +/* + * 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.lookup; + +import brooklyn.config.ConfigKey; +import brooklyn.entity.Entity; +import brooklyn.entity.basic.ConfigKeys; +import brooklyn.management.ManagementContext; +import brooklyn.util.net.Urls; + +public class BrooklynUrlLookup { + + public static ConfigKey<String> BROOKLYN_ROOT_URL = ConfigKeys.newStringConfigKey("brooklyn.root.url"); + + public static String getUrl(ManagementContext bmc, Entity entity) { + String root = bmc.getConfig().getConfig(BROOKLYN_ROOT_URL); + if (root==null) return null; + return Urls.mergePaths(root, "#/", + "/v1/applications/"+entity.getApplicationId()+"/entities/"+entity.getId()); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e406d1ad/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/lookup/PlatformComponentBrooklynLookup.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/lookup/PlatformComponentBrooklynLookup.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/lookup/PlatformComponentBrooklynLookup.java new file mode 100644 index 0000000..6b26849 --- /dev/null +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/lookup/PlatformComponentBrooklynLookup.java @@ -0,0 +1,61 @@ +/* + * 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.lookup; + +import io.brooklyn.camp.spi.PlatformComponent; +import io.brooklyn.camp.spi.PlatformComponent.Builder; +import io.brooklyn.camp.spi.PlatformRootSummary; +import io.brooklyn.camp.spi.collection.ResolvableLink; + +import java.util.Collections; +import java.util.Date; +import java.util.List; + +import brooklyn.entity.Entity; +import brooklyn.management.ManagementContext; + + +public class PlatformComponentBrooklynLookup extends AbstractBrooklynResourceLookup<PlatformComponent> { + + public PlatformComponentBrooklynLookup(PlatformRootSummary root, ManagementContext bmc) { + super(root, bmc); + } + + @Override + public PlatformComponent get(String id) { + Entity entity = bmc.getEntityManager().getEntity(id); + Builder<? extends PlatformComponent> builder = PlatformComponent.builder() + .created(new Date(entity.getCreationTime())) + .id(entity.getId()) + .name(entity.getDisplayName()) + .externalManagementUri(BrooklynUrlLookup.getUrl(bmc, entity)); + + for (Entity child: entity.getChildren()) + // FIXME this walks the whole damn tree! + builder.add( get(child.getId() )); + return builder.build(); + } + + // platform components are not listed at the top level -- you have to walk the assemblies + @Override + public List<ResolvableLink<PlatformComponent>> links() { + return Collections.emptyList(); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e406d1ad/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/lookup/PlatformComponentTemplateBrooklynLookup.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/lookup/PlatformComponentTemplateBrooklynLookup.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/lookup/PlatformComponentTemplateBrooklynLookup.java new file mode 100644 index 0000000..b990464 --- /dev/null +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/lookup/PlatformComponentTemplateBrooklynLookup.java @@ -0,0 +1,59 @@ +/* + * 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.lookup; + +import io.brooklyn.camp.spi.PlatformComponentTemplate; +import io.brooklyn.camp.spi.PlatformRootSummary; +import io.brooklyn.camp.spi.collection.ResolvableLink; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.brooklyn.catalog.CatalogItem; +import brooklyn.catalog.CatalogPredicates; +import brooklyn.entity.Entity; +import brooklyn.entity.proxying.EntitySpec; +import brooklyn.management.ManagementContext; + +public class PlatformComponentTemplateBrooklynLookup extends AbstractTemplateBrooklynLookup<PlatformComponentTemplate> { + + public PlatformComponentTemplateBrooklynLookup(PlatformRootSummary root, ManagementContext bmc) { + super(root, bmc); + } + + @Override + public PlatformComponentTemplate adapt(CatalogItem<?,?> item) { + return PlatformComponentTemplate.builder(). + name(item.getDisplayName()). + id(item.getId()). + description(item.getDescription()). + created(root.getCreated()). + build(); + } + + @Override + public List<ResolvableLink<PlatformComponentTemplate>> links() { + Iterable<CatalogItem<Entity,EntitySpec<?>>> l = bmc.getCatalog().getCatalogItems(CatalogPredicates.IS_ENTITY); + List<ResolvableLink<PlatformComponentTemplate>> result = new ArrayList<ResolvableLink<PlatformComponentTemplate>>(); + for (CatalogItem<Entity,EntitySpec<?>> li: l) + result.add(newLink(li)); + return result; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e406d1ad/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/platform/BrooklynImmutableCampPlatform.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/platform/BrooklynImmutableCampPlatform.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/platform/BrooklynImmutableCampPlatform.java new file mode 100644 index 0000000..c04c134 --- /dev/null +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/platform/BrooklynImmutableCampPlatform.java @@ -0,0 +1,109 @@ +/* + * 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.platform; + +import io.brooklyn.camp.CampPlatform; +import io.brooklyn.camp.spi.ApplicationComponent; +import io.brooklyn.camp.spi.ApplicationComponentTemplate; +import io.brooklyn.camp.spi.Assembly; +import io.brooklyn.camp.spi.AssemblyTemplate; +import io.brooklyn.camp.spi.PlatformComponent; +import io.brooklyn.camp.spi.PlatformComponentTemplate; +import io.brooklyn.camp.spi.PlatformRootSummary; +import io.brooklyn.camp.spi.PlatformTransaction; +import io.brooklyn.camp.spi.collection.BasicResourceLookup; +import io.brooklyn.camp.spi.collection.ResourceLookup; +import io.brooklyn.camp.spi.collection.ResourceLookup.EmptyResourceLookup; + +import org.apache.brooklyn.camp.brooklyn.spi.lookup.AssemblyBrooklynLookup; +import org.apache.brooklyn.camp.brooklyn.spi.lookup.AssemblyTemplateBrooklynLookup; +import org.apache.brooklyn.camp.brooklyn.spi.lookup.PlatformComponentBrooklynLookup; +import org.apache.brooklyn.camp.brooklyn.spi.lookup.PlatformComponentTemplateBrooklynLookup; + +import brooklyn.camp.brooklyn.api.HasBrooklynManagementContext; +import brooklyn.management.ManagementContext; + +/** Immutable CAMP platform which reflects things in the underlying Brooklyn system */ +public class BrooklynImmutableCampPlatform extends CampPlatform implements HasBrooklynManagementContext { + + private final ManagementContext bmc; + private final AssemblyTemplateBrooklynLookup ats; + private final PlatformComponentTemplateBrooklynLookup pcts; + private final BasicResourceLookup<ApplicationComponentTemplate> acts; + private final PlatformComponentBrooklynLookup pcs; + private final AssemblyBrooklynLookup assemblies; + + public BrooklynImmutableCampPlatform(PlatformRootSummary root, ManagementContext managementContext) { + super(root); + this.bmc = managementContext; + + // these come from brooklyn + pcts = new PlatformComponentTemplateBrooklynLookup(root(), getBrooklynManagementContext()); + ats = new AssemblyTemplateBrooklynLookup(root(), getBrooklynManagementContext()); + pcs = new PlatformComponentBrooklynLookup(root(), getBrooklynManagementContext()); + assemblies = new AssemblyBrooklynLookup(root(), getBrooklynManagementContext(), pcs); + + // ACT's are not known in brooklyn (everything comes in as config) -- to be extended to support! + acts = new BasicResourceLookup<ApplicationComponentTemplate>(); + } + + // --- brooklyn setup + + public ManagementContext getBrooklynManagementContext() { + return bmc; + } + + // --- camp comatibility setup + + @Override + public ResourceLookup<PlatformComponentTemplate> platformComponentTemplates() { + return pcts; + } + + @Override + public ResourceLookup<ApplicationComponentTemplate> applicationComponentTemplates() { + return acts; + } + + @Override + public ResourceLookup<AssemblyTemplate> assemblyTemplates() { + return ats; + } + + @Override + public ResourceLookup<PlatformComponent> platformComponents() { + return pcs; + } + + @Override + public ResourceLookup<ApplicationComponent> applicationComponents() { + return new EmptyResourceLookup<ApplicationComponent>(); + } + + @Override + public ResourceLookup<Assembly> assemblies() { + return assemblies; + } + + @Override + public PlatformTransaction transaction() { + throw new IllegalStateException(this+" does not support adding new items"); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e406d1ad/usage/camp/src/main/resources/META-INF/services/io.brooklyn.camp.brooklyn.spi.creation.service.ServiceTypeResolver ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/resources/META-INF/services/io.brooklyn.camp.brooklyn.spi.creation.service.ServiceTypeResolver b/usage/camp/src/main/resources/META-INF/services/io.brooklyn.camp.brooklyn.spi.creation.service.ServiceTypeResolver deleted file mode 100644 index 1a48ccb..0000000 --- a/usage/camp/src/main/resources/META-INF/services/io.brooklyn.camp.brooklyn.spi.creation.service.ServiceTypeResolver +++ /dev/null @@ -1,22 +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. -# -io.brooklyn.camp.brooklyn.spi.creation.service.BrooklynServiceTypeResolver -io.brooklyn.camp.brooklyn.spi.creation.service.CatalogServiceTypeResolver -io.brooklyn.camp.brooklyn.spi.creation.service.ChefServiceTypeResolver -io.brooklyn.camp.brooklyn.spi.creation.service.JavaServiceTypeResolver http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e406d1ad/usage/camp/src/main/resources/META-INF/services/org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceTypeResolver ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/resources/META-INF/services/org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceTypeResolver b/usage/camp/src/main/resources/META-INF/services/org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceTypeResolver new file mode 100644 index 0000000..9c941df --- /dev/null +++ b/usage/camp/src/main/resources/META-INF/services/org.apache.brooklyn.camp.brooklyn.spi.creation.service.ServiceTypeResolver @@ -0,0 +1,22 @@ +# +# 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.camp.brooklyn.spi.creation.service.BrooklynServiceTypeResolver +org.apache.brooklyn.camp.brooklyn.spi.creation.service.CatalogServiceTypeResolver +org.apache.brooklyn.camp.brooklyn.spi.creation.service.ChefServiceTypeResolver +org.apache.brooklyn.camp.brooklyn.spi.creation.service.JavaServiceTypeResolver http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e406d1ad/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java deleted file mode 100644 index 226ec67..0000000 --- a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java +++ /dev/null @@ -1,206 +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 io.brooklyn.camp.brooklyn; - -import io.brooklyn.camp.spi.Assembly; -import io.brooklyn.camp.spi.AssemblyTemplate; - -import java.io.Reader; -import java.io.StringReader; -import java.util.Set; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; - -import brooklyn.catalog.internal.CatalogUtils; -import brooklyn.entity.Entity; -import brooklyn.entity.basic.BrooklynTaskTags; -import brooklyn.entity.basic.Entities; -import brooklyn.entity.basic.StartableApplication; -import brooklyn.entity.rebind.RebindOptions; -import brooklyn.entity.rebind.RebindTestFixture; -import brooklyn.management.ManagementContext; -import brooklyn.management.Task; -import brooklyn.management.internal.LocalManagementContext; -import brooklyn.util.ResourceUtils; -import brooklyn.util.config.ConfigBag; - -import com.google.common.base.Joiner; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Iterables; - -public class AbstractYamlRebindTest extends RebindTestFixture<StartableApplication> { - - private static final Logger LOG = LoggerFactory.getLogger(AbstractYamlTest.class); - protected static final String TEST_VERSION = "0.1.2"; - - protected BrooklynCampPlatform platform; - protected BrooklynCampPlatformLauncherNoServer launcher; - private boolean forceUpdate; - - @BeforeMethod(alwaysRun = true) - @Override - public void setUp() throws Exception { - super.setUp(); - launcher = new BrooklynCampPlatformLauncherNoServer() { - @Override - protected LocalManagementContext newMgmtContext() { - return (LocalManagementContext) mgmt(); - } - }; - launcher.launch(); - platform = launcher.getCampPlatform(); - } - - @AfterMethod(alwaysRun = true) - @Override - public void tearDown() throws Exception { - try { - super.tearDown(); - } finally { - if (launcher != null) launcher.stopServers(); - } - } - - protected StartableApplication rebind(RebindOptions options) throws Exception { - StartableApplication result = super.rebind(options); - if (launcher != null) { - launcher.stopServers(); - launcher = new BrooklynCampPlatformLauncherNoServer() { - @Override - protected LocalManagementContext newMgmtContext() { - return (LocalManagementContext) mgmt(); - } - }; - launcher.launch(); - platform = launcher.getCampPlatform(); - } - return result; - } - - @Override - protected StartableApplication createApp() { - return null; - } - - protected ManagementContext mgmt() { - return (newManagementContext != null) ? newManagementContext : origManagementContext; - } - - /////////////////////////////////////////////////// - // TODO code below is duplicate of AbstractYamlTest - /////////////////////////////////////////////////// - - protected void waitForApplicationTasks(Entity app) { - Set<Task<?>> tasks = BrooklynTaskTags.getTasksInEntityContext(origManagementContext.getExecutionManager(), app); - getLogger().info("Waiting on " + tasks.size() + " task(s)"); - for (Task<?> t : tasks) { - t.blockUntilEnded(); - } - } - - protected Reader loadYaml(String yamlFileName, String ...extraLines) throws Exception { - String input = new ResourceUtils(this).getResourceAsString(yamlFileName).trim(); - StringBuilder builder = new StringBuilder(input); - for (String l: extraLines) - builder.append("\n").append(l); - return new StringReader(builder.toString()); - } - - protected Entity createAndStartApplication(String... multiLineYaml) throws Exception { - return createAndStartApplication(joinLines(multiLineYaml)); - } - - protected Entity createAndStartApplication(String input) throws Exception { - return createAndStartApplication(new StringReader(input)); - } - - protected Entity createAndStartApplication(Reader input) throws Exception { - AssemblyTemplate at = platform.pdp().registerDeploymentPlan(input); - Assembly assembly; - try { - assembly = at.getInstantiator().newInstance().instantiate(at, platform); - } catch (Exception e) { - getLogger().warn("Unable to instantiate " + at + " (rethrowing): " + e); - throw e; - } - getLogger().info("Test - created " + assembly); - final Entity app = origManagementContext.getEntityManager().getEntity(assembly.getId()); - getLogger().info("App - " + app); - - // wait for app to have started - Set<Task<?>> tasks = origManagementContext.getExecutionManager().getTasksWithAllTags(ImmutableList.of( - BrooklynTaskTags.EFFECTOR_TAG, - BrooklynTaskTags.tagForContextEntity(app), - BrooklynTaskTags.tagForEffectorCall(app, "start", ConfigBag.newInstance(ImmutableMap.of("locations", ImmutableMap.of()))))); - Iterables.getOnlyElement(tasks).get(); - - return app; - } - - protected Entity createStartWaitAndLogApplication(Reader input) throws Exception { - Entity app = createAndStartApplication(input); - waitForApplicationTasks(app); - - getLogger().info("App started:"); - Entities.dumpInfo(app); - - return app; - } - - protected void addCatalogItems(Iterable<String> catalogYaml) { - addCatalogItems(joinLines(catalogYaml)); - } - - protected void addCatalogItems(String... catalogYaml) { - addCatalogItems(joinLines(catalogYaml)); - } - - protected void addCatalogItems(String catalogYaml) { - mgmt().getCatalog().addItems(catalogYaml, forceUpdate); - } - - protected void deleteCatalogEntity(String catalogItem) { - mgmt().getCatalog().deleteCatalogItem(catalogItem, TEST_VERSION); - } - - protected Logger getLogger() { - return LOG; - } - - private String joinLines(Iterable<String> catalogYaml) { - return Joiner.on("\n").join(catalogYaml); - } - - private String joinLines(String[] catalogYaml) { - return Joiner.on("\n").join(catalogYaml); - } - - protected String ver(String id) { - return CatalogUtils.getVersionedId(id, TEST_VERSION); - } - - public void forceCatalogUpdate() { - forceUpdate = true; - } - -}
