You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2015/08/20 00:53:55 UTC
[07/36] incubator-brooklyn git commit: Rename o.a.b.effector.core to
o.a.b.core.effector
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/effector/core/Effectors.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/effector/core/Effectors.java b/core/src/main/java/org/apache/brooklyn/effector/core/Effectors.java
deleted file mode 100644
index 7f7bed4..0000000
--- a/core/src/main/java/org/apache/brooklyn/effector/core/Effectors.java
+++ /dev/null
@@ -1,202 +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.effector.core;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.annotation.Nullable;
-
-import org.apache.brooklyn.api.effector.Effector;
-import org.apache.brooklyn.api.effector.ParameterType;
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.mgmt.TaskAdaptable;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.effector.core.EffectorTasks.EffectorBodyTaskFactory;
-import org.apache.brooklyn.effector.core.EffectorTasks.EffectorMarkingTaskFactory;
-import org.apache.brooklyn.effector.core.EffectorTasks.EffectorTaskFactory;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.core.config.ConfigBag;
-import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.text.Strings;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Objects;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
-public class Effectors {
-
- private static final Logger log = LoggerFactory.getLogger(Effectors.class);
-
- public static class EffectorBuilder<T> {
- private Class<T> returnType;
- private String effectorName;
- private String description;
- private Map<String,ParameterType<?>> parameters = new LinkedHashMap<String,ParameterType<?>>();
- private EffectorTaskFactory<T> impl;
-
- private EffectorBuilder(Class<T> returnType, String effectorName) {
- this.returnType = returnType;
- this.effectorName = effectorName;
- }
- public EffectorBuilder<T> description(String description) {
- this.description = description;
- return this;
- }
- public EffectorBuilder<T> parameter(Class<?> paramType, String paramName) {
- return parameter(paramType, paramName, null, null);
- }
- public EffectorBuilder<T> parameter(Class<?> paramType, String paramName, String paramDescription) {
- return parameter(paramType, paramName, paramDescription, null);
- }
- public <V> EffectorBuilder<T> parameter(Class<V> paramType, String paramName, String paramDescription, V defaultValue) {
- return parameter(new BasicParameterType<V>(paramName, paramType, paramDescription, defaultValue));
- }
- public <V> EffectorBuilder<T> parameter(ConfigKey<V> key) {
- return parameter(asParameterType(key));
- }
- public EffectorBuilder<T> parameter(ParameterType<?> p) {
- // allow redeclaring, e.g. for the case where we are overriding an existing effector
- parameters.put(p.getName(), p);
- return this;
- }
- public EffectorBuilder<T> impl(EffectorTaskFactory<T> taskFactory) {
- this.impl = new EffectorMarkingTaskFactory<T>(taskFactory);
- return this;
- }
- public EffectorBuilder<T> impl(EffectorBody<T> effectorBody) {
- this.impl = new EffectorBodyTaskFactory<T>(effectorBody);
- return this;
- }
- /** returns the effector, with an implementation (required); @see {@link #buildAbstract()} */
- public Effector<T> build() {
- Preconditions.checkNotNull(impl, "Cannot create effector %s with no impl (did you forget impl? or did you mean to buildAbstract?)", effectorName);
- return new EffectorAndBody<T>(effectorName, returnType, ImmutableList.copyOf(parameters.values()), description, impl);
- }
-
- /** returns an abstract effector, where the body will be defined later/elsewhere
- * (impl must not be set) */
- public Effector<T> buildAbstract() {
- Preconditions.checkArgument(impl==null, "Cannot create abstract effector {} as an impl is defined", effectorName);
- return new EffectorBase<T>(effectorName, returnType, ImmutableList.copyOf(parameters.values()), description);
- }
- }
-
- /** creates a new effector builder with the given name and return type */
- public static <T> EffectorBuilder<T> effector(Class<T> returnType, String effectorName) {
- return new EffectorBuilder<T>(returnType, effectorName);
- }
-
- /** creates a new effector builder to _override_ the given effector */
- public static <T> EffectorBuilder<T> effector(Effector<T> base) {
- EffectorBuilder<T> builder = new EffectorBuilder<T>(base.getReturnType(), base.getName());
- for (ParameterType<?> p: base.getParameters())
- builder.parameter(p);
- builder.description(base.getDescription());
- if (base instanceof EffectorWithBody)
- builder.impl(((EffectorWithBody<T>) base).getBody());
- return builder;
- }
-
- /** as {@link #invocation(Entity, Effector, Map)} but convenience for passing a {@link ConfigBag} */
- public static <T> TaskAdaptable<T> invocation(Entity entity, Effector<T> eff, ConfigBag parameters) {
- return invocation(entity, eff, parameters==null ? ImmutableMap.of() : parameters.getAllConfig());
- }
-
- /** returns an unsubmitted task which invokes the given effector; use {@link Entities#invokeEffector(EntityLocal, Entity, Effector, Map)} for a submitted variant */
- public static <T> TaskAdaptable<T> invocation(Entity entity, Effector<T> eff, @Nullable Map<?,?> parameters) {
- @SuppressWarnings("unchecked")
- Effector<T> eff2 = (Effector<T>) ((EntityInternal)entity).getEffector(eff.getName());
- if (log.isTraceEnabled()) {
- Object eff1Body = (eff instanceof EffectorWithBody<?> ? ((EffectorWithBody<?>) eff).getBody() : "bodyless");
- String message = String.format("Invoking %s/%s on entity %s", eff, eff1Body, entity);
- if (eff != eff2) {
- Object eff2Body = (eff2 instanceof EffectorWithBody<?> ? ((EffectorWithBody<?>) eff2).getBody() : "bodyless");
- message += String.format(" (actually %s/%s)", eff2, eff2Body);
- }
- log.trace(message);
- }
- if (eff2 != null) {
- if (eff2 != eff) {
- if (eff2 instanceof EffectorWithBody) {
- log.debug("Replacing invocation of {} on {} with {} which is the impl defined at that entity", new Object[] { eff, entity, eff2 });
- return ((EffectorWithBody<T>)eff2).getBody().newTask(entity, eff2, ConfigBag.newInstance().putAll(parameters));
- } else {
- log.warn("Effector {} defined on {} has no body; invoking caller-supplied {} instead", new Object[] { eff2, entity, eff });
- }
- }
- } else {
- log.debug("Effector {} does not exist on {}; attempting to invoke anyway", new Object[] { eff, entity });
- }
-
- if (eff instanceof EffectorWithBody) {
- return ((EffectorWithBody<T>)eff).getBody().newTask(entity, eff, ConfigBag.newInstance().putAll(parameters));
- }
-
- throw new UnsupportedOperationException("No implementation registered for effector "+eff+" on "+entity);
- }
-
- @SuppressWarnings({ "unchecked", "rawtypes" })
- public static <V> ParameterType<V> asParameterType(ConfigKey<V> key) {
- return key.hasDefaultValue()
- ? new BasicParameterType<V>(key.getName(), (Class)key.getType(), key.getDescription(), key.getDefaultValue())
- : new BasicParameterType<V>(key.getName(), (Class)key.getType(), key.getDescription());
- }
-
- public static <V> ConfigKey<V> asConfigKey(ParameterType<V> paramType) {
- return ConfigKeys.newConfigKey(paramType.getParameterClass(), paramType.getName(), paramType.getDescription(), paramType.getDefaultValue());
- }
-
- /** returns an unsubmitted task which will invoke the given effector on the given entities;
- * return type is Task<List<T>> (but haven't put in the blood sweat toil and tears to make the generics work) */
- public static TaskAdaptable<List<?>> invocation(Effector<?> eff, Map<?,?> params, Iterable<? extends Entity> entities) {
- List<TaskAdaptable<?>> tasks = new ArrayList<TaskAdaptable<?>>();
- for (Entity e: entities) tasks.add(invocation(e, eff, params));
- return Tasks.parallel("invoking "+eff+" on "+tasks.size()+" node"+(Strings.s(tasks.size())), tasks.toArray(new TaskAdaptable[tasks.size()]));
- }
-
- /** returns an unsubmitted task which will invoke the given effector on the given entities
- * (this form of method is a convenience for {@link #invocation(Effector, Map, Iterable)}) */
- public static TaskAdaptable<List<?>> invocation(Effector<?> eff, MutableMap<?, ?> params, Entity ...entities) {
- return invocation(eff, params, Arrays.asList(entities));
- }
-
- public static boolean sameSignature(Effector<?> e1, Effector<?> e2) {
- return Objects.equal(e1.getName(), e2.getName()) &&
- Objects.equal(e1.getParameters(), e2.getParameters()) &&
- Objects.equal(e1.getReturnType(), e2.getReturnType());
- }
-
- // TODO sameSignatureAndBody
-
- public static boolean sameInstance(Effector<?> e1, Effector<?> e2) {
- return e1 == e2;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/effector/core/ExplicitEffector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/effector/core/ExplicitEffector.java b/core/src/main/java/org/apache/brooklyn/effector/core/ExplicitEffector.java
deleted file mode 100644
index 46b19ea..0000000
--- a/core/src/main/java/org/apache/brooklyn/effector/core/ExplicitEffector.java
+++ /dev/null
@@ -1,74 +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.effector.core;
-
-import groovy.lang.Closure;
-
-import java.util.List;
-import java.util.Map;
-
-import org.apache.brooklyn.api.effector.ParameterType;
-import org.apache.brooklyn.api.entity.Entity;
-
-import com.google.common.base.Objects;
-import com.google.common.collect.ImmutableList;
-
-public abstract class ExplicitEffector<I,T> extends AbstractEffector<T> {
- public ExplicitEffector(String name, Class<T> type, String description) {
- this(name, type, ImmutableList.<ParameterType<?>>of(), description);
- }
- public ExplicitEffector(String name, Class<T> type, List<ParameterType<?>> parameters, String description) {
- super(name, type, parameters, description);
- }
-
- public T call(Entity entity, Map parameters) {
- return invokeEffector((I) entity, (Map<String,?>)parameters );
- }
-
- public abstract T invokeEffector(I trait, Map<String,?> parameters);
-
- /** convenience to create an effector supplying a closure; annotations are preferred,
- * and subclass here would be failback, but this is offered as
- * workaround for bug GROOVY-5122, as discussed in test class CanSayHi
- */
- public static <I,T> ExplicitEffector<I,T> create(String name, Class<T> type, List<ParameterType<?>> parameters, String description, Closure body) {
- return new ExplicitEffectorFromClosure<I,T>(name, type, parameters, description, body);
- }
-
- private static class ExplicitEffectorFromClosure<I,T> extends ExplicitEffector<I,T> {
- private static final long serialVersionUID = -5771188171702382236L;
- final Closure<T> body;
- public ExplicitEffectorFromClosure(String name, Class<T> type, List<ParameterType<?>> parameters, String description, Closure<T> body) {
- super(name, type, parameters, description);
- this.body = body;
- }
- public T invokeEffector(I trait, Map<String,?> parameters) { return body.call(trait, parameters); }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(super.hashCode(), body);
- }
-
- @Override
- public boolean equals(Object other) {
- return super.equals(other) && Objects.equal(body, ((ExplicitEffectorFromClosure<?,?>)other).body);
- }
-
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/effector/core/MethodEffector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/effector/core/MethodEffector.java b/core/src/main/java/org/apache/brooklyn/effector/core/MethodEffector.java
deleted file mode 100644
index 7dd0828..0000000
--- a/core/src/main/java/org/apache/brooklyn/effector/core/MethodEffector.java
+++ /dev/null
@@ -1,180 +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.effector.core;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.brooklyn.api.effector.Effector;
-import org.apache.brooklyn.api.effector.ParameterType;
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.core.annotation.EffectorParam;
-import org.apache.brooklyn.core.entity.AbstractEntity;
-import org.apache.brooklyn.core.mgmt.internal.EffectorUtils;
-import org.apache.brooklyn.util.core.flags.TypeCoercions;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.apache.brooklyn.util.groovy.GroovyJavaMethods;
-import org.codehaus.groovy.runtime.MethodClosure;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.Lists;
-
-/** concrete class for providing an Effector implementation that gets its information from annotations on a method;
- * see Effector*Test for usage example.
- * <p>
- * note that the method must be on an interface in order for it to be remoted, with the current implementation.
- * see comments in {@link #call(Entity, Map)} for more details.
- */
-public class MethodEffector<T> extends AbstractEffector<T> {
-
- private static final long serialVersionUID = 6989688364011965968L;
- private static final Logger log = LoggerFactory.getLogger(MethodEffector.class);
-
- @SuppressWarnings("rawtypes")
- public static Effector<?> create(Method m) {
- return new MethodEffector(m);
- }
-
- protected static class AnnotationsOnMethod {
- final Class<?> clazz;
- final String name;
- final String description;
- final Class<?> returnType;
- final List<ParameterType<?>> parameters;
-
- public AnnotationsOnMethod(Class<?> clazz, String methodName) {
- this(clazz, inferBestMethod(clazz, methodName));
- }
-
- public AnnotationsOnMethod(Class<?> clazz, Method method) {
- this.clazz = clazz;
- this.name = method.getName();
- this.returnType = method.getReturnType();
-
- // Get the description
- org.apache.brooklyn.core.annotation.Effector effectorAnnotation = method.getAnnotation(org.apache.brooklyn.core.annotation.Effector.class);
- description = (effectorAnnotation != null) ? effectorAnnotation.description() : null;
-
- // Get the parameters
- parameters = Lists.newArrayList();
- int numParameters = method.getParameterTypes().length;
- for (int i = 0; i < numParameters; i++) {
- parameters.add(toParameterType(method, i));
- }
- }
-
- @SuppressWarnings({ "rawtypes", "unchecked" })
- protected static ParameterType<?> toParameterType(Method method, int paramIndex) {
- Annotation[] anns = method.getParameterAnnotations()[paramIndex];
- Class<?> type = method.getParameterTypes()[paramIndex];
- EffectorParam paramAnnotation = findAnnotation(anns, EffectorParam.class);
-
- // TODO if blank, could do "param"+(i+1); would that be better?
- // TODO this will now give "" if name is blank, rather than previously null. Is that ok?!
- String name = (paramAnnotation != null) ? paramAnnotation.name() : null;
-
- String paramDescription = (paramAnnotation == null || EffectorParam.MAGIC_STRING_MEANING_NULL.equals(paramAnnotation.description())) ? null : paramAnnotation.description();
- String description = (paramDescription != null) ? paramDescription : null;
-
- String paramDefaultValue = (paramAnnotation == null || EffectorParam.MAGIC_STRING_MEANING_NULL.equals(paramAnnotation.defaultValue())) ? null : paramAnnotation.defaultValue();
- Object defaultValue = (paramDefaultValue != null) ? TypeCoercions.coerce(paramDefaultValue, type) : null;
-
- return new BasicParameterType(name, type, description, defaultValue);
- }
-
- @SuppressWarnings("unchecked")
- protected static <T extends Annotation> T findAnnotation(Annotation[] anns, Class<T> type) {
- for (Annotation ann : anns) {
- if (type.isInstance(ann)) return (T) ann;
- }
- return null;
- }
-
- protected static Method inferBestMethod(Class<?> clazz, String methodName) {
- Method best = null;
- for (Method it : clazz.getMethods()) {
- if (it.getName().equals(methodName)) {
- if (best==null || best.getParameterTypes().length < it.getParameterTypes().length) best=it;
- }
- }
- if (best==null) {
- throw new IllegalStateException("Cannot find method "+methodName+" on "+clazz.getCanonicalName());
- }
- return best;
- }
- }
-
- /** Defines a new effector whose details are supplied as annotations on the given type and method name */
- public MethodEffector(Class<?> whereEffectorDefined, String methodName) {
- this(new AnnotationsOnMethod(whereEffectorDefined, methodName), null);
- }
-
- public MethodEffector(Method method) {
- this(new AnnotationsOnMethod(method.getDeclaringClass(), method), null);
- }
-
- public MethodEffector(MethodClosure mc) {
- this(new AnnotationsOnMethod((Class<?>)mc.getDelegate(), mc.getMethod()), null);
- }
-
- @SuppressWarnings("unchecked")
- protected MethodEffector(AnnotationsOnMethod anns, String description) {
- super(anns.name, (Class<T>)anns.returnType, anns.parameters, GroovyJavaMethods.<String>elvis(description, anns.description));
- }
-
- @SuppressWarnings({ "rawtypes", "unchecked" })
- public T call(Entity entity, Map parameters) {
- Object[] parametersArray = EffectorUtils.prepareArgsForEffector(this, parameters);
- if (entity instanceof AbstractEntity) {
- return EffectorUtils.invokeMethodEffector(entity, this, parametersArray);
- } else {
- // we are dealing with a proxy here
- // this implementation invokes the method on the proxy
- // (requiring it to be on the interface)
- // and letting the proxy deal with the remoting / runAtEntity;
- // alternatively we could create the task here and pass it to runAtEntity;
- // the latter may allow us to simplify/remove a lot of the stuff from
- // EffectorUtils and possibly Effectors and Entities
-
- // TODO Should really find method with right signature, rather than just the right args.
- // TODO prepareArgs can miss things out that have "default values"! Code below will probably fail if that happens.
- Method[] methods = entity.getClass().getMethods();
- for (Method method : methods) {
- if (method.getName().equals(getName())) {
- if (parametersArray.length == method.getParameterTypes().length) {
- try {
- return (T) method.invoke(entity, parametersArray);
- } catch (Exception e) {
- // exception handled by the proxy invocation (which leads to EffectorUtils.invokeEffectorMethod...)
- throw Exceptions.propagate(e);
- }
- }
- }
- }
- String msg = "Could not find method for effector "+getName()+" with "+parametersArray.length+" parameters on "+entity;
- log.warn(msg+" (throwing); available methods are: "+Arrays.toString(methods));
- throw new IllegalStateException(msg);
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/effector/core/ssh/SshEffectorTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/effector/core/ssh/SshEffectorTasks.java b/core/src/main/java/org/apache/brooklyn/effector/core/ssh/SshEffectorTasks.java
deleted file mode 100644
index b904ba7..0000000
--- a/core/src/main/java/org/apache/brooklyn/effector/core/ssh/SshEffectorTasks.java
+++ /dev/null
@@ -1,334 +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.effector.core.ssh;
-
-import java.util.List;
-import java.util.Map;
-
-import javax.annotation.Nullable;
-
-import org.apache.brooklyn.api.effector.Effector;
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.api.mgmt.Task;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.config.StringConfigMap;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.config.ConfigUtils;
-import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.core.location.internal.LocationInternal;
-import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
-import org.apache.brooklyn.effector.core.EffectorBody;
-import org.apache.brooklyn.effector.core.EffectorTasks;
-import org.apache.brooklyn.effector.core.EffectorTasks.EffectorTaskFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.util.core.config.ConfigBag;
-import org.apache.brooklyn.util.core.internal.ssh.SshTool;
-import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.core.task.ssh.SshFetchTaskFactory;
-import org.apache.brooklyn.util.core.task.ssh.SshFetchTaskWrapper;
-import org.apache.brooklyn.util.core.task.ssh.SshPutTaskFactory;
-import org.apache.brooklyn.util.core.task.ssh.SshPutTaskWrapper;
-import org.apache.brooklyn.util.core.task.ssh.SshTasks;
-import org.apache.brooklyn.util.core.task.ssh.internal.AbstractSshExecTaskFactory;
-import org.apache.brooklyn.util.core.task.ssh.internal.PlainSshExecTaskFactory;
-import org.apache.brooklyn.util.core.task.system.ProcessTaskFactory;
-import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
-import org.apache.brooklyn.util.ssh.BashCommands;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Function;
-import com.google.common.collect.Maps;
-
-/**
- * Conveniences for generating {@link Task} instances to perform SSH activities.
- * <p>
- * If the {@link SshMachineLocation machine} is not specified directly it
- * will be inferred from the {@link Entity} context of either the {@link Effector}
- * or the current {@link Task}.
- *
- * @see SshTasks
- * @since 0.6.0
- */
-@Beta
-public class SshEffectorTasks {
-
- private static final Logger log = LoggerFactory.getLogger(SshEffectorTasks.class);
-
- public static final ConfigKey<Boolean> IGNORE_ENTITY_SSH_FLAGS = ConfigKeys.newBooleanConfigKey("ignoreEntitySshFlags",
- "Whether to ignore any ssh flags (behaviour constraints) set on the entity or location " +
- "where this is running, using only flags explicitly specified", false);
-
- /**
- * Like {@link EffectorBody} but providing conveniences when in an entity with a single machine location.
- */
- public abstract static class SshEffectorBody<T> extends EffectorBody<T> {
-
- /** convenience for accessing the machine */
- public SshMachineLocation machine() {
- return EffectorTasks.getSshMachine(entity());
- }
-
- /** convenience for generating an {@link PlainSshExecTaskFactory} which can be further customised if desired, and then (it must be explicitly) queued */
- public ProcessTaskFactory<Integer> ssh(String ...commands) {
- return new SshEffectorTaskFactory<Integer>(commands).machine(machine());
- }
- }
-
- /** variant of {@link PlainSshExecTaskFactory} which fulfills the {@link EffectorTaskFactory} signature so can be used directly as an impl for an effector,
- * also injects the machine automatically; can also be used outwith effector contexts, and machine is still injected if it is
- * run from inside a task at an entity with a single SshMachineLocation */
- public static class SshEffectorTaskFactory<RET> extends AbstractSshExecTaskFactory<SshEffectorTaskFactory<RET>,RET> implements EffectorTaskFactory<RET> {
-
- public SshEffectorTaskFactory(String ...commands) {
- super(commands);
- }
- public SshEffectorTaskFactory(SshMachineLocation machine, String ...commands) {
- super(machine, commands);
- }
- @Override
- public ProcessTaskWrapper<RET> newTask(Entity entity, Effector<RET> effector, ConfigBag parameters) {
- markDirty();
- if (summary==null) summary(effector.getName()+" (ssh)");
- machine(EffectorTasks.getSshMachine(entity));
- return newTask();
- }
- @Override
- public synchronized ProcessTaskWrapper<RET> newTask() {
- Entity entity = BrooklynTaskTags.getTargetOrContextEntity(Tasks.current());
- if (machine==null) {
- if (log.isDebugEnabled())
- log.debug("Using an ssh task not in an effector without any machine; will attempt to infer the machine: "+this);
- if (entity!=null)
- machine(EffectorTasks.getSshMachine(entity));
- }
- applySshFlags(getConfig(), entity, getMachine());
- return super.newTask();
- }
-
- @Override
- public <T2> SshEffectorTaskFactory<T2> returning(ScriptReturnType type) {
- return (SshEffectorTaskFactory<T2>) super.<T2>returning(type);
- }
-
- @Override
- public SshEffectorTaskFactory<Boolean> returningIsExitCodeZero() {
- return (SshEffectorTaskFactory<Boolean>) super.returningIsExitCodeZero();
- }
-
- public SshEffectorTaskFactory<String> requiringZeroAndReturningStdout() {
- return (SshEffectorTaskFactory<String>) super.requiringZeroAndReturningStdout();
- }
-
- public <RET2> SshEffectorTaskFactory<RET2> returning(Function<ProcessTaskWrapper<?>, RET2> resultTransformation) {
- return (SshEffectorTaskFactory<RET2>) super.returning(resultTransformation);
- }
- }
-
- public static class SshPutEffectorTaskFactory extends SshPutTaskFactory implements EffectorTaskFactory<Void> {
- public SshPutEffectorTaskFactory(String remoteFile) {
- super(remoteFile);
- }
- public SshPutEffectorTaskFactory(SshMachineLocation machine, String remoteFile) {
- super(machine, remoteFile);
- }
- @Override
- public SshPutTaskWrapper newTask(Entity entity, Effector<Void> effector, ConfigBag parameters) {
- machine(EffectorTasks.getSshMachine(entity));
- applySshFlags(getConfig(), entity, getMachine());
- return super.newTask();
- }
- @Override
- public SshPutTaskWrapper newTask() {
- Entity entity = BrooklynTaskTags.getTargetOrContextEntity(Tasks.current());
- if (machine==null) {
- if (log.isDebugEnabled())
- log.debug("Using an ssh put task not in an effector without any machine; will attempt to infer the machine: "+this);
- if (entity!=null) {
- machine(EffectorTasks.getSshMachine(entity));
- }
-
- }
- applySshFlags(getConfig(), entity, getMachine());
- return super.newTask();
- }
- }
-
- public static class SshFetchEffectorTaskFactory extends SshFetchTaskFactory implements EffectorTaskFactory<String> {
- public SshFetchEffectorTaskFactory(String remoteFile) {
- super(remoteFile);
- }
- public SshFetchEffectorTaskFactory(SshMachineLocation machine, String remoteFile) {
- super(machine, remoteFile);
- }
- @Override
- public SshFetchTaskWrapper newTask(Entity entity, Effector<String> effector, ConfigBag parameters) {
- machine(EffectorTasks.getSshMachine(entity));
- applySshFlags(getConfig(), entity, getMachine());
- return super.newTask();
- }
- @Override
- public SshFetchTaskWrapper newTask() {
- Entity entity = BrooklynTaskTags.getTargetOrContextEntity(Tasks.current());
- if (machine==null) {
- if (log.isDebugEnabled())
- log.debug("Using an ssh fetch task not in an effector without any machine; will attempt to infer the machine: "+this);
- if (entity!=null)
- machine(EffectorTasks.getSshMachine(entity));
- }
- applySshFlags(getConfig(), entity, getMachine());
- return super.newTask();
- }
- }
-
- public static SshEffectorTaskFactory<Integer> ssh(String ...commands) {
- return new SshEffectorTaskFactory<Integer>(commands);
- }
-
- public static SshEffectorTaskFactory<Integer> ssh(List<String> commands) {
- return ssh(commands.toArray(new String[commands.size()]));
- }
-
- public static SshPutTaskFactory put(String remoteFile) {
- return new SshPutEffectorTaskFactory(remoteFile);
- }
-
- public static SshFetchEffectorTaskFactory fetch(String remoteFile) {
- return new SshFetchEffectorTaskFactory(remoteFile);
- }
-
- /** task which returns 0 if pid is running */
- public static SshEffectorTaskFactory<Integer> codePidRunning(Integer pid) {
- return ssh("ps -p "+pid).summary("PID "+pid+" is-running check (exit code)").allowingNonZeroExitCode();
- }
-
- /** task which fails if the given PID is not running */
- public static SshEffectorTaskFactory<?> requirePidRunning(Integer pid) {
- return codePidRunning(pid).summary("PID "+pid+" is-running check (required)").requiringExitCodeZero("Process with PID "+pid+" is required to be running");
- }
-
- /** as {@link #codePidRunning(Integer)} but returning boolean */
- public static SshEffectorTaskFactory<Boolean> isPidRunning(Integer pid) {
- return codePidRunning(pid).summary("PID "+pid+" is-running check (boolean)").returning(new Function<ProcessTaskWrapper<?>, Boolean>() {
- public Boolean apply(@Nullable ProcessTaskWrapper<?> input) { return Integer.valueOf(0).equals(input.getExitCode()); }
- });
- }
-
-
- /** task which returns 0 if pid in the given file is running;
- * method accepts wildcards so long as they match a single file on the remote end
- * <p>
- * returns 1 if no matching file,
- * 1 if matching file but no matching process,
- * and 2 if 2+ matching files */
- public static SshEffectorTaskFactory<Integer> codePidFromFileRunning(final String pidFile) {
- return ssh(BashCommands.chain(
- // this fails, but isn't an error
- BashCommands.requireTest("-f "+pidFile, "The PID file "+pidFile+" does not exist."),
- // this fails and logs an error picked up later
- BashCommands.requireTest("`ls "+pidFile+" | wc -w` -eq 1", "ERROR: there are multiple matching PID files"),
- // this fails and logs an error picked up later
- BashCommands.require("cat "+pidFile, "ERROR: the PID file "+pidFile+" cannot be read (permissions?)."),
- // finally check the process
- "ps -p `cat "+pidFile+"`")).summary("PID file "+pidFile+" is-running check (exit code)")
- .allowingNonZeroExitCode()
- .addCompletionListener(new Function<ProcessTaskWrapper<?>,Void>() {
- public Void apply(ProcessTaskWrapper<?> input) {
- if (input.getStderr().contains("ERROR:"))
- throw new IllegalStateException("Invalid or inaccessible PID filespec: "+pidFile);
- return null;
- }
- });
- }
-
- /** task which fails if the pid in the given file is not running (or if there is no such PID file);
- * method accepts wildcards so long as they match a single file on the remote end (fails if 0 or 2+ matching files) */
- public static SshEffectorTaskFactory<?> requirePidFromFileRunning(String pidFile) {
- return codePidFromFileRunning(pidFile)
- .summary("PID file "+pidFile+" is-running check (required)")
- .requiringExitCodeZero("Process with PID from file "+pidFile+" is required to be running");
- }
-
- /** as {@link #codePidFromFileRunning(String)} but returning boolean */
- public static SshEffectorTaskFactory<Boolean> isPidFromFileRunning(String pidFile) {
- return codePidFromFileRunning(pidFile).summary("PID file "+pidFile+" is-running check (boolean)").
- returning(new Function<ProcessTaskWrapper<?>, Boolean>() {
- public Boolean apply(@Nullable ProcessTaskWrapper<?> input) { return ((Integer)0).equals(input.getExitCode()); }
- });
- }
-
- /** extracts the values for the main brooklyn.ssh.config.* config keys (i.e. those declared in ConfigKeys)
- * as declared on the entity, and inserts them in a map using the unprefixed state, for ssh.
- * <p>
- * currently this is computed for each call, which may be wasteful, but it is reliable in the face of config changes.
- * we could cache the Map. note that we do _not_ cache (or even own) the SshTool;
- * the SshTool is created or re-used by the SshMachineLocation making use of these properties */
- @Beta
- public static Map<String, Object> getSshFlags(Entity entity, Location optionalLocation) {
- ConfigBag allConfig = ConfigBag.newInstance();
-
- StringConfigMap globalConfig = ((EntityInternal)entity).getManagementContext().getConfig();
- allConfig.putAll(globalConfig.getAllConfig());
-
- if (optionalLocation!=null)
- allConfig.putAll(((LocationInternal)optionalLocation).config().getBag());
-
- allConfig.putAll(((EntityInternal)entity).getAllConfig());
-
- Map<String, Object> result = Maps.newLinkedHashMap();
- for (String keyS : allConfig.getAllConfig().keySet()) {
- if (keyS.startsWith(SshTool.BROOKLYN_CONFIG_KEY_PREFIX)) {
- ConfigKey<?> key = ConfigKeys.newConfigKey(Object.class, keyS);
-
- Object val = allConfig.getStringKey(keyS);
-
- /*
- * NOV 2013 changing this to rely on config above being inserted in the right order,
- * so entity config will be preferred over location, and location over global.
- * If that is consistent then remove the lines below.
- * (We can also accept null entity and so combine with SshTasks.getSshFlags.)
- */
-
-// // have to use raw config to test whether the config is set
-// Object val = ((EntityInternal)entity).getConfigMap().getRawConfig(key);
-// if (val!=null) {
-// val = entity.getConfig(key);
-// } else {
-// val = globalConfig.getRawConfig(key);
-// if (val!=null) val = globalConfig.getConfig(key);
-// }
-// if (val!=null) {
- result.put(ConfigUtils.unprefixedKey(SshTool.BROOKLYN_CONFIG_KEY_PREFIX, key).getName(), val);
-// }
- }
- }
- return result;
- }
-
- private static void applySshFlags(ConfigBag config, Entity entity, Location machine) {
- if (entity!=null) {
- if (!config.get(IGNORE_ENTITY_SSH_FLAGS)) {
- config.putIfAbsent(getSshFlags(entity, machine));
- }
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicCluster.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicCluster.java b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicCluster.java
index 1b16369..bf39663 100644
--- a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicCluster.java
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicCluster.java
@@ -33,11 +33,11 @@ import org.apache.brooklyn.config.ConfigKey;
import org.apache.brooklyn.core.annotation.Effector;
import org.apache.brooklyn.core.annotation.EffectorParam;
import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.MethodEffector;
import org.apache.brooklyn.core.entity.Attributes;
import org.apache.brooklyn.core.entity.factory.EntityFactory;
import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
import org.apache.brooklyn.core.entity.trait.MemberReplaceable;
-import org.apache.brooklyn.effector.core.MethodEffector;
import org.apache.brooklyn.entity.group.zoneaware.BalancingNodePlacementStrategy;
import org.apache.brooklyn.entity.group.zoneaware.ProportionalZoneFailureDetector;
import org.apache.brooklyn.sensor.core.BasicAttributeSensor;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java
index 7a0c31b..a8c63ef 100644
--- a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java
@@ -39,6 +39,7 @@ import org.apache.brooklyn.api.location.MachineProvisioningLocation;
import org.apache.brooklyn.api.mgmt.Task;
import org.apache.brooklyn.api.policy.Policy;
import org.apache.brooklyn.core.config.render.RendererHints;
+import org.apache.brooklyn.core.effector.Effectors;
import org.apache.brooklyn.core.entity.Entities;
import org.apache.brooklyn.core.entity.factory.EntityFactory;
import org.apache.brooklyn.core.entity.factory.EntityFactoryForLocation;
@@ -50,7 +51,6 @@ import org.apache.brooklyn.core.entity.trait.Startable;
import org.apache.brooklyn.core.entity.trait.StartableMethods;
import org.apache.brooklyn.core.location.Locations;
import org.apache.brooklyn.core.location.cloud.AvailabilityZoneExtension;
-import org.apache.brooklyn.effector.core.Effectors;
import org.apache.brooklyn.entity.stock.DelegateEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java
index 7611ba8..daedc39 100644
--- a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java
@@ -32,6 +32,7 @@ import org.apache.brooklyn.api.entity.EntityLocal;
import org.apache.brooklyn.api.entity.EntitySpec;
import org.apache.brooklyn.api.location.Location;
import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.core.effector.Effectors;
import org.apache.brooklyn.core.entity.Entities;
import org.apache.brooklyn.core.entity.EntityInternal;
import org.apache.brooklyn.core.entity.factory.EntityFactory;
@@ -40,7 +41,6 @@ import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
import org.apache.brooklyn.core.entity.trait.Changeable;
import org.apache.brooklyn.core.entity.trait.Startable;
-import org.apache.brooklyn.effector.core.Effectors;
import org.apache.brooklyn.sensor.enricher.Enrichers;
import org.apache.brooklyn.util.collections.MutableList;
import org.apache.brooklyn.util.exceptions.Exceptions;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicGroup.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicGroup.java b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicGroup.java
index 36ac0f9..bb43d3b 100644
--- a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicGroup.java
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicGroup.java
@@ -28,8 +28,8 @@ import org.apache.brooklyn.api.sensor.SensorEvent;
import org.apache.brooklyn.config.ConfigKey;
import org.apache.brooklyn.core.annotation.Effector;
import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.MethodEffector;
import org.apache.brooklyn.core.entity.trait.Startable;
-import org.apache.brooklyn.effector.core.MethodEffector;
import org.apache.brooklyn.sensor.core.Sensors;
import org.apache.brooklyn.util.core.flags.SetFromFlag;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicRegionsFabric.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicRegionsFabric.java b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicRegionsFabric.java
index fc11e9b..7c46d14 100644
--- a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicRegionsFabric.java
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicRegionsFabric.java
@@ -21,7 +21,7 @@ package org.apache.brooklyn.entity.group;
import org.apache.brooklyn.api.entity.ImplementedBy;
import org.apache.brooklyn.core.annotation.Effector;
import org.apache.brooklyn.core.annotation.EffectorParam;
-import org.apache.brooklyn.effector.core.MethodEffector;
+import org.apache.brooklyn.core.effector.MethodEffector;
@ImplementedBy(DynamicRegionsFabricImpl.class)
public interface DynamicRegionsFabric extends DynamicFabric {
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/entity/group/QuarantineGroupImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/QuarantineGroupImpl.java b/core/src/main/java/org/apache/brooklyn/entity/group/QuarantineGroupImpl.java
index dfddf5f..886862a 100644
--- a/core/src/main/java/org/apache/brooklyn/entity/group/QuarantineGroupImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/QuarantineGroupImpl.java
@@ -23,10 +23,10 @@ import java.util.Set;
import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.core.effector.Effectors;
import org.apache.brooklyn.core.entity.AbstractEntity;
import org.apache.brooklyn.core.entity.Entities;
import org.apache.brooklyn.core.entity.trait.Startable;
-import org.apache.brooklyn.effector.core.Effectors;
import org.apache.brooklyn.util.core.task.DynamicTasks;
import org.apache.brooklyn.util.core.task.Tasks;
import org.apache.brooklyn.util.exceptions.Exceptions;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/sensor/core/HttpRequestSensor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/core/HttpRequestSensor.java b/core/src/main/java/org/apache/brooklyn/sensor/core/HttpRequestSensor.java
index 7a5fecf..6b9c780 100644
--- a/core/src/main/java/org/apache/brooklyn/sensor/core/HttpRequestSensor.java
+++ b/core/src/main/java/org/apache/brooklyn/sensor/core/HttpRequestSensor.java
@@ -25,7 +25,7 @@ import net.minidev.json.JSONObject;
import org.apache.brooklyn.api.entity.EntityLocal;
import org.apache.brooklyn.config.ConfigKey;
import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.effector.core.AddSensor;
+import org.apache.brooklyn.core.effector.AddSensor;
import org.apache.brooklyn.sensor.feed.http.HttpFeed;
import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/sensor/core/StaticSensor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/core/StaticSensor.java b/core/src/main/java/org/apache/brooklyn/sensor/core/StaticSensor.java
index 7bc10bf..0c3a00f 100644
--- a/core/src/main/java/org/apache/brooklyn/sensor/core/StaticSensor.java
+++ b/core/src/main/java/org/apache/brooklyn/sensor/core/StaticSensor.java
@@ -22,7 +22,7 @@ import org.apache.brooklyn.api.entity.EntityLocal;
import org.apache.brooklyn.api.mgmt.Task;
import org.apache.brooklyn.config.ConfigKey;
import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.effector.core.AddSensor;
+import org.apache.brooklyn.core.effector.AddSensor;
import org.apache.brooklyn.sensor.enricher.Propagator;
import org.apache.brooklyn.util.core.config.ConfigBag;
import org.apache.brooklyn.util.core.task.Tasks;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeed.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeed.java b/core/src/main/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeed.java
index 33b284c..95aba9f 100644
--- a/core/src/main/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeed.java
+++ b/core/src/main/java/org/apache/brooklyn/sensor/feed/windows/WindowsPerformanceCounterFeed.java
@@ -40,8 +40,8 @@ import org.apache.brooklyn.api.mgmt.ExecutionContext;
import org.apache.brooklyn.api.sensor.AttributeSensor;
import org.apache.brooklyn.config.ConfigKey;
import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.EffectorTasks;
import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.effector.core.EffectorTasks;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.brooklyn.location.winrm.WinRmMachineLocation;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/main/java/org/apache/brooklyn/util/core/task/ssh/SshTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/ssh/SshTasks.java b/core/src/main/java/org/apache/brooklyn/util/core/task/ssh/SshTasks.java
index 10eea13..448cd61 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/ssh/SshTasks.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/ssh/SshTasks.java
@@ -32,10 +32,10 @@ import org.apache.brooklyn.api.mgmt.TaskQueueingContext;
import org.apache.brooklyn.config.ConfigKey;
import org.apache.brooklyn.core.config.ConfigKeys;
import org.apache.brooklyn.core.config.ConfigUtils;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
import org.apache.brooklyn.core.location.AbstractLocation;
import org.apache.brooklyn.core.location.internal.LocationInternal;
import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
-import org.apache.brooklyn.effector.core.ssh.SshEffectorTasks;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.brooklyn.location.ssh.SshMachineLocation;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorBasicTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/effector/EffectorBasicTest.java b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorBasicTest.java
new file mode 100644
index 0000000..b05a397
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorBasicTest.java
@@ -0,0 +1,183 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.core.effector;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.mgmt.HasTaskChildren;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.trait.FailingEntity;
+import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.location.SimulatedLocation;
+import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.test.TestUtils;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.task.Tasks;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+
+public class EffectorBasicTest extends BrooklynAppUnitTestSupport {
+
+ private static final Logger log = LoggerFactory.getLogger(EffectorBasicTest.class);
+
+ // NB: more tests of effectors in EffectorSayHiTest and EffectorConcatenateTest
+ // as well as EntityConfigMapUsageTest and others
+
+ private List<SimulatedLocation> locs;
+
+ @BeforeMethod(alwaysRun=true)
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ locs = ImmutableList.of(new SimulatedLocation());
+ }
+
+ @Test
+ public void testInvokeEffectorStart() {
+ app.start(locs);
+ TestUtils.assertSetsEqual(locs, app.getLocations());
+ // TODO above does not get registered as a task
+ }
+
+ @Test
+ public void testInvokeEffectorStartWithMap() {
+ app.invoke(Startable.START, MutableMap.of("locations", locs)).getUnchecked();
+ TestUtils.assertSetsEqual(locs, app.getLocations());
+ }
+
+ @Test
+ public void testInvokeEffectorStartWithArgs() {
+ Entities.invokeEffectorWithArgs((EntityLocal)app, app, Startable.START, locs).getUnchecked();
+ TestUtils.assertSetsEqual(locs, app.getLocations());
+ }
+
+ @Test
+ public void testInvokeEffectorStartWithTwoEntities() {
+ TestEntity entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+ TestEntity entity2 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+ app.start(locs);
+ TestUtils.assertSetsEqual(locs, app.getLocations());
+ TestUtils.assertSetsEqual(locs, entity.getLocations());
+ TestUtils.assertSetsEqual(locs, entity2.getLocations());
+ }
+
+ @Test
+ public void testInvokeEffectorTaskHasTag() {
+ Task<Void> starting = app.invoke(Startable.START, MutableMap.of("locations", locs));
+// log.info("TAGS: "+starting.getTags());
+ Assert.assertTrue(starting.getTags().contains(ManagementContextInternal.EFFECTOR_TAG));
+ }
+
+ // check various failure situations
+
+ private FailingEntity createFailingEntity() {
+ FailingEntity entity = app.createAndManageChild(EntitySpec.create(FailingEntity.class)
+ .configure(FailingEntity.FAIL_ON_START, true));
+ return entity;
+ }
+
+ // uncaught failures are propagates
+
+ @Test
+ public void testInvokeEffectorStartFailing_Method() {
+ FailingEntity entity = createFailingEntity();
+ assertStartMethodFails(entity);
+ }
+
+ @Test
+ public void testInvokeEffectorStartFailing_EntityInvoke() {
+ FailingEntity entity = createFailingEntity();
+ assertTaskFails( entity.invoke(Startable.START, MutableMap.of("locations", locs)) );
+ }
+
+ @Test
+ public void testInvokeEffectorStartFailing_EntitiesInvoke() {
+ FailingEntity entity = createFailingEntity();
+
+ assertTaskFails( Entities.invokeEffectorWithArgs(entity, entity, Startable.START, locs) );
+ }
+
+ // caught failures are NOT propagated!
+
+ @Test
+ public void testInvokeEffectorStartFailing_MethodInDynamicTask() {
+ Task<Void> task = app.getExecutionContext().submit(Tasks.<Void>builder().dynamic(true).body(new Callable<Void>() {
+ @Override public Void call() throws Exception {
+ testInvokeEffectorStartFailing_Method();
+ return null;
+ }
+ }).build());
+
+ assertTaskSucceeds(task);
+ assertTaskHasFailedChild(task);
+ }
+
+ @Test
+ public void testInvokeEffectorStartFailing_MethodInTask() {
+ Task<Void> task = app.getExecutionContext().submit(Tasks.<Void>builder().dynamic(false).body(new Callable<Void>() {
+ @Override public Void call() throws Exception {
+ testInvokeEffectorStartFailing_Method();
+ return null;
+ }
+ }).build());
+
+ assertTaskSucceeds(task);
+ }
+
+ private void assertTaskSucceeds(Task<Void> task) {
+ task.getUnchecked();
+ Assert.assertFalse(task.isError());
+ }
+
+ private void assertTaskHasFailedChild(Task<Void> task) {
+ Assert.assertTrue(Tasks.failed( ((HasTaskChildren)task).getChildren() ).iterator().hasNext());
+ }
+
+ private void assertStartMethodFails(FailingEntity entity) {
+ try {
+ entity.start(locs);
+ Assert.fail("Should have failed");
+ } catch (Exception e) {
+ // expected
+ }
+ }
+
+ protected void assertTaskFails(Task<?> t) {
+ try {
+ t.get();
+ Assert.fail("Should have failed");
+ } catch (Exception e) {
+ Exceptions.propagateIfFatal(e);
+ // expected
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorConcatenateTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/effector/EffectorConcatenateTest.java b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorConcatenateTest.java
new file mode 100644
index 0000000..c909a9d
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorConcatenateTest.java
@@ -0,0 +1,241 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.core.effector;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.fail;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.mgmt.ExecutionManager;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.core.annotation.Effector;
+import org.apache.brooklyn.core.annotation.EffectorParam;
+import org.apache.brooklyn.core.effector.MethodEffector;
+import org.apache.brooklyn.core.entity.AbstractEntity;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.core.test.entity.TestApplicationImpl;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.task.BasicExecutionContext;
+import org.apache.brooklyn.util.core.task.Tasks;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+
+public class EffectorConcatenateTest {
+
+
+ private static final Logger log = LoggerFactory.getLogger(EffectorConcatenateTest.class);
+ private static final long TIMEOUT = 10*1000;
+
+ public static class MyEntityImpl extends AbstractEntity {
+
+ public static MethodEffector<String> CONCATENATE = new MethodEffector<String>(MyEntityImpl.class, "concatenate");
+ public static MethodEffector<Void> WAIT_A_BIT = new MethodEffector<Void>(MyEntityImpl.class, "waitabit");
+ public static MethodEffector<Void> SPAWN_CHILD = new MethodEffector<Void>(MyEntityImpl.class, "spawnchild");
+
+ public MyEntityImpl() {
+ super();
+ }
+ public MyEntityImpl(Entity parent) {
+ super(parent);
+ }
+
+ /** The "current task" representing the effector currently executing */
+ AtomicReference<Task<?>> waitingTask = new AtomicReference<Task<?>>();
+
+ /** latch is .countDown'ed by the effector at the beginning of the "waiting" point */
+ CountDownLatch nowWaitingLatch = new CountDownLatch(1);
+
+ /** latch is await'ed on by the effector when it is in the "waiting" point */
+ CountDownLatch continueFromWaitingLatch = new CountDownLatch(1);
+
+ @Effector(description="sample effector concatenating strings")
+ public String concatenate(@EffectorParam(name="first", description="first argument") String first,
+ @EffectorParam(name="second", description="2nd arg") String second) throws Exception {
+ return first+second;
+ }
+
+ @Effector(description="sample effector doing some waiting")
+ public void waitabit() throws Exception {
+ waitingTask.set(Tasks.current());
+
+ Tasks.setExtraStatusDetails("waitabit extra status details");
+
+ Tasks.withBlockingDetails("waitabit.blocking", new Callable<Void>() {
+ public Void call() throws Exception {
+ nowWaitingLatch.countDown();
+ if (!continueFromWaitingLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)) {
+ fail("took too long to be told to continue");
+ }
+ return null;
+ }});
+ }
+
+ @Effector(description="sample effector that spawns a child task that waits a bit")
+ public void spawnchild() throws Exception {
+ // spawn a child, then wait
+ BasicExecutionContext.getCurrentExecutionContext().submit(
+ MutableMap.of("displayName", "SpawnedChildName"),
+ new Callable<Void>() {
+ public Void call() throws Exception {
+ log.info("beginning spawned child response "+Tasks.current()+", with tags "+Tasks.current().getTags());
+ Tasks.setBlockingDetails("spawned child blocking details");
+ nowWaitingLatch.countDown();
+ if (!continueFromWaitingLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)) {
+ fail("took too long to be told to continue");
+ }
+ return null;
+ }});
+ }
+ }
+
+ private TestApplication app;
+ private MyEntityImpl e;
+
+ @BeforeMethod(alwaysRun=true)
+ public void setUp() {
+ app = new TestApplicationImpl();
+ e = new MyEntityImpl(app);
+ Entities.startManagement(app);
+ }
+
+ @AfterMethod(alwaysRun=true)
+ public void tearDown() {
+ if (app != null) Entities.destroyAll(app.getManagementContext());
+ }
+
+ @Test
+ public void testCanInvokeEffector() throws Exception {
+ // invocation map syntax
+ Task<String> task = e.invoke(MyEntityImpl.CONCATENATE, ImmutableMap.of("first", "a", "second", "b"));
+ assertEquals(task.get(TIMEOUT, TimeUnit.MILLISECONDS), "ab");
+
+ // method syntax
+ assertEquals("xy", e.concatenate("x", "y"));
+ }
+
+ @Test
+ public void testReportsTaskDetails() throws Exception {
+ final AtomicReference<String> result = new AtomicReference<String>();
+
+ Thread bg = new Thread(new Runnable() {
+ public void run() {
+ try {
+ // Expect "wait a bit" to tell us it's blocking
+ if (!e.nowWaitingLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)) {
+ result.set("took too long for waitabit to be waiting");
+ return;
+ }
+
+ // Expect "wait a bit" to have retrieved and set its task
+ try {
+ Task<?> t = e.waitingTask.get();
+ String status = t.getStatusDetail(true);
+ log.info("waitabit task says:\n"+status);
+ if (!status.contains("waitabit extra status details")) {
+ result.set("Status not in expected format: doesn't contain extra status details phrase 'My extra status details'\n"+status);
+ return;
+ }
+ if (!status.startsWith("waitabit.blocking")) {
+ result.set("Status not in expected format: doesn't start with blocking details 'waitabit.blocking'\n"+status);
+ return;
+ }
+ } finally {
+ e.continueFromWaitingLatch.countDown();
+ }
+ } catch (Throwable t) {
+ log.warn("Failure: "+t, t);
+ result.set("Failure: "+t);
+ }
+ }});
+ bg.start();
+
+ e.invoke(MyEntityImpl.WAIT_A_BIT, ImmutableMap.<String,Object>of())
+ .get(TIMEOUT, TimeUnit.MILLISECONDS);
+
+ bg.join(TIMEOUT*2);
+ assertFalse(bg.isAlive());
+
+ String problem = result.get();
+ if (problem!=null) fail(problem);
+ }
+
+ @Test
+ public void testReportsSpawnedTaskDetails() throws Exception {
+ final AtomicReference<String> result = new AtomicReference<String>();
+
+ Thread bg = new Thread(new Runnable() {
+ public void run() {
+ try {
+ // Expect "spawned child" to tell us it's blocking
+ if (!e.nowWaitingLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)) {
+ result.set("took too long for spawnchild's sub-task to be waiting");
+ return;
+ }
+
+ // Expect spawned task to be have been tagged with entity
+ ExecutionManager em = e.getManagementContext().getExecutionManager();
+ Task<?> subtask = Iterables.find(BrooklynTaskTags.getTasksInEntityContext(em, e), new Predicate<Task<?>>() {
+ public boolean apply(Task<?> input) {
+ return "SpawnedChildName".equals(input.getDisplayName());
+ }
+ });
+
+ // Expect spawned task to haev correct "blocking details"
+ try {
+ String status = subtask.getStatusDetail(true);
+ log.info("subtask task says:\n"+status);
+ if (!status.contains("spawned child blocking details")) {
+ result.set("Status not in expected format: doesn't contain blocking details phrase 'spawned child blocking details'\n"+status);
+ return;
+ }
+ } finally {
+ e.continueFromWaitingLatch.countDown();
+ }
+ } catch (Throwable t) {
+ log.warn("Failure: "+t, t);
+ result.set("Failure: "+t);
+ }
+ }});
+ bg.start();
+
+ e.invoke(MyEntityImpl.SPAWN_CHILD, ImmutableMap.<String,Object>of())
+ .get(TIMEOUT, TimeUnit.MILLISECONDS);
+
+ bg.join(TIMEOUT*2);
+ assertFalse(bg.isAlive());
+
+ String problem = result.get();
+ if (problem!=null) fail(problem);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorMetadataTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/effector/EffectorMetadataTest.java b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorMetadataTest.java
new file mode 100644
index 0000000..1f1be85
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorMetadataTest.java
@@ -0,0 +1,166 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.core.effector;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.effector.ParameterType;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.entity.ImplementedBy;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.annotation.EffectorParam;
+import org.apache.brooklyn.core.effector.BasicParameterType;
+import org.apache.brooklyn.core.effector.Effectors;
+import org.apache.brooklyn.core.effector.MethodEffector;
+import org.apache.brooklyn.core.entity.AbstractEntity;
+import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.mgmt.internal.EffectorUtils;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Test the operation of the {@link Effector} implementations.
+ *
+ * TODO clarify test purpose
+ */
+public class EffectorMetadataTest extends BrooklynAppUnitTestSupport {
+
+ private MyAnnotatedEntity e1;
+ private MyOverridingEntity e2;
+
+ @BeforeMethod(alwaysRun=true)
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ e1 = app.createAndManageChild(EntitySpec.create(MyAnnotatedEntity.class));
+ e2 = app.createAndManageChild(EntitySpec.create(MyOverridingEntity.class));
+ }
+
+ @Test
+ public void testEffectorMetaDataFromAnnotationsWithConstant() {
+ Effector<?> effector = EffectorUtils.findEffectorDeclared(e1, "effWithNewAnnotation").get();
+ Assert.assertTrue(Effectors.sameSignature(effector, MyAnnotatedEntity.EFF_WITH_NEW_ANNOTATION));
+ assertEquals(effector.getName(), "effWithNewAnnotation");
+ assertEquals(effector.getDescription(), "my effector description");
+ assertEquals(effector.getReturnType(), String.class);
+ assertParametersEqual(
+ effector.getParameters(),
+ ImmutableList.<ParameterType<?>>of(
+ new BasicParameterType<String>("param1", String.class, "my param description", "my default val")));
+ }
+
+ @Test
+ public void testEffectorMetaDataFromAnnotationsWithoutConstant() {
+ Effector<?> effector = EffectorUtils.findEffectorDeclared(e1, "effWithAnnotationButNoConstant").get();
+ assertEquals(effector.getName(), "effWithAnnotationButNoConstant");
+ assertEquals(effector.getDescription(), "my effector description");
+ assertEquals(effector.getReturnType(), String.class);
+ assertParametersEqual(
+ effector.getParameters(),
+ ImmutableList.<ParameterType<?>>of(
+ new BasicParameterType<String>("param1", String.class, "my param description", "my default val")));
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Test
+ public void testEffectorMetaDataFromOverriddenMethod() {
+ // Overridden with new annotations
+ Effector<?> startEffector = EffectorUtils.findEffectorDeclared(e2, "start").get();
+ assertEquals(startEffector.getName(), "start");
+ assertEquals(startEffector.getDescription(), "My overridden start description");
+ assertEquals(startEffector.getReturnType(), void.class);
+ assertParametersEqual(
+ startEffector.getParameters(),
+ ImmutableList.<ParameterType<?>>of(
+ new BasicParameterType<Collection>("locations", Collection.class, "my overridden param description", null)));
+ }
+
+ private void assertParametersEqual(List<ParameterType<?>> actuals, List<ParameterType<?>> expecteds) {
+ assertEquals(actuals.size(), expecteds.size(), "actual="+actuals);
+ for (int i = 0; i < actuals.size(); i++) {
+ ParameterType<?> actual = actuals.get(i);
+ ParameterType<?> expected = expecteds.get(i);
+ assertParameterEqual(actual, expected);
+ }
+ }
+
+ private void assertParameterEqual(ParameterType<?> actual, ParameterType<?> expected) {
+ assertEquals(actual.getName(), expected.getName(), "actual="+actual);
+ assertEquals(actual.getDescription(), expected.getDescription(), "actual="+actual);
+ assertEquals(actual.getParameterClass(), expected.getParameterClass(), "actual="+actual);
+ assertEquals(actual.getParameterClassName(), expected.getParameterClassName(), "actual="+actual);
+ }
+
+ @ImplementedBy(MyAnnotatedEntityImpl.class)
+ public interface MyAnnotatedEntity extends Entity {
+ static MethodEffector<String> EFF_WITH_NEW_ANNOTATION = new MethodEffector<String>(MyAnnotatedEntity.class, "effWithNewAnnotation");
+
+ @org.apache.brooklyn.core.annotation.Effector(description="my effector description")
+ public String effWithNewAnnotation(
+ @EffectorParam(name="param1", defaultValue="my default val", description="my param description") String param1);
+
+ @org.apache.brooklyn.core.annotation.Effector(description="my effector description")
+ public String effWithAnnotationButNoConstant(
+ @EffectorParam(name="param1", defaultValue="my default val", description="my param description") String param1);
+ }
+
+ public static class MyAnnotatedEntityImpl extends AbstractEntity implements MyAnnotatedEntity {
+ @Override
+ public String effWithNewAnnotation(String param1) {
+ return param1;
+ }
+
+ @Override
+ public String effWithAnnotationButNoConstant(String param1) {
+ return param1;
+ }
+ }
+
+ @ImplementedBy(MyOverridingEntityImpl.class)
+ public interface MyOverridingEntity extends Entity, Startable {
+ org.apache.brooklyn.api.effector.Effector<Void> START = Effectors.effector(Startable.START)
+ .description("My overridden start description")
+ .parameter(Collection.class, "locations", "my overridden param description")
+ .build();
+ }
+
+ public static class MyOverridingEntityImpl extends AbstractEntity implements MyOverridingEntity {
+
+ @Override
+ public void restart() {
+ }
+
+ @Override
+ public void start(Collection<? extends Location> locations2) {
+ }
+
+ @Override
+ public void stop() {
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8dbb0e4b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiGroovyTest.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiGroovyTest.groovy b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiGroovyTest.groovy
new file mode 100644
index 0000000..5dd776e
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiGroovyTest.groovy
@@ -0,0 +1,182 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.core.effector
+
+import static org.testng.Assert.*
+
+import org.apache.brooklyn.api.effector.Effector
+import org.apache.brooklyn.api.entity.Entity
+import org.apache.brooklyn.api.entity.EntitySpec
+import org.apache.brooklyn.api.entity.ImplementedBy
+import org.apache.brooklyn.api.mgmt.ManagementContext
+import org.apache.brooklyn.api.mgmt.Task
+import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
+import org.apache.brooklyn.core.mgmt.internal.EffectorUtils
+import org.apache.brooklyn.core.test.entity.TestApplication
+import org.apache.brooklyn.core.annotation.EffectorParam
+import org.apache.brooklyn.core.effector.BasicParameterType;
+import org.apache.brooklyn.core.effector.ExplicitEffector;
+import org.apache.brooklyn.core.effector.MethodEffector;
+import org.apache.brooklyn.core.entity.AbstractEntity
+import org.apache.brooklyn.core.entity.Entities
+import org.apache.brooklyn.core.entity.trait.Startable
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+import org.testng.annotations.AfterMethod
+import org.testng.annotations.BeforeMethod
+import org.testng.annotations.Test
+
+/**
+ * Test the operation of the {@link Effector} implementations.
+ *
+ * TODO clarify test purpose
+ */
+public class EffectorSayHiGroovyTest {
+ private static final Logger log = LoggerFactory.getLogger(EffectorSayHiTest.class);
+
+ private TestApplication app;
+ private MyEntity e;
+
+ @BeforeMethod(alwaysRun=true)
+ public void setUp() {
+ app = TestApplication.Factory.newManagedInstanceForTests();
+ e = app.createAndManageChild(EntitySpec.create(MyEntity.class));
+ }
+
+ @AfterMethod(alwaysRun=true)
+ public void tearDown() {
+ if (app != null) Entities.destroyAll(app.getManagementContext());
+ }
+
+ @Test
+ public void testFindEffectors() {
+ assertEquals("sayHi1", e.SAY_HI_1.getName());
+ assertEquals(["name", "greeting"], e.SAY_HI_1.getParameters()[0..1]*.getName());
+ assertEquals("says hello", e.SAY_HI_1.getDescription());
+
+ assertEquals("sayHi1", e.SAY_HI_1_ALT.getName());
+ assertEquals(["name", "greeting"], e.SAY_HI_1_ALT.getParameters()[0..1]*.getName());
+ assertEquals("says hello", e.SAY_HI_1_ALT.getDescription());
+
+ assertEquals("sayHi2", e.SAY_HI_2.getName());
+ assertEquals(["name", "greeting"], e.SAY_HI_2.getParameters()[0..1]*.getName());
+ assertEquals("says hello", e.SAY_HI_2.getDescription());
+ }
+
+ @Test
+ public void testFindTraitEffectors() {
+ assertEquals("locations", Startable.START.getParameters()[0].getName());
+ }
+
+ @Test
+ public void testInvokeEffectorMethod1BypassInterception() {
+ String name = "sayHi1"
+ def args = ["Bob", "hello"] as Object[]
+
+ //try the alt syntax recommended from web
+ def metaMethod = e.metaClass.getMetaMethod(name, args)
+ if (metaMethod==null)
+ throw new IllegalArgumentException("Invalid arguments (no method found) for method $name: "+args);
+ assertEquals("hello Bob", metaMethod.invoke(e, args))
+ }
+
+ @Test
+ public void testInvokeEffectorMethod2BypassInterception() {
+ String name = "sayHi2"
+ def args = ["Bob", "hello"] as Object[]
+ assertEquals("hello Bob", e.metaClass.invokeMethod(e, name, args))
+ }
+
+ @Test
+ public void testInvokeEffectors1() {
+ assertEquals("hi Bob", e.sayHi1("Bob", "hi"))
+
+ assertEquals("hello Bob", e.SAY_HI_1.call(e, [name:"Bob"]) )
+ assertEquals("hello Bob", e.invoke(e.SAY_HI_1, [name:"Bob"]).get() );
+
+ assertEquals("hello Bob", e.SAY_HI_1_ALT.call(e, [name:"Bob"]) )
+ }
+
+ @Test
+ public void testInvokeEffectors2() {
+ assertEquals("hi Bob", e.sayHi2("Bob", "hi"))
+
+ assertEquals("hello Bob", e.SAY_HI_2.call(e, [name:"Bob"]) )
+ assertEquals("hello Bob", e.invoke(e.SAY_HI_2, [name:"Bob"]).get() );
+
+ }
+
+ @Test
+ public void testCanRetrieveTaskForEffector() {
+ e.sayHi2("Bob", "hi")
+
+ ManagementContext managementContext = e.getManagementContext()
+
+ Set<Task> tasks = managementContext.getExecutionManager().getTasksWithAllTags([
+ BrooklynTaskTags.tagForContextEntity(e),"EFFECTOR"])
+ assertEquals(tasks.size(), 1)
+ assertTrue(tasks.iterator().next().getDescription().contains("sayHi2"))
+ }
+}
+public interface CanSayHi {
+ //prefer following simple groovy syntax
+ static Effector<String> SAY_HI_1 = new MethodEffector<String>(CanSayHi.&sayHi1);
+ //slightly longer-winded pojo also supported
+ static Effector<String> SAY_HI_1_ALT = new MethodEffector<String>(CanSayHi.class, "sayHi1");
+
+ @org.apache.brooklyn.core.annotation.Effector(description="says hello")
+ public String sayHi1(
+ @EffectorParam(name="name") String name,
+ @EffectorParam(name="greeting", defaultValue="hello", description="what to say") String greeting);
+
+ //finally there is a way to provide a class/closure if needed or preferred for some odd reason
+ static Effector<String> SAY_HI_2 =
+
+ //groovy 1.8.2 balks at runtime during getCallSiteArray (bug 5122) if we use anonymous inner class
+// new ExplicitEffector<CanSayHi,String>(
+// "sayHi2", String.class, [
+// [ "name", String.class, "person to say hi to" ] as BasicParameterType<String>,
+// [ "greeting", String.class, "what to say as greeting", "hello" ] as BasicParameterType<String>
+// ],
+// "says hello to a person") {
+// public String invokeEffector(CanSayHi e, Map m) {
+// e.sayHi2(m)
+// }
+// };
+ //following is a workaround, not greatly enamoured of it... but MethodEffector is generally preferred anyway
+ ExplicitEffector.create("sayHi2", String.class, [
+ new BasicParameterType<String>("name", String.class, "person to say hi to"),
+ new BasicParameterType<String>("greeting", String.class, "what to say as greeting", "hello")
+ ],
+ "says hello", { e, m ->
+ def args = EffectorUtils.prepareArgsForEffector(SAY_HI_2, m);
+ e.sayHi2(args[0], args[1]) })
+
+ public String sayHi2(String name, String greeting);
+
+}
+
+@ImplementedBy(MyEntityImpl.class)
+public interface MyEntity extends Entity, CanSayHi {
+}
+
+public class MyEntityImpl extends AbstractEntity implements MyEntity {
+ public String sayHi1(String name, String greeting) { "$greeting $name" }
+ public String sayHi2(String name, String greeting) { "$greeting $name" }
+}