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 2014/07/29 21:31:56 UTC

[01/31] git commit: better tasks logic for deploying wars when target entity is ready (ie service up), failing gracefully if it's not, with some helpers in Tasks and DynamicTasks

Repository: incubator-brooklyn
Updated Branches:
  refs/heads/master f03d82c4f -> 07bfb0550


better tasks logic for deploying wars when target entity is ready (ie service up), failing gracefully if it's not, with some helpers in Tasks and DynamicTasks


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/15f10582
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/15f10582
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/15f10582

Branch: refs/heads/master
Commit: 15f1058230e109fea84884562f24e6af9ff9636f
Parents: 8a3188d
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Jul 18 17:32:59 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 10:41:10 2014 -0400

----------------------------------------------------------------------
 .../java/brooklyn/util/task/DynamicTasks.java   |   6 +
 .../src/main/java/brooklyn/util/task/Tasks.java |   4 +
 .../ControlledDynamicWebAppClusterImpl.java     |   2 +
 .../entity/webapp/DynamicWebAppClusterImpl.java | 197 ++++++++++++-------
 .../entity/webapp/JavaWebAppService.java        |   3 +-
 5 files changed, 136 insertions(+), 76 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/15f10582/core/src/main/java/brooklyn/util/task/DynamicTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/DynamicTasks.java b/core/src/main/java/brooklyn/util/task/DynamicTasks.java
index 4955b32..33780d2 100644
--- a/core/src/main/java/brooklyn/util/task/DynamicTasks.java
+++ b/core/src/main/java/brooklyn/util/task/DynamicTasks.java
@@ -312,5 +312,11 @@ public class DynamicTasks {
     public static void markInessential() {
         Tasks.markInessential();
     }
+
+    /** queues the task if possible, otherwise submits it asynchronously; returns the task for callers to 
+     * {@link Task#getUnchecked()} or {@link Task#blockUntilEnded()} */
+    public static <T> Task<T> submit(TaskAdaptable<T> task, Entity entity) {
+        return queueIfPossible(task).orSubmitAsync(entity).asTask();
+    }
     
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/15f10582/core/src/main/java/brooklyn/util/task/Tasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/Tasks.java b/core/src/main/java/brooklyn/util/task/Tasks.java
index 277f677..d423c86 100644
--- a/core/src/main/java/brooklyn/util/task/Tasks.java
+++ b/core/src/main/java/brooklyn/util/task/Tasks.java
@@ -408,6 +408,10 @@ public class Tasks {
             if (optionalError!=null) throw Exceptions.propagate(optionalError); else throw new RuntimeException("Failed: "+name);
         } }).build();
     }
+    public static Task<Void> warning(final String message, final Throwable optionalError) {
+        log.warn(message);
+        return TaskTags.markInessential(fail(message, optionalError));
+    }
 
     /** marks the current task inessential; this mainly matters if the task is running in a parent
      * {@link TaskQueueingContext} and we don't want the parent to fail if this task fails

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/15f10582/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
index 3f9c026..47e7ec9 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
@@ -311,11 +311,13 @@ public class ControlledDynamicWebAppClusterImpl extends DynamicGroupImpl impleme
 
     @Override
     public void deploy(String url, String targetName) {
+        DynamicWebAppClusterImpl.addToWarsByContext(this, url, targetName);
         getCluster().deploy(url, targetName);
     }
 
     @Override
     public void undeploy(String targetName) {
+        DynamicWebAppClusterImpl.removeFromWarsByContext(this, targetName);
         getCluster().undeploy(targetName);
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/15f10582/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
index 36a62de..e3569d6 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
@@ -23,6 +23,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.Callable;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -31,20 +32,27 @@ import brooklyn.enricher.Enrichers;
 import brooklyn.entity.Entity;
 import brooklyn.entity.annotation.Effector;
 import brooklyn.entity.annotation.EffectorParam;
+import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.basic.Entities;
-import brooklyn.entity.basic.EntityPredicates;
-import brooklyn.entity.basic.Lifecycle;
+import brooklyn.entity.basic.EntityInternal;
+import brooklyn.entity.effector.Effectors;
 import brooklyn.entity.group.DynamicCluster;
 import brooklyn.entity.group.DynamicClusterImpl;
 import brooklyn.event.AttributeSensor;
 import brooklyn.event.SensorEvent;
 import brooklyn.event.SensorEventListener;
-import brooklyn.util.collections.MutableList;
+import brooklyn.management.Task;
+import brooklyn.management.TaskAdaptable;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;
 import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.task.DynamicTasks;
+import brooklyn.util.task.TaskBuilder;
+import brooklyn.util.task.TaskTags;
+import brooklyn.util.task.Tasks;
+import brooklyn.util.time.Duration;
+import brooklyn.util.time.Time;
 
-import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 
@@ -60,7 +68,7 @@ import com.google.common.collect.Iterables;
 public class DynamicWebAppClusterImpl extends DynamicClusterImpl implements DynamicWebAppCluster {
 
     private static final Logger log = LoggerFactory.getLogger(DynamicWebAppClusterImpl.class);
-    private FilenameToWebContextMapper filenameToWebContextMapper = new FilenameToWebContextMapper();
+    private static final FilenameToWebContextMapper filenameToWebContextMapper = new FilenameToWebContextMapper();
     
     /**
      * Instantiate a new DynamicWebAppCluster.  Parameters as per {@link DynamicCluster#DynamicCluster()}
@@ -151,92 +159,131 @@ public class DynamicWebAppClusterImpl extends DynamicClusterImpl implements Dyna
         return up;
     }
     
-    /**
-     * Deploys the given artifact, from a source URL, to all members of the cluster
-     * See {@link FileNameToContextMappingTest} for definitive examples!
-     * 
-     * @param url  where to get the war, as a URL, either classpath://xxx or file:///home/xxx or http(s)...
-     * @param targetName  where to tell the server to serve the WAR, see above
-     */
+    // TODO this will probably be useful elsewhere ... but where to put it?
+    /** Waits for the given target to report service up, then runs the given task
+     * (often an invocation on that entity), with the given name.
+     * If the target goes away, this task marks itself inessential
+     * before failing so as not to cause a parent task to fail. */
+    static <T> Task<T> whenServiceUp(final Entity target, final TaskAdaptable<T> task, String name) {
+        return Tasks.<T>builder().name(name).dynamic(true).body(new Callable<T>() {
+            @Override
+            public T call() {
+                while (true) {
+                    if (!Entities.isManaged(target)) {
+                        Tasks.markInessential();
+                        throw new IllegalStateException("Target "+target+" is no longer managed");
+                    }
+                    if (target.getAttribute(Attributes.SERVICE_UP)) {
+                        TaskTags.markInessential(task);
+                        DynamicTasks.queue(task);
+                        try {
+                            return task.asTask().getUnchecked();
+                        } catch (Exception e) {
+                            if (Entities.isManaged(target)) {
+                                throw Exceptions.propagate(e);
+                            } else {
+                                Tasks.markInessential();
+                                throw new IllegalStateException("Target "+target+" is no longer managed", e);
+                            }
+                        }
+                    }
+                    // TODO replace with subscription?
+                    Time.sleep(Duration.ONE_SECOND);
+                }
+            }
+        }).build();        
+    }
+
+    @Override
     @Effector(description="Deploys the given artifact, from a source URL, to a given deployment filename/context")
     public void deploy(
             @EffectorParam(name="url", description="URL of WAR file") String url, 
             @EffectorParam(name="targetName", description="context path where WAR should be deployed (/ for ROOT)") String targetName) {
-        try {
-            checkNotNull(url, "url");
-            checkNotNull(targetName, "targetName");
-            
-            // set it up so future nodes get the right wars
-            synchronized (this) {
-                Map<String,String> newWarsMap = MutableMap.copyOf(getConfig(WARS_BY_CONTEXT));
-                newWarsMap.put(targetName, url);
-                setConfig(WARS_BY_CONTEXT, newWarsMap);
-            }
-            
-            // now actually deploy
-            List <Entity> clusterMembers = MutableList.copyOf(
-                Iterables.filter(getChildren(), Predicates.and(
-                     Predicates.instanceOf(JavaWebAppSoftwareProcess.class),
-                     EntityPredicates.attributeEqualTo(SERVICE_STATE, Lifecycle.RUNNING)
-            )));
-            Entities.invokeEffectorListWithArgs(this, clusterMembers, DEPLOY, url, targetName).get();            
-            
-            // Update attribute
-            Set<String> deployedWars = MutableSet.copyOf(getAttribute(DEPLOYED_WARS));
-            deployedWars.add(targetName);
-            setAttribute(DEPLOYED_WARS, deployedWars);
-            
-        } catch (Exception e) {
-            // Log and propagate, so that log says which entity had problems...
-            log.warn("Error deploying '"+url+"' to "+targetName+" on "+toString()+"; rethrowing...", e);
-            throw Exceptions.propagate(e);
+        checkNotNull(url, "url");
+        checkNotNull(targetName, "targetName");
+        targetName = filenameToWebContextMapper.convertDeploymentTargetNameToContext(targetName);
+
+        // set it up so future nodes get the right wars
+        addToWarsByContext(this, url, targetName);
+        
+        log.debug("Deploying "+targetName+"->"+url+" across cluster "+this+"; WARs now "+getConfig(WARS_BY_CONTEXT));
+
+        Iterable<CanDeployAndUndeploy> targets = Iterables.filter(getChildren(), CanDeployAndUndeploy.class);
+        TaskBuilder<Void> tb = Tasks.<Void>builder().parallel(true).name("Deploy "+targetName+" to cluster (size "+Iterables.size(targets)+")");
+        for (Entity target: targets) {
+            tb.add(whenServiceUp(target, Effectors.invocation(target, DEPLOY, MutableMap.of("url", url, "targetName", targetName)),
+                "Deploy "+targetName+" to "+target+" when ready"));
         }
+        DynamicTasks.queueIfPossible(tb.build()).orSubmitAsync(this).asTask().getUnchecked();
+
+        // Update attribute
+        Set<String> deployedWars = MutableSet.copyOf(getAttribute(DEPLOYED_WARS));
+        deployedWars.add(targetName);
+        setAttribute(DEPLOYED_WARS, deployedWars);
     }
     
-    /*
-     * TODO
-     * 
-     * - deploy to all, not just running, with a wait-for-running-or-bail-out logic
-     * - thread pool
-     * - redeploy to all (simple way, with notes)
-     */
-    
-    /** For the DEPLOYED_WARS to be updated, the input must match the result of the call to deploy */
+    @Override
     @Effector(description="Undeploys the given context/artifact")
     public void undeploy(@EffectorParam(name="targetName") String targetName) {
+        checkNotNull(targetName, "targetName");
+
+        // set it up so future nodes get the right wars
+        removeFromWarsByContext(this, targetName);
         
-        try {
-            checkNotNull(targetName, "targetName");
-            
-            // set it up so future nodes get the right wars
-            synchronized (this) {
-                Map<String,String> newWarsMap = MutableMap.copyOf(getConfig(WARS_BY_CONTEXT));
-                newWarsMap.remove(targetName);
-                setConfig(WARS_BY_CONTEXT, newWarsMap);
-            }
+        log.debug("Undeploying "+targetName+" across cluster "+this+"; WARs now "+getConfig(WARS_BY_CONTEXT));
+
+        Iterable<CanDeployAndUndeploy> targets = Iterables.filter(getChildren(), CanDeployAndUndeploy.class);
+        TaskBuilder<Void> tb = Tasks.<Void>builder().parallel(true).name("Undeploy "+targetName+" across cluster (size "+Iterables.size(targets)+")");
+        for (Entity target: targets) {
+            tb.add(whenServiceUp(target, Effectors.invocation(target, UNDEPLOY, MutableMap.of("targetName", targetName)),
+                "Undeploy "+targetName+" at "+target+" when ready"));
+        }
+        DynamicTasks.queueIfPossible(tb.build()).orSubmitAsync(this).asTask().getUnchecked();
+
+        // Update attribute
+        Set<String> deployedWars = MutableSet.copyOf(getAttribute(DEPLOYED_WARS));
+        deployedWars.remove( filenameToWebContextMapper.convertDeploymentTargetNameToContext(targetName) );
+        setAttribute(DEPLOYED_WARS, deployedWars);
+    }
+
+    static void addToWarsByContext(Entity entity, String url, String targetName) {
+        targetName = filenameToWebContextMapper.convertDeploymentTargetNameToContext(targetName);
+        synchronized (entity) {
+            Map<String,String> newWarsMap = MutableMap.copyOf(entity.getConfig(WARS_BY_CONTEXT));
+            newWarsMap.put(targetName, url);
+            ((EntityInternal)entity).setConfig(WARS_BY_CONTEXT, newWarsMap);
+        }
+    }
 
-            List <Entity> clusterMembers = MutableList.copyOf(
-                Iterables.filter(getChildren(), Predicates.and(
-                     Predicates.instanceOf(JavaWebAppSoftwareProcess.class),
-                     EntityPredicates.attributeEqualTo(SERVICE_STATE, Lifecycle.RUNNING)
-            )));
-            Entities.invokeEffectorListWithArgs(this, clusterMembers, UNDEPLOY, targetName).get(); 
-            
-            // Update attribute
-            Set<String> deployedWars = MutableSet.copyOf(getAttribute(DEPLOYED_WARS));
-            deployedWars.remove( filenameToWebContextMapper.convertDeploymentTargetNameToContext(targetName) );
-            setAttribute(DEPLOYED_WARS, deployedWars);
-            
-        } catch (Exception e) {
-            // Log and propagate, so that log says which entity had problems...
-            log.warn("Error undeploying '"+targetName+"' on "+toString()+"; rethrowing...", e);
-            throw Exceptions.propagate(e);
+    static void removeFromWarsByContext(Entity entity, String targetName) {
+        targetName = filenameToWebContextMapper.convertDeploymentTargetNameToContext(targetName);
+        synchronized (entity) {
+            Map<String,String> newWarsMap = MutableMap.copyOf(entity.getConfig(WARS_BY_CONTEXT));
+            String url = newWarsMap.remove(targetName);
+            if (url==null) {
+                DynamicTasks.submit(Tasks.warning("Context "+targetName+" not known at "+entity+"; attempting to undeploy regardless", null), entity);
+            }
+            ((EntityInternal)entity).setConfig(WARS_BY_CONTEXT, newWarsMap);
         }
     }
 
     @Override
     public void redeployAll() {
-        throw new UnsupportedOperationException("TODO - support redeploying all WARs (if any of the deploy/undeploys fail)");
+        Map<String, String> wars = MutableMap.copyOf(getConfig(WARS_BY_CONTEXT));
+        String redeployPrefix = "Redeploy all WARs (count "+wars.size()+")";
+
+        log.debug("Redeplying all WARs across cluster "+this+": "+getConfig(WARS_BY_CONTEXT));
+        
+        Iterable<CanDeployAndUndeploy> targets = Iterables.filter(getChildren(), CanDeployAndUndeploy.class);
+        TaskBuilder<Void> tb = Tasks.<Void>builder().parallel(true).name(redeployPrefix+" across cluster (size "+Iterables.size(targets)+")");
+        for (Entity target: targets) {
+            TaskBuilder<Void> redeployAllToTarget = Tasks.<Void>builder().name(redeployPrefix+" at "+target+" (after ready check)");
+            for (String targetName: wars.keySet()) {
+                redeployAllToTarget.add(Effectors.invocation(target, DEPLOY, MutableMap.of("url", wars.get(targetName), "targetName", targetName)));
+            }
+            tb.add(redeployAllToTarget.build());
+        }
+        DynamicTasks.queueIfPossible(tb.build()).orSubmitAsync(this).asTask().getUnchecked();
     }  
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/15f10582/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppService.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppService.java b/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppService.java
index 8561c12..1317ef0 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppService.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppService.java
@@ -23,6 +23,7 @@ import java.util.Map;
 import java.util.Set;
 
 import brooklyn.config.ConfigKey;
+import brooklyn.entity.Entity;
 import brooklyn.entity.annotation.Effector;
 import brooklyn.entity.annotation.EffectorParam;
 import brooklyn.entity.basic.MethodEffector;
@@ -49,7 +50,7 @@ public interface JavaWebAppService extends WebAppService, UsesJava {
             Map.class, "wars.by.context", "Map of context keys (path in user-facing URL, typically without slashes) to archives (e.g. WARs by URL) to deploy, supporting file: and classpath: prefixes)");
     
     /** Optional marker interface for entities which support 'deploy' and 'undeploy' */
-    public interface CanDeployAndUndeploy {
+    public interface CanDeployAndUndeploy extends Entity {
 
         @SuppressWarnings({ "unchecked", "rawtypes" })
         public static final AttributeSensor<Set<String>> DEPLOYED_WARS = new BasicAttributeSensor(


[05/31] git commit: include blocking details when waiting for service up to invoke an effector on a child

Posted by he...@apache.org.
include blocking details when waiting for service up to invoke an effector on a child


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/03944674
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/03944674
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/03944674

Branch: refs/heads/master
Commit: 039446749c3c6926abc51a3b0b21a8b14963851c
Parents: bbfbd37
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Jul 21 20:38:49 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 10:41:11 2014 -0400

----------------------------------------------------------------------
 .../entity/webapp/DynamicWebAppClusterImpl.java | 43 ++++++++++++--------
 1 file changed, 25 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/03944674/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
index 3378972..f62f8eb 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
@@ -168,27 +168,34 @@ public class DynamicWebAppClusterImpl extends DynamicClusterImpl implements Dyna
         return Tasks.<T>builder().name(name).dynamic(true).body(new Callable<T>() {
             @Override
             public T call() {
-                while (true) {
-                    if (!Entities.isManaged(target)) {
-                        Tasks.markInessential();
-                        throw new IllegalStateException("Target "+target+" is no longer managed");
-                    }
-                    if (target.getAttribute(Attributes.SERVICE_UP)) {
-                        TaskTags.markInessential(task);
-                        DynamicTasks.queue(task);
-                        try {
-                            return task.asTask().getUnchecked();
-                        } catch (Exception e) {
-                            if (Entities.isManaged(target)) {
-                                throw Exceptions.propagate(e);
-                            } else {
-                                Tasks.markInessential();
-                                throw new IllegalStateException("Target "+target+" is no longer managed", e);
+                try {
+                    while (true) {
+                        if (!Entities.isManaged(target)) {
+                            Tasks.markInessential();
+                            throw new IllegalStateException("Target "+target+" is no longer managed");
+                        }
+                        if (target.getAttribute(Attributes.SERVICE_UP)) {
+                            Tasks.resetBlockingDetails();
+                            TaskTags.markInessential(task);
+                            DynamicTasks.queue(task);
+                            try {
+                                return task.asTask().getUnchecked();
+                            } catch (Exception e) {
+                                if (Entities.isManaged(target)) {
+                                    throw Exceptions.propagate(e);
+                                } else {
+                                    Tasks.markInessential();
+                                    throw new IllegalStateException("Target "+target+" is no longer managed", e);
+                                }
                             }
+                        } else {
+                            Tasks.setBlockingDetails("Waiting on "+target+" to be ready");
                         }
+                        // TODO replace with subscription?
+                        Time.sleep(Duration.ONE_SECOND);
                     }
-                    // TODO replace with subscription?
-                    Time.sleep(Duration.ONE_SECOND);
+                } finally {
+                    Tasks.resetBlockingDetails();
                 }
             }
         }).build();        


[03/31] git commit: tidy initial pull request from @bmwshop, as per code review, plus some todo comments

Posted by he...@apache.org.
tidy initial pull request from @bmwshop, as per code review, plus some todo comments


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/dbf26e3a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/dbf26e3a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/dbf26e3a

Branch: refs/heads/master
Commit: dbf26e3a46afa7a7b25374043a0e0969052d049f
Parents: 9c9f037
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Jul 18 15:38:37 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 10:41:10 2014 -0400

----------------------------------------------------------------------
 .../webapp/ControlledDynamicWebAppCluster.java  |  25 ++--
 .../ControlledDynamicWebAppClusterImpl.java     | 114 ++++++++++---------
 .../entity/webapp/DynamicWebAppClusterImpl.java |   2 +
 .../entity/webapp/JavaWebAppService.java        |  66 +++++++++++
 .../webapp/JavaWebAppSoftwareProcess.java       |  52 +--------
 5 files changed, 134 insertions(+), 125 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/dbf26e3a/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppCluster.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppCluster.java b/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppCluster.java
index 17fc569..0c263d9 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppCluster.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppCluster.java
@@ -21,8 +21,6 @@ package brooklyn.entity.webapp;
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.Entity;
 import brooklyn.entity.Group;
-import brooklyn.entity.annotation.Effector;
-import brooklyn.entity.annotation.EffectorParam;
 import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.ConfigurableEntityFactory;
@@ -59,8 +57,8 @@ import brooklyn.util.flags.SetFromFlag;
  * members has no effect on the members of the underlying DynamicCluster - treat this as a read-only view.
  */
 @ImplementedBy(ControlledDynamicWebAppClusterImpl.class)
-public interface ControlledDynamicWebAppCluster extends DynamicGroup, Entity, Startable, Resizable, MemberReplaceable, Group, ElasticJavaWebAppService, JavaWebAppSoftwareProcess {
-
+public interface ControlledDynamicWebAppCluster extends DynamicGroup, Entity, Startable, Resizable, MemberReplaceable, Group, ElasticJavaWebAppService, JavaWebAppService.CanDeployAndUndeploy, JavaWebAppService.CanRedeployAll {
+    
     @SetFromFlag("initialSize")
     public static ConfigKey<Integer> INITIAL_SIZE = ConfigKeys.newConfigKeyWithDefault(Cluster.INITIAL_SIZE, 1);
 
@@ -68,20 +66,24 @@ public interface ControlledDynamicWebAppCluster extends DynamicGroup, Entity, St
     public static BasicAttributeSensorAndConfigKey<LoadBalancer> CONTROLLER = new BasicAttributeSensorAndConfigKey<LoadBalancer>(
         LoadBalancer.class, "controlleddynamicwebappcluster.controller", "Controller for the cluster; if null a default will created (using controllerSpec)");
 
+    @SuppressWarnings({ "unchecked", "rawtypes" })
     @SetFromFlag("controllerSpec")
     public static BasicAttributeSensorAndConfigKey<EntitySpec<? extends LoadBalancer>> CONTROLLER_SPEC = new BasicAttributeSensorAndConfigKey(
             EntitySpec.class, "controlleddynamicwebappcluster.controllerSpec", "Spec for creating the controller (if one not supplied explicitly); if null an NGINX instance will be created");
 
+    @SuppressWarnings({ "unchecked", "rawtypes", "deprecation" })
     /** factory (or closure) to create the web server, given flags */
     @SetFromFlag("factory")
     public static BasicAttributeSensorAndConfigKey<ConfigurableEntityFactory<? extends WebAppService>> FACTORY = new BasicAttributeSensorAndConfigKey(
             ConfigurableEntityFactory.class, DynamicCluster.FACTORY.getName(), "factory (or closure) to create the web server");
 
+    @SuppressWarnings({ "unchecked", "rawtypes" })
     /** Spec for web server entiites to be created */
     @SetFromFlag("memberSpec")
     public static BasicAttributeSensorAndConfigKey<EntitySpec<? extends WebAppService>> MEMBER_SPEC = new BasicAttributeSensorAndConfigKey(
             EntitySpec.class, DynamicCluster.MEMBER_SPEC.getName(), "Spec for web server entiites to be created");
 
+    @SuppressWarnings({ "unchecked", "rawtypes" })
     @SetFromFlag("webClusterSpec")
     public static BasicAttributeSensorAndConfigKey<EntitySpec<? extends DynamicWebAppCluster>> WEB_CLUSTER_SPEC = new BasicAttributeSensorAndConfigKey(
             EntitySpec.class, "controlleddynamicwebappcluster.webClusterSpec", "Spec for creating the cluster; if null a DynamicWebAppCluster will be created");
@@ -93,24 +95,11 @@ public interface ControlledDynamicWebAppCluster extends DynamicGroup, Entity, St
 
     public static final AttributeSensor<Lifecycle> SERVICE_STATE = Attributes.SERVICE_STATE;
 
+    
     public LoadBalancer getController();
     
     public ConfigurableEntityFactory<WebAppService> getFactory();
     
     public DynamicWebAppCluster getCluster();
     
-    @Effector(description="Deploys the given artifact, from a source URL, to a given deployment filename/context")
-    public void deploy(
-            @EffectorParam(name="url", description="URL of WAR file") String url, 
-            @EffectorParam(name="targetName", description="context path where WAR should be deployed (/ for ROOT)") String targetName);
-
-    @Effector(description="Undeploys the given context/artifact")
-    public void undeploy(
-            @EffectorParam(name="targetName") String targetName); 
-    
-    @Effector(description="Updates the given context/artifact")
-    public void update(
-    		@EffectorParam(name="url", description="URL of NEW WAR file") String url,
-            @EffectorParam(name="targetName") String targetName);    
-    
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/dbf26e3a/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
index 262f9f8..ac70f3a 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
@@ -18,6 +18,8 @@
  */
 package brooklyn.entity.webapp;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 import java.util.Collection;
 import java.util.EnumSet;
 import java.util.List;
@@ -50,17 +52,14 @@ import brooklyn.event.feed.ConfigToAttributes;
 import brooklyn.location.Location;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
+import brooklyn.util.collections.MutableSet;
 import brooklyn.util.exceptions.Exceptions;
 
 import com.google.common.base.Predicate;
-import com.google.common.base.Throwables;
+import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-
-import brooklyn.entity.webapp.FilenameToWebContextMapper;
-import static com.google.common.base.Preconditions.checkNotNull;
 
 public class ControlledDynamicWebAppClusterImpl extends DynamicGroupImpl implements ControlledDynamicWebAppCluster {
 
@@ -337,76 +336,79 @@ public class ControlledDynamicWebAppClusterImpl extends DynamicGroupImpl impleme
         try {
             checkNotNull(url, "url");
             checkNotNull(targetName, "targetName");
-            // actually deploy
-            List <Entity> cluster_members = Lists.newArrayList();
-//            cluster_members.addAll((Collection<? extends Entity>) Iterables.filter(getCluster().getChildren(), JavaWebAppSoftwareProcess.class)); 
-            for (JavaWebAppSoftwareProcess member : Iterables.filter(getCluster().getChildren(), JavaWebAppSoftwareProcess.class)) {
-            	Lifecycle serviceState = member.getAttribute(SERVICE_STATE);
-            	if (serviceState == Lifecycle.RUNNING) {
-            	  cluster_members.add(member);
-            	}
-            }            
-            Entities.invokeEffectorListWithArgs(this, cluster_members, DEPLOY, url, targetName).get();            
             
-            // Update attribute
-            Set<String> deployedWars = getAttribute(DEPLOYED_WARS);
-            if (deployedWars == null) {
-                deployedWars = Sets.newLinkedHashSet();
+            // set it up so future nodes get the right wars
+            synchronized (this) {
+                Map<String,String> newWarsMap = MutableMap.copyOf(getConfig(WARS_BY_CONTEXT));
+                newWarsMap.put(targetName, url);
+                setConfig(WARS_BY_CONTEXT, newWarsMap);
             }
+            
+            // now actually deploy
+            List <Entity> clusterMembers = MutableList.copyOf(
+                Iterables.filter(getCluster().getChildren(), Predicates.and(
+                     Predicates.instanceOf(JavaWebAppSoftwareProcess.class),
+                     EntityPredicates.attributeEqualTo(SERVICE_STATE, Lifecycle.RUNNING)
+            )));
+            Entities.invokeEffectorListWithArgs(this, clusterMembers, DEPLOY, url, targetName).get();            
+            
+            // Update attribute
+            Set<String> deployedWars = MutableSet.copyOf(getAttribute(DEPLOYED_WARS));
             deployedWars.add(targetName);
             setAttribute(DEPLOYED_WARS, deployedWars);
-        } catch (RuntimeException e) {
+            
+        } catch (Exception e) {
             // Log and propagate, so that log says which entity had problems...
             log.warn("Error deploying '"+url+"' to "+targetName+" on "+toString()+"; rethrowing...", e);
-            throw Throwables.propagate(e);
-        } catch (Throwable th) {
-            // Log and propagate, so that log says which entity had problems...
-            log.warn("Error undeploying '"+targetName+"' on "+toString()+"; rethrowing...", th);
-            throw Throwables.propagate(th);
+            throw Exceptions.propagate(e);
         }
     }
+    
+    /*
+     * TODO
+     * 
+     * - deploy to all, not just running, with a wait-for-running-or-bail-out logic
+     * - thread pool
+     * - redeploy to all (simple way, with notes)
+     * - check-in, then move down with echo here
+     */
+    
     /** For the DEPLOYED_WARS to be updated, the input must match the result of the call to deploy */
     @Effector(description="Undeploys the given context/artifact")
-    public void undeploy(
-            @EffectorParam(name="targetName") String targetName) {
+    public void undeploy(@EffectorParam(name="targetName") String targetName) {
     	
         try {
+            checkNotNull(targetName, "targetName");
+            
+            // set it up so future nodes get the right wars
+            synchronized (this) {
+                Map<String,String> newWarsMap = MutableMap.copyOf(getConfig(WARS_BY_CONTEXT));
+                newWarsMap.remove(targetName);
+                setConfig(WARS_BY_CONTEXT, newWarsMap);
+            }
 
-            List <Entity> cluster_members = Lists.newArrayList();
-//            cluster_members.addAll((Collection<? extends Entity>) Iterables.filter(getCluster().getChildren(), JavaWebAppSoftwareProcess.class));
-            for (JavaWebAppSoftwareProcess member : Iterables.filter(getCluster().getChildren(), JavaWebAppSoftwareProcess.class)) {
-            	Lifecycle serviceState = member.getAttribute(SERVICE_STATE);
-            	if (serviceState == Lifecycle.RUNNING) {
-            	  cluster_members.add(member);
-            	}
-            }             
-            Entities.invokeEffectorListWithArgs(this, cluster_members, UNDEPLOY, targetName).get(); 
+            List <Entity> clusterMembers = MutableList.copyOf(
+                Iterables.filter(getCluster().getChildren(), Predicates.and(
+                     Predicates.instanceOf(JavaWebAppSoftwareProcess.class),
+                     EntityPredicates.attributeEqualTo(SERVICE_STATE, Lifecycle.RUNNING)
+            )));
+            Entities.invokeEffectorListWithArgs(this, clusterMembers, UNDEPLOY, targetName).get(); 
             
-       	
             // Update attribute
-            Set<String> deployedWars = getAttribute(DEPLOYED_WARS);
-            if (deployedWars == null) {
-                deployedWars = Sets.newLinkedHashSet();
-            }
+            Set<String> deployedWars = MutableSet.copyOf(getAttribute(DEPLOYED_WARS));
             deployedWars.remove( filenameToWebContextMapper.convertDeploymentTargetNameToContext(targetName) );
             setAttribute(DEPLOYED_WARS, deployedWars);
-        } catch (RuntimeException e) {
+            
+        } catch (Exception e) {
             // Log and propagate, so that log says which entity had problems...
             log.warn("Error undeploying '"+targetName+"' on "+toString()+"; rethrowing...", e);
-            throw Throwables.propagate(e);
-        } catch (Throwable th) {
-            // Log and propagate, so that log says which entity had problems...
-            log.warn("Error undeploying '"+targetName+"' on "+toString()+"; rethrowing...", th);
-            throw Throwables.propagate(th);
+            throw Exceptions.propagate(e);
         }
+    }
+
+    @Override
+    public void redeployAll() {
+        throw new UnsupportedOperationException("TODO - support redeploying all WARs (if any of the deploy/undeploys fail)");
     }  
-    @Effector(description="Updates the given context/artifact")
-    public void update(
-    		@EffectorParam(name="url", description="URL of NEW WAR file") String url,
-            @EffectorParam(name="targetName") String targetName) {
-    	// simple for now
-    	undeploy(targetName);
-    	deploy(url, targetName);
-    
-    }    
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/dbf26e3a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
index 360870f..ec942ee 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
@@ -82,7 +82,9 @@ public class DynamicWebAppClusterImpl extends DynamicClusterImpl implements Dyna
         }
         
         for (List<? extends AttributeSensor<? extends Number>> es : averagingEnricherSetup) {
+            @SuppressWarnings("unchecked")
             AttributeSensor<Number> t = (AttributeSensor<Number>) es.get(0);
+            @SuppressWarnings("unchecked")
             AttributeSensor<Double> average = (AttributeSensor<Double>) es.get(1);
             addEnricher(Enrichers.builder()
                     .aggregating(t)

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/dbf26e3a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppService.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppService.java b/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppService.java
index 044f49c..8561c12 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppService.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppService.java
@@ -20,9 +20,15 @@ package brooklyn.entity.webapp;
 
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import brooklyn.config.ConfigKey;
+import brooklyn.entity.annotation.Effector;
+import brooklyn.entity.annotation.EffectorParam;
+import brooklyn.entity.basic.MethodEffector;
 import brooklyn.entity.java.UsesJava;
+import brooklyn.event.AttributeSensor;
+import brooklyn.event.basic.BasicAttributeSensor;
 import brooklyn.event.basic.BasicConfigKey;
 import brooklyn.util.flags.SetFromFlag;
 
@@ -32,11 +38,71 @@ public interface JavaWebAppService extends WebAppService, UsesJava {
 	public static final ConfigKey<String> ROOT_WAR = new BasicConfigKey<String>(
 	        String.class, "wars.root", "WAR file to deploy as the ROOT, as URL (supporting file: and classpath: prefixes)");
 
+    @SuppressWarnings({ "unchecked", "rawtypes" })
     @SetFromFlag("wars")
 	public static final ConfigKey<List<String>> NAMED_WARS = new BasicConfigKey(
 	        List.class, "wars.named", "Archive files to deploy, as URL strings (supporting file: and classpath: prefixes); context (path in user-facing URL) will be inferred by name");
     
+    @SuppressWarnings({ "unchecked", "rawtypes" })
     @SetFromFlag("warsByContext")
     public static final ConfigKey<Map<String,String>> WARS_BY_CONTEXT = new BasicConfigKey(
             Map.class, "wars.by.context", "Map of context keys (path in user-facing URL, typically without slashes) to archives (e.g. WARs by URL) to deploy, supporting file: and classpath: prefixes)");
+    
+    /** Optional marker interface for entities which support 'deploy' and 'undeploy' */
+    public interface CanDeployAndUndeploy {
+
+        @SuppressWarnings({ "unchecked", "rawtypes" })
+        public static final AttributeSensor<Set<String>> DEPLOYED_WARS = new BasicAttributeSensor(
+                Set.class, "webapp.deployedWars", "Names of archives/contexts that are currently deployed");
+
+        public static final MethodEffector<Void> DEPLOY = new MethodEffector<Void>(CanDeployAndUndeploy.class, "deploy");
+        public static final MethodEffector<Void> UNDEPLOY = new MethodEffector<Void>(CanDeployAndUndeploy.class, "undeploy");
+
+        /**
+         * Deploys the given artifact, from a source URL, to a given deployment filename/context.
+         * There is some variance in expected filename/context at various servers,
+         * so the following conventions are followed:
+         * <p>
+         *   either ROOT.WAR or /       denotes root context
+         * <p>
+         *   anything of form  FOO.?AR  (ending .?AR) is copied with that name (unless copying not necessary)
+         *                              and is expected to be served from /FOO
+         * <p>
+         *   anything of form  /FOO     (with leading slash) is expected to be served from /FOO
+         *                              (and is copied as FOO.WAR)
+         * <p>
+         *   anything of form  FOO      (without a dot) is expected to be served from /FOO
+         *                              (and is copied as FOO.WAR)
+         * <p>
+         *   otherwise <i>please note</i> behaviour may vary on different appservers;
+         *   e.g. FOO.FOO would probably be ignored on appservers which expect a file copied across (usually),
+         *   but served as /FOO.FOO on systems that take a deployment context.
+         * <p>
+         * See {@link FileNameToContextMappingTest} for definitive examples!
+         *
+         * @param url  where to get the war, as a URL, either classpath://xxx or file:///home/xxx or http(s)...
+         * @param targetName  where to tell the server to serve the WAR, see above
+         */
+        @Effector(description="Deploys the given artifact, from a source URL, to a given deployment filename/context")
+        public void deploy(
+                @EffectorParam(name="url", description="URL of WAR file") String url, 
+                @EffectorParam(name="targetName", description="context path where WAR should be deployed (/ for ROOT)") String targetName);
+
+        /** 
+         * For the DEPLOYED_WARS to be updated, the input must match the result of the call to deploy,
+         * e.g. the transformed name using 
+         */
+        @Effector(description="Undeploys the given context/artifact")
+        public void undeploy(
+                @EffectorParam(name="targetName") String targetName);
+    }
+
+    /** Optional marker interface for entities which support 'redeployAll' */
+    public interface CanRedeployAll {
+        public static final MethodEffector<Void> REDEPLOY_ALL = new MethodEffector<Void>(CanRedeployAll.class, "redeployAll");
+        
+        @Effector(description="Redeploys all web apps known here across the cluster (e.g. if it gets into an inconsistent state)")
+        public void redeployAll();
+    }
+        
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/dbf26e3a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcess.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcess.java b/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcess.java
index a6b43e2..5460f79 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcess.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcess.java
@@ -18,57 +18,7 @@
  */
 package brooklyn.entity.webapp;
 
-import java.util.Set;
-
-import brooklyn.entity.annotation.Effector;
-import brooklyn.entity.annotation.EffectorParam;
-import brooklyn.entity.basic.MethodEffector;
 import brooklyn.entity.basic.SoftwareProcess;
-import brooklyn.event.AttributeSensor;
-import brooklyn.event.basic.BasicAttributeSensor;
-
-public interface JavaWebAppSoftwareProcess extends SoftwareProcess, JavaWebAppService {
-
-    public static final AttributeSensor<Set<String>> DEPLOYED_WARS = new BasicAttributeSensor(
-            Set.class, "webapp.deployedWars", "Names of archives/contexts that are currently deployed");
-
-    public static final MethodEffector<Void> DEPLOY = new MethodEffector<Void>(JavaWebAppSoftwareProcess.class, "deploy");
-    public static final MethodEffector<Void> UNDEPLOY = new MethodEffector<Void>(JavaWebAppSoftwareProcess.class, "undeploy");
-
-    /**
-     * Deploys the given artifact, from a source URL, to a given deployment filename/context.
-     * There is some variance in expected filename/context at various servers,
-     * so the following conventions are followed:
-     * <p>
-     *   either ROOT.WAR or /       denotes root context
-     * <p>
-     *   anything of form  FOO.?AR  (ending .?AR) is copied with that name (unless copying not necessary)
-     *                              and is expected to be served from /FOO
-     * <p>
-     *   anything of form  /FOO     (with leading slash) is expected to be served from /FOO
-     *                              (and is copied as FOO.WAR)
-     * <p>
-     *   anything of form  FOO      (without a dot) is expected to be served from /FOO
-     *                              (and is copied as FOO.WAR)
-     * <p>
-     *   otherwise <i>please note</i> behaviour may vary on different appservers;
-     *   e.g. FOO.FOO would probably be ignored on appservers which expect a file copied across (usually),
-     *   but served as /FOO.FOO on systems that take a deployment context.
-     * <p>
-     * See {@link FileNameToContextMappingTest} for definitive examples!
-     *
-     * @param url  where to get the war, as a URL, either classpath://xxx or file:///home/xxx or http(s)...
-     * @param targetName  where to tell the server to serve the WAR, see above
-     */
-    @Effector(description="Deploys the given artifact, from a source URL, to a given deployment filename/context")
-    public void deploy(
-            @EffectorParam(name="url", description="URL of WAR file") String url, 
-            @EffectorParam(name="targetName", description="context path where WAR should be deployed (/ for ROOT)") String targetName);
 
-    /** 
-     * For the DEPLOYED_WARS to be updated, the input must match the result of the call to deploy
-     */
-    @Effector(description="Undeploys the given context/artifact")
-    public void undeploy(
-            @EffectorParam(name="targetName") String targetName);
+public interface JavaWebAppSoftwareProcess extends SoftwareProcess, JavaWebAppService, JavaWebAppService.CanDeployAndUndeploy {
 }


[19/31] git commit: optimize queue size computation and minor other optimizations

Posted by he...@apache.org.
optimize queue size computation and minor other optimizations


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/e17b6094
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/e17b6094
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/e17b6094

Branch: refs/heads/master
Commit: e17b6094518abf48c298d3dac9b73c279d44be94
Parents: 40b63e2
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Jul 23 19:11:53 2014 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 10:42:09 2014 -0400

----------------------------------------------------------------------
 .../brooklyn/util/task/DynamicSequentialTask.java    | 15 +++++++++------
 .../brooklyn/util/task/SingleThreadedScheduler.java  | 10 ++++++----
 2 files changed, 15 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e17b6094/core/src/main/java/brooklyn/util/task/DynamicSequentialTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/DynamicSequentialTask.java b/core/src/main/java/brooklyn/util/task/DynamicSequentialTask.java
index a17ffbe..520c8b0 100644
--- a/core/src/main/java/brooklyn/util/task/DynamicSequentialTask.java
+++ b/core/src/main/java/brooklyn/util/task/DynamicSequentialTask.java
@@ -184,9 +184,9 @@ public class DynamicSequentialTask<T> extends BasicTask<T> implements HasTaskChi
     /** submits the indicated task for execution in the current execution context, and returns immediately */
     protected void submitBackgroundInheritingContext(Task<?> task) {
         BasicExecutionContext ec = BasicExecutionContext.getCurrentExecutionContext();
-        if (log.isTraceEnabled())
-            log.trace("task {} - submitting background task {} ({})", new Object[] { 
-                Tasks.current(), task, ec });
+        if (log.isTraceEnabled()) {
+            log.trace("task {} - submitting background task {} ({})", new Object[] { Tasks.current(), task, ec });
+        }
         if (ec==null) {
             String message = Tasks.current()!=null ?
                     // user forgot ExecContext:
@@ -197,10 +197,13 @@ public class DynamicSequentialTask<T> extends BasicTask<T> implements HasTaskChi
             throw new IllegalStateException(message);
         }
         synchronized (task) {
-            if (task.isSubmitted() && !task.isDone())
-                log.debug("DST "+this+" skipping submission of child "+task+" because it is already submitted");
-            else
+            if (task.isSubmitted() && !task.isDone()) {
+                if (log.isTraceEnabled()) {
+                    log.trace("DST "+this+" skipping submission of child "+task+" because it is already submitted");
+                }
+            } else {
                 ec.submit(task);
+            }
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e17b6094/core/src/main/java/brooklyn/util/task/SingleThreadedScheduler.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/SingleThreadedScheduler.java b/core/src/main/java/brooklyn/util/task/SingleThreadedScheduler.java
index 420002f..14c08c4 100644
--- a/core/src/main/java/brooklyn/util/task/SingleThreadedScheduler.java
+++ b/core/src/main/java/brooklyn/util/task/SingleThreadedScheduler.java
@@ -49,6 +49,7 @@ public class SingleThreadedScheduler implements TaskScheduler, CanSetName {
     private static final Logger LOG = LoggerFactory.getLogger(SingleThreadedScheduler.class);
     
     private final Queue<QueuedSubmission<?>> order = new ConcurrentLinkedQueue<QueuedSubmission<?>>();
+    private int queueSize = 0;
     private final AtomicBoolean running = new AtomicBoolean(false);
     
     private ExecutorService executor;
@@ -77,13 +78,13 @@ public class SingleThreadedScheduler implements TaskScheduler, CanSetName {
         } else {
             WrappingFuture<T> f = new WrappingFuture<T>();
             order.add(new QueuedSubmission<T>(c, f));
-            int size = order.size();
-            if (size>0 && (size == 50 || (size<=500 && (size%100)==0) || (size%1000)==0) && size!=lastSizeWarn) {
-                LOG.warn("{} is backing up, {} tasks queued", this, size);
+            queueSize++;
+            if (queueSize>0 && (queueSize == 50 || (queueSize<=500 && (queueSize%100)==0) || (queueSize%1000)==0) && queueSize!=lastSizeWarn) {
+                LOG.warn("{} is backing up, {} tasks queued", this, queueSize);
                 if (LOG.isDebugEnabled()) {
                     LOG.debug("Task queue backing up detail, queue "+this+"; task context is "+Tasks.current()+"; latest task is "+c+"; first task is "+order.peek());
                 }
-                lastSizeWarn = size;
+                lastSizeWarn = queueSize;
             }
             return f;
         }
@@ -99,6 +100,7 @@ public class SingleThreadedScheduler implements TaskScheduler, CanSetName {
                 done = true;
             } else {
                 QueuedSubmission<?> qs = order.remove();
+                queueSize--;
                 if (!qs.f.isCancelled()) {
                     Future future = executeNow(qs.c);
                     qs.f.setDelegate(future);


[09/31] git commit: squash code warnings, clarify user-facing messages, fix redeployAll bug

Posted by he...@apache.org.
squash code warnings, clarify user-facing messages, fix redeployAll bug


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/b1fa2993
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/b1fa2993
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/b1fa2993

Branch: refs/heads/master
Commit: b1fa2993378f2dc2d113b95b0852723173464cd0
Parents: 15f1058
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Jul 18 18:14:12 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 10:41:11 2014 -0400

----------------------------------------------------------------------
 core/src/main/java/brooklyn/util/task/ssh/SshTasks.java   | 10 ++++++++--
 .../entity/basic/AbstractSoftwareProcessSshDriver.java    |  2 +-
 .../entity/basic/lifecycle/NaiveScriptRunner.java         |  1 +
 .../brooklyn/entity/basic/lifecycle/ScriptHelper.java     |  6 ++++++
 .../brooklyn/entity/webapp/DynamicWebAppClusterImpl.java  |  2 +-
 5 files changed, 17 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b1fa2993/core/src/main/java/brooklyn/util/task/ssh/SshTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ssh/SshTasks.java b/core/src/main/java/brooklyn/util/task/ssh/SshTasks.java
index 652a083..6a0a63e 100644
--- a/core/src/main/java/brooklyn/util/task/ssh/SshTasks.java
+++ b/core/src/main/java/brooklyn/util/task/ssh/SshTasks.java
@@ -44,6 +44,7 @@ import brooklyn.util.internal.ssh.SshTool;
 import brooklyn.util.net.Urls;
 import brooklyn.util.ssh.BashCommands;
 import brooklyn.util.stream.Streams;
+import brooklyn.util.task.DynamicTasks;
 import brooklyn.util.task.Tasks;
 import brooklyn.util.task.ssh.internal.PlainSshExecTaskFactory;
 import brooklyn.util.task.system.ProcessTaskFactory;
@@ -144,8 +145,13 @@ public class SshTasks {
             .returning(new Function<ProcessTaskWrapper<?>,Boolean>() { public Boolean apply(ProcessTaskWrapper<?> task) {
                 if (task.getExitCode()==0 && task.getStdout().contains("sudo-is-working-"+id)) return true;
                 Entity entity = BrooklynTaskTags.getTargetOrContextEntity(Tasks.current());
-                log.warn("Error setting up sudo for "+task.getMachine().getUser()+"@"+task.getMachine().getAddress().getHostName()+" "+
-                        " (exit code "+task.getExitCode()+(entity!=null ? ", entity "+entity : "")+")");
+                
+                // TODO if in a queueing context can we mark this task inessential and throw?
+                // that way user sees the message...
+                String message = "Error setting up sudo for "+task.getMachine().getUser()+"@"+task.getMachine().getAddress().getHostName()+" "+
+                        " (exit code "+task.getExitCode()+(entity!=null ? ", entity "+entity : "")+")";
+                DynamicTasks.queueIfPossible(Tasks.warning(message, null));
+                
                 Streams.logStreamTail(log, "STDERR of sudo setup problem", Streams.byteArrayOfString(task.getStderr()), 1024);
                 if (requireSuccess) {
                     throw new IllegalStateException("Passwordless sudo is required for "+task.getMachine().getUser()+"@"+task.getMachine().getAddress().getHostName()+

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b1fa2993/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessSshDriver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessSshDriver.java b/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessSshDriver.java
index 6b4e153..198b979 100644
--- a/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessSshDriver.java
+++ b/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessSshDriver.java
@@ -588,7 +588,7 @@ public abstract class AbstractSoftwareProcessSshDriver extends AbstractSoftwareP
             }
             if (INSTALLING.equals(phase)) {
                 // mutexId should be global because otherwise package managers will contend with each other 
-                s.useMutex(getLocation(), "installing", "installing "+elvis(entity,this));
+                s.useMutex(getLocation(), "installation lock at host", "installing "+elvis(entity,this));
                 s.header.append(
                         "export INSTALL_DIR=\""+getInstallDir()+"\"",
                         "mkdir -p $INSTALL_DIR",

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b1fa2993/software/base/src/main/java/brooklyn/entity/basic/lifecycle/NaiveScriptRunner.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/basic/lifecycle/NaiveScriptRunner.java b/software/base/src/main/java/brooklyn/entity/basic/lifecycle/NaiveScriptRunner.java
index 409b10e..670b1df 100644
--- a/software/base/src/main/java/brooklyn/entity/basic/lifecycle/NaiveScriptRunner.java
+++ b/software/base/src/main/java/brooklyn/entity/basic/lifecycle/NaiveScriptRunner.java
@@ -37,6 +37,7 @@ public interface NaiveScriptRunner {
      *  out, err as output/error streams;
      *  logPrefix, prefix string to put in log output;
      *  env, map of environment vars to pass to shell environment */
+    @SuppressWarnings("rawtypes")
     int execute(Map flags, List<String> script, String summaryForLogging);
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b1fa2993/software/base/src/main/java/brooklyn/entity/basic/lifecycle/ScriptHelper.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/basic/lifecycle/ScriptHelper.java b/software/base/src/main/java/brooklyn/entity/basic/lifecycle/ScriptHelper.java
index 6854eb0..e60e1d7 100644
--- a/software/base/src/main/java/brooklyn/entity/basic/lifecycle/ScriptHelper.java
+++ b/software/base/src/main/java/brooklyn/entity/basic/lifecycle/ScriptHelper.java
@@ -66,6 +66,7 @@ public class ScriptHelper {
     public final ScriptPart body = new ScriptPart(this);
     public final ScriptPart footer = new ScriptPart(this);
     
+    @SuppressWarnings("rawtypes")
     protected final Map flags = new LinkedHashMap();
     protected Predicate<? super Integer> resultCodeCheck = Predicates.alwaysTrue();
     protected Predicate<? super ScriptHelper> executionCheck = Predicates.alwaysTrue();
@@ -86,6 +87,7 @@ public class ScriptHelper {
      * Takes a closure which accepts this ScriptHelper and returns true or false
      * as to whether the script needs to run (or can throw error if desired)
      */
+    @SuppressWarnings({ "rawtypes", "unchecked" })
     public ScriptHelper executeIf(Closure c) {
         Predicate<ScriptHelper> predicate = GroovyJavaMethods.predicateFromClosure(c);
         return executeIf(predicate);
@@ -174,6 +176,7 @@ public class ScriptHelper {
      * closure always returns true (and the exit code is made available to the
      * caller if they care)
      */
+    @SuppressWarnings({ "rawtypes", "unchecked" })
     public ScriptHelper requireResultCode(Closure integerFilter) {
         Predicate<Integer> objectPredicate = GroovyJavaMethods.predicateFromClosure(integerFilter);
         return requireResultCode(objectPredicate);
@@ -312,6 +315,7 @@ public class ScriptHelper {
         }
     }
     
+    @SuppressWarnings({ "rawtypes", "unchecked" })
     public int executeInternal() {
         if (!executionCheck.apply(this)) {
             return 0;
@@ -358,10 +362,12 @@ public class ScriptHelper {
         throw new IllegalStateException(message);
     }
 
+    @SuppressWarnings("rawtypes")
     public Map getFlags() {
         return flags;
     }
     
+    @SuppressWarnings("unchecked")
     public ScriptHelper setFlag(String flag, Object value) {
         flags.put(flag, value);
         return this;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b1fa2993/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
index e3569d6..3378972 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
@@ -281,7 +281,7 @@ public class DynamicWebAppClusterImpl extends DynamicClusterImpl implements Dyna
             for (String targetName: wars.keySet()) {
                 redeployAllToTarget.add(Effectors.invocation(target, DEPLOY, MutableMap.of("url", wars.get(targetName), "targetName", targetName)));
             }
-            tb.add(redeployAllToTarget.build());
+            tb.add(whenServiceUp(target, redeployAllToTarget.build(), redeployPrefix+" at "+target+" when ready"));
         }
         DynamicTasks.queueIfPossible(tb.build()).orSubmitAsync(this).asTask().getUnchecked();
     }  


[21/31] git commit: fix and clarify queueing of tasks which have already been submitted

Posted by he...@apache.org.
fix and clarify queueing of tasks which have already been submitted


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/40ce411c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/40ce411c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/40ce411c

Branch: refs/heads/master
Commit: 40ce411cadca61c5ff3b61e22a020f10e0f8a33f
Parents: a5c2987
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Jul 29 13:31:03 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 14:39:24 2014 -0400

----------------------------------------------------------------------
 .../brooklyn/management/TaskQueueingContext.java |  6 +++++-
 .../main/java/brooklyn/util/task/BasicTask.java  |  9 +++++++--
 .../java/brooklyn/util/task/DynamicTasks.java    | 19 ++++++++++++++-----
 .../java/brooklyn/util/task/ForwardingTask.java  |  5 +++++
 .../java/brooklyn/util/task/TaskInternal.java    |  2 +-
 core/src/main/java/brooklyn/util/task/Tasks.java | 10 +++++++++-
 6 files changed, 41 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/40ce411c/api/src/main/java/brooklyn/management/TaskQueueingContext.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/management/TaskQueueingContext.java b/api/src/main/java/brooklyn/management/TaskQueueingContext.java
index 813ed19..431ee17 100644
--- a/api/src/main/java/brooklyn/management/TaskQueueingContext.java
+++ b/api/src/main/java/brooklyn/management/TaskQueueingContext.java
@@ -33,7 +33,11 @@ import com.google.common.annotations.Beta;
 @Beta
 public interface TaskQueueingContext {
 
-    /** queues the task for submission as part of this queueing context; should mark it as submitted */
+    /** queues the task for submission as part of this queueing context
+     * <p>
+     * implementations should mark it as queued but not yet submitted.
+     * note the task may have already been submitted, and is being queued here for informational purposes,
+     * in which case the implementation should not run it. */
     public void queue(Task<?> t);
     
     /** returns a list of queued tasks (immutable copy) */

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/40ce411c/core/src/main/java/brooklyn/util/task/BasicTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/BasicTask.java b/core/src/main/java/brooklyn/util/task/BasicTask.java
index 2e0da38..8370512 100644
--- a/core/src/main/java/brooklyn/util/task/BasicTask.java
+++ b/core/src/main/java/brooklyn/util/task/BasicTask.java
@@ -231,13 +231,18 @@ public class BasicTask<T> implements TaskInternal<T> {
     // basic fields --------------------
 
     @Override
+    public boolean isQueued() {
+        return (queuedTimeUtc >= 0);
+    }
+
+    @Override
     public boolean isQueuedOrSubmitted() {
-        return (queuedTimeUtc >= 0) || isSubmitted();
+        return isQueued() || isSubmitted();
     }
 
     @Override
     public boolean isQueuedAndNotSubmitted() {
-        return (queuedTimeUtc >= 0) && (!isSubmitted());
+        return isQueued() && (!isSubmitted());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/40ce411c/core/src/main/java/brooklyn/util/task/DynamicTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/DynamicTasks.java b/core/src/main/java/brooklyn/util/task/DynamicTasks.java
index 33780d2..4a08d6f 100644
--- a/core/src/main/java/brooklyn/util/task/DynamicTasks.java
+++ b/core/src/main/java/brooklyn/util/task/DynamicTasks.java
@@ -226,7 +226,7 @@ public class DynamicTasks {
     public static <V extends TaskAdaptable<?>> V queue(V task) {
         try {
             Preconditions.checkNotNull(task, "Task to queue cannot be null");
-            Preconditions.checkState(!Tasks.isQueuedOrSubmitted(task), "Task to queue must not yet be submitted: %s", task);
+            Preconditions.checkState(!Tasks.isQueued(task), "Task to queue must not yet be queued: %s", task);
             TaskQueueingContext adder = getTaskQueuingContext();
             if (adder==null) 
                 throw new IllegalStateException("Task "+task+" cannot be queued here; no queueing context available");
@@ -267,14 +267,23 @@ public class DynamicTasks {
         return DynamicTasks.queue(Tasks.<T>builder().name(name).body(job).build());
     }
 
+    /** queues the task if needed, i.e. if it is not yet submitted (so it will run), 
+     * or if it is submitted but not queued and we are in a queueing context (so it is available for informational purposes) */
     public static <T extends TaskAdaptable<?>> T queueIfNeeded(T task) {
-        if (!Tasks.isQueuedOrSubmitted(task))
-            queue(task);
+        if (!Tasks.isQueued(task)) {
+            if (Tasks.isSubmitted(task) && getTaskQueuingContext()==null) {
+                // already submitted and not in a queueing context, don't try to queue
+            } else {
+                // needs submitting, put it in the queue
+                // (will throw an error if we are not a queueing context)
+                queue(task);
+            }
+        }
         return task;
     }
     
-    /** submits the given task if needed, and gets the result (unchecked) 
-     * only permitted in a queueing context (ie a DST main job) */
+    /** submits/queues the given task if needed, and gets the result (unchecked) 
+     * only permitted in a queueing context (ie a DST main job) if the task is not yet submitted */
     // things get really confusing if you try to queueInTaskHierarchy -- easy to cause deadlocks!
     public static <T> T get(TaskAdaptable<T> t) {
         return queueIfNeeded(t).asTask().getUnchecked();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/40ce411c/core/src/main/java/brooklyn/util/task/ForwardingTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ForwardingTask.java b/core/src/main/java/brooklyn/util/task/ForwardingTask.java
index 729e28e..e54ebef 100644
--- a/core/src/main/java/brooklyn/util/task/ForwardingTask.java
+++ b/core/src/main/java/brooklyn/util/task/ForwardingTask.java
@@ -193,6 +193,11 @@ public abstract class ForwardingTask<T> extends ForwardingObject implements Task
     }
 
     @Override
+    public boolean isQueued() {
+        return delegate().isQueued();
+    }
+
+    @Override
     public boolean isQueuedOrSubmitted() {
         return delegate().isQueuedOrSubmitted();
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/40ce411c/core/src/main/java/brooklyn/util/task/TaskInternal.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/TaskInternal.java b/core/src/main/java/brooklyn/util/task/TaskInternal.java
index 5a797bc..d3a4ce8 100644
--- a/core/src/main/java/brooklyn/util/task/TaskInternal.java
+++ b/core/src/main/java/brooklyn/util/task/TaskInternal.java
@@ -53,8 +53,8 @@ public interface TaskInternal<T> extends Task<T> {
     Future<T> getResult();
     
     boolean isQueuedOrSubmitted();
-
     boolean isQueuedAndNotSubmitted();
+    boolean isQueued();
 
     /** marks the task as queued for execution */
     void markQueued();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/40ce411c/core/src/main/java/brooklyn/util/task/Tasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/Tasks.java b/core/src/main/java/brooklyn/util/task/Tasks.java
index d423c86..9a7a062 100644
--- a/core/src/main/java/brooklyn/util/task/Tasks.java
+++ b/core/src/main/java/brooklyn/util/task/Tasks.java
@@ -327,6 +327,14 @@ public class Tasks {
         return isAncestorCancelled(t.getSubmittedByTask());
     }
 
+    public static boolean isQueued(TaskAdaptable<?> task) {
+        return ((TaskInternal<?>)task.asTask()).isQueued();
+    }
+
+    public static boolean isSubmitted(TaskAdaptable<?> task) {
+        return ((TaskInternal<?>)task.asTask()).isSubmitted();
+    }
+    
     public static boolean isQueuedOrSubmitted(TaskAdaptable<?> task) {
         return ((TaskInternal<?>)task.asTask()).isQueuedOrSubmitted();
     }
@@ -336,7 +344,7 @@ public class Tasks {
      * @return true if the task was added, false otherwise.
      */
     public static boolean tryQueueing(TaskQueueingContext adder, TaskAdaptable<?> task) {
-        if (task==null || isQueuedOrSubmitted(task))
+        if (task==null || isQueued(task))
             return false;
         try {
             adder.queue(task.asTask());


[26/31] git commit: improve warnings

Posted by he...@apache.org.
improve warnings


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/04a18c07
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/04a18c07
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/04a18c07

Branch: refs/heads/master
Commit: 04a18c073cbf5a3a5911ad51ce9a76ec074e1d76
Parents: 2bffd08
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Jul 23 18:22:41 2014 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 14:41:56 2014 -0400

----------------------------------------------------------------------
 core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java | 2 +-
 core/src/main/java/brooklyn/util/task/BasicTask.java           | 2 +-
 core/src/main/java/brooklyn/util/task/ExecutionUtils.java      | 1 +
 3 files changed, 3 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04a18c07/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java b/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java
index 2f4d7a3..c69c210 100644
--- a/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java
+++ b/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java
@@ -188,7 +188,7 @@ public class DynamicGroupImpl extends AbstractGroupImpl implements DynamicGroup
                 return;
             }
             if (getConfig(ENTITY_FILTER) == null) {
-                log.warn("{} not (yet) scanning for children: no filter defined", this, this);
+                log.debug("{} not (yet) scanning for children: no filter defined", this, this);
                 return;
             }
             if (getApplication() == null) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04a18c07/core/src/main/java/brooklyn/util/task/BasicTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/BasicTask.java b/core/src/main/java/brooklyn/util/task/BasicTask.java
index 5bbd9cb..e4424b8 100644
--- a/core/src/main/java/brooklyn/util/task/BasicTask.java
+++ b/core/src/main/java/brooklyn/util/task/BasicTask.java
@@ -735,7 +735,7 @@ public class BasicTask<T> implements TaskInternal<T> {
         @Override
         public void onTaskFinalization(Task<?> t) {
             if (!Tasks.isAncestorCancelled(t) && !t.isSubmitted()) {
-                log.warn("Task "+t+" was never submitted; did the code forget to run it?");
+                log.warn(t+" was never submitted; did the code create it and forget to run it? ('cancel' the task to suppress this message)");
                 log.debug("Detail of unsubmitted task "+t+":\n"+t.getStatusDetail(true));
                 return;
             }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/04a18c07/core/src/main/java/brooklyn/util/task/ExecutionUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ExecutionUtils.java b/core/src/main/java/brooklyn/util/task/ExecutionUtils.java
index 3e162d6..37c19d2 100644
--- a/core/src/main/java/brooklyn/util/task/ExecutionUtils.java
+++ b/core/src/main/java/brooklyn/util/task/ExecutionUtils.java
@@ -31,6 +31,7 @@ public class ExecutionUtils {
      * throws exception if the callable is a non-null object which cannot be invoked (not a callable or runnable)
      * @deprecated since 0.7.0 ; this super-loose typing should be avoided; if it is needed, let's move it to one of the Groovy compatibility classes
      */
+    @SuppressWarnings({ "unchecked", "rawtypes" })
     public static Object invoke(Object callable, Object ...args) {
         if (callable instanceof Closure) return ((Closure<?>)callable).call(args);
         if (callable instanceof Callable) {


[07/31] git commit: parallel task should not fail if inessential child fails

Posted by he...@apache.org.
parallel task should not fail if inessential child fails


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/931d3970
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/931d3970
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/931d3970

Branch: refs/heads/master
Commit: 931d3970ea95cd283d98a873cc9adfc384c94bc0
Parents: 8f81e7e
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Jul 21 20:36:53 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 10:41:11 2014 -0400

----------------------------------------------------------------------
 core/src/main/java/brooklyn/util/task/ParallelTask.java | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/931d3970/core/src/main/java/brooklyn/util/task/ParallelTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ParallelTask.java b/core/src/main/java/brooklyn/util/task/ParallelTask.java
index f326f56..eef3ed7 100644
--- a/core/src/main/java/brooklyn/util/task/ParallelTask.java
+++ b/core/src/main/java/brooklyn/util/task/ParallelTask.java
@@ -63,7 +63,11 @@ public class ParallelTask<T> extends CompoundTask<T> {
                 x = task.get();
             } catch (Exception e) {
                 Exceptions.propagateIfFatal(e);
-                exceptions.add(e);
+                if (TaskTags.isInessential(task)) {
+                    // ignore exception is it's inessential
+                } else {
+                    exceptions.add(e);
+                }
                 x = null;
             }
             result.add(x);


[22/31] git commit: code review - excellent comments @aledsage

Posted by he...@apache.org.
code review - excellent comments @aledsage


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/8f2a6941
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/8f2a6941
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/8f2a6941

Branch: refs/heads/master
Commit: 8f2a6941bc538280a22ed2094f8c078ced5cc7f2
Parents: 40ce411
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Jul 29 10:39:07 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 14:39:27 2014 -0400

----------------------------------------------------------------------
 .../brooklyn/entity/group/DynamicCluster.java   | 18 -------
 .../entity/group/DynamicClusterImpl.java        | 33 +++++++-----
 .../event/basic/DependentConfiguration.java     |  3 ++
 .../util/task/BasicExecutionManager.java        | 54 ++++++++++----------
 .../main/java/brooklyn/util/task/BasicTask.java |  9 ++--
 .../java/brooklyn/util/task/TaskBuilder.java    |  6 +--
 .../location/jclouds/JcloudsLocation.java       |  2 +-
 .../brooklyn/location/jclouds/JcloudsUtil.java  |  2 +
 .../entity/webapp/DynamicWebAppClusterImpl.java | 53 +++++++++----------
 .../util/concurrent/CallableFromRunnable.java   | 54 ++++++++++++++++++++
 .../util/exceptions/ReferenceWithError.java     | 33 +++++++-----
 .../brooklyn/util/javalang/Reflections.java     |  1 +
 .../brooklyn/util/javalang/RunnableAdapter.java | 44 ----------------
 .../main/java/brooklyn/util/net/Networking.java |  8 +--
 .../java/brooklyn/util/repeat/Repeater.java     |  8 +--
 .../java/brooklyn/util/GroovyJavaMethods.groovy |  4 +-
 16 files changed, 173 insertions(+), 159 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8f2a6941/core/src/main/java/brooklyn/entity/group/DynamicCluster.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/group/DynamicCluster.java b/core/src/main/java/brooklyn/entity/group/DynamicCluster.java
index 6fec83e..c44f302 100644
--- a/core/src/main/java/brooklyn/entity/group/DynamicCluster.java
+++ b/core/src/main/java/brooklyn/entity/group/DynamicCluster.java
@@ -45,13 +45,11 @@ import brooklyn.event.basic.BasicAttributeSensor;
 import brooklyn.event.basic.BasicNotificationSensor;
 import brooklyn.event.basic.Sensors;
 import brooklyn.location.Location;
-import brooklyn.util.exceptions.ReferenceWithError;
 import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.time.Duration;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Function;
-import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Multimap;
 import com.google.common.reflect.TypeToken;
@@ -178,22 +176,6 @@ public interface DynamicCluster extends AbstractGroup, Cluster, MemberReplaceabl
     @Effector(description="Changes the size of the cluster.")
     Collection<Entity> resizeByDelta(@EffectorParam(name="delta", description="The change in number of nodes") int delta);
 
-    /**
-     * Adds a node to the cluster in a single {@link Location}
-     *
-     * @deprecated since 0.7.0 tricky having this on the interface as implementation details
-     * may change; for instance we are (22 Jul) changing the return type to be a ReferenceWithError 
-     */
-    ReferenceWithError<Optional<Entity>> addInSingleLocation(Location loc, Map<?,?> extraFlags);
-
-    /**
-     * Adds a node to the cluster in each {@link Location}
-     * 
-     * @deprecated since 0.7.0 tricky having this on the interface as implementation details
-     * may change; for instance we are (22 Jul) changing the return type to be a ReferenceWithError 
-     */
-    ReferenceWithError<Collection<Entity>> addInEachLocation(Iterable<Location> locs, Map<?,?> extraFlags);
-
     void setRemovalStrategy(Function<Collection<Entity>, Entity> val);
 
     void setZonePlacementStrategy(NodePlacementStrategy val);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8f2a6941/core/src/main/java/brooklyn/entity/group/DynamicClusterImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/group/DynamicClusterImpl.java b/core/src/main/java/brooklyn/entity/group/DynamicClusterImpl.java
index 271d9e5..b6224a4 100644
--- a/core/src/main/java/brooklyn/entity/group/DynamicClusterImpl.java
+++ b/core/src/main/java/brooklyn/entity/group/DynamicClusterImpl.java
@@ -263,7 +263,8 @@ public class DynamicClusterImpl extends AbstractGroupImpl implements DynamicClus
                 resize(initialSize);
             } catch (Exception e) {
                 Exceptions.propagateIfFatal(e);
-                // ignore problems here; we extract them below
+                // apart from logging, ignore problems here; we extract them below
+                LOG.debug("Error resizing "+this+" to size "+initialSize+" (collecting and handling): "+e, e);
             }
 
             Iterable<Task<?>> failed = Tasks.failed(Tasks.children(Tasks.current()));
@@ -487,7 +488,7 @@ public class DynamicClusterImpl extends AbstractGroupImpl implements DynamicClus
         synchronized (mutex) {
             ReferenceWithError<Optional<Entity>> added = addInSingleLocation(memberLoc, extraFlags);
 
-            if (!added.getIgnoringError().isPresent()) {
+            if (!added.getMaskingError().isPresent()) {
                 String msg = String.format("In %s, failed to grow, to replace %s; not removing", this, member);
                 if (added.hasError())
                     throw new IllegalStateException(msg, added.getError());
@@ -501,7 +502,7 @@ public class DynamicClusterImpl extends AbstractGroupImpl implements DynamicClus
                 throw new StopFailedRuntimeException("replaceMember failed to stop and remove old member "+member.getId(), e);
             }
 
-            return added.getOrThrowError().get();
+            return added.getThrowingError().get();
         }
     }
 
@@ -584,7 +585,7 @@ public class DynamicClusterImpl extends AbstractGroupImpl implements DynamicClus
         }
 
         // create and start the entities
-        return addInEachLocation(chosenLocations, ImmutableMap.of()).getOrThrowError();
+        return addInEachLocation(chosenLocations, ImmutableMap.of()).getThrowingError();
     }
 
     /** <strong>Note</strong> for sub-clases; this method can be called while synchronized on {@link #mutex}. */
@@ -615,16 +616,22 @@ public class DynamicClusterImpl extends AbstractGroupImpl implements DynamicClus
         }
     }
 
-    @Override
-    public ReferenceWithError<Optional<Entity>> addInSingleLocation(Location location, Map<?,?> flags) {
+    protected ReferenceWithError<Optional<Entity>> addInSingleLocation(Location location, Map<?,?> flags) {
         ReferenceWithError<Collection<Entity>> added = addInEachLocation(ImmutableList.of(location), flags);
-        return ReferenceWithError.newInstanceWithInformativeError(
-            Iterables.isEmpty(added.getIgnoringError()) ? Optional.<Entity>absent() : Optional.of(Iterables.getOnlyElement(added.getIgnoringError())),
-                added.getError());
+        
+        Optional<Entity> result = Iterables.isEmpty(added.getMaskingError()) ? Optional.<Entity>absent() : Optional.of(Iterables.getOnlyElement(added.get()));
+        if (!added.hasError()) {
+            return ReferenceWithError.newInstanceWithoutError( result );
+        } else {
+            if (added.masksErrorIfPresent()) {
+                return ReferenceWithError.newInstanceMaskingError( result, added.getError() );
+            } else {
+                return ReferenceWithError.newInstanceThrowingError( result, added.getError() );
+            }
+        }
     }
 
-    @Override
-    public ReferenceWithError<Collection<Entity>> addInEachLocation(Iterable<Location> locations, Map<?,?> flags) {
+    protected ReferenceWithError<Collection<Entity>> addInEachLocation(Iterable<Location> locations, Map<?,?> flags) {
         List<Entity> addedEntities = Lists.newArrayList();
         Map<Entity, Location> addedEntityLocations = Maps.newLinkedHashMap();
         Map<Entity, Task<?>> tasks = Maps.newLinkedHashMap();
@@ -669,10 +676,10 @@ public class DynamicClusterImpl extends AbstractGroupImpl implements DynamicClus
             } else {
                 cleanupFailedNodes(errors.keySet());
             }
-            return ReferenceWithError.newInstanceWithInformativeError(result, Exceptions.create(errors.values()));
+            return ReferenceWithError.newInstanceMaskingError(result, Exceptions.create(errors.values()));
         }
 
-        return ReferenceWithError.newInstanceWithNoError(result);
+        return ReferenceWithError.newInstanceWithoutError(result);
     }
 
     protected void quarantineFailedNodes(Collection<Entity> failedEntities) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8f2a6941/core/src/main/java/brooklyn/event/basic/DependentConfiguration.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/basic/DependentConfiguration.java b/core/src/main/java/brooklyn/event/basic/DependentConfiguration.java
index d569aea..8630214 100644
--- a/core/src/main/java/brooklyn/event/basic/DependentConfiguration.java
+++ b/core/src/main/java/brooklyn/event/basic/DependentConfiguration.java
@@ -151,6 +151,9 @@ public class DependentConfiguration {
         return waitInTaskForAttributeReady(source, sensor, ready, ImmutableList.<AttributeAndSensorCondition<?>>of());
     }
     
+    // TODO would be nice to have an easy semantics for whenServiceUp (cf DynamicWebAppClusterImpl.whenServiceUp)
+    // and TODO would be nice to have it stop when source is unmanaged (with ability to define post-processing)
+    // probably using the builder for both of these...
     public static <T> T waitInTaskForAttributeReady(final Entity source, final AttributeSensor<T> sensor, Predicate<? super T> ready, List<AttributeAndSensorCondition<?>> abortConditions) {
         T value = source.getAttribute(sensor);
         final List<Exception> abortion = Lists.newCopyOnWriteArrayList();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8f2a6941/core/src/main/java/brooklyn/util/task/BasicExecutionManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/BasicExecutionManager.java b/core/src/main/java/brooklyn/util/task/BasicExecutionManager.java
index 18858ee..da8c456 100644
--- a/core/src/main/java/brooklyn/util/task/BasicExecutionManager.java
+++ b/core/src/main/java/brooklyn/util/task/BasicExecutionManager.java
@@ -288,33 +288,33 @@ public class BasicExecutionManager implements ExecutionManager {
     }
 
     public <T> Task<T> scheduleWith(Task<T> task) { return scheduleWith(Collections.emptyMap(), task); }
-	public <T> Task<T> scheduleWith(Map<?,?> flags, Task<T> task) {
-		synchronized (task) {
-			if (((TaskInternal<?>)task).getResult()!=null) return task;
-			return submitNewTask(flags, task);
-		}
-	}
+    public <T> Task<T> scheduleWith(Map<?,?> flags, Task<T> task) {
+        synchronized (task) {
+            if (((TaskInternal<?>)task).getResult()!=null) return task;
+            return submitNewTask(flags, task);
+        }
+    }
 
-	@SuppressWarnings("unchecked")
+    @SuppressWarnings("unchecked")
     protected Task<?> submitNewScheduledTask(final Map<?,?> flags, final ScheduledTask task) {
-		task.submitTimeUtc = System.currentTimeMillis();
-		tasksById.put(task.getId(), task);
-		if (!task.isDone()) {
-			task.result = delayedRunner.schedule(new ScheduledTaskCallable(task, flags),
-			    task.delay.toNanoseconds(), TimeUnit.NANOSECONDS);
-		} else {
-			task.endTimeUtc = System.currentTimeMillis();
-		}
-		return task;
-	}
-	
-	protected class ScheduledTaskCallable implements Callable<Object> {
-	    public ScheduledTask task;
-	    public Map<?,?> flags;
-	    
-	    public ScheduledTaskCallable(ScheduledTask task, Map<?, ?> flags) {
-	        this.task = task;
-	        this.flags = flags;
+        task.submitTimeUtc = System.currentTimeMillis();
+        tasksById.put(task.getId(), task);
+        if (!task.isDone()) {
+            task.result = delayedRunner.schedule(new ScheduledTaskCallable(task, flags),
+                task.delay.toNanoseconds(), TimeUnit.NANOSECONDS);
+        } else {
+            task.endTimeUtc = System.currentTimeMillis();
+        }
+        return task;
+    }
+
+    protected class ScheduledTaskCallable implements Callable<Object> {
+        public ScheduledTask task;
+        public Map<?,?> flags;
+
+        public ScheduledTaskCallable(ScheduledTask task, Map<?, ?> flags) {
+            this.task = task;
+            this.flags = flags;
         }
 
         @SuppressWarnings({ "rawtypes", "unchecked" })
@@ -352,12 +352,12 @@ public class BasicExecutionManager implements ExecutionManager {
                 afterEnd(flags, task);
             }
         }
-        
+
         @Override
         public String toString() {
             return "ScheduledTaskCallable["+task+","+flags+"]";
         }
-	}
+    }
 
     @SuppressWarnings("unchecked")
     protected <T> Task<T> submitNewTask(final Map<?,?> flags, final Task<T> task) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8f2a6941/core/src/main/java/brooklyn/util/task/BasicTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/BasicTask.java b/core/src/main/java/brooklyn/util/task/BasicTask.java
index 8370512..5bbd9cb 100644
--- a/core/src/main/java/brooklyn/util/task/BasicTask.java
+++ b/core/src/main/java/brooklyn/util/task/BasicTask.java
@@ -144,10 +144,11 @@ public class BasicTask<T> implements TaskInternal<T> {
     @Override
     public String toString() {
         // give display name plus id, or job and tags plus id; some jobs have been extended to include nice tostrings 
-        return "Task["+(Strings.isNonEmpty(displayName) ? displayName : 
-                job + 
-                (tags!=null && !tags.isEmpty() ? ";"+tags : "")) +
-                ":"+getId()+"]";
+        return "Task["+
+            (Strings.isNonEmpty(displayName) ? 
+                displayName : 
+                (job + (tags!=null && !tags.isEmpty() ? ";"+tags : "")) ) +
+            ":"+getId()+"]";
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8f2a6941/core/src/main/java/brooklyn/util/task/TaskBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/TaskBuilder.java b/core/src/main/java/brooklyn/util/task/TaskBuilder.java
index 8b0150d..ed3e282 100644
--- a/core/src/main/java/brooklyn/util/task/TaskBuilder.java
+++ b/core/src/main/java/brooklyn/util/task/TaskBuilder.java
@@ -130,9 +130,9 @@ public class TaskBuilder<T> {
     @SuppressWarnings({ "unchecked", "rawtypes" })
     public Task<T> build() {
         MutableMap<String, Object> taskFlags = MutableMap.copyOf(flags);
-        if (name!=null) taskFlags.add("displayName", name);
-        if (description!=null) taskFlags.add("description", description);
-        if (!tags.isEmpty()) taskFlags.add("tags", tags);
+        if (name!=null) taskFlags.put("displayName", name);
+        if (description!=null) taskFlags.put("description", description);
+        if (!tags.isEmpty()) taskFlags.put("tags", tags);
         
         if (Boolean.FALSE.equals(dynamic) && children.isEmpty()) {
             if (swallowChildrenFailures!=null)

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8f2a6941/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
index f37c3cb..0736a7d 100644
--- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
+++ b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
@@ -1742,7 +1742,7 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
             .limitTimeTo(delayMs, MILLISECONDS)
             .runKeepingError();
 
-        if (!reachable.getIgnoringError()) {
+        if (!reachable.getMaskingError()) {
             throw new IllegalStateException("SSH failed for "+
                     user+"@"+vmIp+" ("+setup.getDescription()+") after waiting "+
                     Time.makeTimeStringRounded(delayMs), reachable.getError());

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8f2a6941/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsUtil.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsUtil.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsUtil.java
index 2ac077e..9bb6027 100644
--- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsUtil.java
+++ b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsUtil.java
@@ -76,6 +76,7 @@ import brooklyn.location.jclouds.config.BrooklynStandardJcloudsGuiceModule;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.config.ConfigBag;
+import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.net.Protocol;
 import brooklyn.util.ssh.BashCommands;
 import brooklyn.util.ssh.IptablesCommands;
@@ -391,6 +392,7 @@ public class JcloudsUtil implements JcloudsLocationConfig {
         try {
             client = context.utils().sshForNode().apply(node);
         } catch (Exception e) {
+            Exceptions.propagateIfFatal(e);
             /* i've seen: java.lang.IllegalStateException: Optional.get() cannot be called on an absent value
              * from org.jclouds.crypto.ASN1Codec.createASN1Sequence(ASN1Codec.java:86), if the ssh key has a passphrase, against AWS.
              * 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8f2a6941/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
index 7eb6e25..1b40195 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
@@ -30,8 +30,6 @@ import org.slf4j.LoggerFactory;
 
 import brooklyn.enricher.Enrichers;
 import brooklyn.entity.Entity;
-import brooklyn.entity.annotation.Effector;
-import brooklyn.entity.annotation.EffectorParam;
 import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.EntityInternal;
@@ -68,7 +66,7 @@ import com.google.common.collect.Iterables;
 public class DynamicWebAppClusterImpl extends DynamicClusterImpl implements DynamicWebAppCluster {
 
     private static final Logger log = LoggerFactory.getLogger(DynamicWebAppClusterImpl.class);
-    private static final FilenameToWebContextMapper filenameToWebContextMapper = new FilenameToWebContextMapper();
+    private static final FilenameToWebContextMapper FILENAME_TO_WEB_CONTEXT_MAPPER = new FilenameToWebContextMapper();
     
     /**
      * Instantiate a new DynamicWebAppCluster.  Parameters as per {@link DynamicCluster#DynamicCluster()}
@@ -160,6 +158,7 @@ public class DynamicWebAppClusterImpl extends DynamicClusterImpl implements Dyna
     }
     
     // TODO this will probably be useful elsewhere ... but where to put it?
+    // TODO add support for this in DependentConfiguration (see TODO there)
     /** Waits for the given target to report service up, then runs the given task
      * (often an invocation on that entity), with the given name.
      * If the target goes away, this task marks itself inessential
@@ -174,7 +173,7 @@ public class DynamicWebAppClusterImpl extends DynamicClusterImpl implements Dyna
                             Tasks.markInessential();
                             throw new IllegalStateException("Target "+target+" is no longer managed");
                         }
-                        if (target.getAttribute(Attributes.SERVICE_UP)) {
+                        if (Boolean.TRUE.equals(target.getAttribute(Attributes.SERVICE_UP))) {
                             Tasks.resetBlockingDetails();
                             TaskTags.markInessential(task);
                             DynamicTasks.queue(task);
@@ -202,13 +201,10 @@ public class DynamicWebAppClusterImpl extends DynamicClusterImpl implements Dyna
     }
 
     @Override
-    @Effector(description="Deploys the given artifact, from a source URL, to a given deployment filename/context")
-    public void deploy(
-            @EffectorParam(name="url", description="URL of WAR file") String url, 
-            @EffectorParam(name="targetName", description="context path where WAR should be deployed (/ for ROOT)") String targetName) {
+    public void deploy(String url, String targetName) {
         checkNotNull(url, "url");
         checkNotNull(targetName, "targetName");
-        targetName = filenameToWebContextMapper.convertDeploymentTargetNameToContext(targetName);
+        targetName = FILENAME_TO_WEB_CONTEXT_MAPPER.convertDeploymentTargetNameToContext(targetName);
 
         // set it up so future nodes get the right wars
         addToWarsByContext(this, url, targetName);
@@ -224,19 +220,21 @@ public class DynamicWebAppClusterImpl extends DynamicClusterImpl implements Dyna
         DynamicTasks.queueIfPossible(tb.build()).orSubmitAsync(this).asTask().getUnchecked();
 
         // Update attribute
+        // TODO support for atomic sensor update (should be part of standard tooling; NB there is some work towards this, according to @aledsage)
         Set<String> deployedWars = MutableSet.copyOf(getAttribute(DEPLOYED_WARS));
         deployedWars.add(targetName);
         setAttribute(DEPLOYED_WARS, deployedWars);
     }
     
     @Override
-    @Effector(description="Undeploys the given context/artifact")
-    public void undeploy(@EffectorParam(name="targetName") String targetName) {
+    public void undeploy(String targetName) {
         checkNotNull(targetName, "targetName");
-        targetName = filenameToWebContextMapper.convertDeploymentTargetNameToContext(targetName);
+        targetName = FILENAME_TO_WEB_CONTEXT_MAPPER.convertDeploymentTargetNameToContext(targetName);
         
         // set it up so future nodes get the right wars
-        removeFromWarsByContext(this, targetName);
+        if (!removeFromWarsByContext(this, targetName)) {
+            DynamicTasks.submit(Tasks.warning("Context "+targetName+" not known at "+this+"; attempting to undeploy regardless", null), this);
+        }
         
         log.debug("Undeploying "+targetName+" across cluster "+this+"; WARs now "+getConfig(WARS_BY_CONTEXT));
 
@@ -250,12 +248,13 @@ public class DynamicWebAppClusterImpl extends DynamicClusterImpl implements Dyna
 
         // Update attribute
         Set<String> deployedWars = MutableSet.copyOf(getAttribute(DEPLOYED_WARS));
-        deployedWars.remove( filenameToWebContextMapper.convertDeploymentTargetNameToContext(targetName) );
+        deployedWars.remove( FILENAME_TO_WEB_CONTEXT_MAPPER.convertDeploymentTargetNameToContext(targetName) );
         setAttribute(DEPLOYED_WARS, deployedWars);
     }
 
     static void addToWarsByContext(Entity entity, String url, String targetName) {
-        targetName = filenameToWebContextMapper.convertDeploymentTargetNameToContext(targetName);
+        targetName = FILENAME_TO_WEB_CONTEXT_MAPPER.convertDeploymentTargetNameToContext(targetName);
+        // TODO a better way to do atomic updates, see comment above
         synchronized (entity) {
             Map<String,String> newWarsMap = MutableMap.copyOf(entity.getConfig(WARS_BY_CONTEXT));
             newWarsMap.put(targetName, url);
@@ -263,18 +262,20 @@ public class DynamicWebAppClusterImpl extends DynamicClusterImpl implements Dyna
         }
     }
 
-    static void removeFromWarsByContext(Entity entity, String targetName) {
-        targetName = filenameToWebContextMapper.convertDeploymentTargetNameToContext(targetName);
+    static boolean removeFromWarsByContext(Entity entity, String targetName) {
+        targetName = FILENAME_TO_WEB_CONTEXT_MAPPER.convertDeploymentTargetNameToContext(targetName);
+        // TODO a better way to do atomic updates, see comment above
         synchronized (entity) {
             Map<String,String> newWarsMap = MutableMap.copyOf(entity.getConfig(WARS_BY_CONTEXT));
             String url = newWarsMap.remove(targetName);
             if (url==null) {
-                DynamicTasks.submit(Tasks.warning("Context "+targetName+" not known at "+entity+"; attempting to undeploy regardless", null), entity);
+                return false;
             }
             ((EntityInternal)entity).setConfig(WARS_BY_CONTEXT, newWarsMap);
+            return true;
         }
     }
-
+    
     @Override
     public void redeployAll() {
         Map<String, String> wars = MutableMap.copyOf(getConfig(WARS_BY_CONTEXT));
@@ -282,14 +283,14 @@ public class DynamicWebAppClusterImpl extends DynamicClusterImpl implements Dyna
 
         log.debug("Redeplying all WARs across cluster "+this+": "+getConfig(WARS_BY_CONTEXT));
         
-        Iterable<CanDeployAndUndeploy> targets = Iterables.filter(getChildren(), CanDeployAndUndeploy.class);
-        TaskBuilder<Void> tb = Tasks.<Void>builder().parallel(true).name(redeployPrefix+" across cluster (size "+Iterables.size(targets)+")");
-        for (Entity target: targets) {
-            TaskBuilder<Void> redeployAllToTarget = Tasks.<Void>builder().name(redeployPrefix+" at "+target+" (after ready check)");
-            for (String targetName: wars.keySet()) {
-                redeployAllToTarget.add(Effectors.invocation(target, DEPLOY, MutableMap.of("url", wars.get(targetName), "targetName", targetName)));
+        Iterable<CanDeployAndUndeploy> targetEntities = Iterables.filter(getChildren(), CanDeployAndUndeploy.class);
+        TaskBuilder<Void> tb = Tasks.<Void>builder().parallel(true).name(redeployPrefix+" across cluster (size "+Iterables.size(targetEntities)+")");
+        for (Entity targetEntity: targetEntities) {
+            TaskBuilder<Void> redeployAllToTarget = Tasks.<Void>builder().name(redeployPrefix+" at "+targetEntity+" (after ready check)");
+            for (String warContextPath: wars.keySet()) {
+                redeployAllToTarget.add(Effectors.invocation(targetEntity, DEPLOY, MutableMap.of("url", wars.get(warContextPath), "targetName", warContextPath)));
             }
-            tb.add(whenServiceUp(target, redeployAllToTarget.build(), redeployPrefix+" at "+target+" when ready"));
+            tb.add(whenServiceUp(targetEntity, redeployAllToTarget.build(), redeployPrefix+" at "+targetEntity+" when ready"));
         }
         DynamicTasks.queueIfPossible(tb.build()).orSubmitAsync(this).asTask().getUnchecked();
     }  

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8f2a6941/utils/common/src/main/java/brooklyn/util/concurrent/CallableFromRunnable.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/concurrent/CallableFromRunnable.java b/utils/common/src/main/java/brooklyn/util/concurrent/CallableFromRunnable.java
new file mode 100644
index 0000000..2160e5f
--- /dev/null
+++ b/utils/common/src/main/java/brooklyn/util/concurrent/CallableFromRunnable.java
@@ -0,0 +1,54 @@
+/*
+ * 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 brooklyn.util.concurrent;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
+
+import com.google.common.annotations.Beta;
+
+/** Wraps a Runnable as a Callable. Like {@link Executors#callable(Runnable, Object)} but including the underlying toString. */
+@Beta
+public class CallableFromRunnable<T> implements Callable<T> {
+    
+    public static <T> CallableFromRunnable<T> newInstance(Runnable task, T result) {
+        return new CallableFromRunnable<T>(task, result);
+    }
+    
+    private final Runnable task;
+    private final T result;
+    
+    protected CallableFromRunnable(Runnable task, T result) {
+        this.task = task;
+        this.result = result;
+    }
+    
+    public T call() {
+        task.run();
+        return result;
+    }
+    
+    @Override
+    public String toString() {
+        if (result!=null)
+            return "CallableFromRunnable["+task+(result!=null ? "->"+result : "")+"]";
+        else
+            return ""+task;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8f2a6941/utils/common/src/main/java/brooklyn/util/exceptions/ReferenceWithError.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/exceptions/ReferenceWithError.java b/utils/common/src/main/java/brooklyn/util/exceptions/ReferenceWithError.java
index 7de6fb5..cdb5925 100644
--- a/utils/common/src/main/java/brooklyn/util/exceptions/ReferenceWithError.java
+++ b/utils/common/src/main/java/brooklyn/util/exceptions/ReferenceWithError.java
@@ -27,58 +27,65 @@ public class ReferenceWithError<T> implements Supplier<T> {
 
     private final T object;
     private final Throwable error;
-    private final boolean throwErrorOnAccess;
+    private final boolean maskError;
 
     /** returns a reference which includes an error, and where attempts to get the content cause the error to throw */
-    public static <T> ReferenceWithError<T> newInstanceWithFatalError(T object, Throwable error) {
+    public static <T> ReferenceWithError<T> newInstanceThrowingError(T object, Throwable error) {
         return new ReferenceWithError<T>(object, error, true);
     }
     
     /** returns a reference which includes an error, but attempts to get the content do not cause the error to throw */
-    public static <T> ReferenceWithError<T> newInstanceWithInformativeError(T object, Throwable error) {
+    public static <T> ReferenceWithError<T> newInstanceMaskingError(T object, Throwable error) {
         return new ReferenceWithError<T>(object, error, false);
     }
     
     /** returns a reference which includes an error, but attempts to get the content do not cause the error to throw */
-    public static <T> ReferenceWithError<T> newInstanceWithNoError(T object) {
+    public static <T> ReferenceWithError<T> newInstanceWithoutError(T object) {
         return new ReferenceWithError<T>(object, null, false);
     }
     
     protected ReferenceWithError(@Nullable T object, @Nullable Throwable error, boolean throwErrorOnAccess) {
         this.object = object;
         this.error = error;
-        this.throwErrorOnAccess = throwErrorOnAccess;
+        this.maskError = throwErrorOnAccess;
     }
 
-    public boolean throwsErrorOnAccess() {
-        return throwErrorOnAccess;
+    /** whether this will mask any error on an attempt to {@link #get()};
+     * if false (if created with {@link #newInstanceThrowingError(Object, Throwable)}) a call to {@link #get()} will throw if there is an error;
+     * true if created with {@link #newInstanceMaskingError(Object, Throwable)} and {@link #get()} will not throw */
+    public boolean masksErrorIfPresent() {
+        return maskError;
     }
 
+    /** returns the underlying value, throwing if there is an error and {@link #throwsErrorOnAccess()} is set */
     public T get() {
-        if (throwsErrorOnAccess()) {
-            return getOrThrowError();
+        if (masksErrorIfPresent()) {
+            return getMaskingError();
         }
-        return getIgnoringError();
+        return getThrowingError();
     }
 
-    public T getIgnoringError() {
+    public T getMaskingError() {
         return object;
     }
 
-    public T getOrThrowError() {
+    public T getThrowingError() {
         checkNoError();
         return object;
     }
 
+    /** throws if there is an error (even if masked) */
     public void checkNoError() {
         if (hasError())
             Exceptions.propagate(error);
     }
-    
+
+    /** returns the error (not throwing) */
     public Throwable getError() {
         return error;
     }
     
+    /** true if there is an error (whether masked or not) */
     public boolean hasError() {
         return error!=null;
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8f2a6941/utils/common/src/main/java/brooklyn/util/javalang/Reflections.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/javalang/Reflections.java b/utils/common/src/main/java/brooklyn/util/javalang/Reflections.java
index 9ea35ce..e5b78c6 100644
--- a/utils/common/src/main/java/brooklyn/util/javalang/Reflections.java
+++ b/utils/common/src/main/java/brooklyn/util/javalang/Reflections.java
@@ -209,6 +209,7 @@ public class Reflections {
     /** Invokes a suitable constructor, supporting varargs and primitives */
     public static <T> Optional<T> invokeConstructorWithArgs(ClassLoader classLoader, String className, Object...argsArray) {
         Reflections reflections = new Reflections(classLoader);
+        @SuppressWarnings("unchecked")
         Class<T> clazz = (Class<T>) reflections.loadClass(className);
         return invokeConstructorWithArgs(reflections, clazz, argsArray, false);
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8f2a6941/utils/common/src/main/java/brooklyn/util/javalang/RunnableAdapter.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/javalang/RunnableAdapter.java b/utils/common/src/main/java/brooklyn/util/javalang/RunnableAdapter.java
deleted file mode 100644
index d61e84b..0000000
--- a/utils/common/src/main/java/brooklyn/util/javalang/RunnableAdapter.java
+++ /dev/null
@@ -1,44 +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 brooklyn.util.javalang;
-
-import java.util.concurrent.Callable;
-
-public class RunnableAdapter<T> implements Callable<T> {
-    final Runnable task;
-    final T result;
-    
-    public RunnableAdapter(Runnable task, T result) {
-        this.task = task;
-        this.result = result;
-    }
-    
-    public T call() {
-        task.run();
-        return result;
-    }
-    
-    @Override
-    public String toString() {
-        if (result!=null)
-            return "RunnableAdapter["+task+(result!=null ? "->"+result : "")+"]";
-        else
-            return ""+task;
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8f2a6941/utils/common/src/main/java/brooklyn/util/net/Networking.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/net/Networking.java b/utils/common/src/main/java/brooklyn/util/net/Networking.java
index 5c7df18..8c2d4f1 100644
--- a/utils/common/src/main/java/brooklyn/util/net/Networking.java
+++ b/utils/common/src/main/java/brooklyn/util/net/Networking.java
@@ -387,19 +387,19 @@ public class Networking {
     // TODO go through nic's, looking for public, private, etc, on localhost
 
     /**
-     * intsall TLSv1, fixing:
+     * force use of TLSv1, fixing:
      * http://stackoverflow.com/questions/9828414/receiving-sslhandshakeexception-handshake-failure-despite-my-client-ignoring-al
      */
-    public static void installTlsForHttps() {
+    public static void installTlsOnlyForHttpsForcing() {
         System.setProperty("https.protocols", "TLSv1");
     }
     public static void installTlsForHttpsIfAppropriate() {
         if (System.getProperty("https.protocols")==null && System.getProperty("brooklyn.https.protocols.leave_untouched")==null) {
-            installTlsForHttps();
+            installTlsOnlyForHttpsForcing();
         }
     }
     static {
-        installTlsForHttps();
+        installTlsForHttpsIfAppropriate();
     }
     
     /** does nothing, but forces the class to be loaded and do static initialization */

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8f2a6941/utils/common/src/main/java/brooklyn/util/repeat/Repeater.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/repeat/Repeater.java b/utils/common/src/main/java/brooklyn/util/repeat/Repeater.java
index b2000fa..be0d3f2 100644
--- a/utils/common/src/main/java/brooklyn/util/repeat/Repeater.java
+++ b/utils/common/src/main/java/brooklyn/util/repeat/Repeater.java
@@ -301,7 +301,7 @@ public class Repeater {
      * @return true if the exit condition was satisfied; false if the loop terminated for any other reason.
      */
     public boolean run() {
-        return runKeepingError().getIgnoringError();
+        return runKeepingError().getMaskingError();
     }
     
     public ReferenceWithError<Boolean> runKeepingError() {
@@ -335,7 +335,7 @@ public class Repeater {
             }
             if (done) {
                 if (log.isDebugEnabled()) log.debug("{}: condition satisfied", description);
-                return ReferenceWithError.newInstanceWithNoError(true);
+                return ReferenceWithError.newInstanceWithoutError(true);
             } else {
                 if (log.isDebugEnabled()) {
                     String msg = String.format("%s: unsatisfied during iteration %s %s", description, iterations,
@@ -357,7 +357,7 @@ public class Repeater {
                 }
                 if (warnOnUnRethrownException && lastError != null)
                     log.warn("{}: error caught checking condition: {}", description, lastError.getMessage());
-                return ReferenceWithError.newInstanceWithInformativeError(false, lastError);
+                return ReferenceWithError.newInstanceMaskingError(false, lastError);
             }
 
             if (timer.isExpired()) {
@@ -367,7 +367,7 @@ public class Repeater {
                     log.error("{}: error caught checking condition: {}", description, lastError.getMessage());
                     throw Exceptions.propagate(lastError);
                 }
-                return ReferenceWithError.newInstanceWithInformativeError(false, lastError);
+                return ReferenceWithError.newInstanceMaskingError(false, lastError);
             }
 
             Time.sleep(delayThisIteration);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8f2a6941/utils/groovy/src/main/java/brooklyn/util/GroovyJavaMethods.groovy
----------------------------------------------------------------------
diff --git a/utils/groovy/src/main/java/brooklyn/util/GroovyJavaMethods.groovy b/utils/groovy/src/main/java/brooklyn/util/GroovyJavaMethods.groovy
index c34f72d..199f6a5 100644
--- a/utils/groovy/src/main/java/brooklyn/util/GroovyJavaMethods.groovy
+++ b/utils/groovy/src/main/java/brooklyn/util/GroovyJavaMethods.groovy
@@ -22,7 +22,7 @@ import static brooklyn.util.GroovyJavaMethods.truth
 
 import java.util.concurrent.Callable
 
-import brooklyn.util.javalang.RunnableAdapter
+import brooklyn.util.concurrent.CallableFromRunnable;
 
 import com.google.common.base.Function
 import com.google.common.base.Predicate
@@ -54,7 +54,7 @@ public class GroovyJavaMethods {
     }
 
     public static <T> Callable<T> callableFromRunnable(final Runnable job) {
-        return (job in Callable) ? callableFromClosure(job) : new RunnableAdapter<Object>(job, null);
+        return (job in Callable) ? callableFromClosure(job) : CallableFromRunnable.newInstance(job, null);
     }
 
     public static <T> Predicate<T> predicateFromClosure(final Closure<Boolean> job) {


[14/31] git commit: map target name to right format on cluster-level undeploy

Posted by he...@apache.org.
map target name to right format on cluster-level undeploy


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/e3a3df9a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/e3a3df9a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/e3a3df9a

Branch: refs/heads/master
Commit: e3a3df9a9182f450fcf9c7700adf017183b8d7fc
Parents: 1d8551e
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Jul 22 13:23:31 2014 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 10:42:07 2014 -0400

----------------------------------------------------------------------
 .../java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java     | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e3a3df9a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
index f62f8eb..7eb6e25 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
@@ -233,7 +233,8 @@ public class DynamicWebAppClusterImpl extends DynamicClusterImpl implements Dyna
     @Effector(description="Undeploys the given context/artifact")
     public void undeploy(@EffectorParam(name="targetName") String targetName) {
         checkNotNull(targetName, "targetName");
-
+        targetName = filenameToWebContextMapper.convertDeploymentTargetNameToContext(targetName);
+        
         // set it up so future nodes get the right wars
         removeFromWarsByContext(this, targetName);
         


[28/31] git commit: code review

Posted by he...@apache.org.
code review


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/339736db
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/339736db
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/339736db

Branch: refs/heads/master
Commit: 339736dba4b4870c1bad19641c8e9dca5e8be826
Parents: 6b4b9e5
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Jul 29 15:18:44 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 15:18:44 2014 -0400

----------------------------------------------------------------------
 .../brooklyn/entity/trait/StartableMethods.java |  2 +-
 .../ha/HighAvailabilityManagerImpl.java         |  1 +
 .../java/brooklyn/util/task/DynamicTasks.java   |  6 +++---
 .../java/brooklyn/util/task/ssh/SshTasks.java   | 21 ++++++++++++++++----
 .../entity/proxy/nginx/NginxSshDriver.java      |  2 +-
 5 files changed, 23 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/339736db/core/src/main/java/brooklyn/entity/trait/StartableMethods.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/trait/StartableMethods.java b/core/src/main/java/brooklyn/entity/trait/StartableMethods.java
index bab61e5..e8f1039 100644
--- a/core/src/main/java/brooklyn/entity/trait/StartableMethods.java
+++ b/core/src/main/java/brooklyn/entity/trait/StartableMethods.java
@@ -82,7 +82,7 @@ public class StartableMethods {
             }
             try {
                 TaskAdaptable<Void> task = TaskTags.markInessential(Effectors.invocation((Entity)entity, Startable.STOP, Collections.emptyMap()));
-                DynamicTasks.queueIfPossible(task).orSubmitAsync((Entity)entity).andWaitForSuccess();
+                DynamicTasks.submit(task, (Entity)entity).getUnchecked();
             } catch (Exception e) {
                 log.warn("Error stopping "+entity+"; continuing with shutdown", e);
                 exceptions.add(e);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/339736db/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java b/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java
index 5a13d31..c205ebe 100644
--- a/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java
+++ b/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java
@@ -544,6 +544,7 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager {
                             t.cancel(true);
                         } catch (Exception e) {
                             Exceptions.propagateIfFatal(e);
+                            LOG.debug("Error cancelling "+t+" on "+entity+" (will warn when all tasks are cancelled): "+e, e);
                             exceptions.add(e);
                         }
                     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/339736db/core/src/main/java/brooklyn/util/task/DynamicTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/DynamicTasks.java b/core/src/main/java/brooklyn/util/task/DynamicTasks.java
index 3957b55..c5c17c9 100644
--- a/core/src/main/java/brooklyn/util/task/DynamicTasks.java
+++ b/core/src/main/java/brooklyn/util/task/DynamicTasks.java
@@ -156,8 +156,8 @@ public class DynamicTasks {
          * <p>
          * throws if there are any errors
          */
-        public void andWaitForSuccess() {
-            task.getUnchecked();
+        public T andWaitForSuccess() {
+            return task.getUnchecked();
         }
         public void orCancel() {
             if (!wasQueued()) {
@@ -332,5 +332,5 @@ public class DynamicTasks {
     public static <T> Task<T> submit(TaskAdaptable<T> task, Entity entity) {
         return queueIfPossible(task).orSubmitAsync(entity).asTask();
     }
-    
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/339736db/core/src/main/java/brooklyn/util/task/ssh/SshTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ssh/SshTasks.java b/core/src/main/java/brooklyn/util/task/ssh/SshTasks.java
index 07e0a8a..407d328 100644
--- a/core/src/main/java/brooklyn/util/task/ssh/SshTasks.java
+++ b/core/src/main/java/brooklyn/util/task/ssh/SshTasks.java
@@ -38,6 +38,7 @@ import brooklyn.management.ManagementContext;
 import brooklyn.management.Task;
 import brooklyn.management.TaskAdaptable;
 import brooklyn.management.TaskFactory;
+import brooklyn.management.TaskQueueingContext;
 import brooklyn.util.ResourceUtils;
 import brooklyn.util.config.ConfigBag;
 import brooklyn.util.internal.ssh.SshTool;
@@ -132,7 +133,19 @@ public class SshTasks {
     }
 
     @Beta
-    public static enum OnFailingTask { FAIL, WARN_OR_FAIL_INESSENTIAL_IF_DYNAMIC, WARN_IN_LOG_ONLY, IGNORE }
+    public static enum OnFailingTask { 
+        FAIL,
+        /** issues a warning, sometimes implemented as marking the task inessential and failing it if it appears
+         * we are in a dynamic {@link TaskQueueingContext};
+         * useful because this way the warning appears to the user;
+         * but note that the check is done against the calling thread so use with some care
+         * (and thus this enum is currently here rather then elsewhere) */
+        WARN_OR_IF_DYNAMIC_FAIL_MARKING_INESSENTIAL,
+        /** issues a warning in the log if the task fails, otherwise swallows it */
+        WARN_IN_LOG_ONLY, 
+        /** not even a warning if the task fails (the caller is expected to handle it as appropriate) */
+        IGNORE }
+    
     public static ProcessTaskFactory<Boolean> dontRequireTtyForSudo(SshMachineLocation machine, final boolean failIfCantSudo) {
         return dontRequireTtyForSudo(machine, failIfCantSudo ? OnFailingTask.FAIL : OnFailingTask.WARN_IN_LOG_ONLY);
     }
@@ -140,7 +153,7 @@ public class SshTasks {
      * also gives nice warnings if sudo is not permitted */
     public static ProcessTaskFactory<Boolean> dontRequireTtyForSudo(SshMachineLocation machine, OnFailingTask onFailingTaskRequested) {
         final OnFailingTask onFailingTask;
-        if (onFailingTaskRequested==OnFailingTask.WARN_OR_FAIL_INESSENTIAL_IF_DYNAMIC) {
+        if (onFailingTaskRequested==OnFailingTask.WARN_OR_IF_DYNAMIC_FAIL_MARKING_INESSENTIAL) {
             if (DynamicTasks.getTaskQueuingContext()!=null)
                 onFailingTask = onFailingTaskRequested;
             else
@@ -171,10 +184,10 @@ public class SshTasks {
                 }
                 Streams.logStreamTail(log, "STDERR of sudo setup problem", Streams.byteArrayOfString(task.getStderr()), 1024);
                 
-                if (onFailingTask==OnFailingTask.WARN_OR_FAIL_INESSENTIAL_IF_DYNAMIC) {
+                if (onFailingTask==OnFailingTask.WARN_OR_IF_DYNAMIC_FAIL_MARKING_INESSENTIAL) {
                     Tasks.markInessential();
                 }
-                if (onFailingTask==OnFailingTask.FAIL || onFailingTask==OnFailingTask.WARN_OR_FAIL_INESSENTIAL_IF_DYNAMIC) {
+                if (onFailingTask==OnFailingTask.FAIL || onFailingTask==OnFailingTask.WARN_OR_IF_DYNAMIC_FAIL_MARKING_INESSENTIAL) {
                     throw new IllegalStateException("Passwordless sudo is required for "+task.getMachine().getUser()+"@"+task.getMachine().getAddress().getHostName()+
                             (entity!=null ? " ("+entity+")" : ""));
                 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/339736db/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxSshDriver.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxSshDriver.java b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxSshDriver.java
index df261c0..81e74fd 100644
--- a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxSshDriver.java
+++ b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxSshDriver.java
@@ -116,7 +116,7 @@ public class NginxSshDriver extends AbstractSoftwareProcessSshDriver implements
     @Override
     public void install() {
         // inessential here, installation will fail later if it needs to sudo (eg if using port 80)
-        DynamicTasks.queueIfPossible(SshTasks.dontRequireTtyForSudo(getMachine(), OnFailingTask.WARN_OR_FAIL_INESSENTIAL_IF_DYNAMIC)).orSubmitAndBlock();
+        DynamicTasks.queueIfPossible(SshTasks.dontRequireTtyForSudo(getMachine(), OnFailingTask.WARN_OR_IF_DYNAMIC_FAIL_MARKING_INESSENTIAL)).orSubmitAndBlock();
 
         DownloadResolver nginxResolver = mgmt().getEntityDownloadsManager().newDownloader(this);
         List<String> nginxUrls = nginxResolver.getTargets();


[31/31] git commit: This closes #91

Posted by he...@apache.org.
This closes #91


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/07bfb055
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/07bfb055
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/07bfb055

Branch: refs/heads/master
Commit: 07bfb0550942a117fc8e4793a3910be76fcc1011
Parents: 9751ef8 28c0cac
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Jul 29 15:30:08 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 15:30:08 2014 -0400

----------------------------------------------------------------------
 .../brooklyn/entity/rebind/RebindManager.java   |  1 +
 .../entity/basic/AbstractApplication.java       |  2 +-
 .../brooklyn/entity/basic/DynamicGroupImpl.java |  2 +-
 .../brooklyn/entity/trait/StartableMethods.java |  2 +-
 .../FixedListMachineProvisioningLocation.java   | 25 ++++++--
 .../ha/HighAvailabilityManagerImpl.java         | 60 ++++++++++++++++----
 .../management/usage/ApplicationUsage.java      |  3 +-
 .../main/java/brooklyn/util/task/BasicTask.java |  2 +-
 .../java/brooklyn/util/task/DynamicTasks.java   | 11 +++-
 .../java/brooklyn/util/task/ExecutionUtils.java |  1 +
 .../java/brooklyn/util/task/ssh/SshTasks.java   | 50 +++++++++++++---
 .../postgresql/PostgreSqlSshDriver.java         |  3 +-
 .../entity/proxy/nginx/NginxSshDriver.java      |  5 +-
 .../brooklyn/qa/longevity/MonitorUtils.java     | 15 ++++-
 .../brooklyn/qa/longevity/MonitorUtilsTest.java |  8 ++-
 15 files changed, 152 insertions(+), 38 deletions(-)
----------------------------------------------------------------------



[11/31] git commit: fix memory leak where peeked-locations are kept by their parents

Posted by he...@apache.org.
fix memory leak where peeked-locations are kept by their parents


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/2ecb9687
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/2ecb9687
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/2ecb9687

Branch: refs/heads/master
Commit: 2ecb9687df779864b1bdd51ddc003baed2d8b98e
Parents: 3411881
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Jul 23 13:06:25 2014 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 10:42:07 2014 -0400

----------------------------------------------------------------------
 .../main/java/brooklyn/location/basic/AbstractLocation.java   | 2 +-
 .../location/basic/FixedListMachineProvisioningLocation.java  | 2 +-
 .../brooklyn/management/internal/LocalLocationManager.java    | 7 +++++++
 3 files changed, 9 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2ecb9687/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/location/basic/AbstractLocation.java b/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
index d468622..eb46be7 100644
--- a/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
+++ b/core/src/main/java/brooklyn/location/basic/AbstractLocation.java
@@ -528,7 +528,7 @@ public abstract class AbstractLocation implements LocationInternal, HasHostGeoIn
         child.setParent(this);
     }
     
-    protected boolean removeChild(Location child) {
+    public boolean removeChild(Location child) {
         boolean removed;
         synchronized (children) {
             removed = children.remove(child);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2ecb9687/core/src/main/java/brooklyn/location/basic/FixedListMachineProvisioningLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/location/basic/FixedListMachineProvisioningLocation.java b/core/src/main/java/brooklyn/location/basic/FixedListMachineProvisioningLocation.java
index 523eb6d..242319b 100644
--- a/core/src/main/java/brooklyn/location/basic/FixedListMachineProvisioningLocation.java
+++ b/core/src/main/java/brooklyn/location/basic/FixedListMachineProvisioningLocation.java
@@ -184,7 +184,7 @@ implements MachineProvisioningLocation<T>, Closeable {
     }
 
     @Override
-    protected boolean removeChild(Location child) {
+    public boolean removeChild(Location child) {
         if (inUse.contains(child)) {
             throw new IllegalStateException("Child location "+child+" is in use; cannot remove from "+this);
         }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2ecb9687/core/src/main/java/brooklyn/management/internal/LocalLocationManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/internal/LocalLocationManager.java b/core/src/main/java/brooklyn/management/internal/LocalLocationManager.java
index 3038257..8ce4dbe 100644
--- a/core/src/main/java/brooklyn/management/internal/LocalLocationManager.java
+++ b/core/src/main/java/brooklyn/management/internal/LocalLocationManager.java
@@ -88,6 +88,13 @@ public class LocalLocationManager implements LocationManager {
             T loc = locationFactory.createLocation(spec);
             if (!createUnmanaged) {
                 manage(loc);
+            } else {
+                // remove references
+                Location parent = loc.getParent();
+                if (parent!=null) {
+                    ((AbstractLocation)parent).removeChild(loc);
+                }
+                preRegisteredLocationsById.remove(loc.getId());
             }
             
             return loc;


[24/31] git commit: unmanage and stop rebind on failure, before publishing the new state, and cancel tasks on demotion

Posted by he...@apache.org.
unmanage and stop rebind on failure, before publishing the new state, and cancel tasks on demotion


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/13299c62
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/13299c62
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/13299c62

Branch: refs/heads/master
Commit: 13299c62f8c55fec90630ff5618dd4857dc8f2f9
Parents: 08a91f6
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Jul 23 16:56:24 2014 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 14:40:46 2014 -0400

----------------------------------------------------------------------
 .../brooklyn/entity/rebind/RebindManager.java   |  1 +
 .../entity/basic/AbstractApplication.java       |  2 +-
 .../ha/HighAvailabilityManagerImpl.java         | 59 ++++++++++++++++----
 3 files changed, 50 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/13299c62/api/src/main/java/brooklyn/entity/rebind/RebindManager.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/entity/rebind/RebindManager.java b/api/src/main/java/brooklyn/entity/rebind/RebindManager.java
index 854aa78..978fa3f 100644
--- a/api/src/main/java/brooklyn/entity/rebind/RebindManager.java
+++ b/api/src/main/java/brooklyn/entity/rebind/RebindManager.java
@@ -74,6 +74,7 @@ public interface RebindManager {
      */
     public void start();
 
+    /** Stops persisting. Waits for any current persistence to complete. */
     public void stop();
 
     /** @deprecated since 0.7.0; use {@link #waitForPendingComplete(Duration)} */

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/13299c62/core/src/main/java/brooklyn/entity/basic/AbstractApplication.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/AbstractApplication.java b/core/src/main/java/brooklyn/entity/basic/AbstractApplication.java
index 3ded835..b7edf59 100644
--- a/core/src/main/java/brooklyn/entity/basic/AbstractApplication.java
+++ b/core/src/main/java/brooklyn/entity/basic/AbstractApplication.java
@@ -224,7 +224,7 @@ public abstract class AbstractApplication extends AbstractEntity implements Star
             throw e;
         } catch (RuntimeException e) {
             if (getManagementContext().isRunning()) {
-                log.warn("Problem storing application event "+state+" for "+this, e);
+                log.warn("Problem recording application event '"+state+"' for "+this, e);
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/13299c62/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java b/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java
index f42abad..5a13d31 100644
--- a/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java
+++ b/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java
@@ -23,6 +23,7 @@ import static com.google.common.base.Preconditions.checkState;
 
 import java.io.IOException;
 import java.net.URI;
+import java.util.Collection;
 import java.util.concurrent.Callable;
 import java.util.concurrent.TimeUnit;
 
@@ -33,6 +34,7 @@ import org.slf4j.LoggerFactory;
 
 import brooklyn.BrooklynVersion;
 import brooklyn.entity.Application;
+import brooklyn.entity.Entity;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.rebind.RebindManager;
 import brooklyn.entity.rebind.plane.dto.BasicManagementNodeSyncRecord;
@@ -43,6 +45,7 @@ import brooklyn.management.ha.BasicMasterChooser.AlphabeticMasterChooser;
 import brooklyn.management.ha.ManagementPlaneSyncRecordPersister.Delta;
 import brooklyn.management.internal.ManagementContextInternal;
 import brooklyn.util.collections.MutableMap;
+import brooklyn.util.collections.MutableSet;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.task.BasicTask;
 import brooklyn.util.task.ScheduledTask;
@@ -321,14 +324,6 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager {
         if (LOG.isTraceEnabled()) LOG.trace("Published management-node health: {}", memento);
     }
     
-    /**
-     * Publishes (via {@link #persister}) the state of this management node with itself set to master.
-     */
-    protected synchronized void publishDemotionFromMasterOnFailure() {
-        checkState(getNodeState() == ManagementNodeState.FAILED, "node status must be failed on publish, but is %s", getNodeState());
-        publishDemotionFromMaster(true);
-    }
-    
     protected synchronized void publishDemotionFromMaster(boolean clearMaster) {
         checkState(getNodeState() != ManagementNodeState.MASTER, "node status must not be master when demoting", getNodeState());
         
@@ -403,6 +398,12 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager {
     protected void checkMaster(boolean initializing) {
         ManagementPlaneSyncRecord memento = loadManagementPlaneSyncRecord(false);
         
+        if (getNodeState() == ManagementNodeState.FAILED) {
+            // if we have failed then no point in checking who is master
+            // (if somehow this node is subsequently clearFailure() then it will resume)
+            return;
+        }
+        
         String currMasterNodeId = memento.getMasterNodeId();
         ManagementNodeSyncRecord currMasterNodeRecord = memento.getManagementNodes().get(currMasterNodeId);
         ManagementNodeSyncRecord ownNodeRecord = memento.getManagementNodes().get(ownNodeId);
@@ -502,12 +503,17 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager {
             managementContext.getRebindManager().rebind(managementContext.getCatalog().getRootClassLoader());
         } catch (Exception e) {
             LOG.error("Management node enountered problem during rebind when promoting self to master; demoting to FAILED and rethrowing: "+e);
-            nodeState = ManagementNodeState.FAILED;
-            publishDemotionFromMasterOnFailure();
+            demoteToFailed();
             throw Exceptions.propagate(e);
         }
         managementContext.getRebindManager().start();
     }
+    
+    protected void demoteToFailed() {
+        nodeState = ManagementNodeState.FAILED;
+        onDemotion();
+        publishDemotionFromMaster(true);
+    }
 
     protected void demoteToStandby() {
         if (!running) {
@@ -516,10 +522,41 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager {
         }
 
         nodeState = ManagementNodeState.STANDBY;
+        onDemotion();
+        publishDemotionFromMaster(false);
+    }
+    
+    protected void onDemotion() {
         managementContext.getRebindManager().stop();
         for (Application app: managementContext.getApplications())
             Entities.unmanage(app);
-        publishDemotionFromMaster(false);
+        // let's try forcibly interrupting tasks on managed entities
+        Collection<Exception> exceptions = MutableSet.of();
+        int tasks = 0;
+        LOG.debug("Cancelling tasks on demotion");
+        try {
+            for (Entity entity: managementContext.getEntityManager().getEntities()) {
+                for (Task<?> t: managementContext.getExecutionContext(entity).getTasks()) {
+                    if (!t.isDone()) {
+                        tasks++;
+                        try {
+                            LOG.debug("Cancelling "+t+" on "+entity);
+                            t.cancel(true);
+                        } catch (Exception e) {
+                            Exceptions.propagateIfFatal(e);
+                            exceptions.add(e);
+                        }
+                    }
+                }
+            }
+        } catch (Exception e) {
+            Exceptions.propagateIfFatal(e);
+            LOG.warn("Error inspecting tasks to cancel on demotion: "+e, e);
+        }
+        if (!exceptions.isEmpty())
+            LOG.warn("Error when cancelling tasks on demotion: "+Exceptions.create(exceptions));
+        if (tasks>0)
+            LOG.info("Cancelled "+tasks+" tasks on demotion");
     }
 
     /**


[27/31] git commit: avoid NPE on rebind when locations have been unmanaged

Posted by he...@apache.org.
avoid NPE on rebind when locations have been unmanaged


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/6b4b9e5d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/6b4b9e5d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/6b4b9e5d

Branch: refs/heads/master
Commit: 6b4b9e5d31281d76b1478926e195a556592796c8
Parents: 04a18c0
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Jul 29 14:37:27 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 15:18:22 2014 -0400

----------------------------------------------------------------------
 .../FixedListMachineProvisioningLocation.java   | 25 +++++++++++++++-----
 1 file changed, 19 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6b4b9e5d/core/src/main/java/brooklyn/location/basic/FixedListMachineProvisioningLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/location/basic/FixedListMachineProvisioningLocation.java b/core/src/main/java/brooklyn/location/basic/FixedListMachineProvisioningLocation.java
index 242319b..595ab8a 100644
--- a/core/src/main/java/brooklyn/location/basic/FixedListMachineProvisioningLocation.java
+++ b/core/src/main/java/brooklyn/location/basic/FixedListMachineProvisioningLocation.java
@@ -28,6 +28,9 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import brooklyn.location.Location;
 import brooklyn.location.LocationSpec;
 import brooklyn.location.MachineLocation;
@@ -35,6 +38,7 @@ import brooklyn.location.MachineProvisioningLocation;
 import brooklyn.location.NoMachinesAvailableException;
 import brooklyn.management.LocationManager;
 import brooklyn.util.collections.MutableMap;
+import brooklyn.util.collections.MutableSet;
 import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.stream.Streams;
 import brooklyn.util.text.WildcardGlobs;
@@ -63,6 +67,8 @@ implements MachineProvisioningLocation<T>, Closeable {
     // and getMachines() returns the real sets risking 
     // ConcurrentModificationException in the caller if it iterates over them etc.
     
+    private static final Logger log = LoggerFactory.getLogger(FixedListMachineProvisioningLocation.class);
+    
     private final Object lock = new Object();
     
     @SetFromFlag
@@ -89,14 +95,21 @@ implements MachineProvisioningLocation<T>, Closeable {
     public void init() {
         super.init();
         
-        for (MachineLocation location: machines) {
-            // FIXME Bad casting
-            Location machine = (Location) location;
-            Location parent = machine.getParent();
-            if (parent == null) {
-                addChild(machine);
+        Set<T> machinesCopy = MutableSet.of();
+        for (T location: machines) {
+            if (location==null) {
+                log.warn(""+this+" initialized with null location, removing (may be due to rebind with reference to an unmanaged location)");
+            } else {
+                Location parent = location.getParent();
+                if (parent == null) {
+                    addChild(location);
+                }
+                machinesCopy.add(location);
             }
         }
+        if (!machinesCopy.equals(machines)) {
+            machines = machinesCopy;
+        }
     }
     
     @Override


[23/31] git commit: prevent NPE due to applicationName being null

Posted by he...@apache.org.
prevent NPE due to applicationName being null


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/08a91f61
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/08a91f61
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/08a91f61

Branch: refs/heads/master
Commit: 08a91f61c83fabe2dacafc9176423db988207e64
Parents: 8f2a694
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Jul 23 16:56:14 2014 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 14:40:46 2014 -0400

----------------------------------------------------------------------
 .../src/main/java/brooklyn/management/usage/ApplicationUsage.java | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/08a91f61/core/src/main/java/brooklyn/management/usage/ApplicationUsage.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/usage/ApplicationUsage.java b/core/src/main/java/brooklyn/management/usage/ApplicationUsage.java
index 7f78807..cf72791 100644
--- a/core/src/main/java/brooklyn/management/usage/ApplicationUsage.java
+++ b/core/src/main/java/brooklyn/management/usage/ApplicationUsage.java
@@ -66,7 +66,8 @@ public class ApplicationUsage {
 
     public ApplicationUsage(String applicationId, String applicationName, String entityType, Map<String, String> metadata) {
         this.applicationId = checkNotNull(applicationId, "applicationId");
-        this.applicationName = checkNotNull(applicationName, "applicationName");
+        // allow name to be null, happens in certain failed rebind cases
+        this.applicationName = applicationName;
         this.entityType = checkNotNull(entityType, "entityType");
         this.metadata = checkNotNull(metadata, "metadata");
     }


[15/31] git commit: collect tomcat stats less often as it appears to be expensive

Posted by he...@apache.org.
collect tomcat stats less often as it appears to be expensive


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/d755ab48
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/d755ab48
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/d755ab48

Branch: refs/heads/master
Commit: d755ab48842868e7df5177f6a0a6462200e3d429
Parents: a7885b5
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Jul 23 17:42:21 2014 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 10:42:08 2014 -0400

----------------------------------------------------------------------
 .../java/brooklyn/entity/webapp/tomcat/TomcatServerImpl.java     | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d755ab48/software/webapp/src/main/java/brooklyn/entity/webapp/tomcat/TomcatServerImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/tomcat/TomcatServerImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/tomcat/TomcatServerImpl.java
index ea79eb1..a83f284 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/tomcat/TomcatServerImpl.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/tomcat/TomcatServerImpl.java
@@ -29,7 +29,6 @@ import brooklyn.entity.java.JavaAppUtils;
 import brooklyn.entity.webapp.JavaWebAppSoftwareProcessImpl;
 import brooklyn.event.feed.jmx.JmxAttributePollConfig;
 import brooklyn.event.feed.jmx.JmxFeed;
-import brooklyn.util.time.Duration;
 
 import com.google.common.base.Functions;
 import com.google.common.base.Predicates;
@@ -57,7 +56,7 @@ public class TomcatServerImpl extends JavaWebAppSoftwareProcessImpl implements T
 
             jmxFeed = JmxFeed.builder()
                     .entity(this)
-                    .period(500, TimeUnit.MILLISECONDS)
+                    .period(3000, TimeUnit.MILLISECONDS)
                     .pollAttribute(new JmxAttributePollConfig<Integer>(ERROR_COUNT)
                             .objectName(requestProcessorMbeanName)
                             .attributeName("errorCount"))
@@ -95,6 +94,7 @@ public class TomcatServerImpl extends JavaWebAppSoftwareProcessImpl implements T
         }
     }
 
+    @SuppressWarnings("rawtypes")
     @Override
     public Class getDriverInterface() {
         return Tomcat7Driver.class;


[12/31] git commit: don't block rebind just because a group can't rescan his elements; it may be referencing an entity which has gone away

Posted by he...@apache.org.
don't block rebind just because a group can't rescan his elements; it may be referencing an entity which has gone away


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/34118815
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/34118815
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/34118815

Branch: refs/heads/master
Commit: 34118815866f016b2a5a0a2161ba9e617c933452
Parents: 254a6f7
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Jul 23 13:05:57 2014 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 10:42:07 2014 -0400

----------------------------------------------------------------------
 .../main/java/brooklyn/entity/basic/DynamicGroupImpl.java   | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/34118815/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java b/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java
index 11544eb..2f4d7a3 100644
--- a/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java
+++ b/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java
@@ -33,6 +33,7 @@ import brooklyn.event.SensorEventListener;
 import brooklyn.management.internal.CollectionChangeListener;
 import brooklyn.management.internal.ManagementContextInternal;
 import brooklyn.util.GroovyJavaMethods;
+import brooklyn.util.exceptions.Exceptions;
 
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
@@ -160,7 +161,13 @@ public class DynamicGroupImpl extends AbstractGroupImpl implements DynamicGroup
         }
         setChangeListener = new MyEntitySetChangeListener();
         ((ManagementContextInternal) getManagementContext()).addEntitySetListener(setChangeListener);
-        rescanEntities();
+        try {
+            rescanEntities();
+        } catch (Exception e) {
+            log.warn("Error rescanning entities when rebinding; may be a group set against an unknown entity: "+e);
+            log.debug("Trace for rescan entities error", e);
+            Exceptions.propagateIfFatal(e);
+        }
     }
 
     @Override


[16/31] git commit: include job information in the toString for tasks that don't have a display name, and don't set the display name to tasks, and give jobs useful toStrings in many places

Posted by he...@apache.org.
include job information in the toString for tasks that don't have a display name, and don't set the display name to tasks, and give jobs useful toStrings in many places


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/40b63e21
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/40b63e21
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/40b63e21

Branch: refs/heads/master
Commit: 40b63e214dd9fd5abb8277e2f1beb6e64cdbc65e
Parents: d755ab4
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Jul 23 17:44:05 2014 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 10:42:08 2014 -0400

----------------------------------------------------------------------
 .../internal/LocalSubscriptionManager.java      |  4 ++
 .../util/task/BasicExecutionManager.java        |  2 +-
 .../main/java/brooklyn/util/task/BasicTask.java | 14 +++----
 .../util/task/DynamicSequentialTask.java        |  2 +-
 .../util/task/SingleThreadedScheduler.java      | 12 +++---
 .../brooklyn/util/javalang/RunnableAdapter.java | 44 ++++++++++++++++++++
 .../java/brooklyn/util/GroovyJavaMethods.groovy |  5 ++-
 7 files changed, 66 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/40b63e21/core/src/main/java/brooklyn/management/internal/LocalSubscriptionManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/internal/LocalSubscriptionManager.java b/core/src/main/java/brooklyn/management/internal/LocalSubscriptionManager.java
index a1d084a..0bd8578 100644
--- a/core/src/main/java/brooklyn/management/internal/LocalSubscriptionManager.java
+++ b/core/src/main/java/brooklyn/management/internal/LocalSubscriptionManager.java
@@ -180,6 +180,10 @@ public class LocalSubscriptionManager extends AbstractSubscriptionManager {
                     continue;
                 final Subscription sAtClosureCreation = s;
                 em.submit(mapOf("tag", s.subscriberExecutionManagerTag), new Runnable() {
+                    @Override
+                    public String toString() {
+                        return "LSM.publish("+event+")";
+                    }
                     public void run() {
                         sAtClosureCreation.listener.onEvent(event);
                     }});

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/40b63e21/core/src/main/java/brooklyn/util/task/BasicExecutionManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/BasicExecutionManager.java b/core/src/main/java/brooklyn/util/task/BasicExecutionManager.java
index 1a89501..18858ee 100644
--- a/core/src/main/java/brooklyn/util/task/BasicExecutionManager.java
+++ b/core/src/main/java/brooklyn/util/task/BasicExecutionManager.java
@@ -412,7 +412,7 @@ public class BasicExecutionManager implements ExecutionManager {
             }
             @Override
             public String toString() {
-                return "BasicExecutionManager.submitNewTask.Callable["+task+","+flags+"]";
+                return "BEM.call("+task+","+flags+")";
             }
         };
         

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/40b63e21/core/src/main/java/brooklyn/util/task/BasicTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/BasicTask.java b/core/src/main/java/brooklyn/util/task/BasicTask.java
index 8337edf..2e0da38 100644
--- a/core/src/main/java/brooklyn/util/task/BasicTask.java
+++ b/core/src/main/java/brooklyn/util/task/BasicTask.java
@@ -20,7 +20,6 @@ package brooklyn.util.task;
 
 import static brooklyn.util.JavaGroovyEquivalents.asString;
 import static brooklyn.util.JavaGroovyEquivalents.elvisString;
-import static brooklyn.util.JavaGroovyEquivalents.join;
 import groovy.lang.Closure;
 
 import java.io.PrintWriter;
@@ -117,8 +116,7 @@ public class BasicTask<T> implements TaskInternal<T> {
 
         description = elvisString(flags.remove("description"), "");
         String d = asString(flags.remove("displayName"));
-        if (d==null) d = join(tags, "-");
-        displayName = d;
+        displayName = (d==null ? "" : d);
     }
 
     public BasicTask(Runnable job) { this(GroovyJavaMethods.<T>callableFromRunnable(job)); }
@@ -144,10 +142,12 @@ public class BasicTask<T> implements TaskInternal<T> {
     }
 
     @Override
-    public String toString() { 
-        return "Task["+(displayName!=null && displayName.length()>0?displayName+
-                (tags!=null && !tags.isEmpty()?"":";")+" ":"")+
-                (tags!=null && !tags.isEmpty()?tags+"; ":"")+getId()+"]";
+    public String toString() {
+        // give display name plus id, or job and tags plus id; some jobs have been extended to include nice tostrings 
+        return "Task["+(Strings.isNonEmpty(displayName) ? displayName : 
+                job + 
+                (tags!=null && !tags.isEmpty() ? ";"+tags : "")) +
+                ":"+getId()+"]";
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/40b63e21/core/src/main/java/brooklyn/util/task/DynamicSequentialTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/DynamicSequentialTask.java b/core/src/main/java/brooklyn/util/task/DynamicSequentialTask.java
index 15ccb14..a17ffbe 100644
--- a/core/src/main/java/brooklyn/util/task/DynamicSequentialTask.java
+++ b/core/src/main/java/brooklyn/util/task/DynamicSequentialTask.java
@@ -367,7 +367,7 @@ public class DynamicSequentialTask<T> extends BasicTask<T> implements HasTaskChi
         
         @Override
         public String toString() {
-            return "DstJob:"+DynamicSequentialTask.this;
+            return "DstJob:"+DynamicSequentialTask.this.getId();
         }
 
         /** waits for this job to complete, or the given time to elapse */

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/40b63e21/core/src/main/java/brooklyn/util/task/SingleThreadedScheduler.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/SingleThreadedScheduler.java b/core/src/main/java/brooklyn/util/task/SingleThreadedScheduler.java
index 4c28369..420002f 100644
--- a/core/src/main/java/brooklyn/util/task/SingleThreadedScheduler.java
+++ b/core/src/main/java/brooklyn/util/task/SingleThreadedScheduler.java
@@ -76,12 +76,7 @@ public class SingleThreadedScheduler implements TaskScheduler, CanSetName {
             return executeNow(c);
         } else {
             WrappingFuture<T> f = new WrappingFuture<T>();
-            order.add(new QueuedSubmission<T>(c, f) {
-                @Override
-                public String toString() {
-                    return "QueuedSubmission["+c+"]";
-                }
-            });
+            order.add(new QueuedSubmission<T>(c, f));
             int size = order.size();
             if (size>0 && (size == 50 || (size<=500 && (size%100)==0) || (size%1000)==0) && size!=lastSizeWarn) {
                 LOG.warn("{} is backing up, {} tasks queued", this, size);
@@ -133,6 +128,11 @@ public class SingleThreadedScheduler implements TaskScheduler, CanSetName {
             this.c = c;
             this.f = f;
         }
+        
+        @Override
+        public String toString() {
+            return "QueuedSubmission["+c+"]@"+Integer.toHexString(System.identityHashCode(this));
+        }
     }
     
     /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/40b63e21/utils/common/src/main/java/brooklyn/util/javalang/RunnableAdapter.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/javalang/RunnableAdapter.java b/utils/common/src/main/java/brooklyn/util/javalang/RunnableAdapter.java
new file mode 100644
index 0000000..d61e84b
--- /dev/null
+++ b/utils/common/src/main/java/brooklyn/util/javalang/RunnableAdapter.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package brooklyn.util.javalang;
+
+import java.util.concurrent.Callable;
+
+public class RunnableAdapter<T> implements Callable<T> {
+    final Runnable task;
+    final T result;
+    
+    public RunnableAdapter(Runnable task, T result) {
+        this.task = task;
+        this.result = result;
+    }
+    
+    public T call() {
+        task.run();
+        return result;
+    }
+    
+    @Override
+    public String toString() {
+        if (result!=null)
+            return "RunnableAdapter["+task+(result!=null ? "->"+result : "")+"]";
+        else
+            return ""+task;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/40b63e21/utils/groovy/src/main/java/brooklyn/util/GroovyJavaMethods.groovy
----------------------------------------------------------------------
diff --git a/utils/groovy/src/main/java/brooklyn/util/GroovyJavaMethods.groovy b/utils/groovy/src/main/java/brooklyn/util/GroovyJavaMethods.groovy
index 5867bda..c34f72d 100644
--- a/utils/groovy/src/main/java/brooklyn/util/GroovyJavaMethods.groovy
+++ b/utils/groovy/src/main/java/brooklyn/util/GroovyJavaMethods.groovy
@@ -21,7 +21,8 @@ package brooklyn.util;
 import static brooklyn.util.GroovyJavaMethods.truth
 
 import java.util.concurrent.Callable
-import java.util.concurrent.Executors
+
+import brooklyn.util.javalang.RunnableAdapter
 
 import com.google.common.base.Function
 import com.google.common.base.Predicate
@@ -53,7 +54,7 @@ public class GroovyJavaMethods {
     }
 
     public static <T> Callable<T> callableFromRunnable(final Runnable job) {
-        return (job in Callable) ? callableFromClosure(job) : Executors.callable(job);
+        return (job in Callable) ? callableFromClosure(job) : new RunnableAdapter<Object>(job, null);
     }
 
     public static <T> Predicate<T> predicateFromClosure(final Closure<Boolean> job) {


[06/31] git commit: improve display of task results, catch NPE when switching task contexts, and ensure data is cleared (nulled) for old map entries due to backbone bug (without this, sometimes blockingTask might show up as `TYPEOF undefined` when you in

Posted by he...@apache.org.
improve display of task results, catch NPE when switching task contexts, and ensure data is cleared (nulled) for old map entries due to backbone bug (without this, sometimes blockingTask might show up as `TYPEOF undefined` when you inspect its JSON)


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/bbfbd376
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/bbfbd376
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/bbfbd376

Branch: refs/heads/master
Commit: bbfbd37608bc76ceb00db96f83168b65a9973ca0
Parents: 931d397
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Jul 21 20:37:23 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 10:41:11 2014 -0400

----------------------------------------------------------------------
 .../src/main/webapp/assets/js/model/task-summary.js     |  2 +-
 .../src/main/webapp/assets/js/view/activity-details.js  | 12 ++++++++----
 2 files changed, 9 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/bbfbd376/usage/jsgui/src/main/webapp/assets/js/model/task-summary.js
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/js/model/task-summary.js b/usage/jsgui/src/main/webapp/assets/js/model/task-summary.js
index 23014d7..afc3549 100644
--- a/usage/jsgui/src/main/webapp/assets/js/model/task-summary.js
+++ b/usage/jsgui/src/main/webapp/assets/js/model/task-summary.js
@@ -65,7 +65,7 @@ define([
         parse: function(resp) {
             _.keys(this.attributes).forEach(function(key) {
               if (resp[key] === undefined) {
-                resp[key] = undefined;
+                resp[key] = null;
               }
             });
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/bbfbd376/usage/jsgui/src/main/webapp/assets/js/view/activity-details.js
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/js/view/activity-details.js b/usage/jsgui/src/main/webapp/assets/js/view/activity-details.js
index 989b531..df98a77 100644
--- a/usage/jsgui/src/main/webapp/assets/js/view/activity-details.js
+++ b/usage/jsgui/src/main/webapp/assets/js/view/activity-details.js
@@ -146,10 +146,14 @@ define([
                         that.displayTextForLinkedTask(v)+"</a>" })
             this.updateFieldWith('result',
                 function(v) {
-                    if (v.toString().length<20 &&  !/\r|\n/.exec(v)) {
-                        return " with result: <span class='result-literal'>"+_.escape(v)+"</span>";
+                    // use display string (JSON.stringify(_.escape(v)) because otherwise list of [null,null] is just ","  
+                    var vs = Util.toDisplayString(v);
+                    if (vs.trim().length==0) {
+                        return " (empty result)";
+                    } else if (vs.length<20 &&  !/\r|\n/.exec(v)) {
+                        return " with result: <span class='result-literal'>"+vs+"</span>";
                     } else {
-                        return "<div class='result-literal'>"+_.escape(v).replace(/\n+/g,"<br>")+"</div>"
+                        return "<div class='result-literal'>"+vs.replace(/\n+/g,"<br>")+"</div>"
                     }
                  })
             this.updateFieldWith('tags', function(tags) {
@@ -276,7 +280,7 @@ define([
             }
             ViewUtils.updateMyDataTable(this.subtasksTable, subtasks, function(task, index) {
                 return [ task.get("id"),
-                         (task.get("entityId") && task.get("entityId")!=that.task.get("entityId") ? task.get("entityDisplayName") + ": " : "") + 
+                         (task.get("entityId") && (!that.task || task.get("entityId")!=that.task.get("entityId")) ? task.get("entityDisplayName") + ": " : "") + 
                          task.get("displayName"),
                          task.get("submitTimeUtc") <= 0 ? "-" : moment(task.get("submitTimeUtc")).calendar(),
                          task.get("currentStatus")


[13/31] git commit: fix link error

Posted by he...@apache.org.
fix link error


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/254a6f79
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/254a6f79
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/254a6f79

Branch: refs/heads/master
Commit: 254a6f79b7358f41e89903621a5532f32785e325
Parents: e3a3df9
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Jul 23 13:05:22 2014 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 10:42:07 2014 -0400

----------------------------------------------------------------------
 docs/use/guide/quickstart/policies-and-catalogs.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/254a6f79/docs/use/guide/quickstart/policies-and-catalogs.md
----------------------------------------------------------------------
diff --git a/docs/use/guide/quickstart/policies-and-catalogs.md b/docs/use/guide/quickstart/policies-and-catalogs.md
index efa06ff..f649cf9 100644
--- a/docs/use/guide/quickstart/policies-and-catalogs.md
+++ b/docs/use/guide/quickstart/policies-and-catalogs.md
@@ -26,7 +26,7 @@ Now when we open the web console, two applications are displayed from the catalo
 
 Select the 'Demo Web Cluster with DB' and click 'Next'.
 
-[![Viewing Catalog entries in Add Application dialog.](images/add-application-catalog-web-cluster-with-db.png)](add-application-catalog-web-cluster-with-db-largea.png)
+[![Viewing Catalog entries in Add Application dialog.](images/add-application-catalog-web-cluster-with-db.png)](add-application-catalog-web-cluster-with-db-large.png)
 
 Select the Location that Brooklyn should deploy to, and name your application:
 
@@ -58,7 +58,7 @@ As load is added, Brooklyn requests a new cloud machine, creates a new app serve
 
 ### Next
 
-The [Elastic Web Cluster Example]({{site.url}}/use/examples/webcluster/index.html) page
+The [Elastic Web Cluster Example]({{site.url}}use/examples/webcluster/index.html) page
 details how to build this demo application from scratch in Java. It shows in more detail how Brooklyn can
 complement your application with policy driven management, and how applications can be
 run from the command line.


[18/31] git commit: provide some detail and better tostrings when tasks are backing up

Posted by he...@apache.org.
provide some detail and better tostrings when tasks are backing up


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/c4b29907
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/c4b29907
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/c4b29907

Branch: refs/heads/master
Commit: c4b29907a39f39d03a2cd896e62df76adf29acb3
Parents: 2ecb968
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Jul 23 13:21:16 2014 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 10:42:08 2014 -0400

----------------------------------------------------------------------
 .../util/task/BasicExecutionManager.java        | 163 +++++++++++--------
 .../util/task/SingleThreadedScheduler.java      |  11 +-
 2 files changed, 102 insertions(+), 72 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c4b29907/core/src/main/java/brooklyn/util/task/BasicExecutionManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/BasicExecutionManager.java b/core/src/main/java/brooklyn/util/task/BasicExecutionManager.java
index a9d6a46..1a89501 100644
--- a/core/src/main/java/brooklyn/util/task/BasicExecutionManager.java
+++ b/core/src/main/java/brooklyn/util/task/BasicExecutionManager.java
@@ -300,47 +300,64 @@ public class BasicExecutionManager implements ExecutionManager {
 		task.submitTimeUtc = System.currentTimeMillis();
 		tasksById.put(task.getId(), task);
 		if (!task.isDone()) {
-			task.result = delayedRunner.schedule(new Callable<Object>() { @SuppressWarnings("rawtypes")
-            public Object call() {
-				if (task.startTimeUtc==-1) task.startTimeUtc = System.currentTimeMillis();
-				try {
-				    beforeStart(flags, task);
-				    final TaskInternal<?> taskScheduled = (TaskInternal<?>) task.newTask();
-				    taskScheduled.setSubmittedByTask(task);
-				    final Callable<?> oldJob = taskScheduled.getJob();
-				    taskScheduled.setJob(new Callable() { public Object call() {
-				        task.recentRun = taskScheduled;
-				        synchronized (task) {
-				            task.notifyAll();
-				        }
-				        Object result;
-				        try {
-				            result = oldJob.call();
-				        } catch (Exception e) {
-				            log.warn("Error executing "+oldJob+" (scheduled job of "+task+" - "+task.getDescription()+"); cancelling scheduled execution", e);
-				            throw Exceptions.propagate(e);
-				        }
-				        task.runCount++;
-				        if (task.period!=null && !task.isCancelled()) {
-				            task.delay = task.period;
-				            submitNewScheduledTask(flags, task);
-				        }
-				        return result;
-				    }});
-				    task.nextRun = taskScheduled;
-				    BasicExecutionContext ec = BasicExecutionContext.getCurrentExecutionContext();
-				    if (ec!=null) return ec.submit(taskScheduled);
-				    else return submit(taskScheduled);
-				} finally {
-				    afterEnd(flags, task);
-				}
-			}},
-			task.delay.toNanoseconds(), TimeUnit.NANOSECONDS);
+			task.result = delayedRunner.schedule(new ScheduledTaskCallable(task, flags),
+			    task.delay.toNanoseconds(), TimeUnit.NANOSECONDS);
 		} else {
 			task.endTimeUtc = System.currentTimeMillis();
 		}
 		return task;
 	}
+	
+	protected class ScheduledTaskCallable implements Callable<Object> {
+	    public ScheduledTask task;
+	    public Map<?,?> flags;
+	    
+	    public ScheduledTaskCallable(ScheduledTask task, Map<?, ?> flags) {
+	        this.task = task;
+	        this.flags = flags;
+        }
+
+        @SuppressWarnings({ "rawtypes", "unchecked" })
+        public Object call() {
+            if (task.startTimeUtc==-1) task.startTimeUtc = System.currentTimeMillis();
+            try {
+                beforeStart(flags, task);
+                final TaskInternal<?> taskScheduled = (TaskInternal<?>) task.newTask();
+                taskScheduled.setSubmittedByTask(task);
+                final Callable<?> oldJob = taskScheduled.getJob();
+                taskScheduled.setJob(new Callable() { public Object call() {
+                    task.recentRun = taskScheduled;
+                    synchronized (task) {
+                        task.notifyAll();
+                    }
+                    Object result;
+                    try {
+                        result = oldJob.call();
+                    } catch (Exception e) {
+                        log.warn("Error executing "+oldJob+" (scheduled job of "+task+" - "+task.getDescription()+"); cancelling scheduled execution", e);
+                        throw Exceptions.propagate(e);
+                    }
+                    task.runCount++;
+                    if (task.period!=null && !task.isCancelled()) {
+                        task.delay = task.period;
+                        submitNewScheduledTask(flags, task);
+                    }
+                    return result;
+                }});
+                task.nextRun = taskScheduled;
+                BasicExecutionContext ec = BasicExecutionContext.getCurrentExecutionContext();
+                if (ec!=null) return ec.submit(taskScheduled);
+                else return submit(taskScheduled);
+            } finally {
+                afterEnd(flags, task);
+            }
+        }
+        
+        @Override
+        public String toString() {
+            return "ScheduledTaskCallable["+task+","+flags+"]";
+        }
+	}
 
     @SuppressWarnings("unchecked")
     protected <T> Task<T> submitNewTask(final Map<?,?> flags, final Task<T> task) {
@@ -355,43 +372,49 @@ public class BasicExecutionManager implements ExecutionManager {
         if (((TaskInternal<T>)task).getJob() == null) 
             throw new NullPointerException("Task "+task+" submitted with with null job: job must be supplied.");
         
-        Callable<T> job = new Callable<T>() { public T call() {
-          try {
-            T result = null;
-            Throwable error = null;
-            String oldThreadName = Thread.currentThread().getName();
-            try {
-                if (RENAME_THREADS) {
-                    String newThreadName = oldThreadName+"-"+task.getDisplayName()+
-                            "["+task.getId().substring(0, 8)+"]";
-                    Thread.currentThread().setName(newThreadName);
-                }
-                beforeStart(flags, task);
-                if (!task.isCancelled()) {
-                    result = ((TaskInternal<T>)task).getJob().call();
-                } else throw new CancellationException();
-            } catch(Throwable e) {
-                error = e;
-            } finally {
-                if (RENAME_THREADS) {
-                    Thread.currentThread().setName(oldThreadName);
+        Callable<T> job = new Callable<T>() { 
+            public T call() {
+                try {
+                    T result = null;
+                    Throwable error = null;
+                    String oldThreadName = Thread.currentThread().getName();
+                    try {
+                        if (RENAME_THREADS) {
+                            String newThreadName = oldThreadName+"-"+task.getDisplayName()+
+                                "["+task.getId().substring(0, 8)+"]";
+                            Thread.currentThread().setName(newThreadName);
+                        }
+                        beforeStart(flags, task);
+                        if (!task.isCancelled()) {
+                            result = ((TaskInternal<T>)task).getJob().call();
+                        } else throw new CancellationException();
+                    } catch(Throwable e) {
+                        error = e;
+                    } finally {
+                        if (RENAME_THREADS) {
+                            Thread.currentThread().setName(oldThreadName);
+                        }
+                        afterEnd(flags, task);
+                    }
+                    if (error!=null) {
+                        if (log.isDebugEnabled()) {
+                            // debug only here, because we rethrow
+                            log.debug("Exception running task "+task+" (rethrowing): "+error.getMessage(), error);
+                            if (log.isTraceEnabled())
+                                log.trace("Trace for exception running task "+task+" (rethrowing): "+error.getMessage(), error);
+                        }
+                        throw Exceptions.propagate(error);
+                    }
+                    return result;
+                } finally {
+                    ((TaskInternal<?>)task).runListeners();
                 }
-                afterEnd(flags, task);
             }
-            if (error!=null) {
-                if (log.isDebugEnabled()) {
-                    // debug only here, because we rethrow
-                    log.debug("Exception running task "+task+" (rethrowing): "+error.getMessage(), error);
-                    if (log.isTraceEnabled())
-                        log.trace("Trace for exception running task "+task+" (rethrowing): "+error.getMessage(), error);
-                }
-                throw Exceptions.propagate(error);
+            @Override
+            public String toString() {
+                return "BasicExecutionManager.submitNewTask.Callable["+task+","+flags+"]";
             }
-            return result;
-          } finally {
-              ((TaskInternal<?>)task).runListeners();
-          }
-        }};
+        };
         
         // If there's a scheduler then use that; otherwise execute it directly
         Set<TaskScheduler> schedulers = null;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c4b29907/core/src/main/java/brooklyn/util/task/SingleThreadedScheduler.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/SingleThreadedScheduler.java b/core/src/main/java/brooklyn/util/task/SingleThreadedScheduler.java
index c53dc95..4c28369 100644
--- a/core/src/main/java/brooklyn/util/task/SingleThreadedScheduler.java
+++ b/core/src/main/java/brooklyn/util/task/SingleThreadedScheduler.java
@@ -18,7 +18,6 @@
  */
 package brooklyn.util.task;
 
-import java.util.Map;
 import java.util.Queue;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CancellationException;
@@ -77,10 +76,18 @@ public class SingleThreadedScheduler implements TaskScheduler, CanSetName {
             return executeNow(c);
         } else {
             WrappingFuture<T> f = new WrappingFuture<T>();
-            order.add(new QueuedSubmission<T>(c, f));
+            order.add(new QueuedSubmission<T>(c, f) {
+                @Override
+                public String toString() {
+                    return "QueuedSubmission["+c+"]";
+                }
+            });
             int size = order.size();
             if (size>0 && (size == 50 || (size<=500 && (size%100)==0) || (size%1000)==0) && size!=lastSizeWarn) {
                 LOG.warn("{} is backing up, {} tasks queued", this, size);
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("Task queue backing up detail, queue "+this+"; task context is "+Tasks.current()+"; latest task is "+c+"; first task is "+order.peek());
+                }
                 lastSizeWarn = size;
             }
             return f;


[30/31] git commit: This closes #83

Posted by he...@apache.org.
This closes #83


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/9751ef8b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/9751ef8b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/9751ef8b

Branch: refs/heads/master
Commit: 9751ef8bcfeb7ac8ac94497ffb0cde36ca818b17
Parents: f03d82c 8f2a694
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Jul 29 15:30:06 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 15:30:06 2014 -0400

----------------------------------------------------------------------
 .../management/TaskQueueingContext.java         |   6 +-
 .../brooklyn/entity/basic/AbstractEntity.java   |   2 +-
 .../entity/basic/AbstractGroupImpl.java         |   2 +-
 .../brooklyn/entity/basic/DynamicGroupImpl.java |  11 +-
 .../java/brooklyn/entity/basic/Entities.java    |  10 +-
 .../brooklyn/entity/group/DynamicCluster.java   |  14 +-
 .../entity/group/DynamicClusterImpl.java        |  55 ++++--
 .../event/basic/DependentConfiguration.java     |   3 +
 .../location/basic/AbstractLocation.java        |   2 +-
 .../FixedListMachineProvisioningLocation.java   |   2 +-
 .../internal/AbstractManagementContext.java     |   7 +-
 .../internal/LocalLocationManager.java          |   7 +
 .../internal/LocalManagementContext.java        |  22 ++-
 .../internal/LocalSubscriptionManager.java      |   4 +
 .../main/java/brooklyn/util/ResourceUtils.java  |   3 +
 .../util/task/BasicExecutionManager.java        | 193 +++++++++++--------
 .../main/java/brooklyn/util/task/BasicTask.java |  24 ++-
 .../util/task/DynamicSequentialTask.java        |  17 +-
 .../java/brooklyn/util/task/DynamicTasks.java   |  25 ++-
 .../java/brooklyn/util/task/ForwardingTask.java |   5 +
 .../java/brooklyn/util/task/ParallelTask.java   |   6 +-
 .../util/task/SingleThreadedScheduler.java      |  19 +-
 .../java/brooklyn/util/task/TaskBuilder.java    |  38 ++--
 .../java/brooklyn/util/task/TaskInternal.java   |   2 +-
 .../src/main/java/brooklyn/util/task/Tasks.java |  14 +-
 .../java/brooklyn/util/task/ssh/SshTasks.java   |  10 +-
 .../entity/effector/EffectorBasicTest.java      |  90 ++++++++-
 .../entity/group/DynamicClusterTest.java        |  21 +-
 ...DynamicClusterWithAvailabilityZonesTest.java |   4 +-
 .../guide/quickstart/policies-and-catalogs.md   |   4 +-
 .../location/jclouds/JcloudsLocation.java       |  11 +-
 .../brooklyn/location/jclouds/JcloudsUtil.java  |  15 +-
 .../basic/AbstractSoftwareProcessSshDriver.java |   2 +-
 .../basic/lifecycle/NaiveScriptRunner.java      |   1 +
 .../entity/basic/lifecycle/ScriptHelper.java    |   6 +
 .../webapp/ControlledDynamicWebAppCluster.java  |  10 +-
 .../ControlledDynamicWebAppClusterImpl.java     |  29 ++-
 .../entity/webapp/DynamicWebAppCluster.java     |   2 +-
 .../entity/webapp/DynamicWebAppClusterImpl.java | 168 ++++++++++++++++
 .../entity/webapp/DynamicWebAppFabricImpl.java  |   2 +
 .../entity/webapp/ElasticJavaWebAppService.java |   7 +-
 .../entity/webapp/JavaWebAppService.java        |  67 +++++++
 .../webapp/JavaWebAppSoftwareProcess.java       |  52 +----
 .../webapp/JavaWebAppSoftwareProcessImpl.java   |   3 +
 .../entity/webapp/WebAppServiceConstants.java   |  42 +---
 .../entity/webapp/WebAppServiceMetrics.java     |  73 +++++++
 .../entity/webapp/jboss/JBoss6Server.java       |   3 +-
 .../entity/webapp/jboss/JBoss7Server.java       |   3 +-
 .../entity/webapp/tomcat/TomcatServerImpl.java  |   4 +-
 .../main/webapp/assets/js/model/task-summary.js |   2 +-
 .../webapp/assets/js/view/activity-details.js   |  12 +-
 .../util/concurrent/CallableFromRunnable.java   |  54 ++++++
 .../util/exceptions/ReferenceWithError.java     |  93 +++++++++
 .../brooklyn/util/javalang/Reflections.java     |   1 +
 .../main/java/brooklyn/util/net/Networking.java |  19 ++
 .../java/brooklyn/util/repeat/Repeater.java     |  11 +-
 .../java/brooklyn/util/GroovyJavaMethods.groovy |   5 +-
 57 files changed, 1019 insertions(+), 300 deletions(-)
----------------------------------------------------------------------



[08/31] git commit: have at-entity tasks show up as children (in dynamic queueing context, though still submitted externally which means they will not be run as part of queue), and allow them to have children: improves traceability in GUI when effector m

Posted by he...@apache.org.
have at-entity tasks show up as children (in dynamic queueing context, though still submitted externally which means they will not be run as part of queue), and allow them to have children: improves traceability in GUI when effector methods call other effector methods, they show up as children rather than background tasks (or worse, not even as background tasks); and support setting flags in TaskBuilder


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/8f81e7ef
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/8f81e7ef
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/8f81e7ef

Branch: refs/heads/master
Commit: 8f81e7ef3ead8344c0aec3ec9cd081ea5700e138
Parents: b1fa299
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Jul 21 20:33:51 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 10:41:11 2014 -0400

----------------------------------------------------------------------
 .../internal/LocalManagementContext.java        | 18 ++++++++--
 .../java/brooklyn/util/task/TaskBuilder.java    | 38 +++++++++++++-------
 2 files changed, 41 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8f81e7ef/core/src/main/java/brooklyn/management/internal/LocalManagementContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/internal/LocalManagementContext.java b/core/src/main/java/brooklyn/management/internal/LocalManagementContext.java
index 3ee97a7..2ab2be6 100644
--- a/core/src/main/java/brooklyn/management/internal/LocalManagementContext.java
+++ b/core/src/main/java/brooklyn/management/internal/LocalManagementContext.java
@@ -52,11 +52,14 @@ import brooklyn.management.ExecutionManager;
 import brooklyn.management.ManagementContext;
 import brooklyn.management.SubscriptionManager;
 import brooklyn.management.Task;
+import brooklyn.management.TaskAdaptable;
 import brooklyn.management.ha.OsgiManager;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.task.BasicExecutionContext;
 import brooklyn.util.task.BasicExecutionManager;
+import brooklyn.util.task.DynamicTasks;
+import brooklyn.util.task.Tasks;
 import brooklyn.util.text.Strings;
 
 import com.google.common.annotations.Beta;
@@ -322,12 +325,21 @@ public class LocalManagementContext extends AbstractManagementContext {
         terminate();
     }
 
+    @SuppressWarnings({ "unchecked", "rawtypes" })
     @Override
-    public <T> Task<T> runAtEntity(@SuppressWarnings("rawtypes") Map flags, Entity entity, Callable<T> c) {
+    public <T> Task<T> runAtEntity(Map flags, Entity entity, Callable<T> c) {
 		manageIfNecessary(entity, elvis(Arrays.asList(flags.get("displayName"), flags.get("description"), flags, c)));
-        return getExecutionContext(entity).submit(flags, c);
+        return runAtEntity(entity, Tasks.<T>builder().dynamic(true).body(c).flags(flags).build());
     }
 
+    protected <T> Task<T> runAtEntity(Entity entity, TaskAdaptable<T> task) {
+        getExecutionContext(entity).submit(task);
+        if (DynamicTasks.getTaskQueuingContext()!=null) {
+            // put it in the queueing context so it appears
+            DynamicTasks.getTaskQueuingContext().queue(task.asTask());
+        }
+        return task.asTask();
+    }
     
     @Override
     protected <T> Task<T> runAtEntity(final Entity entity, final Effector<T> eff, @SuppressWarnings("rawtypes") final Map parameters) {
@@ -338,7 +350,7 @@ public class LocalManagementContext extends AbstractManagementContext {
             log.debug("Top-level effector invocation: {} on {}", eff, entity);
             ec = getExecutionContext(entity);
         }
-        return ec.submit(Effectors.invocation(entity, eff, parameters));
+        return runAtEntity(entity, Effectors.invocation(entity, eff, parameters));
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8f81e7ef/core/src/main/java/brooklyn/util/task/TaskBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/TaskBuilder.java b/core/src/main/java/brooklyn/util/task/TaskBuilder.java
index 35dd8bc..8b0150d 100644
--- a/core/src/main/java/brooklyn/util/task/TaskBuilder.java
+++ b/core/src/main/java/brooklyn/util/task/TaskBuilder.java
@@ -18,10 +18,9 @@
  */
 package brooklyn.util.task;
 
-import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.Callable;
 
@@ -30,7 +29,9 @@ import brooklyn.management.TaskAdaptable;
 import brooklyn.management.TaskFactory;
 import brooklyn.management.TaskQueueingContext;
 import brooklyn.util.JavaGroovyEquivalents;
+import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
+import brooklyn.util.collections.MutableSet;
 
 import com.google.common.collect.Iterables;
 
@@ -41,8 +42,9 @@ public class TaskBuilder<T> {
     String description = null;
     Callable<T> body = null;
     Boolean swallowChildrenFailures = null;
-    List<TaskAdaptable<?>> children = new ArrayList<TaskAdaptable<?>>();
-    Set<Object> tags = new LinkedHashSet<Object>();
+    List<TaskAdaptable<?>> children = MutableList.of();
+    Set<Object> tags = MutableSet.of();
+    Map<String,Object> flags = MutableMap.of();
     Boolean dynamic = null;
     boolean parallel = false;
     
@@ -112,18 +114,30 @@ public class TaskBuilder<T> {
         tags.add(tag);
         return this;
     }
+    
+    /** adds a flag to the given task */
+    public TaskBuilder<T> flag(String flag, Object value) {
+        flags.put(flag, value);
+        return this;
+    }
+
+    /** adds the given flags to the given task */
+    public TaskBuilder<T> flags(Map<String,Object> flags) {
+        this.flags.putAll(flags);
+        return this;
+    }
 
     @SuppressWarnings({ "unchecked", "rawtypes" })
     public Task<T> build() {
-        MutableMap<String, Object> flags = MutableMap.of();
-        if (name!=null) flags.add("displayName", name);
-        if (description!=null) flags.add("description", description);
-        if (!tags.isEmpty()) flags.add("tags", tags);
+        MutableMap<String, Object> taskFlags = MutableMap.copyOf(flags);
+        if (name!=null) taskFlags.add("displayName", name);
+        if (description!=null) taskFlags.add("description", description);
+        if (!tags.isEmpty()) taskFlags.add("tags", tags);
         
         if (Boolean.FALSE.equals(dynamic) && children.isEmpty()) {
             if (swallowChildrenFailures!=null)
                 throw new IllegalArgumentException("Cannot set swallowChildrenFailures for non-dynamic task: "+this);
-            return new BasicTask<T>(flags, body);
+            return new BasicTask<T>(taskFlags, body);
         }
         
         // prefer dynamic set unless (a) user has said not dynamic, or (b) it's parallel (since there is no dynamic parallel yet)
@@ -132,7 +146,7 @@ public class TaskBuilder<T> {
         if (Boolean.TRUE.equals(dynamic) || (dynamic==null && !parallel)) {
             if (parallel)
                 throw new UnsupportedOperationException("No implementation of parallel dynamic aggregate task available");
-            DynamicSequentialTask<T> result = new DynamicSequentialTask<T>(flags, body);
+            DynamicSequentialTask<T> result = new DynamicSequentialTask<T>(taskFlags, body);
             if (swallowChildrenFailures!=null && swallowChildrenFailures.booleanValue()) result.swallowChildrenFailures();
             for (TaskAdaptable t: children)
                 result.queue(t.asTask());
@@ -148,9 +162,9 @@ public class TaskBuilder<T> {
         }
         
         if (parallel)
-            return new ParallelTask(flags, children);
+            return new ParallelTask(taskFlags, children);
         else
-            return new SequentialTask(flags, children);
+            return new SequentialTask(taskFlags, children);
     }
 
     /** returns a a factory based on this builder */


[20/31] git commit: fix ibm jdk TLS bug

Posted by he...@apache.org.
fix ibm jdk TLS bug


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/a5c29875
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/a5c29875
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/a5c29875

Branch: refs/heads/master
Commit: a5c29875505e62d9d28a1f6c2457710d1d89f94f
Parents: e17b609
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Jul 23 19:43:25 2014 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 10:42:09 2014 -0400

----------------------------------------------------------------------
 .../main/java/brooklyn/util/ResourceUtils.java   |  3 +++
 .../location/jclouds/JcloudsLocation.java        |  2 ++
 .../main/java/brooklyn/util/net/Networking.java  | 19 +++++++++++++++++++
 3 files changed, 24 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a5c29875/core/src/main/java/brooklyn/util/ResourceUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/ResourceUtils.java b/core/src/main/java/brooklyn/util/ResourceUtils.java
index 5aacfb3..cabd036 100644
--- a/core/src/main/java/brooklyn/util/ResourceUtils.java
+++ b/core/src/main/java/brooklyn/util/ResourceUtils.java
@@ -46,6 +46,7 @@ import brooklyn.management.classloading.JavaBrooklynClassLoadingContext;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.javalang.Threads;
+import brooklyn.util.net.Networking;
 import brooklyn.util.net.Urls;
 import brooklyn.util.os.Os;
 import brooklyn.util.stream.Streams;
@@ -66,6 +67,8 @@ public class ResourceUtils {
     private String context = null;
     private Object contextObject = null;
     
+    static { Networking.init(); }
+    
     /**
      * Creates a {@link ResourceUtils} object with a specific class loader and context.
      * <p>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a5c29875/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
index 1873244..f37c3cb 100644
--- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
+++ b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
@@ -194,6 +194,8 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
     @SetFromFlag // so it's persisted
     private final Map<JcloudsSshMachineLocation,String> vmInstanceIds = Maps.newLinkedHashMap();
     
+    static { Networking.init(); }
+    
     public JcloudsLocation() {
         super();
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a5c29875/utils/common/src/main/java/brooklyn/util/net/Networking.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/net/Networking.java b/utils/common/src/main/java/brooklyn/util/net/Networking.java
index dde2678..5c7df18 100644
--- a/utils/common/src/main/java/brooklyn/util/net/Networking.java
+++ b/utils/common/src/main/java/brooklyn/util/net/Networking.java
@@ -386,4 +386,23 @@ public class Networking {
 
     // TODO go through nic's, looking for public, private, etc, on localhost
 
+    /**
+     * intsall TLSv1, fixing:
+     * http://stackoverflow.com/questions/9828414/receiving-sslhandshakeexception-handshake-failure-despite-my-client-ignoring-al
+     */
+    public static void installTlsForHttps() {
+        System.setProperty("https.protocols", "TLSv1");
+    }
+    public static void installTlsForHttpsIfAppropriate() {
+        if (System.getProperty("https.protocols")==null && System.getProperty("brooklyn.https.protocols.leave_untouched")==null) {
+            installTlsForHttps();
+        }
+    }
+    static {
+        installTlsForHttps();
+    }
+    
+    /** does nothing, but forces the class to be loaded and do static initialization */
+    public static void init() {}
+    
 }


[02/31] git commit: move deploy and redeploy bodies to DynamicWebAppCluster, with ControlledDWAC calling to that, and with new interfaces for the shared items (deploy effectors etc) so that ControlledDWAC is not a JavaWebAppSoftwareProcess

Posted by he...@apache.org.
move deploy and redeploy bodies to DynamicWebAppCluster, with ControlledDWAC calling to that,
and with new interfaces for the shared items (deploy effectors etc) so that ControlledDWAC is not a JavaWebAppSoftwareProcess


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/8a3188d3
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/8a3188d3
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/8a3188d3

Branch: refs/heads/master
Commit: 8a3188d3bbed97b905857c5187f722d67f0f178a
Parents: dbf26e3
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Jul 18 15:58:16 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 10:41:10 2014 -0400

----------------------------------------------------------------------
 .../brooklyn/entity/basic/AbstractEntity.java   |   2 +-
 .../entity/basic/AbstractGroupImpl.java         |   2 +-
 .../brooklyn/entity/basic/DynamicGroupImpl.java |   2 +-
 .../ControlledDynamicWebAppClusterImpl.java     | 113 +++----------------
 .../entity/webapp/DynamicWebAppCluster.java     |   2 +-
 .../entity/webapp/DynamicWebAppClusterImpl.java | 110 ++++++++++++++++++
 .../entity/webapp/DynamicWebAppFabricImpl.java  |   2 +
 .../entity/webapp/ElasticJavaWebAppService.java |   7 +-
 .../webapp/JavaWebAppSoftwareProcessImpl.java   |   3 +
 .../entity/webapp/WebAppServiceConstants.java   |  42 +------
 .../entity/webapp/WebAppServiceMetrics.java     |  73 ++++++++++++
 .../entity/webapp/jboss/JBoss6Server.java       |   3 +-
 .../entity/webapp/jboss/JBoss7Server.java       |   3 +-
 13 files changed, 215 insertions(+), 149 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8a3188d3/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
index 0f291bf..438f407 100644
--- a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
+++ b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
@@ -243,7 +243,7 @@ public abstract class AbstractEntity implements EntityLocal, EntityInternal {
      * @deprecated since 0.5; instead use no-arg constructor with EntityManager().createEntity(spec)
      */
     @Deprecated
-    public AbstractEntity(Map flags, Entity parent) {
+    public AbstractEntity(@SuppressWarnings("rawtypes") Map flags, Entity parent) {
         if (flags==null) {
             throw new IllegalArgumentException("Flags passed to entity "+this+" must not be null (try no-arguments or empty map)");
         }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8a3188d3/core/src/main/java/brooklyn/entity/basic/AbstractGroupImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/AbstractGroupImpl.java b/core/src/main/java/brooklyn/entity/basic/AbstractGroupImpl.java
index 8542e3a..4aeb931 100644
--- a/core/src/main/java/brooklyn/entity/basic/AbstractGroupImpl.java
+++ b/core/src/main/java/brooklyn/entity/basic/AbstractGroupImpl.java
@@ -61,7 +61,7 @@ public abstract class AbstractGroupImpl extends AbstractEntity implements Abstra
     }
 
     @Deprecated
-    public AbstractGroupImpl(Map flags, Entity parent) {
+    public AbstractGroupImpl(@SuppressWarnings("rawtypes") Map flags, Entity parent) {
         super(flags, parent);
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8a3188d3/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java b/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java
index 67a5d26..11544eb 100644
--- a/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java
+++ b/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java
@@ -50,7 +50,7 @@ public class DynamicGroupImpl extends AbstractGroupImpl implements DynamicGroup
     public DynamicGroupImpl() { }
 
     @Deprecated
-    public DynamicGroupImpl(Map flags, Entity parent) {
+    public DynamicGroupImpl(@SuppressWarnings("rawtypes") Map flags, Entity parent) {
         super(flags, parent);
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8a3188d3/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
index ac70f3a..3f9c026 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
@@ -18,13 +18,10 @@
  */
 package brooklyn.entity.webapp;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-
 import java.util.Collection;
 import java.util.EnumSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import java.util.concurrent.ExecutionException;
 
 import org.slf4j.Logger;
@@ -32,8 +29,6 @@ import org.slf4j.LoggerFactory;
 
 import brooklyn.enricher.Enrichers;
 import brooklyn.entity.Entity;
-import brooklyn.entity.annotation.Effector;
-import brooklyn.entity.annotation.EffectorParam;
 import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.basic.ConfigurableEntityFactory;
 import brooklyn.entity.basic.DynamicGroupImpl;
@@ -52,25 +47,20 @@ import brooklyn.event.feed.ConfigToAttributes;
 import brooklyn.location.Location;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.collections.MutableSet;
 import brooklyn.util.exceptions.Exceptions;
 
-import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 
 public class ControlledDynamicWebAppClusterImpl extends DynamicGroupImpl implements ControlledDynamicWebAppCluster {
 
     public static final Logger log = LoggerFactory.getLogger(ControlledDynamicWebAppClusterImpl.class);
-    private FilenameToWebContextMapper filenameToWebContextMapper = new FilenameToWebContextMapper();
 
     public ControlledDynamicWebAppClusterImpl() {
         this(MutableMap.of(), null);
     }
     
-    public ControlledDynamicWebAppClusterImpl(Map flags) {
+    public ControlledDynamicWebAppClusterImpl(Map<?,?> flags) {
         this(flags, null);
     }
     
@@ -78,7 +68,8 @@ public class ControlledDynamicWebAppClusterImpl extends DynamicGroupImpl impleme
         this(MutableMap.of(), parent);
     }
     
-    public ControlledDynamicWebAppClusterImpl(Map flags, Entity parent) {
+    @Deprecated
+    public ControlledDynamicWebAppClusterImpl(Map<?,?> flags, Entity parent) {
         super(flags, parent);
         setAttribute(SERVICE_UP, false);
     }
@@ -115,6 +106,7 @@ public class ControlledDynamicWebAppClusterImpl extends DynamicGroupImpl impleme
             webClusterSpec = EntitySpec.create(DynamicWebAppCluster.class);
         }
         boolean hasMemberSpec = webClusterSpec.getConfig().containsKey(DynamicWebAppCluster.MEMBER_SPEC) || webClusterSpec.getFlags().containsKey("memberSpec");
+        @SuppressWarnings("deprecation")
         boolean hasMemberFactory = webClusterSpec.getConfig().containsKey(DynamicWebAppCluster.FACTORY) || webClusterSpec.getFlags().containsKey("factory");
         if (!(hasMemberSpec || hasMemberFactory)) {
             webClusterSpec.configure(webClusterFlags);
@@ -168,6 +160,7 @@ public class ControlledDynamicWebAppClusterImpl extends DynamicGroupImpl impleme
         return getAttribute(CONTROLLER);
     }
 
+    @SuppressWarnings("unchecked")
     @Override
     public synchronized ConfigurableEntityFactory<WebAppService> getFactory() {
         return (ConfigurableEntityFactory<WebAppService>) getAttribute(FACTORY);
@@ -316,99 +309,19 @@ public class ControlledDynamicWebAppClusterImpl extends DynamicGroupImpl impleme
         return getCluster().getCurrentSize();
     }
 
-    private Entity findChildOrNull(Predicate<? super Entity> predicate) {
-        for (Entity contender : getChildren()) {
-            if (predicate.apply(contender)) return contender;
-        }
-        return null;
-    }
-    /**
-     * Deploys the given artifact, from a source URL, to all members of the cluster
-     * See {@link FileNameToContextMappingTest} for definitive examples!
-     * 
-     * @param url  where to get the war, as a URL, either classpath://xxx or file:///home/xxx or http(s)...
-     * @param targetName  where to tell the server to serve the WAR, see above
-     */
-    @Effector(description="Deploys the given artifact, from a source URL, to a given deployment filename/context")
-    public void deploy(
-            @EffectorParam(name="url", description="URL of WAR file") String url, 
-            @EffectorParam(name="targetName", description="context path where WAR should be deployed (/ for ROOT)") String targetName) {
-        try {
-            checkNotNull(url, "url");
-            checkNotNull(targetName, "targetName");
-            
-            // set it up so future nodes get the right wars
-            synchronized (this) {
-                Map<String,String> newWarsMap = MutableMap.copyOf(getConfig(WARS_BY_CONTEXT));
-                newWarsMap.put(targetName, url);
-                setConfig(WARS_BY_CONTEXT, newWarsMap);
-            }
-            
-            // now actually deploy
-            List <Entity> clusterMembers = MutableList.copyOf(
-                Iterables.filter(getCluster().getChildren(), Predicates.and(
-                     Predicates.instanceOf(JavaWebAppSoftwareProcess.class),
-                     EntityPredicates.attributeEqualTo(SERVICE_STATE, Lifecycle.RUNNING)
-            )));
-            Entities.invokeEffectorListWithArgs(this, clusterMembers, DEPLOY, url, targetName).get();            
-            
-            // Update attribute
-            Set<String> deployedWars = MutableSet.copyOf(getAttribute(DEPLOYED_WARS));
-            deployedWars.add(targetName);
-            setAttribute(DEPLOYED_WARS, deployedWars);
-            
-        } catch (Exception e) {
-            // Log and propagate, so that log says which entity had problems...
-            log.warn("Error deploying '"+url+"' to "+targetName+" on "+toString()+"; rethrowing...", e);
-            throw Exceptions.propagate(e);
-        }
+    @Override
+    public void deploy(String url, String targetName) {
+        getCluster().deploy(url, targetName);
     }
-    
-    /*
-     * TODO
-     * 
-     * - deploy to all, not just running, with a wait-for-running-or-bail-out logic
-     * - thread pool
-     * - redeploy to all (simple way, with notes)
-     * - check-in, then move down with echo here
-     */
-    
-    /** For the DEPLOYED_WARS to be updated, the input must match the result of the call to deploy */
-    @Effector(description="Undeploys the given context/artifact")
-    public void undeploy(@EffectorParam(name="targetName") String targetName) {
-    	
-        try {
-            checkNotNull(targetName, "targetName");
-            
-            // set it up so future nodes get the right wars
-            synchronized (this) {
-                Map<String,String> newWarsMap = MutableMap.copyOf(getConfig(WARS_BY_CONTEXT));
-                newWarsMap.remove(targetName);
-                setConfig(WARS_BY_CONTEXT, newWarsMap);
-            }
 
-            List <Entity> clusterMembers = MutableList.copyOf(
-                Iterables.filter(getCluster().getChildren(), Predicates.and(
-                     Predicates.instanceOf(JavaWebAppSoftwareProcess.class),
-                     EntityPredicates.attributeEqualTo(SERVICE_STATE, Lifecycle.RUNNING)
-            )));
-            Entities.invokeEffectorListWithArgs(this, clusterMembers, UNDEPLOY, targetName).get(); 
-            
-            // Update attribute
-            Set<String> deployedWars = MutableSet.copyOf(getAttribute(DEPLOYED_WARS));
-            deployedWars.remove( filenameToWebContextMapper.convertDeploymentTargetNameToContext(targetName) );
-            setAttribute(DEPLOYED_WARS, deployedWars);
-            
-        } catch (Exception e) {
-            // Log and propagate, so that log says which entity had problems...
-            log.warn("Error undeploying '"+targetName+"' on "+toString()+"; rethrowing...", e);
-            throw Exceptions.propagate(e);
-        }
+    @Override
+    public void undeploy(String targetName) {
+        getCluster().undeploy(targetName);
     }
 
     @Override
     public void redeployAll() {
-        throw new UnsupportedOperationException("TODO - support redeploying all WARs (if any of the deploy/undeploys fail)");
-    }  
+        getCluster().redeployAll();
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8a3188d3/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppCluster.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppCluster.java b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppCluster.java
index e561c56..04ec69e 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppCluster.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppCluster.java
@@ -35,7 +35,7 @@ import brooklyn.util.time.Duration;
  * </ul>
  */
 @ImplementedBy(DynamicWebAppClusterImpl.class)
-public interface DynamicWebAppCluster extends DynamicCluster, WebAppService {
+public interface DynamicWebAppCluster extends DynamicCluster, WebAppService, JavaWebAppService, JavaWebAppService.CanDeployAndUndeploy, JavaWebAppService.CanRedeployAll {
 
     public static final AttributeSensor<Double> REQUEST_COUNT_PER_NODE = new BasicAttributeSensor<Double>(
             Double.class, "webapp.reqs.total.perNode", "Cluster entity request average");

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8a3188d3/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
index ec942ee..36a62de 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
@@ -18,17 +18,35 @@
  */
 package brooklyn.entity.webapp;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import brooklyn.enricher.Enrichers;
 import brooklyn.entity.Entity;
+import brooklyn.entity.annotation.Effector;
+import brooklyn.entity.annotation.EffectorParam;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.basic.EntityPredicates;
+import brooklyn.entity.basic.Lifecycle;
 import brooklyn.entity.group.DynamicCluster;
 import brooklyn.entity.group.DynamicClusterImpl;
 import brooklyn.event.AttributeSensor;
 import brooklyn.event.SensorEvent;
 import brooklyn.event.SensorEventListener;
+import brooklyn.util.collections.MutableList;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.collections.MutableSet;
+import brooklyn.util.exceptions.Exceptions;
 
+import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
 
 /**
  * DynamicWebAppClusters provide cluster-wide aggregates of entity attributes.  Currently totals and averages:
@@ -41,6 +59,9 @@ import com.google.common.collect.ImmutableList;
  */
 public class DynamicWebAppClusterImpl extends DynamicClusterImpl implements DynamicWebAppCluster {
 
+    private static final Logger log = LoggerFactory.getLogger(DynamicWebAppClusterImpl.class);
+    private FilenameToWebContextMapper filenameToWebContextMapper = new FilenameToWebContextMapper();
+    
     /**
      * Instantiate a new DynamicWebAppCluster.  Parameters as per {@link DynamicCluster#DynamicCluster()}
      */
@@ -129,4 +150,93 @@ public class DynamicWebAppClusterImpl extends DynamicClusterImpl implements Dyna
         }
         return up;
     }
+    
+    /**
+     * Deploys the given artifact, from a source URL, to all members of the cluster
+     * See {@link FileNameToContextMappingTest} for definitive examples!
+     * 
+     * @param url  where to get the war, as a URL, either classpath://xxx or file:///home/xxx or http(s)...
+     * @param targetName  where to tell the server to serve the WAR, see above
+     */
+    @Effector(description="Deploys the given artifact, from a source URL, to a given deployment filename/context")
+    public void deploy(
+            @EffectorParam(name="url", description="URL of WAR file") String url, 
+            @EffectorParam(name="targetName", description="context path where WAR should be deployed (/ for ROOT)") String targetName) {
+        try {
+            checkNotNull(url, "url");
+            checkNotNull(targetName, "targetName");
+            
+            // set it up so future nodes get the right wars
+            synchronized (this) {
+                Map<String,String> newWarsMap = MutableMap.copyOf(getConfig(WARS_BY_CONTEXT));
+                newWarsMap.put(targetName, url);
+                setConfig(WARS_BY_CONTEXT, newWarsMap);
+            }
+            
+            // now actually deploy
+            List <Entity> clusterMembers = MutableList.copyOf(
+                Iterables.filter(getChildren(), Predicates.and(
+                     Predicates.instanceOf(JavaWebAppSoftwareProcess.class),
+                     EntityPredicates.attributeEqualTo(SERVICE_STATE, Lifecycle.RUNNING)
+            )));
+            Entities.invokeEffectorListWithArgs(this, clusterMembers, DEPLOY, url, targetName).get();            
+            
+            // Update attribute
+            Set<String> deployedWars = MutableSet.copyOf(getAttribute(DEPLOYED_WARS));
+            deployedWars.add(targetName);
+            setAttribute(DEPLOYED_WARS, deployedWars);
+            
+        } catch (Exception e) {
+            // Log and propagate, so that log says which entity had problems...
+            log.warn("Error deploying '"+url+"' to "+targetName+" on "+toString()+"; rethrowing...", e);
+            throw Exceptions.propagate(e);
+        }
+    }
+    
+    /*
+     * TODO
+     * 
+     * - deploy to all, not just running, with a wait-for-running-or-bail-out logic
+     * - thread pool
+     * - redeploy to all (simple way, with notes)
+     */
+    
+    /** For the DEPLOYED_WARS to be updated, the input must match the result of the call to deploy */
+    @Effector(description="Undeploys the given context/artifact")
+    public void undeploy(@EffectorParam(name="targetName") String targetName) {
+        
+        try {
+            checkNotNull(targetName, "targetName");
+            
+            // set it up so future nodes get the right wars
+            synchronized (this) {
+                Map<String,String> newWarsMap = MutableMap.copyOf(getConfig(WARS_BY_CONTEXT));
+                newWarsMap.remove(targetName);
+                setConfig(WARS_BY_CONTEXT, newWarsMap);
+            }
+
+            List <Entity> clusterMembers = MutableList.copyOf(
+                Iterables.filter(getChildren(), Predicates.and(
+                     Predicates.instanceOf(JavaWebAppSoftwareProcess.class),
+                     EntityPredicates.attributeEqualTo(SERVICE_STATE, Lifecycle.RUNNING)
+            )));
+            Entities.invokeEffectorListWithArgs(this, clusterMembers, UNDEPLOY, targetName).get(); 
+            
+            // Update attribute
+            Set<String> deployedWars = MutableSet.copyOf(getAttribute(DEPLOYED_WARS));
+            deployedWars.remove( filenameToWebContextMapper.convertDeploymentTargetNameToContext(targetName) );
+            setAttribute(DEPLOYED_WARS, deployedWars);
+            
+        } catch (Exception e) {
+            // Log and propagate, so that log says which entity had problems...
+            log.warn("Error undeploying '"+targetName+"' on "+toString()+"; rethrowing...", e);
+            throw Exceptions.propagate(e);
+        }
+    }
+
+    @Override
+    public void redeployAll() {
+        throw new UnsupportedOperationException("TODO - support redeploying all WARs (if any of the deploy/undeploys fail)");
+    }  
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8a3188d3/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppFabricImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppFabricImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppFabricImpl.java
index 3af6817..4023748 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppFabricImpl.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppFabricImpl.java
@@ -63,7 +63,9 @@ public class DynamicWebAppFabricImpl extends DynamicFabricImpl implements Dynami
         }
         
         for (List<? extends AttributeSensor<? extends Number>> es : averagingEnricherSetup) {
+            @SuppressWarnings("unchecked")
             AttributeSensor<Number> t = (AttributeSensor<Number>) es.get(0);
+            @SuppressWarnings("unchecked")
             AttributeSensor<Double> average = (AttributeSensor<Double>) es.get(1);
             
             // TODO This needs to respond to changes in FABRIC_SIZE as well, to recalculate

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8a3188d3/software/webapp/src/main/java/brooklyn/entity/webapp/ElasticJavaWebAppService.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/ElasticJavaWebAppService.java b/software/webapp/src/main/java/brooklyn/entity/webapp/ElasticJavaWebAppService.java
index 26e9e96..89a1311 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/ElasticJavaWebAppService.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/ElasticJavaWebAppService.java
@@ -24,6 +24,7 @@ import brooklyn.entity.Entity;
 import brooklyn.entity.basic.AbstractConfigurableEntityFactory;
 import brooklyn.entity.basic.ConfigurableEntityFactory;
 import brooklyn.entity.basic.EntityFactoryForLocation;
+import brooklyn.entity.proxying.EntitySpec;
 import brooklyn.entity.trait.Startable;
 import brooklyn.location.Location;
 import brooklyn.location.MachineProvisioningLocation;
@@ -34,10 +35,14 @@ public interface ElasticJavaWebAppService extends JavaWebAppService, Startable {
         ConfigurableEntityFactory<ElasticJavaWebAppService> newWebClusterFactory();
     }
 
+    /** @deprecated since 0.7.0 use {@link EntitySpec} */
+    @Deprecated
     public static class Factory extends AbstractConfigurableEntityFactory<ElasticJavaWebAppService>
     implements EntityFactoryForLocation<ElasticJavaWebAppService> {
 
-        public ElasticJavaWebAppService newEntity2(Map flags, Entity parent) {
+        private static final long serialVersionUID = 6654647949712073832L;
+
+        public ElasticJavaWebAppService newEntity2(@SuppressWarnings("rawtypes") Map flags, Entity parent) {
             return new ControlledDynamicWebAppClusterImpl(flags, parent);
         }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8a3188d3/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcessImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcessImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcessImpl.java
index c67ad2b..2b6ab29 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcessImpl.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcessImpl.java
@@ -48,14 +48,17 @@ public abstract class JavaWebAppSoftwareProcessImpl extends SoftwareProcessImpl
         super();
     }
 
+    @SuppressWarnings("rawtypes")
     public JavaWebAppSoftwareProcessImpl(Entity parent){
         this(new LinkedHashMap(),parent);
     }
 
+    @SuppressWarnings("rawtypes")
     public JavaWebAppSoftwareProcessImpl(Map flags){
         this(flags, null);
     }
 
+    @SuppressWarnings("rawtypes")
     public JavaWebAppSoftwareProcessImpl(Map flags, Entity parent) {
         super(flags, parent);
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8a3188d3/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceConstants.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceConstants.java b/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceConstants.java
index b76ea2e..4a9903e 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceConstants.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceConstants.java
@@ -23,17 +23,14 @@ import java.util.Set;
 import brooklyn.config.render.RendererHints;
 import brooklyn.entity.basic.Attributes;
 import brooklyn.event.AttributeSensor;
-import brooklyn.event.basic.BasicAttributeSensor;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
 import brooklyn.event.basic.Sensors;
 import brooklyn.util.flags.SetFromFlag;
-import brooklyn.util.text.ByteSizeStrings;
-import brooklyn.util.time.Duration;
 
 import com.google.common.collect.ImmutableList;
 
-public interface WebAppServiceConstants {
+public interface WebAppServiceConstants extends WebAppServiceMetrics {
 
     @SetFromFlag("httpPort")
     public static final PortAttributeSensorAndConfigKey HTTP_PORT = Attributes.HTTP_PORT;
@@ -50,50 +47,15 @@ public interface WebAppServiceConstants {
     public static final BasicAttributeSensorAndConfigKey<HttpsSslConfig> HTTPS_SSL_CONFIG = new BasicAttributeSensorAndConfigKey<HttpsSslConfig>(
             HttpsSslConfig.class, "webapp.https.ssl", "SSL Configuration for HTTPS", null);
     
-    public static final AttributeSensor<Integer> REQUEST_COUNT =
-            Sensors.newIntegerSensor("webapp.reqs.total", "Request count");
-    public static final brooklyn.event.basic.BasicAttributeSensor<Integer> ERROR_COUNT =
-            new brooklyn.event.basic.BasicAttributeSensor<Integer>(Integer.class, "webapp.reqs.errors", "Request errors");
-    public static final AttributeSensor<Integer> TOTAL_PROCESSING_TIME = Sensors.newIntegerSensor(
-            "webapp.reqs.processingTime.total", "Total processing time, reported by webserver (millis)");
-    public static final AttributeSensor<Integer> MAX_PROCESSING_TIME =
-            Sensors.newIntegerSensor("webapp.reqs.processingTime.max", "Max processing time for any single request, reported by webserver (millis)");
-
-    /** the fraction of time represented by the most recent delta to TOTAL_PROCESSING_TIME, ie 0.4 if 800 millis were accumulated in last 2s;
-     * easily configured with {@link WebAppServiceMethods#connectWebAppServerPolicies(brooklyn.entity.basic.EntityLocal, brooklyn.util.time.Duration)} */
-    public static final AttributeSensor<Double> PROCESSING_TIME_FRACTION_LAST =
-            Sensors.newDoubleSensor("webapp.reqs.processingTime.fraction.last", "Fraction of time spent processing, reported by webserver (percentage, last datapoint)");
-    public static final AttributeSensor<Double> PROCESSING_TIME_FRACTION_IN_WINDOW =
-            Sensors.newDoubleSensor("webapp.reqs.processingTime.fraction.windowed", "Fraction of time spent processing, reported by webserver (percentage, over time window)");
-
-    public static final AttributeSensor<Long> BYTES_RECEIVED =
-            new BasicAttributeSensor<Long>(Long.class, "webapp.reqs.bytes.received", "Total bytes received by the webserver");
-    public static final AttributeSensor<Long> BYTES_SENT =
-            new BasicAttributeSensor<Long>(Long.class, "webapp.reqs.bytes.sent", "Total bytes sent by the webserver");
-
-    /** req/second computed from the delta of the last request count and an associated timestamp */
-    public static final AttributeSensor<Double> REQUESTS_PER_SECOND_LAST =
-            Sensors.newDoubleSensor("webapp.reqs.perSec.last", "Reqs/sec (last datapoint)");
-
-    /** rolled-up req/second for a window, 
-     * easily configured with {@link WebAppServiceMethods#connectWebAppServerPolicies(brooklyn.entity.basic.EntityLocal, brooklyn.util.time.Duration)} */
-    public static final AttributeSensor<Double> REQUESTS_PER_SECOND_IN_WINDOW =
-            Sensors.newDoubleSensor("webapp.reqs.perSec.windowed", "Reqs/sec (over time window)");
-
     public static final AttributeSensor<String> ROOT_URL = RootUrl.ROOT_URL;
 
 }
 
-//this class is added because the ROOT_URL relies on a static initialization which unfortunately can't be added to
-//an interface.
+// this class is added because the ROOT_URL relies on a static initialization which unfortunately can't be added to an interface.
 class RootUrl {
     public static final AttributeSensor<String> ROOT_URL = Sensors.newStringSensor("webapp.url", "URL");
 
     static {
         RendererHints.register(ROOT_URL, new RendererHints.NamedActionWithUrl("Open"));
-        RendererHints.register(WebAppServiceConstants.TOTAL_PROCESSING_TIME, RendererHints.displayValue(Duration.millisToStringRounded()));
-        RendererHints.register(WebAppServiceConstants.MAX_PROCESSING_TIME, RendererHints.displayValue(Duration.millisToStringRounded()));
-        RendererHints.register(WebAppServiceConstants.BYTES_RECEIVED, RendererHints.displayValue(ByteSizeStrings.metric()));
-        RendererHints.register(WebAppServiceConstants.BYTES_SENT, RendererHints.displayValue(ByteSizeStrings.metric()));
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8a3188d3/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceMetrics.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceMetrics.java b/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceMetrics.java
new file mode 100644
index 0000000..710e344
--- /dev/null
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceMetrics.java
@@ -0,0 +1,73 @@
+/*
+ * 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 brooklyn.entity.webapp;
+
+import brooklyn.config.render.RendererHints;
+import brooklyn.event.AttributeSensor;
+import brooklyn.event.basic.BasicAttributeSensor;
+import brooklyn.event.basic.Sensors;
+import brooklyn.util.text.ByteSizeStrings;
+import brooklyn.util.time.Duration;
+
+public interface WebAppServiceMetrics {
+    
+    public static final AttributeSensor<Integer> REQUEST_COUNT = Initializer.REQUEST_COUNT;
+        
+    public static final brooklyn.event.basic.BasicAttributeSensor<Integer> ERROR_COUNT =
+            new brooklyn.event.basic.BasicAttributeSensor<Integer>(Integer.class, "webapp.reqs.errors", "Request errors");
+    public static final AttributeSensor<Integer> TOTAL_PROCESSING_TIME = Sensors.newIntegerSensor(
+            "webapp.reqs.processingTime.total", "Total processing time, reported by webserver (millis)");
+    public static final AttributeSensor<Integer> MAX_PROCESSING_TIME =
+            Sensors.newIntegerSensor("webapp.reqs.processingTime.max", "Max processing time for any single request, reported by webserver (millis)");
+
+    /** the fraction of time represented by the most recent delta to TOTAL_PROCESSING_TIME, ie 0.4 if 800 millis were accumulated in last 2s;
+     * easily configured with {@link WebAppServiceMethods#connectWebAppServerPolicies(brooklyn.entity.basic.EntityLocal, brooklyn.util.time.Duration)} */
+    public static final AttributeSensor<Double> PROCESSING_TIME_FRACTION_LAST =
+            Sensors.newDoubleSensor("webapp.reqs.processingTime.fraction.last", "Fraction of time spent processing, reported by webserver (percentage, last datapoint)");
+    public static final AttributeSensor<Double> PROCESSING_TIME_FRACTION_IN_WINDOW =
+            Sensors.newDoubleSensor("webapp.reqs.processingTime.fraction.windowed", "Fraction of time spent processing, reported by webserver (percentage, over time window)");
+
+    public static final AttributeSensor<Long> BYTES_RECEIVED =
+            new BasicAttributeSensor<Long>(Long.class, "webapp.reqs.bytes.received", "Total bytes received by the webserver");
+    public static final AttributeSensor<Long> BYTES_SENT =
+            new BasicAttributeSensor<Long>(Long.class, "webapp.reqs.bytes.sent", "Total bytes sent by the webserver");
+
+    /** req/second computed from the delta of the last request count and an associated timestamp */
+    public static final AttributeSensor<Double> REQUESTS_PER_SECOND_LAST =
+            Sensors.newDoubleSensor("webapp.reqs.perSec.last", "Reqs/sec (last datapoint)");
+
+    /** rolled-up req/second for a window, 
+     * easily configured with {@link WebAppServiceMethods#connectWebAppServerPolicies(brooklyn.entity.basic.EntityLocal, brooklyn.util.time.Duration)} */
+    public static final AttributeSensor<Double> REQUESTS_PER_SECOND_IN_WINDOW =
+            Sensors.newDoubleSensor("webapp.reqs.perSec.windowed", "Reqs/sec (over time window)");
+
+    // this class is added because the above need static initialization which unfortunately can't be added to an interface.
+    static class Initializer {
+        public static final AttributeSensor<Integer> REQUEST_COUNT =
+            Sensors.newIntegerSensor("webapp.reqs.total", "Request count");
+
+        static {
+            RendererHints.register(WebAppServiceConstants.TOTAL_PROCESSING_TIME, RendererHints.displayValue(Duration.millisToStringRounded()));
+            RendererHints.register(WebAppServiceConstants.MAX_PROCESSING_TIME, RendererHints.displayValue(Duration.millisToStringRounded()));
+            RendererHints.register(WebAppServiceConstants.BYTES_RECEIVED, RendererHints.displayValue(ByteSizeStrings.metric()));
+            RendererHints.register(WebAppServiceConstants.BYTES_SENT, RendererHints.displayValue(ByteSizeStrings.metric()));
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8a3188d3/software/webapp/src/main/java/brooklyn/entity/webapp/jboss/JBoss6Server.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/jboss/JBoss6Server.java b/software/webapp/src/main/java/brooklyn/entity/webapp/jboss/JBoss6Server.java
index d3a6041..f2cc135 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/jboss/JBoss6Server.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/jboss/JBoss6Server.java
@@ -24,14 +24,13 @@ import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.SoftwareProcess;
 import brooklyn.entity.java.UsesJmx;
 import brooklyn.entity.proxying.ImplementedBy;
-import brooklyn.entity.webapp.JavaWebAppService;
 import brooklyn.entity.webapp.JavaWebAppSoftwareProcess;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.util.flags.SetFromFlag;
 
 @Catalog(name="JBoss Application Server 6", description="AS6: an open source Java application server from JBoss", iconUrl="classpath:///jboss-logo.png")
 @ImplementedBy(JBoss6ServerImpl.class)
-public interface JBoss6Server extends JavaWebAppSoftwareProcess, JavaWebAppService, UsesJmx {
+public interface JBoss6Server extends JavaWebAppSoftwareProcess, UsesJmx {
 
     // TODO Instead of using portIncrement, would prefer to use http_port as "8080+" etc.
     // On localhost, if an existing jboss6 is running and consuming the required port(s), 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8a3188d3/software/webapp/src/main/java/brooklyn/entity/webapp/jboss/JBoss7Server.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/jboss/JBoss7Server.java b/software/webapp/src/main/java/brooklyn/entity/webapp/jboss/JBoss7Server.java
index 620294c..70b5131 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/jboss/JBoss7Server.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/jboss/JBoss7Server.java
@@ -24,7 +24,6 @@ import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.SoftwareProcess;
 import brooklyn.entity.proxying.ImplementedBy;
 import brooklyn.entity.trait.HasShortName;
-import brooklyn.entity.webapp.JavaWebAppService;
 import brooklyn.entity.webapp.JavaWebAppSoftwareProcess;
 import brooklyn.event.AttributeSensor;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
@@ -36,7 +35,7 @@ import brooklyn.util.javalang.JavaClassNames;
 
 @Catalog(name="JBoss Application Server 7", description="AS7: an open source Java application server from JBoss", iconUrl="classpath:///jboss-logo.png")
 @ImplementedBy(JBoss7ServerImpl.class)
-public interface JBoss7Server extends JavaWebAppSoftwareProcess, JavaWebAppService, HasShortName {
+public interface JBoss7Server extends JavaWebAppSoftwareProcess, HasShortName {
 
     @SetFromFlag("version")
     ConfigKey<String> SUGGESTED_VERSION =


[25/31] git commit: create task warnings which show up in the gui on sudo failure

Posted by he...@apache.org.
create task warnings which show up in the gui on sudo failure


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/2bffd089
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/2bffd089
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/2bffd089

Branch: refs/heads/master
Commit: 2bffd089de8c9824d472c2796d1650dd013c3879
Parents: 13299c6
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Jul 23 18:12:51 2014 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 14:41:50 2014 -0400

----------------------------------------------------------------------
 .../java/brooklyn/util/task/DynamicTasks.java   |  5 +++
 .../java/brooklyn/util/task/ssh/SshTasks.java   | 37 +++++++++++++++-----
 .../postgresql/PostgreSqlSshDriver.java         |  3 +-
 .../entity/proxy/nginx/NginxSshDriver.java      |  5 +--
 4 files changed, 39 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2bffd089/core/src/main/java/brooklyn/util/task/DynamicTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/DynamicTasks.java b/core/src/main/java/brooklyn/util/task/DynamicTasks.java
index 4a08d6f..3957b55 100644
--- a/core/src/main/java/brooklyn/util/task/DynamicTasks.java
+++ b/core/src/main/java/brooklyn/util/task/DynamicTasks.java
@@ -159,6 +159,11 @@ public class DynamicTasks {
         public void andWaitForSuccess() {
             task.getUnchecked();
         }
+        public void orCancel() {
+            if (!wasQueued()) {
+                task.cancel(false);
+            }
+        }
     }
     
     /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2bffd089/core/src/main/java/brooklyn/util/task/ssh/SshTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ssh/SshTasks.java b/core/src/main/java/brooklyn/util/task/ssh/SshTasks.java
index 6a0a63e..07e0a8a 100644
--- a/core/src/main/java/brooklyn/util/task/ssh/SshTasks.java
+++ b/core/src/main/java/brooklyn/util/task/ssh/SshTasks.java
@@ -131,9 +131,24 @@ public class SshTasks {
         return result;
     }
 
+    @Beta
+    public static enum OnFailingTask { FAIL, WARN_OR_FAIL_INESSENTIAL_IF_DYNAMIC, WARN_IN_LOG_ONLY, IGNORE }
+    public static ProcessTaskFactory<Boolean> dontRequireTtyForSudo(SshMachineLocation machine, final boolean failIfCantSudo) {
+        return dontRequireTtyForSudo(machine, failIfCantSudo ? OnFailingTask.FAIL : OnFailingTask.WARN_IN_LOG_ONLY);
+    }
     /** creates a task which returns modifies sudoers to ensure non-tty access is permitted;
      * also gives nice warnings if sudo is not permitted */
-    public static ProcessTaskFactory<Boolean> dontRequireTtyForSudo(SshMachineLocation machine, final boolean requireSuccess) {
+    public static ProcessTaskFactory<Boolean> dontRequireTtyForSudo(SshMachineLocation machine, OnFailingTask onFailingTaskRequested) {
+        final OnFailingTask onFailingTask;
+        if (onFailingTaskRequested==OnFailingTask.WARN_OR_FAIL_INESSENTIAL_IF_DYNAMIC) {
+            if (DynamicTasks.getTaskQueuingContext()!=null)
+                onFailingTask = onFailingTaskRequested;
+            else
+                onFailingTask = OnFailingTask.WARN_IN_LOG_ONLY;
+        } else {
+            onFailingTask = onFailingTaskRequested;
+        }
+        
         final String id = Identifiers.makeRandomId(6);
         return newSshExecTaskFactory(machine, 
                 BashCommands.dontRequireTtyForSudo(),
@@ -146,18 +161,24 @@ public class SshTasks {
                 if (task.getExitCode()==0 && task.getStdout().contains("sudo-is-working-"+id)) return true;
                 Entity entity = BrooklynTaskTags.getTargetOrContextEntity(Tasks.current());
                 
-                // TODO if in a queueing context can we mark this task inessential and throw?
-                // that way user sees the message...
-                String message = "Error setting up sudo for "+task.getMachine().getUser()+"@"+task.getMachine().getAddress().getHostName()+" "+
-                        " (exit code "+task.getExitCode()+(entity!=null ? ", entity "+entity : "")+")";
-                DynamicTasks.queueIfPossible(Tasks.warning(message, null));
                 
+                if (onFailingTask!=OnFailingTask.IGNORE) {
+                    // TODO if in a queueing context can we mark this task inessential and throw?
+                    // that way user sees the message...
+                    String message = "Error setting up sudo for "+task.getMachine().getUser()+"@"+task.getMachine().getAddress().getHostName()+" "+
+                        " (exit code "+task.getExitCode()+(entity!=null ? ", entity "+entity : "")+")";
+                    DynamicTasks.queueIfPossible(Tasks.warning(message, null));
+                }
                 Streams.logStreamTail(log, "STDERR of sudo setup problem", Streams.byteArrayOfString(task.getStderr()), 1024);
-                if (requireSuccess) {
+                
+                if (onFailingTask==OnFailingTask.WARN_OR_FAIL_INESSENTIAL_IF_DYNAMIC) {
+                    Tasks.markInessential();
+                }
+                if (onFailingTask==OnFailingTask.FAIL || onFailingTask==OnFailingTask.WARN_OR_FAIL_INESSENTIAL_IF_DYNAMIC) {
                     throw new IllegalStateException("Passwordless sudo is required for "+task.getMachine().getUser()+"@"+task.getMachine().getAddress().getHostName()+
                             (entity!=null ? " ("+entity+")" : ""));
                 }
-                return true; 
+                return false; 
             } });
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2bffd089/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java b/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java
index 5552ae1..5f112af 100644
--- a/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java
+++ b/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java
@@ -56,6 +56,7 @@ import brooklyn.util.os.Os;
 import brooklyn.util.stream.Streams;
 import brooklyn.util.task.DynamicTasks;
 import brooklyn.util.task.ssh.SshTasks;
+import brooklyn.util.task.ssh.SshTasks.OnFailingTask;
 import brooklyn.util.task.system.ProcessTaskWrapper;
 import brooklyn.util.text.Identifiers;
 import brooklyn.util.text.StringFunctions;
@@ -112,7 +113,7 @@ public class PostgreSqlSshDriver extends AbstractSoftwareProcessSshDriver implem
 
         DynamicTasks.queueIfPossible(SshTasks.dontRequireTtyForSudo(getMachine(),
             // sudo is absolutely required here, in customize we set user to postgres
-            true)).orSubmitAndBlock();
+            OnFailingTask.FAIL)).orSubmitAndBlock();
         DynamicTasks.waitForLast();
 
         // Check whether we can find a usable pg_ctl, and if not install one

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2bffd089/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxSshDriver.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxSshDriver.java b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxSshDriver.java
index afe3e21..df261c0 100644
--- a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxSshDriver.java
+++ b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxSshDriver.java
@@ -43,6 +43,7 @@ import brooklyn.util.stream.Streams;
 import brooklyn.util.task.DynamicTasks;
 import brooklyn.util.task.Tasks;
 import brooklyn.util.task.ssh.SshTasks;
+import brooklyn.util.task.ssh.SshTasks.OnFailingTask;
 import brooklyn.util.text.Strings;
 
 import com.google.common.collect.ImmutableList;
@@ -114,8 +115,8 @@ public class NginxSshDriver extends AbstractSoftwareProcessSshDriver implements
 
     @Override
     public void install() {
-        // will fail later if can't sudo (if sudo is required)
-        DynamicTasks.queueIfPossible(SshTasks.dontRequireTtyForSudo(getMachine(), false)).orSubmitAndBlock();
+        // inessential here, installation will fail later if it needs to sudo (eg if using port 80)
+        DynamicTasks.queueIfPossible(SshTasks.dontRequireTtyForSudo(getMachine(), OnFailingTask.WARN_OR_FAIL_INESSENTIAL_IF_DYNAMIC)).orSubmitAndBlock();
 
         DownloadResolver nginxResolver = mgmt().getEntityDownloadsManager().newDownloader(this);
         List<String> nginxUrls = nginxResolver.getTargets();


[29/31] git commit: fix QA-monitoring test failure on osx

Posted by he...@apache.org.
fix QA-monitoring test failure on osx


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/28c0cac3
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/28c0cac3
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/28c0cac3

Branch: refs/heads/master
Commit: 28c0cac35c79b0e57919ed7189a3560cb9c3c69e
Parents: 339736d
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Jul 29 15:27:04 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 15:27:04 2014 -0400

----------------------------------------------------------------------
 .../java/brooklyn/qa/longevity/MonitorUtils.java     | 15 ++++++++++++++-
 .../java/brooklyn/qa/longevity/MonitorUtilsTest.java |  8 +++++++-
 2 files changed, 21 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28c0cac3/usage/qa/src/main/java/brooklyn/qa/longevity/MonitorUtils.java
----------------------------------------------------------------------
diff --git a/usage/qa/src/main/java/brooklyn/qa/longevity/MonitorUtils.java b/usage/qa/src/main/java/brooklyn/qa/longevity/MonitorUtils.java
index 65f0d00..290a555 100644
--- a/usage/qa/src/main/java/brooklyn/qa/longevity/MonitorUtils.java
+++ b/usage/qa/src/main/java/brooklyn/qa/longevity/MonitorUtils.java
@@ -271,6 +271,19 @@ public class MonitorUtils {
         }
     }
 
+    public static class ProcessHasStderr extends IllegalStateException {
+        private static final long serialVersionUID = -937871002993888405L;
+        
+        byte[] stderrBytes;
+        public ProcessHasStderr(byte[] stderrBytes) {
+            this("Process printed to stderr: " + new String(stderrBytes), stderrBytes);
+        }
+        public ProcessHasStderr(String message, byte[] stderrBytes) {
+            super(message);
+            this.stderrBytes = stderrBytes;
+        }
+    }
+    
     /**
      * Waits for the given process to complete, consuming its stdout and returning it as a string.
      * If there is any output on stderr an exception will be thrown.
@@ -292,7 +305,7 @@ public class MonitorUtils {
             gobblerErr.blockUntilFinished();
 
             if (bytesErr.size() > 0) {
-                throw new IllegalStateException("Process printed to stderr: " + new String(bytesErr.toByteArray()));
+                throw new ProcessHasStderr(bytesErr.toByteArray());
             }
 
             return new String(bytesOut.toByteArray());

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/28c0cac3/usage/qa/src/test/java/brooklyn/qa/longevity/MonitorUtilsTest.java
----------------------------------------------------------------------
diff --git a/usage/qa/src/test/java/brooklyn/qa/longevity/MonitorUtilsTest.java b/usage/qa/src/test/java/brooklyn/qa/longevity/MonitorUtilsTest.java
index b43df13..2f1e854 100644
--- a/usage/qa/src/test/java/brooklyn/qa/longevity/MonitorUtilsTest.java
+++ b/usage/qa/src/test/java/brooklyn/qa/longevity/MonitorUtilsTest.java
@@ -32,6 +32,7 @@ import java.util.List;
 
 import org.testng.annotations.Test;
 
+import brooklyn.qa.longevity.MonitorUtils.ProcessHasStderr;
 import brooklyn.util.os.Os;
 import brooklyn.util.text.Strings;
 
@@ -99,7 +100,12 @@ public class MonitorUtilsTest {
 
         assertTrue(MonitorUtils.isPidRunning(usedPid));
         assertFalse(MonitorUtils.isPidRunning(unusedPid));
-        assertFalse(MonitorUtils.isPidRunning(1234567)); // too large
+        
+        try {
+            assertFalse(MonitorUtils.isPidRunning(1234567)); // too large
+        } catch (ProcessHasStderr e) {
+            // expected on osx
+        }
     }
 
     @Test(groups="UNIX")


[04/31] git commit: deploy / undeploy / update on the ControlledDynamicWebAppCluster

Posted by he...@apache.org.
deploy / undeploy / update on the ControlledDynamicWebAppCluster


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/9c9f0377
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/9c9f0377
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/9c9f0377

Branch: refs/heads/master
Commit: 9c9f03777114b591de5cf96a9fbbf466141c2f2c
Parents: f03d82c
Author: bmwshop <bm...@gmail.com>
Authored: Mon Jun 23 11:01:00 2014 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 10:41:10 2014 -0400

----------------------------------------------------------------------
 .../webapp/ControlledDynamicWebAppCluster.java  | 19 +++-
 .../ControlledDynamicWebAppClusterImpl.java     | 96 ++++++++++++++++++++
 2 files changed, 114 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c9f0377/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppCluster.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppCluster.java b/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppCluster.java
index 9fef09c..17fc569 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppCluster.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppCluster.java
@@ -21,6 +21,8 @@ package brooklyn.entity.webapp;
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.Entity;
 import brooklyn.entity.Group;
+import brooklyn.entity.annotation.Effector;
+import brooklyn.entity.annotation.EffectorParam;
 import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.ConfigurableEntityFactory;
@@ -57,7 +59,7 @@ import brooklyn.util.flags.SetFromFlag;
  * members has no effect on the members of the underlying DynamicCluster - treat this as a read-only view.
  */
 @ImplementedBy(ControlledDynamicWebAppClusterImpl.class)
-public interface ControlledDynamicWebAppCluster extends DynamicGroup, Entity, Startable, Resizable, MemberReplaceable, Group, ElasticJavaWebAppService {
+public interface ControlledDynamicWebAppCluster extends DynamicGroup, Entity, Startable, Resizable, MemberReplaceable, Group, ElasticJavaWebAppService, JavaWebAppSoftwareProcess {
 
     @SetFromFlag("initialSize")
     public static ConfigKey<Integer> INITIAL_SIZE = ConfigKeys.newConfigKeyWithDefault(Cluster.INITIAL_SIZE, 1);
@@ -96,4 +98,19 @@ public interface ControlledDynamicWebAppCluster extends DynamicGroup, Entity, St
     public ConfigurableEntityFactory<WebAppService> getFactory();
     
     public DynamicWebAppCluster getCluster();
+    
+    @Effector(description="Deploys the given artifact, from a source URL, to a given deployment filename/context")
+    public void deploy(
+            @EffectorParam(name="url", description="URL of WAR file") String url, 
+            @EffectorParam(name="targetName", description="context path where WAR should be deployed (/ for ROOT)") String targetName);
+
+    @Effector(description="Undeploys the given context/artifact")
+    public void undeploy(
+            @EffectorParam(name="targetName") String targetName); 
+    
+    @Effector(description="Updates the given context/artifact")
+    public void update(
+    		@EffectorParam(name="url", description="URL of NEW WAR file") String url,
+            @EffectorParam(name="targetName") String targetName);    
+    
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9c9f0377/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
index acb2327..262f9f8 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
@@ -22,6 +22,7 @@ import java.util.Collection;
 import java.util.EnumSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ExecutionException;
 
 import org.slf4j.Logger;
@@ -29,6 +30,8 @@ import org.slf4j.LoggerFactory;
 
 import brooklyn.enricher.Enrichers;
 import brooklyn.entity.Entity;
+import brooklyn.entity.annotation.Effector;
+import brooklyn.entity.annotation.EffectorParam;
 import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.basic.ConfigurableEntityFactory;
 import brooklyn.entity.basic.DynamicGroupImpl;
@@ -50,12 +53,19 @@ import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
 
 import com.google.common.base.Predicate;
+import com.google.common.base.Throwables;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+import brooklyn.entity.webapp.FilenameToWebContextMapper;
+import static com.google.common.base.Preconditions.checkNotNull;
 
 public class ControlledDynamicWebAppClusterImpl extends DynamicGroupImpl implements ControlledDynamicWebAppCluster {
 
     public static final Logger log = LoggerFactory.getLogger(ControlledDynamicWebAppClusterImpl.class);
+    private FilenameToWebContextMapper filenameToWebContextMapper = new FilenameToWebContextMapper();
 
     public ControlledDynamicWebAppClusterImpl() {
         this(MutableMap.of(), null);
@@ -313,4 +323,90 @@ public class ControlledDynamicWebAppClusterImpl extends DynamicGroupImpl impleme
         }
         return null;
     }
+    /**
+     * Deploys the given artifact, from a source URL, to all members of the cluster
+     * See {@link FileNameToContextMappingTest} for definitive examples!
+     * 
+     * @param url  where to get the war, as a URL, either classpath://xxx or file:///home/xxx or http(s)...
+     * @param targetName  where to tell the server to serve the WAR, see above
+     */
+    @Effector(description="Deploys the given artifact, from a source URL, to a given deployment filename/context")
+    public void deploy(
+            @EffectorParam(name="url", description="URL of WAR file") String url, 
+            @EffectorParam(name="targetName", description="context path where WAR should be deployed (/ for ROOT)") String targetName) {
+        try {
+            checkNotNull(url, "url");
+            checkNotNull(targetName, "targetName");
+            // actually deploy
+            List <Entity> cluster_members = Lists.newArrayList();
+//            cluster_members.addAll((Collection<? extends Entity>) Iterables.filter(getCluster().getChildren(), JavaWebAppSoftwareProcess.class)); 
+            for (JavaWebAppSoftwareProcess member : Iterables.filter(getCluster().getChildren(), JavaWebAppSoftwareProcess.class)) {
+            	Lifecycle serviceState = member.getAttribute(SERVICE_STATE);
+            	if (serviceState == Lifecycle.RUNNING) {
+            	  cluster_members.add(member);
+            	}
+            }            
+            Entities.invokeEffectorListWithArgs(this, cluster_members, DEPLOY, url, targetName).get();            
+            
+            // Update attribute
+            Set<String> deployedWars = getAttribute(DEPLOYED_WARS);
+            if (deployedWars == null) {
+                deployedWars = Sets.newLinkedHashSet();
+            }
+            deployedWars.add(targetName);
+            setAttribute(DEPLOYED_WARS, deployedWars);
+        } catch (RuntimeException e) {
+            // Log and propagate, so that log says which entity had problems...
+            log.warn("Error deploying '"+url+"' to "+targetName+" on "+toString()+"; rethrowing...", e);
+            throw Throwables.propagate(e);
+        } catch (Throwable th) {
+            // Log and propagate, so that log says which entity had problems...
+            log.warn("Error undeploying '"+targetName+"' on "+toString()+"; rethrowing...", th);
+            throw Throwables.propagate(th);
+        }
+    }
+    /** For the DEPLOYED_WARS to be updated, the input must match the result of the call to deploy */
+    @Effector(description="Undeploys the given context/artifact")
+    public void undeploy(
+            @EffectorParam(name="targetName") String targetName) {
+    	
+        try {
+
+            List <Entity> cluster_members = Lists.newArrayList();
+//            cluster_members.addAll((Collection<? extends Entity>) Iterables.filter(getCluster().getChildren(), JavaWebAppSoftwareProcess.class));
+            for (JavaWebAppSoftwareProcess member : Iterables.filter(getCluster().getChildren(), JavaWebAppSoftwareProcess.class)) {
+            	Lifecycle serviceState = member.getAttribute(SERVICE_STATE);
+            	if (serviceState == Lifecycle.RUNNING) {
+            	  cluster_members.add(member);
+            	}
+            }             
+            Entities.invokeEffectorListWithArgs(this, cluster_members, UNDEPLOY, targetName).get(); 
+            
+       	
+            // Update attribute
+            Set<String> deployedWars = getAttribute(DEPLOYED_WARS);
+            if (deployedWars == null) {
+                deployedWars = Sets.newLinkedHashSet();
+            }
+            deployedWars.remove( filenameToWebContextMapper.convertDeploymentTargetNameToContext(targetName) );
+            setAttribute(DEPLOYED_WARS, deployedWars);
+        } catch (RuntimeException e) {
+            // Log and propagate, so that log says which entity had problems...
+            log.warn("Error undeploying '"+targetName+"' on "+toString()+"; rethrowing...", e);
+            throw Throwables.propagate(e);
+        } catch (Throwable th) {
+            // Log and propagate, so that log says which entity had problems...
+            log.warn("Error undeploying '"+targetName+"' on "+toString()+"; rethrowing...", th);
+            throw Throwables.propagate(th);
+        }
+    }  
+    @Effector(description="Updates the given context/artifact")
+    public void update(
+    		@EffectorParam(name="url", description="URL of NEW WAR file") String url,
+            @EffectorParam(name="targetName") String targetName) {
+    	// simple for now
+    	undeploy(targetName);
+    	deploy(url, targetName);
+    
+    }    
 }


[17/31] git commit: give better error when ssh key with passphrase is used

Posted by he...@apache.org.
give better error when ssh key with passphrase is used


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/a7885b5f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/a7885b5f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/a7885b5f

Branch: refs/heads/master
Commit: a7885b5feaf20060187d38d2ac2de2f616004977
Parents: c4b2990
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Jul 23 15:24:19 2014 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 10:42:08 2014 -0400

----------------------------------------------------------------------
 .../brooklyn/location/jclouds/JcloudsLocation.java     |  9 +++++----
 .../java/brooklyn/location/jclouds/JcloudsUtil.java    | 13 ++++++++++++-
 .../src/main/java/brooklyn/util/repeat/Repeater.java   | 11 ++++++++---
 3 files changed, 25 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a7885b5f/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
index e27e16c..1873244 100644
--- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
+++ b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
@@ -110,6 +110,7 @@ import brooklyn.util.collections.MutableMap;
 import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.CompoundRuntimeException;
 import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.exceptions.ReferenceWithError;
 import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.Maybe;
@@ -1733,16 +1734,16 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
         
         Stopwatch stopwatch = Stopwatch.createStarted();
         
-        boolean reachable = new Repeater()
+        ReferenceWithError<Boolean> reachable = new Repeater()
             .every(1,SECONDS)
             .until(checker)
             .limitTimeTo(delayMs, MILLISECONDS)
-            .run();
+            .runKeepingError();
 
-        if (!reachable) {
+        if (!reachable.getIgnoringError()) {
             throw new IllegalStateException("SSH failed for "+
                     user+"@"+vmIp+" ("+setup.getDescription()+") after waiting "+
-                    Time.makeTimeStringRounded(delayMs));
+                    Time.makeTimeStringRounded(delayMs), reachable.getError());
         }
         
         LOG.debug("VM {}: is sshable after {} on {}@{}",new Object[] {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a7885b5f/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsUtil.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsUtil.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsUtil.java
index f3fdb34..2ac077e 100644
--- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsUtil.java
+++ b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsUtil.java
@@ -387,7 +387,18 @@ public class JcloudsUtil implements JcloudsLocationConfig {
         //     jclouds.ssh.max-retries
         //     jclouds.ssh.retry-auth
 
-        final SshClient client = context.utils().sshForNode().apply(node);
+        SshClient client;
+        try {
+            client = context.utils().sshForNode().apply(node);
+        } catch (Exception e) {
+            /* i've seen: java.lang.IllegalStateException: Optional.get() cannot be called on an absent value
+             * from org.jclouds.crypto.ASN1Codec.createASN1Sequence(ASN1Codec.java:86), if the ssh key has a passphrase, against AWS.
+             * 
+             * others have reported: java.lang.IllegalArgumentException: DER length more than 4 bytes
+             * when using a key with a passphrase (perhaps from other clouds?); not sure if that's this callpath or a different one.
+             */
+            throw new IllegalStateException("Unable to connect SshClient to "+node+"; check that the node is accessible and that the SSH key exists and is correctly configured, including any passphrase defined", e);
+        }
         return client.getHostAddress();
     }
     

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a7885b5f/utils/common/src/main/java/brooklyn/util/repeat/Repeater.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/repeat/Repeater.java b/utils/common/src/main/java/brooklyn/util/repeat/Repeater.java
index 71ca099..b2000fa 100644
--- a/utils/common/src/main/java/brooklyn/util/repeat/Repeater.java
+++ b/utils/common/src/main/java/brooklyn/util/repeat/Repeater.java
@@ -30,6 +30,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.exceptions.ReferenceWithError;
 import brooklyn.util.time.CountdownTimer;
 import brooklyn.util.time.Duration;
 import brooklyn.util.time.Time;
@@ -300,6 +301,10 @@ public class Repeater {
      * @return true if the exit condition was satisfied; false if the loop terminated for any other reason.
      */
     public boolean run() {
+        return runKeepingError().getIgnoringError();
+    }
+    
+    public ReferenceWithError<Boolean> runKeepingError() {
         Preconditions.checkState(body != null, "repeat() method has not been called to set the body");
         Preconditions.checkState(exitCondition != null, "until() method has not been called to set the exit condition");
         Preconditions.checkState(delayOnIteration != null, "every() method (or other delaySupplier() / backoff() method) has not been called to set the loop delay");
@@ -330,7 +335,7 @@ public class Repeater {
             }
             if (done) {
                 if (log.isDebugEnabled()) log.debug("{}: condition satisfied", description);
-                return true;
+                return ReferenceWithError.newInstanceWithNoError(true);
             } else {
                 if (log.isDebugEnabled()) {
                     String msg = String.format("%s: unsatisfied during iteration %s %s", description, iterations,
@@ -352,7 +357,7 @@ public class Repeater {
                 }
                 if (warnOnUnRethrownException && lastError != null)
                     log.warn("{}: error caught checking condition: {}", description, lastError.getMessage());
-                return false;
+                return ReferenceWithError.newInstanceWithInformativeError(false, lastError);
             }
 
             if (timer.isExpired()) {
@@ -362,7 +367,7 @@ public class Repeater {
                     log.error("{}: error caught checking condition: {}", description, lastError.getMessage());
                     throw Exceptions.propagate(lastError);
                 }
-                return false;
+                return ReferenceWithError.newInstanceWithInformativeError(false, lastError);
             }
 
             Time.sleep(delayThisIteration);


[10/31] git commit: effector invocations had been somewhat inconsistent in what failed -- the method call, the surrounding context -- this ensures that a programmatic call to invoke an effector will throw if it fails, that the effector task is added to a

Posted by he...@apache.org.
effector invocations had been somewhat inconsistent in what failed -- the method call, the surrounding context -- this ensures that a programmatic call to invoke an effector will throw if it fails, that the effector task is added to any parent context, but as an inessential task so it does not fail the parent context.  new tests for this are in BasicEffectorTest.  the effect is particularly magnified when we attempt to add programmatically driven effector calls to the dynamic task context (so they show up in the gui).  these are now marked inessential, which i think is right because the user is interacting programmatically, and as the caller they would typically get on the result and handle errors themselves.

this largely preserves existing behaviour, apart from with the exception that effector method calls inside other effectors could previously fail without throwing, and now they throw.

this mainly affected dynamic cluster which in some places relied on failures being silently ignored, e.g. in the resize effector call.  this effector now reliably fails if the cluster does not resize.  previously it would depend whether it was in a task or not.  to preserve compatibility in that class as much as possible, some interface methods (non-effector) have had their signature changed.  it was not clear why these were on the interface, so i have deprecated them there also.


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/1d8551ed
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/1d8551ed
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/1d8551ed

Branch: refs/heads/master
Commit: 1d8551ed67fd788bca29f49646de69ef45ca412d
Parents: 0394467
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Jul 22 13:18:41 2014 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 10:42:03 2014 -0400

----------------------------------------------------------------------
 .../java/brooklyn/entity/basic/Entities.java    | 10 ++-
 .../brooklyn/entity/group/DynamicCluster.java   | 14 ++-
 .../entity/group/DynamicClusterImpl.java        | 44 +++++++---
 .../internal/AbstractManagementContext.java     |  7 +-
 .../internal/LocalManagementContext.java        |  6 +-
 .../java/brooklyn/util/task/ParallelTask.java   |  2 +-
 .../entity/effector/EffectorBasicTest.java      | 90 +++++++++++++++++++-
 .../entity/group/DynamicClusterTest.java        | 21 ++++-
 ...DynamicClusterWithAvailabilityZonesTest.java |  4 +-
 .../util/exceptions/ReferenceWithError.java     | 86 +++++++++++++++++++
 10 files changed, 258 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1d8551ed/core/src/main/java/brooklyn/entity/basic/Entities.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/Entities.java b/core/src/main/java/brooklyn/entity/basic/Entities.java
index 2811890..3e8b225 100644
--- a/core/src/main/java/brooklyn/entity/basic/Entities.java
+++ b/core/src/main/java/brooklyn/entity/basic/Entities.java
@@ -80,6 +80,7 @@ import brooklyn.util.repeat.Repeater;
 import brooklyn.util.stream.Streams;
 import brooklyn.util.task.DynamicTasks;
 import brooklyn.util.task.ParallelTask;
+import brooklyn.util.task.TaskTags;
 import brooklyn.util.task.Tasks;
 import brooklyn.util.task.system.ProcessTaskWrapper;
 import brooklyn.util.task.system.SystemTasks;
@@ -161,7 +162,7 @@ public class Entities {
                         "description", "Invoking effector \""+effector.getName()+"\" on "+tasks.size()+(tasks.size() == 1 ? " entity" : " entities"),
                         "tag", BrooklynTaskTags.tagForCallerEntity(callingEntity)),
                 tasks);
-        
+        TaskTags.markInessential(invoke);
         return DynamicTasks.queueIfPossible(invoke).orSubmitAsync(callingEntity).asTask();
     }
     public static <T> Task<List<T>> invokeEffectorListWithMap(EntityLocal callingEntity, Iterable<? extends Entity> entitiesToCall,
@@ -183,11 +184,18 @@ public class Entities {
     public static <T> Task<T> invokeEffector(EntityLocal callingEntity, Entity entityToCall,
             final Effector<T> effector, final Map<String,?> parameters) {
         Task<T> t = Effectors.invocation(entityToCall, effector, parameters).asTask();
+        TaskTags.markInessential(t);
         
         // we pass to callingEntity for consistency above, but in exec-context it should be
         // re-dispatched to targetEntity
         ((EntityInternal)callingEntity).getManagementSupport().getExecutionContext().submit(
                 MutableMap.of("tag", BrooklynTaskTags.tagForCallerEntity(callingEntity)), t);
+        
+        if (DynamicTasks.getTaskQueuingContext()!=null) {
+            // include it as a child (in the gui), marked inessential, because the caller is invoking programmatically
+            DynamicTasks.queue(t);
+        }
+        
         return t;
     }
     @SuppressWarnings("unchecked")

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1d8551ed/core/src/main/java/brooklyn/entity/group/DynamicCluster.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/group/DynamicCluster.java b/core/src/main/java/brooklyn/entity/group/DynamicCluster.java
index 917752f..6fec83e 100644
--- a/core/src/main/java/brooklyn/entity/group/DynamicCluster.java
+++ b/core/src/main/java/brooklyn/entity/group/DynamicCluster.java
@@ -45,6 +45,7 @@ import brooklyn.event.basic.BasicAttributeSensor;
 import brooklyn.event.basic.BasicNotificationSensor;
 import brooklyn.event.basic.Sensors;
 import brooklyn.location.Location;
+import brooklyn.util.exceptions.ReferenceWithError;
 import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.time.Duration;
 
@@ -80,6 +81,7 @@ import com.google.common.reflect.TypeToken;
  */
 // TODO document use of advanced availability zone configuration and features
 @ImplementedBy(DynamicClusterImpl.class)
+@SuppressWarnings("serial")
 public interface DynamicCluster extends AbstractGroup, Cluster, MemberReplaceable {
 
     @Beta
@@ -121,6 +123,7 @@ public interface DynamicCluster extends AbstractGroup, Cluster, MemberReplaceabl
             "dynamiccluster.memberspec", "entity spec for creating new cluster members", null);
 
     /** @deprecated since 0.7.0; use {@link #MEMBER_SPEC} instead. */
+    @SuppressWarnings("rawtypes")
     @Deprecated
     @SetFromFlag("factory")
     ConfigKey<EntityFactory> FACTORY = ConfigKeys.newConfigKey(
@@ -131,6 +134,7 @@ public interface DynamicCluster extends AbstractGroup, Cluster, MemberReplaceabl
             new TypeToken<Function<Collection<Entity>, Entity>>() {},
             "dynamiccluster.removalstrategy", "strategy for deciding what to remove when down-sizing", null);
 
+    @SuppressWarnings("rawtypes")
     @SetFromFlag("customChildFlags")
     ConfigKey<Map> CUSTOM_CHILD_FLAGS = ConfigKeys.newConfigKey(
             Map.class, "dynamiccluster.customChildFlags", "Additional flags to be passed to children when they are being created", ImmutableMap.of());
@@ -176,13 +180,19 @@ public interface DynamicCluster extends AbstractGroup, Cluster, MemberReplaceabl
 
     /**
      * Adds a node to the cluster in a single {@link Location}
+     *
+     * @deprecated since 0.7.0 tricky having this on the interface as implementation details
+     * may change; for instance we are (22 Jul) changing the return type to be a ReferenceWithError 
      */
-    Optional<Entity> addInSingleLocation(Location loc, Map<?,?> extraFlags);
+    ReferenceWithError<Optional<Entity>> addInSingleLocation(Location loc, Map<?,?> extraFlags);
 
     /**
      * Adds a node to the cluster in each {@link Location}
+     * 
+     * @deprecated since 0.7.0 tricky having this on the interface as implementation details
+     * may change; for instance we are (22 Jul) changing the return type to be a ReferenceWithError 
      */
-    Collection<Entity> addInEachLocation(Iterable<Location> locs, Map<?,?> extraFlags);
+    ReferenceWithError<Collection<Entity>> addInEachLocation(Iterable<Location> locs, Map<?,?> extraFlags);
 
     void setRemovalStrategy(Function<Collection<Entity>, Entity> val);
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1d8551ed/core/src/main/java/brooklyn/entity/group/DynamicClusterImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/group/DynamicClusterImpl.java b/core/src/main/java/brooklyn/entity/group/DynamicClusterImpl.java
index 410b01e..271d9e5 100644
--- a/core/src/main/java/brooklyn/entity/group/DynamicClusterImpl.java
+++ b/core/src/main/java/brooklyn/entity/group/DynamicClusterImpl.java
@@ -56,11 +56,13 @@ import brooklyn.policy.Policy;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.exceptions.ReferenceWithError;
 import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.javalang.JavaClassNames;
 import brooklyn.util.javalang.Reflections;
 import brooklyn.util.task.DynamicTasks;
+import brooklyn.util.task.TaskTags;
 import brooklyn.util.task.Tasks;
 import brooklyn.util.text.StringPredicates;
 import brooklyn.util.text.Strings;
@@ -257,7 +259,12 @@ public class DynamicClusterImpl extends AbstractGroupImpl implements DynamicClus
             int initialSize = getConfig(INITIAL_SIZE).intValue();
             int initialQuorumSize = getInitialQuorumSize();
 
-            resize(initialSize);
+            try {
+                resize(initialSize);
+            } catch (Exception e) {
+                Exceptions.propagateIfFatal(e);
+                // ignore problems here; we extract them below
+            }
 
             Iterable<Task<?>> failed = Tasks.failed(Tasks.children(Tasks.current()));
             Iterator<Task<?>> fi = failed.iterator();
@@ -478,10 +485,12 @@ public class DynamicClusterImpl extends AbstractGroupImpl implements DynamicClus
      */
     protected Entity replaceMember(Entity member, Location memberLoc, Map<?, ?> extraFlags) {
         synchronized (mutex) {
-            Optional<Entity> added = addInSingleLocation(memberLoc, extraFlags);
+            ReferenceWithError<Optional<Entity>> added = addInSingleLocation(memberLoc, extraFlags);
 
-            if (!added.isPresent()) {
+            if (!added.getIgnoringError().isPresent()) {
                 String msg = String.format("In %s, failed to grow, to replace %s; not removing", this, member);
+                if (added.hasError())
+                    throw new IllegalStateException(msg, added.getError());
                 throw new IllegalStateException(msg);
             }
 
@@ -492,7 +501,7 @@ public class DynamicClusterImpl extends AbstractGroupImpl implements DynamicClus
                 throw new StopFailedRuntimeException("replaceMember failed to stop and remove old member "+member.getId(), e);
             }
 
-            return added.get();
+            return added.getOrThrowError().get();
         }
     }
 
@@ -575,7 +584,7 @@ public class DynamicClusterImpl extends AbstractGroupImpl implements DynamicClus
         }
 
         // create and start the entities
-        return addInEachLocation(chosenLocations, ImmutableMap.of());
+        return addInEachLocation(chosenLocations, ImmutableMap.of()).getOrThrowError();
     }
 
     /** <strong>Note</strong> for sub-clases; this method can be called while synchronized on {@link #mutex}. */
@@ -607,13 +616,15 @@ public class DynamicClusterImpl extends AbstractGroupImpl implements DynamicClus
     }
 
     @Override
-    public Optional<Entity> addInSingleLocation(Location location, Map<?,?> flags) {
-        Collection<Entity> added = addInEachLocation(ImmutableList.of(location), flags);
-        return Iterables.isEmpty(added) ? Optional.<Entity>absent() : Optional.of(Iterables.getOnlyElement(added));
+    public ReferenceWithError<Optional<Entity>> addInSingleLocation(Location location, Map<?,?> flags) {
+        ReferenceWithError<Collection<Entity>> added = addInEachLocation(ImmutableList.of(location), flags);
+        return ReferenceWithError.newInstanceWithInformativeError(
+            Iterables.isEmpty(added.getIgnoringError()) ? Optional.<Entity>absent() : Optional.of(Iterables.getOnlyElement(added.getIgnoringError())),
+                added.getError());
     }
 
     @Override
-    public Collection<Entity> addInEachLocation(Iterable<Location> locations, Map<?,?> flags) {
+    public ReferenceWithError<Collection<Entity>> addInEachLocation(Iterable<Location> locations, Map<?,?> flags) {
         List<Entity> addedEntities = Lists.newArrayList();
         Map<Entity, Location> addedEntityLocations = Maps.newLinkedHashMap();
         Map<Entity, Task<?>> tasks = Maps.newLinkedHashMap();
@@ -627,7 +638,9 @@ public class DynamicClusterImpl extends AbstractGroupImpl implements DynamicClus
             tasks.put(entity, task);
         }
 
-        DynamicTasks.queueIfPossible(Tasks.parallel("starting "+tasks.size()+" node"+Strings.s(tasks.size())+" (parallel)", tasks.values())).orSubmitAsync(this);
+        Task<List<?>> parallel = Tasks.parallel("starting "+tasks.size()+" node"+Strings.s(tasks.size())+" (parallel)", tasks.values());
+        TaskTags.markInessential(parallel);
+        DynamicTasks.queueIfPossible(parallel).orSubmitAsync(this);
         Map<Entity, Throwable> errors = waitForTasksOnEntityStart(tasks);
 
         // if tracking, then report success/fail to the ZoneFailureDetector
@@ -643,6 +656,11 @@ public class DynamicClusterImpl extends AbstractGroupImpl implements DynamicClus
                 }
             }
         }
+        
+        Collection<Entity> result = MutableList.<Entity> builder()
+            .addAll(addedEntities)
+            .removeAll(errors.keySet())
+            .build();
 
         // quarantine/cleanup as necessary
         if (!errors.isEmpty()) {
@@ -651,12 +669,10 @@ public class DynamicClusterImpl extends AbstractGroupImpl implements DynamicClus
             } else {
                 cleanupFailedNodes(errors.keySet());
             }
+            return ReferenceWithError.newInstanceWithInformativeError(result, Exceptions.create(errors.values()));
         }
 
-        return MutableList.<Entity> builder()
-                .addAll(addedEntities)
-                .removeAll(errors.keySet())
-                .build();
+        return ReferenceWithError.newInstanceWithNoError(result);
     }
 
     protected void quarantineFailedNodes(Collection<Entity> failedEntities) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1d8551ed/core/src/main/java/brooklyn/management/internal/AbstractManagementContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/internal/AbstractManagementContext.java b/core/src/main/java/brooklyn/management/internal/AbstractManagementContext.java
index 46e751d..0a3077a 100644
--- a/core/src/main/java/brooklyn/management/internal/AbstractManagementContext.java
+++ b/core/src/main/java/brooklyn/management/internal/AbstractManagementContext.java
@@ -290,12 +290,17 @@ public abstract class AbstractManagementContext implements ManagementContextInte
      * Returns the actual task (if it is local) or a proxy task (if it is remote);
      * if management for the entity has not yet started this may start it.
      * 
-     * @deprecated since 0.6.0 use effectors (or support {@code runAtEntity(Entity, Task)} if something else is needed);
+     * @deprecated since 0.6.0 use effectors (or support {@code runAtEntity(Entity, Effector, Map)} if something else is needed);
      * (Callable with Map flags is too open-ended, bothersome to support, and not used much) 
      */
     @Deprecated
     public abstract <T> Task<T> runAtEntity(@SuppressWarnings("rawtypes") Map flags, Entity entity, Callable<T> c);
 
+    /** Runs the given effector in the right place for the given entity.
+     * The task is immediately submitted in the background, but also recorded in the queueing context (if present)
+     * so it appears as a child, but marked inessential so it does not fail the parent task, who will ordinarily
+     * call {@link Task#get()} on the object and may do their own failure handling. 
+     */
     protected abstract <T> Task<T> runAtEntity(final Entity entity, final Effector<T> eff, @SuppressWarnings("rawtypes") final Map parameters);
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1d8551ed/core/src/main/java/brooklyn/management/internal/LocalManagementContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/internal/LocalManagementContext.java b/core/src/main/java/brooklyn/management/internal/LocalManagementContext.java
index 2ab2be6..136dba1 100644
--- a/core/src/main/java/brooklyn/management/internal/LocalManagementContext.java
+++ b/core/src/main/java/brooklyn/management/internal/LocalManagementContext.java
@@ -59,6 +59,7 @@ import brooklyn.util.guava.Maybe;
 import brooklyn.util.task.BasicExecutionContext;
 import brooklyn.util.task.BasicExecutionManager;
 import brooklyn.util.task.DynamicTasks;
+import brooklyn.util.task.TaskTags;
 import brooklyn.util.task.Tasks;
 import brooklyn.util.text.Strings;
 
@@ -335,7 +336,10 @@ public class LocalManagementContext extends AbstractManagementContext {
     protected <T> Task<T> runAtEntity(Entity entity, TaskAdaptable<T> task) {
         getExecutionContext(entity).submit(task);
         if (DynamicTasks.getTaskQueuingContext()!=null) {
-            // put it in the queueing context so it appears
+            // put it in the queueing context so it appears in the GUI
+            // mark it inessential as this is being invoked from code,
+            // the caller will do 'get' to handle errors
+            TaskTags.markInessential(task);
             DynamicTasks.getTaskQueuingContext().queue(task.asTask());
         }
         return task.asTask();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1d8551ed/core/src/main/java/brooklyn/util/task/ParallelTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ParallelTask.java b/core/src/main/java/brooklyn/util/task/ParallelTask.java
index eef3ed7..9828bbf 100644
--- a/core/src/main/java/brooklyn/util/task/ParallelTask.java
+++ b/core/src/main/java/brooklyn/util/task/ParallelTask.java
@@ -64,7 +64,7 @@ public class ParallelTask<T> extends CompoundTask<T> {
             } catch (Exception e) {
                 Exceptions.propagateIfFatal(e);
                 if (TaskTags.isInessential(task)) {
-                    // ignore exception is it's inessential
+                    // ignore exception as it's inessential
                 } else {
                     exceptions.add(e);
                 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1d8551ed/core/src/test/java/brooklyn/entity/effector/EffectorBasicTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/effector/EffectorBasicTest.java b/core/src/test/java/brooklyn/entity/effector/EffectorBasicTest.java
index e435445..66618f8 100644
--- a/core/src/test/java/brooklyn/entity/effector/EffectorBasicTest.java
+++ b/core/src/test/java/brooklyn/entity/effector/EffectorBasicTest.java
@@ -19,6 +19,7 @@
 package brooklyn.entity.effector;
 
 import java.util.List;
+import java.util.concurrent.Callable;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -30,13 +31,17 @@ import brooklyn.entity.BrooklynAppUnitTestSupport;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.EntityLocal;
 import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.entity.trait.FailingEntity;
 import brooklyn.entity.trait.Startable;
 import brooklyn.location.basic.SimulatedLocation;
+import brooklyn.management.HasTaskChildren;
 import brooklyn.management.Task;
 import brooklyn.management.internal.ManagementContextInternal;
 import brooklyn.test.TestUtils;
 import brooklyn.test.entity.TestEntity;
 import brooklyn.util.collections.MutableMap;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.task.Tasks;
 
 import com.google.common.collect.ImmutableList;
 
@@ -75,7 +80,6 @@ public class EffectorBasicTest extends BrooklynAppUnitTestSupport {
         TestUtils.assertSetsEqual(locs, app.getLocations());
     }
 
-
     @Test
     public void testInvokeEffectorStartWithTwoEntities() {
         TestEntity entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
@@ -92,5 +96,89 @@ public class EffectorBasicTest extends BrooklynAppUnitTestSupport {
 //        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/1d8551ed/core/src/test/java/brooklyn/entity/group/DynamicClusterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/group/DynamicClusterTest.java b/core/src/test/java/brooklyn/entity/group/DynamicClusterTest.java
index ebdd5fe..298d6d2 100644
--- a/core/src/test/java/brooklyn/entity/group/DynamicClusterTest.java
+++ b/core/src/test/java/brooklyn/entity/group/DynamicClusterTest.java
@@ -39,6 +39,7 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 
+import org.testng.Assert;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
@@ -349,7 +350,7 @@ public class DynamicClusterTest extends BrooklynAppUnitTestSupport {
                     }}));
 
         cluster.start(ImmutableList.of(loc));
-        cluster.resize(3);
+        resizeExpectingError(cluster, 3);
         assertEquals(cluster.getCurrentSize(), (Integer)2);
         assertEquals(cluster.getMembers().size(), 2);
         for (Entity member : cluster.getMembers()) {
@@ -357,6 +358,20 @@ public class DynamicClusterTest extends BrooklynAppUnitTestSupport {
         }
     }
 
+    static Exception resizeExpectingError(DynamicCluster cluster, int size) {
+        try {
+            cluster.resize(size);
+            Assert.fail("Resize should have failed");
+            // unreachable:
+            return null;
+        } catch (Exception e) {
+            Exceptions.propagateIfFatal(e);
+            // expect: brooklyn.util.exceptions.PropagatedRuntimeException: Error invoking resize at DynamicClusterImpl{id=I9Ggxfc1}: 1 of 3 parallel child tasks failed: Simulating entity stop failure for test
+            Assert.assertTrue(e.toString().contains("resize"));
+            return e;
+        }
+    }
+
     @Test
     public void testInitialQuorumSizeSufficientForStartup() throws Exception {
         final int failNum = 1;
@@ -447,7 +462,7 @@ public class DynamicClusterTest extends BrooklynAppUnitTestSupport {
                     }}));
 
         cluster.start(ImmutableList.of(loc));
-        cluster.resize(3);
+        resizeExpectingError(cluster, 3);
         assertEquals(cluster.getCurrentSize(), (Integer)2);
         assertEquals(cluster.getMembers().size(), 2);
         assertEquals(Iterables.size(Iterables.filter(cluster.getChildren(), Predicates.instanceOf(FailingEntity.class))), 3);
@@ -484,7 +499,7 @@ public class DynamicClusterTest extends BrooklynAppUnitTestSupport {
         assertEquals(cluster.getChildren().size(), 0, "children="+cluster.getChildren());
         
         // Failed node will not be a member or child
-        cluster.resize(3);
+        resizeExpectingError(cluster, 3);
         assertEquals(cluster.getCurrentSize(), (Integer)2);
         assertEquals(cluster.getMembers().size(), 2);
         assertEquals(cluster.getChildren().size(), 2, "children="+cluster.getChildren());

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1d8551ed/core/src/test/java/brooklyn/entity/group/DynamicClusterWithAvailabilityZonesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/group/DynamicClusterWithAvailabilityZonesTest.java b/core/src/test/java/brooklyn/entity/group/DynamicClusterWithAvailabilityZonesTest.java
index 569f99f..6574400 100644
--- a/core/src/test/java/brooklyn/entity/group/DynamicClusterWithAvailabilityZonesTest.java
+++ b/core/src/test/java/brooklyn/entity/group/DynamicClusterWithAvailabilityZonesTest.java
@@ -154,9 +154,9 @@ public class DynamicClusterWithAvailabilityZonesTest extends BrooklynAppUnitTest
         String otherLoc = (locUsed.equals("zone1") ? "zone2" : "zone1");
         
         // This entity will fail; configured to give up on that zone after just two failure
-        cluster.resize(2);
+        DynamicClusterTest.resizeExpectingError(cluster, 2);
         assertEquals(cluster.getCurrentSize(), (Integer)1);
-        cluster.resize(2);
+        DynamicClusterTest.resizeExpectingError(cluster, 2);
         assertEquals(cluster.getCurrentSize(), (Integer)1);
         
         cluster.resize(3);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1d8551ed/utils/common/src/main/java/brooklyn/util/exceptions/ReferenceWithError.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/exceptions/ReferenceWithError.java b/utils/common/src/main/java/brooklyn/util/exceptions/ReferenceWithError.java
new file mode 100644
index 0000000..7de6fb5
--- /dev/null
+++ b/utils/common/src/main/java/brooklyn/util/exceptions/ReferenceWithError.java
@@ -0,0 +1,86 @@
+/*
+ * 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 brooklyn.util.exceptions;
+
+import javax.annotation.Nullable;
+
+import com.google.common.base.Supplier;
+
+/** A reference to an object which can carry an object alongside it. */
+public class ReferenceWithError<T> implements Supplier<T> {
+
+    private final T object;
+    private final Throwable error;
+    private final boolean throwErrorOnAccess;
+
+    /** returns a reference which includes an error, and where attempts to get the content cause the error to throw */
+    public static <T> ReferenceWithError<T> newInstanceWithFatalError(T object, Throwable error) {
+        return new ReferenceWithError<T>(object, error, true);
+    }
+    
+    /** returns a reference which includes an error, but attempts to get the content do not cause the error to throw */
+    public static <T> ReferenceWithError<T> newInstanceWithInformativeError(T object, Throwable error) {
+        return new ReferenceWithError<T>(object, error, false);
+    }
+    
+    /** returns a reference which includes an error, but attempts to get the content do not cause the error to throw */
+    public static <T> ReferenceWithError<T> newInstanceWithNoError(T object) {
+        return new ReferenceWithError<T>(object, null, false);
+    }
+    
+    protected ReferenceWithError(@Nullable T object, @Nullable Throwable error, boolean throwErrorOnAccess) {
+        this.object = object;
+        this.error = error;
+        this.throwErrorOnAccess = throwErrorOnAccess;
+    }
+
+    public boolean throwsErrorOnAccess() {
+        return throwErrorOnAccess;
+    }
+
+    public T get() {
+        if (throwsErrorOnAccess()) {
+            return getOrThrowError();
+        }
+        return getIgnoringError();
+    }
+
+    public T getIgnoringError() {
+        return object;
+    }
+
+    public T getOrThrowError() {
+        checkNoError();
+        return object;
+    }
+
+    public void checkNoError() {
+        if (hasError())
+            Exceptions.propagate(error);
+    }
+    
+    public Throwable getError() {
+        return error;
+    }
+    
+    public boolean hasError() {
+        return error!=null;
+    }
+    
+}