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" }
+}