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 2017/10/03 14:23:38 UTC

[01/35] brooklyn-server git commit: Merge branch 'bundle-rest-api' into adjunct-rest-api-and-highlights-2

Repository: brooklyn-server
Updated Branches:
  refs/heads/master ff5ba379e -> baf807097


Merge branch 'bundle-rest-api' into adjunct-rest-api-and-highlights-2


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

Branch: refs/heads/master
Commit: 80a4c255d595d4df9a2af7199b9a03e9f2a5641d
Parents: 459e892 1cd6bf4
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Sep 13 16:52:14 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Sep 13 16:52:14 2017 +0100

----------------------------------------------------------------------
 .../brooklyn/api/catalog/BrooklynCatalog.java   |    1 -
 .../typereg/RegisteredTypeLoadingContext.java   |    2 +-
 .../catalog/internal/BasicBrooklynCatalog.java  |  106 +-
 .../core/mgmt/ha/OsgiArchiveInstaller.java      |   18 +-
 .../mgmt/ha/OsgiBundleInstallationResult.java   |   21 +-
 .../brooklyn/core/mgmt/ha/OsgiManager.java      |   89 +-
 .../core/typereg/RegisteredTypePredicates.java  |   54 +-
 .../brooklyn/core/typereg/RegisteredTypes.java  |   43 +-
 .../org/apache/brooklyn/rest/api/BundleApi.java |  158 +++
 .../apache/brooklyn/rest/api/CatalogApi.java    |    3 +
 .../apache/brooklyn/rest/api/SubtypeApi.java    |   96 ++
 .../org/apache/brooklyn/rest/api/TypeApi.java   |   94 ++
 .../rest/domain/AdjunctConfigSummary.java       |   85 ++
 .../domain/BundleInstallationRestResult.java    |   67 ++
 .../brooklyn/rest/domain/BundleSummary.java     |   99 ++
 .../brooklyn/rest/domain/ConfigSummary.java     |   17 +-
 .../rest/domain/EnricherConfigSummary.java      |   54 +-
 .../rest/domain/PolicyConfigSummary.java        |   53 +-
 .../brooklyn/rest/domain/TaskSummary.java       |    9 +-
 .../apache/brooklyn/rest/domain/TypeDetail.java |   86 ++
 .../brooklyn/rest/domain/TypeSummary.java       |  287 +++++
 .../apache/brooklyn/rest/BrooklynRestApi.java   |    8 +-
 .../brooklyn/rest/resources/BundleResource.java |  186 +++
 .../rest/resources/CatalogResource.java         |   40 +-
 .../rest/resources/SubtypeResource.java         |   82 ++
 .../brooklyn/rest/resources/TypeResource.java   |  186 +++
 .../rest/transform/EntityTransformer.java       |   25 +-
 .../rest/transform/TypeTransformer.java         |  194 ++++
 .../BundleAndTypeAndSubtypeResourcesTest.java   | 1093 ++++++++++++++++++
 .../brooklyn/util/osgi/VersionedName.java       |   24 +-
 30 files changed, 3062 insertions(+), 218 deletions(-)
----------------------------------------------------------------------



[32/35] brooklyn-server git commit: address PR comments, note deprecation now since 0.13.0, and remove/update other deprecated

Posted by he...@apache.org.
address PR comments, note deprecation now since 0.13.0, and remove/update other deprecated


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

Branch: refs/heads/master
Commit: 28dbb83e0d52a978b4756b7a1c379da309ee820a
Parents: dd4f05e
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Oct 3 10:24:47 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Oct 3 12:29:11 2017 +0100

----------------------------------------------------------------------
 .../brooklyn/core/entity/EntityAdjuncts.java    | 28 ++++++-
 .../apache/brooklyn/core/policy/Policies.java   | 86 ++------------------
 .../apache/brooklyn/rest/api/AdjunctApi.java    | 14 ++--
 .../org/apache/brooklyn/rest/api/PolicyApi.java |  2 +-
 .../brooklyn/rest/api/PolicyConfigApi.java      |  2 +-
 .../brooklyn/rest/domain/AdjunctSummary.java    |  2 -
 .../brooklyn/rest/domain/ApplicationSpec.java   | 12 +--
 .../rest/domain/CatalogEnricherSummary.java     |  4 +-
 .../rest/domain/CatalogEntitySummary.java       |  4 +-
 .../rest/domain/CatalogItemSummary.java         |  4 +-
 .../rest/domain/CatalogLocationSummary.java     |  4 +-
 .../rest/domain/CatalogPolicySummary.java       |  4 +-
 .../brooklyn/rest/domain/EffectorSummary.java   |  9 +-
 .../brooklyn/rest/domain/EntityDetail.java      | 14 ++--
 .../brooklyn/rest/domain/EntitySummary.java     | 11 +--
 .../rest/domain/PolicyConfigSummary.java        |  2 +-
 .../brooklyn/rest/domain/PolicySummary.java     |  2 +-
 .../rest/domain/ScriptExecutionSummary.java     | 11 +--
 .../brooklyn/rest/domain/SensorSummary.java     |  7 +-
 .../rest/resources/AdjunctResource.java         | 48 ++++++-----
 .../rest/transform/AdjunctTransformer.java      |  4 +-
 .../rest/transform/CatalogTransformer.java      |  2 +-
 .../rest/transform/ConfigTransformer.java       |  2 +
 .../rest/transform/PolicyTransformer.java       |  2 +-
 .../rest/util/BrooklynRestResourceUtils.java    | 13 +--
 .../rest/testing/BrooklynRestResourceTest.java  |  2 +-
 26 files changed, 139 insertions(+), 156 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28dbb83e/core/src/main/java/org/apache/brooklyn/core/entity/EntityAdjuncts.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/EntityAdjuncts.java b/core/src/main/java/org/apache/brooklyn/core/entity/EntityAdjuncts.java
index fc1daf4..8c06384 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/EntityAdjuncts.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/EntityAdjuncts.java
@@ -23,13 +23,17 @@ import java.util.List;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.objs.EntityAdjunct;
+import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.api.sensor.Enricher;
+import org.apache.brooklyn.api.sensor.Feed;
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ComputeServiceIndicatorsFromChildrenAndMembers;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ComputeServiceState;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceNotUpLogic;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.guava.Maybe;
 
+import com.google.common.annotations.Beta;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 
@@ -66,5 +70,27 @@ public class EntityAdjuncts {
         if (SYSTEM_ENRICHER_UNIQUE_TAGS.contains(enr.getUniqueTag())) return true;
         return false;
     }
-    
+
+    @Beta
+    public static Lifecycle inferAdjunctStatus(EntityAdjunct a) {
+        if (a.isRunning()) return Lifecycle.RUNNING;
+        if (a.isDestroyed()) return Lifecycle.DESTROYED;
+        
+        // adjuncts don't currently support an "error" state; though that would be useful!
+        
+        if (a instanceof Policy) {
+            if (((Policy)a).isSuspended()) return Lifecycle.STOPPED;
+            return Lifecycle.CREATED;
+        }
+        if (a instanceof Feed) {
+            if (((Feed)a).isSuspended()) return Lifecycle.STOPPED;
+            if (((Feed)a).isActivated()) return Lifecycle.STARTING;
+            return Lifecycle.CREATED;
+        }
+
+        // Enricher doesn't support suspend so if not running or destroyed then
+        // it is just created
+        return Lifecycle.CREATED;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28dbb83e/core/src/main/java/org/apache/brooklyn/core/policy/Policies.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/policy/Policies.java b/core/src/main/java/org/apache/brooklyn/core/policy/Policies.java
index 4b32dfc..0af5c6a 100644
--- a/core/src/main/java/org/apache/brooklyn/core/policy/Policies.java
+++ b/core/src/main/java/org/apache/brooklyn/core/policy/Policies.java
@@ -18,94 +18,18 @@
  */
 package org.apache.brooklyn.core.policy;
 
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.objs.EntityAdjunct;
 import org.apache.brooklyn.api.policy.Policy;
-import org.apache.brooklyn.api.sensor.Feed;
-import org.apache.brooklyn.api.sensor.Sensor;
-import org.apache.brooklyn.api.sensor.SensorEvent;
-import org.apache.brooklyn.api.sensor.SensorEventListener;
+import org.apache.brooklyn.core.entity.EntityAdjuncts;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
-import com.google.common.annotations.Beta;
-
-import groovy.lang.Closure;
-
-@SuppressWarnings({"rawtypes","unchecked"})
+/** @deprecated since 0.13.0 use {@link EntityAdjuncts} */
+@Deprecated
 public class Policies {
 
-    private static final Logger LOG = LoggerFactory.getLogger(Policies.class);
-
-    /**
-     * @deprecated since 0.11.0; explicit groovy utilities/support will be deleted.
-     */
+    /** @deprecated since 0.13.0, use {@link EntityAdjuncts#inferAdjunctStatus(org.apache.brooklyn.api.objs.EntityAdjunct)} */
     @Deprecated
-    public static SensorEventListener listenerFromValueClosure(final Closure code) {
-        LOG.warn("Use of groovy.lang.Closure is deprecated in Policies.listenerFromValueClosure()");
-        return new SensorEventListener() {
-            @Override
-            public void onEvent(SensorEvent event) {
-                code.call(event.getValue());
-            }
-        };
-    }
-    
-    /**
-     * @deprecated since 0.11.0; explicit groovy utilities/support will be deleted.
-     */
-    @Deprecated
-    public static <T> Policy newSingleSensorValuePolicy(final Sensor<T> sensor, final Closure code) {
-        LOG.warn("Use of groovy.lang.Closure is deprecated in Policies.newSingleSensorValuePolicy()");
-        return new AbstractPolicy() {
-            @Override
-            public void setEntity(EntityLocal entity) {
-                super.setEntity(entity);
-                entity.subscriptions().subscribe(entity, sensor, listenerFromValueClosure(code));
-            }
-        };
-    }
-    
-    /**
-     * @deprecated since 0.11.0; explicit groovy utilities/support will be deleted.
-     */
-    @Deprecated
-    public static <S,T> Policy newSingleSensorValuePolicy(final Entity remoteEntity, final Sensor<T> remoteSensor, 
-            final Closure code) {
-        LOG.warn("Use of groovy.lang.Closure is deprecated in Policies.newSingleSensorValuePolicy()");
-        return new AbstractPolicy() {
-            @Override
-            public void setEntity(EntityLocal entity) {
-                super.setEntity(entity);
-                entity.subscriptions().subscribe(remoteEntity, remoteSensor, listenerFromValueClosure(code));
-            }
-        };
-    }
-
     public static Lifecycle getPolicyStatus(Policy p) {
-        return inferAdjunctStatus(p);
-    }
-    
-    @Beta
-    public static Lifecycle inferAdjunctStatus(EntityAdjunct a) {
-        if (a.isRunning()) return Lifecycle.RUNNING;
-        if (a.isDestroyed()) return Lifecycle.DESTROYED;
-        
-        // adjuncts don't currently support an "error" state; though that would be useful!
-        
-        if (a instanceof Policy) {
-            if (((Policy)a).isSuspended()) return Lifecycle.STOPPED;
-            return Lifecycle.CREATED;
-        }
-        if (a instanceof Feed) {
-            if (((Feed)a).isSuspended()) return Lifecycle.STOPPED;
-            if (((Feed)a).isActivated()) return Lifecycle.STARTING;
-            return Lifecycle.CREATED;
-        }
-        
-        return Lifecycle.STOPPED;
+        return EntityAdjuncts.inferAdjunctStatus(p);
     }
     
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28dbb83e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java
index 1886f63..da5c1bf 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java
@@ -54,18 +54,20 @@ public interface AdjunctApi {
             response = org.apache.brooklyn.rest.domain.AdjunctSummary.class,
             responseContainer = "List")
     @ApiResponses(value = {
-            @ApiResponse(code = 404, message = "Could not find application or entity")
+            @ApiResponse(code = 404, message = "Could not find application or entity"),
+            @ApiResponse(code = 400, message = "Type is not known adjunct kind")
     })
     public List<AdjunctSummary> list(
             @ApiParam(value = "Application ID or name", required = true)
             @PathParam("application") final String application,
             @ApiParam(value = "Entity ID or name", required = true)
             @PathParam("entity") final String entityToken,
-            @ApiParam(value = "Filter by adjunct type", required = false)
+            @ApiParam(value = "Filter by adjunct type (policy, enricher, feed)", required = false)
             @QueryParam("adjunctType") final String adjunctType);
 
+    // TODO support YAML ?
     @POST
-    @ApiOperation(value = "Add an adjunct (policy, enricher, or feed)", notes = "Returns a summary of the added adjunct")
+    @ApiOperation(value = "Create and add an adjunct (e.g. a policy, enricher, or feed) to this entity", notes = "Returns a summary of the added adjunct")
     @ApiResponses(value = {
             @ApiResponse(code = 404, message = "Could not find application or entity"),
             @ApiResponse(code = 400, message = "Type is not a suitable adjunct")
@@ -121,7 +123,8 @@ public interface AdjunctApi {
     @Path("/{adjunct}/start")
     @ApiOperation(value = "Start or resume an adjunct")
     @ApiResponses(value = {
-            @ApiResponse(code = 404, message = "Could not find application, entity or adjunct")
+            @ApiResponse(code = 404, message = "Could not find application, entity or adjunct"),
+            @ApiResponse(code = 400, message = "Adjunct does not support start/stop")
     })
     public Response start(
             @ApiParam(name = "application", value = "Application ID or name", required = true)
@@ -137,7 +140,8 @@ public interface AdjunctApi {
     @Path("/{adjunct}/stop")
     @ApiOperation(value = "Suspends an adjunct")
     @ApiResponses(value = {
-            @ApiResponse(code = 404, message = "Could not find application, entity or adjunct")
+            @ApiResponse(code = 404, message = "Could not find application, entity or adjunct"),
+            @ApiResponse(code = 400, message = "Adjunct does not support start/stop")
     })
     public Response stop(
             @ApiParam(name = "application", value = "Application ID or name", required = true)

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28dbb83e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyApi.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyApi.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyApi.java
index 95f41db..1bee2f8 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyApi.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyApi.java
@@ -36,7 +36,7 @@ import java.util.Map;
 @Api("Entity Policies")
 @Produces(MediaType.APPLICATION_JSON)
 @Consumes(MediaType.APPLICATION_JSON)
-/** @deprecated since 0.12.0 use AdjunctApi */
+/** @deprecated since 0.13.0 use AdjunctApi */
 @Deprecated
 public interface PolicyApi {
     

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28dbb83e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyConfigApi.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyConfigApi.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyConfigApi.java
index 8d061dd..f38d9d4 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyConfigApi.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyConfigApi.java
@@ -42,7 +42,7 @@ import io.swagger.annotations.ApiResponses;
 @Api("Entity Policy Config")
 @Produces(MediaType.APPLICATION_JSON)
 @Consumes(MediaType.APPLICATION_JSON)
-/** @deprecated since 0.12.0 use AdjunctApi */
+/** @deprecated since 0.13.0 use AdjunctApi */
 @Deprecated
 public interface PolicyConfigApi {
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28dbb83e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctSummary.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctSummary.java
index ca80644..97ce1b2 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctSummary.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctSummary.java
@@ -58,8 +58,6 @@ public class AdjunctSummary implements HasName, Serializable, Identifiable {
         highlights = a.getHighlights();
     }
         
-    /** @deprecated since 0.12.0 only for legacy type-specific summary classes */
-    @Deprecated   
     protected AdjunctSummary(
             String id,
             String name,

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28dbb83e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ApplicationSpec.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ApplicationSpec.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ApplicationSpec.java
index 52f7efd..172f66f 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ApplicationSpec.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ApplicationSpec.java
@@ -27,8 +27,9 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
 import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 
@@ -85,12 +86,13 @@ public class ApplicationSpec implements HasName, Serializable {
     }
 
     private final String name;
-    @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+    @JsonInclude(Include.NON_NULL)
     private final String type;
-    @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+    @JsonInclude(Include.NON_NULL)
     private final Set<EntitySpec> entities;
+    @JsonInclude(Include.NON_NULL)
     private final Set<String> locations;
-    @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY)
+    @JsonInclude(Include.NON_EMPTY)
     private final Map<String, String> config;
 
   public ApplicationSpec(
@@ -106,7 +108,7 @@ public class ApplicationSpec implements HasName, Serializable {
       } else {
           this.entities = (entities.isEmpty() && type!=null) ? null : ImmutableSet.copyOf(entities);
       }
-      this.locations = ImmutableSet.copyOf(checkNotNull(locations, "locations must be provided for an application spec"));
+      this.locations = locations == null ? Collections.emptySet() : ImmutableSet.copyOf(locations);
       this.config = config == null ? Collections.<String, String>emptyMap() : ImmutableMap.<String, String>copyOf(config);
       if (this.entities!=null && this.type!=null) throw new IllegalStateException("cannot supply both type and entities for an application spec");
       // valid for both to be null, e.g. for an anonymous type

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28dbb83e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEnricherSummary.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEnricherSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEnricherSummary.java
index c655515..56ff0ff 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEnricherSummary.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEnricherSummary.java
@@ -23,11 +23,13 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 
+import org.apache.brooklyn.rest.api.TypeApi;
+
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.google.common.collect.ImmutableSet;
 
-/** @deprecated since 0.12.0 new TypeApi returns TypeSummary */
+/** @deprecated since 0.13.0 new {@link TypeApi} returns {@link TypeSummary} */
 @Deprecated
 public class CatalogEnricherSummary extends CatalogItemSummary {
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28dbb83e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEntitySummary.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEntitySummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEntitySummary.java
index 7dbc1be..6df6b38 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEntitySummary.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEntitySummary.java
@@ -23,11 +23,13 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 
+import org.apache.brooklyn.rest.api.TypeApi;
+
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 
-/** @deprecated since 0.12.0 new TypeApi returns TypeSummary */
+/** @deprecated since 0.13.0 new {@link TypeApi} returns {@link TypeSummary} */
 @Deprecated
 public class CatalogEntitySummary extends CatalogItemSummary {
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28dbb83e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogItemSummary.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogItemSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogItemSummary.java
index cd85c13..19a1749 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogItemSummary.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogItemSummary.java
@@ -26,6 +26,8 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 
+import org.apache.brooklyn.rest.api.TypeApi;
+
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
@@ -36,7 +38,7 @@ import com.google.common.collect.ImmutableMap;
  * see also, subclasses */
 @JsonIgnoreProperties(ignoreUnknown = true)
 // ignore unknown, ie properties from subclasses (entity)
-/** @deprecated since 0.12.0 new TypeApi returns TypeSummary */
+/** @deprecated since 0.13.0 new {@link TypeApi} returns {@link TypeSummary} */
 @Deprecated
 public class CatalogItemSummary implements HasId, HasName, Serializable {
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28dbb83e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogLocationSummary.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogLocationSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogLocationSummary.java
index 5fb1a4b..1b76948 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogLocationSummary.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogLocationSummary.java
@@ -23,10 +23,12 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 
+import org.apache.brooklyn.rest.api.TypeApi;
+
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.collect.ImmutableSet;
 
-/** @deprecated since 0.12.0 new TypeApi returns TypeSummary */
+/** @deprecated since 0.13.0 new {@link TypeApi} returns {@link TypeSummary} */
 @Deprecated
 public class CatalogLocationSummary extends CatalogItemSummary {
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28dbb83e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogPolicySummary.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogPolicySummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogPolicySummary.java
index ad67786..dafa6bb 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogPolicySummary.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogPolicySummary.java
@@ -23,11 +23,13 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 
+import org.apache.brooklyn.rest.api.TypeApi;
+
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.google.common.collect.ImmutableSet;
 
-/** @deprecated since 0.12.0 new TypeApi returns TypeSummary */
+/** @deprecated since 0.13.0 new {@link TypeApi} returns {@link TypeSummary} */
 @Deprecated
 public class CatalogPolicySummary extends CatalogItemSummary {
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28dbb83e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EffectorSummary.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EffectorSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EffectorSummary.java
index 3e09c73..7f38438 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EffectorSummary.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EffectorSummary.java
@@ -23,8 +23,9 @@ import java.net.URI;
 import java.util.Map;
 import java.util.Set;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
 import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
 import com.google.common.collect.ImmutableMap;
@@ -38,7 +39,7 @@ public class EffectorSummary implements HasName, Serializable {
 
         private final String name;
         private final String type;
-        @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+        @JsonInclude(Include.NON_NULL)
         private final String description;
         private final T defaultValue;
         private final boolean shouldSanitize;
@@ -110,9 +111,9 @@ public class EffectorSummary implements HasName, Serializable {
     private final String name;
     private final String returnType;
     private final Set<ParameterSummary<?>> parameters;
-    @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+    @JsonInclude(Include.NON_EMPTY)
     private final String description;
-    @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+    @JsonInclude(Include.NON_EMPTY)
     private final Map<String, URI> links;
 
     public EffectorSummary(

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28dbb83e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntityDetail.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntityDetail.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntityDetail.java
index 567c40b..f49bb81 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntityDetail.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntityDetail.java
@@ -18,23 +18,25 @@
  */
 package org.apache.brooklyn.rest.domain;
 
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-import com.google.common.collect.ImmutableList;
-import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
-
 import java.net.URI;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.collect.ImmutableList;
+
 public class EntityDetail extends EntitySummary {
 
     private static final long serialVersionUID = 100490507982229165L;
 
     private final String applicationId;
     private final String parentId;
-    @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY)
+    @JsonInclude(Include.NON_EMPTY)
     private final List<EntitySummary> children;
     private final List<String> groupIds;
     private final List<Map<String, String>> members;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28dbb83e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntitySummary.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntitySummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntitySummary.java
index e0a585a..ae123ef 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntitySummary.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntitySummary.java
@@ -18,15 +18,16 @@
  */
 package org.apache.brooklyn.rest.domain;
 
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-import com.google.common.collect.ImmutableMap;
-
 import java.io.Serializable;
 import java.net.URI;
 import java.util.Map;
 import java.util.Objects;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.collect.ImmutableMap;
+
 public class EntitySummary implements HasId, HasName, Serializable {
 
     private static final long serialVersionUID = 100490507982229165L;
@@ -34,7 +35,7 @@ public class EntitySummary implements HasId, HasName, Serializable {
     private final String id;
     private final String name;
     private final String type;
-    @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+    @JsonInclude(Include.NON_NULL)
     private final String catalogItemId;
     private final Map<String, URI> links;
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28dbb83e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicyConfigSummary.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicyConfigSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicyConfigSummary.java
index 3386045..4098ee1 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicyConfigSummary.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicyConfigSummary.java
@@ -26,7 +26,7 @@ import org.apache.brooklyn.config.ConfigKey;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 
-/** @deprecated since 0.13.0 no different to ConfigSummary, use that */
+/** @deprecated since 0.13.0 no different to {@link ConfigSummary}, use that */
 @Deprecated
 public class PolicyConfigSummary extends ConfigSummary {
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28dbb83e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicySummary.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicySummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicySummary.java
index da4a86a..1d0e930 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicySummary.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicySummary.java
@@ -26,7 +26,7 @@ import org.apache.brooklyn.api.objs.HighlightTuple;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 
-/** @deprecated since 0.12.0 use {@link AdjunctSummary}; this class is identical */
+/** @deprecated since 0.13.0 use {@link AdjunctSummary}; this class is identical */
 @Deprecated
 public class PolicySummary extends AdjunctSummary {
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28dbb83e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ScriptExecutionSummary.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ScriptExecutionSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ScriptExecutionSummary.java
index c84573c..3266018 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ScriptExecutionSummary.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ScriptExecutionSummary.java
@@ -21,20 +21,21 @@ package org.apache.brooklyn.rest.domain;
 import java.io.Serializable;
 import java.util.Objects;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
 import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 
 public class ScriptExecutionSummary implements Serializable {
 
     private static final long serialVersionUID = -7707936602991185960L;
 
-    @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+    @JsonInclude(Include.NON_NULL)
     private final Object result;
-    @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY)
+    @JsonInclude(Include.NON_EMPTY)
     private final String problem;
-    @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY)
+    @JsonInclude(Include.NON_EMPTY)
     private final String stdout;
-    @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY)
+    @JsonInclude(Include.NON_EMPTY)
     private final String stderr;
 
     public ScriptExecutionSummary(

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28dbb83e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/SensorSummary.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/SensorSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/SensorSummary.java
index 11a4d2f..9442f33 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/SensorSummary.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/SensorSummary.java
@@ -23,8 +23,9 @@ import java.net.URI;
 import java.util.Map;
 import java.util.Objects;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
 import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.google.common.collect.ImmutableMap;
 
 public class SensorSummary implements HasName, Serializable {
@@ -33,9 +34,9 @@ public class SensorSummary implements HasName, Serializable {
 
     private final String name;
     private final String type;
-    @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+    @JsonInclude(Include.NON_NULL)
     private final String description;
-    @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+    @JsonInclude(Include.NON_NULL)
     private final Map<String, URI> links;
 
     public SensorSummary(

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28dbb83e/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java
index 08f3698..6090e6d 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java
@@ -51,7 +51,6 @@ import org.apache.brooklyn.rest.filter.HaHotStateRequired;
 import org.apache.brooklyn.rest.transform.AdjunctTransformer;
 import org.apache.brooklyn.rest.transform.ConfigTransformer;
 import org.apache.brooklyn.rest.transform.EntityTransformer;
-import org.apache.brooklyn.rest.util.BrooklynRestResourceUtils;
 import org.apache.brooklyn.rest.util.WebResourceUtils;
 import org.apache.brooklyn.util.core.ClassLoaderUtils;
 import org.apache.brooklyn.util.core.flags.TypeCoercions;
@@ -121,9 +120,11 @@ public class AdjunctResource extends AbstractBrooklynRestResource implements Adj
         } else {
             try {
                 Class<?> type = new ClassLoaderUtils(this, mgmt()).loadClass(adjunctTypeName);
-                if (Policy.class.isAssignableFrom(type)) spec = PolicySpec.create((Class) type);
-                else if (Enricher.class.isAssignableFrom(type)) spec = EnricherSpec.create((Class) type);
-                else if (Feed.class.isAssignableFrom(type)) {
+                if (Policy.class.isAssignableFrom(type)) {
+                    spec = PolicySpec.create((Class) type);
+                } else if (Enricher.class.isAssignableFrom(type)) {
+                    spec = EnricherSpec.create((Class) type);
+                } else if (Feed.class.isAssignableFrom(type)) {
                     // TODO add FeedSpec ?  would be needed even if using the type registry
                     throw WebResourceUtils.badRequest("Creation of feeds from java type (%s) not supported", adjunctTypeName);
                 } else {
@@ -141,9 +142,11 @@ public class AdjunctResource extends AbstractBrooklynRestResource implements Adj
         spec.configure(config);
 
         EntityAdjunct instance;
-        if (spec instanceof PolicySpec) instance = entity.policies().add((PolicySpec)spec);
-        else if (spec instanceof EnricherSpec) instance = entity.enrichers().add((EnricherSpec)spec);
-        else {
+        if (spec instanceof PolicySpec) {
+            instance = entity.policies().add((PolicySpec)spec);
+        } else if (spec instanceof EnricherSpec) {
+            instance = entity.enrichers().add((EnricherSpec)spec);
+        } else {
             // TODO add FeedSpec
             throw WebResourceUtils.badRequest("Unexpected spec type %s", spec);
         }
@@ -169,9 +172,13 @@ public class AdjunctResource extends AbstractBrooklynRestResource implements Adj
     @Override
     public Response start(String application, String entityToken, String adjunctId) {
         EntityAdjunct adjunct = brooklyn().getAdjunct(application, entityToken, adjunctId);
-        if (adjunct instanceof Policy) ((Policy)adjunct).resume();
-        else if (adjunct instanceof Feed) ((Feed)adjunct).resume();
-        else throw WebResourceUtils.badRequest("%s does not support start/resume", adjunct);
+        if (adjunct instanceof Policy) {
+            ((Policy)adjunct).resume();
+        } else if (adjunct instanceof Feed) {
+            ((Feed)adjunct).resume();
+        } else {
+            throw WebResourceUtils.badRequest("%s does not support start/resume", adjunct);
+        }
         
         return Response.status(Response.Status.NO_CONTENT).build();
     }
@@ -179,9 +186,13 @@ public class AdjunctResource extends AbstractBrooklynRestResource implements Adj
     @Override
     public Response stop(String application, String entityToken, String adjunctId) {
         EntityAdjunct adjunct = brooklyn().getAdjunct(application, entityToken, adjunctId);
-        if (adjunct instanceof Policy) ((Policy)adjunct).suspend();
-        else if (adjunct instanceof Feed) ((Feed)adjunct).suspend();
-        else throw WebResourceUtils.badRequest("%s does not support suspend", adjunct);
+        if (adjunct instanceof Policy) {
+            ((Policy)adjunct).suspend();
+        } else if (adjunct instanceof Feed) {
+            ((Feed)adjunct).suspend();
+        } else {
+            throw WebResourceUtils.badRequest("%s does not support suspend", adjunct);
+        }
         
         return Response.status(Response.Status.NO_CONTENT).build();
     }
@@ -200,6 +211,7 @@ public class AdjunctResource extends AbstractBrooklynRestResource implements Adj
             ((Feed)adjunct).suspend();
             ((EntityInternal)entity).feeds().remove((Feed) adjunct);
         } else {
+            // shouldn't come here
             throw WebResourceUtils.badRequest("Unexpected adjunct type %s", adjunct);
         }
         
@@ -233,7 +245,8 @@ public class AdjunctResource extends AbstractBrooklynRestResource implements Adj
     public String getConfig(String application, String entityToken, String adjunctToken, String configKeyName) {
         EntityAdjunct adjunct = brooklyn().getAdjunct(application, entityToken, adjunctToken);
         Set<ConfigKey<?>> cki = adjunct.config().findKeysDeclared(ConfigPredicates.nameSatisfies(Predicates.equalTo(configKeyName)));
-        if (cki.isEmpty()) throw WebResourceUtils.notFound("Cannot find config key '%s' in policy '%s' of entity '%s'", configKeyName, adjunctToken, entityToken);
+        // TODO try deprecated names?
+        if (cki.isEmpty()) throw WebResourceUtils.notFound("Cannot find config key '%s' in adjunct '%s' of entity '%s'", configKeyName, adjunctToken, entityToken);
 
         return brooklyn().getStringValueForDisplay(adjunct.config().get(cki.iterator().next()));
     }
@@ -249,7 +262,8 @@ public class AdjunctResource extends AbstractBrooklynRestResource implements Adj
 
         EntityAdjunct adjunct = brooklyn().getAdjunct(entity, adjunctToken);
         Set<ConfigKey<?>> cki = adjunct.config().findKeysDeclared(ConfigPredicates.nameSatisfies(Predicates.equalTo(configKeyName)));
-        if (cki.isEmpty()) throw WebResourceUtils.notFound("Cannot find config key '%s' in policy '%s' of entity '%s'", configKeyName, adjunctToken, entityToken);
+        // TODO try deprecated names?
+        if (cki.isEmpty()) throw WebResourceUtils.notFound("Cannot find config key '%s' in adjunct '%s' of entity '%s'", configKeyName, adjunctToken, entityToken);
         ConfigKey<?> ck = cki.iterator().next();
         
         adjunct.config().set((ConfigKey) cki, TypeCoercions.coerce(value, ck.getTypeToken()));
@@ -257,8 +271,4 @@ public class AdjunctResource extends AbstractBrooklynRestResource implements Adj
         return Response.status(Response.Status.OK).build();
     }
 
-    public static String getStringValueForDisplay(BrooklynRestResourceUtils utils, EntityAdjunct policy, Object value) {
-        return utils.getStringValueForDisplay(value);
-    }
-    
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28dbb83e/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java
index a00cb6e..f6598ec 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java
@@ -30,7 +30,7 @@ import org.apache.brooklyn.api.objs.EntityAdjunct;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.api.sensor.Feed;
 import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.policy.Policies;
+import org.apache.brooklyn.core.entity.EntityAdjuncts;
 import org.apache.brooklyn.rest.api.AdjunctApi;
 import org.apache.brooklyn.rest.domain.AdjunctDetail;
 import org.apache.brooklyn.rest.domain.AdjunctSummary;
@@ -86,7 +86,7 @@ public class AdjunctTransformer {
     }
 
     public static Status inferStatus(EntityAdjunct adjunct) {
-        return ApplicationTransformer.statusFromLifecycle( Policies.inferAdjunctStatus(adjunct) );
+        return ApplicationTransformer.statusFromLifecycle( EntityAdjuncts.inferAdjunctStatus(adjunct) );
     }
 
     public static URI adjunctUri(Entity entity, EntityAdjunct adjunct, UriBuilder ub) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28dbb83e/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/CatalogTransformer.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/CatalogTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/CatalogTransformer.java
index 6eeaeb8..8bff9f1 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/CatalogTransformer.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/CatalogTransformer.java
@@ -71,7 +71,7 @@ import org.slf4j.LoggerFactory;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
 
-/** @deprecated since 0.13.0 use RegisteredType methods */
+/** @deprecated since 0.13.0 use {@link RegisteredType} methods in {@link TypeTransformer} */
 @Deprecated
 public class CatalogTransformer {
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28dbb83e/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/ConfigTransformer.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/ConfigTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/ConfigTransformer.java
index 22d4299..314ce3c 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/ConfigTransformer.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/ConfigTransformer.java
@@ -79,6 +79,8 @@ public class ConfigTransformer {
         return this;
     }
     
+    /** configures this transformer to be able to include links, and which types of links to include;
+     * note {@link #on(Entity)} or {@link #on(Entity, EntityAdjunct)} is needed to construct most links. */
     public ConfigTransformer includeLinks(UriBuilder ub, boolean includeContextLinks, boolean includeActionLinks) {
         this.ub = ub;
         this.includeContextLinks = includeContextLinks;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28dbb83e/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/PolicyTransformer.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/PolicyTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/PolicyTransformer.java
index 2cb5dc7..577e4f1 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/PolicyTransformer.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/PolicyTransformer.java
@@ -43,7 +43,7 @@ import static org.apache.brooklyn.rest.util.WebResourceUtils.serviceUriBuilder;
 
 /**
  * Converts from Brooklyn entities to restful API summary objects
- * @deprecated since 0.12.0 use {@link AdjunctTransformer} and {@link AdjunctSummary} 
+ * @deprecated since 0.13.0 use {@link AdjunctTransformer} and {@link AdjunctSummary} 
  */
 @Deprecated
 public class PolicyTransformer {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28dbb83e/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java
index 9b0a3d4..d382205 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java
@@ -155,18 +155,19 @@ public class BrooklynRestResourceUtils {
         for (Policy p: entity.policies()) {
             if (adjunct.equals(p.getId())) return p;
         }
-        for (Policy p: entity.policies()) {
-            if (adjunct.equals(p.getDisplayName())) return p;
-        }
         for (Enricher p: entity.enrichers()) {
             if (adjunct.equals(p.getId())) return p;
         }
-        for (Enricher p: entity.enrichers()) {
-            if (adjunct.equals(p.getDisplayName())) return p;
-        }
         for (Feed p: ((EntityInternal)entity).feeds()) {
             if (adjunct.equals(p.getId())) return p;
         }
+        
+        for (Policy p: entity.policies()) {
+            if (adjunct.equals(p.getDisplayName())) return p;
+        }
+        for (Enricher p: entity.enrichers()) {
+            if (adjunct.equals(p.getDisplayName())) return p;
+        }
         for (Feed p: ((EntityInternal)entity).feeds()) {
             if (adjunct.equals(p.getDisplayName())) return p;
         }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/28dbb83e/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/testing/BrooklynRestResourceTest.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/testing/BrooklynRestResourceTest.java b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/testing/BrooklynRestResourceTest.java
index 30d6697..183f3de 100644
--- a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/testing/BrooklynRestResourceTest.java
+++ b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/testing/BrooklynRestResourceTest.java
@@ -152,7 +152,7 @@ public abstract class BrooklynRestResourceTest extends BrooklynRestApiTest {
                 .run();
         
         if (!started) {
-            log.warn("Did not start application "+applicationRef+":");
+            log.warn("Did not start application "+applicationRef+" ("+getApplicationStatus(applicationRef)+"):");
             Collection<Application> apps = getManagementContext().getApplications();
             for (Application app: apps)
                 Entities.dumpInfo(app);


[08/35] brooklyn-server git commit: use new public class MaybeSupplier for Maybe instances backed by supplier

Posted by he...@apache.org.
use new public class MaybeSupplier for Maybe instances backed by supplier

so callers can access the supplier in cases where it might also provide other info such as Identifiable


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

Branch: refs/heads/master
Commit: 784bc960f926823be374fa05d3df3fd542ee857a
Parents: 9d2faf0
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Sep 11 18:00:11 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Sep 15 10:29:08 2017 +0100

----------------------------------------------------------------------
 .../org/apache/brooklyn/util/guava/Maybe.java   | 43 ++++++++++++--------
 1 file changed, 25 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/784bc960/utils/common/src/main/java/org/apache/brooklyn/util/guava/Maybe.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/guava/Maybe.java b/utils/common/src/main/java/org/apache/brooklyn/util/guava/Maybe.java
index b115acb..a68b400 100644
--- a/utils/common/src/main/java/org/apache/brooklyn/util/guava/Maybe.java
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/guava/Maybe.java
@@ -183,29 +183,40 @@ public abstract class Maybe<T> implements Serializable, Supplier<T> {
             public T get() {
                 return value.get();
             }
-            @Override
-            public boolean isNull() {
-                // should always be false as per Optional contract
-                return get()==null;
-            }
         };
         return absent();
     }
     
-    public static <T> Maybe<T> of(final Supplier<T> value) {
+    @SuppressWarnings("unused")
+    private static <T> Maybe<T> ofOldKeptForDeserializationOfAnonymousInnerClass(final Supplier<T> value) {
         return new AbstractPresent<T>() {
             private static final long serialVersionUID = -5735268814211401356L;
             @Override
             public T get() {
                 return value.get();
             }
-            @Override
-            public boolean isNull() {
-                return get()==null;
-            }
         };
     }
     
+    public static <T> Maybe<T> of(final Supplier<T> value) {
+        return new MaybeSupplier<T>(value);
+    }
+    
+    public static class MaybeSupplier<T> extends AbstractPresent<T> {
+        private static final long serialVersionUID = -823731500051341455L;
+        private Supplier<T> supplier;
+        public MaybeSupplier(Supplier<T> value) {
+            this.supplier = value;
+        }
+        @Override
+        public T get() {
+            return supplier.get();
+        }
+        public Supplier<T> getSupplier() {
+            return supplier;
+        }
+    }
+    
     /** returns a Maybe containing the next element in the iterator, or absent if none */ 
     public static <T> Maybe<T> next(Iterator<T> iterator) {
         return iterator.hasNext() ? Maybe.of(iterator.next()) : Maybe.<T>absent();
@@ -279,10 +290,6 @@ public abstract class Maybe<T> implements Serializable, Supplier<T> {
             public V get() {
                 return f.apply(Maybe.this.get());
             }
-            @Override
-            public boolean isNull() {
-                return get()==null;
-            }
         };
         return absent();
     }
@@ -392,6 +399,10 @@ public abstract class Maybe<T> implements Serializable, Supplier<T> {
         protected AbstractPresent() {
         }
         @Override
+        public boolean isNull() {
+            return get()==null;
+        }
+        @Override
         public boolean isPresent() {
             return true;
         }
@@ -407,10 +418,6 @@ public abstract class Maybe<T> implements Serializable, Supplier<T> {
         public T get() {
             return value;
         }
-        @Override
-        public boolean isNull() {
-            return value==null;
-        }
     }
 
     public static class SoftlyPresent<T> extends Maybe<T> {


[13/35] brooklyn-server git commit: add support for same-thread execution

Posted by he...@apache.org.
add support for same-thread execution

submitting and blocking is unnecessary overhead in many places


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

Branch: refs/heads/master
Commit: 8983bf2cdae3e1b3bbc00d12cfb4baf09fb732fe
Parents: 4c2468d
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Sep 11 23:15:50 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Sep 15 10:29:09 2017 +0100

----------------------------------------------------------------------
 .../brooklyn/api/mgmt/ExecutionContext.java     |  24 ++-
 .../util/core/task/BasicExecutionContext.java   | 156 +++++++++++++++----
 .../util/core/task/BasicExecutionManager.java   |   8 +-
 .../brooklyn/util/core/task/BasicTask.java      |   9 +-
 .../brooklyn/util/core/task/ValueResolver.java  |   8 +-
 .../brooklyn/core/entity/EntityConfigTest.java  |  12 ++
 .../internal/EntityExecutionManagerTest.java    |   1 -
 7 files changed, 174 insertions(+), 44 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8983bf2c/api/src/main/java/org/apache/brooklyn/api/mgmt/ExecutionContext.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/mgmt/ExecutionContext.java b/api/src/main/java/org/apache/brooklyn/api/mgmt/ExecutionContext.java
index 344907a..142e664 100644
--- a/api/src/main/java/org/apache/brooklyn/api/mgmt/ExecutionContext.java
+++ b/api/src/main/java/org/apache/brooklyn/api/mgmt/ExecutionContext.java
@@ -27,6 +27,7 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.util.guava.Maybe;
 
 import com.google.common.annotations.Beta;
+import com.google.common.base.Supplier;
 
 /**
  * This is a Brooklyn extension to the Java {@link Executor}.
@@ -71,14 +72,29 @@ public interface ExecutionContext extends Executor {
      * Gets the value promptly, or returns {@link Maybe#absent()} if the value is not yet available.
      * It may throw an error if it cannot be determined whether a value is available immediately or not.
      * <p>
-     * Implementations will typically attempt to execute in the current thread, with appropriate
-     * tricks to make it look like it is in a sub-thread, and will attempt to be non-blocking but
-     * if needed they may block.
+     * Implementations will typically act like {@link #get(TaskAdaptable)} with additional
+     * tricks to attempt to be non-blocking, such as recognizing some "immediate" markers.  
      * <p>
-     * Supports {@link Callable} and {@link Runnable} and some {@link Task} targets to be evaluated with "immediate" semantics.
+     * Also supports {@link Callable}, {@link Runnable}, and {@link Supplier} argument types.
      */
     // TODO reference ImmediateSupplier when that class is moved to utils project
     @Beta
     <T> Maybe<T> getImmediately(Object callableOrSupplierOrTask);
 
+    /**
+     * Efficient shortcut for {@link #submit(TaskAdaptable)} followed by an immediate {@link Task#get()}.
+     * <p>
+     * Implementations will typically attempt to execute in the current thread, with appropriate
+     * configuration to make it look like it is in a sub-thread, 
+     * ie registering this as a task and allowing
+     * context methods on tasks to see the given sub-task.
+     * <p>
+     * If the argument has already been submitted it simply blocks on it.
+     * 
+     * @param task
+     * @return result of the task execution
+     */
+    @Beta
+    <T> T get(TaskAdaptable<T> task);
+    
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8983bf2c/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
index e0dd8b0..8166dc0 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
@@ -26,8 +26,12 @@ import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.mgmt.ExecutionContext;
@@ -42,7 +46,10 @@ import org.apache.brooklyn.core.mgmt.BrooklynTaskTags.WrappedEntity;
 import org.apache.brooklyn.core.mgmt.entitlement.Entitlements;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.task.ImmediateSupplier.ImmediateUnsupportedException;
+import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.time.CountdownTimer;
+import org.apache.brooklyn.util.time.Duration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -100,6 +107,106 @@ public class BasicExecutionContext extends AbstractExecutionContext {
     @Override
     public Set<Task<?>> getTasks() { return executionManager.getTasksWithAllTags(tags); }
 
+    @Override
+    public <T> T get(TaskAdaptable<T> task) {
+        final TaskInternal<T> t = (TaskInternal<T>) task.asTask();
+        
+        if (t.isQueuedOrSubmitted()) {
+            if (t.isDone()) {
+                return t.getUnchecked();
+            } else {
+                throw new ImmediateUnsupportedException("Task is in progress and incomplete: "+t);
+            }
+        }
+
+        return runInSameThread(t, new Callable<Maybe<T>>() {
+            public Maybe<T> call() {
+                try {
+                    return Maybe.of(t.getJob().call());
+                } catch (Exception e) {
+                    Exceptions.propagateIfFatal(e);
+                    return Maybe.absent(e);
+                }
+            }
+        }).get();
+    }
+    
+    private static class SimpleFuture<T> implements Future<T> {
+        boolean cancelled = false;
+        boolean done = false;
+        Maybe<T> result;
+        
+        public synchronized Maybe<T> set(Maybe<T> result) {
+            this.result = result;
+            done = true;
+            notifyAll();
+            return result;
+        }
+
+        @Override
+        public boolean cancel(boolean mayInterruptIfRunning) {
+            cancelled = true;
+            return true;
+        }
+
+        @Override
+        public boolean isCancelled() {
+            return cancelled;
+        }
+
+        @Override
+        public boolean isDone() {
+            return done;
+        }
+
+        @Override
+        public T get() throws InterruptedException, ExecutionException {
+            return result.get();
+        }
+
+        @Override
+        public synchronized T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+            if (isDone()) return get();
+            CountdownTimer time = CountdownTimer.newInstanceStarted( Duration.of(timeout, unit) );
+            while (!time.isExpired()) {
+                wait(time.getDurationRemaining().lowerBound(Duration.ONE_MILLISECOND).toMilliseconds());
+                if (isDone()) return get();
+            }
+            throw new TimeoutException();
+        }
+    }
+    
+    private <T> Maybe<T> runInSameThread(final Task<T> task, Callable<Maybe<T>> job) {
+        ((TaskInternal<T>)task).getMutableTags().addAll(tags);
+        
+        Task<?> previousTask = BasicExecutionManager.getPerThreadCurrentTask().get();
+        BasicExecutionContext oldExecutionContext = getCurrentExecutionContext();
+        registerPerThreadExecutionContext();
+        ((BasicExecutionManager)executionManager).beforeSubmitInSameThreadTask(null, task);
+
+        SimpleFuture<T> future = new SimpleFuture<>();
+        try {
+            ((BasicExecutionManager)executionManager).afterSubmitRecordFuture(task, future);
+            ((BasicExecutionManager)executionManager).beforeStartInSameThreadTask(null, task);
+
+            // TODO this does not apply the same context-switching logic as submit
+            
+            return future.set(job.call());
+            
+        } catch (Exception e) {
+            future.set(Maybe.absent(e));
+            throw Exceptions.propagate(e);
+            
+        } finally {
+            try {
+                ((BasicExecutionManager)executionManager).afterEndInSameThreadTask(null, task);
+            } finally {
+                BasicExecutionManager.getPerThreadCurrentTask().set(previousTask);
+                perThreadExecutionContext.set(oldExecutionContext);
+            }
+        }
+    }
+    
     /** performs execution without spawning a new task thread, though it does temporarily set a fake task for the purpose of getting context;
      * currently supports {@link Supplier}, {@link Callable}, {@link Runnable}, or {@link Task} instances; 
      * with tasks if it is submitted or in progress,
@@ -110,9 +217,9 @@ public class BasicExecutionContext extends AbstractExecutionContext {
     @SuppressWarnings("unchecked")
     @Override
     public <T> Maybe<T> getImmediately(Object callableOrSupplier) {
-        BasicTask<?> fakeTaskForContext;
+        BasicTask<T> fakeTaskForContext;
         if (callableOrSupplier instanceof BasicTask) {
-            fakeTaskForContext = (BasicTask<?>)callableOrSupplier;
+            fakeTaskForContext = (BasicTask<T>)callableOrSupplier;
             if (fakeTaskForContext.isQueuedOrSubmitted()) {
                 if (fakeTaskForContext.isDone()) {
                     return Maybe.of((T)fakeTaskForContext.getUnchecked());
@@ -122,41 +229,26 @@ public class BasicExecutionContext extends AbstractExecutionContext {
             }
             callableOrSupplier = fakeTaskForContext.getJob();
         } else {
-            fakeTaskForContext = new BasicTask<Object>(MutableMap.of("displayName", "immediate evaluation"));
+            fakeTaskForContext = new BasicTask<T>(MutableMap.of("displayName", "immediate evaluation"));
         }
-        fakeTaskForContext.tags.addAll(tags);
+        final ImmediateSupplier<T> job = callableOrSupplier instanceof ImmediateSupplier ? (ImmediateSupplier<T>) callableOrSupplier 
+            : InterruptingImmediateSupplier.<T>of(callableOrSupplier);
         fakeTaskForContext.tags.add(BrooklynTaskTags.IMMEDIATE_TASK_TAG);
         fakeTaskForContext.tags.add(BrooklynTaskTags.TRANSIENT_TASK_TAG);
-        
-        Task<?> previousTask = BasicExecutionManager.getPerThreadCurrentTask().get();
-        BasicExecutionContext oldExecutionContext = getCurrentExecutionContext();
-        registerPerThreadExecutionContext();
-        ((BasicExecutionManager)executionManager).beforeSubmitInSameThreadTask(null, fakeTaskForContext);
 
-        try {
-            ((BasicExecutionManager)executionManager).beforeStartInSameThreadTask(null, fakeTaskForContext);
-            fakeTaskForContext.cancel();
-            
-            if (!(callableOrSupplier instanceof ImmediateSupplier)) {
-                callableOrSupplier = InterruptingImmediateSupplier.of(callableOrSupplier);
-            }
-            boolean wasAlreadyInterrupted = Thread.interrupted();
-            try {
-                return ((ImmediateSupplier<T>)callableOrSupplier).getImmediately();
-            } finally {
-                if (wasAlreadyInterrupted) {
-                    Thread.currentThread().interrupt();
+        return runInSameThread(fakeTaskForContext, new Callable<Maybe<T>>() {
+            public Maybe<T> call() {
+                fakeTaskForContext.cancel();
+                
+                boolean wasAlreadyInterrupted = Thread.interrupted();
+                try {
+                    return job.getImmediately();
+                } finally {
+                    if (wasAlreadyInterrupted) {
+                        Thread.currentThread().interrupt();
+                    }
                 }
-            }
- 
-        } finally {
-            try {
-                ((BasicExecutionManager)executionManager).afterEndInSameThreadTask(null, fakeTaskForContext);
-            } finally {
-                BasicExecutionManager.getPerThreadCurrentTask().set(previousTask);
-                perThreadExecutionContext.set(oldExecutionContext);
-            }
-        }
+            } });
     }
     
     @SuppressWarnings({ "unchecked", "rawtypes" })

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8983bf2c/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
index afc8c99..22d5b23 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
@@ -703,6 +703,12 @@ public class BasicExecutionManager implements ExecutionManager {
         } else {
             future = runner.submit(job);
         }
+        afterSubmitRecordFuture(task, future);
+        
+        return task;
+    }
+
+    protected <T> void afterSubmitRecordFuture(final Task<T> task, Future<T> future) {
         // SubmissionCallable (above) invokes the listeners on completion;
         // this future allows a caller to add custom listeners
         // (it does not notify the listeners; that's our job);
@@ -714,8 +720,6 @@ public class BasicExecutionManager implements ExecutionManager {
         
         // finally expose the future to callers
         ((TaskInternal<T>)task).initInternalFuture(listenableFuture);
-        
-        return task;
     }
     
     protected void beforeSubmitScheduledTaskAllIterations(Map<?,?> flags, Task<?> task) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8983bf2c/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
index f1a066f..f908ad4 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
@@ -412,17 +412,20 @@ public class BasicTask<T> implements TaskInternal<T> {
         blockUntilStarted(null);
     }
 
-    // TODO: This should log a message if timeout is null and the method blocks for an unreasonably long time -
-    // it probably means someone called .get() and forgot to submit the task.
     @Override
     public synchronized boolean blockUntilStarted(Duration timeout) {
         Long endTime = timeout==null ? null : System.currentTimeMillis() + timeout.toMillisecondsRoundingUp();
+        int count = 0;
         while (true) {
             if (cancelled) throw new CancellationException();
+            if (startTimeUtc>0) return true;
             if (internalFuture==null)
                 try {
                     if (timeout==null) {
-                        wait();
+                        // 5s so that it will repeat in case something sets the future without notifying;
+                        // can of course repeat here forever if someone calls get on an unsubmitted task,
+                        // but that is not hard to discover with a thread dump, seeing it waiting here
+                        wait(5*1000);
                     } else {
                         long remaining = endTime - System.currentTimeMillis();
                         if (remaining>0)

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8983bf2c/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolver.java b/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolver.java
index afd6109..d93dfa4 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolver.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolver.java
@@ -434,7 +434,11 @@ public class ValueResolver<T> implements DeferredSupplier<T>, Iterable<Maybe<Obj
                         // (should discourage this in favour of task factories which can be transiently interrupted?)
                         BrooklynTaskTags.addTagDynamically(task, BrooklynTaskTags.NON_TRANSIENT_TASK_TAG);
                     }
-                    exec.submit(task);
+                    if (timer!=null || Thread.currentThread().isInterrupted()) {
+                        exec.submit(task);
+                    } else {
+                        exec.get(task);
+                    }
                 }
             }
 
@@ -483,7 +487,7 @@ public class ValueResolver<T> implements DeferredSupplier<T>, Iterable<Maybe<Obj
                     String description = getDescription();
                     TaskBuilder<Object> tb = Tasks.<Object>builder()
                             .body(callable)
-                            .displayName("Resolving dependent value")
+                            .displayName("Resolving dependent value of deferred supplier")
                             .description(description);
                     if (isTransientTask) tb.tag(BrooklynTaskTags.TRANSIENT_TASK_TAG);
                     

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8983bf2c/core/src/test/java/org/apache/brooklyn/core/entity/EntityConfigTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/EntityConfigTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/EntityConfigTest.java
index b583b1e..b510178 100644
--- a/core/src/test/java/org/apache/brooklyn/core/entity/EntityConfigTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/EntityConfigTest.java
@@ -697,6 +697,18 @@ public class EntityConfigTest extends BrooklynAppUnitTestSupport {
         assertEquals(getConfigFuture.get(TIMEOUT_MS, TimeUnit.MILLISECONDS), "abc");
         assertEquals(work.callCount.get(), 1);
     }
+    
+    @Test
+    public void testGetConfigRunsInSameThread() throws Exception {
+        Callable<String> job = () -> ""+Thread.currentThread().getId();
+
+        final MyOtherEntity entity = app.addChild(EntitySpec.create(MyOtherEntity.class));
+        assertEquals( ((EntityInternal)entity).getExecutionContext().get(new BasicTask<>(job)), job.call() );
+        
+        // and config also runs in same thread (after validation)
+        entity.config().set(MyOtherEntity.STRING_KEY, new BasicTask<>(job));
+        assertEquals(entity.config().get(MyOtherEntity.STRING_KEY), job.call());
+    }
 
     @ImplementedBy(MyBaseEntityImpl.class)
     public interface MyBaseEntity extends EntityInternal {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8983bf2c/core/src/test/java/org/apache/brooklyn/core/mgmt/internal/EntityExecutionManagerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/internal/EntityExecutionManagerTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/internal/EntityExecutionManagerTest.java
index c84e016..51f5bdc 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/internal/EntityExecutionManagerTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/internal/EntityExecutionManagerTest.java
@@ -521,5 +521,4 @@ public class EntityExecutionManagerTest extends BrooklynAppUnitTestSupport {
         }
         return ((EntityInternal)e).getExecutionContext().submit(tb.build());
     }
-
 }


[22/35] brooklyn-server git commit: Merge branch 'master' into adjunct-rest-2

Posted by he...@apache.org.
Merge branch 'master' into adjunct-rest-2

Big changes to config key construction, following on from previous deprecation


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

Branch: refs/heads/master
Commit: 62bcbc5f4b7695420b026952ce6ae7f180dcaec6
Parents: 45261c7 df83d44
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Sep 25 11:29:45 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Mon Sep 25 11:29:45 2017 +0100

----------------------------------------------------------------------
 api/pom.xml                                     |    2 +-
 .../brooklyn/api/catalog/BrooklynCatalog.java   |    4 +
 .../brooklyn/api/typereg/RegisteredType.java    |    5 +-
 camp/camp-base/pom.xml                          |    2 +-
 camp/camp-brooklyn/pom.xml                      |    2 +-
 .../camp/brooklyn/AbstractYamlTest.java         |   31 +-
 .../brooklyn/EmptySoftwareProcessYamlTest.java  |   94 +-
 .../camp/brooklyn/FunctionSensorYamlTest.java   |  123 ++
 .../VanillaSoftwareProcessYamlTest.java         |  299 +++++
 .../CatalogOsgiVersionMoreEntityRebindTest.java |   10 +-
 .../CatalogOsgiVersionMoreEntityTest.java       |    3 +
 .../java-web-app-and-db-with-function-2.yaml    |    9 +-
 .../java-web-app-and-db-with-function.yaml      |    7 +-
 ...-java-web-app-spec-and-db-with-function.yaml |    7 +-
 .../test/resources/visitors-creation-script.sql |   19 +-
 camp/camp-server/pom.xml                        |    2 +-
 camp/pom.xml                                    |    2 +-
 core/pom.xml                                    |    2 +-
 .../apache/brooklyn/core/BrooklynVersion.java   |    2 +-
 .../brooklyn/core/config/BasicConfigKey.java    |   41 +-
 .../brooklyn/core/entity/AbstractEntity.java    |    6 +-
 .../apache/brooklyn/core/entity/Attributes.java |   10 +-
 .../core/entity/BrooklynConfigKeys.java         |  124 +-
 .../core/mgmt/entitlement/Entitlements.java     |    1 +
 .../mgmt/ha/OsgiBundleInstallationResult.java   |    4 +-
 .../BasicExternalConfigSupplierRegistry.java    |   12 +-
 .../core/objs/AbstractEntityAdjunct.java        |   61 +-
 .../core/sensor/BasicAttributeSensor.java       |   11 +-
 .../brooklyn/core/sensor/BasicSensor.java       |   19 +-
 .../apache/brooklyn/core/sensor/Sensors.java    |    9 +-
 .../core/sensor/function/FunctionSensor.java    |   89 ++
 .../core/typereg/BasicBrooklynTypeRegistry.java |   20 +-
 .../typereg/BasicTypeImplementationPlan.java    |    4 +-
 .../typereg/RegisteredTypeLoadingContexts.java  |    6 +-
 .../core/typereg/RegisteredTypePredicates.java  |   78 +-
 .../brooklyn/core/typereg/RegisteredTypes.java  |    2 +-
 .../enricher/stock/AbstractAggregator.java      |   37 +-
 .../enricher/stock/AbstractTransformer.java     |   22 +-
 .../brooklyn/enricher/stock/Aggregator.java     |   15 +-
 .../brooklyn/enricher/stock/Combiner.java       |   33 +-
 .../apache/brooklyn/enricher/stock/Joiner.java  |   17 +-
 .../brooklyn/enricher/stock/MapAggregator.java  |   11 +-
 .../enricher/stock/PercentageEnricher.java      |    7 +-
 .../brooklyn/enricher/stock/Transformer.java    |   23 +-
 .../brooklyn/enricher/stock/UpdatingMap.java    |   23 +-
 .../YamlRollingTimeWindowMeanEnricher.java      |   13 +-
 .../stock/YamlTimeWeightedDeltaEnricher.java    |    7 +-
 .../enricher/stock/reducer/Reducer.java         |   26 +-
 .../brooklyn/entity/group/AbstractGroup.java    |   13 +-
 .../apache/brooklyn/entity/group/Cluster.java   |    2 +
 .../brooklyn/entity/group/DynamicCluster.java   |   21 +-
 .../brooklyn/entity/group/DynamicFabric.java    |   23 +-
 .../brooklyn/entity/group/DynamicGroup.java     |    6 +-
 .../brooklyn/entity/stock/BasicStartable.java   |    6 +-
 .../brooklyn/entity/stock/DelegateEntity.java   |    7 +-
 core/src/main/resources/catalog.bom             |   57 +-
 .../entity/RecordingSensorEventListener.java    |   12 +
 .../core/mgmt/osgi/OsgiStandaloneTest.java      |    4 +-
 .../core/policy/basic/EnricherTypeTest.java     |    6 -
 .../sensor/function/FunctionSensorTest.java     |   77 ++
 .../core/test/entity/TestEntityImpl.java        |    2 +-
 .../stock/TransformingEnricherTest.java         |    7 +-
 .../util/core/internal/ssh/ExecCmdAsserts.java  |   12 +-
 core/src/test/resources/catalog.bom             |    2 +-
 karaf/commands/pom.xml                          |    2 +-
 karaf/features/pom.xml                          |    2 +-
 karaf/httpcomponent-extension/pom.xml           |    2 +-
 karaf/init/pom.xml                              |    2 +-
 .../init/src/main/resources/catalog-classes.bom |  107 +-
 karaf/jetty-config/pom.xml                      |    2 +-
 karaf/pom.xml                                   |    2 +-
 karaf/start/pom.xml                             |    2 +-
 launcher-common/pom.xml                         |    2 +-
 launcher/pom.xml                                |    2 +-
 .../java-web-app-and-db-with-function.yaml      |    3 +-
 .../test/resources/visitors-creation-script.sql |   19 +-
 locations/container/pom.xml                     |    2 +-
 .../resources/generic-application.tests.bom     |    8 +-
 .../src/test/resources/generic.tests.bom        |    2 +-
 locations/jclouds/pom.xml                       |    2 +-
 .../location/jclouds/JcloudsLocation.java       |   73 +-
 .../api/JcloudsLocationConfigPublic.java        |    6 +
 .../JcloudsMaxConcurrencyStubbedTest.java       |  225 ++++
 logging/logback-includes/pom.xml                |    2 +-
 logging/logback-xml/pom.xml                     |    2 +-
 parent/pom.xml                                  |    2 +-
 policy/pom.xml                                  |    2 +-
 .../action/AbstractScheduledEffectorPolicy.java |  292 +++++
 .../policy/action/PeriodicEffectorPolicy.java   |  116 ++
 .../policy/action/ScheduledEffectorPolicy.java  |  100 ++
 .../policy/autoscaling/AutoScalerPolicy.java    |   25 +-
 .../policy/ha/ConnectionFailureDetector.java    |   14 +-
 .../policy/ha/ServiceFailureDetector.java       |   16 +-
 .../brooklyn/policy/ha/ServiceReplacer.java     |   20 +-
 .../brooklyn/policy/ha/ServiceRestarter.java    |   16 +-
 .../policy/ha/SshMachineFailureDetector.java    |    4 +-
 policy/src/main/resources/catalog.bom           |   92 +-
 .../action/AbstractEffectorPolicyTest.java      |   81 ++
 .../action/PeriodicEffectorPolicyTest.java      |  123 ++
 .../action/ScheduledEffectorPolicyTest.java     |  121 ++
 .../action/ScheduledPolicyRebindTest.java       |  137 +++
 .../AutoScalerPolicyPoolSizeTest.java           |   18 +-
 .../AbstractLoadBalancingPolicyTest.java        |    1 -
 pom.xml                                         |    4 +-
 rest/rest-api/pom.xml                           |    2 +-
 .../apache/brooklyn/rest/api/AdjunctApi.java    |    6 +-
 .../org/apache/brooklyn/rest/api/BundleApi.java |   37 +-
 .../apache/brooklyn/rest/api/CatalogApi.java    |   56 +-
 .../brooklyn/rest/api/EntityConfigApi.java      |   10 +-
 .../apache/brooklyn/rest/api/SubtypeApi.java    |   96 --
 .../org/apache/brooklyn/rest/api/TypeApi.java   |   16 +-
 .../rest/domain/AdjunctConfigSummary.java       |   85 --
 .../brooklyn/rest/domain/AdjunctDetail.java     |    4 +-
 .../brooklyn/rest/domain/BundleSummary.java     |    7 +
 .../brooklyn/rest/domain/ConfigSummary.java     |   66 +-
 .../rest/domain/EnricherConfigSummary.java      |   11 +-
 .../rest/domain/EntityConfigSummary.java        |   67 +-
 .../rest/domain/LocationConfigSummary.java      |   40 +-
 .../rest/domain/PolicyConfigSummary.java        |   29 +-
 .../apache/brooklyn/rest/domain/TypeDetail.java |    3 +-
 .../brooklyn/rest/domain/TypeSummary.java       |   12 +-
 rest/rest-resources/pom.xml                     |    2 +-
 .../apache/brooklyn/rest/BrooklynRestApi.java   |    2 -
 .../rest/resources/AdjunctResource.java         |    8 +-
 .../brooklyn/rest/resources/BundleResource.java |   45 +-
 .../rest/resources/EntityConfigResource.java    |    8 +-
 .../rest/resources/SubtypeResource.java         |   82 --
 .../brooklyn/rest/resources/TypeResource.java   |   23 +-
 .../rest/transform/AdjunctTransformer.java      |   41 +-
 .../rest/transform/EntityTransformer.java       |  111 +-
 .../rest/transform/PolicyTransformer.java       |    3 +-
 .../rest/transform/TypeTransformer.java         |   43 +-
 .../BundleAndTypeAndSubtypeResourcesTest.java   | 1093 -----------------
 .../resources/BundleAndTypeResourcesTest.java   | 1098 ++++++++++++++++++
 .../resources/EntityConfigResourceTest.java     |    2 +-
 rest/rest-server/pom.xml                        |    2 +-
 server-cli/pom.xml                              |    2 +-
 .../brooklyn/cli/lister/ItemDescriptors.java    |   28 +-
 .../main/resources/brooklyn/default.catalog.bom |    2 +-
 server-cli/src/main/resources/catalog.bom       |    2 +-
 software/base/pom.xml                           |    2 +-
 .../entity/brooklynnode/BrooklynNode.java       |    2 +-
 .../brooklynnode/BrooklynNodeSshDriver.java     |    2 +-
 .../brooklyn/entity/java/JmxmpSslSupport.java   |    2 +-
 .../apache/brooklyn/entity/java/UsesJava.java   |   10 +-
 .../apache/brooklyn/entity/java/UsesJmx.java    |   37 +-
 .../software/base/AbstractVanillaProcess.java   |   21 +-
 .../software/base/EmptySoftwareProcessImpl.java |    4 +-
 .../entity/software/base/SoftwareProcess.java   |   37 +-
 .../software/base/SoftwareProcessImpl.java      |    1 -
 .../software/base/VanillaSoftwareProcess.java   |    5 +-
 .../base/VanillaSoftwareProcessImpl.java        |   16 +-
 .../base/VanillaSoftwareProcessSshDriver.java   |   12 +-
 .../software/base/VanillaWindowsProcess.java    |   22 +-
 software/base/src/main/resources/catalog.bom    |   17 +-
 software/winrm/pom.xml                          |    2 +-
 test-framework/pom.xml                          |    2 +-
 test-framework/src/main/resources/catalog.bom   |   12 +-
 test-support/pom.xml                            |    2 +-
 .../test/performance/PerformanceTestUtils.java  |   50 +-
 .../osgi/com-example-entities/pom.xml           |    2 +-
 utils/common/dependencies/osgi/entities/pom.xml |    2 +-
 .../dependencies/osgi/more-entities-v1/pom.xml  |    2 +-
 .../osgi/more-entities-v2-evil-twin/pom.xml     |    2 +-
 .../dependencies/osgi/more-entities-v2/pom.xml  |    2 +-
 utils/common/pom.xml                            |    2 +-
 .../apache/brooklyn/util/guava/TypeTokens.java  |   38 +-
 .../javalang/coerce/TypeCoercerExtensible.java  |   15 +-
 .../brooklyn/util/maven/MavenArtifactTest.java  |    4 +-
 utils/groovy/pom.xml                            |    2 +-
 utils/jmx/jmxmp-ssl-agent/pom.xml               |    2 +-
 utils/jmx/jmxrmi-agent/pom.xml                  |    2 +-
 utils/rest-swagger/pom.xml                      |    2 +-
 utils/rt-felix/pom.xml                          |    2 +-
 utils/test-support/pom.xml                      |    2 +-
 175 files changed, 4572 insertions(+), 2177 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/62bcbc5f/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/62bcbc5f/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java
----------------------------------------------------------------------
diff --cc rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java
index 5fc1366,0000000..1886f63
mode 100644,000000..100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java
@@@ -1,233 -1,0 +1,233 @@@
 +/*
 + * Licensed to the Apache Software Foundation (ASF) under one
 + * or more contributor license agreements.  See the NOTICE file
 + * distributed with this work for additional information
 + * regarding copyright ownership.  The ASF licenses this file
 + * to you under the Apache License, Version 2.0 (the
 + * "License"); you may not use this file except in compliance
 + * with the License.  You may obtain a copy of the License at
 + *
 + *     http://www.apache.org/licenses/LICENSE-2.0
 + *
 + * Unless required by applicable law or agreed to in writing,
 + * software distributed under the License is distributed on an
 + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 + * KIND, either express or implied.  See the License for the
 + * specific language governing permissions and limitations
 + * under the License.
 + */
 +package org.apache.brooklyn.rest.api;
 +
 +import java.util.List;
 +import java.util.Map;
 +
 +import javax.ws.rs.Consumes;
 +import javax.ws.rs.DELETE;
 +import javax.ws.rs.GET;
 +import javax.ws.rs.POST;
 +import javax.ws.rs.Path;
 +import javax.ws.rs.PathParam;
 +import javax.ws.rs.Produces;
 +import javax.ws.rs.QueryParam;
 +import javax.ws.rs.core.MediaType;
 +import javax.ws.rs.core.Response;
 +
- import org.apache.brooklyn.rest.domain.AdjunctConfigSummary;
 +import org.apache.brooklyn.rest.domain.AdjunctDetail;
 +import org.apache.brooklyn.rest.domain.AdjunctSummary;
++import org.apache.brooklyn.rest.domain.ConfigSummary;
 +import org.apache.brooklyn.rest.domain.Status;
 +
 +import io.swagger.annotations.Api;
 +import io.swagger.annotations.ApiOperation;
 +import io.swagger.annotations.ApiParam;
 +import io.swagger.annotations.ApiResponse;
 +import io.swagger.annotations.ApiResponses;
 +
 +@Path("/applications/{application}/entities/{entity}/adjuncts")
 +@Api("Entity Adjuncts (policies, enrichers, feeds)")
 +@Produces(MediaType.APPLICATION_JSON)
 +@Consumes(MediaType.APPLICATION_JSON)
 +public interface AdjunctApi {
 +
 +    @GET
 +    @ApiOperation(value = "Fetch the adjuncts attached to a specific application entity",
 +            response = org.apache.brooklyn.rest.domain.AdjunctSummary.class,
 +            responseContainer = "List")
 +    @ApiResponses(value = {
 +            @ApiResponse(code = 404, message = "Could not find application or entity")
 +    })
 +    public List<AdjunctSummary> list(
 +            @ApiParam(value = "Application ID or name", required = true)
 +            @PathParam("application") final String application,
 +            @ApiParam(value = "Entity ID or name", required = true)
 +            @PathParam("entity") final String entityToken,
 +            @ApiParam(value = "Filter by adjunct type", required = false)
 +            @QueryParam("adjunctType") final String adjunctType);
 +
 +    @POST
 +    @ApiOperation(value = "Add an adjunct (policy, enricher, or feed)", notes = "Returns a summary of the added adjunct")
 +    @ApiResponses(value = {
 +            @ApiResponse(code = 404, message = "Could not find application or entity"),
 +            @ApiResponse(code = 400, message = "Type is not a suitable adjunct")
 +    })
 +    public AdjunctSummary addAdjunct(
 +            @ApiParam(name = "application", value = "Application ID or name", required = true)
 +            @PathParam("application") String application,
 +
 +            @ApiParam(name = "entity", value = "Entity ID or name", required = true)
 +            @PathParam("entity") String entityToken,
 +
 +            @ApiParam(name = "type", value = "Adjunct from the type registry to instantiate and add", required = true)
 +            @QueryParam("type")
 +            String adjunctRegisteredTypeName,
 +
 +            // TODO would like to make this optional but jersey complains if we do
 +            @ApiParam(name = "config", value = "Configuration for the adjunct (as key value pairs)", required = true)
 +            Map<String, String> config);
 +
 +    @GET
 +    @Path("/{adjunct}")
 +    @ApiOperation(value = "Gets detail of an adjunct")
 +    @ApiResponses(value = {
 +            @ApiResponse(code = 404, message = "Could not find application, entity or adjunct")
 +    })
 +    public AdjunctDetail get(
 +            @ApiParam(name = "application", value = "Application ID or name", required = true)
 +            @PathParam("application") String application,
 +
 +            @ApiParam(name = "entity", value = "Entity ID or name", required = true)
 +            @PathParam("entity") String entityToken,
 +
 +            @ApiParam(name = "adjunct", value = "Adjunct ID or name", required = true)
 +            @PathParam("adjunct") String adjunctId);
 +    
 +    @GET
 +    @Path("/{adjunct}/status")
 +    @ApiOperation(value = "Gets status of an adjunct (RUNNING / SUSPENDED)")
 +    @ApiResponses(value = {
 +            @ApiResponse(code = 404, message = "Could not find application, entity or adjunct")
 +    })
 +    public Status getStatus(
 +            @ApiParam(name = "application", value = "Application ID or name", required = true)
 +            @PathParam("application") String application,
 +
 +            @ApiParam(name = "entity", value = "Entity ID or name", required = true)
 +            @PathParam("entity") String entityToken,
 +
 +            @ApiParam(name = "adjunct", value = "Adjunct ID or name", required = true)
 +            @PathParam("adjunct") String adjunctId);
 +
 +    @POST
 +    @Path("/{adjunct}/start")
 +    @ApiOperation(value = "Start or resume an adjunct")
 +    @ApiResponses(value = {
 +            @ApiResponse(code = 404, message = "Could not find application, entity or adjunct")
 +    })
 +    public Response start(
 +            @ApiParam(name = "application", value = "Application ID or name", required = true)
 +            @PathParam("application") String application,
 +
 +            @ApiParam(name = "entity", value = "Entity ID or name", required = true)
 +            @PathParam("entity") String entityToken,
 +
 +            @ApiParam(name = "adjunct", value = "Adjunct ID or name", required = true)
 +            @PathParam("adjunct") String adjunctId);
 +
 +    @POST
 +    @Path("/{adjunct}/stop")
 +    @ApiOperation(value = "Suspends an adjunct")
 +    @ApiResponses(value = {
 +            @ApiResponse(code = 404, message = "Could not find application, entity or adjunct")
 +    })
 +    public Response stop(
 +            @ApiParam(name = "application", value = "Application ID or name", required = true)
 +            @PathParam("application") String application,
 +
 +            @ApiParam(name = "entity", value = "Entity ID or name", required = true)
 +            @PathParam("entity") String entityToken,
 +
 +            @ApiParam(name = "adjunct", value = "Adjunct ID or name", required = true)
 +            @PathParam("adjunct") String adjunctId);
 +
 +    @DELETE
 +    @Path("/{adjunct}")
 +    @ApiOperation(value = "Destroy an adjunct", notes="Removes an adjunct from being associated with the entity and destroys it (stopping first if running)")
 +    @ApiResponses(value = {
 +            @ApiResponse(code = 404, message = "Could not find application, entity or adjunct")
 +    })
 +    public Response destroy(
 +            @ApiParam(name = "application", value = "Application ID or name", required = true)
 +            @PathParam("application") String application,
 +
 +            @ApiParam(name = "entity", value = "Entity ID or name", required = true)
 +            @PathParam("entity") String entityToken,
 +
 +            @ApiParam(name = "adjunct", value = "Adjunct ID or name", required = true)
 +            @PathParam("adjunct") String adjunctId);
 +
 +    /// ---------- config ---------------
 +    
 +    @GET
 +    @Path("/{adjunct}/config")
 +    @ApiOperation(value = "Fetch the config keys for a specific adjunct",
-             response = org.apache.brooklyn.rest.domain.AdjunctConfigSummary.class,
++            response = org.apache.brooklyn.rest.domain.ConfigSummary.class,
 +            responseContainer = "List")
 +    @ApiResponses(value = {
 +            @ApiResponse(code = 404, message = "Could not find application or entity or adjunct")
 +    })
-     public List<AdjunctConfigSummary> listConfig(
++    public List<ConfigSummary> listConfig(
 +            @ApiParam(value = "Application ID or name", required = true)
 +            @PathParam("application") final String application,
 +            @ApiParam(value = "Entity ID or name", required = true)
 +            @PathParam("entity") final String entityToken,
 +            @ApiParam(value = "Adjunct ID or name", required = true)
 +            @PathParam("adjunct") final String adjunctToken);
 +
 +    // TODO support parameters  ?show=value,summary&name=xxx &format={string,json,xml}
 +    // (and in sensors class)
 +    @GET
 +    @Path("/{adjunct}/config-current")
 +    @ApiOperation(value = "Fetch config key values in batch", notes="Returns a map of config name to value")
 +    public Map<String, Object> batchConfigRead(
 +            @ApiParam(value = "Application ID or name", required = true)
 +            @PathParam("application") String application,
 +            @ApiParam(value = "Entity ID or name", required = true)
 +            @PathParam("entity") String entityToken,
 +            @ApiParam(value = "Adjunct ID or name", required = true)
 +            @PathParam("adjunct") String adjunctToken) ;
 +
 +    @GET
 +    @Path("/{adjunct}/config/{config}")
 +    @ApiOperation(value = "Fetch config value", response = Object.class)
 +    @ApiResponses(value = {
 +            @ApiResponse(code = 404, message = "Could not find application, entity, adjunct or config key")
 +    })
 +    public String getConfig(
 +            @ApiParam(value = "Application ID or name", required = true)
 +            @PathParam("application") String application,
 +            @ApiParam(value = "Entity ID or name", required = true)
 +            @PathParam("entity") String entityToken,
 +            @ApiParam(value = "Adjunct ID or name", required = true)
 +            @PathParam("adjunct") String adjunctToken,
 +            @ApiParam(value = "Config key ID", required = true)
 +            @PathParam("config") String configKeyName);
 +
 +    @POST
 +    @Path("/{adjunct}/config/{config}")
 +    @Consumes(value = {"*/*"})
 +    @ApiOperation(value = "Sets the given config on this adjunct")
 +    @ApiResponses(value = {
 +            @ApiResponse(code = 404, message = "Could not find application, entity, adjunct or config key")
 +    })
 +    public Response setConfig(
 +            @ApiParam(value = "Application ID or name", required = true)
 +            @PathParam("application") String application,
 +            @ApiParam(value = "Entity ID or name", required = true)
 +            @PathParam("entity") String entityToken,
 +            @ApiParam(value = "Adjunct ID or name", required = true)
 +            @PathParam("adjunct") String adjunctToken,
 +            @ApiParam(value = "Config key ID", required = true)
 +            @PathParam("config") String configKeyName,
 +            @ApiParam(name = "value", value = "New value for the configuration", required = true)
 +            Object value);
 +}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/62bcbc5f/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/EntityConfigApi.java
----------------------------------------------------------------------
diff --cc rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/EntityConfigApi.java
index 4a5bbde,4a5bbde..a0e3604
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/EntityConfigApi.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/EntityConfigApi.java
@@@ -18,7 -18,7 +18,6 @@@
   */
  package org.apache.brooklyn.rest.api;
  
--import io.swagger.annotations.Api;
  import java.util.List;
  import java.util.Map;
  
@@@ -32,12 -32,12 +31,13 @@@ import javax.ws.rs.Produces
  import javax.ws.rs.QueryParam;
  import javax.ws.rs.core.MediaType;
  
--import org.apache.brooklyn.rest.domain.EntityConfigSummary;
++import org.apache.brooklyn.rest.domain.ConfigSummary;
  
--import io.swagger.annotations.ApiResponse;
--import io.swagger.annotations.ApiResponses;
++import io.swagger.annotations.Api;
  import io.swagger.annotations.ApiOperation;
  import io.swagger.annotations.ApiParam;
++import io.swagger.annotations.ApiResponse;
++import io.swagger.annotations.ApiResponses;
  
  @Path("/applications/{application}/entities/{entity}/config")
  @Api("Entity Config")
@@@ -52,7 -52,7 +52,7 @@@ public interface EntityConfigApi 
      @ApiResponses(value = {
              @ApiResponse(code = 404, message = "Could not find application or entity")
      })
--    public List<EntityConfigSummary> list(
++    public List<ConfigSummary> list(
              @ApiParam(value = "Application ID or name", required = true)
              @PathParam("application") final String application,
              @ApiParam(value = "Entity ID or name", required = true)

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/62bcbc5f/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctDetail.java
----------------------------------------------------------------------
diff --cc rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctDetail.java
index ddce5f4,0000000..a2f348c
mode 100644,000000..100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctDetail.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctDetail.java
@@@ -1,72 -1,0 +1,72 @@@
 +/*
 + * Licensed to the Apache Software Foundation (ASF) under one
 + * or more contributor license agreements.  See the NOTICE file
 + * distributed with this work for additional information
 + * regarding copyright ownership.  The ASF licenses this file
 + * to you under the Apache License, Version 2.0 (the
 + * "License"); you may not use this file except in compliance
 + * with the License.  You may obtain a copy of the License at
 + *
 + *     http://www.apache.org/licenses/LICENSE-2.0
 + *
 + * Unless required by applicable law or agreed to in writing,
 + * software distributed under the License is distributed on an
 + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 + * KIND, either express or implied.  See the License for the
 + * specific language governing permissions and limitations
 + * under the License.
 + */
 +package org.apache.brooklyn.rest.domain;
 +
 +import java.util.Map;
 +import java.util.Set;
 +
 +import org.apache.brooklyn.api.objs.EntityAdjunct;
 +import org.apache.brooklyn.util.collections.MutableMap;
 +import org.apache.brooklyn.util.collections.MutableSet;
 +
 +import com.fasterxml.jackson.annotation.JsonInclude;
 +import com.fasterxml.jackson.annotation.JsonInclude.Include;
 +
 +public class AdjunctDetail extends AdjunctSummary {
 +
 +    private static final long serialVersionUID = -5086680835225136768L;
 +
 +    @JsonInclude(Include.NON_EMPTY)
 +    private String functionallyUniqueIdentifier;
 +    @JsonInclude(Include.NON_EMPTY)
 +    private Set<Object> tags;
 +    @JsonInclude(Include.NON_EMPTY)
-     final Set<AdjunctConfigSummary> parameters = MutableSet.of();
++    final Set<ConfigSummary> parameters = MutableSet.of();
 +    final Map<String,Object> config = MutableMap.of();
 +
 +    // for json
 +    protected AdjunctDetail() {}
 +
 +    public AdjunctDetail(EntityAdjunct a) {
 +        super(a);
 +        this.functionallyUniqueIdentifier = a.getUniqueTag();
 +        this.tags = a.tags().getTags();
 +    }
 +    
 +    public String getFunctionallyUniqueIdentifier() {
 +        return functionallyUniqueIdentifier;
 +    }
 +    
 +    public Set<Object> getTags() {
 +        return tags;
 +    }
 +    
-     public AdjunctDetail parameter(AdjunctConfigSummary p) {
++    public AdjunctDetail parameter(ConfigSummary p) {
 +        parameters.add(p); return this;
 +    }
 +
 +    public AdjunctDetail config(String key, Object val) {
 +        config.put(key, val); return this;
 +    }
 +
 +    public AdjunctDetail config(Map<String,Object> vals) {
 +        config.putAll(vals); return this;
 +    }
 +
 +}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/62bcbc5f/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/BrooklynRestApi.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/62bcbc5f/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java
----------------------------------------------------------------------
diff --cc rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java
index 9dd4c10,0000000..3b5185a
mode 100644,000000..100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java
@@@ -1,263 -1,0 +1,263 @@@
 +/*
 + * Licensed to the Apache Software Foundation (ASF) under one
 + * or more contributor license agreements.  See the NOTICE file
 + * distributed with this work for additional information
 + * regarding copyright ownership.  The ASF licenses this file
 + * to you under the Apache License, Version 2.0 (the
 + * "License"); you may not use this file except in compliance
 + * with the License.  You may obtain a copy of the License at
 + *
 + *     http://www.apache.org/licenses/LICENSE-2.0
 + *
 + * Unless required by applicable law or agreed to in writing,
 + * software distributed under the License is distributed on an
 + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 + * KIND, either express or implied.  See the License for the
 + * specific language governing permissions and limitations
 + * under the License.
 + */
 +package org.apache.brooklyn.rest.resources;
 +
 +import java.util.Collections;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.Set;
 +
 +import javax.ws.rs.core.Context;
 +import javax.ws.rs.core.Response;
 +import javax.ws.rs.core.UriInfo;
 +
 +import org.apache.brooklyn.api.entity.Entity;
 +import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec;
 +import org.apache.brooklyn.api.objs.BrooklynObjectType;
 +import org.apache.brooklyn.api.objs.EntityAdjunct;
 +import org.apache.brooklyn.api.policy.Policy;
 +import org.apache.brooklyn.api.policy.PolicySpec;
 +import org.apache.brooklyn.api.sensor.Enricher;
 +import org.apache.brooklyn.api.sensor.EnricherSpec;
 +import org.apache.brooklyn.api.sensor.Feed;
 +import org.apache.brooklyn.api.typereg.RegisteredType;
 +import org.apache.brooklyn.config.ConfigKey;
 +import org.apache.brooklyn.core.config.ConfigPredicates;
 +import org.apache.brooklyn.core.entity.EntityInternal;
 +import org.apache.brooklyn.core.mgmt.entitlement.Entitlements;
 +import org.apache.brooklyn.rest.api.AdjunctApi;
- import org.apache.brooklyn.rest.domain.AdjunctConfigSummary;
 +import org.apache.brooklyn.rest.domain.AdjunctDetail;
 +import org.apache.brooklyn.rest.domain.AdjunctSummary;
++import org.apache.brooklyn.rest.domain.ConfigSummary;
 +import org.apache.brooklyn.rest.domain.Status;
 +import org.apache.brooklyn.rest.domain.SummaryComparators;
 +import org.apache.brooklyn.rest.filter.HaHotStateRequired;
 +import org.apache.brooklyn.rest.transform.AdjunctTransformer;
 +import org.apache.brooklyn.rest.transform.EntityTransformer;
 +import org.apache.brooklyn.rest.util.BrooklynRestResourceUtils;
 +import org.apache.brooklyn.rest.util.WebResourceUtils;
 +import org.apache.brooklyn.util.core.ClassLoaderUtils;
 +import org.apache.brooklyn.util.core.flags.TypeCoercions;
 +import org.apache.brooklyn.util.exceptions.Exceptions;
 +import org.apache.brooklyn.util.text.Strings;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +
 +import com.google.common.base.Function;
 +import com.google.common.base.Predicates;
 +import com.google.common.collect.FluentIterable;
 +import com.google.common.collect.Iterables;
 +import com.google.common.collect.Lists;
 +
 +@HaHotStateRequired
 +public class AdjunctResource extends AbstractBrooklynRestResource implements AdjunctApi {
 +
 +    private static final Logger log = LoggerFactory.getLogger(AdjunctResource.class);
 +
 +    private @Context UriInfo ui;
 +
 +    @Override
 +    public List<AdjunctSummary> list(String application, String entityToken, String adjunctType) {
 +        final Entity entity = brooklyn().getEntity(application, entityToken);
 +        Iterable<? extends EntityAdjunct> source = Collections.emptyList();
 +        boolean all = Strings.isBlank(adjunctType);
 +        boolean any = false;
 +        if (all || adjunctType.equalsIgnoreCase(BrooklynObjectType.POLICY.name())) {
 +            any = true;
 +            source = Iterables.concat(source, entity.policies());
 +        }
 +        if (all || adjunctType.equalsIgnoreCase(BrooklynObjectType.ENRICHER.name())) {
 +            any = true;
 +            source = Iterables.concat(source, entity.enrichers());
 +        }
 +        if (all || adjunctType.equalsIgnoreCase(BrooklynObjectType.FEED.name())) {
 +            any = true;
 +            source = Iterables.concat(source, ((EntityInternal)entity).feeds());
 +        }
 +        if (!any) {
 +            throw WebResourceUtils.badRequest("Unknown adjunct type '%s'; use 'policy', 'enricher', or 'feed'", adjunctType);
 +        }
 +        return FluentIterable.from(source)
 +            .transform(new Function<EntityAdjunct, AdjunctSummary>() {
 +                @Override
 +                public AdjunctSummary apply(EntityAdjunct adjunct) {
 +                    return AdjunctTransformer.adjunctSummary(entity, adjunct, ui.getBaseUriBuilder());
 +                }
 +            })
 +            .toSortedList(SummaryComparators.nameComparator());
 +    }
 +
 +    // TODO would like to make 'config' arg optional but jersey complains if we do
 +    @SuppressWarnings({ "rawtypes", "unchecked" })
 +    @Override
 +    public AdjunctSummary addAdjunct(String application, String entityToken, String adjunctTypeName, Map<String, String> config) {
 +        Entity entity = brooklyn().getEntity(application, entityToken);
 +        if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.MODIFY_ENTITY, entity)) {
 +            throw WebResourceUtils.forbidden("User '%s' is not authorized to modify entity '%s'",
 +                    Entitlements.getEntitlementContext().user(), entity);
 +        }
 +        
 +        RegisteredType rt = brooklyn().getTypeRegistry().get(adjunctTypeName);
 +        AbstractBrooklynObjectSpec<?, ?> spec;
 +        if (rt!=null) {
 +            spec = brooklyn().getTypeRegistry().createSpec(rt, null, null);
 +        } else {
 +            try {
 +                Class<?> type = new ClassLoaderUtils(this, mgmt()).loadClass(adjunctTypeName);
 +                if (Policy.class.isAssignableFrom(type)) spec = PolicySpec.create((Class) type);
 +                else if (Enricher.class.isAssignableFrom(type)) spec = EnricherSpec.create((Class) type);
 +                else if (Feed.class.isAssignableFrom(type)) {
 +                    // TODO add FeedSpec ?  would be needed even if using the type registry
 +                    throw WebResourceUtils.badRequest("Creation of feeds from java type (%s) not supported", adjunctTypeName);
 +                } else {
 +                    throw WebResourceUtils.badRequest("Invalid type %s; not a support adjunct type", adjunctTypeName);
 +                }
 +            } catch (ClassNotFoundException e) {
 +                throw WebResourceUtils.badRequest("No adjunct with type %s found", adjunctTypeName);
 +            } catch (ClassCastException e) {
 +                throw WebResourceUtils.badRequest("No adjunct with type %s found", adjunctTypeName);
 +            } catch (Exception e) {
 +                throw Exceptions.propagate(e);
 +            }
 +        }
 +
 +        spec.configure(config);
 +
 +        EntityAdjunct instance;
 +        if (spec instanceof PolicySpec) instance = entity.policies().add((PolicySpec)spec);
 +        else if (spec instanceof EnricherSpec) instance = entity.enrichers().add((EnricherSpec)spec);
 +        else {
 +            // TODO add FeedSpec
 +            throw WebResourceUtils.badRequest("Unexpected spec type %s", spec);
 +        }
 +
 +        log.debug("REST API added adjunct " + instance + " to " + entity);
 +
 +        return AdjunctTransformer.adjunctDetail(brooklyn(), entity, instance, ui.getBaseUriBuilder());
 +    }
 +
 +    @Override
 +    public AdjunctDetail get(String application, String entityToken, String adjunctId) {
 +        Entity entity = brooklyn().getEntity(application, entityToken);
 +        EntityAdjunct adjunct = brooklyn().getAdjunct(entity, adjunctId);
 +
 +        return AdjunctTransformer.adjunctDetail(brooklyn(), entity, adjunct, ui.getBaseUriBuilder());
 +    }
 +    
 +    @Override
 +    public Status getStatus(String application, String entityToken, String adjunctId) {
 +        return AdjunctTransformer.inferStatus( brooklyn().getAdjunct(application, entityToken, adjunctId) );
 +    }
 +
 +    @Override
 +    public Response start(String application, String entityToken, String adjunctId) {
 +        EntityAdjunct adjunct = brooklyn().getAdjunct(application, entityToken, adjunctId);
 +        if (adjunct instanceof Policy) ((Policy)adjunct).resume();
 +        else if (adjunct instanceof Feed) ((Feed)adjunct).resume();
 +        else throw WebResourceUtils.badRequest("%s does not support start/resume", adjunct);
 +        
 +        return Response.status(Response.Status.NO_CONTENT).build();
 +    }
 +
 +    @Override
 +    public Response stop(String application, String entityToken, String adjunctId) {
 +        EntityAdjunct adjunct = brooklyn().getAdjunct(application, entityToken, adjunctId);
 +        if (adjunct instanceof Policy) ((Policy)adjunct).suspend();
 +        else if (adjunct instanceof Feed) ((Feed)adjunct).suspend();
 +        else throw WebResourceUtils.badRequest("%s does not support suspend", adjunct);
 +        
 +        return Response.status(Response.Status.NO_CONTENT).build();
 +    }
 +
 +    @Override
 +    public Response destroy(String application, String entityToken, String adjunctId) {
 +        Entity entity = brooklyn().getEntity(application, entityToken);
 +        EntityAdjunct adjunct = brooklyn().getAdjunct(entity, adjunctId);
 +
 +        if (adjunct instanceof Policy) {
 +            ((Policy)adjunct).suspend();
 +            entity.policies().remove((Policy) adjunct);
 +        } else if (adjunct instanceof Enricher) {
 +            entity.enrichers().remove((Enricher) adjunct);
 +        } else if (adjunct instanceof Feed) {
 +            ((Feed)adjunct).suspend();
 +            ((EntityInternal)entity).feeds().remove((Feed) adjunct);
 +        } else {
 +            throw WebResourceUtils.badRequest("Unexpected adjunct type %s", adjunct);
 +        }
 +        
 +        return Response.status(Response.Status.NO_CONTENT).build();
 +    }
 +    
 +    // ---- config ----
 +    
 +    @Override
-     public List<AdjunctConfigSummary> listConfig(
++    public List<ConfigSummary> listConfig(
 +            final String application, final String entityToken, final String adjunctToken) {
 +        Entity entity = brooklyn().getEntity(application, entityToken);
 +        EntityAdjunct adjunct = brooklyn().getAdjunct(entity, adjunctToken);
 +
-         List<AdjunctConfigSummary> result = Lists.newArrayList();
++        List<ConfigSummary> result = Lists.newArrayList();
 +        for (ConfigKey<?> key : adjunct.config().findKeysPresent(Predicates.alwaysTrue())) {
-             result.add(AdjunctTransformer.configSummary(brooklyn(), entity, adjunct, key, ui.getBaseUriBuilder()));
++            result.add(AdjunctTransformer.configSummary(brooklyn(), ui.getBaseUriBuilder(), entity, adjunct, key));
 +        }
 +        return result;
 +    }
 +
 +    // TODO support parameters  ?show=value,summary&name=xxx &format={string,json,xml}
 +    // (and in sensors class)
 +    @Override
 +    public Map<String, Object> batchConfigRead(String application, String entityToken, String adjunctToken) {
 +        // TODO: add test
 +        return EntityTransformer.getConfigValues(brooklyn(), brooklyn().getAdjunct(application, entityToken, adjunctToken) );
 +    }
 +
 +    @Override
 +    public String getConfig(String application, String entityToken, String adjunctToken, String configKeyName) {
 +        EntityAdjunct adjunct = brooklyn().getAdjunct(application, entityToken, adjunctToken);
 +        Set<ConfigKey<?>> cki = adjunct.config().findKeysDeclared(ConfigPredicates.nameSatisfies(Predicates.equalTo(configKeyName)));
 +        if (cki.isEmpty()) throw WebResourceUtils.notFound("Cannot find config key '%s' in policy '%s' of entity '%s'", configKeyName, adjunctToken, entityToken);
 +
 +        return brooklyn().getStringValueForDisplay(adjunct.config().get(cki.iterator().next()));
 +    }
 +
 +    @SuppressWarnings({ "unchecked", "rawtypes" })
 +    @Override
 +    public Response setConfig(String application, String entityToken, String adjunctToken, String configKeyName, Object value) {
 +        Entity entity = brooklyn().getEntity(application, entityToken);
 +        if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.MODIFY_ENTITY, entity)) {
 +            throw WebResourceUtils.forbidden("User '%s' is not authorized to modify entity '%s'",
 +                    Entitlements.getEntitlementContext().user(), entity);
 +        }
 +
 +        EntityAdjunct adjunct = brooklyn().getAdjunct(entity, adjunctToken);
 +        Set<ConfigKey<?>> cki = adjunct.config().findKeysDeclared(ConfigPredicates.nameSatisfies(Predicates.equalTo(configKeyName)));
 +        if (cki.isEmpty()) throw WebResourceUtils.notFound("Cannot find config key '%s' in policy '%s' of entity '%s'", configKeyName, adjunctToken, entityToken);
 +        ConfigKey<?> ck = cki.iterator().next();
 +        
 +        adjunct.config().set((ConfigKey) cki, TypeCoercions.coerce(value, ck.getTypeToken()));
 +
 +        return Response.status(Response.Status.OK).build();
 +    }
 +
 +    public static String getStringValueForDisplay(BrooklynRestResourceUtils utils, EntityAdjunct policy, Object value) {
 +        return utils.getStringValueForDisplay(value);
 +    }
 +    
 +}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/62bcbc5f/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/EntityConfigResource.java
----------------------------------------------------------------------
diff --cc rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/EntityConfigResource.java
index d85f1d7,d85f1d7..dd909e4
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/EntityConfigResource.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/EntityConfigResource.java
@@@ -32,7 -32,7 +32,7 @@@ import org.apache.brooklyn.core.entity.
  import org.apache.brooklyn.core.mgmt.entitlement.Entitlements;
  import org.apache.brooklyn.core.mgmt.entitlement.Entitlements.EntityAndItem;
  import org.apache.brooklyn.rest.api.EntityConfigApi;
--import org.apache.brooklyn.rest.domain.EntityConfigSummary;
++import org.apache.brooklyn.rest.domain.ConfigSummary;
  import org.apache.brooklyn.rest.filter.HaHotStateRequired;
  import org.apache.brooklyn.rest.transform.EntityTransformer;
  import org.apache.brooklyn.rest.util.WebResourceUtils;
@@@ -52,7 -52,7 +52,7 @@@ public class EntityConfigResource exten
      private static final Logger LOG = LoggerFactory.getLogger(EntityConfigResource.class);
  
      @Override
--    public List<EntityConfigSummary> list(final String application, final String entityToken) {
++    public List<ConfigSummary> list(final String application, final String entityToken) {
          final Entity entity = brooklyn().getEntity(application, entityToken);
          if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_ENTITY, entity)) {
              throw WebResourceUtils.forbidden("User '%s' is not authorized to see entity '%s'",
@@@ -61,7 -61,7 +61,7 @@@
  
          // TODO merge with keys which have values:
          //      ((EntityInternal) entity).config().getBag().getAllConfigAsConfigKeyMap();
--        List<EntityConfigSummary> result = Lists.newArrayList();
++        List<ConfigSummary> result = Lists.newArrayList();
          
          for (ConfigKey<?> key : entity.getEntityType().getConfigKeys()) {
              // Exclude config that user is not allowed to see
@@@ -70,7 -70,7 +70,7 @@@
                          new Object[] {Entitlements.getEntitlementContext().user(), key.getName(), entity});
                  continue;
              }
--            result.add(EntityTransformer.entityConfigSummary(entity, key, ui.getBaseUriBuilder()));
++            result.add(EntityTransformer.configSummary(brooklyn(), ui.getBaseUriBuilder(), entity, key));
          }
          
          return result;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/62bcbc5f/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java
----------------------------------------------------------------------
diff --cc rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java
index db7d4cd,0000000..f841f33
mode 100644,000000..100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java
@@@ -1,117 -1,0 +1,116 @@@
 +/*
 + * Licensed to the Apache Software Foundation (ASF) under one
 + * or more contributor license agreements.  See the NOTICE file
 + * distributed with this work for additional information
 + * regarding copyright ownership.  The ASF licenses this file
 + * to you under the Apache License, Version 2.0 (the
 + * "License"); you may not use this file except in compliance
 + * with the License.  You may obtain a copy of the License at
 + *
 + *     http://www.apache.org/licenses/LICENSE-2.0
 + *
 + * Unless required by applicable law or agreed to in writing,
 + * software distributed under the License is distributed on an
 + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 + * KIND, either express or implied.  See the License for the
 + * specific language governing permissions and limitations
 + * under the License.
 + */
 +package org.apache.brooklyn.rest.transform;
 +
 +import static org.apache.brooklyn.rest.util.WebResourceUtils.serviceUriBuilder;
 +
 +import java.net.URI;
 +import java.util.Map;
 +
++import javax.annotation.Nullable;
 +import javax.ws.rs.core.UriBuilder;
 +
 +import org.apache.brooklyn.api.entity.Entity;
 +import org.apache.brooklyn.api.objs.EntityAdjunct;
++import org.apache.brooklyn.api.objs.SpecParameter;
 +import org.apache.brooklyn.api.policy.Policy;
 +import org.apache.brooklyn.api.sensor.Feed;
 +import org.apache.brooklyn.config.ConfigKey;
 +import org.apache.brooklyn.core.policy.Policies;
 +import org.apache.brooklyn.rest.api.AdjunctApi;
 +import org.apache.brooklyn.rest.api.ApplicationApi;
 +import org.apache.brooklyn.rest.api.EntityApi;
- import org.apache.brooklyn.rest.domain.AdjunctConfigSummary;
 +import org.apache.brooklyn.rest.domain.AdjunctDetail;
 +import org.apache.brooklyn.rest.domain.AdjunctSummary;
- import org.apache.brooklyn.rest.domain.ApplicationSummary;
++import org.apache.brooklyn.rest.domain.ConfigSummary;
 +import org.apache.brooklyn.rest.domain.Status;
 +import org.apache.brooklyn.rest.util.BrooklynRestResourceUtils;
 +import org.apache.brooklyn.util.collections.MutableMap;
 +
 +import com.google.common.base.Predicates;
- import com.google.common.collect.ImmutableMap;
 +
 +/**
 + * Converts from Brooklyn entities to restful API summary objects
 + */
 +public class AdjunctTransformer {
 +
 +    public static AdjunctSummary adjunctSummary(Entity entity, EntityAdjunct adjunct, UriBuilder ub) {
 +        return embellish(new AdjunctSummary(adjunct), entity, adjunct, ub);
 +    }
 +
 +    @SuppressWarnings("unchecked")
 +    private static <T extends AdjunctSummary> T embellish(T adjunctSummary, Entity entity, EntityAdjunct adjunct, UriBuilder ub) {
 +        return (T) adjunctSummary.state(inferStatus(adjunct)).links( buildLinks(entity, adjunct, ub, adjunctSummary instanceof AdjunctDetail) );
 +    }
 +
 +    public static AdjunctDetail adjunctDetail(BrooklynRestResourceUtils utils, Entity entity, EntityAdjunct adjunct, UriBuilder ub) {
 +        AdjunctDetail result = embellish(new AdjunctDetail(adjunct), entity, adjunct, ub);
 +        for (ConfigKey<?> key: adjunct.config().findKeysDeclared(Predicates.alwaysTrue())) {
-             result.parameter(configSummary(utils, entity, adjunct, key, ub));
++            result.parameter(configSummary(utils, ub, entity, adjunct, key));
 +        }
 +        result.config(EntityTransformer.getConfigValues(utils, adjunct));
 +        return result;
 +    }
 +
 +    protected static Map<String, URI> buildLinks(Entity entity, EntityAdjunct adjunct, UriBuilder ub, boolean detail) {
 +        MutableMap<String,URI> links = MutableMap.of();
 +
 +        links.put("self", serviceUriBuilder(ub, AdjunctApi.class, "get").build(entity.getApplicationId(), entity.getId(), adjunct.getId()));
 +        
 +        if (detail) {
 +            links.put("application", serviceUriBuilder(ub, ApplicationApi.class, "get").build(entity.getApplicationId()));
 +            links.put("entity", serviceUriBuilder(ub, EntityApi.class, "get").build(entity.getApplicationId(), entity.getId()));
 +            links.put("config", serviceUriBuilder(ub, AdjunctApi.class, "listConfig").build(entity.getApplicationId(), entity.getId(), adjunct.getId()));
 +            links.put("status", serviceUriBuilder(ub, AdjunctApi.class, "getStatus").build(entity.getApplicationId(), entity.getId(), adjunct.getId()));
 +            if (adjunct instanceof Policy || adjunct instanceof Feed) {
 +                links.put("start", serviceUriBuilder(ub, AdjunctApi.class, "start").build(entity.getApplicationId(), entity.getId(), adjunct.getId()));
 +                links.put("stop", serviceUriBuilder(ub, AdjunctApi.class, "stop").build(entity.getApplicationId(), entity.getId(), adjunct.getId()));
 +            }
 +            links.put("destroy", serviceUriBuilder(ub, AdjunctApi.class, "destroy").build(entity.getApplicationId(), entity.getId(), adjunct.getId()));
 +        }
 +        
 +        return links.asUnmodifiable();
 +    }
 +
 +    public static Status inferStatus(EntityAdjunct adjunct) {
 +        return ApplicationTransformer.statusFromLifecycle( Policies.inferAdjunctStatus(adjunct) );
 +    }
 +
-     public static AdjunctConfigSummary configSummary(BrooklynRestResourceUtils utils, ApplicationSummary application, Entity entity, EntityAdjunct adjunct, ConfigKey<?> config, UriBuilder ub) {
-         return configSummary(utils, entity, adjunct, config, ub);
++    public static ConfigSummary configSummary(BrooklynRestResourceUtils utils, UriBuilder ub, @Nullable Entity entity, @Nullable EntityAdjunct adjunct, SpecParameter<?> input) {
++        Double priority = input.isPinned() ? Double.valueOf(1d) : null;
++        return configSummary(utils, ub, entity, adjunct, input.getConfigKey(), input.getLabel(), priority, input.isPinned());
 +    }
 +
-     public static AdjunctConfigSummary configSummary(BrooklynRestResourceUtils utils, Entity entity, EntityAdjunct adjunct, ConfigKey<?> config, UriBuilder ub) {
-         URI applicationUri = serviceUriBuilder(ub, ApplicationApi.class, "get").build(entity.getApplicationId());
-         URI entityUri = serviceUriBuilder(ub, EntityApi.class, "get").build(entity.getApplicationId(), entity.getId());
-         URI adjunctUri = serviceUriBuilder(ub, AdjunctApi.class, "get").build(entity.getApplicationId(), entity.getId(), adjunct.getId());
-         URI configUri = serviceUriBuilder(ub, AdjunctApi.class, "getConfig").build(entity.getApplicationId(), entity.getId(), adjunct.getId(), config.getName());
- 
-         Map<String, URI> links = ImmutableMap.<String, URI>builder()
-                 .put("self", configUri)
-                 .put("application", applicationUri)
-                 .put("entity", entityUri)
-                 .put("policy", adjunctUri)
++    public static ConfigSummary configSummary(BrooklynRestResourceUtils utils, UriBuilder ub, Entity entity, EntityAdjunct adjunct, ConfigKey<?> config) {
++        // TODO get catalog info from other sources?
++        // see EntityTransformer.configSummary
++        return configSummary(utils, ub, entity, adjunct, config, null, null, null);
++    }
++    public static ConfigSummary configSummary(BrooklynRestResourceUtils utils, UriBuilder ub, @Nullable Entity entity, @Nullable EntityAdjunct adjunct, ConfigKey<?> config, String label, Double priority, Boolean pinned) {
++        URI configUri = entity==null ? null : serviceUriBuilder(ub, AdjunctApi.class, "getConfig").build(entity.getApplicationId(), entity.getId(), adjunct.getId(), config.getName());
++        Map<String, URI> links = MutableMap.<String, URI>builder()
++                .putIfNotNull("self", configUri)
++                // no point in including app/entity on every summary shown in a list
++                // (this is only ever used in a list, as self points at the value)
 +                .build();
 +
-         return new AdjunctConfigSummary(config.getName(), config.getTypeName(), config.getDescription(), 
-                 utils.getStringValueForDisplay(config.getDefaultValue()), 
-                 config.isReconfigurable(), 
-                 links);
++        // TODO get actions, see EntityTransformer.configSummary
++        return new ConfigSummary(config, label, priority, pinned, links);
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/62bcbc5f/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/EntityTransformer.java
----------------------------------------------------------------------
diff --cc rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/EntityTransformer.java
index cb7877f,73b2831..9359bb5
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/EntityTransformer.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/EntityTransformer.java
@@@ -126,58 -120,58 +126,78 @@@ public class EntityTransformer 
              }));
      }
  
++    /** @deprecated since 0.13.0 use {@link #configSummary(BrooklynRestResourceUtils, UriBuilder, Entity, ConfigKey, String, Double, Boolean) */
++    @Deprecated
      public static EntityConfigSummary entityConfigSummary(ConfigKey<?> config, String label, Double priority, Boolean pinned, Map<String, URI> links) {
--        Map<String, URI> mapOfLinks =  links==null ? null : ImmutableMap.copyOf(links);
--        return new EntityConfigSummary(config, label, priority, pinned, mapOfLinks);
--    }
--
-     public static AdjunctConfigSummary adjunctConfigSummary(ConfigKey<?> config, String label, Double priority, Map<String, URI> links) {
-         return new AdjunctConfigSummary(config, label, priority, links);
 -    public static ConfigSummary configSummary(ConfigKey<?> config, String label, Double priority, Boolean pinned, Map<String, URI> links) {
 -        return new ConfigSummary(config, label, priority, pinned, links);
++        return new EntityConfigSummary(config, label, priority, pinned, links);
      }
  
++    /** @deprecated since 0.13.0 use {@link AdjunctTransformer#configSummary(BrooklynRestResourceUtils, UriBuilder, Entity, org.apache.brooklyn.api.objs.EntityAdjunct, ConfigKey, String, Double, Boolean)} */
++    @Deprecated
      public static PolicyConfigSummary policyConfigSummary(ConfigKey<?> config, String label, Double priority, Map<String, URI> links) {
          return new PolicyConfigSummary(config, label, priority, links);
      }
  
++    /** @deprecated since 0.13.0 use {@link AdjunctTransformer#configSummary(BrooklynRestResourceUtils, UriBuilder, Entity, org.apache.brooklyn.api.objs.EntityAdjunct, ConfigKey, String, Double, Boolean)} */
++    @Deprecated
      public static EnricherConfigSummary enricherConfigSummary(ConfigKey<?> config, String label, Double priority, Map<String, URI> links) {
          return new EnricherConfigSummary(config, label, priority, links);
      }
  
      /** generates a representation for a given config key, 
       * with label inferred from annoation in the entity class,
--     * and links pointing to the entity and the applicaiton */
++     * and links pointing to the entity and the application 
++     * @deprecated since 0.13.0 use {@link #configSummary(BrooklynRestResourceUtils, UriBuilder, Entity, ConfigKey)} */
++    @Deprecated
      public static EntityConfigSummary entityConfigSummary(Entity entity, ConfigKey<?> config, UriBuilder ub) {
--      /*
--       * following code nearly there to get the @CatalogConfig annotation
--       * in the class and use that to populate a label
--       */
--
--//    EntityDynamicType typeMap = 
--//            ((AbstractEntity)entity).getMutableEntityType();
--//      // above line works if we can cast; line below won't work, but there should some way
--//      // to get back the handle to the spec from an entity local, which then *would* work
--//            EntityTypes.getDefinedEntityType(entity.getClass());
++        return (EntityConfigSummary) configSummary(null, ub, entity, config);
++    }
++    
++    public static ConfigSummary configSummary(BrooklynRestResourceUtils utils, UriBuilder ub, Entity entity, ConfigKey<?> config) {
++        // TODO get catalog/display info
++        
++        /*
++         * following code nearly there to get the @CatalogConfig annotation
++         * in the class and use that to populate a label
++         */
  
--//    String label = typeMap.getConfigKeyField(config.getName());
--        String label = null;
--        Double priority = null;
++//      EntityDynamicType typeMap = 
++//              ((AbstractEntity)entity).getMutableEntityType();
++//        // above line works if we can cast; line below won't work, but there should some way
++//        // to get back the handle to the spec from an entity local, which then *would* work
++//              EntityTypes.getDefinedEntityType(entity.getClass());
  
--        URI applicationUri = serviceUriBuilder(ub, ApplicationApi.class, "get").build(entity.getApplicationId());
--        URI entityUri = serviceUriBuilder(ub, EntityApi.class, "get").build(entity.getApplicationId(), entity.getId());
--        URI selfUri = serviceUriBuilder(ub, EntityConfigApi.class, "get").build(entity.getApplicationId(), entity.getId(), config.getName());
++//      String label = typeMap.getConfigKeyField(config.getName());
++        return configSummary(null, ub, entity, config, null);
++    }
++    public static ConfigSummary configSummary(BrooklynRestResourceUtils utils, UriBuilder ub, Entity entity, ConfigKey<?> config, CatalogConfig annotation) {
++        String label = annotation==null ? null : annotation.label();
++        Double priority = annotation==null ? null : annotation.priority();
++        boolean pinned = annotation!=null && annotation.pinned();
++        return configSummary(utils, ub, entity, config, label, priority, pinned);
++    }
++    public static ConfigSummary configSummary(BrooklynRestResourceUtils utils, UriBuilder ub, Entity entity, ConfigKey<?> config, String label, Double priority, Boolean pinned) {
++        // entity can be null if coming from catalog
++        URI applicationUri = entity==null ? null : serviceUriBuilder(ub, ApplicationApi.class, "get").build(entity.getApplicationId());
++        URI entityUri = entity==null ? null : serviceUriBuilder(ub, EntityApi.class, "get").build(entity.getApplicationId(), entity.getId());
++        URI selfUri = entity==null ? null : serviceUriBuilder(ub, EntityConfigApi.class, "get").build(entity.getApplicationId(), entity.getId(), config.getName());
          
          MutableMap.Builder<String, URI> lb = MutableMap.<String, URI>builder()
--            .put("self", selfUri)
--            .put("application", applicationUri)
--            .put("entity", entityUri)
--            .put("action:json", selfUri);
++            .putIfNotNull("self", selfUri)
++            // TODO wasteful including these on every item as it is just a list, remove
++            .putIfNotNull("application", applicationUri)
++            .putIfNotNull("entity", entityUri)
++            // TODO is this json or a display value?
++            .putIfNotNull("action:json", selfUri);
  
          Iterable<RendererHints.NamedAction> hints = Iterables.filter(RendererHints.getHintsFor(config), RendererHints.NamedAction.class);
          for (RendererHints.NamedAction na : hints) {
--            SensorTransformer.addNamedAction(lb, na, entity.getConfig(config), config, entity);
++            if (entity!=null) {
++                SensorTransformer.addNamedAction(lb, na, entity.getConfig(config), config, entity);
++            }
          }
      
--        return entityConfigSummary(config, label, priority, null, lb.build());
++        return new EntityConfigSummary(config, label, priority, pinned, lb.build());
      }
  
      public static URI applicationUri(Application entity, UriBuilder ub) {
@@@ -188,6 -182,6 +208,8 @@@
          return serviceUriBuilder(ub, EntityApi.class, "get").build(entity.getApplicationId(), entity.getId());
      }
      
++    /** @deprecated since 0.13.0 use {@link #configSummary(BrooklynRestResourceUtils, UriBuilder, Entity, ConfigKey, CatalogConfig) */
++    @Deprecated
      public static EntityConfigSummary entityConfigSummary(ConfigKey<?> config, Field configKeyField) {
          CatalogConfig catalogConfig = configKeyField!=null ? configKeyField.getAnnotation(CatalogConfig.class) : null;
          String label = catalogConfig==null ? null : catalogConfig.label();
@@@ -196,6 -190,6 +218,8 @@@
          return entityConfigSummary(config, label, priority, pinned, null);
      }
  
++    /** @deprecated since 0.13.0 use {@link #configSummary(BrooklynRestResourceUtils, UriBuilder, Entity, ConfigKey, AtomicInteger) */
++    @Deprecated
      public static EntityConfigSummary entityConfigSummary(SpecParameter<?> input, AtomicInteger paramPriorityCnt) {
          // Increment the priority because the config container is a set. Server-side we are using an ordered set
          // which results in correctly ordered items on the wire (as a list). Clients which use the java bindings
@@@ -204,16 -198,17 +228,39 @@@
          return entityConfigSummary(input.getConfigKey(), input.getLabel(), priority, input.isPinned(), null);
      }
  
-     public static AdjunctConfigSummary adjunctConfigSummary(SpecParameter<?> input) {
++    /** @deprecated since 0.13.0 use {@link #configSummary(BrooklynRestResourceUtils, UriBuilder, Entity, SpecParameter) */
++    @Deprecated
+     public static ConfigSummary configSummary(SpecParameter<?> input) {
 -        // could increment priority, or take from annotation, or introduce new field
++        // TODO could increment priority, or take from annotation, or introduce new field
          Double priority = input.isPinned() ? Double.valueOf(1d) : null;
-         return policyConfigSummary(input.getConfigKey(), input.getLabel(), priority, null);
 -        return configSummary(input.getConfigKey(), input.getLabel(), priority, input.isPinned(), null);
++        return new EntityConfigSummary(input.getConfigKey(), input.getLabel(), priority, input.isPinned(), null);
      }
  
++    
++    public static ConfigSummary configSummary(BrooklynRestResourceUtils utils, UriBuilder ub, Entity entity, SpecParameter<?> input, AtomicInteger paramPriorityCnt) {
++        // Increment the priority because the config container is a set. Server-side we are using an ordered set
++        // which results in correctly ordered items on the wire (as a list). Clients which use the java bindings
++        // though will push the items in an unordered set - so give them means to recover the correct order.
++        Double priority = input.isPinned() ? Double.valueOf(paramPriorityCnt.incrementAndGet()) : null;
++        return configSummary(utils, ub, entity, input.getConfigKey(), input.getLabel(), priority, input.isPinned());
++    }
++
++    public static ConfigSummary configSummary(BrooklynRestResourceUtils utils, UriBuilder ub, Entity entity, SpecParameter<?> input) {
++        // TODO allow taking priority from a setting somewhere?
++        // (this just sets priority 1 if no value specified)
++        return configSummary(utils, ub, entity, input, new AtomicInteger(0));
++    }
++
++
++    /** @deprecated since 0.13.0 use {@link AdjunctTransformer#configSummary(BrooklynRestResourceUtils, UriBuilder, Entity, org.apache.brooklyn.api.objs.EntityAdjunct, SpecParameter)} */
++    @Deprecated
      public static PolicyConfigSummary policyConfigSummary(SpecParameter<?> input) {
          Double priority = input.isPinned() ? Double.valueOf(1d) : null;
          return policyConfigSummary(input.getConfigKey(), input.getLabel(), priority, null);
      }
  
++    /** @deprecated since 0.13.0 use {@link AdjunctTransformer#configSummary(BrooklynRestResourceUtils, UriBuilder, Entity, org.apache.brooklyn.api.objs.EntityAdjunct, SpecParameter)} */
++    @Deprecated
      public static EnricherConfigSummary enricherConfigSummary(SpecParameter<?> input) {
          Double priority = input.isPinned() ? Double.valueOf(1d) : null;
          return enricherConfigSummary(input.getConfigKey(), input.getLabel(), priority, null);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/62bcbc5f/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/PolicyTransformer.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/62bcbc5f/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/TypeTransformer.java
----------------------------------------------------------------------
diff --cc rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/TypeTransformer.java
index fb3fdd3,e37ee6a..d081efd
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/TypeTransformer.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/TypeTransformer.java
@@@ -50,11 -50,11 +50,10 @@@ import org.apache.brooklyn.core.objs.Br
  import org.apache.brooklyn.core.typereg.RegisteredTypePredicates;
  import org.apache.brooklyn.core.typereg.RegisteredTypes;
  import org.apache.brooklyn.rest.api.TypeApi;
- import org.apache.brooklyn.rest.domain.AdjunctConfigSummary;
  import org.apache.brooklyn.rest.domain.BundleInstallationRestResult;
  import org.apache.brooklyn.rest.domain.BundleSummary;
+ import org.apache.brooklyn.rest.domain.ConfigSummary;
  import org.apache.brooklyn.rest.domain.EffectorSummary;
--import org.apache.brooklyn.rest.domain.EntityConfigSummary;
  import org.apache.brooklyn.rest.domain.SensorSummary;
  import org.apache.brooklyn.rest.domain.SummaryComparators;
  import org.apache.brooklyn.rest.domain.TypeDetail;
@@@ -96,14 -96,14 +95,15 @@@ public class TypeTransformer 
                      RegisteredTypes.isSubtypeOf(item, Policy.class) || RegisteredTypes.isSubtypeOf(item, Enricher.class) || RegisteredTypes.isSubtypeOf(item, Feed.class)
                      ) {
                  try {
-                     Set<AdjunctConfigSummary> config = Sets.newLinkedHashSet();
+                     Set<ConfigSummary> config = Sets.newLinkedHashSet();
                      
                      AbstractBrooklynObjectSpec<?,?> spec = b.getTypeRegistry().createSpec(item, null, null);
++                    AtomicInteger priority = new AtomicInteger(0);
                      for (final SpecParameter<?> input : spec.getParameters()){
-                         config.add(EntityTransformer.adjunctConfigSummary(input));
 -                        config.add(EntityTransformer.configSummary(input));
++                        config.add(EntityTransformer.configSummary(null, null, null, input, priority));
                      }
                      
-                     result.getExtraFields().put("config", config);
+                     result.setExtraField("config", config);
                  } catch (Exception e) {
                      Exceptions.propagateIfFatal(e);
                      log.trace("Unable to create spec for "+item+": "+e, e);
@@@ -119,7 -119,7 +119,7 @@@
  
      protected static <T extends TypeSummary> void embellishEntity(T result, RegisteredType item, BrooklynRestResourceUtils b) {
          try {
--            Set<EntityConfigSummary> config = Sets.newLinkedHashSet();
++            Set<ConfigSummary> config = Sets.newLinkedHashSet();
              Set<SensorSummary> sensors = Sets.newTreeSet(SummaryComparators.nameComparator());
              Set<EffectorSummary> effectors = Sets.newTreeSet(SummaryComparators.nameComparator());
        
@@@ -129,7 -129,7 +129,7 @@@
     
              AtomicInteger paramPriorityCnt = new AtomicInteger();
              for (SpecParameter<?> input: spec.getParameters())
--                config.add(EntityTransformer.entityConfigSummary(input, paramPriorityCnt));
++                config.add(EntityTransformer.configSummary(null, null, null, input, paramPriorityCnt));
              for (Sensor<?> x: type.getSensors())
                  sensors.add(SensorTransformer.sensorSummaryForCatalog(x));
              for (Effector<?> x: type.getEffectors())

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/62bcbc5f/server-cli/src/main/java/org/apache/brooklyn/cli/lister/ItemDescriptors.java
----------------------------------------------------------------------
diff --cc server-cli/src/main/java/org/apache/brooklyn/cli/lister/ItemDescriptors.java
index f245d06,f245d06..61a7a2a
--- a/server-cli/src/main/java/org/apache/brooklyn/cli/lister/ItemDescriptors.java
+++ b/server-cli/src/main/java/org/apache/brooklyn/cli/lister/ItemDescriptors.java
@@@ -18,16 -18,16 +18,18 @@@
   */
  package org.apache.brooklyn.cli.lister;
  
--import java.net.URI;
++import java.lang.reflect.Field;
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.Comparator;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
++import java.util.concurrent.atomic.AtomicInteger;
  
  import org.apache.brooklyn.api.catalog.BrooklynCatalog;
  import org.apache.brooklyn.api.catalog.Catalog;
++import org.apache.brooklyn.api.catalog.CatalogConfig;
  import org.apache.brooklyn.api.catalog.CatalogItem;
  import org.apache.brooklyn.api.effector.Effector;
  import org.apache.brooklyn.api.entity.EntityType;
@@@ -41,8 -41,8 +43,8 @@@ import org.apache.brooklyn.config.Confi
  import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
  import org.apache.brooklyn.core.objs.BrooklynDynamicType;
  import org.apache.brooklyn.core.objs.BrooklynTypes;
++import org.apache.brooklyn.rest.domain.ConfigSummary;
  import org.apache.brooklyn.rest.domain.EffectorSummary;
--import org.apache.brooklyn.rest.domain.EntityConfigSummary;
  import org.apache.brooklyn.rest.domain.SensorSummary;
  import org.apache.brooklyn.rest.domain.SummaryComparators;
  import org.apache.brooklyn.rest.transform.EffectorTransformer;
@@@ -131,12 -131,12 +133,14 @@@ public class ItemDescriptors 
          }
          
          if (!headingsOnly) {
--            Set<EntityConfigSummary> config = Sets.newTreeSet(SummaryComparators.nameComparator());
++            Set<ConfigSummary> config = Sets.newTreeSet(SummaryComparators.nameComparator());
              Set<SensorSummary> sensors = Sets.newTreeSet(SummaryComparators.nameComparator());
              Set<EffectorSummary> effectors = Sets.newTreeSet(SummaryComparators.nameComparator());
  
              for (ConfigKey<?> x: type.getConfigKeys()) {
--                config.add(EntityTransformer.entityConfigSummary(x, dynamicType.getConfigKeyField(x.getName())));
++                Field field = dynamicType.getConfigKeyField(x.getName());
++                CatalogConfig annotation = field==null ? null : field.getAnnotation(CatalogConfig.class);
++                config.add(EntityTransformer.configSummary(null, null, null, x, annotation));
              }
              result.put("config", config);
              
@@@ -184,7 -184,7 +188,7 @@@
      public static Map<String, Object> toItemDescriptor(BrooklynCatalog catalog, CatalogItem<?, ?> item, boolean headingsOnly) {
          Map<String,Object> itemDescriptor = MutableMap.of();
          AbstractBrooklynObjectSpec<?,?> spec = catalog.peekSpec(item);
--        List<EntityConfigSummary> config = new ArrayList<>();
++        List<ConfigSummary> config = new ArrayList<>();
  
          if (item.getDisplayName() != null) {
              itemDescriptor.put("name", item.getDisplayName());
@@@ -199,19 -199,19 +203,9 @@@
          itemDescriptor.put("iconUrl", blankIfNull(item.getIconUrl()));
  
          if (!headingsOnly) {
--            double priorityCounter = 0.0d;
++            AtomicInteger priority = new AtomicInteger(0);
              for (SpecParameter<?> param: spec.getParameters()) {
--                Double priority;
--                if (param.isPinned()) {
--                    priority = priorityCounter;
--                    priorityCounter++;
--                } else {
--                    priority = null;
--                }
--
--                EntityConfigSummary entityConfigSummary = EntityTransformer.entityConfigSummary(param.getConfigKey(),
--                    param.getLabel(), priority, param.isPinned(), MutableMap.<String,URI>of());
--                config.add(entityConfigSummary);
++                config.add(EntityTransformer.configSummary(null, null, null, param, priority));
              }
              itemDescriptor.put("config", config);
          }


[19/35] brooklyn-server git commit: preserve errors as much as possible when submitted to run in same thread

Posted by he...@apache.org.
preserve errors as much as possible when submitted to run in same thread


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

Branch: refs/heads/master
Commit: 24250a5e2c4e380b06e72fc9db52d3e5989fd00e
Parents: 26dffef
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Sat Sep 16 04:43:31 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Sat Sep 16 04:44:12 2017 +0100

----------------------------------------------------------------------
 .../util/core/task/BasicExecutionContext.java   | 51 +++++++++++---------
 1 file changed, 28 insertions(+), 23 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/24250a5e/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
index 73baef2..7953b14 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
@@ -133,16 +133,15 @@ public class BasicExecutionContext extends AbstractExecutionContext {
             }
         }
 
-        return runInSameThread(t, new Callable<Maybe<T>>() {
-            public Maybe<T> call() {
-                try {
+        try {
+            return runInSameThread(t, new Callable<Maybe<T>>() {
+                public Maybe<T> call() throws Exception {
                     return Maybe.of(t.getJob().call());
-                } catch (Exception e) {
-                    Exceptions.propagateIfFatal(e);
-                    return Maybe.absent(e);
                 }
-            }
-        }).get();
+            }).get();
+        } catch (Exception e) {
+            throw Exceptions.propagate(e);
+        }
     }
     
     private static class SimpleFuture<T> implements Future<T> {
@@ -190,7 +189,7 @@ public class BasicExecutionContext extends AbstractExecutionContext {
         }
     }
     
-    private <T> Maybe<T> runInSameThread(final Task<T> task, Callable<Maybe<T>> job) {
+    private <T> Maybe<T> runInSameThread(final Task<T> task, Callable<Maybe<T>> job) throws Exception {
         ((TaskInternal<T>)task).getMutableTags().addAll(tags);
         
         Task<?> previousTask = BasicExecutionManager.getPerThreadCurrentTask().get();
@@ -209,9 +208,11 @@ public class BasicExecutionContext extends AbstractExecutionContext {
             return future.set(job.call());
             
         } catch (Exception e) {
-            error = e;
             future.set(Maybe.absent(e));
-            throw Exceptions.propagate(e);
+            Exceptions.propagateIfInterrupt(e);
+            error = e;
+            // error above will be rethrown by `afterEnd`
+            return null;  // not actually returned
             
         } finally {
             try {
@@ -252,19 +253,23 @@ public class BasicExecutionContext extends AbstractExecutionContext {
         fakeTaskForContext.tags.add(BrooklynTaskTags.IMMEDIATE_TASK_TAG);
         fakeTaskForContext.tags.add(BrooklynTaskTags.TRANSIENT_TASK_TAG);
 
-        return runInSameThread(fakeTaskForContext, new Callable<Maybe<T>>() {
-            public Maybe<T> call() {
-                fakeTaskForContext.cancel();
-                
-                boolean wasAlreadyInterrupted = Thread.interrupted();
-                try {
-                    return job.getImmediately();
-                } finally {
-                    if (wasAlreadyInterrupted) {
-                        Thread.currentThread().interrupt();
+        try {
+            return runInSameThread(fakeTaskForContext, new Callable<Maybe<T>>() {
+                public Maybe<T> call() {
+                    fakeTaskForContext.cancel();
+                    
+                    boolean wasAlreadyInterrupted = Thread.interrupted();
+                    try {
+                        return job.getImmediately();
+                    } finally {
+                        if (wasAlreadyInterrupted) {
+                            Thread.currentThread().interrupt();
+                        }
                     }
-                }
-            } });
+                } });
+        } catch (Exception e) {
+            throw Exceptions.propagate(e);
+        }
     }
     
     @SuppressWarnings({ "unchecked", "rawtypes" })


[18/35] brooklyn-server git commit: more tests for edge case where cancel doesn't cause listeners to run, and more tests for cancel

Posted by he...@apache.org.
more tests for edge case where cancel doesn't cause listeners to run, and more tests for cancel


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

Branch: refs/heads/master
Commit: 26dffef47d5d443b538d0b5a16dc133f01960372
Parents: 62359c6
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Sep 15 17:43:58 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Sat Sep 16 03:29:04 2017 +0100

----------------------------------------------------------------------
 .../util/core/task/BasicTasksFutureTest.java    | 50 ++++++++++++--------
 1 file changed, 31 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/26dffef4/core/src/test/java/org/apache/brooklyn/util/core/task/BasicTasksFutureTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/util/core/task/BasicTasksFutureTest.java b/core/src/test/java/org/apache/brooklyn/util/core/task/BasicTasksFutureTest.java
index 9d53532..a2bfd59 100644
--- a/core/src/test/java/org/apache/brooklyn/util/core/task/BasicTasksFutureTest.java
+++ b/core/src/test/java/org/apache/brooklyn/util/core/task/BasicTasksFutureTest.java
@@ -75,7 +75,7 @@ public class BasicTasksFutureTest {
 
     @Test
     public void testBlockAndGetWithTimeoutsAndListenableFuture() throws InterruptedException {
-        Task<String> t = waitForSemaphore(Duration.FIVE_SECONDS, true, "x");
+        Task<String> t = waitForSemaphore(Duration.FIVE_SECONDS, true, "x", true);
         
         Assert.assertFalse(t.blockUntilEnded(Duration.millis(1)));
         Assert.assertFalse(t.blockUntilEnded(Duration.ZERO));
@@ -149,11 +149,12 @@ public class BasicTasksFutureTest {
         Assert.fail("did not get data for '"+key+"' in time");
     }
 
-    private <T> Task<T> waitForSemaphore(final Duration time, final boolean requireSemaphore, final T result) {
-        return Tasks.<T>builder().body(new Callable<T>() {
+    private <T> Task<T> waitForSemaphore(final Duration time, final boolean requireSemaphore, final T result, boolean dynamic) {
+        return Tasks.<T>builder().dynamic(dynamic).body(new Callable<T>() {
             @Override
             public T call() { 
                 try {
+                    log.info("about to release semaphore");
                     started.release();
                     log.info("waiting up to "+time+" to acquire before returning "+result);
                     if (!waitInTask.tryAcquire(time.toMilliseconds(), TimeUnit.MILLISECONDS)) {
@@ -174,32 +175,43 @@ public class BasicTasksFutureTest {
     }
 
     @Test
-    public void testCancelAfterStartTriggersListenableFuture() throws Exception {
-        doTestCancelTriggersListenableFuture(Duration.millis(50));
+    public void testCancelAfterStartTriggersListenableFutureDynamic() throws Exception {
+        doTestCancelTriggersListenableFuture(Duration.millis(50), true);
     }
     @Test
-    public void testCancelImmediateTriggersListenableFuture() throws Exception {
+    public void testCancelImmediateTriggersListenableFutureDynamic() throws Exception {
         // if cancel fires after submit but before it passes to the executor,
-        // that needs handling separately; this doesn't guarantee this code path,
-        // but it happens sometimes (and it should be handled)
-        
-        // have seen this fail once, not getting "before", but can't see why, may be spurious
-        doTestCancelTriggersListenableFuture(Duration.ZERO);
+        // that needs handling separately as it falls into an edge where the future is set and cancelled
+        // so the executor won't run it, and our wrapper logic doesn't apply; 
+        // this test doesn't guarantee this code path, but makes it likely enough it happens once in a while.
+        doTestCancelTriggersListenableFuture(Duration.ZERO, true);
     }
     @Test
-    public void testCancelBeforeTriggersListenableFuture() throws Exception {
-        // if cancel fires after submit but before it passes to the executor,
-        // that needs handling separately; this doesn't guarantee this code path,
-        // but it happens sometimes (and it should be handled)
-        doTestCancelTriggersListenableFuture(Duration.millis(-50));
+    public void testCancelBeforeTriggersListenableFutureDynamic() throws Exception {
+        doTestCancelTriggersListenableFuture(Duration.millis(-50), true);
+    }
+    @Test
+    public void testCancelAfterStartTriggersListenableFutureSimple() throws Exception {
+        doTestCancelTriggersListenableFuture(Duration.millis(50), true);
+    }
+    @Test
+    public void testCancelImmediateTriggersListenableFutureSimple() throws Exception {
+        doTestCancelTriggersListenableFuture(Duration.ZERO, false);
+    }
+    @Test
+    public void testCancelBeforeTriggersListenableFutureSimple() throws Exception {
+        doTestCancelTriggersListenableFuture(Duration.millis(-50), false);
     }
-    public void doTestCancelTriggersListenableFuture(Duration delay) throws Exception {
-        Task<String> t = waitForSemaphore(Duration.TEN_SECONDS, true, "x");
+    public void doTestCancelTriggersListenableFuture(Duration delay, boolean dynamic) throws Exception {
+        Task<String> t = waitForSemaphore(Duration.TEN_SECONDS, true, "x", dynamic);
         addFutureListener(t, "before");
 
         Stopwatch watch = Stopwatch.createStarted();
         if (delay.isNegative()) {
-            new Thread(() -> { Time.sleep(delay.multiply(-1)); ec.submit(t); }).run(); 
+            new Thread(() -> {
+                Time.sleep(delay.multiply(-1)); 
+                ec.submit(t); 
+            }).start(); 
         } else {
             ec.submit(t);
         }


[25/35] brooklyn-server git commit: address issue of back-ref from BasicTask to BasicExecutionManager

Posted by he...@apache.org.
address issue of back-ref from BasicTask to BasicExecutionManager

by introducing interface for advanced cancellation semantics


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

Branch: refs/heads/master
Commit: 4b7844ce80eeee87f0b4ca1a44eb891c177548df
Parents: 8077f16
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Thu Sep 28 15:34:32 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Thu Sep 28 15:34:32 2017 +0100

----------------------------------------------------------------------
 .../util/core/task/BasicExecutionManager.java   |  5 +--
 .../brooklyn/util/core/task/BasicTask.java      |  5 ++-
 .../brooklyn/util/core/task/TaskInternal.java   |  7 ++---
 .../task/TaskInternalCancellableWithMode.java   | 32 ++++++++++++++++++++
 4 files changed, 39 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4b7844ce/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
index 5818568..c2bf12c 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
@@ -574,7 +574,7 @@ public class BasicExecutionManager implements ExecutionManager {
         }
     }
 
-    final static class CancellingListenableForwardingFutureForTask<T> extends SimpleForwardingFuture<T> implements ListenableFuture<T> {
+    final static class CancellingListenableForwardingFutureForTask<T> extends SimpleForwardingFuture<T> implements ListenableFuture<T>, TaskInternalCancellableWithMode {
         private final Task<T> task;
         private BasicExecutionManager execMgmt;
         private final ExecutionList listeners;
@@ -600,7 +600,8 @@ public class BasicExecutionManager implements ExecutionManager {
             return listeners;
         }
         
-        boolean cancel(TaskCancellationMode mode) {
+        @Override
+        public boolean cancel(TaskCancellationMode mode) {
             boolean result = false;
             if (log.isTraceEnabled()) {
                 log.trace("CLFFT cancelling "+task+" mode "+mode);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4b7844ce/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
index d952f9e..9367b4a 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
@@ -45,7 +45,6 @@ import org.apache.brooklyn.api.mgmt.HasTaskChildren;
 import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.api.objs.Identifiable;
 import org.apache.brooklyn.util.JavaGroovyEquivalents;
-import org.apache.brooklyn.util.core.task.BasicExecutionManager.CancellingListenableForwardingFutureForTask;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.guava.Maybe.MaybeSupplier;
@@ -330,8 +329,8 @@ public class BasicTask<T> implements TaskInternal<T> {
     
     protected boolean doCancel(TaskCancellationMode mode) {
         if (internalFuture!=null) { 
-            if (internalFuture instanceof CancellingListenableForwardingFutureForTask) {
-                return ((CancellingListenableForwardingFutureForTask<?>)internalFuture).cancel(mode);
+            if (internalFuture instanceof TaskInternalCancellableWithMode) {
+                return ((TaskInternalCancellableWithMode)internalFuture).cancel(mode);
             } else {
                 return internalFuture.cancel(mode.isAllowedToInterruptTask());
             }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4b7844ce/core/src/main/java/org/apache/brooklyn/util/core/task/TaskInternal.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/TaskInternal.java b/core/src/main/java/org/apache/brooklyn/util/core/task/TaskInternal.java
index c49544a..7c82f6e 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/TaskInternal.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/TaskInternal.java
@@ -45,7 +45,7 @@ import com.google.common.util.concurrent.ListenableFuture;
  * @author aled
  */
 @Beta
-public interface TaskInternal<T> extends Task<T> {
+public interface TaskInternal<T> extends Task<T>, TaskInternalCancellableWithMode {
     
     /** sets the internal future object used to record the association to a job submitted to an {@link ExecutorService} */
     void initInternalFuture(ListenableFuture<T> result);
@@ -128,12 +128,9 @@ public interface TaskInternal<T> extends Task<T> {
      * this returns the "real" task represented by this one */
     Task<?> getProxyTarget();
 
-    /** clearer semantics around cancellation; may be promoted to {@link Task} */
-    @Beta
-    public boolean cancel(TaskCancellationMode mode);
-    
     @Beta
     public static class TaskCancellationMode {
+        
         public static final TaskCancellationMode DO_NOT_INTERRUPT = new TaskCancellationMode(false, false, false);
         public static final TaskCancellationMode INTERRUPT_TASK_BUT_NOT_SUBMITTED_TASKS = new TaskCancellationMode(true, false, false);
         public static final TaskCancellationMode INTERRUPT_TASK_AND_DEPENDENT_SUBMITTED_TASKS = new TaskCancellationMode(true, true, false);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4b7844ce/core/src/main/java/org/apache/brooklyn/util/core/task/TaskInternalCancellableWithMode.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/TaskInternalCancellableWithMode.java b/core/src/main/java/org/apache/brooklyn/util/core/task/TaskInternalCancellableWithMode.java
new file mode 100644
index 0000000..75aac91
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/TaskInternalCancellableWithMode.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.core.task;
+
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.util.core.task.TaskInternal.TaskCancellationMode;
+
+import com.google.common.annotations.Beta;
+
+/** clearer semantics around cancellation; may be promoted to {@link Task} */
+@Beta
+public interface TaskInternalCancellableWithMode {
+
+    boolean cancel(TaskCancellationMode mode);
+
+}
\ No newline at end of file


[24/35] brooklyn-server git commit: address many of the PR comments, bigger ones to follow

Posted by he...@apache.org.
address many of the PR comments, bigger ones to follow


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

Branch: refs/heads/master
Commit: 8077f16a807ccd585a0f13310a5a44f278770864
Parents: 2bdcf1a
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Thu Sep 28 15:25:10 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Thu Sep 28 15:34:16 2017 +0100

----------------------------------------------------------------------
 .../util/core/task/BasicExecutionContext.java   | 16 +++++++++-----
 .../util/core/task/BasicExecutionManager.java   |  3 +--
 .../brooklyn/util/core/task/ValueResolver.java  |  3 ++-
 .../core/effector/EffectorSayHiTest.java        |  1 +
 .../util/core/task/BasicTasksFutureTest.java    | 23 ++++++++++----------
 .../core/task/NonBasicTaskExecutionTest.java    |  8 +------
 .../org/apache/brooklyn/util/guava/Maybe.java   |  2 +-
 .../apache/brooklyn/util/repeat/Repeater.java   |  7 ++++--
 8 files changed, 33 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8077f16a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
index 429cad7..5e645a9 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
@@ -98,7 +98,7 @@ public class BasicExecutionContext extends AbstractExecutionContext {
      * Creates an execution context which wraps {@link ExecutionManager}
      * adding the given tags to all tasks submitted through this context.
      */
-    public BasicExecutionContext(ExecutionManager executionManager, Iterable<Object> tagsForThisContext) {
+    public BasicExecutionContext(ExecutionManager executionManager, Iterable<?> tagsForThisContext) {
         this.executionManager = executionManager;
         if (tagsForThisContext!=null) Iterables.addAll(tags, tagsForThisContext);
 
@@ -128,11 +128,7 @@ public class BasicExecutionContext extends AbstractExecutionContext {
         final TaskInternal<T> t = (TaskInternal<T>) task.asTask();
         
         if (t.isQueuedOrSubmitted()) {
-            if (t.isDone()) {
-                return t.getUnchecked();
-            } else {
-                throw new ImmediateUnsupportedException("Task is in progress and incomplete: "+t);
-            }
+            return t.getUnchecked();
         }
         
         ContextSwitchingInfo<T> switchContextWrapper = getContextSwitchingTask(t, Collections.emptyList(), false);
@@ -151,6 +147,8 @@ public class BasicExecutionContext extends AbstractExecutionContext {
         }
     }
     
+    // could perhaps use Guava's SettableFuture -- though would have to take care re 
+    // supporting set(Maybe<T>)
     private static class SimpleFuture<T> implements Future<T> {
         boolean cancelled = false;
         boolean done = false;
@@ -206,6 +204,12 @@ public class BasicExecutionContext extends AbstractExecutionContext {
         }
     }
     
+    /** Internal utility method to avoid replication between 
+     * implementations in {@link #get(Task)} and {@link #getImmediately(Object)}.
+     * The two submit different jobs but after doing a lot of the same setup and catch/finally.
+     * Logic re return type is a little fiddly given the differences but should be clearer
+     * seeing how the two work (as opposed to this method being designed as something
+     * more generally useful). */
     private <T> Maybe<T> runInSameThread(final Task<T> task, Callable<Maybe<T>> job) throws Exception {
         ((TaskInternal<T>)task).getMutableTags().addAll(tags);
         

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8077f16a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
index 4fcfadb..5818568 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
@@ -263,7 +263,7 @@ public class BasicExecutionManager implements ExecutionManager {
         incompleteTaskIds.remove(task.getId());
         if (removed!=null && removed.isSubmitted() && !removed.isDone(true)) {
             Entity context = BrooklynTaskTags.getContextEntity(removed);
-            if (!Entities.isManaged(context)) {
+            if (context!=null && !Entities.isManaged(context)) {
                 log.debug("Forgetting about active task on unmanagement of "+context+": "+removed);
             } else {
                 log.warn("Deleting submitted task before completion: "+removed+"; this task will continue to run in the background outwith "+this+", but perhaps it should have been cancelled?");
@@ -470,7 +470,6 @@ public class BasicExecutionManager implements ExecutionManager {
                         }
                         Object result;
                         try {
-                            lastError = null;
                             result = oldJob.call();
                             task.lastThrownType = null;
                         } catch (Exception e) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8077f16a/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolver.java b/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolver.java
index d93dfa4..0e75d16 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolver.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolver.java
@@ -434,7 +434,8 @@ public class ValueResolver<T> implements DeferredSupplier<T>, Iterable<Maybe<Obj
                         // (should discourage this in favour of task factories which can be transiently interrupted?)
                         BrooklynTaskTags.addTagDynamically(task, BrooklynTaskTags.NON_TRANSIENT_TASK_TAG);
                     }
-                    if (timer!=null || Thread.currentThread().isInterrupted()) {
+                    // FIXME
+                    if (timer!=null || Thread.currentThread().isInterrupted() || isEvaluatingImmediately()) {
                         exec.submit(task);
                     } else {
                         exec.get(task);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8077f16a/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiTest.java b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiTest.java
index 9039cf2..5110315 100644
--- a/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiTest.java
@@ -110,6 +110,7 @@ public class EffectorSayHiTest extends BrooklynAppUnitTestSupport {
     }
     
     @Test(groups="WIP")  // see comments at BasicExecutionContext.getImmediately
+    // FIXME
     public void testInvocationGetImmediately() throws Exception {
         assertEquals(((EntityInternal)e).getExecutionContext()
             .getImmediately( Effectors.invocation(e, MyEntity.SAY_HI_1, ImmutableMap.of("name", "Bob", "greeting", "hi")) ), "hi Bob");

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8077f16a/core/src/test/java/org/apache/brooklyn/util/core/task/BasicTasksFutureTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/util/core/task/BasicTasksFutureTest.java b/core/src/test/java/org/apache/brooklyn/util/core/task/BasicTasksFutureTest.java
index a2bfd59..0db1158 100644
--- a/core/src/test/java/org/apache/brooklyn/util/core/task/BasicTasksFutureTest.java
+++ b/core/src/test/java/org/apache/brooklyn/util/core/task/BasicTasksFutureTest.java
@@ -176,7 +176,7 @@ public class BasicTasksFutureTest {
 
     @Test
     public void testCancelAfterStartTriggersListenableFutureDynamic() throws Exception {
-        doTestCancelTriggersListenableFuture(Duration.millis(50), true);
+        doTestCancelTriggersListenableFuture(null, Duration.millis(50), true);
     }
     @Test
     public void testCancelImmediateTriggersListenableFutureDynamic() throws Exception {
@@ -184,32 +184,32 @@ public class BasicTasksFutureTest {
         // that needs handling separately as it falls into an edge where the future is set and cancelled
         // so the executor won't run it, and our wrapper logic doesn't apply; 
         // this test doesn't guarantee this code path, but makes it likely enough it happens once in a while.
-        doTestCancelTriggersListenableFuture(Duration.ZERO, true);
+        doTestCancelTriggersListenableFuture(null, Duration.ZERO, true);
     }
     @Test
     public void testCancelBeforeTriggersListenableFutureDynamic() throws Exception {
-        doTestCancelTriggersListenableFuture(Duration.millis(-50), true);
+        doTestCancelTriggersListenableFuture(Duration.millis(50), null, true);
     }
     @Test
     public void testCancelAfterStartTriggersListenableFutureSimple() throws Exception {
-        doTestCancelTriggersListenableFuture(Duration.millis(50), true);
+        doTestCancelTriggersListenableFuture(null, Duration.millis(50), true);
     }
     @Test
     public void testCancelImmediateTriggersListenableFutureSimple() throws Exception {
-        doTestCancelTriggersListenableFuture(Duration.ZERO, false);
+        doTestCancelTriggersListenableFuture(null, Duration.ZERO, false);
     }
     @Test
     public void testCancelBeforeTriggersListenableFutureSimple() throws Exception {
-        doTestCancelTriggersListenableFuture(Duration.millis(-50), false);
+        doTestCancelTriggersListenableFuture(Duration.millis(50), null, false);
     }
-    public void doTestCancelTriggersListenableFuture(Duration delay, boolean dynamic) throws Exception {
+    public void doTestCancelTriggersListenableFuture(Duration delayBeforeSubmit, Duration delayBeforeCancel, boolean dynamic) throws Exception {
         Task<String> t = waitForSemaphore(Duration.TEN_SECONDS, true, "x", dynamic);
         addFutureListener(t, "before");
 
         Stopwatch watch = Stopwatch.createStarted();
-        if (delay.isNegative()) {
+        if (delayBeforeSubmit!=null) {
             new Thread(() -> {
-                Time.sleep(delay.multiply(-1)); 
+                Time.sleep(delayBeforeSubmit); 
                 ec.submit(t); 
             }).start(); 
         } else {
@@ -218,10 +218,11 @@ public class BasicTasksFutureTest {
         
         addFutureListener(t, "during");
 
-        log.info("test cancelling "+t+" ("+t.getClass()+") after "+delay);
+        log.info("test cancelling "+t+" ("+t.getClass()+") after "+delayBeforeCancel+
+            ", submit delay "+delayBeforeSubmit);
         // NB: three different code paths (callers to this method) for notifying futures 
         // depending whether task is started before, at, or after the cancel 
-        if (!delay.isNegative()) Time.sleep(delay);
+        if (delayBeforeCancel!=null) Time.sleep(delayBeforeCancel);
 
         synchronized (data) {
             t.cancel(true);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8077f16a/core/src/test/java/org/apache/brooklyn/util/core/task/NonBasicTaskExecutionTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/util/core/task/NonBasicTaskExecutionTest.java b/core/src/test/java/org/apache/brooklyn/util/core/task/NonBasicTaskExecutionTest.java
index 6fd3021..f31c7ab 100644
--- a/core/src/test/java/org/apache/brooklyn/util/core/task/NonBasicTaskExecutionTest.java
+++ b/core/src/test/java/org/apache/brooklyn/util/core/task/NonBasicTaskExecutionTest.java
@@ -33,10 +33,6 @@ import java.util.concurrent.TimeUnit;
 import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.core.task.BasicExecutionManager;
-import org.apache.brooklyn.util.core.task.BasicTask;
-import org.apache.brooklyn.util.core.task.ForwardingTask;
-import org.apache.brooklyn.util.core.task.TaskInternal;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.annotations.AfterMethod;
@@ -44,9 +40,7 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 /**
- * Test the operation of the {@link BasicTask} class.
- *
- * TODO clarify test purpose
+ * Test some internal aspects of {@link BasicTask} execution.
  */
 public class NonBasicTaskExecutionTest {
     private static final Logger log = LoggerFactory.getLogger(NonBasicTaskExecutionTest.class);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8077f16a/utils/common/src/main/java/org/apache/brooklyn/util/guava/Maybe.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/guava/Maybe.java b/utils/common/src/main/java/org/apache/brooklyn/util/guava/Maybe.java
index a68b400..8b69cc0 100644
--- a/utils/common/src/main/java/org/apache/brooklyn/util/guava/Maybe.java
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/guava/Maybe.java
@@ -204,7 +204,7 @@ public abstract class Maybe<T> implements Serializable, Supplier<T> {
     
     public static class MaybeSupplier<T> extends AbstractPresent<T> {
         private static final long serialVersionUID = -823731500051341455L;
-        private Supplier<T> supplier;
+        private final Supplier<T> supplier;
         public MaybeSupplier(Supplier<T> value) {
             this.supplier = value;
         }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8077f16a/utils/common/src/main/java/org/apache/brooklyn/util/repeat/Repeater.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/repeat/Repeater.java b/utils/common/src/main/java/org/apache/brooklyn/util/repeat/Repeater.java
index 4c59c8d..bcd1c9c 100644
--- a/utils/common/src/main/java/org/apache/brooklyn/util/repeat/Repeater.java
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/repeat/Repeater.java
@@ -30,6 +30,7 @@ import javax.annotation.Nullable;
 
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.exceptions.ReferenceWithError;
+import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.time.CountdownTimer;
 import org.apache.brooklyn.util.time.Duration;
 import org.apache.brooklyn.util.time.Time;
@@ -278,13 +279,15 @@ public class Repeater implements Callable<Boolean> {
         Preconditions.checkNotNull(supplier, "supplier must not be null");
         Preconditions.checkNotNull(exitCondition, "exitCondition must not be null");
         return until(new Callable<Boolean>() {
+            private Maybe<T> lastValue = Maybe.absent();
             @Override
             public Boolean call() throws Exception {
-                return exitCondition.apply(supplier.get());
+                lastValue = Maybe.ofAllowingNull(supplier.get());
+                return exitCondition.apply(lastValue.get());
             }
             @Override
             public String toString() {
-                return supplier.get()+" "+exitCondition.toString();
+                return ""+(lastValue.isPresent() ? lastValue.get() : supplier) + " " + exitCondition;
             }
         });
     }


[30/35] brooklyn-server git commit: add deprecation notes to description for REST endpoints so they appear in swagger

Posted by he...@apache.org.
add deprecation notes to description for REST endpoints so they appear in swagger


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

Branch: refs/heads/master
Commit: e0160538fee0dd8f0308ed4d6787d54bf813d7dc
Parents: 4f4507a
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Oct 3 09:31:52 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Oct 3 09:31:52 2017 +0100

----------------------------------------------------------------------
 .../apache/brooklyn/rest/api/CatalogApi.java    | 34 +++++++++++---------
 .../org/apache/brooklyn/rest/api/PolicyApi.java | 14 ++++----
 .../brooklyn/rest/api/PolicyConfigApi.java      |  8 ++---
 3 files changed, 29 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e0160538/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/CatalogApi.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/CatalogApi.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/CatalogApi.java
index 6499f14..2c115df 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/CatalogApi.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/CatalogApi.java
@@ -58,7 +58,7 @@ public interface CatalogApi {
     @Consumes("application/json-deprecated")  // prevent this from taking things
     @POST
     @ApiOperation(
-            value = "Add a catalog items (e.g. new type of entity, policy or location) by uploading YAML descriptor.",
+            value = "Add a catalog items (e.g. new type of entity, policy or location) by uploading YAML descriptor (deprecated, use POST of yaml or ZIP/JAR instead)",
             notes = "Return value is map of ID to CatalogItemSummary.",
             response = String.class,
             hidden = true
@@ -159,7 +159,7 @@ public interface CatalogApi {
     @DELETE
     @Path("/applications/{symbolicName}/{version}")
     @ApiOperation(
-            value = "Deletes a specific version of an application's definition from the catalog",
+            value = "Deletes a specific version of an application's definition from the catalog (deprecated, use /catalog/bundles endpoint instead)",
             notes = "Version must exists, otherwise the API will return a 404. Alternatively, passing 'latest' will" +
                     "pick up the latest version for the given 'symbolicName'"
     )
@@ -179,7 +179,7 @@ public interface CatalogApi {
     @DELETE
     @Path("/entities/{symbolicName}/{version}")
     @ApiOperation(
-            value = "Deletes a specific version of an entity's definition from the catalog",
+            value = "Deletes a specific version of an entity's definition from the catalog (deprecated, use /catalog/bundles endpoint instead, as we add/delete bundles now)",
             notes = "Version must exists, otherwise the API will return a 404. Alternatively, passing 'latest' will" +
                     "pick up the latest version for the given 'symbolicName'"
     )
@@ -199,7 +199,7 @@ public interface CatalogApi {
     @DELETE
     @Path("/policies/{policyId}/{version}")
     @ApiOperation(
-            value = "Deletes a specific version of an policy's definition from the catalog",
+            value = "Deletes a specific version of an policy's definition from the catalog (deprecated, use /catalog/bundles endpoint instead, as we add/delete bundles now)",
             notes = "Version must exists, otherwise the API will return a 404. Alternatively, passing 'latest' will" +
                     "pick up the latest version for the given 'policyId'")
     @ApiResponses(value = {
@@ -218,7 +218,7 @@ public interface CatalogApi {
     @DELETE
     @Path("/locations/{locationId}/{version}")
     @ApiOperation(
-            value = "Deletes a specific version of an location's definition from the catalog",
+            value = "Deletes a specific version of an location's definition from the catalog (deprecated, use /catalog/bundles endpoint instead, as we add/delete bundles now)",
             notes = "Version must exists, otherwise the API will return a 404. Alternatively, passing 'latest' will" +
                     "pick up the latest version for the given 'locationId'"
     )
@@ -237,7 +237,7 @@ public interface CatalogApi {
     @Deprecated
     @GET
     @Path("/entities")
-    @ApiOperation(value = "List available entity types optionally matching a query", 
+    @ApiOperation(value = "List available entity types optionally matching a query  (deprecated, use /catalog/types endpoint instead, with supertype=entity)", 
             response = CatalogItemSummary.class,
             responseContainer = "List")
     public List<CatalogEntitySummary> listEntities(
@@ -254,7 +254,7 @@ public interface CatalogApi {
     @Deprecated
     @GET
     @Path("/applications")
-    @ApiOperation(value = "Fetch a list of templates (for applications) optionally matching a query", 
+    @ApiOperation(value = "Fetch a list of templates (for applications) optionally matching a query (deprecated, use /catalog/types endpoint instead, with supertype=application; note some semantics of templates are changing as definition becomes more precise)", 
             response = CatalogItemSummary.class,
             responseContainer = "List")
     public List<CatalogItemSummary> listApplications(
@@ -271,7 +271,7 @@ public interface CatalogApi {
     @GET
     @Path("/entities/{symbolicName}/{version}")
     @ApiOperation(
-            value = "Fetch a specific version of an entity's definition from the catalog",
+            value = "Fetch a specific version of an entity's definition from the catalog (deprecated, use /catalog/types endpoint instead)",
             notes = "Version must exists, otherwise the API will return a 404. Alternatively, passing 'latest' will" +
                     "pick up the latest version for the given 'symbolicName'",
             response = CatalogEntitySummary.class,
@@ -292,7 +292,7 @@ public interface CatalogApi {
     @GET
     @Path("/applications/{symbolicName}/{version}")
     @ApiOperation(
-            value = "Fetch a specific version of an application's definition from the catalog",
+            value = "Fetch a specific version of an application's definition from the catalog (deprecated, use /catalog/types endpoint instead)",
             notes = "Version must exists, otherwise the API will return a 404. Alternatively, passing 'latest' will" +
                     "pick up the latest version for the given 'symbolicName'",
             response = CatalogEntitySummary.class,
@@ -312,7 +312,7 @@ public interface CatalogApi {
     @Deprecated
     @GET
     @Path("/policies")
-    @ApiOperation(value = "List available policies optionally matching a query", 
+    @ApiOperation(value = "List available policies optionally matching a query (deprecated, use /catalog/types endpoint instead)", 
             response = CatalogPolicySummary.class,
             responseContainer = "List")
     public List<CatalogPolicySummary> listPolicies(
@@ -329,7 +329,7 @@ public interface CatalogApi {
     @GET
     @Path("/policies/{policyId}/{version}")
     @ApiOperation(
-            value = "Fetch a policy's definition from the catalog",
+            value = "Fetch a policy's definition from the catalog (deprecated, use /catalog/types endpoint instead)",
             notes = "Version must exists, otherwise the API will return a 404. Alternatively, passing 'latest' will" +
                     "pick up the latest version for the given 'policyId'",
             response = CatalogItemSummary.class,
@@ -348,7 +348,7 @@ public interface CatalogApi {
     @Deprecated
     @GET
     @Path("/locations")
-    @ApiOperation(value = "List available locations optionally matching a query", 
+    @ApiOperation(value = "List available locations optionally matching a query (deprecated, use /catalog/types endpoint instead)", 
             response = CatalogLocationSummary.class,
             responseContainer = "List")
     public List<CatalogLocationSummary> listLocations(
@@ -365,7 +365,7 @@ public interface CatalogApi {
     @GET
     @Path("/locations/{locationId}/{version}")
     @ApiOperation(
-            value = "Fetch a location's definition from the catalog",
+            value = "Fetch a location's definition from the catalog (deprecated, use /catalog/types endpoint instead)",
             notes = "Version must exists, otherwise the API will return a 404. Alternatively, passing 'latest' will" +
                     "pick up the latest version for the given 'locationId'",
             response = CatalogItemSummary.class,
@@ -406,6 +406,7 @@ public interface CatalogApi {
     @ApiResponses(value = {
             @ApiResponse(code = 404, message = "Undefined catalog item"),
     })
+    @ApiOperation(value = "Deprecate an item (deprecated, use /catalog/types endpoint instead, but disabled/deprecating is not supported for individual types)")
     @Path("/entities/{itemId}/deprecated")
     public void setDeprecated(
         @ApiParam(name = "itemId", value = "The ID of the catalog item to be deprecated", required = true)
@@ -419,6 +420,7 @@ public interface CatalogApi {
     @Deprecated
     @POST
     @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_OCTET_STREAM, MediaType.TEXT_PLAIN})
+    @ApiOperation(value = "Disable an item (deprecated, use /catalog/types endpoint instead, but disabled/deprecating is not supported for individual types)")
     @ApiResponses(value = {
             @ApiResponse(code = 404, message = "Undefined catalog item"),
     })
@@ -434,7 +436,7 @@ public interface CatalogApi {
     @Deprecated
     @GET
     @Path("/enrichers")
-    @ApiOperation(value = "List available enrichers types optionally matching a query",
+    @ApiOperation(value = "List available enrichers types optionally matching a query (deprecated, use /catalog/types endpoint instead)",
             response = CatalogItemSummary.class,
             responseContainer = "List")
     public List<CatalogEnricherSummary> listEnrichers(
@@ -450,7 +452,7 @@ public interface CatalogApi {
     @Deprecated
     @GET
     @Path("/enrichers/{enricherId}/{version}")
-    @ApiOperation(value = "Fetch an enricher's definition from the catalog",
+    @ApiOperation(value = "Fetch an enricher's definition from the catalog (deprecated, use /catalog/types endpoint instead)",
             response = CatalogItemSummary.class,
             responseContainer = "List")
     @ApiResponses(value = {
@@ -467,7 +469,7 @@ public interface CatalogApi {
     @Deprecated
     @DELETE
     @Path("/enrichers/{enricherId}/{version}")
-    @ApiOperation(value = "Deletes a specific version of an enricher's definition from the catalog")
+    @ApiOperation(value = "Deletes a specific version of an enricher's definition from the catalog (deprecated, use /catalog/types endpoint instead)")
     @ApiResponses(value = {
             @ApiResponse(code = 404, message = "Enricher not found")
     })

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e0160538/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyApi.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyApi.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyApi.java
index 329c0e1..95f41db 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyApi.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyApi.java
@@ -41,7 +41,7 @@ import java.util.Map;
 public interface PolicyApi {
     
     @GET
-    @ApiOperation(value = "Fetch the policies attached to a specific application entity",
+    @ApiOperation(value = "Fetch the policies attached to a specific application entity (deprecated, use adjuncts/ endpoint instead)",
             response = org.apache.brooklyn.rest.domain.PolicySummary.class,
             responseContainer = "List")
     @ApiResponses(value = {
@@ -57,7 +57,7 @@ public interface PolicyApi {
     // (and in sensors class)
     @GET
     @Path("/current-state")
-    @ApiOperation(value = "Fetch policy states in batch", notes="Returns a map of policy ID to whether it is active")
+    @ApiOperation(value = "Fetch policy states in batch", notes="Returns a map of policy ID to whether it is active (deprecated, use adjuncts/ endpoint instead)")
     // FIXME method name -- this is nothing to do with config!
     public Map<String, Boolean> batchConfigRead(
             @ApiParam(value = "Application ID or name", required = true)
@@ -66,7 +66,7 @@ public interface PolicyApi {
             @PathParam("entity") String entityToken) ;
 
     @POST
-    @ApiOperation(value = "Add a policy", notes = "Returns a summary of the new policy")
+    @ApiOperation(value = "Add a policy", notes = "Returns a summary of the new policy (deprecated, use adjuncts/ endpoint instead)")
     @ApiResponses(value = {
             @ApiResponse(code = 404, message = "Could not find application or entity"),
             @ApiResponse(code = 400, message = "Type is not a class implementing Policy")
@@ -88,7 +88,7 @@ public interface PolicyApi {
 
     @GET
     @Path("/{policy}")
-    @ApiOperation(value = "Gets status of a policy (RUNNING / SUSPENDED)")
+    @ApiOperation(value = "Gets status of a policy (RUNNING / SUSPENDED) (deprecated, use adjuncts/ endpoint instead)")
     @ApiResponses(value = {
             @ApiResponse(code = 404, message = "Could not find application, entity or policy")
     })
@@ -104,7 +104,7 @@ public interface PolicyApi {
 
     @POST
     @Path("/{policy}/start")
-    @ApiOperation(value = "Start or resume a policy")
+    @ApiOperation(value = "Start or resume a policy (deprecated, use adjuncts/ endpoint instead)")
     @ApiResponses(value = {
             @ApiResponse(code = 404, message = "Could not find application, entity or policy")
     })
@@ -120,7 +120,7 @@ public interface PolicyApi {
 
     @POST
     @Path("/{policy}/stop")
-    @ApiOperation(value = "Suspends a policy")
+    @ApiOperation(value = "Suspends a policy (deprecated, use adjuncts/ endpoint instead)")
     @ApiResponses(value = {
             @ApiResponse(code = 404, message = "Could not find application, entity or policy")
     })
@@ -137,7 +137,7 @@ public interface PolicyApi {
     // TODO: Should be DELETE /policy, not POST /policy/destroy
     @POST
     @Path("/{policy}/destroy")
-    @ApiOperation(value = "Destroy a policy", notes="Removes a policy from being associated with the entity and destroys it (stopping first if running)")
+    @ApiOperation(value = "Destroy a policy (deprecated, use adjuncts/ endpoint instead)", notes="Removes a policy from being associated with the entity and destroys it (stopping first if running)")
     @ApiResponses(value = {
             @ApiResponse(code = 404, message = "Could not find application, entity or policy")
     })

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e0160538/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyConfigApi.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyConfigApi.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyConfigApi.java
index 06a4b86..8d061dd 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyConfigApi.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyConfigApi.java
@@ -47,7 +47,7 @@ import io.swagger.annotations.ApiResponses;
 public interface PolicyConfigApi {
 
     @GET
-    @ApiOperation(value = "Fetch the config keys for a specific policy",
+    @ApiOperation(value = "Fetch the config keys for a specific policy (deprecated, use adjuncts/ endpoint instead)",
             response = org.apache.brooklyn.rest.domain.ConfigSummary.class,
             responseContainer = "List")
     @ApiResponses(value = {
@@ -65,7 +65,7 @@ public interface PolicyConfigApi {
     // (and in sensors class)
     @GET
     @Path("/current-state")
-    @ApiOperation(value = "Fetch config key values in batch", notes="Returns a map of config name to value")
+    @ApiOperation(value = "Fetch config key values in batch (deprecated, use adjuncts/ endpoint instead)", notes="Returns a map of config name to value")
     public Map<String, Object> batchConfigRead(
             @ApiParam(value = "Application ID or name", required = true)
             @PathParam("application") String application,
@@ -76,7 +76,7 @@ public interface PolicyConfigApi {
 
     @GET
     @Path("/{config}")
-    @ApiOperation(value = "Fetch config value", response = Object.class)
+    @ApiOperation(value = "Fetch config value (deprecated, use adjuncts/ endpoint instead)", response = Object.class)
     @ApiResponses(value = {
             @ApiResponse(code = 404, message = "Could not find application, entity, policy or config key")
     })
@@ -93,7 +93,7 @@ public interface PolicyConfigApi {
     @POST
     @Path("/{config}")
     @Consumes(value = {"*/*"})
-    @ApiOperation(value = "Sets the given config on this policy")
+    @ApiOperation(value = "Sets the given config on this policy (deprecated, use adjuncts/ endpoint instead)")
     @ApiResponses(value = {
             @ApiResponse(code = 404, message = "Could not find application, entity, policy or config key")
     })


[07/35] brooklyn-server git commit: remove soft refs in tasks in favour of lookup

Posted by he...@apache.org.
remove soft refs in tasks in favour of lookup

soft refs are expensive in the GC phase -- improves speed by 20% in some cases


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

Branch: refs/heads/master
Commit: 9a105e05dbe0d8019a7b4f3c3abd523e66a24a84
Parents: 784bc96
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Sep 11 18:03:37 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Sep 15 10:29:08 2017 +0100

----------------------------------------------------------------------
 .../java/org/apache/brooklyn/api/mgmt/Task.java |  2 ++
 .../util/core/task/BasicExecutionManager.java   | 36 ++++++++++++++++++--
 .../brooklyn/util/core/task/BasicTask.java      | 31 ++++++++++-------
 .../brooklyn/util/core/task/ForwardingTask.java | 11 ++++++
 .../brooklyn/util/core/task/TaskInternal.java   |  2 ++
 5 files changed, 68 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9a105e05/api/src/main/java/org/apache/brooklyn/api/mgmt/Task.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/mgmt/Task.java b/api/src/main/java/org/apache/brooklyn/api/mgmt/Task.java
index ce7a96d..969c3a8 100644
--- a/api/src/main/java/org/apache/brooklyn/api/mgmt/Task.java
+++ b/api/src/main/java/org/apache/brooklyn/api/mgmt/Task.java
@@ -55,6 +55,8 @@ public interface Task<T> extends ListenableFuture<T>, TaskAdaptable<T> {
     
     /** task which submitted this task, if was submitted by a task */
     public Task<?> getSubmittedByTask();
+    /** task which submitted this task, if was submitted by a task */
+    public String getSubmittedByTaskId();
 
     /** The thread where the task is running, if it is running. */
     public Thread getThread();

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9a105e05/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
index aa61a57..afc8c99 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
@@ -57,6 +57,7 @@ import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.core.task.TaskInternal.TaskCancellationMode;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.exceptions.RuntimeInterruptedException;
+import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.text.Identifiers;
 import org.apache.brooklyn.util.text.Strings;
 import org.apache.brooklyn.util.time.CountdownTimer;
@@ -69,8 +70,10 @@ import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.CaseFormat;
 import com.google.common.base.Function;
 import com.google.common.base.Preconditions;
+import com.google.common.base.Supplier;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.Callables;
 import com.google.common.util.concurrent.ExecutionList;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.ThreadFactoryBuilder;
@@ -729,7 +732,9 @@ public class BasicExecutionManager implements ExecutionManager {
         incompleteTaskIds.add(task.getId());
         
         Task<?> currentTask = Tasks.current();
-        if (currentTask!=null) ((TaskInternal<?>)task).setSubmittedByTask(currentTask);
+        if (currentTask!=null) ((TaskInternal<?>)task).setSubmittedByTask(
+                // do this instead of soft reference (2017-09) as soft refs impact GC 
+                Maybe.of(new TaskLookup(this, currentTask)) );
         ((TaskInternal<?>)task).setSubmitTimeUtc(System.currentTimeMillis());
         
         if (flags!=null && flags.get("tag")!=null) ((TaskInternal<?>)task).getMutableTags().add(flags.remove("tag"));
@@ -742,6 +747,33 @@ public class BasicExecutionManager implements ExecutionManager {
         tasksById.put(task.getId(), task);
         totalTaskCount.incrementAndGet();
     }
+    
+    private static class TaskLookup implements Supplier<Task<?>> {
+        // this class is not meant to be serialized, but if it is, make sure exec mgr doesn't sneak in
+        transient BasicExecutionManager mgr;
+        
+        String id;
+        String displayName;
+        public TaskLookup(BasicExecutionManager mgr, Task<?> t) {
+            this.mgr = mgr;
+            id = t.getId();
+            displayName = t.getDisplayName();
+        }
+        @Override
+        public Task<?> get() {
+            if (mgr==null) return gone();
+            Task<?> result = mgr.getTask(id);
+            if (result!=null) return result;
+            return gone();
+        }
+        private <T> Task<T> gone() {
+            Task<T> t = Tasks.<T>builder().dynamic(false).displayName(displayName)
+                .description("Details of the original task "+id+" have been forgotten.")
+                .body(Callables.returning((T)null)).build();
+            ((BasicTask<T>)t).ignoreIfNotRun();
+            return t;
+        }
+    }
 
     protected void beforeStartScheduledTaskSubmissionIteration(Map<?,?> flags, Task<?> task) {
         internalBeforeStart(flags, task, true);
@@ -856,7 +888,7 @@ public class BasicExecutionManager implements ExecutionManager {
         if (startedInThisThread) {
             PerThreadCurrentTaskHolder.perThreadCurrentTask.remove();
             //clear thread _after_ endTime set, so we won't get a null thread when there is no end-time
-            if (RENAME_THREADS && startedInThisThread) {
+            if (RENAME_THREADS) {
                 Thread thread = task.getThread();
                 if (thread==null) {
                     log.warn("BasicTask.afterEnd invoked without corresponding beforeStart");

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9a105e05/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
index 4398675..f1a066f 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
@@ -43,10 +43,12 @@ import java.util.concurrent.TimeoutException;
 
 import org.apache.brooklyn.api.mgmt.HasTaskChildren;
 import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.api.objs.Identifiable;
 import org.apache.brooklyn.util.JavaGroovyEquivalents;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.groovy.GroovyJavaMethods;
 import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.guava.Maybe.MaybeSupplier;
 import org.apache.brooklyn.util.text.Identifiers;
 import org.apache.brooklyn.util.text.Strings;
 import org.apache.brooklyn.util.time.Duration;
@@ -57,10 +59,10 @@ import org.slf4j.LoggerFactory;
 import com.google.common.annotations.Beta;
 import com.google.common.base.Function;
 import com.google.common.base.Objects;
+import com.google.common.base.Supplier;
 import com.google.common.base.Throwables;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
-import com.google.common.util.concurrent.Callables;
 import com.google.common.util.concurrent.ExecutionList;
 import com.google.common.util.concurrent.ListenableFuture;
 
@@ -256,6 +258,17 @@ public class BasicTask<T> implements TaskInternal<T> {
         if (submittedByTask==null) return null;
         return submittedByTask.orNull(); 
     }
+    @Override
+    public String getSubmittedByTaskId() {
+        if (submittedByTask==null || submittedByTask.isAbsent()) return null;
+        if (submittedByTask instanceof MaybeSupplier) {
+            Supplier<?> supplier = ((MaybeSupplier<?>)submittedByTask).getSupplier();
+            if (supplier instanceof Identifiable) {
+                return ((Identifiable)supplier).getId();
+            }
+        }
+        return submittedByTask.get().getId();
+    }
 
     /** the thread where the task is running, if it is running */
     @Override
@@ -906,19 +919,13 @@ public class BasicTask<T> implements TaskInternal<T> {
         submitTimeUtc = val;
     }
     
-    private static <T> Task<T> newGoneTaskFor(Task<?> task) {
-        Task<T> t = Tasks.<T>builder().dynamic(false).displayName(task.getDisplayName())
-            .description("Details of the original task "+task+" have been forgotten.")
-            .body(Callables.returning((T)null)).build();
-        ((BasicTask<T>)t).ignoreIfNotRun();
-        return t;
-    }
-    
-    @SuppressWarnings({ "unchecked", "rawtypes" })
     @Override
     public void setSubmittedByTask(Task<?> task) {
-        // possible optimization, store details but don't create task until later
-        submittedByTask = Maybe.softThen((Task)task, (Maybe)Maybe.of(BasicTask.newGoneTaskFor(task)));
+        setSubmittedByTask(Maybe.of(task));
+    }
+    @Override
+    public void setSubmittedByTask(Maybe<Task<?>> taskM) {
+        submittedByTask = taskM;
     }
     
     @Override

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9a105e05/core/src/main/java/org/apache/brooklyn/util/core/task/ForwardingTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/ForwardingTask.java b/core/src/main/java/org/apache/brooklyn/util/core/task/ForwardingTask.java
index 7233ea8..83f2128 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/ForwardingTask.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/ForwardingTask.java
@@ -27,6 +27,7 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
 import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.time.Duration;
 
 import com.google.common.base.Function;
@@ -118,6 +119,11 @@ public abstract class ForwardingTask<T> extends ForwardingObject implements Task
     }
 
     @Override
+    public String getSubmittedByTaskId() {
+        return delegate().getSubmittedByTaskId();
+    }
+
+    @Override
     public Thread getThread() {
         return delegate().getThread();
     }
@@ -303,6 +309,11 @@ public abstract class ForwardingTask<T> extends ForwardingObject implements Task
     }
 
     @Override
+    public void setSubmittedByTask(Maybe<Task<?>> taskM) {
+        delegate().setSubmittedByTask(taskM);
+    }
+
+    @Override
     public Set<Object> getMutableTags() {
         return delegate().getMutableTags();
     }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9a105e05/core/src/main/java/org/apache/brooklyn/util/core/task/TaskInternal.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/TaskInternal.java b/core/src/main/java/org/apache/brooklyn/util/core/task/TaskInternal.java
index 83b9eab..6b3365b 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/TaskInternal.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/TaskInternal.java
@@ -25,6 +25,7 @@ import java.util.concurrent.Future;
 
 import org.apache.brooklyn.api.mgmt.ExecutionManager;
 import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.time.Duration;
 
 import com.google.common.annotations.Beta;
@@ -113,6 +114,7 @@ public interface TaskInternal<T> extends Task<T> {
     void setSubmitTimeUtc(long currentTimeMillis);
 
     void setSubmittedByTask(Task<?> task);
+    void setSubmittedByTask(Maybe<Task<?>> task);
     
     Set<Object> getMutableTags();
 


[11/35] brooklyn-server git commit: add and use builder for ScheduledTask

Posted by he...@apache.org.
add and use builder for ScheduledTask


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

Branch: refs/heads/master
Commit: 18a908bd42f5a09da838c2f90bd6f79b5cd14766
Parents: 934cf4c
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Sep 12 17:31:42 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Sep 15 10:29:09 2017 +0100

----------------------------------------------------------------------
 .../org/apache/brooklyn/core/feed/Poller.java   | 41 +++++++++-----------
 .../mgmt/ha/HighAvailabilityManagerImpl.java    |  2 +-
 .../rebind/PeriodicDeltaChangeListener.java     |  4 +-
 .../core/mgmt/rebind/RebindManagerImpl.java     |  2 +-
 .../location/ssh/SshMachineLocation.java        |  6 +--
 .../brooklyn/util/core/task/ScheduledTask.java  | 41 ++++++++++++++++++++
 .../util/core/task/ScheduledExecutionTest.java  | 19 +++++----
 .../policy/ha/AbstractFailureDetector.java      |  3 +-
 8 files changed, 76 insertions(+), 42 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/18a908bd/core/src/main/java/org/apache/brooklyn/core/feed/Poller.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/feed/Poller.java b/core/src/main/java/org/apache/brooklyn/core/feed/Poller.java
index 1a29c48..03fd1df 100644
--- a/core/src/main/java/org/apache/brooklyn/core/feed/Poller.java
+++ b/core/src/main/java/org/apache/brooklyn/core/feed/Poller.java
@@ -143,29 +143,26 @@ public class Poller<V> {
         for (final PollJob<V> pollJob : pollJobs) {
             final String scheduleName = pollJob.handler.getDescription();
             if (pollJob.pollPeriod.compareTo(Duration.ZERO) > 0) {
-                Callable<Task<?>> pollingTaskFactory = new Callable<Task<?>>() {
-                    @Override
-                    public Task<?> call() {
-                        DynamicSequentialTask<Void> task = new DynamicSequentialTask<Void>(MutableMap.of("displayName", scheduleName, "entity", entity), 
-                            new Callable<Void>() { @Override public Void call() {
-                                if (!Entities.isManaged(entity)) {
-                                    return null;
-                                }
-                                if (onlyIfServiceUp && !Boolean.TRUE.equals(entity.getAttribute(Attributes.SERVICE_UP))) {
-                                    return null;
-                                }
-                                pollJob.wrappedJob.run();
-                                return null; 
-                            } } );
-                        BrooklynTaskTags.setTransient(task);
-                        return task;
-                    }
-                };
-                Map<String, ?> taskFlags = MutableMap.of("displayName", "scheduled:" + scheduleName);
-                ScheduledTask task = new ScheduledTask(taskFlags, pollingTaskFactory)
+                ScheduledTask t = ScheduledTask.builder(() -> {
+                            DynamicSequentialTask<Void> task = new DynamicSequentialTask<Void>(MutableMap.of("displayName", scheduleName, "entity", entity), 
+                                new Callable<Void>() { @Override public Void call() {
+                                    if (!Entities.isManaged(entity)) {
+                                        return null;
+                                    }
+                                    if (onlyIfServiceUp && !Boolean.TRUE.equals(entity.getAttribute(Attributes.SERVICE_UP))) {
+                                        return null;
+                                    }
+                                    pollJob.wrappedJob.run();
+                                    return null; 
+                                } } );
+                            BrooklynTaskTags.setTransient(task);
+                            return task;
+                        })
+                        .displayName("scheduled:" + scheduleName)
                         .period(pollJob.pollPeriod)
-                        .cancelOnException(false);
-                tasks.add(Entities.submit(entity, task));
+                        .cancelOnException(false)
+                        .build();
+                tasks.add(Entities.submit(entity, t));
             } else {
                 if (log.isDebugEnabled()) log.debug("Activating poll (but leaving off, as period {}) for {} (using {})", new Object[] {pollJob.pollPeriod, entity, this});
             }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/18a908bd/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerImpl.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerImpl.java
index f6dc1a4..c161533 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerImpl.java
@@ -589,7 +589,7 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager {
         } else {
             if (pollingTask!=null) pollingTask.cancel(true);
             
-            ScheduledTask task = new ScheduledTask(MutableMap.of("period", pollPeriod, "displayName", "scheduled:[HA poller task]", "tag", BrooklynTaskTags.TRANSIENT_TASK_TAG), taskFactory);
+            ScheduledTask task = ScheduledTask.builder(taskFactory).period(pollPeriod).displayName("scheduled:[HA poller task]").tagTransient().build();
             pollingTask = managementContext.getExecutionManager().submit(task);
         }
     }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/18a908bd/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/PeriodicDeltaChangeListener.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/PeriodicDeltaChangeListener.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/PeriodicDeltaChangeListener.java
index 62b2069..5f5e50a 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/PeriodicDeltaChangeListener.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/PeriodicDeltaChangeListener.java
@@ -244,8 +244,8 @@ public class PeriodicDeltaChangeListener implements ChangeListener {
                         }}).build();
                 }
             };
-            scheduledTask = (ScheduledTask) executionContext.submit(new ScheduledTask(MutableMap.of("displayName", "scheduled[periodic-persister]",
-                "tags", MutableSet.of(BrooklynTaskTags.TRANSIENT_TASK_TAG)), taskFactory).period(period).delay(period));
+            scheduledTask = (ScheduledTask) executionContext.submit(
+                ScheduledTask.builder(taskFactory).displayName("scheduled:[periodic-persister]").tagTransient().period(period).delay(period).build() );
         }
     }
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/18a908bd/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindManagerImpl.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindManagerImpl.java
index d605753..d896376 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindManagerImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindManagerImpl.java
@@ -355,7 +355,7 @@ public class RebindManagerImpl implements RebindManager {
             }
         };
         readOnlyTask = (ScheduledTask) managementContext.getServerExecutionContext().submit(
-            new ScheduledTask(MutableMap.of("displayName", "Periodic read-only rebind"), taskFactory).period(periodicPersistPeriod));
+            ScheduledTask.builder(taskFactory).displayName("scheduled:[periodic-read-only-rebind]").period(periodicPersistPeriod).build() );
     }
     
     @Override

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/18a908bd/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java b/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java
index 167d83e..7033398 100644
--- a/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java
+++ b/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java
@@ -491,10 +491,8 @@ public class SshMachineLocation extends AbstractLocation implements MachineLocat
         };
         
         Duration expiryDuration = getConfig(SSH_CACHE_EXPIRY_DURATION);
-        cleanupTask = getManagementContext().getExecutionManager().submit(new ScheduledTask(
-            MutableMap.of("displayName", "scheduled[ssh-location cache cleaner]"), cleanupTaskFactory)
-                .period(expiryDuration)
-                .delay(expiryDuration));
+        cleanupTask = getManagementContext().getExecutionManager().submit(
+            ScheduledTask.builder(cleanupTaskFactory).displayName("scheduled:[ssh-location cache cleaner]").period(expiryDuration).delay(expiryDuration).build() );
     }
     
     // TODO close has been used for a long time to perform clean-up wanted on unmanagement, but that's not clear; 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/18a908bd/core/src/main/java/org/apache/brooklyn/util/core/task/ScheduledTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/ScheduledTask.java b/core/src/main/java/org/apache/brooklyn/util/core/task/ScheduledTask.java
index 89eb6ab..745d49c 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/ScheduledTask.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/ScheduledTask.java
@@ -21,6 +21,7 @@ package org.apache.brooklyn.util.core.task;
 import static org.apache.brooklyn.util.JavaGroovyEquivalents.elvis;
 import static org.apache.brooklyn.util.JavaGroovyEquivalents.groovyTruth;
 
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CancellationException;
@@ -29,6 +30,8 @@ import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
+import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.time.Duration;
@@ -118,6 +121,44 @@ public class ScheduledTask extends BasicTask<Object> {
         cancelOnException = cancelFlag == null || Boolean.TRUE.equals(cancelFlag);
     }
     
+    public static Builder builder(Callable<Task<?>> val) {
+        return new Builder(val);
+    }
+    
+    public static class Builder {
+        Callable<Task<?>> factory;
+
+        String displayName;
+        List<Object> tags = MutableList.of();
+        Duration delay, period;
+        Integer maxInterations;
+        boolean cancelOnException = true;
+        Map<String,Object> flags = MutableMap.of();
+        
+        public Builder(Callable<Task<?>> val) { this.factory = val; }
+        
+        public ScheduledTask build() {
+            return new ScheduledTask(MutableMap.copyOf(flags)
+                    .addIfNotNull("displayName", displayName) 
+                    .addIfNotNull("tags", tags.isEmpty() ? null : tags)
+                    .addIfNotNull("delay", delay) 
+                    .addIfNotNull("period", period) 
+                    .addIfNotNull("maxIterations", maxInterations) 
+                    .addIfNotNull("cancelOnException", cancelOnException) 
+                , factory);
+        }
+        
+        public Builder displayName(String val) { this.displayName = val; return this; }
+        public Builder tag(Object val) { this.tags.add(val); return this; }
+        public Builder tagTransient() { return tag(BrooklynTaskTags.TRANSIENT_TASK_TAG); }
+        public Builder delay(Duration val) { this.delay = val; return this; }
+        public Builder period(Duration val) { this.period = val; return this; }
+        public Builder maxIterations(Integer val) { this.maxInterations = val; return this; }
+        public Builder cancelOnException(boolean val) { this.cancelOnException = val; return this; }
+        public Builder addFlags(Map<String,?> val) { this.flags.putAll(val); return this; }
+
+    }
+    
     public ScheduledTask delay(Duration d) {
         this.delay = d;
         return this;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/18a908bd/core/src/test/java/org/apache/brooklyn/util/core/task/ScheduledExecutionTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/util/core/task/ScheduledExecutionTest.java b/core/src/test/java/org/apache/brooklyn/util/core/task/ScheduledExecutionTest.java
index 536dfea..166da59 100644
--- a/core/src/test/java/org/apache/brooklyn/util/core/task/ScheduledExecutionTest.java
+++ b/core/src/test/java/org/apache/brooklyn/util/core/task/ScheduledExecutionTest.java
@@ -52,19 +52,18 @@ public class ScheduledExecutionTest {
     
     @Test
     public void testScheduledTask() throws Exception {
-        int PERIOD = 20;
+        Duration PERIOD = Duration.millis(20);
         BasicExecutionManager m = new BasicExecutionManager("mycontextid");
         final AtomicInteger i = new AtomicInteger(0);
-        ScheduledTask t = new ScheduledTask(MutableMap.of("delay", 2*PERIOD, "period", PERIOD, "maxIterations", 5), new Callable<Task<?>>() {
-            @Override
-            public Task<?> call() throws Exception {
-                return new BasicTask<Integer>(new Callable<Integer>() {
-                    @Override
-                    public Integer call() {
-                        log.debug("task running: "+Tasks.current()+" "+Tasks.current().getStatusDetail(false));
+        ScheduledTask t = ScheduledTask.builder(() -> new BasicTask<Integer>(() -> {
+                        log.info("task running: "+Tasks.current()+" "+Tasks.current().getStatusDetail(false));
                         return i.incrementAndGet();
-                    }});
-            }});
+                    }))
+                .displayName("test-1")
+                .delay(PERIOD.multiply(2))
+                .period(PERIOD)
+                .maxIterations(5)
+                .build();
     
         log.info("submitting {} {}", t, t.getStatusDetail(false));
         m.submit(t);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/18a908bd/policy/src/main/java/org/apache/brooklyn/policy/ha/AbstractFailureDetector.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/ha/AbstractFailureDetector.java b/policy/src/main/java/org/apache/brooklyn/policy/ha/AbstractFailureDetector.java
index d625a4f..840335a 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/ha/AbstractFailureDetector.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/ha/AbstractFailureDetector.java
@@ -191,10 +191,9 @@ public abstract class AbstractFailureDetector extends AbstractPolicy {
         doStartPolling();
     }
 
-    @SuppressWarnings("unchecked")
     protected void doStartPolling() {
         if (scheduledTask == null || scheduledTask.isDone()) {
-            ScheduledTask task = new ScheduledTask(MutableMap.of("period", getPollPeriod(), "displayName", getTaskName()), pollingTaskFactory);
+            ScheduledTask task = ScheduledTask.builder(pollingTaskFactory).displayName( getTaskName() ).period(getPollPeriod()).build();
             scheduledTask = ((EntityInternal)entity).getExecutionContext().submit(task);
         }
     }


[21/35] brooklyn-server git commit: apply context-switching task wrapper for same-thread and immediate tasks

Posted by he...@apache.org.
apply context-switching task wrapper for same-thread and immediate tasks

now behave same as submitted tasks. add tests, and comments about limits of getImmediately.


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

Branch: refs/heads/master
Commit: 2bdcf1ac81853410100920968f92a82c41b1f5b6
Parents: ab480ed
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Sep 18 12:49:51 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Mon Sep 18 16:40:56 2017 +0100

----------------------------------------------------------------------
 .../brooklyn/core/effector/Effectors.java       |   2 +-
 .../util/core/task/BasicExecutionContext.java   | 158 +++++++++++--------
 .../core/effector/EffectorSayHiTest.java        |  19 ++-
 3 files changed, 114 insertions(+), 65 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/2bdcf1ac/core/src/main/java/org/apache/brooklyn/core/effector/Effectors.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/Effectors.java b/core/src/main/java/org/apache/brooklyn/core/effector/Effectors.java
index 53db25a..653c607 100644
--- a/core/src/main/java/org/apache/brooklyn/core/effector/Effectors.java
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/Effectors.java
@@ -202,7 +202,7 @@ public class Effectors {
 
     /** returns an unsubmitted task which will invoke the given effector on the given entities
      * (this form of method is a convenience for {@link #invocation(Effector, Map, Iterable)}) */
-    public static TaskAdaptable<List<?>> invocation(Effector<?> eff, MutableMap<?, ?> params, Entity ...entities) {
+    public static TaskAdaptable<List<?>> invocation(Effector<?> eff, Map<?, ?> params, Entity ...entities) {
         return invocation(eff, params, Arrays.asList(entities));
     }
     

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/2bdcf1ac/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
index 114aac7..429cad7 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
@@ -21,6 +21,7 @@ package org.apache.brooklyn.util.core.task;
 import java.lang.reflect.Proxy;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Set;
@@ -133,6 +134,11 @@ public class BasicExecutionContext extends AbstractExecutionContext {
                 throw new ImmediateUnsupportedException("Task is in progress and incomplete: "+t);
             }
         }
+        
+        ContextSwitchingInfo<T> switchContextWrapper = getContextSwitchingTask(t, Collections.emptyList(), false);
+        if (switchContextWrapper!=null) {
+            return switchContextWrapper.context.get(switchContextWrapper.wrapperTask);
+        }
 
         try {
             return runInSameThread(t, new Callable<Maybe<T>>() {
@@ -213,12 +219,6 @@ public class BasicExecutionContext extends AbstractExecutionContext {
         try {
             ((BasicExecutionManager)executionManager).afterSubmitRecordFuture(task, future);
             ((BasicExecutionManager)executionManager).beforeStartInSameThreadTask(null, task);
-
-            // TODO this does not apply the same context-switching logic as submit;
-            // means if task on X submits via this method a non-child (non-queued) task for an effector on Y,
-            // a request to get all of X's tasks recursively won't pick up the call on Y
-            // (because parent tasks don't have records of submitted tasks unless they are children) 
-            
             return future.set(job.call());
             
         } catch (Exception e) {
@@ -253,24 +253,35 @@ public class BasicExecutionContext extends AbstractExecutionContext {
             fakeTaskForContext = (BasicTask<T>)callableOrSupplier;
             if (fakeTaskForContext.isQueuedOrSubmitted()) {
                 if (fakeTaskForContext.isDone()) {
-                    return Maybe.of((T)fakeTaskForContext.getUnchecked());
+                    return Maybe.of(fakeTaskForContext.getUnchecked());
                 } else {
                     throw new ImmediateUnsupportedException("Task is in progress and incomplete: "+fakeTaskForContext);
                 }
             }
             callableOrSupplier = fakeTaskForContext.getJob();
+        } else if (callableOrSupplier instanceof TaskAdaptable) {
+            return getImmediately( ((TaskAdaptable<T>)callableOrSupplier).asTask() );
         } else {
-            fakeTaskForContext = new BasicTask<T>(MutableMap.of("displayName", "immediate evaluation"));
+            fakeTaskForContext = new BasicTask<T>(MutableMap.of("displayName", "Immediate evaluation"));
         }
         final ImmediateSupplier<T> job = callableOrSupplier instanceof ImmediateSupplier ? (ImmediateSupplier<T>) callableOrSupplier 
             : InterruptingImmediateSupplier.<T>of(callableOrSupplier);
         fakeTaskForContext.tags.add(BrooklynTaskTags.IMMEDIATE_TASK_TAG);
         fakeTaskForContext.tags.add(BrooklynTaskTags.TRANSIENT_TASK_TAG);
 
+        ContextSwitchingInfo<T> switchContextWrapper = getContextSwitchingTask(fakeTaskForContext, Collections.emptyList(), true);
+        if (switchContextWrapper!=null) {
+            return switchContextWrapper.context.getImmediately(switchContextWrapper.wrapperTask);
+        }
+
         try {
             return runInSameThread(fakeTaskForContext, new Callable<Maybe<T>>() {
                 public Maybe<T> call() {
-                    // TODO do we really want to cancel? means if it submits other things they won't run, even if they return immediately
+                    // TODO could try to make this work for more types of tasks by not cancelling, it just interrupting;
+                    // however the biggest place "getImmediate" fails is with DSTs where interrupting is sufficient to abort them
+                    // unnecessarily, as queue.andWait attempts to block (again, unnecessarily, but not a straightforward fix).
+                    // limited success of getImmediately is okay -- but no harm in expanding coverage by resolving that and removing cancel.
+                    // see WIP test in EffectorSayHiTest
                     fakeTaskForContext.cancel();
                     
                     boolean wasAlreadyInterrupted = Thread.interrupted();
@@ -294,68 +305,18 @@ public class BasicExecutionContext extends AbstractExecutionContext {
             return submitInternal(propertiesQ, ((TaskAdaptable<?>)task).asTask());
         
         Map properties = MutableMap.copyOf(propertiesQ);
-        Collection taskTags;
+        Collection<Object> taskTags;
         if (properties.get("tags")==null) {
             taskTags = new ArrayList();
         } else {
             taskTags = new ArrayList((Collection)properties.get("tags"));
         }
         properties.put("tags", taskTags);
-        
-        // FIXME some of this is brooklyn-specific logic, should be moved to a BrooklynExecContext subclass;
-        // the issue is that we want to ensure that cross-entity calls switch execution contexts;
-        // previously it was all very messy how that was handled (and it didn't really handle it in many cases)
         if (task instanceof Task<?>) taskTags.addAll( ((Task<?>)task).getTags() ); 
-        Entity target = BrooklynTaskTags.getWrappedEntityOfType(taskTags, BrooklynTaskTags.TARGET_ENTITY);
 
-        checkUserSuppliedContext(task, taskTags);
-
-        if (target!=null && !tags.contains(BrooklynTaskTags.tagForContextEntity(target))) {
-            // task is switching execution context boundaries
-            /* 
-             * longer notes:
-             * you fall in to this block if the caller requests a target entity different to the current context 
-             * (e.g. where entity X is invoking an effector on Y, it will start in X's context, 
-             * but the effector should run in Y's context).
-             * 
-             * we need to make sure there is a reference from this execution context to the submitted task,
-             * IE the submitted task is a child of something in this execution context.
-             * this ensures it shows up via the REST API and in the UI; without it we lose the reference to the child when browsing in the context of the parent.
-             * 
-             * if it is queued or it is already recorded as a child we can simply submit in target context;
-             * but if not we need to wrap it in a task running in this context with the submitted task as a child to have that reference.
-             */
-            final ExecutionContext tc = ((EntityInternal)target).getExecutionContext();
-            if (log.isDebugEnabled())
-                log.debug("Switching task context on execution of "+task+": from "+this+" to "+target+" (in "+Tasks.current()+")");
-            
-            final Task<T> t;
-            if (task instanceof Task<?>) {
-                t = (Task<T>)task;
-                if (Tasks.isQueuedOrSubmitted(t) ||
-                        ((Tasks.current() instanceof HasTaskChildren) && Iterables.contains( ((HasTaskChildren)Tasks.current()).getChildren(), t ))) {
-                    // we are already tracked by parent, just submit it 
-                    return tc.submit(t);
-                }
-            } else {
-                // for callables and runnables there is definitely no record
-                if (task instanceof Callable) {
-                    t = Tasks.<T>builder().dynamic(false).body((Callable<T>)task).build();
-                } else if (task instanceof Runnable) {
-                    t = Tasks.<T>builder().dynamic(false).body((Runnable)task).build();
-                } else {
-                    throw new IllegalArgumentException("Unhandled task type: "+task+"; type="+(task!=null ? task.getClass() : "null"));
-                }                
-            }
-                
-            return submit(
-                // 2017-09 changed, doesn't have to be a dynamic task; can be a simple sequential task wrapping the child
-                Tasks.<T>builder().displayName("Cross-context execution: "+t.getDescription()).dynamic(false).parallel(false).body(new Callable<T>() {
-                    @Override
-                    public T call() { 
-                        return tc.get(t); 
-                    }
-                }).build() );
+        ContextSwitchingInfo<T> switchContextWrapper = getContextSwitchingTask(task, taskTags, false);
+        if (switchContextWrapper!=null) {
+            return switchContextWrapper.context.submit(switchContextWrapper.wrapperTask);
         }
 
         EntitlementContext entitlementContext = BrooklynTaskTags.getEntitlement(taskTags);
@@ -405,6 +366,77 @@ public class BasicExecutionContext extends AbstractExecutionContext {
         }
     }
 
+    private static class ContextSwitchingInfo<T> {
+        final ExecutionContext context;
+        final Task<T> wrapperTask;
+        ContextSwitchingInfo(ExecutionContext context, Task<T> wrapperTask) {
+            this.context = context;
+            this.wrapperTask = wrapperTask;
+        }
+    }
+    
+    @SuppressWarnings("unchecked")
+    protected <T> ContextSwitchingInfo<T> getContextSwitchingTask(final Object task, Collection<Object> taskTags, boolean immediate) {
+        checkUserSuppliedContext(task, taskTags);
+        
+        Entity target = BrooklynTaskTags.getWrappedEntityOfType(taskTags, BrooklynTaskTags.TARGET_ENTITY);
+        if (target==null || tags.contains(BrooklynTaskTags.tagForContextEntity(target))) {
+            return null;
+        }
+        
+        // task is switching execution context boundaries
+        
+        // some of this is brooklyn-specific logic, should be moved to a BrooklynExecContext subclass;
+        // the issue is that we want to ensure that cross-entity calls switch execution contexts;
+        // previously it was all very messy how that was handled (and it didn't really handle it in many cases)
+
+        /* 
+         * longer notes:
+         * you fall in to this block if the caller requests a target entity different to the current context 
+         * (e.g. where entity X is invoking an effector on Y, it will start in X's context, 
+         * but the effector should run in Y's context).
+         * 
+         * we need to make sure there is a reference from this execution context to the submitted task,
+         * IE the submitted task is a child of something in this execution context.
+         * this ensures it shows up via the REST API and in the UI; without it we lose the reference to the child when browsing in the context of the parent.
+         * 
+         * if it is queued or it is already recorded as a child we can simply submit in target context;
+         * but if not we need to wrap it in a task running in this context with the submitted task as a child to have that reference.
+         */
+        final ExecutionContext tc = ((EntityInternal)target).getExecutionContext();
+        if (log.isDebugEnabled())
+            log.debug("Switching task context on execution of "+task+": from "+this+" to "+target+" (in "+Tasks.current()+")");
+            
+        final Task<T> t;
+        if (task instanceof Task<?>) {
+            t = (Task<T>)task;
+            if (Tasks.isQueuedOrSubmitted(t) ||
+                    ((Tasks.current() instanceof HasTaskChildren) && Iterables.contains( ((HasTaskChildren)Tasks.current()).getChildren(), t ))) {
+                // we are already tracked by parent, just submit it 
+                return new ContextSwitchingInfo<>(tc, t);
+            }
+        } else {
+            // for callables and runnables there is definitely no record
+            if (task instanceof Callable) {
+                t = Tasks.<T>builder().dynamic(false).body((Callable<T>)task).build();
+            } else if (task instanceof Runnable) {
+                t = Tasks.<T>builder().dynamic(false).body((Runnable)task).build();
+            } else {
+                throw new IllegalArgumentException("Unhandled task type: "+task+"; type="+(task!=null ? task.getClass() : "null"));
+            }                
+        }
+            
+        return 
+            // 2017-09 changed, doesn't have to be a dynamic task; can be a simple sequential task wrapping the child
+            new ContextSwitchingInfo<>(tc, Tasks.<T>builder().displayName("Cross-context execution: "+t.getDescription()).dynamic(false).parallel(false).body(new Callable<T>() {
+                @Override
+                public T call() throws Exception {
+                    if (immediate) return tc.<T>getImmediately(t).get();
+                    return tc.get(t); 
+                }
+            }).build());
+    }
+
     private void registerPerThreadExecutionContext() { perThreadExecutionContext.set(this); }
 
     private void clearPerThreadExecutionContext() { perThreadExecutionContext.remove(); }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/2bdcf1ac/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiTest.java b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiTest.java
index df8a2cb..9039cf2 100644
--- a/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiTest.java
@@ -34,8 +34,8 @@ import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.mgmt.ExecutionContext;
 import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.core.annotation.EffectorParam;
-import org.apache.brooklyn.core.effector.MethodEffector;
 import org.apache.brooklyn.core.entity.AbstractEntity;
+import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
 import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
@@ -99,6 +99,23 @@ public class EffectorSayHiTest extends BrooklynAppUnitTestSupport {
     }
 
     @Test
+    public void testInvocationSubmission() throws Exception {
+        assertEquals(((EntityInternal)e).getExecutionContext()
+            .submit( Effectors.invocation(e, MyEntity.SAY_HI_1, ImmutableMap.of("name", "Bob", "greeting", "hi")) ).get(), "hi Bob");
+    }
+    @Test
+    public void testInvocationGet() throws Exception {
+        assertEquals(((EntityInternal)e).getExecutionContext()
+            .get( Effectors.invocation(e, MyEntity.SAY_HI_1, ImmutableMap.of("name", "Bob", "greeting", "hi")) ), "hi Bob");
+    }
+    
+    @Test(groups="WIP")  // see comments at BasicExecutionContext.getImmediately
+    public void testInvocationGetImmediately() throws Exception {
+        assertEquals(((EntityInternal)e).getExecutionContext()
+            .getImmediately( Effectors.invocation(e, MyEntity.SAY_HI_1, ImmutableMap.of("name", "Bob", "greeting", "hi")) ), "hi Bob");
+    }
+
+    @Test
     public void testCanRetrieveTaskForEffector() {
         e.sayHi1("Bob", "hi");
 


[29/35] brooklyn-server git commit: Merge branch 'master' into adjunct-rest-api-and-highlights

Posted by he...@apache.org.
Merge branch 'master' into adjunct-rest-api-and-highlights


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

Branch: refs/heads/master
Commit: 4f4507a7df90c739ea5b76f6945a888f3b7d2f1a
Parents: 83c3d50 e2c0247
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Oct 3 09:17:05 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Oct 3 09:17:05 2017 +0100

----------------------------------------------------------------------
 .../brooklyn/api/mgmt/rebind/RebindManager.java |  14 +-
 ...loudsCustomizerInstantiationYamlDslTest.java | 156 +++++--
 .../brooklyn/core/catalog/CatalogLoadMode.java  |  73 ----
 .../catalog/internal/BasicBrooklynCatalog.java  |  28 +-
 .../catalog/internal/CatalogInitialization.java |  88 +---
 .../core/catalog/internal/CatalogUtils.java     |  31 +-
 .../mgmt/ha/HighAvailabilityManagerImpl.java    |  45 +-
 .../core/mgmt/ha/OsgiArchiveInstaller.java      | 210 +++++++---
 .../brooklyn/core/mgmt/ha/OsgiManager.java      |  36 +-
 .../internal/AbstractManagementContext.java     |   5 +-
 .../core/mgmt/internal/LocalUsageManager.java   |  31 +-
 .../ManagementNodeStateListenerManager.java     | 175 ++++++++
 .../NonDeploymentManagementContext.java         |  19 -
 .../rebind/ImmediateDeltaChangeListener.java    | 160 -------
 .../core/mgmt/rebind/RebindIteration.java       |  60 +--
 .../core/mgmt/rebind/RebindManagerImpl.java     |  30 --
 .../mgmt/rebind/dto/BasicEntityMemento.java     |   2 +-
 .../mgmt/rebind/dto/MementosGenerators.java     |   5 +-
 .../mgmt/usage/ManagementNodeStateListener.java |  53 +++
 .../core/objs/BasicConfigurableObject.java      |   4 +-
 .../core/server/BrooklynServerConfig.java       |  28 +-
 .../FixedListMachineProvisioningLocation.java   |   3 +-
 .../brooklyn/util/core/ClassLoaderUtils.java    |   7 +-
 .../brooklyn/util/core/flags/TypeCoercions.java |  21 +
 .../brooklyn/util/core/osgi/BundleMaker.java    |  38 +-
 .../ha/HighAvailabilityManagerInMemoryTest.java |   5 -
 .../ha/HighAvailabilityManagerTestFixture.java  |  61 ++-
 .../core/mgmt/rebind/RebindCatalogItemTest.java |   2 -
 .../core/mgmt/rebind/RebindFailuresTest.java    |  18 +-
 .../core/mgmt/rebind/RebindFeedWithHaTest.java  |   3 +-
 .../usage/ManagementNodeStateListenerTest.java  | 160 +++++++
 .../util/core/ClassLoaderUtilsTest.java         |   6 +-
 .../util/core/internal/TypeCoercionsTest.java   |  31 ++
 .../core/internal/ssh/RecordingSshTool.java     |   7 +
 .../util/core/osgi/BundleMakerTest.java         |   8 +-
 .../bundlemaker/withmanifest/myemptyfile.txt    |   0
 .../launcher/osgi/OsgiLauncherImpl.java         |   2 +-
 .../init/src/main/resources/catalog-classes.bom | 364 ----------------
 karaf/init/src/main/resources/catalog.bom       |  25 ++
 .../BrooklynLauncherRebindCatalogTest.java      |   2 +-
 .../brooklyn/launcher/BrooklynLauncherTest.java |   2 +-
 .../CleanOrphanedLocationsIntegrationTest.java  |   2 +-
 .../jclouds/LocationCustomizerDelegate.java     |   8 +-
 ...ailabilityManagerJcloudsObjectStoreTest.java |   7 +-
 .../main/java/org/apache/brooklyn/cli/Main.java |  21 +-
 .../java/org/apache/brooklyn/cli/CliTest.java   |  32 +-
 .../brooklyn/entity/chef/ChefAttributeFeed.java | 413 -------------------
 .../entity/chef/ChefAttributePollConfig.java    |  61 ---
 .../brooklyn/entity/chef/ChefBashCommands.java  |  42 --
 .../apache/brooklyn/entity/chef/ChefConfig.java |  94 -----
 .../brooklyn/entity/chef/ChefConfigs.java       | 102 -----
 .../apache/brooklyn/entity/chef/ChefEntity.java |  26 --
 .../brooklyn/entity/chef/ChefEntityImpl.java    |  39 --
 .../entity/chef/ChefLifecycleEffectorTasks.java | 364 ----------------
 .../brooklyn/entity/chef/ChefServerTasks.java   |  97 -----
 .../brooklyn/entity/chef/ChefSoloDriver.java    |  85 ----
 .../brooklyn/entity/chef/ChefSoloTasks.java     |  70 ----
 .../apache/brooklyn/entity/chef/ChefTasks.java  | 154 -------
 .../entity/chef/KnifeConvergeTaskFactory.java   | 249 -----------
 .../brooklyn/entity/chef/KnifeTaskFactory.java  | 241 -----------
 .../entity/resolve/ChefEntitySpecResolver.java  |  42 --
 ...oklyn.core.resolve.entity.EntitySpecResolver |   1 -
 .../resources/OSGI-INF/blueprint/blueprint.xml  |   5 -
 software/base/src/main/resources/catalog.bom    |  88 ----
 .../brooklyn/entity/chef/ChefConfigsTest.java   |  40 --
 .../entity/chef/ChefLiveTestSupport.java        |  99 -----
 .../chef/ChefServerTasksIntegrationTest.java    | 109 -----
 .../AbstractChefToyMySqlEntityLiveTest.java     |  41 --
 .../ChefSoloDriverMySqlEntityLiveTest.java      |  49 ---
 .../mysql/ChefSoloDriverToyMySqlEntity.java     |  89 ----
 ...micChefAutodetectToyMySqlEntityLiveTest.java |  43 --
 ...DynamicChefServerToyMySqlEntityLiveTest.java |  50 ---
 .../DynamicChefSoloToyMySqlEntityLiveTest.java  |  43 --
 .../chef/mysql/DynamicToyMySqlEntityChef.java   |  81 ----
 .../chef/mysql/TypedToyMySqlEntityChef.java     |  55 ---
 .../apache/brooklyn/util/stream/Streams.java    |  39 +-
 .../brooklyn/util/stream/StreamsTest.java       |  17 +
 77 files changed, 1091 insertions(+), 3925 deletions(-)
----------------------------------------------------------------------



[35/35] brooklyn-server git commit: This closes #816

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


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

Branch: refs/heads/master
Commit: baf807097f62c2dbe365102ce759dedbf1c6caad
Parents: c177a7c 447283b
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Oct 3 15:23:16 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Oct 3 15:23:16 2017 +0100

----------------------------------------------------------------------
 .../brooklyn/api/mgmt/ExecutionContext.java     |  30 +-
 .../java/org/apache/brooklyn/api/mgmt/Task.java |  18 +-
 .../brooklyn/core/config/BasicConfigKey.java    |   4 +-
 .../brooklyn/core/config/ConfigConstraints.java |   1 +
 .../brooklyn/core/effector/Effectors.java       |   2 +-
 .../org/apache/brooklyn/core/feed/Poller.java   |  41 +-
 .../brooklyn/core/mgmt/BrooklynTaskTags.java    |  12 +-
 .../core/mgmt/EntityManagementUtils.java        |   1 +
 .../mgmt/ha/HighAvailabilityManagerImpl.java    |   2 +-
 .../internal/AbstractManagementContext.java     |   5 +-
 .../mgmt/internal/BrooklynGarbageCollector.java |  25 +-
 .../mgmt/internal/EntityManagementSupport.java  |   1 +
 .../internal/QueueingSubscriptionManager.java   |   2 +
 .../rebind/PeriodicDeltaChangeListener.java     |   4 +-
 .../core/mgmt/rebind/RebindManagerImpl.java     |   2 +-
 .../AbstractConfigurationSupportInternal.java   |   8 +-
 .../location/ssh/SshMachineLocation.java        |   6 +-
 .../util/core/task/BasicExecutionContext.java   | 345 ++++++++++++-----
 .../util/core/task/BasicExecutionManager.java   | 372 ++++++++++++-------
 .../brooklyn/util/core/task/BasicTask.java      |  67 ++--
 .../brooklyn/util/core/task/CompoundTask.java   |   4 -
 .../util/core/task/DynamicSequentialTask.java   |   1 +
 .../brooklyn/util/core/task/DynamicTasks.java   |   1 +
 .../brooklyn/util/core/task/ForwardingTask.java |  16 +
 .../core/task/ListenableForwardingFuture.java   |  75 ----
 .../brooklyn/util/core/task/ScheduledTask.java  |  55 ++-
 .../brooklyn/util/core/task/TaskInternal.java   |  16 +-
 .../task/TaskInternalCancellableWithMode.java   |  32 ++
 .../brooklyn/util/core/task/TaskTags.java       |  10 +-
 .../apache/brooklyn/util/core/task/Tasks.java   |   4 +-
 .../brooklyn/util/core/task/ValueResolver.java  |  10 +-
 .../core/effector/EffectorSayHiTest.java        |  20 +-
 .../brooklyn/core/entity/EntityConfigTest.java  |  12 +
 .../internal/EntityExecutionManagerTest.java    |   1 -
 .../core/mgmt/rebind/RebindFeedTest.java        |   4 +-
 .../util/core/task/BasicTasksFutureTest.java    |  58 ++-
 .../core/task/DynamicSequentialTaskTest.java    |  17 +-
 .../core/task/NonBasicTaskExecutionTest.java    |   8 +-
 .../util/core/task/ScheduledExecutionTest.java  |  19 +-
 .../util/core/task/ValueResolverTest.java       |   3 +-
 .../policy/ha/AbstractFailureDetector.java      |   3 +-
 .../java/org/apache/brooklyn/test/Asserts.java  |  27 +-
 .../brooklyn/util/collections/MutableSet.java   |  14 +-
 .../org/apache/brooklyn/util/guava/Maybe.java   |  43 ++-
 .../apache/brooklyn/util/repeat/Repeater.java   |  25 +-
 45 files changed, 954 insertions(+), 472 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/baf80709/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/baf80709/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/baf80709/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindManagerImpl.java
----------------------------------------------------------------------


[20/35] brooklyn-server git commit: tidy how cross-context submitted, and use simple tasks in more places

Posted by he...@apache.org.
tidy how cross-context submitted, and use simple tasks in more places


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

Branch: refs/heads/master
Commit: ab480ed288e7ccca90f8c05c06a817169cedd659
Parents: 24250a5
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Sun Sep 17 12:47:10 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Mon Sep 18 16:40:46 2017 +0100

----------------------------------------------------------------------
 .../util/core/task/BasicExecutionContext.java   | 74 ++++++++++++--------
 .../apache/brooklyn/util/core/task/Tasks.java   |  2 +-
 2 files changed, 46 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/ab480ed2/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
index 7953b14..114aac7 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
@@ -25,6 +25,7 @@ import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.Callable;
+import java.util.concurrent.CancellationException;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
@@ -169,11 +170,21 @@ public class BasicExecutionContext extends AbstractExecutionContext {
 
         @Override
         public boolean isDone() {
-            return done;
+            return done || cancelled;
         }
 
         @Override
         public T get() throws InterruptedException, ExecutionException {
+            if (!isDone()) {
+                synchronized (this) {
+                    while (!isDone()) {
+                        wait(1000);
+                    }
+                }
+            }
+            if (isCancelled() && !done) {
+                throw new CancellationException();
+            }
             return result.get();
         }
 
@@ -203,7 +214,10 @@ public class BasicExecutionContext extends AbstractExecutionContext {
             ((BasicExecutionManager)executionManager).afterSubmitRecordFuture(task, future);
             ((BasicExecutionManager)executionManager).beforeStartInSameThreadTask(null, task);
 
-            // TODO this does not apply the same context-switching logic as submit
+            // TODO this does not apply the same context-switching logic as submit;
+            // means if task on X submits via this method a non-child (non-queued) task for an effector on Y,
+            // a request to get all of X's tasks recursively won't pick up the call on Y
+            // (because parent tasks don't have records of submitted tasks unless they are children) 
             
             return future.set(job.call());
             
@@ -256,6 +270,7 @@ public class BasicExecutionContext extends AbstractExecutionContext {
         try {
             return runInSameThread(fakeTaskForContext, new Callable<Maybe<T>>() {
                 public Maybe<T> call() {
+                    // TODO do we really want to cancel? means if it submits other things they won't run, even if they return immediately
                     fakeTaskForContext.cancel();
                     
                     boolean wasAlreadyInterrupted = Thread.interrupted();
@@ -303,43 +318,44 @@ public class BasicExecutionContext extends AbstractExecutionContext {
              * (e.g. where entity X is invoking an effector on Y, it will start in X's context, 
              * but the effector should run in Y's context).
              * 
-             * if X is invoking an effector on himself in his own context, or a sensor or other task, it will not come in to this block.
+             * we need to make sure there is a reference from this execution context to the submitted task,
+             * IE the submitted task is a child of something in this execution context.
+             * this ensures it shows up via the REST API and in the UI; without it we lose the reference to the child when browsing in the context of the parent.
+             * 
+             * if it is queued or it is already recorded as a child we can simply submit in target context;
+             * but if not we need to wrap it in a task running in this context with the submitted task as a child to have that reference.
              */
             final ExecutionContext tc = ((EntityInternal)target).getExecutionContext();
             if (log.isDebugEnabled())
                 log.debug("Switching task context on execution of "+task+": from "+this+" to "+target+" (in "+Tasks.current()+")");
             
+            final Task<T> t;
             if (task instanceof Task<?>) {
-                final Task<T> t = (Task<T>)task;
-                if (!Tasks.isQueuedOrSubmitted(t) && (!(Tasks.current() instanceof HasTaskChildren) || 
-                        !Iterables.contains( ((HasTaskChildren)Tasks.current()).getChildren(), t ))) {
-                    // this task is switching execution context boundaries _and_ it is not a child and not yet queued,
-                    // so wrap it in a task running in this context to keep a reference to the child
-                    // (this matters when we are navigating in the GUI; without it we lose the reference to the child 
-                    // when browsing in the context of the parent)
-                    return submit(Tasks.<T>builder().displayName("Cross-context execution: "+t.getDescription()).dynamic(true).body(new Callable<T>() {
-                        @Override
-                        public T call() { 
-                            return DynamicTasks.get(t); 
-                        }
-                    }).build());
-                } else {
-                    // if we are already tracked by parent, just submit it 
+                t = (Task<T>)task;
+                if (Tasks.isQueuedOrSubmitted(t) ||
+                        ((Tasks.current() instanceof HasTaskChildren) && Iterables.contains( ((HasTaskChildren)Tasks.current()).getChildren(), t ))) {
+                    // we are already tracked by parent, just submit it 
                     return tc.submit(t);
                 }
             } else {
-                // as above, but here we are definitely not a child (what we are submitting isn't even a task)
-                // (will only come here if properties defines tags including a target entity, which probably never happens) 
-                submit(Tasks.<T>builder().displayName("Cross-context execution").dynamic(true).body(() -> {
-                    if (task instanceof Callable) {
-                        return DynamicTasks.queue( Tasks.<T>builder().dynamic(false).body((Callable<T>)task).build() ).getUnchecked();
-                    } else if (task instanceof Runnable) {
-                        return DynamicTasks.queue( Tasks.<T>builder().dynamic(false).body((Runnable)task).build() ).getUnchecked();
-                    } else {
-                        throw new IllegalArgumentException("Unhandled task type: "+task+"; type="+(task!=null ? task.getClass() : "null"));
-                    }
-                }).build());
+                // for callables and runnables there is definitely no record
+                if (task instanceof Callable) {
+                    t = Tasks.<T>builder().dynamic(false).body((Callable<T>)task).build();
+                } else if (task instanceof Runnable) {
+                    t = Tasks.<T>builder().dynamic(false).body((Runnable)task).build();
+                } else {
+                    throw new IllegalArgumentException("Unhandled task type: "+task+"; type="+(task!=null ? task.getClass() : "null"));
+                }                
             }
+                
+            return submit(
+                // 2017-09 changed, doesn't have to be a dynamic task; can be a simple sequential task wrapping the child
+                Tasks.<T>builder().displayName("Cross-context execution: "+t.getDescription()).dynamic(false).parallel(false).body(new Callable<T>() {
+                    @Override
+                    public T call() { 
+                        return tc.get(t); 
+                    }
+                }).build() );
         }
 
         EntitlementContext entitlementContext = BrooklynTaskTags.getEntitlement(taskTags);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/ab480ed2/core/src/main/java/org/apache/brooklyn/util/core/task/Tasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/Tasks.java b/core/src/main/java/org/apache/brooklyn/util/core/task/Tasks.java
index 2db73df..12247c4 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/Tasks.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/Tasks.java
@@ -234,7 +234,7 @@ public class Tasks {
         return sequential(name, asTasks(Iterables.toArray(tasks, TaskAdaptable.class)));
     }
     private static Task<List<?>> sequentialInternal(String name, Task<?>[] tasks) {
-        return Tasks.<List<?>>builder().displayName(name).parallel(false).add(tasks).build();
+        return Tasks.<List<?>>builder().displayName(name).dynamic(false).parallel(false).add(tasks).build();
     }
     private static TaskFactory<?> sequentialInternal(final String name, final TaskFactory<?> ...taskFactories) {
         return new TaskFactory<TaskAdaptable<?>>() {


[23/35] brooklyn-server git commit: clean up config rest utils following deprecation of config classes

Posted by he...@apache.org.
clean up config rest utils following deprecation of config classes


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

Branch: refs/heads/master
Commit: 83c3d5006e653d4d70ebbf46759bf7ecd29c581a
Parents: 62bcbc5
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Sep 25 13:00:46 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Mon Sep 25 13:04:38 2017 +0100

----------------------------------------------------------------------
 .../rest/resources/AdjunctResource.java         |   3 +-
 .../rest/resources/CatalogResource.java         |  21 ++-
 .../rest/resources/EntityConfigResource.java    |   4 +-
 .../rest/transform/AdjunctTransformer.java      |  34 +---
 .../rest/transform/CatalogTransformer.java      |  30 ++--
 .../rest/transform/ConfigTransformer.java       | 173 +++++++++++++++++++
 .../rest/transform/EntityTransformer.java       | 114 ++----------
 .../rest/transform/SensorTransformer.java       |  21 ++-
 .../rest/transform/TypeTransformer.java         |   6 +-
 .../brooklyn/cli/lister/ItemDescriptors.java    |  10 +-
 10 files changed, 257 insertions(+), 159 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/83c3d500/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java
index 3b5185a..08f3698 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java
@@ -49,6 +49,7 @@ import org.apache.brooklyn.rest.domain.Status;
 import org.apache.brooklyn.rest.domain.SummaryComparators;
 import org.apache.brooklyn.rest.filter.HaHotStateRequired;
 import org.apache.brooklyn.rest.transform.AdjunctTransformer;
+import org.apache.brooklyn.rest.transform.ConfigTransformer;
 import org.apache.brooklyn.rest.transform.EntityTransformer;
 import org.apache.brooklyn.rest.util.BrooklynRestResourceUtils;
 import org.apache.brooklyn.rest.util.WebResourceUtils;
@@ -215,7 +216,7 @@ public class AdjunctResource extends AbstractBrooklynRestResource implements Adj
 
         List<ConfigSummary> result = Lists.newArrayList();
         for (ConfigKey<?> key : adjunct.config().findKeysPresent(Predicates.alwaysTrue())) {
-            result.add(AdjunctTransformer.configSummary(brooklyn(), ui.getBaseUriBuilder(), entity, adjunct, key));
+            result.add(ConfigTransformer.of(key).on(entity, adjunct).includeLinks(ui.getBaseUriBuilder(), false, true).transform());
         }
         return result;
     }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/83c3d500/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
index 65e6956..f95c1ee 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
@@ -84,6 +84,7 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
     private static final Logger log = LoggerFactory.getLogger(CatalogResource.class);
     private static final String LATEST = "latest";
     
+    @Deprecated
     private Function<RegisteredType, CatalogItemSummary> toCatalogItemSummary(final UriInfo ui) {
         return new Function<RegisteredType, CatalogItemSummary>() {
             @Override
@@ -202,11 +203,13 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
     }
 
     @Override
+    @Deprecated
     public void deleteApplication(String symbolicName, String version) throws Exception {
         deleteEntity(symbolicName, version);
     }
 
     @Override
+    @Deprecated
     public void deleteEntity(String symbolicName, String version) throws Exception {
         if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.MODIFY_CATALOG_ITEM, StringAndArgument.of(symbolicName+(Strings.isBlank(version) ? "" : ":"+version), "delete"))) {
             throw WebResourceUtils.forbidden("User '%s' is not authorized to modify catalog",
@@ -226,6 +229,7 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
     }
 
     @Override
+    @Deprecated
     public void deletePolicy(String policyId, String version) throws Exception {
         if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.MODIFY_CATALOG_ITEM, StringAndArgument.of(policyId+(Strings.isBlank(version) ? "" : ":"+version), "delete"))) {
             throw WebResourceUtils.forbidden("User '%s' is not authorized to modify catalog",
@@ -245,6 +249,7 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
     }
 
     @Override
+    @Deprecated
     public void deleteLocation(String locationId, String version) throws Exception {
         if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.MODIFY_CATALOG_ITEM, StringAndArgument.of(locationId+(Strings.isBlank(version) ? "" : ":"+version), "delete"))) {
             throw WebResourceUtils.forbidden("User '%s' is not authorized to modify catalog",
@@ -264,6 +269,7 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
     }
 
     @Override
+    @Deprecated
     public List<CatalogEntitySummary> listEntities(String regex, String fragment, boolean allVersions) {
         Predicate<RegisteredType> filter =
                 Predicates.and(
@@ -274,6 +280,7 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
     }
 
     @Override
+    @Deprecated
     public List<CatalogItemSummary> listApplications(String regex, String fragment, boolean allVersions) {
         @SuppressWarnings("unchecked")
         Predicate<RegisteredType> filter =
@@ -285,6 +292,7 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
     }
     
     @Override
+    @Deprecated
     public CatalogEntitySummary getEntity(String symbolicName, String version) {
         if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_CATALOG_ITEM, symbolicName+(Strings.isBlank(version)?"":":"+version))) {
             throw WebResourceUtils.forbidden("User '%s' is not authorized to see catalog entry",
@@ -302,11 +310,13 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
     }
 
     @Override
+    @Deprecated
     public CatalogEntitySummary getApplication(String symbolicName, String version) {
         return getEntity(symbolicName, version);
     }
 
     @Override
+    @Deprecated
     public List<CatalogPolicySummary> listPolicies(String regex, String fragment, boolean allVersions) {
         Predicate<RegisteredType> filter =
                 Predicates.and(
@@ -317,6 +327,7 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
     }
 
     @Override
+    @Deprecated
     public CatalogPolicySummary getPolicy(String policyId, String version) throws Exception {
         if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_CATALOG_ITEM, policyId+(Strings.isBlank(version)?"":":"+version))) {
             throw WebResourceUtils.forbidden("User '%s' is not authorized to see catalog entry",
@@ -333,6 +344,7 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
     }
 
     @Override
+    @Deprecated
     public List<CatalogLocationSummary> listLocations(String regex, String fragment, boolean allVersions) {
         Predicate<RegisteredType> filter =
                 Predicates.and(
@@ -343,6 +355,7 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
     }
 
     @Override
+    @Deprecated
     public CatalogLocationSummary getLocation(String locationId, String version) throws Exception {
         if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_CATALOG_ITEM, locationId+(Strings.isBlank(version)?"":":"+version))) {
             throw WebResourceUtils.forbidden("User '%s' is not authorized to see catalog entry",
@@ -359,6 +372,7 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
     }
 
     @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Deprecated
     private <T,SpecT> List<CatalogItemSummary> getCatalogItemSummariesMatchingRegexFragment(
             Predicate<RegisteredType> type, String regex, String fragment, boolean allVersions) {
         List<Predicate<RegisteredType>> filters = new ArrayList();
@@ -390,8 +404,8 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
         return getCatalogItemIcon(mgmt().getTypeRegistry().get(itemId, version));
     }
     
-    @SuppressWarnings("deprecation")
     @Override
+    @Deprecated
     public void setDeprecated(String itemId, boolean deprecated) {
         if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.MODIFY_CATALOG_ITEM, StringAndArgument.of(itemId, "deprecated"))) {
             throw WebResourceUtils.forbidden("User '%s' is not authorized to modify catalog",
@@ -400,8 +414,8 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
         CatalogUtils.setDeprecated(mgmt(), itemId, deprecated);
     }
 
-    @SuppressWarnings("deprecation")
     @Override
+    @Deprecated
     public void setDisabled(String itemId, boolean disabled) {
         if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.MODIFY_CATALOG_ITEM, StringAndArgument.of(itemId, "disabled"))) {
             throw WebResourceUtils.forbidden("User '%s' is not authorized to modify catalog",
@@ -411,6 +425,7 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
     }
 
     @Override
+    @Deprecated
     public List<CatalogEnricherSummary> listEnrichers(@ApiParam(name = "regex", value = "Regular expression to search for") @DefaultValue("") String regex, @ApiParam(name = "fragment", value = "Substring case-insensitive to search for") @DefaultValue("") String fragment, @ApiParam(name = "allVersions", value = "Include all versions (defaults false, only returning the best version)") @DefaultValue("false") boolean includeAllVersions) {
         Predicate<RegisteredType> filter =
                 Predicates.and(
@@ -421,6 +436,7 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
     }
 
     @Override
+    @Deprecated
     public CatalogEnricherSummary getEnricher(@ApiParam(name = "enricherId", value = "The ID of the enricher to retrieve", required = true) String enricherId, @ApiParam(name = "version", value = "The version identifier of the enricher to retrieve", required = true) String version) throws Exception {
         if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_CATALOG_ITEM, enricherId+(Strings.isBlank(version)?"":":"+version))) {
             throw WebResourceUtils.forbidden("User '%s' is not authorized to see catalog entry",
@@ -436,6 +452,7 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
     }
 
     @Override
+    @Deprecated
     public void deleteEnricher(@ApiParam(name = "enricherId", value = "The ID of the enricher to delete", required = true) String enricherId, @ApiParam(name = "version", value = "The version identifier of the enricher to delete", required = true) String version) throws Exception {
         if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.MODIFY_CATALOG_ITEM, StringAndArgument.of(enricherId+(Strings.isBlank(version) ? "" : ":"+version), "delete"))) {
             throw WebResourceUtils.forbidden("User '%s' is not authorized to modify catalog",

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/83c3d500/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/EntityConfigResource.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/EntityConfigResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/EntityConfigResource.java
index dd909e4..3431b99 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/EntityConfigResource.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/EntityConfigResource.java
@@ -34,7 +34,7 @@ import org.apache.brooklyn.core.mgmt.entitlement.Entitlements.EntityAndItem;
 import org.apache.brooklyn.rest.api.EntityConfigApi;
 import org.apache.brooklyn.rest.domain.ConfigSummary;
 import org.apache.brooklyn.rest.filter.HaHotStateRequired;
-import org.apache.brooklyn.rest.transform.EntityTransformer;
+import org.apache.brooklyn.rest.transform.ConfigTransformer;
 import org.apache.brooklyn.rest.util.WebResourceUtils;
 import org.apache.brooklyn.util.core.flags.TypeCoercions;
 import org.apache.brooklyn.util.core.task.Tasks;
@@ -70,7 +70,7 @@ public class EntityConfigResource extends AbstractBrooklynRestResource implement
                         new Object[] {Entitlements.getEntitlementContext().user(), key.getName(), entity});
                 continue;
             }
-            result.add(EntityTransformer.configSummary(brooklyn(), ui.getBaseUriBuilder(), entity, key));
+            result.add(ConfigTransformer.of(key).on(entity).includeLinks(ui.getBaseUriBuilder(), true, true).transform());
         }
         
         return result;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/83c3d500/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java
index f841f33..a00cb6e 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java
@@ -23,22 +23,17 @@ import static org.apache.brooklyn.rest.util.WebResourceUtils.serviceUriBuilder;
 import java.net.URI;
 import java.util.Map;
 
-import javax.annotation.Nullable;
 import javax.ws.rs.core.UriBuilder;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.objs.EntityAdjunct;
-import org.apache.brooklyn.api.objs.SpecParameter;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.api.sensor.Feed;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.policy.Policies;
 import org.apache.brooklyn.rest.api.AdjunctApi;
-import org.apache.brooklyn.rest.api.ApplicationApi;
-import org.apache.brooklyn.rest.api.EntityApi;
 import org.apache.brooklyn.rest.domain.AdjunctDetail;
 import org.apache.brooklyn.rest.domain.AdjunctSummary;
-import org.apache.brooklyn.rest.domain.ConfigSummary;
 import org.apache.brooklyn.rest.domain.Status;
 import org.apache.brooklyn.rest.util.BrooklynRestResourceUtils;
 import org.apache.brooklyn.util.collections.MutableMap;
@@ -62,7 +57,7 @@ public class AdjunctTransformer {
     public static AdjunctDetail adjunctDetail(BrooklynRestResourceUtils utils, Entity entity, EntityAdjunct adjunct, UriBuilder ub) {
         AdjunctDetail result = embellish(new AdjunctDetail(adjunct), entity, adjunct, ub);
         for (ConfigKey<?> key: adjunct.config().findKeysDeclared(Predicates.alwaysTrue())) {
-            result.parameter(configSummary(utils, ub, entity, adjunct, key));
+            result.parameter(ConfigTransformer.of(key).on(entity, adjunct).includeLinks(ub, false, true).transform());
         }
         result.config(EntityTransformer.getConfigValues(utils, adjunct));
         return result;
@@ -74,8 +69,10 @@ public class AdjunctTransformer {
         links.put("self", serviceUriBuilder(ub, AdjunctApi.class, "get").build(entity.getApplicationId(), entity.getId(), adjunct.getId()));
         
         if (detail) {
-            links.put("application", serviceUriBuilder(ub, ApplicationApi.class, "get").build(entity.getApplicationId()));
-            links.put("entity", serviceUriBuilder(ub, EntityApi.class, "get").build(entity.getApplicationId(), entity.getId()));
+            links.put("application", EntityTransformer.applicationUri(entity.getApplication(), ub) );
+            links.put("entity", EntityTransformer.entityUri(entity, ub) );
+            links.put("adjunct", adjunctUri(entity, adjunct, ub) );
+            
             links.put("config", serviceUriBuilder(ub, AdjunctApi.class, "listConfig").build(entity.getApplicationId(), entity.getId(), adjunct.getId()));
             links.put("status", serviceUriBuilder(ub, AdjunctApi.class, "getStatus").build(entity.getApplicationId(), entity.getId(), adjunct.getId()));
             if (adjunct instanceof Policy || adjunct instanceof Feed) {
@@ -92,25 +89,8 @@ public class AdjunctTransformer {
         return ApplicationTransformer.statusFromLifecycle( Policies.inferAdjunctStatus(adjunct) );
     }
 
-    public static ConfigSummary configSummary(BrooklynRestResourceUtils utils, UriBuilder ub, @Nullable Entity entity, @Nullable EntityAdjunct adjunct, SpecParameter<?> input) {
-        Double priority = input.isPinned() ? Double.valueOf(1d) : null;
-        return configSummary(utils, ub, entity, adjunct, input.getConfigKey(), input.getLabel(), priority, input.isPinned());
+    public static URI adjunctUri(Entity entity, EntityAdjunct adjunct, UriBuilder ub) {
+        return serviceUriBuilder(ub, AdjunctApi.class, "get").build(entity.getApplicationId(), entity.getId(), adjunct.getId());
     }
 
-    public static ConfigSummary configSummary(BrooklynRestResourceUtils utils, UriBuilder ub, Entity entity, EntityAdjunct adjunct, ConfigKey<?> config) {
-        // TODO get catalog info from other sources?
-        // see EntityTransformer.configSummary
-        return configSummary(utils, ub, entity, adjunct, config, null, null, null);
-    }
-    public static ConfigSummary configSummary(BrooklynRestResourceUtils utils, UriBuilder ub, @Nullable Entity entity, @Nullable EntityAdjunct adjunct, ConfigKey<?> config, String label, Double priority, Boolean pinned) {
-        URI configUri = entity==null ? null : serviceUriBuilder(ub, AdjunctApi.class, "getConfig").build(entity.getApplicationId(), entity.getId(), adjunct.getId(), config.getName());
-        Map<String, URI> links = MutableMap.<String, URI>builder()
-                .putIfNotNull("self", configUri)
-                // no point in including app/entity on every summary shown in a list
-                // (this is only ever used in a list, as self points at the value)
-                .build();
-
-        // TODO get actions, see EntityTransformer.configSummary
-        return new ConfigSummary(config, label, priority, pinned, links);
-    }
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/83c3d500/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/CatalogTransformer.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/CatalogTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/CatalogTransformer.java
index aa30dd5..6eeaeb8 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/CatalogTransformer.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/CatalogTransformer.java
@@ -71,6 +71,8 @@ import org.slf4j.LoggerFactory;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
 
+/** @deprecated since 0.13.0 use RegisteredType methods */
+@Deprecated
 public class CatalogTransformer {
 
     private static final org.slf4j.Logger log = LoggerFactory.getLogger(CatalogTransformer.class);
@@ -87,9 +89,9 @@ public class CatalogTransformer {
             EntityDynamicType typeMap = BrooklynTypes.getDefinedEntityType(spec.getType());
             EntityType type = typeMap.getSnapshot();
 
-            AtomicInteger paramPriorityCnt = new AtomicInteger();
+            AtomicInteger priority = new AtomicInteger();
             for (SpecParameter<?> input: spec.getParameters())
-                config.add(EntityTransformer.entityConfigSummary(input, paramPriorityCnt));
+                config.add(ConfigTransformer.of(input).uiIncrementAndSetPriorityIfPinned(priority).transformLegacyEntityConfig());
             for (Sensor<?> x: type.getSensors())
                 sensors.add(SensorTransformer.sensorSummaryForCatalog(x));
             for (Effector<?> x: type.getEffectors())
@@ -149,8 +151,9 @@ public class CatalogTransformer {
         PolicySpec<?> spec = null;
         try{
             spec = b.getTypeRegistry().createSpec(item, null, PolicySpec.class);
-            for (final SpecParameter<?> input : spec.getParameters()){
-                config.add(EntityTransformer.policyConfigSummary(input));
+            AtomicInteger priority = new AtomicInteger();
+            for (SpecParameter<?> input: spec.getParameters()) {
+                config.add(ConfigTransformer.of(input).uiIncrementAndSetPriorityIfPinned(priority).transformLegacyPolicyConfig());
             }
         }catch (Exception e) {
             Exceptions.propagateIfFatal(e);
@@ -169,8 +172,9 @@ public class CatalogTransformer {
         EnricherSpec<?> spec = null;
         try{
             spec = b.getTypeRegistry().createSpec(item, null, EnricherSpec.class);
-            for (final SpecParameter<?> input : spec.getParameters()){
-                config.add(EntityTransformer.enricherConfigSummary(input));
+            AtomicInteger priority = new AtomicInteger();
+            for (SpecParameter<?> input: spec.getParameters()) {
+                config.add(ConfigTransformer.of(input).uiIncrementAndSetPriorityIfPinned(priority).transformLegacyEnricherConfig());
             }
         }catch (Exception e) {
             Exceptions.propagateIfFatal(e);
@@ -257,9 +261,9 @@ public class CatalogTransformer {
             EntityDynamicType typeMap = BrooklynTypes.getDefinedEntityType(spec.getType());
             EntityType type = typeMap.getSnapshot();
 
-            AtomicInteger paramPriorityCnt = new AtomicInteger();
+            AtomicInteger priority = new AtomicInteger();
             for (SpecParameter<?> input: spec.getParameters())
-                config.add(EntityTransformer.entityConfigSummary(input, paramPriorityCnt));
+                config.add(ConfigTransformer.of(input).uiIncrementAndSetPriorityIfPinned(priority).transformLegacyEntityConfig());
             for (Sensor<?> x: type.getSensors())
                 sensors.add(SensorTransformer.sensorSummaryForCatalog(x));
             for (Effector<?> x: type.getEffectors())
@@ -315,8 +319,9 @@ public class CatalogTransformer {
         final Set<PolicyConfigSummary> config = Sets.newLinkedHashSet();
         try{
             final PolicySpec<?> spec = (PolicySpec<?>) b.getCatalog().peekSpec(item);
-            for (final SpecParameter<?> input : spec.getParameters()){
-                config.add(EntityTransformer.policyConfigSummary(input));
+            AtomicInteger priority = new AtomicInteger();
+            for (SpecParameter<?> input: spec.getParameters()) {
+                config.add(ConfigTransformer.of(input).uiIncrementAndSetPriorityIfPinned(priority).transformLegacyPolicyConfig());
             }
         }catch (Exception e) {
             Exceptions.propagateIfFatal(e);
@@ -333,8 +338,9 @@ public class CatalogTransformer {
         final Set<EnricherConfigSummary> config = Sets.newLinkedHashSet();
         try{
             final EnricherSpec<?> spec = (EnricherSpec<?>) b.getCatalog().peekSpec(item);
-            for (final SpecParameter<?> input : spec.getParameters()){
-                config.add(EntityTransformer.enricherConfigSummary(input));
+            AtomicInteger priority = new AtomicInteger();
+            for (SpecParameter<?> input: spec.getParameters()) {
+                config.add(ConfigTransformer.of(input).uiIncrementAndSetPriorityIfPinned(priority).transformLegacyEnricherConfig());
             }
         }catch (Exception e) {
             Exceptions.propagateIfFatal(e);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/83c3d500/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/ConfigTransformer.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/ConfigTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/ConfigTransformer.java
new file mode 100644
index 0000000..22d4299
--- /dev/null
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/ConfigTransformer.java
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.rest.transform;
+
+import static org.apache.brooklyn.rest.util.WebResourceUtils.serviceUriBuilder;
+
+import java.lang.reflect.Field;
+import java.net.URI;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.ws.rs.core.UriBuilder;
+
+import org.apache.brooklyn.api.catalog.CatalogConfig;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.objs.BrooklynObject;
+import org.apache.brooklyn.api.objs.EntityAdjunct;
+import org.apache.brooklyn.api.objs.SpecParameter;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.render.RendererHints;
+import org.apache.brooklyn.rest.api.AdjunctApi;
+import org.apache.brooklyn.rest.api.EntityConfigApi;
+import org.apache.brooklyn.rest.domain.ConfigSummary;
+import org.apache.brooklyn.util.collections.MutableMap;
+
+import com.google.common.collect.Iterables;
+
+public class ConfigTransformer {
+
+    private final ConfigKey<?> key;
+
+    UriBuilder ub;
+    boolean includeContextLinks, includeActionLinks;
+    Entity entity;
+    EntityAdjunct adjunct;
+    
+    String label;
+    Double priority;
+    Boolean pinned;
+    
+    public static ConfigTransformer of(ConfigKey<?> key) {
+        return new ConfigTransformer(key);
+    }
+
+    public static ConfigTransformer of(SpecParameter<?> param) {
+        ConfigTransformer result = of(param.getConfigKey());
+        result.label = param.getLabel();
+        result.pinned = param.isPinned();
+        return result;
+    }
+
+    private ConfigTransformer(ConfigKey<?> key) {
+        this.key = key;
+    }
+    
+    public ConfigTransformer on(Entity entity) {
+        this.entity = entity;
+        return this;
+    }
+    
+    public ConfigTransformer on(Entity entity, EntityAdjunct adjunct) {
+        this.entity = entity;
+        this.adjunct = adjunct;
+        return this;
+    }
+    
+    public ConfigTransformer includeLinks(UriBuilder ub, boolean includeContextLinks, boolean includeActionLinks) {
+        this.ub = ub;
+        this.includeContextLinks = includeContextLinks;
+        this.includeActionLinks = includeActionLinks;
+        return this;
+    }
+    
+    public ConfigTransformer uiMetadata(String label, Double priority, Boolean pinned) {
+        this.label = label;
+        this.priority = priority;
+        this.pinned = pinned;
+        return this;
+    }
+    
+    public ConfigTransformer uiMetadata(String label, Boolean pinned) {
+        return uiMetadata(label, Boolean.TRUE.equals(pinned) ? 1.0d : 0, pinned);
+    }
+    
+    public ConfigTransformer uiIncrementAndSetPriorityIfPinned(AtomicInteger lastPriority) {
+        if (Boolean.TRUE.equals(pinned)) {
+            this.priority = (double) lastPriority.incrementAndGet();
+        }
+        return this;
+    }
+
+    public ConfigTransformer uiMetadata(Field keyField) {
+        if (keyField==null) return this;
+        return uiMetadata(keyField.getDeclaredAnnotation(CatalogConfig.class));
+    }
+        
+    public ConfigTransformer uiMetadata(CatalogConfig annotation) {
+        if (annotation==null) return this;
+        return uiMetadata(annotation.label(), annotation.priority(), annotation.pinned());
+    }
+    
+    public ConfigSummary transform() {
+        MutableMap.Builder<String, URI> lb = new MutableMap.Builder<String, URI>();
+        
+        if (ub!=null && entity!=null) {
+            URI self;
+            if (adjunct!=null) {
+                self = serviceUriBuilder(ub, AdjunctApi.class, "getConfig").build(entity.getApplicationId(), entity.getId(), adjunct.getId(), key.getName());
+            } else {
+                self = serviceUriBuilder(ub, EntityConfigApi.class, "get").build(entity.getApplicationId(), entity.getId(), key.getName());
+            }
+            lb.put("self", self);
+            
+            if (includeContextLinks) {
+                // TODO wasteful including these
+                lb.put("application", EntityTransformer.applicationUri(entity.getApplication(), ub) );
+                lb.put("entity", EntityTransformer.entityUri(entity, ub) );
+                if (adjunct!=null) {
+                    lb.put("adjunct", AdjunctTransformer.adjunctUri(entity, adjunct, ub) );
+                }
+            }
+            if (includeActionLinks) {
+                // TODO is this json or a display value?
+                lb.put("action:json", self);
+                
+                Iterable<RendererHints.NamedAction> hints = Iterables.filter(RendererHints.getHintsFor(key), RendererHints.NamedAction.class);
+                BrooklynObject context = adjunct!=null ? adjunct : entity;
+                for (RendererHints.NamedAction na : hints) {
+                    SensorTransformer.addNamedAction(lb, na, context.getConfig(key), key, context);
+                }
+            }
+            
+        }
+
+        // TODO if ui metadata not set try to infer or get more info from caller ?
+        
+        return new ConfigSummary(key, label, priority, pinned, lb.build());
+    }
+
+    @Deprecated
+    public org.apache.brooklyn.rest.domain.EntityConfigSummary transformLegacyEntityConfig() {
+        ConfigSummary v2 = transform();
+        return new org.apache.brooklyn.rest.domain.EntityConfigSummary(key, v2.getLabel(), v2.getPriority(), v2.isPinned(), v2.getLinks()); 
+    }
+
+    @Deprecated
+    public org.apache.brooklyn.rest.domain.EnricherConfigSummary transformLegacyEnricherConfig() {
+        ConfigSummary v2 = transform();
+        return new org.apache.brooklyn.rest.domain.EnricherConfigSummary(key, v2.getLabel(), v2.getPriority(), v2.getLinks()); 
+    }
+
+    @Deprecated
+    public org.apache.brooklyn.rest.domain.PolicyConfigSummary transformLegacyPolicyConfig() {
+        ConfigSummary v2 = transform();
+        return new org.apache.brooklyn.rest.domain.PolicyConfigSummary(key, v2.getLabel(), v2.getPriority(), v2.getLinks()); 
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/83c3d500/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/EntityTransformer.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/EntityTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/EntityTransformer.java
index 9359bb5..1537f07 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/EntityTransformer.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/EntityTransformer.java
@@ -36,25 +36,21 @@ import org.apache.brooklyn.api.objs.BrooklynObject;
 import org.apache.brooklyn.api.objs.SpecParameter;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
-import org.apache.brooklyn.core.config.render.RendererHints;
 import org.apache.brooklyn.core.objs.BrooklynObjectInternal;
 import org.apache.brooklyn.core.typereg.RegisteredTypes;
 import org.apache.brooklyn.rest.api.ApplicationApi;
 import org.apache.brooklyn.rest.api.CatalogApi;
 import org.apache.brooklyn.rest.api.EntityApi;
-import org.apache.brooklyn.rest.api.EntityConfigApi;
 import org.apache.brooklyn.rest.domain.ConfigSummary;
 import org.apache.brooklyn.rest.domain.EnricherConfigSummary;
 import org.apache.brooklyn.rest.domain.EntityConfigSummary;
 import org.apache.brooklyn.rest.domain.EntitySummary;
 import org.apache.brooklyn.rest.domain.PolicyConfigSummary;
 import org.apache.brooklyn.rest.util.BrooklynRestResourceUtils;
-import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 
@@ -126,89 +122,39 @@ public class EntityTransformer {
             }));
     }
 
-    /** @deprecated since 0.13.0 use {@link #configSummary(BrooklynRestResourceUtils, UriBuilder, Entity, ConfigKey, String, Double, Boolean) */
+    public static URI applicationUri(Application entity, UriBuilder ub) {
+        return serviceUriBuilder(ub, ApplicationApi.class, "get").build(entity.getApplicationId());
+    }
+    
+    public static URI entityUri(Entity entity, UriBuilder ub) {
+        return serviceUriBuilder(ub, EntityApi.class, "get").build(entity.getApplicationId(), entity.getId());
+    }
+    
+    /** @deprecated since 0.13.0 use {@link ConfigTransformer} */
     @Deprecated
     public static EntityConfigSummary entityConfigSummary(ConfigKey<?> config, String label, Double priority, Boolean pinned, Map<String, URI> links) {
         return new EntityConfigSummary(config, label, priority, pinned, links);
     }
 
-    /** @deprecated since 0.13.0 use {@link AdjunctTransformer#configSummary(BrooklynRestResourceUtils, UriBuilder, Entity, org.apache.brooklyn.api.objs.EntityAdjunct, ConfigKey, String, Double, Boolean)} */
+    /** @deprecated since 0.13.0 use {@link ConfigTransformer} */
     @Deprecated
     public static PolicyConfigSummary policyConfigSummary(ConfigKey<?> config, String label, Double priority, Map<String, URI> links) {
         return new PolicyConfigSummary(config, label, priority, links);
     }
 
-    /** @deprecated since 0.13.0 use {@link AdjunctTransformer#configSummary(BrooklynRestResourceUtils, UriBuilder, Entity, org.apache.brooklyn.api.objs.EntityAdjunct, ConfigKey, String, Double, Boolean)} */
+    /** @deprecated since 0.13.0 use {@link ConfigTransformer} */
     @Deprecated
     public static EnricherConfigSummary enricherConfigSummary(ConfigKey<?> config, String label, Double priority, Map<String, URI> links) {
         return new EnricherConfigSummary(config, label, priority, links);
     }
 
-    /** generates a representation for a given config key, 
-     * with label inferred from annoation in the entity class,
-     * and links pointing to the entity and the application 
-     * @deprecated since 0.13.0 use {@link #configSummary(BrooklynRestResourceUtils, UriBuilder, Entity, ConfigKey)} */
+    /** @deprecated since 0.13.0 use {@link ConfigTransformer} */
     @Deprecated
-    public static EntityConfigSummary entityConfigSummary(Entity entity, ConfigKey<?> config, UriBuilder ub) {
-        return (EntityConfigSummary) configSummary(null, ub, entity, config);
+    public static ConfigSummary entityConfigSummary(Entity entity, ConfigKey<?> config, UriBuilder ub) {
+        return ConfigTransformer.of(config).on(entity).includeLinks(ub, true, true).transform();
     }
-    
-    public static ConfigSummary configSummary(BrooklynRestResourceUtils utils, UriBuilder ub, Entity entity, ConfigKey<?> config) {
-        // TODO get catalog/display info
-        
-        /*
-         * following code nearly there to get the @CatalogConfig annotation
-         * in the class and use that to populate a label
-         */
-
-//      EntityDynamicType typeMap = 
-//              ((AbstractEntity)entity).getMutableEntityType();
-//        // above line works if we can cast; line below won't work, but there should some way
-//        // to get back the handle to the spec from an entity local, which then *would* work
-//              EntityTypes.getDefinedEntityType(entity.getClass());
 
-//      String label = typeMap.getConfigKeyField(config.getName());
-        return configSummary(null, ub, entity, config, null);
-    }
-    public static ConfigSummary configSummary(BrooklynRestResourceUtils utils, UriBuilder ub, Entity entity, ConfigKey<?> config, CatalogConfig annotation) {
-        String label = annotation==null ? null : annotation.label();
-        Double priority = annotation==null ? null : annotation.priority();
-        boolean pinned = annotation!=null && annotation.pinned();
-        return configSummary(utils, ub, entity, config, label, priority, pinned);
-    }
-    public static ConfigSummary configSummary(BrooklynRestResourceUtils utils, UriBuilder ub, Entity entity, ConfigKey<?> config, String label, Double priority, Boolean pinned) {
-        // entity can be null if coming from catalog
-        URI applicationUri = entity==null ? null : serviceUriBuilder(ub, ApplicationApi.class, "get").build(entity.getApplicationId());
-        URI entityUri = entity==null ? null : serviceUriBuilder(ub, EntityApi.class, "get").build(entity.getApplicationId(), entity.getId());
-        URI selfUri = entity==null ? null : serviceUriBuilder(ub, EntityConfigApi.class, "get").build(entity.getApplicationId(), entity.getId(), config.getName());
-        
-        MutableMap.Builder<String, URI> lb = MutableMap.<String, URI>builder()
-            .putIfNotNull("self", selfUri)
-            // TODO wasteful including these on every item as it is just a list, remove
-            .putIfNotNull("application", applicationUri)
-            .putIfNotNull("entity", entityUri)
-            // TODO is this json or a display value?
-            .putIfNotNull("action:json", selfUri);
-
-        Iterable<RendererHints.NamedAction> hints = Iterables.filter(RendererHints.getHintsFor(config), RendererHints.NamedAction.class);
-        for (RendererHints.NamedAction na : hints) {
-            if (entity!=null) {
-                SensorTransformer.addNamedAction(lb, na, entity.getConfig(config), config, entity);
-            }
-        }
-    
-        return new EntityConfigSummary(config, label, priority, pinned, lb.build());
-    }
-
-    public static URI applicationUri(Application entity, UriBuilder ub) {
-        return serviceUriBuilder(ub, ApplicationApi.class, "get").build(entity.getApplicationId());
-    }
-    
-    public static URI entityUri(Entity entity, UriBuilder ub) {
-        return serviceUriBuilder(ub, EntityApi.class, "get").build(entity.getApplicationId(), entity.getId());
-    }
-    
-    /** @deprecated since 0.13.0 use {@link #configSummary(BrooklynRestResourceUtils, UriBuilder, Entity, ConfigKey, CatalogConfig) */
+    /** @deprecated since 0.13.0 use {@link ConfigTransformer} */
     @Deprecated
     public static EntityConfigSummary entityConfigSummary(ConfigKey<?> config, Field configKeyField) {
         CatalogConfig catalogConfig = configKeyField!=null ? configKeyField.getAnnotation(CatalogConfig.class) : null;
@@ -218,7 +164,7 @@ public class EntityTransformer {
         return entityConfigSummary(config, label, priority, pinned, null);
     }
 
-    /** @deprecated since 0.13.0 use {@link #configSummary(BrooklynRestResourceUtils, UriBuilder, Entity, ConfigKey, AtomicInteger) */
+    /** @deprecated since 0.13.0 use {@link ConfigTransformer} */
     @Deprecated
     public static EntityConfigSummary entityConfigSummary(SpecParameter<?> input, AtomicInteger paramPriorityCnt) {
         // Increment the priority because the config container is a set. Server-side we are using an ordered set
@@ -228,38 +174,14 @@ public class EntityTransformer {
         return entityConfigSummary(input.getConfigKey(), input.getLabel(), priority, input.isPinned(), null);
     }
 
-    /** @deprecated since 0.13.0 use {@link #configSummary(BrooklynRestResourceUtils, UriBuilder, Entity, SpecParameter) */
-    @Deprecated
-    public static ConfigSummary configSummary(SpecParameter<?> input) {
-        // TODO could increment priority, or take from annotation, or introduce new field
-        Double priority = input.isPinned() ? Double.valueOf(1d) : null;
-        return new EntityConfigSummary(input.getConfigKey(), input.getLabel(), priority, input.isPinned(), null);
-    }
-
-    
-    public static ConfigSummary configSummary(BrooklynRestResourceUtils utils, UriBuilder ub, Entity entity, SpecParameter<?> input, AtomicInteger paramPriorityCnt) {
-        // Increment the priority because the config container is a set. Server-side we are using an ordered set
-        // which results in correctly ordered items on the wire (as a list). Clients which use the java bindings
-        // though will push the items in an unordered set - so give them means to recover the correct order.
-        Double priority = input.isPinned() ? Double.valueOf(paramPriorityCnt.incrementAndGet()) : null;
-        return configSummary(utils, ub, entity, input.getConfigKey(), input.getLabel(), priority, input.isPinned());
-    }
-
-    public static ConfigSummary configSummary(BrooklynRestResourceUtils utils, UriBuilder ub, Entity entity, SpecParameter<?> input) {
-        // TODO allow taking priority from a setting somewhere?
-        // (this just sets priority 1 if no value specified)
-        return configSummary(utils, ub, entity, input, new AtomicInteger(0));
-    }
-
-
-    /** @deprecated since 0.13.0 use {@link AdjunctTransformer#configSummary(BrooklynRestResourceUtils, UriBuilder, Entity, org.apache.brooklyn.api.objs.EntityAdjunct, SpecParameter)} */
+    /** @deprecated since 0.13.0 use {@link ConfigTransformer} */
     @Deprecated
     public static PolicyConfigSummary policyConfigSummary(SpecParameter<?> input) {
         Double priority = input.isPinned() ? Double.valueOf(1d) : null;
         return policyConfigSummary(input.getConfigKey(), input.getLabel(), priority, null);
     }
 
-    /** @deprecated since 0.13.0 use {@link AdjunctTransformer#configSummary(BrooklynRestResourceUtils, UriBuilder, Entity, org.apache.brooklyn.api.objs.EntityAdjunct, SpecParameter)} */
+    /** @deprecated since 0.13.0 use {@link ConfigTransformer} */
     @Deprecated
     public static EnricherConfigSummary enricherConfigSummary(SpecParameter<?> input) {
         Double priority = input.isPinned() ? Double.valueOf(1d) : null;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/83c3d500/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/SensorTransformer.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/SensorTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/SensorTransformer.java
index 19820d0..e4971ff 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/SensorTransformer.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/SensorTransformer.java
@@ -18,25 +18,28 @@
  */
 package org.apache.brooklyn.rest.transform;
 
+import static org.apache.brooklyn.rest.util.WebResourceUtils.serviceUriBuilder;
+
 import java.net.URI;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import javax.ws.rs.core.UriBuilder;
+
 import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.objs.BrooklynObject;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.api.sensor.Sensor;
 import org.apache.brooklyn.core.config.render.RendererHints;
+import org.apache.brooklyn.rest.api.ApplicationApi;
+import org.apache.brooklyn.rest.api.EntityApi;
+import org.apache.brooklyn.rest.api.SensorApi;
 import org.apache.brooklyn.rest.domain.SensorSummary;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.text.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.collect.Iterables;
-import javax.ws.rs.core.UriBuilder;
-import org.apache.brooklyn.rest.api.ApplicationApi;
-import org.apache.brooklyn.rest.api.EntityApi;
-import org.apache.brooklyn.rest.api.SensorApi;
-import static org.apache.brooklyn.rest.util.WebResourceUtils.serviceUriBuilder;
 
 public class SensorTransformer {
 
@@ -71,7 +74,7 @@ public class SensorTransformer {
     }
     
     @SuppressWarnings("unchecked")
-    static <T> void addNamedAction(MutableMap.Builder<String, URI> lb, RendererHints.NamedAction na, T value, Object context, Entity contextEntity) {
+    static <T> void addNamedAction(MutableMap.Builder<String, URI> lb, RendererHints.NamedAction na, T value, Object contextKeyOrSensor, BrooklynObject contextObject) {
         if (na instanceof RendererHints.NamedActionWithUrl) {
             try {
                 String v = ((RendererHints.NamedActionWithUrl<T>) na).getUrlFromValue(value);
@@ -81,7 +84,7 @@ public class SensorTransformer {
                 }
             } catch (Exception e) {
                 Exceptions.propagateIfFatal(e);
-                log.warn("Unable to make action "+na+" from "+context+" on "+contextEntity+": "+e, e);
+                log.warn("Unable to make action "+na+" from "+contextKeyOrSensor+" on "+contextObject+": "+e, e);
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/83c3d500/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/TypeTransformer.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/TypeTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/TypeTransformer.java
index d081efd..736ee83 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/TypeTransformer.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/TypeTransformer.java
@@ -100,7 +100,7 @@ public class TypeTransformer {
                     AbstractBrooklynObjectSpec<?,?> spec = b.getTypeRegistry().createSpec(item, null, null);
                     AtomicInteger priority = new AtomicInteger(0);
                     for (final SpecParameter<?> input : spec.getParameters()){
-                        config.add(EntityTransformer.configSummary(null, null, null, input, priority));
+                        config.add(ConfigTransformer.of(input).uiIncrementAndSetPriorityIfPinned(priority).transform());
                     }
                     
                     result.setExtraField("config", config);
@@ -127,9 +127,9 @@ public class TypeTransformer {
             EntityDynamicType typeMap = BrooklynTypes.getDefinedEntityType(spec.getType());
             EntityType type = typeMap.getSnapshot();
    
-            AtomicInteger paramPriorityCnt = new AtomicInteger();
+            AtomicInteger priority = new AtomicInteger();
             for (SpecParameter<?> input: spec.getParameters())
-                config.add(EntityTransformer.configSummary(null, null, null, input, paramPriorityCnt));
+                config.add(ConfigTransformer.of(input).uiIncrementAndSetPriorityIfPinned(priority).transform());
             for (Sensor<?> x: type.getSensors())
                 sensors.add(SensorTransformer.sensorSummaryForCatalog(x));
             for (Effector<?> x: type.getEffectors())

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/83c3d500/server-cli/src/main/java/org/apache/brooklyn/cli/lister/ItemDescriptors.java
----------------------------------------------------------------------
diff --git a/server-cli/src/main/java/org/apache/brooklyn/cli/lister/ItemDescriptors.java b/server-cli/src/main/java/org/apache/brooklyn/cli/lister/ItemDescriptors.java
index 61a7a2a..1a4ad31 100644
--- a/server-cli/src/main/java/org/apache/brooklyn/cli/lister/ItemDescriptors.java
+++ b/server-cli/src/main/java/org/apache/brooklyn/cli/lister/ItemDescriptors.java
@@ -18,7 +18,6 @@
  */
 package org.apache.brooklyn.cli.lister;
 
-import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -29,7 +28,6 @@ import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.brooklyn.api.catalog.BrooklynCatalog;
 import org.apache.brooklyn.api.catalog.Catalog;
-import org.apache.brooklyn.api.catalog.CatalogConfig;
 import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.effector.Effector;
 import org.apache.brooklyn.api.entity.EntityType;
@@ -47,8 +45,8 @@ import org.apache.brooklyn.rest.domain.ConfigSummary;
 import org.apache.brooklyn.rest.domain.EffectorSummary;
 import org.apache.brooklyn.rest.domain.SensorSummary;
 import org.apache.brooklyn.rest.domain.SummaryComparators;
+import org.apache.brooklyn.rest.transform.ConfigTransformer;
 import org.apache.brooklyn.rest.transform.EffectorTransformer;
-import org.apache.brooklyn.rest.transform.EntityTransformer;
 import org.apache.brooklyn.rest.transform.SensorTransformer;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.exceptions.RuntimeInterruptedException;
@@ -138,9 +136,7 @@ public class ItemDescriptors {
             Set<EffectorSummary> effectors = Sets.newTreeSet(SummaryComparators.nameComparator());
 
             for (ConfigKey<?> x: type.getConfigKeys()) {
-                Field field = dynamicType.getConfigKeyField(x.getName());
-                CatalogConfig annotation = field==null ? null : field.getAnnotation(CatalogConfig.class);
-                config.add(EntityTransformer.configSummary(null, null, null, x, annotation));
+                config.add(ConfigTransformer.of(x).uiMetadata(dynamicType.getConfigKeyField(x.getName())).transform());
             }
             result.put("config", config);
             
@@ -205,7 +201,7 @@ public class ItemDescriptors {
         if (!headingsOnly) {
             AtomicInteger priority = new AtomicInteger(0);
             for (SpecParameter<?> param: spec.getParameters()) {
-                config.add(EntityTransformer.configSummary(null, null, null, param, priority));
+                config.add(ConfigTransformer.of(param).uiIncrementAndSetPriorityIfPinned(priority).transform());
             }
             itemDescriptor.put("config", config);
         }


[06/35] brooklyn-server git commit: mark task names needing tidy as TODO and tidy some

Posted by he...@apache.org.
mark task names needing tidy as TODO and tidy some


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

Branch: refs/heads/master
Commit: 4c2468d0f001bfdde74dd5b48c90935d0d746981
Parents: 9a105e0
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Sep 11 11:04:08 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Sep 15 10:29:08 2017 +0100

----------------------------------------------------------------------
 .../java/org/apache/brooklyn/core/config/BasicConfigKey.java | 4 ++--
 .../org/apache/brooklyn/core/config/ConfigConstraints.java   | 1 +
 .../org/apache/brooklyn/core/mgmt/EntityManagementUtils.java | 1 +
 .../brooklyn/core/mgmt/internal/EntityManagementSupport.java | 1 +
 .../core/mgmt/internal/QueueingSubscriptionManager.java      | 2 ++
 .../core/objs/AbstractConfigurationSupportInternal.java      | 8 ++++++--
 .../org/apache/brooklyn/util/core/task/DynamicTasks.java     | 1 +
 7 files changed, 14 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4c2468d0/core/src/main/java/org/apache/brooklyn/core/config/BasicConfigKey.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/config/BasicConfigKey.java b/core/src/main/java/org/apache/brooklyn/core/config/BasicConfigKey.java
index 8c6c25b..61f4874 100644
--- a/core/src/main/java/org/apache/brooklyn/core/config/BasicConfigKey.java
+++ b/core/src/main/java/org/apache/brooklyn/core/config/BasicConfigKey.java
@@ -441,9 +441,9 @@ public class BasicConfigKey<T> implements ConfigKeySelfExtracting<T>, Serializab
     
     protected Object resolveValue(Object v, ExecutionContext exec) throws ExecutionException, InterruptedException {
         if (v instanceof Collection || v instanceof Map) {
-            return Tasks.resolveDeepValue(v, Object.class, exec, "config "+name);
+            return Tasks.resolveDeepValue(v, Object.class, exec, "Resolving deep config "+name);
         } else {
-            return Tasks.resolveValue(v, getType(), exec, "config "+name);
+            return Tasks.resolveValue(v, getType(), exec, "Resolving config "+name);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4c2468d0/core/src/main/java/org/apache/brooklyn/core/config/ConfigConstraints.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/config/ConfigConstraints.java b/core/src/main/java/org/apache/brooklyn/core/config/ConfigConstraints.java
index c508349..2d0cf7d 100644
--- a/core/src/main/java/org/apache/brooklyn/core/config/ConfigConstraints.java
+++ b/core/src/main/java/org/apache/brooklyn/core/config/ConfigConstraints.java
@@ -112,6 +112,7 @@ public abstract class ConfigConstraints<T extends BrooklynObject> {
     abstract Iterable<ConfigKey<?>> getBrooklynObjectTypeConfigKeys();
 
     public Iterable<ConfigKey<?>> getViolations() {
+        // TODO in new task
         return validateAll();
     }
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4c2468d0/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java
index a036622..0cd18fc 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java
@@ -91,6 +91,7 @@ public class EntityManagementUtils {
      */
     @Beta
     public static <T extends Application> T createUnstarted(ManagementContext mgmt, EntitySpec<T> spec, Optional<String> entityId) {
+        // TODO wrap in task
         T app = ((EntityManagerInternal)mgmt.getEntityManager()).createEntity(spec, entityId);
         return app;
     }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4c2468d0/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityManagementSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityManagementSupport.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityManagementSupport.java
index 852166b..97c7bac 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityManagementSupport.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityManagementSupport.java
@@ -160,6 +160,7 @@ public class EntityManagementSupport {
     
     public void onManagementStarting(ManagementTransitionInfo info) {
         try {
+            // TODO same-thread task on this entity, with internal tag ?
             synchronized (this) {
                 boolean alreadyManaging = isDeployed();
                 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4c2468d0/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/QueueingSubscriptionManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/QueueingSubscriptionManager.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/QueueingSubscriptionManager.java
index d24e7a4..83facda 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/QueueingSubscriptionManager.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/QueueingSubscriptionManager.java
@@ -76,6 +76,7 @@ public class QueueingSubscriptionManager extends AbstractSubscriptionManager {
     
     @SuppressWarnings("unchecked")
     public synchronized void startDelegatingForSubscribing() {
+        // TODO wrap in same-thread task
         assert delegate!=null;
         for (QueuedSubscription s: queuedSubscriptions) {
             delegate.subscribe(s.flags, s.s);
@@ -86,6 +87,7 @@ public class QueueingSubscriptionManager extends AbstractSubscriptionManager {
     
     @SuppressWarnings("unchecked")
     public synchronized void startDelegatingForPublishing() {
+        // TODO wrap in same-thread task
         assert delegate!=null;
         for (SensorEvent evt: queuedSensorEvents) {
             delegate.publish(evt);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4c2468d0/core/src/main/java/org/apache/brooklyn/core/objs/AbstractConfigurationSupportInternal.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractConfigurationSupportInternal.java b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractConfigurationSupportInternal.java
index 4b3876b..460c8c4 100644
--- a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractConfigurationSupportInternal.java
+++ b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractConfigurationSupportInternal.java
@@ -106,9 +106,10 @@ public abstract class AbstractConfigurationSupportInternal implements BrooklynOb
             }
         };
 
+        // TODO can we remove the DST ?  this is structured so maybe not
         Task<T> t = Tasks.<T>builder().body(job)
-                .displayName("Resolving dependent value")
-                .description("Resolving "+key.getName())
+                .displayName("Resolving config "+key.getName())
+                .description("Internal non-blocking structured key resolution")
                 .tag(BrooklynTaskTags.TRANSIENT_TASK_TAG)
                 .build();
         try {
@@ -131,6 +132,9 @@ public abstract class AbstractConfigurationSupportInternal implements BrooklynOb
         // getRaw returns Maybe(val) if the key was explicitly set (where val can be null)
         // or Absent if the config key was unset.
         Object unresolved = getRaw(key).or(key.getDefaultValue());
+        // TODO add description that we are evaluating this config key to be used if the code below submits futher tasks
+        // and look at other uses of "description" method
+        // and make sure it is marked transient
         Maybe<Object> resolved = Tasks.resolving(unresolved)
                 .as(Object.class)
                 .immediately(true)

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4c2468d0/core/src/main/java/org/apache/brooklyn/util/core/task/DynamicTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/DynamicTasks.java b/core/src/main/java/org/apache/brooklyn/util/core/task/DynamicTasks.java
index c966cf0..15b062a 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/DynamicTasks.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/DynamicTasks.java
@@ -292,6 +292,7 @@ public class DynamicTasks {
      * 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) {
+        // TODO do in foreground?
         return queueIfNeeded(t).asTask().getUnchecked();
     }
 


[12/35] brooklyn-server git commit: diff task submisson paths share code about how to end, and tidy listeners

Posted by he...@apache.org.
diff task submisson paths share code about how to end, and tidy listeners

fix bug where some where executed and GC'd before the child had actually run,
by ensuring listeners don't run until the task recognizes the cancellation.

also tidy how end code is shared, and remove deprecation


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

Branch: refs/heads/master
Commit: 934cf4ccbed5719f1b22ff032af77583c1cf6ad2
Parents: 8983bf2
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Sep 12 12:12:00 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Sep 15 10:29:09 2017 +0100

----------------------------------------------------------------------
 .../java/org/apache/brooklyn/api/mgmt/Task.java |  16 +-
 .../mgmt/ha/HighAvailabilityManagerImpl.java    |   2 +-
 .../mgmt/internal/BrooklynGarbageCollector.java |  20 +-
 .../util/core/task/BasicExecutionContext.java   |   6 +-
 .../util/core/task/BasicExecutionManager.java   | 247 +++++++++++--------
 .../brooklyn/util/core/task/BasicTask.java      |  30 +--
 .../brooklyn/util/core/task/CompoundTask.java   |   4 -
 .../util/core/task/DynamicSequentialTask.java   |   1 +
 .../brooklyn/util/core/task/ForwardingTask.java |   5 +
 .../brooklyn/util/core/task/ScheduledTask.java  |  14 +-
 .../brooklyn/util/core/task/TaskInternal.java   |   8 +-
 .../core/mgmt/rebind/RebindFeedTest.java        |   4 +-
 12 files changed, 213 insertions(+), 144 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/934cf4cc/api/src/main/java/org/apache/brooklyn/api/mgmt/Task.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/mgmt/Task.java b/api/src/main/java/org/apache/brooklyn/api/mgmt/Task.java
index 969c3a8..3c8aa45 100644
--- a/api/src/main/java/org/apache/brooklyn/api/mgmt/Task.java
+++ b/api/src/main/java/org/apache/brooklyn/api/mgmt/Task.java
@@ -91,7 +91,7 @@ public interface Task<T> extends ListenableFuture<T>, TaskAdaptable<T> {
      * {@link #get()} is guaranteed to return immediately, throwing in the case of cancellation
      * prior to completion (and including the case above where a thread may still be running).
      * <p>
-     * To check whether cancelled threads for this task have completed, 
+     * To check whether cancelled threads for this task have completed, use {@link #isDone(boolean))}. 
      * inspect {@link #getEndTimeUtc()}, which is guaranteed to be set when threads complete
      * if the thread is started (as determinable by whether {@link #getStartTimeUtc()} is set).
      * (The threads of submitted/child tasks will usually be independent; to determine their
@@ -99,6 +99,20 @@ public interface Task<T> extends ListenableFuture<T>, TaskAdaptable<T> {
      */
     @Override
     public boolean isDone();
+
+    /**
+     * As {@link #isDone()}, identical if the argument is false, but by supplying {@code true} 
+     * this will also check {@link #getEndTimeUtc()} if {@link #isBegun()}
+     * to guarantee that the task is no longer running.
+     * {@link #isDone()} will return true for cancelled tasks even if they are still running.
+     * <p>
+     * In a task hierarchy, the threads of tasks submitted by this may still be ongoing.
+     * To determine their completion, inspect the {@link ExecutionManager}.
+     *   
+     * @param andTaskHasEnded
+     * @return
+     */
+    public boolean isDone(boolean andTaskNotRunning);
     
     /**
      * Causes calling thread to block until the task is started.

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/934cf4cc/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerImpl.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerImpl.java
index a4f8870..f6dc1a4 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerImpl.java
@@ -589,7 +589,7 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager {
         } else {
             if (pollingTask!=null) pollingTask.cancel(true);
             
-            ScheduledTask task = new ScheduledTask(MutableMap.of("period", pollPeriod, "displayName", "scheduled:[HA poller task]"), taskFactory);
+            ScheduledTask task = new ScheduledTask(MutableMap.of("period", pollPeriod, "displayName", "scheduled:[HA poller task]", "tag", BrooklynTaskTags.TRANSIENT_TASK_TAG), taskFactory);
             pollingTask = managementContext.getExecutionManager().submit(task);
         }
     }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/934cf4cc/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/BrooklynGarbageCollector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/BrooklynGarbageCollector.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/BrooklynGarbageCollector.java
index 203c3a5..7995768 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/BrooklynGarbageCollector.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/BrooklynGarbageCollector.java
@@ -292,15 +292,12 @@ public class BrooklynGarbageCollector {
         }
     }
     
-    /** @deprecated since 0.7.0, method moved internal until semantics are clarified; see also {@link #shouldDeleteTaskImmediately(Task)} */
-    @Deprecated
-    public boolean shouldDeleteTask(Task<?> task) {
-        return shouldDeleteTaskImmediately(task);
-    }
     /** whether this task should be deleted on completion,
      * because it is transient, or because it is submitted background without much context information */
     protected boolean shouldDeleteTaskImmediately(Task<?> task) {
-        if (!task.isDone()) return false;
+        if (!task.isDone(true)) {
+            return false;
+        }
         
         Set<Object> tags = BrooklynTaskTags.getTagsFast(task);
         if (tags.contains(ManagementContextInternal.TRANSIENT_TASK_TAG))
@@ -430,7 +427,10 @@ public class BrooklynGarbageCollector {
         while (ei.hasNext()) {
             Entry<Entity, Task<?>> ee = ei.next();
             if (Entities.isManaged(ee.getKey())) continue;
-            if (ee.getValue()!=null && !ee.getValue().isDone()) continue;
+            if (ee.getValue()!=null && !ee.getValue().isDone(true)) {
+                // wait for the unmanagement task to complete
+                continue;
+            }
             deleteTasksForEntity(ee.getKey());
             synchronized (unmanagedEntitiesNeedingGc) {
                 unmanagedEntitiesNeedingGc.remove(ee.getKey());
@@ -446,7 +446,7 @@ public class BrooklynGarbageCollector {
 
         try {
             for (Task<?> task: allTasks) {
-                if (!task.isDone()) continue;
+                if (!task.isDone(true)) continue;
                 if (BrooklynTaskTags.isSubTask(task)) continue;
 
                 if (maxTaskAge.isShorterThan(Duration.sinceUtc(task.getEndTimeUtc())))
@@ -466,7 +466,7 @@ public class BrooklynGarbageCollector {
     protected void expireTransientTasks() {
         Set<Task<?>> transientTasks = executionManager.getTasksWithTag(BrooklynTaskTags.TRANSIENT_TASK_TAG);
         for (Task<?> t: transientTasks) {
-            if (!t.isDone()) continue;
+            if (!t.isDone(true)) continue;
             executionManager.deleteTask(t);
         }
     }
@@ -532,7 +532,7 @@ public class BrooklynGarbageCollector {
         List<Task<?>> tasksToConsiderDeleting = MutableList.of();
         try {
             for (Task<?> task: tasks) {
-                if (!task.isDone()) continue;
+                if (!task.isDone(true)) continue;
                 
                 Set<Object> tags = TaskTags.getTagsFast(task);
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/934cf4cc/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
index 8166dc0..547ae24 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
@@ -183,8 +183,9 @@ public class BasicExecutionContext extends AbstractExecutionContext {
         BasicExecutionContext oldExecutionContext = getCurrentExecutionContext();
         registerPerThreadExecutionContext();
         ((BasicExecutionManager)executionManager).beforeSubmitInSameThreadTask(null, task);
-
+        
         SimpleFuture<T> future = new SimpleFuture<>();
+        Throwable error = null;
         try {
             ((BasicExecutionManager)executionManager).afterSubmitRecordFuture(task, future);
             ((BasicExecutionManager)executionManager).beforeStartInSameThreadTask(null, task);
@@ -194,12 +195,13 @@ public class BasicExecutionContext extends AbstractExecutionContext {
             return future.set(job.call());
             
         } catch (Exception e) {
+            error = e;
             future.set(Maybe.absent(e));
             throw Exceptions.propagate(e);
             
         } finally {
             try {
-                ((BasicExecutionManager)executionManager).afterEndInSameThreadTask(null, task);
+                ((BasicExecutionManager)executionManager).afterEndInSameThreadTask(null, task, error);
             } finally {
                 BasicExecutionManager.getPerThreadCurrentTask().set(previousTask);
                 perThreadExecutionContext.set(oldExecutionContext);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/934cf4cc/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
index 22d5b23..0f666ba 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
@@ -46,12 +46,14 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 
+import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.mgmt.ExecutionManager;
 import org.apache.brooklyn.api.mgmt.HasTaskChildren;
 import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.api.mgmt.TaskAdaptable;
 import org.apache.brooklyn.core.BrooklynFeatureEnablement;
 import org.apache.brooklyn.core.config.Sanitizer;
+import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.core.task.TaskInternal.TaskCancellationMode;
@@ -256,8 +258,13 @@ public class BasicExecutionManager implements ExecutionManager {
         }
         Task<?> removed = tasksById.remove(task.getId());
         incompleteTaskIds.remove(task.getId());
-        if (removed!=null && removed.isSubmitted() && !removed.isDone()) {
-            log.warn("Deleting submitted task before completion: "+removed+"; this task will continue to run in the background outwith "+this+", but perhaps it should have been cancelled?");
+        if (removed!=null && removed.isSubmitted() && !removed.isDone(true)) {
+            Entity context = BrooklynTaskTags.getContextEntity(removed);
+            if (!Entities.isManaged(context)) {
+                log.debug("Forgetting about active task on unmanagement of "+context+": "+removed);
+            } else {
+                log.warn("Deleting submitted task before completion: "+removed+"; this task will continue to run in the background outwith "+this+", but perhaps it should have been cancelled?");
+            }
         }
         return removed != null;
     }
@@ -406,17 +413,20 @@ public class BasicExecutionManager implements ExecutionManager {
     protected Task<?> submitNewScheduledTask(final Map<?,?> flags, final ScheduledTask task) {
         beforeSubmitScheduledTaskAllIterations(flags, task);
         
-        return submitSubsequentScheduledTask(flags, task);
+        if (!submitSubsequentScheduledTask(flags, task)) {
+            afterEndScheduledTaskAllIterations(flags, task, null);
+        }
+        return task;
     }
     
-    protected Task<?> submitSubsequentScheduledTask(final Map<?,?> flags, final ScheduledTask task) {
+    private boolean submitSubsequentScheduledTask(final Map<?,?> flags, final ScheduledTask task) {
         if (!task.isDone()) {
             task.internalFuture = delayedRunner.schedule(new ScheduledTaskCallable(task, flags),
                 task.delay.toNanoseconds(), TimeUnit.NANOSECONDS);
+            return true;
         } else {
-            afterEndScheduledTaskAllIterations(flags, task);
+            return false;
         }
-        return task;
     }
 
     protected class ScheduledTaskCallable implements Callable<Object> {
@@ -431,15 +441,24 @@ public class BasicExecutionManager implements ExecutionManager {
         @Override
         @SuppressWarnings({ "rawtypes", "unchecked" })
         public Object call() {
-            if (task.startTimeUtc==-1) task.startTimeUtc = System.currentTimeMillis();
+            if (task.startTimeUtc==-1) {
+                // this is overwritten on each run; not sure if that's best or not
+                task.startTimeUtc = System.currentTimeMillis();
+            }
             TaskInternal<?> taskScheduled = null;
+            Throwable error = null;
             try {
-                beforeStartScheduledTaskSubmissionIteration(flags, task);
                 taskScheduled = (TaskInternal<?>) task.newTask();
                 taskScheduled.setSubmittedByTask(task);
+                beforeStartScheduledTaskSubmissionIteration(flags, task, taskScheduled);
                 final Callable<?> oldJob = taskScheduled.getJob();
                 final TaskInternal<?> taskScheduledF = taskScheduled;
                 taskScheduled.setJob(new Callable() { @Override public Object call() {
+                    if (task.isCancelled()) {
+                        afterEndScheduledTaskAllIterations(flags, task, new CancellationException("cancel detected"));
+                        throw new CancellationException("cancel detected");  // above throws, but for good measure
+                    }
+                    Throwable lastError = null;
                     boolean shouldResubmit = true;
                     task.recentRun = taskScheduledF;
                     try {
@@ -448,19 +467,22 @@ public class BasicExecutionManager implements ExecutionManager {
                         }
                         Object result;
                         try {
+                            lastError = null;
                             result = oldJob.call();
                             task.lastThrownType = null;
                         } catch (Exception e) {
+                            lastError = e;
                             shouldResubmit = shouldResubmitOnException(oldJob, e);
                             throw Exceptions.propagate(e);
                         }
                         return result;
                     } finally {
                         // do in finally block in case we were interrupted
-                        if (shouldResubmit) {
-                            resubmit();
+                        if (shouldResubmit && resubmit()) {
+                            // resubmitted fine, no-op
                         } else {
-                            afterEndScheduledTaskAllIterations(flags, task);
+                            // not resubmitted, note ending
+                            afterEndScheduledTaskAllIterations(flags, task, lastError);
                         }
                     }
                 }});
@@ -468,16 +490,23 @@ public class BasicExecutionManager implements ExecutionManager {
                 BasicExecutionContext ec = BasicExecutionContext.getCurrentExecutionContext();
                 if (ec!=null) return ec.submit(taskScheduled);
                 else return submit(taskScheduled);
+
+            } catch (Exception e) {
+                error = e;
+                throw Exceptions.propagate(e);
+                
             } finally {
-                afterEndScheduledTaskSubmissionIteration(flags, task, taskScheduled);
+                afterEndScheduledTaskSubmissionIteration(flags, task, taskScheduled, error);
             }
         }
 
-        private void resubmit() {
+        private boolean resubmit() {
             task.runCount++;
             if (task.period!=null && !task.isCancelled()) {
                 task.delay = task.period;
-                submitSubsequentScheduledTask(flags, task);
+                return submitSubsequentScheduledTask(flags, task);
+            } else {
+                return false;
             }
         }
 
@@ -520,47 +549,19 @@ public class BasicExecutionManager implements ExecutionManager {
 
         @Override
         public T call() {
+            T result = null;
+            Throwable error = null;
             try {
-                T result = null;
-                Throwable error = null;
-                try {
-                    beforeStartAtomicTask(flags, task);
-                    if (!task.isCancelled()) {
-                        result = ((TaskInternal<T>)task).getJob().call();
-                    } else throw new CancellationException();
-                } catch(Throwable e) {
-                    error = e;
-                } finally {
-                    afterEndAtomicTask(flags, task);
-                }
-                if (error!=null) {
-                    /* we throw, after logging debug.
-                     * the throw means the error is available for task submitters to monitor.
-                     * however it is possible no one is monitoring it, in which case we will have debug logging only for errors.
-                     * (the alternative, of warn-level logging in lots of places where we don't want it, seems worse!) 
-                     */
-                    if (log.isDebugEnabled()) {
-                        // debug only here, because most submitters will handle failures
-                        if (error instanceof InterruptedException || error instanceof RuntimeInterruptedException) {
-                            log.debug("Detected interruption on task "+task+" (rethrowing)" +
-                                    (Strings.isNonBlank(error.getMessage()) ? ": "+error.getMessage() : ""));
-                        } else if (error instanceof NullPointerException ||
-                                error instanceof IndexOutOfBoundsException ||
-                                error instanceof ClassCastException) {
-                            log.debug("Exception running task "+task+" (rethrowing): "+error, error);
-                        } else {
-                            log.debug("Exception running task "+task+" (rethrowing): "+error);
-                        }
-                        if (log.isTraceEnabled()) {
-                            log.trace("Trace for exception running task "+task+" (rethrowing): "+error, error);
-                        }
-                    }
-                    throw Exceptions.propagate(error);
-                }
-                return result;
+                beforeStartAtomicTask(flags, task);
+                if (!task.isCancelled()) {
+                    result = ((TaskInternal<T>)task).getJob().call();
+                } else throw new CancellationException();
+            } catch(Throwable e) {
+                error = e;
             } finally {
-                ((TaskInternal<?>)task).runListeners();
+                afterEndAtomicTask(flags, task, error);
             }
+            return result;
         }
 
         @Override
@@ -634,26 +635,30 @@ public class BasicExecutionManager implements ExecutionManager {
                     log.trace("On cancel of "+task+", applicable subtask count "+subtasksFound+", of which "+subtasksReallyCancelled+" were actively cancelled");
                 }
             }
-            
-            ((TaskInternal<?>)task).runListeners();
+  
+            // no longer run listeners when we say to cancel, they get run when the task really ends
+            // TODO confirm no problems (added 2017-09)
+//            ((TaskInternal<?>)task).runListeners();
             return result;
         }
     }
 
-    private final class SubmissionListenerToCallOtherListeners<T> implements Runnable {
+    private final class SubmissionListenerToCallManagerListeners<T> implements Runnable {
         private final Task<T> task;
 
-        private SubmissionListenerToCallOtherListeners(Task<T> task) {
+        private SubmissionListenerToCallManagerListeners(Task<T> task) {
             this.task = task;
         }
 
         @Override
         public void run() {
-            try {
-                ((TaskInternal<?>)task).runListeners();
-            } catch (Exception e) {
-                log.warn("Error running task listeners for task "+task+" done", e);
-            }
+            // TODO remove after confirmation this is fine; this listener runs as one of the task's listeners
+            // so the task.runListeners will always be no-op
+//            try {
+//                ((TaskInternal<?>)task).runListeners();
+//            } catch (Exception e) {
+//                log.warn("Error running task listeners for task "+task+" done", e);
+//            }
             
             for (ExecutionListener listener : listeners) {
                 try {
@@ -715,7 +720,7 @@ public class BasicExecutionManager implements ExecutionManager {
         // except on cancel we want to listen
         ListenableFuture<T> listenableFuture = new CancellingListenableForwardingFutureForTask<T>(this, future, ((TaskInternal<T>)task).getListeners(), task);
         // and we want to make sure *our* (manager) listeners are given suitable callback 
-        ((TaskInternal<T>)task).addListener(new SubmissionListenerToCallOtherListeners<T>(task), runner);
+        ((TaskInternal<T>)task).addListener(new SubmissionListenerToCallManagerListeners<T>(task), runner);
         // NB: can the above mean multiple callbacks to TaskInternal#runListeners?
         
         // finally expose the future to callers
@@ -735,10 +740,12 @@ public class BasicExecutionManager implements ExecutionManager {
     protected void internalBeforeSubmit(Map<?,?> flags, Task<?> task) {
         incompleteTaskIds.add(task.getId());
         
-        Task<?> currentTask = Tasks.current();
-        if (currentTask!=null) ((TaskInternal<?>)task).setSubmittedByTask(
-                // do this instead of soft reference (2017-09) as soft refs impact GC 
-                Maybe.of(new TaskLookup(this, currentTask)) );
+        if (task.getSubmittedByTaskId()==null) {
+            Task<?> currentTask = Tasks.current();
+            if (currentTask!=null) ((TaskInternal<?>)task).setSubmittedByTask(
+                    // do this instead of soft reference (2017-09) as soft refs impact GC 
+                    Maybe.of(new TaskLookup(this, currentTask)) );
+        }
         ((TaskInternal<?>)task).setSubmitTimeUtc(System.currentTimeMillis());
         
         if (flags!=null && flags.get("tag")!=null) ((TaskInternal<?>)task).getMutableTags().add(flags.remove("tag"));
@@ -761,6 +768,9 @@ public class BasicExecutionManager implements ExecutionManager {
         public TaskLookup(BasicExecutionManager mgr, Task<?> t) {
             this.mgr = mgr;
             id = t.getId();
+            if (mgr.getTask(id)==null) {
+                log.warn("Created task lookup for task which is not registered: "+t);
+            }
             displayName = t.getDisplayName();
         }
         @Override
@@ -771,16 +781,16 @@ public class BasicExecutionManager implements ExecutionManager {
             return gone();
         }
         private <T> Task<T> gone() {
-            Task<T> t = Tasks.<T>builder().dynamic(false).displayName(displayName)
-                .description("Details of the original task "+id+" have been forgotten.")
+            Task<T> t = Tasks.<T>builder().dynamic(false).displayName(displayName+" (placeholder for "+id+")")
+                .description("Details of the original task have been forgotten.")
                 .body(Callables.returning((T)null)).build();
             ((BasicTask<T>)t).ignoreIfNotRun();
             return t;
         }
     }
 
-    protected void beforeStartScheduledTaskSubmissionIteration(Map<?,?> flags, Task<?> task) {
-        internalBeforeStart(flags, task, true);
+    protected void beforeStartScheduledTaskSubmissionIteration(Map<?,?> flags, Task<?> taskRepeatedlyScheduling, Task<?> taskIteration) {
+        internalBeforeStart(flags, taskRepeatedlyScheduling, true);
     }
     protected void beforeStartAtomicTask(Map<?,?> flags, Task<?> task) {
         internalBeforeStart(flags, task, true);
@@ -856,54 +866,87 @@ public class BasicExecutionManager implements ExecutionManager {
     private static boolean loggedClosureDeprecatedInInvokeCallback;
     
     /** normally (if not interrupted) called once for each call to {@link #beforeSubmitScheduledTaskAllIterations(Map, Task)} */
-    protected void afterEndScheduledTaskAllIterations(Map<?,?> flags, Task<?> task) {
-        internalAfterEnd(flags, task, false, true);
+    protected void afterEndScheduledTaskAllIterations(Map<?,?> flags, Task<?> taskRepeatedlyScheduling, Throwable error) {
+        internalAfterEnd(flags, taskRepeatedlyScheduling, false, true, error);
     }
     /** called once for each call to {@link #beforeStartScheduledTaskSubmissionIteration(Map, Task)},
      * with a per-iteration task generated by the surrounding scheduled task */
-    protected void afterEndScheduledTaskSubmissionIteration(Map<?,?> flags, Task<?> scheduledTask, Task<?> taskIteration) {
-        internalAfterEnd(flags, scheduledTask, true, false);
+    protected void afterEndScheduledTaskSubmissionIteration(Map<?,?> flags, Task<?> taskRepeatedlyScheduling, Task<?> taskIteration, Throwable error) {
+        internalAfterEnd(flags, taskRepeatedlyScheduling, true, false, error);
     }
     /** called once for each task on which {@link #beforeStartAtomicTask(Map, Task)} is invoked,
      * and normally (if not interrupted prior to start) 
      * called once for each task on which {@link #beforeSubmitAtomicTask(Map, Task)} */
-    protected void afterEndAtomicTask(Map<?,?> flags, Task<?> task) {
-        internalAfterEnd(flags, task, true, true);
+    protected void afterEndAtomicTask(Map<?,?> flags, Task<?> task, Throwable error) {
+        internalAfterEnd(flags, task, true, true, error);
     }
-    protected void afterEndInSameThreadTask(Map<?,?> flags, Task<?> task) {
-        internalAfterEnd(flags, task, true, true);
+    protected void afterEndInSameThreadTask(Map<?,?> flags, Task<?> task, Throwable error) {
+        internalAfterEnd(flags, task, true, true, error);
     }
     /** normally (if not interrupted) called once for each call to {@link #internalBeforeSubmit(Map, Task)},
      * and, for atomic tasks and scheduled-task submission iterations where 
      * always called once if {@link #internalBeforeStart(Map, Task)} is invoked and in the same thread as that method */
-    protected void internalAfterEnd(Map<?,?> flags, Task<?> task, boolean startedInThisThread, boolean isEndingAllIterations) {
-        if (log.isTraceEnabled()) log.trace(this+" afterEnd, task: "+task);
-        if (startedInThisThread) {
-            activeTaskCount.decrementAndGet();
-        }
-        if (isEndingAllIterations) {
-            incompleteTaskIds.remove(task.getId());
-            if (flags!=null) {
-                invokeCallback(flags.get("newTaskEndCallback"), task);
+    protected void internalAfterEnd(Map<?,?> flags, Task<?> task, boolean startedInThisThread, boolean isEndingAllIterations, Throwable error) {
+        try {
+            if (log.isTraceEnabled()) log.trace(this+" afterEnd, task: "+task);
+            if (startedInThisThread) {
+                activeTaskCount.decrementAndGet();
             }
-            ((TaskInternal<?>)task).setEndTimeUtc(System.currentTimeMillis());
-        }
-
-        if (startedInThisThread) {
-            PerThreadCurrentTaskHolder.perThreadCurrentTask.remove();
-            //clear thread _after_ endTime set, so we won't get a null thread when there is no end-time
-            if (RENAME_THREADS) {
-                Thread thread = task.getThread();
-                if (thread==null) {
-                    log.warn("BasicTask.afterEnd invoked without corresponding beforeStart");
-                } else {
-                    thread.setName(threadOriginalName.get());
-                    threadOriginalName.remove();
+            if (isEndingAllIterations) {
+                incompleteTaskIds.remove(task.getId());
+                if (flags!=null) {
+                    invokeCallback(flags.get("newTaskEndCallback"), task);
+                }
+                ((TaskInternal<?>)task).setEndTimeUtc(System.currentTimeMillis());
+            }
+    
+            if (startedInThisThread) {
+                PerThreadCurrentTaskHolder.perThreadCurrentTask.remove();
+                //clear thread _after_ endTime set, so we won't get a null thread when there is no end-time
+                if (RENAME_THREADS) {
+                    Thread thread = task.getThread();
+                    if (thread==null) {
+                        log.warn("BasicTask.afterEnd invoked without corresponding beforeStart");
+                    } else {
+                        thread.setName(threadOriginalName.get());
+                        threadOriginalName.remove();
+                    }
+                }
+                ((TaskInternal<?>)task).setThread(null);
+            }
+        } finally {
+            try {
+                if (error!=null) {
+                    /* we throw, after logging debug.
+                     * the throw means the error is available for task submitters to monitor.
+                     * however it is possible no one is monitoring it, in which case we will have debug logging only for errors.
+                     * (the alternative, of warn-level logging in lots of places where we don't want it, seems worse!) 
+                     */
+                    if (log.isDebugEnabled()) {
+                        // debug only here, because most submitters will handle failures
+                        if (error instanceof InterruptedException || error instanceof RuntimeInterruptedException) {
+                            log.debug("Detected interruption on task "+task+" (rethrowing)" +
+                                    (Strings.isNonBlank(error.getMessage()) ? ": "+error.getMessage() : ""));
+                        } else if (error instanceof NullPointerException ||
+                                error instanceof IndexOutOfBoundsException ||
+                                error instanceof ClassCastException) {
+                            log.debug("Exception running task "+task+" (rethrowing): "+error, error);
+                        } else {
+                            log.debug("Exception running task "+task+" (rethrowing): "+error);
+                        }
+                        if (log.isTraceEnabled()) {
+                            log.trace("Trace for exception running task "+task+" (rethrowing): "+error, error);
+                        }
+                    }
+                    throw Exceptions.propagate(error);
+                }
+            } finally {
+                synchronized (task) { task.notifyAll(); }
+                if (isEndingAllIterations) {
+                    ((TaskInternal<?>)task).runListeners();
                 }
             }
-            ((TaskInternal<?>)task).setThread(null);
         }
-        synchronized (task) { task.notifyAll(); }
     }
 
     public TaskScheduler getTaskSchedulerForTag(Object tag) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/934cf4cc/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
index f908ad4..3c9b163 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
@@ -46,7 +46,6 @@ import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.api.objs.Identifiable;
 import org.apache.brooklyn.util.JavaGroovyEquivalents;
 import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.apache.brooklyn.util.groovy.GroovyJavaMethods;
 import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.guava.Maybe.MaybeSupplier;
 import org.apache.brooklyn.util.text.Identifiers;
@@ -142,18 +141,6 @@ public class BasicTask<T> implements TaskInternal<T> {
         this(flags, JavaGroovyEquivalents.toCallable(job));
     }
     
-    /**
-     * @deprecated since 0.11.0; explicit groovy utilities/support will be deleted.
-     */
-    @Deprecated
-    public BasicTask(Closure<T> job) { this(GroovyJavaMethods.callableFromClosure(job)); }
-    
-    /**
-     * @deprecated since 0.11.0; explicit groovy utilities/support will be deleted.
-     */
-    @Deprecated
-    public BasicTask(Map<?,?> flags, Closure<T> job) { this(flags, GroovyJavaMethods.callableFromClosure(job)); }
-
     @Override
     public String getId() {
         return id;
@@ -358,11 +345,19 @@ public class BasicTask<T> implements TaskInternal<T> {
     }
 
     @Override
+    public boolean isDone(boolean andTaskNotRunning) {
+        if (!cancelled && !(internalFuture!=null && internalFuture.isDone()) && endTimeUtc<=0) {
+            return false;
+        }
+        if (andTaskNotRunning && cancelled && isBegun() && endTimeUtc<=0) {
+            return false;
+        }
+        return true;
+    }
+    
+    @Override
     public boolean isDone() {
-        // if endTime is set, result might not be completed yet, but it will be set very soon 
-        // (the two values are set close in time, result right after the endTime;
-        // but callback hooks might not see the result yet)
-        return cancelled || (internalFuture!=null && internalFuture.isDone()) || endTimeUtc>0;
+        return isDone(false);
     }
 
     /**
@@ -415,7 +410,6 @@ public class BasicTask<T> implements TaskInternal<T> {
     @Override
     public synchronized boolean blockUntilStarted(Duration timeout) {
         Long endTime = timeout==null ? null : System.currentTimeMillis() + timeout.toMillisecondsRoundingUp();
-        int count = 0;
         while (true) {
             if (cancelled) throw new CancellationException();
             if (startTimeUtc>0) return true;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/934cf4cc/core/src/main/java/org/apache/brooklyn/util/core/task/CompoundTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/CompoundTask.java b/core/src/main/java/org/apache/brooklyn/util/core/task/CompoundTask.java
index 3cbb548..c7f2d69 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/CompoundTask.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/CompoundTask.java
@@ -89,10 +89,6 @@ public abstract class CompoundTask<T> extends BasicTask<List<T>> implements HasT
         for (Object job : jobs) {
             Task subtask;
             if (job instanceof TaskAdaptable) { subtask = ((TaskAdaptable)job).asTask(); }
-            else if (job instanceof Closure)  {
-                log.warn("Use of groovy.lang.Closure is deprecated, in CompoundTask jobs");
-                subtask = new BasicTask<T>((Closure) job);
-            }
             else if (job instanceof Callable) { subtask = new BasicTask<T>((Callable) job); }
             else if (job instanceof Runnable) { subtask = new BasicTask<T>((Runnable) job); }
             

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/934cf4cc/core/src/main/java/org/apache/brooklyn/util/core/task/DynamicSequentialTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/DynamicSequentialTask.java b/core/src/main/java/org/apache/brooklyn/util/core/task/DynamicSequentialTask.java
index 5fb8ee8..362fd5d 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/DynamicSequentialTask.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/DynamicSequentialTask.java
@@ -173,6 +173,7 @@ public class DynamicSequentialTask<T> extends BasicTask<T> implements HasTaskChi
     
     @Override
     public boolean cancel(TaskCancellationMode mode) {
+        // super is invoked in the method below
         return cancel(mode, null);
     }
     

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/934cf4cc/core/src/main/java/org/apache/brooklyn/util/core/task/ForwardingTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/ForwardingTask.java b/core/src/main/java/org/apache/brooklyn/util/core/task/ForwardingTask.java
index 83f2128..81bd972 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/ForwardingTask.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/ForwardingTask.java
@@ -72,6 +72,11 @@ public abstract class ForwardingTask<T> extends ForwardingObject implements Task
     public boolean isDone() {
         return delegate().isDone();
     }
+    
+    @Override
+    public boolean isDone(boolean andTaskNotRunning) {
+        return delegate().isDone(andTaskNotRunning);
+    }
 
     @Override
     public Task<T> asTask() {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/934cf4cc/core/src/main/java/org/apache/brooklyn/util/core/task/ScheduledTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/ScheduledTask.java b/core/src/main/java/org/apache/brooklyn/util/core/task/ScheduledTask.java
index c253916..89eb6ab 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/ScheduledTask.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/ScheduledTask.java
@@ -30,6 +30,7 @@ import java.util.concurrent.TimeUnit;
 
 import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.time.Duration;
 
 import com.google.common.annotations.Beta;
@@ -178,7 +179,10 @@ public class ScheduledTask extends BasicTask<Object> {
     }
     
     @Override
-    public boolean isDone() {
+    public boolean isDone(boolean andTaskNoLongerRunning) {
+        if (andTaskNoLongerRunning) {
+            return super.isDone(true);
+        }
         return isCancelled() || (maxIterations!=null && maxIterations <= runCount) || (period==null && nextRun!=null && nextRun.isDone());
     }
     
@@ -214,6 +218,14 @@ public class ScheduledTask extends BasicTask<Object> {
     protected boolean doCancel(org.apache.brooklyn.util.core.task.TaskInternal.TaskCancellationMode mode) {
         if (nextRun!=null) {
             ((TaskInternal<?>)nextRun).cancel(mode);
+            try {
+                ((TaskInternal<?>)nextRun).getJob().call();
+                nextRun = null;
+            } catch (CancellationException e) {
+                // expected, ignore
+            } catch (Exception e) {
+                throw Exceptions.propagateAnnotated("Error cancelling scheduled task "+this, e);
+            }
         }
         return super.doCancel(mode);
     }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/934cf4cc/core/src/main/java/org/apache/brooklyn/util/core/task/TaskInternal.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/TaskInternal.java b/core/src/main/java/org/apache/brooklyn/util/core/task/TaskInternal.java
index 6b3365b..c49544a 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/TaskInternal.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/TaskInternal.java
@@ -97,8 +97,10 @@ public interface TaskInternal<T> extends Task<T> {
     
     Object getExtraStatusText();
 
-    /** On task completion (or cancellation) runs the listeners which have been registered using 
-     * {@link #addListener(Runnable, java.util.concurrent.Executor)}. */
+    /** On task completion runs the listeners which have been registered using 
+     * {@link #addListener(Runnable, java.util.concurrent.Executor)}.
+     * <p>
+     * Doeas not run immediately on cancellation, it waits for the task to recognize it is cancelled. */
     void runListeners();
 
     void setEndTimeUtc(long val);
@@ -126,7 +128,7 @@ public interface TaskInternal<T> extends Task<T> {
      * this returns the "real" task represented by this one */
     Task<?> getProxyTarget();
 
-    /** clearer semantics around cancellation; may be promoted to {@link Task} if we  */
+    /** clearer semantics around cancellation; may be promoted to {@link Task} */
     @Beta
     public boolean cancel(TaskCancellationMode mode);
     

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/934cf4cc/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindFeedTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindFeedTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindFeedTest.java
index 1503bfa..68e6f78 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindFeedTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindFeedTest.java
@@ -44,6 +44,8 @@ import org.apache.brooklyn.feed.http.HttpValueFunctions;
 import org.apache.brooklyn.feed.ssh.SshFeed;
 import org.apache.brooklyn.feed.ssh.SshPollConfig;
 import org.apache.brooklyn.feed.ssh.SshValueFunctions;
+import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.core.http.BetterMockWebServer;
@@ -58,8 +60,6 @@ import org.testng.Assert;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
-import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
-import org.apache.brooklyn.location.ssh.SshMachineLocation;
 
 import com.google.common.base.Function;
 import com.google.common.base.Predicates;


[26/35] brooklyn-server git commit: change TaskInternal.setSubmittedBy(Maybe) to take a String

Posted by he...@apache.org.
change TaskInternal.setSubmittedBy(Maybe) to take a String


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

Branch: refs/heads/master
Commit: ed4eeba2f97545d5343f33ff7d08febad52bc523
Parents: 4b7844c
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Thu Sep 28 15:41:52 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Thu Sep 28 15:41:52 2017 +0100

----------------------------------------------------------------------
 .../util/core/task/BasicExecutionManager.java     |  3 ++-
 .../apache/brooklyn/util/core/task/BasicTask.java | 18 ++++++------------
 .../brooklyn/util/core/task/ForwardingTask.java   |  4 ++--
 .../brooklyn/util/core/task/TaskInternal.java     |  3 ++-
 4 files changed, 12 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/ed4eeba2/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
index c2bf12c..e71b43e 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
@@ -755,7 +755,8 @@ public class BasicExecutionManager implements ExecutionManager {
             Task<?> currentTask = Tasks.current();
             if (currentTask!=null) ((TaskInternal<?>)task).setSubmittedByTask(
                     // do this instead of soft reference (2017-09) as soft refs impact GC 
-                    Maybe.of(new TaskLookup(this, currentTask)) );
+                    Maybe.of(new TaskLookup(this, currentTask)),
+                    currentTask.getId());
         }
         ((TaskInternal<?>)task).setSubmitTimeUtc(System.currentTimeMillis());
         

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/ed4eeba2/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
index 9367b4a..4f448ec 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
@@ -43,11 +43,9 @@ import java.util.concurrent.TimeoutException;
 
 import org.apache.brooklyn.api.mgmt.HasTaskChildren;
 import org.apache.brooklyn.api.mgmt.Task;
-import org.apache.brooklyn.api.objs.Identifiable;
 import org.apache.brooklyn.util.JavaGroovyEquivalents;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.guava.Maybe;
-import org.apache.brooklyn.util.guava.Maybe.MaybeSupplier;
 import org.apache.brooklyn.util.text.Identifiers;
 import org.apache.brooklyn.util.text.Strings;
 import org.apache.brooklyn.util.time.Duration;
@@ -58,7 +56,6 @@ import org.slf4j.LoggerFactory;
 import com.google.common.annotations.Beta;
 import com.google.common.base.Function;
 import com.google.common.base.Objects;
-import com.google.common.base.Supplier;
 import com.google.common.base.Throwables;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
@@ -204,6 +201,7 @@ public class BasicTask<T> implements TaskInternal<T> {
     protected long startTimeUtc = -1;
     protected long endTimeUtc = -1;
     protected Maybe<Task<?>> submittedByTask;
+    protected String submittedByTaskId;
 
     protected volatile Thread thread = null;
     protected volatile boolean cancelled = false;
@@ -247,14 +245,9 @@ public class BasicTask<T> implements TaskInternal<T> {
     }
     @Override
     public String getSubmittedByTaskId() {
+        if (submittedByTaskId!=null) return submittedByTaskId;
         if (submittedByTask==null || submittedByTask.isAbsent()) return null;
-        if (submittedByTask instanceof MaybeSupplier) {
-            Supplier<?> supplier = ((MaybeSupplier<?>)submittedByTask).getSupplier();
-            if (supplier instanceof Identifiable) {
-                return ((Identifiable)supplier).getId();
-            }
-        }
-        return submittedByTask.get().getId();
+        throw new IllegalStateException("Task was set up with a submitted task but no task ID");
     }
 
     /** the thread where the task is running, if it is running */
@@ -917,11 +910,12 @@ public class BasicTask<T> implements TaskInternal<T> {
     
     @Override
     public void setSubmittedByTask(Task<?> task) {
-        setSubmittedByTask(Maybe.of(task));
+        setSubmittedByTask(Maybe.of(task), task==null ? null : task.getId());
     }
     @Override
-    public void setSubmittedByTask(Maybe<Task<?>> taskM) {
+    public void setSubmittedByTask(Maybe<Task<?>> taskM, String taskId) {
         submittedByTask = taskM;
+        submittedByTaskId = taskId;
     }
     
     @Override

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/ed4eeba2/core/src/main/java/org/apache/brooklyn/util/core/task/ForwardingTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/ForwardingTask.java b/core/src/main/java/org/apache/brooklyn/util/core/task/ForwardingTask.java
index 81bd972..1254c35 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/ForwardingTask.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/ForwardingTask.java
@@ -314,8 +314,8 @@ public abstract class ForwardingTask<T> extends ForwardingObject implements Task
     }
 
     @Override
-    public void setSubmittedByTask(Maybe<Task<?>> taskM) {
-        delegate().setSubmittedByTask(taskM);
+    public void setSubmittedByTask(Maybe<Task<?>> taskM, String taskId) {
+        delegate().setSubmittedByTask(taskM, taskId);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/ed4eeba2/core/src/main/java/org/apache/brooklyn/util/core/task/TaskInternal.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/TaskInternal.java b/core/src/main/java/org/apache/brooklyn/util/core/task/TaskInternal.java
index 7c82f6e..5bf5ae6 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/TaskInternal.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/TaskInternal.java
@@ -116,7 +116,8 @@ public interface TaskInternal<T> extends Task<T>, TaskInternalCancellableWithMod
     void setSubmitTimeUtc(long currentTimeMillis);
 
     void setSubmittedByTask(Task<?> task);
-    void setSubmittedByTask(Maybe<Task<?>> task);
+    /** Variant of {@link #setSubmittedByTask(Task)} which allows better support for GC'd tasks. */
+    void setSubmittedByTask(Maybe<Task<?>> task, String taskId);
     
     Set<Object> getMutableTags();
 


[34/35] brooklyn-server git commit: This closes #821

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


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

Branch: refs/heads/master
Commit: c177a7c1b4a45fae773d85ebf1e8af60d71e3cbd
Parents: ff5ba37 d5d72cb
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Oct 3 15:17:12 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Oct 3 15:17:12 2017 +0100

----------------------------------------------------------------------
 .../org/apache/brooklyn/api/entity/Entity.java  |   3 +
 .../org/apache/brooklyn/api/sensor/Feed.java    |   2 +-
 .../brooklyn/core/entity/AbstractEntity.java    |  34 ++-
 .../brooklyn/core/entity/EntityAdjuncts.java    |  28 +-
 .../brooklyn/core/entity/EntityInternal.java    |  16 +-
 .../apache/brooklyn/core/feed/AbstractFeed.java |   2 +-
 .../apache/brooklyn/core/policy/Policies.java   |  66 +----
 .../core/entity/EntityConcurrencyTest.java      |   2 +-
 .../launcher/CleanOrphanedAdjunctsTest.java     |   6 +-
 .../apache/brooklyn/rest/api/AdjunctApi.java    | 237 ++++++++++++++++
 .../apache/brooklyn/rest/api/CatalogApi.java    |  34 +--
 .../brooklyn/rest/api/EntityConfigApi.java      |  10 +-
 .../org/apache/brooklyn/rest/api/PolicyApi.java |  16 +-
 .../brooklyn/rest/api/PolicyConfigApi.java      |  35 ++-
 .../brooklyn/rest/domain/AdjunctDetail.java     |  72 +++++
 .../brooklyn/rest/domain/AdjunctSummary.java    | 148 ++++++++++
 .../brooklyn/rest/domain/ApplicationSpec.java   |  12 +-
 .../rest/domain/CatalogEnricherSummary.java     |   4 +
 .../rest/domain/CatalogEntitySummary.java       |   4 +
 .../rest/domain/CatalogItemSummary.java         |   4 +
 .../rest/domain/CatalogLocationSummary.java     |   4 +
 .../rest/domain/CatalogPolicySummary.java       |   4 +
 .../brooklyn/rest/domain/EffectorSummary.java   |   9 +-
 .../brooklyn/rest/domain/EntityDetail.java      |  14 +-
 .../brooklyn/rest/domain/EntitySummary.java     |  11 +-
 .../rest/domain/PolicyConfigSummary.java        |   2 +-
 .../brooklyn/rest/domain/PolicySummary.java     |  83 +-----
 .../rest/domain/ScriptExecutionSummary.java     |  11 +-
 .../brooklyn/rest/domain/SensorSummary.java     |   7 +-
 .../org/apache/brooklyn/rest/domain/Status.java |   7 +-
 .../apache/brooklyn/rest/BrooklynRestApi.java   |   2 +
 .../rest/resources/AdjunctResource.java         | 273 +++++++++++++++++++
 .../rest/resources/CatalogResource.java         |  21 +-
 .../rest/resources/EntityConfigResource.java    |  10 +-
 .../rest/resources/PolicyConfigResource.java    |   1 +
 .../brooklyn/rest/resources/PolicyResource.java |   2 +-
 .../rest/transform/AdjunctTransformer.java      |  96 +++++++
 .../rest/transform/CatalogTransformer.java      |  30 +-
 .../rest/transform/ConfigTransformer.java       | 175 ++++++++++++
 .../rest/transform/EntityTransformer.java       | 107 ++++----
 .../rest/transform/PolicyTransformer.java       |   3 +
 .../rest/transform/SensorTransformer.java       |  21 +-
 .../rest/transform/TypeTransformer.java         |  10 +-
 .../rest/util/BrooklynRestResourceUtils.java    |  44 +++
 .../rest/resources/AdjunctResourceTest.java     | 198 ++++++++++++++
 .../rest/testing/BrooklynRestResourceTest.java  |   2 +-
 .../brooklyn/cli/lister/ItemDescriptors.java    |  26 +-
 47 files changed, 1566 insertions(+), 342 deletions(-)
----------------------------------------------------------------------



[02/35] brooklyn-server git commit: Merge branch 'highlights-adjuncts' into adjunct-rest-api-and-highlights-2

Posted by he...@apache.org.
Merge branch 'highlights-adjuncts' into adjunct-rest-api-and-highlights-2


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

Branch: refs/heads/master
Commit: 2860af56a7e77de8742fb3b6a0c22903f33e3a6b
Parents: 80a4c25 7170846
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Sep 13 16:52:27 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Sep 13 16:52:27 2017 +0100

----------------------------------------------------------------------
 .../brooklyn/api/objs/HighlightTuple.java       |  23 ++--
 .../core/enricher/AbstractEnricher.java         |  19 +++-
 .../entity/lifecycle/ServiceStateLogic.java     |   3 +
 .../apache/brooklyn/core/feed/AbstractFeed.java |  16 ++-
 .../core/feed/AttributePollHandler.java         |   2 +
 .../org/apache/brooklyn/core/feed/Poller.java   |  20 +++-
 .../core/objs/AbstractEntityAdjunct.java        | 104 ++++++++++++++++++-
 .../enricher/stock/AbstractAggregator.java      |  12 +++
 .../stock/AbstractMultipleSensorAggregator.java |   2 -
 .../enricher/stock/AbstractTransformer.java     |   3 +
 .../stock/AbstractTypeTransformingEnricher.java |   3 +
 .../brooklyn/enricher/stock/Aggregator.java     |   5 +
 .../brooklyn/enricher/stock/Combiner.java       |   2 +
 .../apache/brooklyn/enricher/stock/Joiner.java  |   1 +
 .../brooklyn/enricher/stock/Propagator.java     |   6 ++
 .../brooklyn/enricher/stock/UpdatingMap.java    |   2 +
 .../enricher/stock/reducer/Reducer.java         |   1 +
 .../group/AbstractMembershipTrackingPolicy.java |  23 +++-
 .../SshCommandMembershipTrackingPolicy.java     |  15 ++-
 .../core/policy/basic/BasicPolicyTest.java      |   9 +-
 .../policy/autoscaling/AutoScalerPolicy.java    |  62 +++++++----
 .../brooklyn/policy/ha/ServiceReplacer.java     |  46 ++++----
 .../brooklyn/policy/ha/ServiceRestarter.java    |   9 +-
 .../autoscaling/AutoScalerPolicyRebindTest.java |   5 +-
 .../testing/mocks/RestMockSimplePolicy.java     |   4 +-
 .../entity/machine/pool/ServerPoolImpl.java     |   1 +
 .../software/base/SoftwareProcessImpl.java      |   3 +
 .../brooklynnode/SelectMasterEffectorTest.java  |   2 +-
 28 files changed, 329 insertions(+), 74 deletions(-)
----------------------------------------------------------------------



[04/35] brooklyn-server git commit: don't repeat task tracking code between scheduled and non-scheduled code paths

Posted by he...@apache.org.
don't repeat task tracking code between scheduled and non-scheduled code paths


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

Branch: refs/heads/master
Commit: a11af34c33c69ef00adeb8906bb81d0776915c6b
Parents: 438846c
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Sep 8 16:00:29 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Sep 15 10:29:07 2017 +0100

----------------------------------------------------------------------
 .../brooklyn/util/core/task/BasicExecutionManager.java      | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/a11af34c/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
index 729639d..4f8a9ec 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
@@ -401,9 +401,6 @@ public class BasicExecutionManager implements ExecutionManager {
     }
 
     protected Task<?> submitNewScheduledTask(final Map<?,?> flags, final ScheduledTask task) {
-        tasksById.put(task.getId(), task);
-        totalTaskCount.incrementAndGet();
-        
         beforeSubmitScheduledTaskAllIterations(flags, task);
         
         return submitSubsequentScheduledTask(flags, task);
@@ -680,9 +677,6 @@ public class BasicExecutionManager implements ExecutionManager {
         if (task instanceof ScheduledTask)
             return (Task<T>) submitNewScheduledTask(flags, (ScheduledTask)task);
         
-        tasksById.put(task.getId(), task);
-        totalTaskCount.incrementAndGet();
-        
         beforeSubmitAtomicTask(flags, task);
         
         if (((TaskInternal<T>)task).getJob() == null) 
@@ -741,6 +735,9 @@ public class BasicExecutionManager implements ExecutionManager {
         for (Object tag: BrooklynTaskTags.getTagsFast(task)) {
             tasksWithTagCreating(tag).add(task);
         }
+        
+        tasksById.put(task.getId(), task);
+        totalTaskCount.incrementAndGet();
     }
 
     protected void beforeStartScheduledTaskSubmissionIteration(Map<?,?> flags, Task<?> task) {


[09/35] brooklyn-server git commit: more bookkeeping for immediate/same-thread tasks

Posted by he...@apache.org.
more bookkeeping for immediate/same-thread tasks


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

Branch: refs/heads/master
Commit: 9d2faf0eddcd37ed0ec31cf1b9856a95b5702e14
Parents: a11af34
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Sep 11 08:40:31 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Sep 15 10:29:08 2017 +0100

----------------------------------------------------------------------
 .../util/core/task/BasicExecutionContext.java   | 14 ++++++---
 .../util/core/task/BasicExecutionManager.java   | 32 ++++++++++++++------
 .../util/core/task/ValueResolverTest.java       |  3 +-
 3 files changed, 34 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9d2faf0e/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
index 6bb7679..e0dd8b0 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
@@ -131,11 +131,11 @@ public class BasicExecutionContext extends AbstractExecutionContext {
         Task<?> previousTask = BasicExecutionManager.getPerThreadCurrentTask().get();
         BasicExecutionContext oldExecutionContext = getCurrentExecutionContext();
         registerPerThreadExecutionContext();
+        ((BasicExecutionManager)executionManager).beforeSubmitInSameThreadTask(null, fakeTaskForContext);
 
-        if (previousTask!=null) fakeTaskForContext.setSubmittedByTask(previousTask);
-        fakeTaskForContext.cancel();
         try {
-            BasicExecutionManager.getPerThreadCurrentTask().set(fakeTaskForContext);
+            ((BasicExecutionManager)executionManager).beforeStartInSameThreadTask(null, fakeTaskForContext);
+            fakeTaskForContext.cancel();
             
             if (!(callableOrSupplier instanceof ImmediateSupplier)) {
                 callableOrSupplier = InterruptingImmediateSupplier.of(callableOrSupplier);
@@ -150,8 +150,12 @@ public class BasicExecutionContext extends AbstractExecutionContext {
             }
  
         } finally {
-            BasicExecutionManager.getPerThreadCurrentTask().set(previousTask);
-            perThreadExecutionContext.set(oldExecutionContext);
+            try {
+                ((BasicExecutionManager)executionManager).afterEndInSameThreadTask(null, fakeTaskForContext);
+            } finally {
+                BasicExecutionManager.getPerThreadCurrentTask().set(previousTask);
+                perThreadExecutionContext.set(oldExecutionContext);
+            }
         }
     }
     

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9d2faf0e/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
index 4f8a9ec..aa61a57 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
@@ -721,6 +721,9 @@ public class BasicExecutionManager implements ExecutionManager {
     protected void beforeSubmitAtomicTask(Map<?,?> flags, Task<?> task) {
         internalBeforeSubmit(flags, task);
     }
+    protected void beforeSubmitInSameThreadTask(Map<?,?> flags, Task<?> task) {
+        internalBeforeSubmit(flags, task);
+    }
     /** invoked when a task is submitted */
     protected void internalBeforeSubmit(Map<?,?> flags, Task<?> task) {
         incompleteTaskIds.add(task.getId());
@@ -729,8 +732,8 @@ public class BasicExecutionManager implements ExecutionManager {
         if (currentTask!=null) ((TaskInternal<?>)task).setSubmittedByTask(currentTask);
         ((TaskInternal<?>)task).setSubmitTimeUtc(System.currentTimeMillis());
         
-        if (flags.get("tag")!=null) ((TaskInternal<?>)task).getMutableTags().add(flags.remove("tag"));
-        if (flags.get("tags")!=null) ((TaskInternal<?>)task).getMutableTags().addAll((Collection<?>)flags.remove("tags"));
+        if (flags!=null && flags.get("tag")!=null) ((TaskInternal<?>)task).getMutableTags().add(flags.remove("tag"));
+        if (flags!=null && flags.get("tags")!=null) ((TaskInternal<?>)task).getMutableTags().addAll((Collection<?>)flags.remove("tags"));
 
         for (Object tag: BrooklynTaskTags.getTagsFast(task)) {
             tasksWithTagCreating(tag).add(task);
@@ -741,15 +744,18 @@ public class BasicExecutionManager implements ExecutionManager {
     }
 
     protected void beforeStartScheduledTaskSubmissionIteration(Map<?,?> flags, Task<?> task) {
-        internalBeforeStart(flags, task);
+        internalBeforeStart(flags, task, true);
     }
     protected void beforeStartAtomicTask(Map<?,?> flags, Task<?> task) {
-        internalBeforeStart(flags, task);
+        internalBeforeStart(flags, task, true);
+    }
+    protected void beforeStartInSameThreadTask(Map<?,?> flags, Task<?> task) {
+        internalBeforeStart(flags, task, false);
     }
     
     /** invoked in a task's thread when a task is starting to run (may be some time after submitted), 
      * but before doing any of the task's work, so that we can update bookkeeping and notify callbacks */
-    protected void internalBeforeStart(Map<?,?> flags, Task<?> task) {
+    protected void internalBeforeStart(Map<?,?> flags, Task<?> task, boolean allowJitter) {
         int count = activeTaskCount.incrementAndGet();
         if (count % 1000==0) {
             log.warn("High number of active tasks: task #"+count+" is "+task);
@@ -769,9 +775,12 @@ public class BasicExecutionManager implements ExecutionManager {
             ((TaskInternal<?>)task).setStartTimeUtc(System.currentTimeMillis());
         }
 
-        jitterThreadStart(task);
-
-        invokeCallback(flags.get("newTaskStartCallback"), task);
+        if (allowJitter) {
+            jitterThreadStart(task);
+        }
+        if (flags!=null) {
+            invokeCallback(flags.get("newTaskStartCallback"), task);
+        }
     }
 
     private void jitterThreadStart(Task<?> task) {
@@ -825,6 +834,9 @@ public class BasicExecutionManager implements ExecutionManager {
     protected void afterEndAtomicTask(Map<?,?> flags, Task<?> task) {
         internalAfterEnd(flags, task, true, true);
     }
+    protected void afterEndInSameThreadTask(Map<?,?> flags, Task<?> task) {
+        internalAfterEnd(flags, task, true, true);
+    }
     /** normally (if not interrupted) called once for each call to {@link #internalBeforeSubmit(Map, Task)},
      * and, for atomic tasks and scheduled-task submission iterations where 
      * always called once if {@link #internalBeforeStart(Map, Task)} is invoked and in the same thread as that method */
@@ -835,7 +847,9 @@ public class BasicExecutionManager implements ExecutionManager {
         }
         if (isEndingAllIterations) {
             incompleteTaskIds.remove(task.getId());
-            invokeCallback(flags.get("newTaskEndCallback"), task);
+            if (flags!=null) {
+                invokeCallback(flags.get("newTaskEndCallback"), task);
+            }
             ((TaskInternal<?>)task).setEndTimeUtc(System.currentTimeMillis());
         }
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9d2faf0e/core/src/test/java/org/apache/brooklyn/util/core/task/ValueResolverTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/util/core/task/ValueResolverTest.java b/core/src/test/java/org/apache/brooklyn/util/core/task/ValueResolverTest.java
index 6e57c84..1f5c754 100644
--- a/core/src/test/java/org/apache/brooklyn/util/core/task/ValueResolverTest.java
+++ b/core/src/test/java/org/apache/brooklyn/util/core/task/ValueResolverTest.java
@@ -471,7 +471,8 @@ public class ValueResolverTest extends BrooklynAppUnitTestSupport {
     private void assertImmediateFakeTaskFromMethod(CallInfo callInfo, String method) {
         // previously task was null, but now there is a "fake task"
         assertNotNull(callInfo.task);
-        Assert.assertFalse(callInfo.task.isSubmitted());       
+        // it is now submitted in same thread (2017-09)
+        Assert.assertTrue(callInfo.task.isSubmitted());       
         assertContainsCallingMethod(callInfo.stackTrace, method);
     }
     


[31/35] brooklyn-server git commit: steps toward bringing FeedSupport in line with other AdjunctSupport classes

Posted by he...@apache.org.
steps toward bringing FeedSupport in line with other AdjunctSupport classes

deprecating more methods which need to change or should go

will need to add FeedSpec in future to bring it fully in line


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

Branch: refs/heads/master
Commit: dd4f05e04efc1bbfa70d024f6ad4191017291e5f
Parents: e016053
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Oct 3 09:50:39 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Oct 3 09:50:39 2017 +0100

----------------------------------------------------------------------
 .../org/apache/brooklyn/api/entity/Entity.java  |  3 ++
 .../brooklyn/core/entity/AbstractEntity.java    | 29 ++++++++++++++++----
 .../brooklyn/core/entity/EntityInternal.java    | 14 ++++------
 .../apache/brooklyn/core/feed/AbstractFeed.java |  2 +-
 .../core/entity/EntityConcurrencyTest.java      |  2 +-
 .../launcher/CleanOrphanedAdjunctsTest.java     |  6 ++--
 6 files changed, 39 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/dd4f05e0/api/src/main/java/org/apache/brooklyn/api/entity/Entity.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/entity/Entity.java b/api/src/main/java/org/apache/brooklyn/api/entity/Entity.java
index da9169e..bbee0ad 100644
--- a/api/src/main/java/org/apache/brooklyn/api/entity/Entity.java
+++ b/api/src/main/java/org/apache/brooklyn/api/entity/Entity.java
@@ -286,7 +286,10 @@ public interface Entity extends BrooklynObject {
     
     /**
      * Adds the given feed to this entity. Also calls feed.setEntity if available.
+     * 
+     * @deprecated since 0.13.0; see {@link FeedSupport#add(Feed)}
      */
+    @Deprecated
     <T extends Feed> T addFeed(T feed);
     
     SensorSupport sensors();

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/dd4f05e0/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java b/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java
index d221c16..bd7df06 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java
@@ -1871,7 +1871,8 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E
      */
     @Override
     public <T extends Feed> T addFeed(T feed) {
-        return feeds().add(feed);
+        feeds().add(feed);
+        return feed;
     }
 
     @Override
@@ -1896,8 +1897,9 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E
         public <T extends Feed> T add(T feed) {
             return addFeed(feed);
         }
-
-        @Override
+        
+        /** @deprecated since 0.13.0 use {@link #add(Feed)} */
+        @Deprecated
         public <T extends Feed> T addFeed(T feed) {
             Feed old = findApparentlyEqualAndWarnIfNotSameUniqueTag(feedsInternal, feed);
             if (old != null) {
@@ -1921,7 +1923,7 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E
             getManagementContext().getRebindManager().getChangeListener().onManaged(feed);
             getManagementSupport().getEntityChangeListener().onFeedAdded(feed);
             // TODO Could add equivalent of AbstractEntity.POLICY_ADDED for feeds; no use-case for that yet
-
+            
             return feed;
         }
 
@@ -1930,7 +1932,8 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E
             return removeFeed(feed);
         }
 
-        @Override
+        /** @deprecated since 0.13.0 use {@link #remove(Feed)} */
+        @Deprecated
         public boolean removeFeed(Feed feed) {
             feed.stop();
             boolean changed = feedsInternal.remove(feed);
@@ -1960,6 +1963,22 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E
         public Iterator<Feed> iterator() {
             return getFeeds().iterator();
         }
+
+        // TODO add these back when we implement AdjunctSupport (after 0.13.0)
+//        @Override
+//        public int size() {
+//            return getFeeds().size();
+//        }
+//
+//        @Override
+//        public boolean isEmpty() {
+//            return getFeeds().isEmpty();
+//        }
+//
+//        @Override
+//        public List<Feed> asList() {
+//            return ImmutableList.copyOf(getFeeds());
+//        }
     }
     
     // -------- SENSORS --------------------

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/dd4f05e0/core/src/main/java/org/apache/brooklyn/core/entity/EntityInternal.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/EntityInternal.java b/core/src/main/java/org/apache/brooklyn/core/entity/EntityInternal.java
index 7377f38..46d10ab 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/EntityInternal.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/EntityInternal.java
@@ -189,29 +189,27 @@ public interface EntityInternal extends BrooklynObjectInternal, EntityLocal, Reb
         void remove(AttributeSensor<?> attribute);
     }
 
+    // TODO extend AdjunctSupport<Feed>, after 0.13.0
     public interface FeedSupport extends Iterable<Feed> {
 
         Collection<Feed> getFeeds();
 
         /**
          * Adds the given feed to this entity. The feed will automatically be re-added on brooklyn restart.
+         * 
+         * @deprecated since 0.13.0 will change to return type 'void', for consistency with other {@link AdjunctSupport}
          */
-        <T extends Feed> T add(T feed);
-
-        /** @deprecated since 0.10.0; use {@link #add()} */
         @Deprecated
-        <T extends Feed> T addFeed(T feed);
+//        @Override
+        <T extends Feed> T add(T feed);
 
         /**
          * Removes the given feed from this entity. 
          * @return True if the feed existed at this entity; false otherwise
          */
+//        @Override
         boolean remove(Feed feed);
 
-        /** @deprecated since 0.10.0; use {@link #remove()} */
-        @Deprecated
-        boolean removeFeed(Feed feed);
-
         /**
          * Removes all feeds from this entity.
          * Use with caution as some entities automatically register feeds; this will remove those feeds as well.

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/dd4f05e0/core/src/main/java/org/apache/brooklyn/core/feed/AbstractFeed.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/feed/AbstractFeed.java b/core/src/main/java/org/apache/brooklyn/core/feed/AbstractFeed.java
index 84165ea..316d269 100644
--- a/core/src/main/java/org/apache/brooklyn/core/feed/AbstractFeed.java
+++ b/core/src/main/java/org/apache/brooklyn/core/feed/AbstractFeed.java
@@ -62,7 +62,7 @@ public abstract class AbstractFeed extends AbstractEntityAdjunct implements Feed
     public void setEntity(EntityLocal entity) {
         super.setEntity(entity);
         if (BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_FEED_REGISTRATION_PROPERTY)) {
-            ((EntityInternal)entity).feeds().addFeed(this);
+            ((EntityInternal)entity).feeds().add(this);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/dd4f05e0/core/src/test/java/org/apache/brooklyn/core/entity/EntityConcurrencyTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/EntityConcurrencyTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/EntityConcurrencyTest.java
index f606226..a4a77c0 100644
--- a/core/src/test/java/org/apache/brooklyn/core/entity/EntityConcurrencyTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/EntityConcurrencyTest.java
@@ -261,7 +261,7 @@ public class EntityConcurrencyTest extends BrooklynAppUnitTestSupport {
         for (int i = 0; i < NUM_TASKS; i++) {
             ListenableFuture<?> future = executor.submit(new Runnable() {
                 @Override public void run() {
-                    entity.feeds().addFeed(new MyFeed());
+                    entity.feeds().add(new MyFeed());
                 }});
             futures.add(future);
         }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/dd4f05e0/launcher/src/test/java/org/apache/brooklyn/launcher/CleanOrphanedAdjunctsTest.java
----------------------------------------------------------------------
diff --git a/launcher/src/test/java/org/apache/brooklyn/launcher/CleanOrphanedAdjunctsTest.java b/launcher/src/test/java/org/apache/brooklyn/launcher/CleanOrphanedAdjunctsTest.java
index f9e772a..b8f8fef 100644
--- a/launcher/src/test/java/org/apache/brooklyn/launcher/CleanOrphanedAdjunctsTest.java
+++ b/launcher/src/test/java/org/apache/brooklyn/launcher/CleanOrphanedAdjunctsTest.java
@@ -54,7 +54,8 @@ public class CleanOrphanedAdjunctsTest extends AbstractCleanOrphanedStateTest {
     @Test
     public void testDeletesOrphanedFeeds() throws Exception {
         EntityInternal entity = origApp.addChild(EntitySpec.create(TestEntity.class).impl(MyEntity.class));
-        Feed feed = entity.feeds().add(new MyFeed());
+        Feed feed = new MyFeed();
+        entity.feeds().add(feed);
         MementoTweaker tweaker = new MementoTweaker(new Deletions().entities(entity.getId()));
         assertTransformDeletes(new Deletions().feeds(feed.getId()), tweaker);
     }
@@ -63,7 +64,8 @@ public class CleanOrphanedAdjunctsTest extends AbstractCleanOrphanedStateTest {
     public void testKeepsReachableAdjuncts() throws Exception {
         MyPolicy policy = origApp.policies().add(PolicySpec.create(MyPolicy.class));
         MyEnricher enricher = origApp.enrichers().add(EnricherSpec.create(MyEnricher.class));
-        Feed feed = origApp.feeds().add(new MyFeed());
+        Feed feed = new MyFeed();
+        origApp.feeds().add(feed);
         
         // Double-check we have the state we expected for the assertions that it is unmodified!
         BrooklynMementoRawData origData = getRawData();


[27/35] brooklyn-server git commit: improve description of `getImmediately` and tidy a few usages

Posted by he...@apache.org.
improve description of `getImmediately` and tidy a few usages

all usages seem consistent with the current cancellation semantics,
they just weren't very clear


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

Branch: refs/heads/master
Commit: afc17ee0025235e061cfb29a44863ad5fab9fa9d
Parents: ed4eeba
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Thu Sep 28 16:14:17 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Thu Sep 28 17:28:29 2017 +0100

----------------------------------------------------------------------
 .../org/apache/brooklyn/api/mgmt/ExecutionContext.java  |  8 +++++++-
 .../brooklyn/util/core/task/BasicExecutionContext.java  | 12 ++++++++----
 .../apache/brooklyn/util/core/task/ValueResolver.java   |  9 +++++----
 .../brooklyn/core/effector/EffectorSayHiTest.java       |  2 +-
 4 files changed, 21 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/afc17ee0/api/src/main/java/org/apache/brooklyn/api/mgmt/ExecutionContext.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/mgmt/ExecutionContext.java b/api/src/main/java/org/apache/brooklyn/api/mgmt/ExecutionContext.java
index 142e664..2ad9482 100644
--- a/api/src/main/java/org/apache/brooklyn/api/mgmt/ExecutionContext.java
+++ b/api/src/main/java/org/apache/brooklyn/api/mgmt/ExecutionContext.java
@@ -75,7 +75,13 @@ public interface ExecutionContext extends Executor {
      * Implementations will typically act like {@link #get(TaskAdaptable)} with additional
      * tricks to attempt to be non-blocking, such as recognizing some "immediate" markers.  
      * <p>
-     * Also supports {@link Callable}, {@link Runnable}, and {@link Supplier} argument types.
+     * Supports {@link Callable}, {@link Runnable}, and {@link Supplier} argument types as well as {@link Task}.
+     * <p>
+     * This executes the given code, and in the case of {@link Task} it may cancel it, 
+     * so the caller should not use this if the argument is going to be used later and
+     * is expected to be pristine.  Supply a {@link TaskFactory} if this method's {@link Task#cancel(boolean)}
+     * is problematic, or consider other utilities (such as ValueResolver with immediate(true)
+     * in a downstream project).
      */
     // TODO reference ImmediateSupplier when that class is moved to utils project
     @Beta

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/afc17ee0/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
index 5e645a9..435e50e 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
@@ -281,10 +281,14 @@ public class BasicExecutionContext extends AbstractExecutionContext {
         try {
             return runInSameThread(fakeTaskForContext, new Callable<Maybe<T>>() {
                 public Maybe<T> call() {
-                    // TODO could try to make this work for more types of tasks by not cancelling, it just interrupting;
-                    // however the biggest place "getImmediate" fails is with DSTs where interrupting is sufficient to abort them
-                    // unnecessarily, as queue.andWait attempts to block (again, unnecessarily, but not a straightforward fix).
-                    // limited success of getImmediately is okay -- but no harm in expanding coverage by resolving that and removing cancel.
+                    // could try to make this work for more types of tasks by not cancelling, just interrupting;
+                    // however there is a danger that immediate-submission tasks are leaked if we don't cancel.
+                    // for instance with DSTs the thread interrupt may apply only to the main job queue.andWait blocking,
+                    // leaving other tasks leaked.
+                    //
+                    // this method is best-effort so fine if it doesn't succeed.  good if we can expand
+                    // coverage but NOT at the expense of major leaks of course!
+                    //
                     // see WIP test in EffectorSayHiTest
                     fakeTaskForContext.cancel();
                     

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/afc17ee0/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolver.java b/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolver.java
index 0e75d16..5f7621b 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolver.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolver.java
@@ -434,11 +434,12 @@ public class ValueResolver<T> implements DeferredSupplier<T>, Iterable<Maybe<Obj
                         // (should discourage this in favour of task factories which can be transiently interrupted?)
                         BrooklynTaskTags.addTagDynamically(task, BrooklynTaskTags.NON_TRANSIENT_TASK_TAG);
                     }
-                    // FIXME
-                    if (timer!=null || Thread.currentThread().isInterrupted() || isEvaluatingImmediately()) {
-                        exec.submit(task);
-                    } else {
+                    if (timer==null && !Thread.currentThread().isInterrupted() && !isEvaluatingImmediately()) {
+                        // if all conditions above:  no timeout, not immediate, and not interrupted,
+                        // then we can run in this thread
                         exec.get(task);
+                    } else {
+                        exec.submit(task);
                     }
                 }
             }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/afc17ee0/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiTest.java b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiTest.java
index 5110315..bc41d45 100644
--- a/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiTest.java
@@ -110,7 +110,7 @@ public class EffectorSayHiTest extends BrooklynAppUnitTestSupport {
     }
     
     @Test(groups="WIP")  // see comments at BasicExecutionContext.getImmediately
-    // FIXME
+    // TODO this will be fixed soon by #835
     public void testInvocationGetImmediately() throws Exception {
         assertEquals(((EntityInternal)e).getExecutionContext()
             .getImmediately( Effectors.invocation(e, MyEntity.SAY_HI_1, ImmutableMap.of("name", "Bob", "greeting", "hi")) ), "hi Bob");


[05/35] brooklyn-server git commit: optimization: skip tags copy on common simple lookups

Posted by he...@apache.org.
optimization: skip tags copy on common simple lookups


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

Branch: refs/heads/master
Commit: 438846c2967a64e109395a258effbf5b4db2cfd4
Parents: 16c788e
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Sep 12 22:11:56 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Sep 15 10:29:07 2017 +0100

----------------------------------------------------------------------
 .../org/apache/brooklyn/core/mgmt/BrooklynTaskTags.java | 12 ++++++------
 .../core/mgmt/internal/BrooklynGarbageCollector.java    |  5 +++--
 .../brooklyn/util/core/task/BasicExecutionManager.java  |  8 ++++----
 .../org/apache/brooklyn/util/core/task/BasicTask.java   |  1 +
 .../org/apache/brooklyn/util/core/task/TaskTags.java    | 10 +++++++++-
 .../java/org/apache/brooklyn/util/core/task/Tasks.java  |  2 +-
 6 files changed, 24 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/438846c2/core/src/main/java/org/apache/brooklyn/core/mgmt/BrooklynTaskTags.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/BrooklynTaskTags.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/BrooklynTaskTags.java
index 7d721d0..5cb1027 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/BrooklynTaskTags.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/BrooklynTaskTags.java
@@ -140,7 +140,7 @@ public class BrooklynTaskTags extends TaskTags {
 
     public static WrappedEntity getWrappedEntityTagOfType(Task<?> t, String wrappingType) {
         if (t==null) return null;
-        return getWrappedEntityTagOfType(t.getTags(), wrappingType);
+        return getWrappedEntityTagOfType( getTagsFast(t), wrappingType);
     }
     public static WrappedEntity getWrappedEntityTagOfType(Collection<?> tags, String wrappingType) {
         for (Object x: tags)
@@ -196,7 +196,7 @@ public class BrooklynTaskTags extends TaskTags {
     }
 
     public static ManagementContext getManagementContext(Task<?> task) {
-        for (Object tag : task.getTags())
+        for (Object tag : getTagsFast(task))
             if ((tag instanceof ManagementContext))
                 return (ManagementContext) tag;
         return null;
@@ -297,7 +297,7 @@ public class BrooklynTaskTags extends TaskTags {
     /** returns the set of tags indicating the streams available on a task */
     public static Set<WrappedStream> streams(Task<?> task) {
         Set<WrappedStream> result = new LinkedHashSet<BrooklynTaskTags.WrappedStream>();
-        for (Object tag: task.getTags()) {
+        for (Object tag: getTagsFast(task)) {
             if (tag instanceof WrappedStream) {
                 result.add((WrappedStream)tag);
             }
@@ -308,7 +308,7 @@ public class BrooklynTaskTags extends TaskTags {
     /** returns the tag for the indicated stream, or null */
     public static WrappedStream stream(Task<?> task, String streamType) {
         if (task==null) return null;
-        for (Object tag: task.getTags())
+        for (Object tag: getTagsFast(task))
             if ((tag instanceof WrappedStream) && ((WrappedStream)tag).streamType.equals(streamType))
                 return (WrappedStream)tag;
         return null;
@@ -432,7 +432,7 @@ public class BrooklynTaskTags extends TaskTags {
     public static EffectorCallTag getEffectorCallTag(Task<?> task, boolean recurse) {
         Task<?> t = task;
         while (t!=null) {
-            for (Object tag: t.getTags()) {
+            for (Object tag: getTagsFast(task)) {
                 if (tag instanceof EffectorCallTag)
                     return (EffectorCallTag)tag;
             }
@@ -473,7 +473,7 @@ public class BrooklynTaskTags extends TaskTags {
 
     public static EntitlementContext getEntitlement(Task<?> task) {
         if (task==null) return null;
-        return getEntitlement(task.getTags());
+        return getEntitlement(getTagsFast(task));
     }
     
     public static EntitlementContext getEntitlement(Collection<?> tags) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/438846c2/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/BrooklynGarbageCollector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/BrooklynGarbageCollector.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/BrooklynGarbageCollector.java
index 98dfd90..203c3a5 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/BrooklynGarbageCollector.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/BrooklynGarbageCollector.java
@@ -52,6 +52,7 @@ import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.core.task.BasicExecutionManager;
 import org.apache.brooklyn.util.core.task.ExecutionListener;
+import org.apache.brooklyn.util.core.task.TaskTags;
 import org.apache.brooklyn.util.core.task.Tasks;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.guava.Maybe.SoftlyPresent;
@@ -301,7 +302,7 @@ public class BrooklynGarbageCollector {
     protected boolean shouldDeleteTaskImmediately(Task<?> task) {
         if (!task.isDone()) return false;
         
-        Set<Object> tags = task.getTags();
+        Set<Object> tags = BrooklynTaskTags.getTagsFast(task);
         if (tags.contains(ManagementContextInternal.TRANSIENT_TASK_TAG))
             return true;
         if (tags.contains(ManagementContextInternal.EFFECTOR_TAG) || tags.contains(ManagementContextInternal.NON_TRANSIENT_TASK_TAG))
@@ -533,7 +534,7 @@ public class BrooklynGarbageCollector {
             for (Task<?> task: tasks) {
                 if (!task.isDone()) continue;
                 
-                Set<Object> tags = task.getTags();
+                Set<Object> tags = TaskTags.getTagsFast(task);
 
                 int categoryTags = 0, tooFullCategoryTags = 0;
                 for (Object tag: tags) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/438846c2/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
index aa16e7b..729639d 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
@@ -239,7 +239,7 @@ public class BasicExecutionManager implements ExecutionManager {
     }
 
     protected boolean deleteTaskNonRecursive(Task<?> task) {
-        Set<?> tags = checkNotNull(task, "task").getTags();
+        Set<?> tags = TaskTags.getTagsFast(checkNotNull(task, "task"));
         for (Object tag : tags) {
             synchronized (tasksByTag) {
                 Set<Task<?>> tasks = tasksWithTagLiveOrNull(tag);
@@ -669,7 +669,7 @@ public class BasicExecutionManager implements ExecutionManager {
     protected <T> Task<T> submitNewTask(final Map<?,?> flags, final Task<T> task) {
         if (log.isTraceEnabled()) {
             log.trace("Submitting task {} ({}), with flags {}, and tags {}, job {}; caller {}", 
-                new Object[] {task.getId(), task, Sanitizer.sanitize(flags), task.getTags(), 
+                new Object[] {task.getId(), task, Sanitizer.sanitize(flags), BrooklynTaskTags.getTagsFast(task), 
                 (task instanceof TaskInternal ? ((TaskInternal<T>)task).getJob() : "<unavailable>"),
                 Tasks.current() });
             if (Tasks.current()==null && BrooklynTaskTags.isTransient(task)) {
@@ -692,7 +692,7 @@ public class BasicExecutionManager implements ExecutionManager {
         
         // If there's a scheduler then use that; otherwise execute it directly
         Set<TaskScheduler> schedulers = null;
-        for (Object tago: task.getTags()) {
+        for (Object tago: BrooklynTaskTags.getTagsFast(task)) {
             TaskScheduler scheduler = getTaskSchedulerForTag(tago);
             if (scheduler!=null) {
                 if (schedulers==null) schedulers = new LinkedHashSet<TaskScheduler>(2);
@@ -738,7 +738,7 @@ public class BasicExecutionManager implements ExecutionManager {
         if (flags.get("tag")!=null) ((TaskInternal<?>)task).getMutableTags().add(flags.remove("tag"));
         if (flags.get("tags")!=null) ((TaskInternal<?>)task).getMutableTags().addAll((Collection<?>)flags.remove("tags"));
 
-        for (Object tag: ((TaskInternal<?>)task).getTags()) {
+        for (Object tag: BrooklynTaskTags.getTagsFast(task)) {
             tasksWithTagCreating(tag).add(task);
         }
     }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/438846c2/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
index 5e63c68..4398675 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
@@ -917,6 +917,7 @@ public class BasicTask<T> implements TaskInternal<T> {
     @SuppressWarnings({ "unchecked", "rawtypes" })
     @Override
     public void setSubmittedByTask(Task<?> task) {
+        // possible optimization, store details but don't create task until later
         submittedByTask = Maybe.softThen((Task)task, (Maybe)Maybe.of(BasicTask.newGoneTaskFor(task)));
     }
     

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/438846c2/core/src/main/java/org/apache/brooklyn/util/core/task/TaskTags.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/TaskTags.java b/core/src/main/java/org/apache/brooklyn/util/core/task/TaskTags.java
index 4319796..c62ace4 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/TaskTags.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/TaskTags.java
@@ -25,6 +25,7 @@ import javax.annotation.Nullable;
 import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.api.mgmt.TaskAdaptable;
 
+import com.google.common.annotations.Beta;
 import com.google.common.base.Function;
 
 public class TaskTags {
@@ -63,7 +64,7 @@ public class TaskTags {
 
     public static boolean hasTag(Task<?> task, Object tag) {
         if (task==null) return false;
-        return task.getTags().contains(tag);
+        return getTagsFast(task).contains(tag);
     }
     
     public static <U,V extends TaskAdaptable<U>> V markInessential(V task) {
@@ -71,4 +72,11 @@ public class TaskTags {
         return task;
     }
 
+    @Beta
+    public static Set<Object> getTagsFast(Task<?> task) {
+        if (task==null) return null;
+        if (task instanceof BasicTask) return ((BasicTask<?>)task).getMutableTags();
+        return task.getTags();
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/438846c2/core/src/main/java/org/apache/brooklyn/util/core/task/Tasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/Tasks.java b/core/src/main/java/org/apache/brooklyn/util/core/task/Tasks.java
index 66c4068..2db73df 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/Tasks.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/Tasks.java
@@ -253,7 +253,7 @@ public class Tasks {
     public static <T> T tag(@Nullable Task<?> task, Class<T> type, boolean recurseHierarchy) {
         // support null task to make it easier for callers to walk hierarchies
         if (task==null) return null;
-        for (Object tag: task.getTags())
+        for (Object tag: TaskTags.getTagsFast(task))
             if (type.isInstance(tag)) return (T)tag;
         if (!recurseHierarchy) return null;
         return tag(task.getSubmittedByTask(), type, true);


[33/35] brooklyn-server git commit: add adjuncts rest test, and minor fixes

Posted by he...@apache.org.
add adjuncts rest test, and minor fixes


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

Branch: refs/heads/master
Commit: d5d72cb9d98430112b93559a7f51d6c5b3e6a62f
Parents: 28dbb83
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Oct 3 13:18:20 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Oct 3 13:18:20 2017 +0100

----------------------------------------------------------------------
 .../apache/brooklyn/rest/api/AdjunctApi.java    |   2 +-
 .../rest/resources/AdjunctResource.java         |   7 +-
 .../brooklyn/rest/resources/PolicyResource.java |   1 -
 .../rest/resources/AdjunctResourceTest.java     | 198 +++++++++++++++++++
 4 files changed, 202 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d5d72cb9/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java
index da5c1bf..ee43441 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java
@@ -72,7 +72,7 @@ public interface AdjunctApi {
             @ApiResponse(code = 404, message = "Could not find application or entity"),
             @ApiResponse(code = 400, message = "Type is not a suitable adjunct")
     })
-    public AdjunctSummary addAdjunct(
+    public AdjunctDetail addAdjunct(
             @ApiParam(name = "application", value = "Application ID or name", required = true)
             @PathParam("application") String application,
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d5d72cb9/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java
index 6090e6d..1111193 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java
@@ -106,7 +106,7 @@ public class AdjunctResource extends AbstractBrooklynRestResource implements Adj
     // TODO would like to make 'config' arg optional but jersey complains if we do
     @SuppressWarnings({ "rawtypes", "unchecked" })
     @Override
-    public AdjunctSummary addAdjunct(String application, String entityToken, String adjunctTypeName, Map<String, String> config) {
+    public AdjunctDetail addAdjunct(String application, String entityToken, String adjunctTypeName, Map<String, String> config) {
         Entity entity = brooklyn().getEntity(application, entityToken);
         if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.MODIFY_ENTITY, entity)) {
             throw WebResourceUtils.forbidden("User '%s' is not authorized to modify entity '%s'",
@@ -227,7 +227,7 @@ public class AdjunctResource extends AbstractBrooklynRestResource implements Adj
         EntityAdjunct adjunct = brooklyn().getAdjunct(entity, adjunctToken);
 
         List<ConfigSummary> result = Lists.newArrayList();
-        for (ConfigKey<?> key : adjunct.config().findKeysPresent(Predicates.alwaysTrue())) {
+        for (ConfigKey<?> key : adjunct.config().findKeysDeclared(Predicates.alwaysTrue())) {
             result.add(ConfigTransformer.of(key).on(entity, adjunct).includeLinks(ui.getBaseUriBuilder(), false, true).transform());
         }
         return result;
@@ -237,7 +237,6 @@ public class AdjunctResource extends AbstractBrooklynRestResource implements Adj
     // (and in sensors class)
     @Override
     public Map<String, Object> batchConfigRead(String application, String entityToken, String adjunctToken) {
-        // TODO: add test
         return EntityTransformer.getConfigValues(brooklyn(), brooklyn().getAdjunct(application, entityToken, adjunctToken) );
     }
 
@@ -266,7 +265,7 @@ public class AdjunctResource extends AbstractBrooklynRestResource implements Adj
         if (cki.isEmpty()) throw WebResourceUtils.notFound("Cannot find config key '%s' in adjunct '%s' of entity '%s'", configKeyName, adjunctToken, entityToken);
         ConfigKey<?> ck = cki.iterator().next();
         
-        adjunct.config().set((ConfigKey) cki, TypeCoercions.coerce(value, ck.getTypeToken()));
+        adjunct.config().set((ConfigKey) ck, TypeCoercions.coerce(value, ck.getTypeToken()));
 
         return Response.status(Response.Status.OK).build();
     }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d5d72cb9/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java
index 125b0b7..924d3fd 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java
@@ -71,7 +71,6 @@ public class PolicyResource extends AbstractBrooklynRestResource implements Poli
     // (and in sensors class)
     @Override
     public Map<String, Boolean> batchConfigRead( String application, String entityToken) {
-        // TODO: add test
         Entity entity = brooklyn().getEntity(application, entityToken);
         Map<String, Boolean> result = Maps.newLinkedHashMap();
         for (Policy p : entity.policies()) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d5d72cb9/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/AdjunctResourceTest.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/AdjunctResourceTest.java b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/AdjunctResourceTest.java
new file mode 100644
index 0000000..2bd9f2d
--- /dev/null
+++ b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/AdjunctResourceTest.java
@@ -0,0 +1,198 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.rest.resources;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.fail;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.apache.brooklyn.api.objs.HighlightTuple;
+import org.apache.brooklyn.rest.domain.AdjunctDetail;
+import org.apache.brooklyn.rest.domain.AdjunctSummary;
+import org.apache.brooklyn.rest.domain.ApplicationSpec;
+import org.apache.brooklyn.rest.domain.ConfigSummary;
+import org.apache.brooklyn.rest.domain.EntitySpec;
+import org.apache.brooklyn.rest.testing.BrooklynRestResourceTest;
+import org.apache.brooklyn.rest.testing.mocks.RestMockSimpleEntity;
+import org.apache.brooklyn.rest.testing.mocks.RestMockSimplePolicy;
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+
+@Test(singleThreaded = true,
+        // by using a different suite name we disallow interleaving other tests between the methods of this test class, which wrecks the test fixtures
+        suiteName = "AdjunctResourceTest")
+public class AdjunctResourceTest extends BrooklynRestResourceTest {
+
+    private static final Logger log = LoggerFactory.getLogger(AdjunctResourceTest.class);
+
+    private static final String ENDPOINT = "/applications/simple-app/entities/simple-ent/adjuncts/";
+
+    private final ApplicationSpec simpleSpec = ApplicationSpec.builder().name("simple-app").entities(
+            ImmutableSet.of(new EntitySpec("simple-ent", RestMockSimpleEntity.class.getName()))).locations(
+            ImmutableSet.of("localhost")).build();
+
+    private String policyId;
+    
+    @BeforeClass(alwaysRun = true)
+    public void setUp() throws Exception {
+        startServer();
+        Response aResponse = clientDeploy(simpleSpec);
+        waitForApplicationToBeRunning(aResponse.getLocation());
+
+        Response pResponse = client().path(ENDPOINT)
+                .query("type", RestMockSimplePolicy.class.getCanonicalName())
+                .type(MediaType.APPLICATION_JSON_TYPE)
+                .post(toJsonEntity(ImmutableMap.of()));
+
+        AdjunctDetail response = pResponse.readEntity(AdjunctDetail.class);
+        assertNotNull(response.getId());
+        policyId = response.getId();
+
+    }
+
+    @Test
+    public void testListAdjuncts() throws Exception {
+        Set<AdjunctSummary> adjuncts = client().path(ENDPOINT)
+                .get(new GenericType<Set<AdjunctSummary>>() {});
+        
+        AdjunctSummary policy = null;
+        List<AdjunctSummary> others = MutableList.of();
+        for (AdjunctSummary adj : adjuncts) {
+            if (adj.getId().equals(policyId)) {
+                policy = adj;
+            } else {
+                others.add(adj);
+            }
+        }
+        
+        log.info("Non-policy adjuncts: "+others);
+        Asserts.assertSize(others, 4);
+
+        assertEquals(policy.getName(), RestMockSimplePolicy.class.getName());
+    }
+    
+
+    @Test
+    public void testGetDetail() throws Exception {
+        AdjunctDetail policy = client().path(ENDPOINT+policyId)
+                .get(AdjunctDetail.class);
+        
+        assertEquals(policy.getName(), RestMockSimplePolicy.class.getName());
+    }
+
+    @Test
+    public void testListConfig() throws Exception {
+        Set<ConfigSummary> config = client().path(ENDPOINT + policyId + "/config")
+                .get(new GenericType<Set<ConfigSummary>>() {});
+        
+        Set<String> configNames = Sets.newLinkedHashSet();
+        for (ConfigSummary conf : config) {
+            configNames.add(conf.getName());
+        }
+
+        assertEquals(configNames, ImmutableSet.of(
+                RestMockSimplePolicy.SAMPLE_CONFIG.getName(),
+                RestMockSimplePolicy.INTEGER_CONFIG.getName()));
+    }
+
+    @Test
+    public void testGetNonExistentConfigReturns404() throws Exception {
+        String invalidConfigName = "doesnotexist";
+        try {
+            ConfigSummary summary = client().path(ENDPOINT + policyId + "/config/" + invalidConfigName)
+                    .get(ConfigSummary.class);
+            fail("Should have thrown 404, but got "+summary);
+        } catch (Exception e) {
+            if (!e.toString().contains("404")) throw e;
+        }
+    }
+
+    @Test
+    public void testGetDefaultValue() throws Exception {
+        String configName = RestMockSimplePolicy.SAMPLE_CONFIG.getName();
+        String expectedVal = RestMockSimplePolicy.SAMPLE_CONFIG.getDefaultValue();
+        
+        String configVal = client().path(ENDPOINT + policyId + "/config/" + configName)
+                .get(String.class);
+        assertEquals(configVal, expectedVal);
+    }
+    
+    @Test(dependsOnMethods = "testGetDefaultValue")
+    public void testReconfigureConfig() throws Exception {
+        String configName = RestMockSimplePolicy.SAMPLE_CONFIG.getName();
+        
+        Response response = client().path(ENDPOINT + policyId + "/config/" + configName)
+                .post(toJsonEntity("newval"));
+
+        assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
+    }
+    
+    @Test(dependsOnMethods = "testReconfigureConfig")
+    public void testGetConfigValue() throws Exception {
+        String configName = RestMockSimplePolicy.SAMPLE_CONFIG.getName();
+        String expectedVal = "newval";
+        
+        Map<String, Object> allState = client().path(ENDPOINT + policyId + "/config-current")
+                .get(new GenericType<Map<String, Object>>() {});
+        assertEquals(allState, ImmutableMap.of(configName, expectedVal));
+        
+        String configVal = client().path(ENDPOINT + policyId + "/config/" + configName)
+                .get(String.class);
+        assertEquals(configVal, expectedVal);
+    }
+
+    @Test
+    public void testHighlights() throws Exception {
+        Set<AdjunctSummary> policies = client().path(ENDPOINT)
+            .query("adjunctType", "policy")
+            .get(new GenericType<Set<AdjunctSummary>>() {});
+
+        assertEquals(policies.size(), 1);
+        AdjunctSummary policySummary = policies.iterator().next();
+
+        Map<String, HighlightTuple> highlights = policySummary.getHighlights();
+
+        assertEquals(highlights.size(), 2);
+        HighlightTuple highlightTupleTask = highlights.get("testNameTask");
+        assertEquals(highlightTupleTask.getDescription(), "testDescription");
+        assertEquals(highlightTupleTask.getTime(), 123L);
+        assertEquals(highlightTupleTask.getTaskId(), "testTaskId");
+
+        HighlightTuple highlightTupleNoTask = highlights.get("testNameNoTask");
+        assertEquals(highlightTupleNoTask.getDescription(), "testDescription");
+        assertEquals(highlightTupleNoTask.getTime(), 123L);
+        assertEquals(highlightTupleNoTask.getTaskId(), null);
+    }
+}


[10/35] brooklyn-server git commit: tidy BasicExecutionManagement constructors

Posted by he...@apache.org.
tidy BasicExecutionManagement constructors


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

Branch: refs/heads/master
Commit: c1f78bb2ba82504b2f0bfc1aa4831564d1f314b4
Parents: a341cce
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Sep 15 09:21:29 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Sep 15 10:29:09 2017 +0100

----------------------------------------------------------------------
 .../internal/AbstractManagementContext.java     |  5 ++--
 .../util/core/task/BasicExecutionContext.java   | 26 +++++++++++++++-----
 .../brooklyn/util/collections/MutableSet.java   | 14 ++++++++++-
 3 files changed, 35 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/c1f78bb2/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java
index 322d60e..52eed44 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java
@@ -72,7 +72,6 @@ import org.apache.brooklyn.core.mgmt.ha.HighAvailabilityManagerImpl;
 import org.apache.brooklyn.core.mgmt.rebind.RebindManagerImpl;
 import org.apache.brooklyn.core.typereg.BasicBrooklynTypeRegistry;
 import org.apache.brooklyn.util.collections.MutableList;
-import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.task.BasicExecutionContext;
@@ -237,7 +236,7 @@ public abstract class AbstractManagementContext implements ManagementContextInte
                     BrooklynTaskTags.tagForContextEntity(e),
                     this
             );
-            return new BasicExecutionContext(MutableMap.of("tags", tags), getExecutionManager());
+            return new BasicExecutionContext(getExecutionManager(), tags);
         } else {
             return ((EntityInternal)e).getExecutionContext();
         }
@@ -250,7 +249,7 @@ public abstract class AbstractManagementContext implements ManagementContextInte
                 this,
                 BrooklynTaskTags.BROOKLYN_SERVER_TASK_TAG
         );
-        return new BasicExecutionContext(MutableMap.of("tags", tags), getExecutionManager());
+        return new BasicExecutionContext(getExecutionManager(), tags);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/c1f78bb2/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
index 547ae24..73baef2 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionContext.java
@@ -21,7 +21,6 @@ package org.apache.brooklyn.util.core.task;
 import java.lang.reflect.Proxy;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Set;
@@ -45,6 +44,7 @@ import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags.WrappedEntity;
 import org.apache.brooklyn.core.mgmt.entitlement.Entitlements;
 import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.core.task.ImmediateSupplier.ImmediateUnsupportedException;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.guava.Maybe;
@@ -73,23 +73,37 @@ public class BasicExecutionContext extends AbstractExecutionContext {
     final Set<Object> tags = new LinkedHashSet<Object>();
 
     public BasicExecutionContext(ExecutionManager executionManager) {
-        this(Collections.emptyMap(), executionManager);
+        this(executionManager, null);
     }
     
     /**
+     * As {@link #BasicExecutionContext(ExecutionManager, Iterable)} but taking a flags map.
      * Supported flags are {@code tag} and {@code tags}
      * 
      * @see ExecutionManager#submit(Map, TaskAdaptable)
+     * @deprecated since 0.12.0 use {@link #BasicExecutionContext(ExecutionManager, Iterable)}
      */
+    @Deprecated
     public BasicExecutionContext(Map<?, ?> flags, ExecutionManager executionManager) {
+        this(executionManager, MutableSet.of().put(flags.remove("tag")).putAll((Iterable<?>)flags.remove("tag")));
+        if (!flags.isEmpty()) {
+            log.warn("Unexpected flags passed to execution context ("+tags+"): "+flags,
+                new Throwable("Trace for unexpected flags passed to execution context"));
+        }
+    }
+    
+    /**
+     * Creates an execution context which wraps {@link ExecutionManager}
+     * adding the given tags to all tasks submitted through this context.
+     */
+    public BasicExecutionContext(ExecutionManager executionManager, Iterable<Object> tagsForThisContext) {
         this.executionManager = executionManager;
+        if (tagsForThisContext!=null) Iterables.addAll(tags, tagsForThisContext);
 
-        if (flags.get("tag") != null) tags.add(flags.remove("tag"));
-        if (flags.containsKey("tags")) tags.addAll((Collection<?>)flags.remove("tags"));
-
-        // FIXME brooklyn-specific check, just for sanity
+        // brooklyn-specific check, just for sanity
         // the context tag should always be a non-proxy entity, because that is what is passed to effector tasks
         // which may require access to internal methods
+        // (could remove this check if generalizing; it has been here for a long time and the problem seems gone)
         for (Object tag: tags) {
             if (tag instanceof BrooklynTaskTags.WrappedEntity) {
                 if (Proxy.isProxyClass(((WrappedEntity)tag).entity.getClass())) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/c1f78bb2/utils/common/src/main/java/org/apache/brooklyn/util/collections/MutableSet.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/collections/MutableSet.java b/utils/common/src/main/java/org/apache/brooklyn/util/collections/MutableSet.java
index bcadf33..1049304 100644
--- a/utils/common/src/main/java/org/apache/brooklyn/util/collections/MutableSet.java
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/collections/MutableSet.java
@@ -213,7 +213,19 @@ public class MutableSet<V> extends LinkedHashSet<V> {
         if (setToAdd!=null) addAll(setToAdd);
         return this;
     }
-    
+
+    /** as {@link #add(V)} but fluent style */
+    public MutableSet<V> put(V e) {
+        add(e);
+        return this;
+    }
+
+    /** as {@link #addIfNotNull(V)} but fluent style */
+    public MutableSet<V> putIfNotNull(V e) {
+        if (e!=null) add(e);
+        return this;
+    }
+
     public boolean removeIfNotNull(V item) {
         if (item==null) return false;
         return remove(item);


[28/35] brooklyn-server git commit: fix null ref in task submitted-by field

Posted by he...@apache.org.
fix null ref in task submitted-by field


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

Branch: refs/heads/master
Commit: 447283bdab4b8a2be5c7ff67d07b346d00f8d4c2
Parents: afc17ee
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Oct 2 15:56:54 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Mon Oct 2 15:56:54 2017 +0100

----------------------------------------------------------------------
 .../main/java/org/apache/brooklyn/util/core/task/BasicTask.java | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/447283bd/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
index 4f448ec..4913ab3 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
@@ -56,6 +56,7 @@ import org.slf4j.LoggerFactory;
 import com.google.common.annotations.Beta;
 import com.google.common.base.Function;
 import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
 import com.google.common.base.Throwables;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
@@ -910,11 +911,11 @@ public class BasicTask<T> implements TaskInternal<T> {
     
     @Override
     public void setSubmittedByTask(Task<?> task) {
-        setSubmittedByTask(Maybe.of(task), task==null ? null : task.getId());
+        setSubmittedByTask(Maybe.ofDisallowingNull(task), task==null ? null : task.getId());
     }
     @Override
     public void setSubmittedByTask(Maybe<Task<?>> taskM, String taskId) {
-        submittedByTask = taskM;
+        submittedByTask = Preconditions.checkNotNull(taskM);
         submittedByTaskId = taskId;
     }
     


[16/35] brooklyn-server git commit: improve task cancellation code

Posted by he...@apache.org.
improve task cancellation code

consistently notify listeners and update maps and counts, and remove deprecated internal listeners class;
add logging and speed increase to related tests (and Asserts.eventually can wait on on object to speed things up!)


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

Branch: refs/heads/master
Commit: 7c2c8e1aa9a7a2c0be9476c93bd5f8c46c77e1ae
Parents: 5e19dec
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Sep 15 18:30:11 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Sat Sep 16 02:42:05 2017 +0100

----------------------------------------------------------------------
 .../util/core/task/BasicExecutionManager.java   | 83 ++++++++++++++------
 .../brooklyn/util/core/task/BasicTask.java      |  6 +-
 .../core/task/ListenableForwardingFuture.java   | 75 ------------------
 .../core/task/DynamicSequentialTaskTest.java    | 17 ++--
 .../java/org/apache/brooklyn/test/Asserts.java  | 27 ++++++-
 .../apache/brooklyn/util/repeat/Repeater.java   | 22 +++++-
 6 files changed, 115 insertions(+), 115 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/7c2c8e1a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
index bed08e7..4fcfadb 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
@@ -34,6 +34,7 @@ import java.util.concurrent.CancellationException;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
 import java.util.concurrent.ScheduledExecutorService;
@@ -77,6 +78,7 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Sets;
 import com.google.common.util.concurrent.Callables;
 import com.google.common.util.concurrent.ExecutionList;
+import com.google.common.util.concurrent.ForwardingFuture.SimpleForwardingFuture;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.ThreadFactoryBuilder;
 
@@ -110,10 +112,11 @@ public class BasicExecutionManager implements ExecutionManager {
     private final ExecutorService runner;
         
     private final ScheduledExecutorService delayedRunner;
-    
-    // TODO Could have a set of all knownTasks; but instead we're having a separate set per tag,
-    // so the same task could be listed multiple times if it has multiple tags...
 
+    // inefficient having so many records, and also doing searches through ...
+    // many things in here could be more efficient however (different types of lookup etc),
+    // do that when we need to.
+    
     //access to this field AND to members in this field is synchronized, 
     //to allow us to preserve order while guaranteeing thread-safe
     //(but more testing is needed before we are completely sure it is thread-safe!)
@@ -553,9 +556,11 @@ public class BasicExecutionManager implements ExecutionManager {
             Throwable error = null;
             try {
                 beforeStartAtomicTask(flags, task);
-                if (!task.isCancelled()) {
-                    result = ((TaskInternal<T>)task).getJob().call();
-                } else throw new CancellationException();
+                if (task.isCancelled()) {
+                    afterEndForCancelBeforeStart(flags, task, false);
+                    throw new CancellationException();
+                }
+                result = ((TaskInternal<T>)task).getJob().call();
             } catch(Throwable e) {
                 error = e;
             } finally {
@@ -570,21 +575,33 @@ public class BasicExecutionManager implements ExecutionManager {
         }
     }
 
-    @SuppressWarnings("deprecation")
-    // TODO do we even need a listenable future here?  possibly if someone wants to interrogate the future it might
-    // be interesting, so possibly it is useful that we implement ListenableFuture...
-    private final static class CancellingListenableForwardingFutureForTask<T> extends ListenableForwardingFuture<T> {
+    final static class CancellingListenableForwardingFutureForTask<T> extends SimpleForwardingFuture<T> implements ListenableFuture<T> {
         private final Task<T> task;
         private BasicExecutionManager execMgmt;
-
+        private final ExecutionList listeners;
+        
         private CancellingListenableForwardingFutureForTask(BasicExecutionManager execMgmt, Future<T> delegate, ExecutionList list, Task<T> task) {
-            super(delegate, list);
+            super(delegate);
+            this.listeners = list;
             this.execMgmt = execMgmt;
             this.task = task;
         }
 
         @Override
-        public boolean cancel(TaskCancellationMode mode) {
+        public final boolean cancel(boolean mayInterrupt) {
+            return cancel(TaskCancellationMode.INTERRUPT_TASK_AND_DEPENDENT_SUBMITTED_TASKS);
+        }
+
+        @Override
+        public void addListener(Runnable listener, Executor executor) {
+            listeners.add(listener, executor);
+        }
+
+        public ExecutionList getListeners() {
+            return listeners;
+        }
+        
+        boolean cancel(TaskCancellationMode mode) {
             boolean result = false;
             if (log.isTraceEnabled()) {
                 log.trace("CLFFT cancelling "+task+" mode "+mode);
@@ -616,7 +633,6 @@ public class BasicExecutionManager implements ExecutionManager {
                         }
                     }
                 }
-                // TODO this is inefficient; might want to keep an index on submitted-by
                 for (Task<?> t: execMgmt.getAllTasks()) {
                     if (task.equals(t.getSubmittedByTask())) {
                         if (mode.isAllowedToInterruptAllSubmittedTasks() || BrooklynTaskTags.isTransient(t)) {
@@ -636,7 +652,7 @@ public class BasicExecutionManager implements ExecutionManager {
                 }
             }
   
-            // note: as of 2017-09 no longer run listeners when we say to cancel, they get run when the task really ends
+            execMgmt.afterEndForCancelBeforeStart(null, task, true);
             return result;
         }
     }
@@ -644,14 +660,15 @@ public class BasicExecutionManager implements ExecutionManager {
     // NB: intended to be run by task.runListeners, used to run any listeners the manager wants 
     private final class SubmissionListenerToCallManagerListeners<T> implements Runnable {
         private final Task<T> task;
+        private final CancellingListenableForwardingFutureForTask<T> listenerSource;
 
-        private SubmissionListenerToCallManagerListeners(Task<T> task) {
+        public SubmissionListenerToCallManagerListeners(Task<T> task, CancellingListenableForwardingFutureForTask<T> listenableFuture) {
             this.task = task;
+            listenerSource = listenableFuture;
         }
 
         @Override
         public void run() {
-            
             for (ExecutionListener listener : listeners) {
                 try {
                     listener.onTaskDone(task);
@@ -659,6 +676,8 @@ public class BasicExecutionManager implements ExecutionManager {
                     log.warn("Error running execution listener "+listener+" of task "+task+" done", e);
                 }
             }
+            // run any listeners the task owner has added to its future
+            listenerSource.getListeners().execute();
         }
     }
 
@@ -710,9 +729,9 @@ public class BasicExecutionManager implements ExecutionManager {
         // this future allows a caller to add custom listeners
         // (it does not notify the listeners; that's our job);
         // except on cancel we want to listen
-        ListenableFuture<T> listenableFuture = new CancellingListenableForwardingFutureForTask<T>(this, future, ((TaskInternal<T>)task).getListeners(), task);
+        CancellingListenableForwardingFutureForTask<T> listenableFuture = new CancellingListenableForwardingFutureForTask<T>(this, future, ((TaskInternal<T>)task).getListeners(), task);
         // and we want to make sure *our* (manager) listeners are given suitable callback 
-        ((TaskInternal<T>)task).addListener(new SubmissionListenerToCallManagerListeners<T>(task), runner);
+        ((TaskInternal<T>)task).addListener(new SubmissionListenerToCallManagerListeners<T>(task, listenableFuture), runner);
         // NB: can the above mean multiple callbacks to TaskInternal#runListeners?
         
         // finally expose the future to callers
@@ -875,18 +894,37 @@ public class BasicExecutionManager implements ExecutionManager {
     protected void afterEndInSameThreadTask(Map<?,?> flags, Task<?> task, Throwable error) {
         internalAfterEnd(flags, task, true, true, error);
     }
+    protected void afterEndForCancelBeforeStart(Map<?,?> flags, Task<?> task, boolean calledFromCanceller) {
+        if (calledFromCanceller) {
+            if (task.isBegun()) {
+                // do nothing from canceller thread if task has begin;
+                // we don't want to set end time or listeners prematurely.
+                return ;
+            } else {
+                // normally task won't be submitted by executor, so do some of the end operations.
+                // there is a chance task has begun but not set start time,
+                // in which case _both_ canceller thread and task thread will run this,
+                // but they will happen very close in time so end time is set sensibly by either,
+                // and dedupe will be done based on presence in "incompleteTaskIds"
+                // to ensure listeners and callback only invoked once
+            }
+        }
+        internalAfterEnd(flags, task, !calledFromCanceller, true, null);
+    }
+    
     /** normally (if not interrupted) called once for each call to {@link #internalBeforeSubmit(Map, Task)},
      * and, for atomic tasks and scheduled-task submission iterations where 
      * always called once if {@link #internalBeforeStart(Map, Task)} is invoked and in the same thread as that method */
     protected void internalAfterEnd(Map<?,?> flags, Task<?> task, boolean startedInThisThread, boolean isEndingAllIterations, Throwable error) {
+        boolean taskWasSubmittedAndNotYetEnded = true;
         try {
             if (log.isTraceEnabled()) log.trace(this+" afterEnd, task: "+task);
             if (startedInThisThread) {
                 activeTaskCount.decrementAndGet();
             }
             if (isEndingAllIterations) {
-                incompleteTaskIds.remove(task.getId());
-                if (flags!=null) {
+                taskWasSubmittedAndNotYetEnded = incompleteTaskIds.remove(task.getId());
+                if (flags!=null && taskWasSubmittedAndNotYetEnded) {
                     invokeCallback(flags.get("newTaskEndCallback"), task);
                 }
                 ((TaskInternal<?>)task).setEndTimeUtc(System.currentTimeMillis());
@@ -934,7 +972,8 @@ public class BasicExecutionManager implements ExecutionManager {
                 }
             } finally {
                 synchronized (task) { task.notifyAll(); }
-                if (isEndingAllIterations) {
+                if (isEndingAllIterations && taskWasSubmittedAndNotYetEnded) {
+                    // prevent from running twice on cancellation after start
                     ((TaskInternal<?>)task).runListeners();
                 }
             }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/7c2c8e1a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
index 3c9b163..d952f9e 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicTask.java
@@ -45,6 +45,7 @@ import org.apache.brooklyn.api.mgmt.HasTaskChildren;
 import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.api.objs.Identifiable;
 import org.apache.brooklyn.util.JavaGroovyEquivalents;
+import org.apache.brooklyn.util.core.task.BasicExecutionManager.CancellingListenableForwardingFutureForTask;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.guava.Maybe.MaybeSupplier;
@@ -327,11 +328,10 @@ public class BasicTask<T> implements TaskInternal<T> {
         return true;
     }
     
-    @SuppressWarnings("deprecation")
     protected boolean doCancel(TaskCancellationMode mode) {
         if (internalFuture!=null) { 
-            if (internalFuture instanceof ListenableForwardingFuture) {
-                return ((ListenableForwardingFuture<?>)internalFuture).cancel(mode);
+            if (internalFuture instanceof CancellingListenableForwardingFutureForTask) {
+                return ((CancellingListenableForwardingFutureForTask<?>)internalFuture).cancel(mode);
             } else {
                 return internalFuture.cancel(mode.isAllowedToInterruptTask());
             }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/7c2c8e1a/core/src/main/java/org/apache/brooklyn/util/core/task/ListenableForwardingFuture.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/ListenableForwardingFuture.java b/core/src/main/java/org/apache/brooklyn/util/core/task/ListenableForwardingFuture.java
deleted file mode 100644
index ac42d2f..0000000
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/ListenableForwardingFuture.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.brooklyn.util.core.task;
-
-import java.util.concurrent.Executor;
-import java.util.concurrent.Future;
-
-import org.apache.brooklyn.util.core.task.TaskInternal.TaskCancellationMode;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.util.concurrent.ExecutionList;
-import com.google.common.util.concurrent.ForwardingFuture.SimpleForwardingFuture;
-import com.google.common.util.concurrent.ListenableFuture;
-
-/** Wraps a Future, making it a ListenableForwardingFuture, but with the caller having the responsibility to:
- * <li> invoke the listeners on job completion (success or error)
- * <li> invoke the listeners on cancel
- * 
- * @deprecated since 0.9.0 likely to leave the public API */
-@Deprecated  // TODO just one subclass, it can hold the behaviour we need from this, 
-// and the methods here are surprising as they expect the caller to notify the list
-public abstract class ListenableForwardingFuture<T> extends SimpleForwardingFuture<T> implements ListenableFuture<T> {
-
-    private static final Logger log = LoggerFactory.getLogger(ListenableForwardingFuture.class);
-    
-    // TODO these are never accessed or used
-    final ExecutionList listeners;
-    
-    protected ListenableForwardingFuture(Future<T> delegate) {
-        super(delegate);
-        this.listeners = new ExecutionList();
-    }
-
-    protected ListenableForwardingFuture(Future<T> delegate, ExecutionList list) {
-        super(delegate);
-        this.listeners = list;
-    }
-
-    private static boolean warned = false;
-    
-    @Override
-    public void addListener(Runnable listener, Executor executor) {
-        if (!warned) {
-            log.warn("Use of deprecated ListenableForwardingFuture.addListener at "+this+" (future calls will not be logged)", new Throwable("stack trace"));
-            warned = true;
-        }
-        
-        listeners.add(listener, executor);
-    }
-    
-    public abstract boolean cancel(TaskCancellationMode mode);
-    
-    @Override
-    public final boolean cancel(boolean mayInterrupt) {
-        return cancel(TaskCancellationMode.INTERRUPT_TASK_AND_DEPENDENT_SUBMITTED_TASKS);
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/7c2c8e1a/core/src/test/java/org/apache/brooklyn/util/core/task/DynamicSequentialTaskTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/util/core/task/DynamicSequentialTaskTest.java b/core/src/test/java/org/apache/brooklyn/util/core/task/DynamicSequentialTaskTest.java
index e218cc7..f0bcdf7 100644
--- a/core/src/test/java/org/apache/brooklyn/util/core/task/DynamicSequentialTaskTest.java
+++ b/core/src/test/java/org/apache/brooklyn/util/core/task/DynamicSequentialTaskTest.java
@@ -50,7 +50,6 @@ import org.testng.annotations.Test;
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
 import com.google.common.base.Stopwatch;
-import com.google.common.base.Supplier;
 import com.google.common.base.Suppliers;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
@@ -87,6 +86,7 @@ public class DynamicSequentialTaskTest {
     @AfterMethod(alwaysRun=true)
     public void tearDown() throws Exception {
         if (em != null) {
+            log.debug("tearing down");
             // need to await termination, otherwise interrupted-but-still-running threads 
             // may update the cancellations/messages and interfere with subsequent tests
             Assert.assertTrue(em.shutdownNow(Duration.FIVE_SECONDS));
@@ -250,7 +250,7 @@ public class DynamicSequentialTaskTest {
     
     @Test
     public void testCancellationModeAndSubmitted() throws Exception {
-        // seems actually to be the logging which causes this to take ~50ms ?
+        // used to spend time waiting for end time to be set; now listens for notify which makes it go faster
         
         doTestCancellationModeAndSubmitted(true, TaskCancellationMode.DO_NOT_INTERRUPT, false, false);
         
@@ -304,24 +304,21 @@ public class DynamicSequentialTaskTest {
             throw new IllegalStateException("Invalid cancellationMode: "+cancellationMode);
         }
 
-        // the cancelled task always reports cancelled and done
+        // the cancelled task always reports cancelled and done right away
         Assert.assertEquals(t.isDone(), true);
         Assert.assertEquals(t.isCancelled(), true);
-        // end time might not be set for another fraction of a second
         if (expectedTaskInterrupted) { 
-            Asserts.eventually(new Supplier<Number>() {
-                @Override public Number get() { return t.getEndTimeUtc(); }}, 
-                MathPredicates.<Number>greaterThanOrEqual(0));
+            // end time might not be set for another fraction of a second, when task truly ended, but should be set soon if task was interrupted
+            Asserts.eventually( () -> t.getEndTimeUtc(), MathPredicates.greaterThanOrEqual(0), null, null, null, t );
         } else {
+            // if interrupts not allowed, time should not be set until long delay expires
             Assert.assertTrue(t.getEndTimeUtc() < 0, "Wrong end time: "+t.getEndTimeUtc());
         }
         
         if (expectedSubtaskCancelled) {
             Asserts.eventually(Suppliers.ofInstance(t1), TaskPredicates.isDone());
             Assert.assertTrue(t1.isCancelled());
-            Asserts.eventually(new Supplier<Number>() {
-                @Override public Number get() { return t1.getEndTimeUtc(); }}, 
-                MathPredicates.<Number>greaterThanOrEqual(0));
+            Asserts.eventually( () -> t1.getEndTimeUtc(), MathPredicates.greaterThanOrEqual(0), null, null, null, t );
         } else {
             Time.sleep(TINY_TIME);
             Assert.assertFalse(t1.isCancelled());

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/7c2c8e1a/utils/common/src/main/java/org/apache/brooklyn/test/Asserts.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/org/apache/brooklyn/test/Asserts.java b/utils/common/src/main/java/org/apache/brooklyn/test/Asserts.java
index 0a105d9..dc672b5 100644
--- a/utils/common/src/main/java/org/apache/brooklyn/test/Asserts.java
+++ b/utils/common/src/main/java/org/apache/brooklyn/test/Asserts.java
@@ -805,7 +805,11 @@ public class Asserts {
     public static <T> void eventually(Supplier<? extends T> supplier, Predicate<T> predicate, Duration timeout) {
         eventually(supplier, predicate, timeout, null, null);
     }
-    
+
+    /** As {@link #eventually(Supplier, Predicate, Duration, Duration, String)} when no object is going to be notified. */
+    public static <T> void eventually(Supplier<? extends T> supplier, Predicate<T> predicate, Duration timeout, Duration period, String errMsg) {
+        eventually(supplier, predicate, timeout, period, errMsg, null);
+    }
     /** Asserts that eventually the supplier gives a value accepted by the predicate. 
      * Tests periodically and succeeds as soon as the supplier gives an allowed value.
      * Other arguments can be null.
@@ -814,9 +818,12 @@ public class Asserts {
      * @param predicate the {@link Predicate} to apply to each value given by the supplier
      * @param timeout how long to wait, default {@link #DEFAULT_LONG_TIMEOUT}
      * @param period how often to check, default quite often so you won't notice but letting the CPU do work
-     * @param errMsg an error message to display if not satisfied, in addition to the last-tested supplied value and the predicate
+     * @param errMsg optional error message to display if not satisfied, in addition to the last-tested supplied value and the predicate
+     * @param notifyObject optional object that will be notified of change and should pre-empt the period to redo the check
      */
-    public static <T> void eventually(Supplier<? extends T> supplier, Predicate<T> predicate, Duration timeout, Duration period, String errMsg) {
+    public static <T> void eventually(Supplier<? extends T> supplier, Predicate<T> predicate, Duration timeout, Duration period, String errMsg, Object notifyObject) {
+        // TODO use Repeater (there are too many args here)
+        
         if (timeout==null) timeout = DEFAULT_LONG_TIMEOUT;
         if (period==null) period = DEFAULT_SHORT_PERIOD;
         CountdownTimer timeleft = timeout.countdownTimer();
@@ -824,7 +831,19 @@ public class Asserts {
         T supplied;
         int count = 0;
         do {
-            if (count++ > 0) Duration.sleep(period);
+            if (count++ > 0) {
+                if (notifyObject!=null) {
+                    synchronized (notifyObject) {
+                        try {
+                            notifyObject.wait(period.toMilliseconds());
+                        } catch (InterruptedException e) {
+                            throw Exceptions.propagate(e);
+                        }
+                    }
+                } else {
+                    Duration.sleep(period);
+                }
+            }
             supplied = supplier.get();
             if (predicate.apply(supplied)) return;
         } while (timeleft.isNotExpired());

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/7c2c8e1a/utils/common/src/main/java/org/apache/brooklyn/util/repeat/Repeater.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/repeat/Repeater.java b/utils/common/src/main/java/org/apache/brooklyn/util/repeat/Repeater.java
index a04f58c..4c59c8d 100644
--- a/utils/common/src/main/java/org/apache/brooklyn/util/repeat/Repeater.java
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/repeat/Repeater.java
@@ -42,6 +42,7 @@ import com.google.common.base.Preconditions;
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
 import com.google.common.base.Stopwatch;
+import com.google.common.base.Supplier;
 import com.google.common.util.concurrent.Callables;
 import com.google.common.util.concurrent.MoreExecutors;
 
@@ -246,6 +247,10 @@ public class Repeater implements Callable<Boolean> {
         return backoff(Duration.millis(10), 1.2, finalDelay);
     }
 
+    // TODO support waitingOn to allow notify to interrupt the waits;
+    // however TBC whether such a wake increases iteration count and backoff timer;
+    // probably not as there could be any number of spurious wakes to increment that unexpectedly
+    
     /**
      * Set code fragment that tests if the loop has completed.
      *
@@ -269,6 +274,21 @@ public class Repeater implements Callable<Boolean> {
         });
     }
 
+    public <T> Repeater until(final Supplier<T> supplier, final Predicate<T> exitCondition) {
+        Preconditions.checkNotNull(supplier, "supplier must not be null");
+        Preconditions.checkNotNull(exitCondition, "exitCondition must not be null");
+        return until(new Callable<Boolean>() {
+            @Override
+            public Boolean call() throws Exception {
+                return exitCondition.apply(supplier.get());
+            }
+            @Override
+            public String toString() {
+                return supplier.get()+" "+exitCondition.toString();
+            }
+        });
+    }
+
     /**
      * If the exit condition check throws an exception, it will be recorded and the last exception will be thrown on failure.
      *
@@ -350,7 +370,7 @@ public class Repeater implements Callable<Boolean> {
         ReferenceWithError<Boolean> result = runKeepingError();
         result.checkNoError();
         if (!result.get()) {
-            throw new IllegalStateException(description+" unsatisfied after "+Duration.of(timer));
+            throw new IllegalStateException(description+" unsatisfied after "+Duration.of(timer)+": "+exitCondition);
         }
     }
 


[17/35] brooklyn-server git commit: Merge branch 'master' into tasks-better

Posted by he...@apache.org.
Merge branch 'master' into tasks-better

conflict in adjacent line changes in Poller, fixed


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

Branch: refs/heads/master
Commit: 62359c60e54feebe0c38146d8eb6bfb055d8962a
Parents: 7c2c8e1 c9f7b0d
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Sat Sep 16 02:54:25 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Sat Sep 16 02:54:25 2017 +0100

----------------------------------------------------------------------
 .../brooklyn/api/objs/HighlightTuple.java       |  23 +++-
 .../test/resources/visitors-creation-script.sql |   5 +-
 .../core/enricher/AbstractEnricher.java         |  19 ++-
 .../brooklyn/core/entity/AbstractEntity.java    |   6 +-
 .../apache/brooklyn/core/entity/Attributes.java |  10 +-
 .../core/entity/BrooklynConfigKeys.java         | 124 ++++++++++++++-----
 .../entity/lifecycle/ServiceStateLogic.java     |   3 +
 .../apache/brooklyn/core/feed/AbstractFeed.java |  16 ++-
 .../core/feed/AttributePollHandler.java         |   2 +
 .../org/apache/brooklyn/core/feed/Poller.java   |  20 ++-
 .../core/objs/AbstractEntityAdjunct.java        | 103 ++++++++++++++-
 .../enricher/stock/AbstractAggregator.java      |  49 ++++++--
 .../stock/AbstractMultipleSensorAggregator.java |   2 -
 .../enricher/stock/AbstractTransformer.java     |  21 +++-
 .../stock/AbstractTypeTransformingEnricher.java |   3 +
 .../brooklyn/enricher/stock/Aggregator.java     |  20 ++-
 .../brooklyn/enricher/stock/Combiner.java       |  35 ++++--
 .../apache/brooklyn/enricher/stock/Joiner.java  |  18 ++-
 .../brooklyn/enricher/stock/MapAggregator.java  |  11 +-
 .../enricher/stock/PercentageEnricher.java      |   7 +-
 .../brooklyn/enricher/stock/Propagator.java     |   6 +
 .../brooklyn/enricher/stock/Transformer.java    |  23 +++-
 .../brooklyn/enricher/stock/UpdatingMap.java    |  25 +++-
 .../YamlRollingTimeWindowMeanEnricher.java      |  13 +-
 .../stock/YamlTimeWeightedDeltaEnricher.java    |   7 +-
 .../enricher/stock/reducer/Reducer.java         |  27 ++--
 .../brooklyn/entity/group/AbstractGroup.java    |  13 +-
 .../group/AbstractMembershipTrackingPolicy.java |  23 +++-
 .../apache/brooklyn/entity/group/Cluster.java   |   2 +
 .../brooklyn/entity/group/DynamicCluster.java   |  21 +++-
 .../brooklyn/entity/group/DynamicFabric.java    |  23 +++-
 .../brooklyn/entity/group/DynamicGroup.java     |   6 +-
 .../SshCommandMembershipTrackingPolicy.java     |  15 ++-
 .../brooklyn/entity/stock/BasicStartable.java   |   6 +-
 .../brooklyn/entity/stock/DelegateEntity.java   |   7 +-
 core/src/main/resources/catalog.bom             |  55 +++++++-
 .../core/policy/basic/BasicPolicyTest.java      |   9 +-
 .../stock/TransformingEnricherTest.java         |   7 +-
 .../init/src/main/resources/catalog-classes.bom | 105 ++++++++++++++--
 .../test/resources/visitors-creation-script.sql |   5 +-
 .../policy/autoscaling/AutoScalerPolicy.java    |  83 ++++++++++---
 .../policy/ha/ConnectionFailureDetector.java    |  14 ++-
 .../policy/ha/ServiceFailureDetector.java       |  16 ++-
 .../brooklyn/policy/ha/ServiceReplacer.java     |  66 ++++++----
 .../brooklyn/policy/ha/ServiceRestarter.java    |  25 +++-
 .../policy/ha/SshMachineFailureDetector.java    |   4 +-
 policy/src/main/resources/catalog.bom           |  77 +++++++-----
 .../autoscaling/AutoScalerPolicyRebindTest.java |   5 +-
 .../resources/EntityConfigResourceTest.java     |   2 +-
 .../testing/mocks/RestMockSimplePolicy.java     |   4 +-
 .../apache/brooklyn/entity/java/UsesJava.java   |  10 +-
 .../apache/brooklyn/entity/java/UsesJmx.java    |  37 ++++--
 .../entity/machine/pool/ServerPoolImpl.java     |   1 +
 .../software/base/AbstractVanillaProcess.java   |  21 +++-
 .../entity/software/base/SoftwareProcess.java   |  37 +++---
 .../software/base/SoftwareProcessImpl.java      |   4 +-
 .../software/base/VanillaSoftwareProcess.java   |   3 -
 .../base/VanillaSoftwareProcessSshDriver.java   |  12 +-
 .../software/base/VanillaWindowsProcess.java    |  22 ++--
 software/base/src/main/resources/catalog.bom    |  15 ++-
 .../brooklynnode/SelectMasterEffectorTest.java  |   2 +-
 test-framework/src/main/resources/catalog.bom   |  10 ++
 62 files changed, 1050 insertions(+), 315 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/62359c60/core/src/main/java/org/apache/brooklyn/core/feed/Poller.java
----------------------------------------------------------------------
diff --cc core/src/main/java/org/apache/brooklyn/core/feed/Poller.java
index 03fd1df,5a78f37..940057e
--- a/core/src/main/java/org/apache/brooklyn/core/feed/Poller.java
+++ b/core/src/main/java/org/apache/brooklyn/core/feed/Poller.java
@@@ -143,26 -146,32 +146,29 @@@ public class Poller<V> 
          for (final PollJob<V> pollJob : pollJobs) {
              final String scheduleName = pollJob.handler.getDescription();
              if (pollJob.pollPeriod.compareTo(Duration.ZERO) > 0) {
 -                Callable<Task<?>> pollingTaskFactory = new Callable<Task<?>>() {
 -                    @Override
 -                    public Task<?> call() {
 -                        DynamicSequentialTask<Void> task = new DynamicSequentialTask<Void>(MutableMap.of("displayName", scheduleName, "entity", entity), 
 -                            new Callable<Void>() { @Override public Void call() {
 -                                if (!Entities.isManaged(entity)) {
 -                                    return null;
 -                                }
 -                                if (onlyIfServiceUp && !Boolean.TRUE.equals(entity.getAttribute(Attributes.SERVICE_UP))) {
 -                                    return null;
 -                                }
 -                                pollJob.wrappedJob.run();
 -                                return null; 
 -                            } } );
 -                        BrooklynTaskTags.setTransient(task);
 -                        return task;
 -                    }
 -                };
 -                Map<String, ?> taskFlags = MutableMap.of("displayName", "scheduled:" + scheduleName);
 -                ScheduledTask task = new ScheduledTask(taskFlags, pollingTaskFactory)
 +                ScheduledTask t = ScheduledTask.builder(() -> {
 +                            DynamicSequentialTask<Void> task = new DynamicSequentialTask<Void>(MutableMap.of("displayName", scheduleName, "entity", entity), 
 +                                new Callable<Void>() { @Override public Void call() {
 +                                    if (!Entities.isManaged(entity)) {
 +                                        return null;
 +                                    }
 +                                    if (onlyIfServiceUp && !Boolean.TRUE.equals(entity.getAttribute(Attributes.SERVICE_UP))) {
 +                                        return null;
 +                                    }
 +                                    pollJob.wrappedJob.run();
 +                                    return null; 
 +                                } } );
 +                            BrooklynTaskTags.setTransient(task);
 +                            return task;
 +                        })
 +                        .displayName("scheduled:" + scheduleName)
                          .period(pollJob.pollPeriod)
 -                        .cancelOnException(false);
 -                tasks.add(Entities.submit(entity, task));
 +                        .cancelOnException(false)
 +                        .build();
 +                tasks.add(Entities.submit(entity, t));
+                 if (minPeriod==null || (pollJob.pollPeriod.isShorterThan(minPeriod))) {
+                     minPeriod = pollJob.pollPeriod;
+                 }
              } else {
                  if (log.isDebugEnabled()) log.debug("Activating poll (but leaving off, as period {}) for {} (using {})", new Object[] {pollJob.pollPeriod, entity, this});
              }


[14/35] brooklyn-server git commit: remove interim TODO comments about checking that things work

Posted by he...@apache.org.
remove interim TODO comments about checking that things work


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

Branch: refs/heads/master
Commit: a341cceddb303d0076b9632b3fa64e3a7ffaa4f9
Parents: 18a908b
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Sep 12 17:36:28 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Sep 15 10:29:09 2017 +0100

----------------------------------------------------------------------
 .../brooklyn/util/core/task/BasicExecutionManager.java  | 12 ++----------
 1 file changed, 2 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/a341cced/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
index 0f666ba..bed08e7 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/BasicExecutionManager.java
@@ -636,13 +636,12 @@ public class BasicExecutionManager implements ExecutionManager {
                 }
             }
   
-            // no longer run listeners when we say to cancel, they get run when the task really ends
-            // TODO confirm no problems (added 2017-09)
-//            ((TaskInternal<?>)task).runListeners();
+            // note: as of 2017-09 no longer run listeners when we say to cancel, they get run when the task really ends
             return result;
         }
     }
 
+    // NB: intended to be run by task.runListeners, used to run any listeners the manager wants 
     private final class SubmissionListenerToCallManagerListeners<T> implements Runnable {
         private final Task<T> task;
 
@@ -652,13 +651,6 @@ public class BasicExecutionManager implements ExecutionManager {
 
         @Override
         public void run() {
-            // TODO remove after confirmation this is fine; this listener runs as one of the task's listeners
-            // so the task.runListeners will always be no-op
-//            try {
-//                ((TaskInternal<?>)task).runListeners();
-//            } catch (Exception e) {
-//                log.warn("Error running task listeners for task "+task+" done", e);
-//            }
             
             for (ExecutionListener listener : listeners) {
                 try {


[03/35] brooklyn-server git commit: add adjunct REST API, deprecating policy endpoint

Posted by he...@apache.org.
add adjunct REST API, deprecating policy endpoint


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

Branch: refs/heads/master
Commit: 45261c7e155e1022cd172d9816a647ba35f0218c
Parents: 2860af5
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Sep 13 16:22:56 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Sep 13 17:34:53 2017 +0100

----------------------------------------------------------------------
 .../org/apache/brooklyn/api/sensor/Feed.java    |   2 +-
 .../brooklyn/core/entity/AbstractEntity.java    |   5 +
 .../brooklyn/core/entity/EntityInternal.java    |   2 +-
 .../apache/brooklyn/core/policy/Policies.java   |  30 ++-
 .../apache/brooklyn/rest/api/AdjunctApi.java    | 233 ++++++++++++++++
 .../org/apache/brooklyn/rest/api/PolicyApi.java |   2 +
 .../brooklyn/rest/api/PolicyConfigApi.java      |  27 +-
 .../brooklyn/rest/domain/AdjunctDetail.java     |  72 +++++
 .../brooklyn/rest/domain/AdjunctSummary.java    | 150 +++++++++++
 .../rest/domain/CatalogEnricherSummary.java     |   2 +
 .../rest/domain/CatalogEntitySummary.java       |   2 +
 .../rest/domain/CatalogItemSummary.java         |   2 +
 .../rest/domain/CatalogLocationSummary.java     |   2 +
 .../rest/domain/CatalogPolicySummary.java       |   2 +
 .../rest/domain/EnricherConfigSummary.java      |   3 +-
 .../rest/domain/PolicyConfigSummary.java        |   3 +-
 .../brooklyn/rest/domain/PolicySummary.java     |  83 +-----
 .../org/apache/brooklyn/rest/domain/Status.java |   7 +-
 .../apache/brooklyn/rest/BrooklynRestApi.java   |   2 +
 .../rest/resources/AdjunctResource.java         | 263 +++++++++++++++++++
 .../rest/resources/PolicyConfigResource.java    |   1 +
 .../brooklyn/rest/resources/PolicyResource.java |   1 +
 .../rest/transform/AdjunctTransformer.java      | 117 +++++++++
 .../rest/transform/EntityTransformer.java       |  21 ++
 .../rest/transform/PolicyTransformer.java       |   3 +
 .../rest/util/BrooklynRestResourceUtils.java    |  43 +++
 26 files changed, 983 insertions(+), 97 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/45261c7e/api/src/main/java/org/apache/brooklyn/api/sensor/Feed.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/sensor/Feed.java b/api/src/main/java/org/apache/brooklyn/api/sensor/Feed.java
index d50e092..01a4714 100644
--- a/api/src/main/java/org/apache/brooklyn/api/sensor/Feed.java
+++ b/api/src/main/java/org/apache/brooklyn/api/sensor/Feed.java
@@ -43,7 +43,7 @@ public interface Feed extends EntityAdjunct, Rebindable {
 
     /** 
      * True if everything has been _started_ (or it is starting) but not stopped,
-     * even if it is suspended; see also {@link #isActive()}
+     * even if it is suspended; see also {@link #isRunning()}
      */
     boolean isActivated();
     

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/45261c7e/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java b/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java
index 08b6591..8c31512 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java
@@ -1951,6 +1951,11 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E
             }
             return changed;
         }
+
+        @Override
+        public Iterator<Feed> iterator() {
+            return getFeeds().iterator();
+        }
     }
     
     // -------- SENSORS --------------------

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/45261c7e/core/src/main/java/org/apache/brooklyn/core/entity/EntityInternal.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/EntityInternal.java b/core/src/main/java/org/apache/brooklyn/core/entity/EntityInternal.java
index d6d51a1..7377f38 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/EntityInternal.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/EntityInternal.java
@@ -189,7 +189,7 @@ public interface EntityInternal extends BrooklynObjectInternal, EntityLocal, Reb
         void remove(AttributeSensor<?> attribute);
     }
 
-    public interface FeedSupport {
+    public interface FeedSupport extends Iterable<Feed> {
 
         Collection<Feed> getFeeds();
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/45261c7e/core/src/main/java/org/apache/brooklyn/core/policy/Policies.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/policy/Policies.java b/core/src/main/java/org/apache/brooklyn/core/policy/Policies.java
index db9bece..4b32dfc 100644
--- a/core/src/main/java/org/apache/brooklyn/core/policy/Policies.java
+++ b/core/src/main/java/org/apache/brooklyn/core/policy/Policies.java
@@ -20,7 +20,9 @@ package org.apache.brooklyn.core.policy;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.objs.EntityAdjunct;
 import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.api.sensor.Feed;
 import org.apache.brooklyn.api.sensor.Sensor;
 import org.apache.brooklyn.api.sensor.SensorEvent;
 import org.apache.brooklyn.api.sensor.SensorEventListener;
@@ -28,6 +30,8 @@ import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.annotations.Beta;
+
 import groovy.lang.Closure;
 
 @SuppressWarnings({"rawtypes","unchecked"})
@@ -81,11 +85,27 @@ public class Policies {
     }
 
     public static Lifecycle getPolicyStatus(Policy p) {
-        if (p.isRunning()) return Lifecycle.RUNNING;
-        if (p.isDestroyed()) return Lifecycle.DESTROYED;
-        if (p.isSuspended()) return Lifecycle.STOPPED;
-        // TODO could policy be in an error state?
-        return Lifecycle.CREATED;        
+        return inferAdjunctStatus(p);
+    }
+    
+    @Beta
+    public static Lifecycle inferAdjunctStatus(EntityAdjunct a) {
+        if (a.isRunning()) return Lifecycle.RUNNING;
+        if (a.isDestroyed()) return Lifecycle.DESTROYED;
+        
+        // adjuncts don't currently support an "error" state; though that would be useful!
+        
+        if (a instanceof Policy) {
+            if (((Policy)a).isSuspended()) return Lifecycle.STOPPED;
+            return Lifecycle.CREATED;
+        }
+        if (a instanceof Feed) {
+            if (((Feed)a).isSuspended()) return Lifecycle.STOPPED;
+            if (((Feed)a).isActivated()) return Lifecycle.STARTING;
+            return Lifecycle.CREATED;
+        }
+        
+        return Lifecycle.STOPPED;
     }
     
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/45261c7e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java
new file mode 100644
index 0000000..5fc1366
--- /dev/null
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java
@@ -0,0 +1,233 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.rest.api;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.apache.brooklyn.rest.domain.AdjunctConfigSummary;
+import org.apache.brooklyn.rest.domain.AdjunctDetail;
+import org.apache.brooklyn.rest.domain.AdjunctSummary;
+import org.apache.brooklyn.rest.domain.Status;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+@Path("/applications/{application}/entities/{entity}/adjuncts")
+@Api("Entity Adjuncts (policies, enrichers, feeds)")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public interface AdjunctApi {
+
+    @GET
+    @ApiOperation(value = "Fetch the adjuncts attached to a specific application entity",
+            response = org.apache.brooklyn.rest.domain.AdjunctSummary.class,
+            responseContainer = "List")
+    @ApiResponses(value = {
+            @ApiResponse(code = 404, message = "Could not find application or entity")
+    })
+    public List<AdjunctSummary> list(
+            @ApiParam(value = "Application ID or name", required = true)
+            @PathParam("application") final String application,
+            @ApiParam(value = "Entity ID or name", required = true)
+            @PathParam("entity") final String entityToken,
+            @ApiParam(value = "Filter by adjunct type", required = false)
+            @QueryParam("adjunctType") final String adjunctType);
+
+    @POST
+    @ApiOperation(value = "Add an adjunct (policy, enricher, or feed)", notes = "Returns a summary of the added adjunct")
+    @ApiResponses(value = {
+            @ApiResponse(code = 404, message = "Could not find application or entity"),
+            @ApiResponse(code = 400, message = "Type is not a suitable adjunct")
+    })
+    public AdjunctSummary addAdjunct(
+            @ApiParam(name = "application", value = "Application ID or name", required = true)
+            @PathParam("application") String application,
+
+            @ApiParam(name = "entity", value = "Entity ID or name", required = true)
+            @PathParam("entity") String entityToken,
+
+            @ApiParam(name = "type", value = "Adjunct from the type registry to instantiate and add", required = true)
+            @QueryParam("type")
+            String adjunctRegisteredTypeName,
+
+            // TODO would like to make this optional but jersey complains if we do
+            @ApiParam(name = "config", value = "Configuration for the adjunct (as key value pairs)", required = true)
+            Map<String, String> config);
+
+    @GET
+    @Path("/{adjunct}")
+    @ApiOperation(value = "Gets detail of an adjunct")
+    @ApiResponses(value = {
+            @ApiResponse(code = 404, message = "Could not find application, entity or adjunct")
+    })
+    public AdjunctDetail get(
+            @ApiParam(name = "application", value = "Application ID or name", required = true)
+            @PathParam("application") String application,
+
+            @ApiParam(name = "entity", value = "Entity ID or name", required = true)
+            @PathParam("entity") String entityToken,
+
+            @ApiParam(name = "adjunct", value = "Adjunct ID or name", required = true)
+            @PathParam("adjunct") String adjunctId);
+    
+    @GET
+    @Path("/{adjunct}/status")
+    @ApiOperation(value = "Gets status of an adjunct (RUNNING / SUSPENDED)")
+    @ApiResponses(value = {
+            @ApiResponse(code = 404, message = "Could not find application, entity or adjunct")
+    })
+    public Status getStatus(
+            @ApiParam(name = "application", value = "Application ID or name", required = true)
+            @PathParam("application") String application,
+
+            @ApiParam(name = "entity", value = "Entity ID or name", required = true)
+            @PathParam("entity") String entityToken,
+
+            @ApiParam(name = "adjunct", value = "Adjunct ID or name", required = true)
+            @PathParam("adjunct") String adjunctId);
+
+    @POST
+    @Path("/{adjunct}/start")
+    @ApiOperation(value = "Start or resume an adjunct")
+    @ApiResponses(value = {
+            @ApiResponse(code = 404, message = "Could not find application, entity or adjunct")
+    })
+    public Response start(
+            @ApiParam(name = "application", value = "Application ID or name", required = true)
+            @PathParam("application") String application,
+
+            @ApiParam(name = "entity", value = "Entity ID or name", required = true)
+            @PathParam("entity") String entityToken,
+
+            @ApiParam(name = "adjunct", value = "Adjunct ID or name", required = true)
+            @PathParam("adjunct") String adjunctId);
+
+    @POST
+    @Path("/{adjunct}/stop")
+    @ApiOperation(value = "Suspends an adjunct")
+    @ApiResponses(value = {
+            @ApiResponse(code = 404, message = "Could not find application, entity or adjunct")
+    })
+    public Response stop(
+            @ApiParam(name = "application", value = "Application ID or name", required = true)
+            @PathParam("application") String application,
+
+            @ApiParam(name = "entity", value = "Entity ID or name", required = true)
+            @PathParam("entity") String entityToken,
+
+            @ApiParam(name = "adjunct", value = "Adjunct ID or name", required = true)
+            @PathParam("adjunct") String adjunctId);
+
+    @DELETE
+    @Path("/{adjunct}")
+    @ApiOperation(value = "Destroy an adjunct", notes="Removes an adjunct from being associated with the entity and destroys it (stopping first if running)")
+    @ApiResponses(value = {
+            @ApiResponse(code = 404, message = "Could not find application, entity or adjunct")
+    })
+    public Response destroy(
+            @ApiParam(name = "application", value = "Application ID or name", required = true)
+            @PathParam("application") String application,
+
+            @ApiParam(name = "entity", value = "Entity ID or name", required = true)
+            @PathParam("entity") String entityToken,
+
+            @ApiParam(name = "adjunct", value = "Adjunct ID or name", required = true)
+            @PathParam("adjunct") String adjunctId);
+
+    /// ---------- config ---------------
+    
+    @GET
+    @Path("/{adjunct}/config")
+    @ApiOperation(value = "Fetch the config keys for a specific adjunct",
+            response = org.apache.brooklyn.rest.domain.AdjunctConfigSummary.class,
+            responseContainer = "List")
+    @ApiResponses(value = {
+            @ApiResponse(code = 404, message = "Could not find application or entity or adjunct")
+    })
+    public List<AdjunctConfigSummary> listConfig(
+            @ApiParam(value = "Application ID or name", required = true)
+            @PathParam("application") final String application,
+            @ApiParam(value = "Entity ID or name", required = true)
+            @PathParam("entity") final String entityToken,
+            @ApiParam(value = "Adjunct ID or name", required = true)
+            @PathParam("adjunct") final String adjunctToken);
+
+    // TODO support parameters  ?show=value,summary&name=xxx &format={string,json,xml}
+    // (and in sensors class)
+    @GET
+    @Path("/{adjunct}/config-current")
+    @ApiOperation(value = "Fetch config key values in batch", notes="Returns a map of config name to value")
+    public Map<String, Object> batchConfigRead(
+            @ApiParam(value = "Application ID or name", required = true)
+            @PathParam("application") String application,
+            @ApiParam(value = "Entity ID or name", required = true)
+            @PathParam("entity") String entityToken,
+            @ApiParam(value = "Adjunct ID or name", required = true)
+            @PathParam("adjunct") String adjunctToken) ;
+
+    @GET
+    @Path("/{adjunct}/config/{config}")
+    @ApiOperation(value = "Fetch config value", response = Object.class)
+    @ApiResponses(value = {
+            @ApiResponse(code = 404, message = "Could not find application, entity, adjunct or config key")
+    })
+    public String getConfig(
+            @ApiParam(value = "Application ID or name", required = true)
+            @PathParam("application") String application,
+            @ApiParam(value = "Entity ID or name", required = true)
+            @PathParam("entity") String entityToken,
+            @ApiParam(value = "Adjunct ID or name", required = true)
+            @PathParam("adjunct") String adjunctToken,
+            @ApiParam(value = "Config key ID", required = true)
+            @PathParam("config") String configKeyName);
+
+    @POST
+    @Path("/{adjunct}/config/{config}")
+    @Consumes(value = {"*/*"})
+    @ApiOperation(value = "Sets the given config on this adjunct")
+    @ApiResponses(value = {
+            @ApiResponse(code = 404, message = "Could not find application, entity, adjunct or config key")
+    })
+    public Response setConfig(
+            @ApiParam(value = "Application ID or name", required = true)
+            @PathParam("application") String application,
+            @ApiParam(value = "Entity ID or name", required = true)
+            @PathParam("entity") String entityToken,
+            @ApiParam(value = "Adjunct ID or name", required = true)
+            @PathParam("adjunct") String adjunctToken,
+            @ApiParam(value = "Config key ID", required = true)
+            @PathParam("config") String configKeyName,
+            @ApiParam(name = "value", value = "New value for the configuration", required = true)
+            Object value);
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/45261c7e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyApi.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyApi.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyApi.java
index a698f7d..329c0e1 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyApi.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyApi.java
@@ -36,6 +36,8 @@ import java.util.Map;
 @Api("Entity Policies")
 @Produces(MediaType.APPLICATION_JSON)
 @Consumes(MediaType.APPLICATION_JSON)
+/** @deprecated since 0.12.0 use AdjunctApi */
+@Deprecated
 public interface PolicyApi {
     
     @GET

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/45261c7e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyConfigApi.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyConfigApi.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyConfigApi.java
index 1e6bfe6..06a4b86 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyConfigApi.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyConfigApi.java
@@ -18,23 +18,32 @@
  */
 package org.apache.brooklyn.rest.api;
 
-import io.swagger.annotations.Api;
-import org.apache.brooklyn.rest.domain.PolicyConfigSummary;
-import io.swagger.annotations.ApiResponse;
-import io.swagger.annotations.ApiResponses;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
+import java.util.List;
+import java.util.Map;
 
-import javax.ws.rs.*;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
-import java.util.List;
-import java.util.Map;
+
+import org.apache.brooklyn.rest.domain.PolicyConfigSummary;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
 
 @Path("/applications/{application}/entities/{entity}/policies/{policy}/config")
 @Api("Entity Policy Config")
 @Produces(MediaType.APPLICATION_JSON)
 @Consumes(MediaType.APPLICATION_JSON)
+/** @deprecated since 0.12.0 use AdjunctApi */
+@Deprecated
 public interface PolicyConfigApi {
 
     @GET

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/45261c7e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctDetail.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctDetail.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctDetail.java
new file mode 100644
index 0000000..ddce5f4
--- /dev/null
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctDetail.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.rest.domain;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.brooklyn.api.objs.EntityAdjunct;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.collections.MutableSet;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+
+public class AdjunctDetail extends AdjunctSummary {
+
+    private static final long serialVersionUID = -5086680835225136768L;
+
+    @JsonInclude(Include.NON_EMPTY)
+    private String functionallyUniqueIdentifier;
+    @JsonInclude(Include.NON_EMPTY)
+    private Set<Object> tags;
+    @JsonInclude(Include.NON_EMPTY)
+    final Set<AdjunctConfigSummary> parameters = MutableSet.of();
+    final Map<String,Object> config = MutableMap.of();
+
+    // for json
+    protected AdjunctDetail() {}
+
+    public AdjunctDetail(EntityAdjunct a) {
+        super(a);
+        this.functionallyUniqueIdentifier = a.getUniqueTag();
+        this.tags = a.tags().getTags();
+    }
+    
+    public String getFunctionallyUniqueIdentifier() {
+        return functionallyUniqueIdentifier;
+    }
+    
+    public Set<Object> getTags() {
+        return tags;
+    }
+    
+    public AdjunctDetail parameter(AdjunctConfigSummary p) {
+        parameters.add(p); return this;
+    }
+
+    public AdjunctDetail config(String key, Object val) {
+        config.put(key, val); return this;
+    }
+
+    public AdjunctDetail config(Map<String,Object> vals) {
+        config.putAll(vals); return this;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/45261c7e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctSummary.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctSummary.java
new file mode 100644
index 0000000..ca80644
--- /dev/null
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctSummary.java
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.rest.domain;
+
+import java.io.Serializable;
+import java.net.URI;
+import java.util.Map;
+import java.util.Objects;
+
+import org.apache.brooklyn.api.objs.BrooklynObjectType;
+import org.apache.brooklyn.api.objs.EntityAdjunct;
+import org.apache.brooklyn.api.objs.HighlightTuple;
+import org.apache.brooklyn.api.objs.Identifiable;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.google.common.collect.ImmutableMap;
+
+public class AdjunctSummary implements HasName, Serializable, Identifiable {
+
+    private static final long serialVersionUID = -8106551648118942612L;
+    
+    private String id;
+    private String name;
+    private BrooklynObjectType adjunctType;
+    @JsonInclude(Include.NON_EMPTY)
+    private String catalogItemId;
+    private Status state;
+    @JsonInclude(Include.NON_EMPTY)
+    private Map<String, HighlightTuple> highlights;
+    
+    private Map<String, URI> links;
+
+    // for json
+    protected AdjunctSummary() {}
+    
+    public AdjunctSummary(EntityAdjunct a) {
+        id = a.getId();
+        name = a.getDisplayName();
+        adjunctType = BrooklynObjectType.of(a);
+        catalogItemId = a.getCatalogItemId();
+        highlights = a.getHighlights();
+    }
+        
+    /** @deprecated since 0.12.0 only for legacy type-specific summary classes */
+    @Deprecated   
+    protected AdjunctSummary(
+            String id,
+            String name,
+            BrooklynObjectType adjunctType,
+            String catalogItemId,
+            Status state,
+            Map<String, HighlightTuple> highlights,
+            Map<String, URI> links) {
+        this.id = id;
+        this.name = name;
+        this.adjunctType = adjunctType;
+        this.catalogItemId = catalogItemId;
+        this.state = state;
+        this.highlights = (highlights == null) ? ImmutableMap.of() : ImmutableMap.copyOf(highlights);
+        this.links = (links == null) ? ImmutableMap.<String, URI> of() : ImmutableMap.copyOf(links);
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    public BrooklynObjectType getAdjunctType() {
+        return adjunctType;
+    }
+    
+    public String getCatalogItemId() {
+        return catalogItemId;
+    }
+
+    public Status getState() {
+        return state;
+    }
+
+    public Map<String, HighlightTuple> getHighlights() {
+        return highlights;
+    }
+
+    public Map<String, URI> getLinks() {
+        return links;
+    }
+    
+    public AdjunctSummary state(Status state) {
+        this.state = state; return this;
+    }
+    
+    public AdjunctSummary links(Map<String, URI> links) {
+        this.links = links; return this;
+    }
+
+    
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof AdjunctSummary)) return false;
+        AdjunctSummary that = (AdjunctSummary) o;
+        return Objects.equals(id, that.id) &&
+                Objects.equals(name, that.name) &&
+                Objects.equals(adjunctType, that.adjunctType) &&
+                Objects.equals(catalogItemId, that.catalogItemId) &&
+                Objects.equals(state, that.state) &&
+                Objects.equals(highlights, that.highlights) &&
+                Objects.equals(links, that.links) ;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(id, name, adjunctType, catalogItemId, state, highlights, links);
+    }
+
+    @Override
+    public String toString() {
+        return (adjunctType!=null ? adjunctType.name() : "AdjunctSummary")+"{" +
+                "id='" + id + '\'' +
+                ", name='" + name + '\'' +
+                ", catalogItemId='" + catalogItemId + '\'' +
+                ", state='" + state + '\'' +
+                ", highlights=" + highlights +
+                ", links=" + links +
+                '}';
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/45261c7e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEnricherSummary.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEnricherSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEnricherSummary.java
index 2e81ae1..c655515 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEnricherSummary.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEnricherSummary.java
@@ -27,6 +27,8 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.google.common.collect.ImmutableSet;
 
+/** @deprecated since 0.12.0 new TypeApi returns TypeSummary */
+@Deprecated
 public class CatalogEnricherSummary extends CatalogItemSummary {
 
     private static final long serialVersionUID = -588856488327394445L;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/45261c7e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEntitySummary.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEntitySummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEntitySummary.java
index 5947b7f..7dbc1be 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEntitySummary.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEntitySummary.java
@@ -27,6 +27,8 @@ import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 
+/** @deprecated since 0.12.0 new TypeApi returns TypeSummary */
+@Deprecated
 public class CatalogEntitySummary extends CatalogItemSummary {
 
     private static final long serialVersionUID = 1063908984191424539L;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/45261c7e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogItemSummary.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogItemSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogItemSummary.java
index cdb86d4..cd85c13 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogItemSummary.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogItemSummary.java
@@ -36,6 +36,8 @@ import com.google.common.collect.ImmutableMap;
  * see also, subclasses */
 @JsonIgnoreProperties(ignoreUnknown = true)
 // ignore unknown, ie properties from subclasses (entity)
+/** @deprecated since 0.12.0 new TypeApi returns TypeSummary */
+@Deprecated
 public class CatalogItemSummary implements HasId, HasName, Serializable {
 
     private static final long serialVersionUID = -823483595879417681L;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/45261c7e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogLocationSummary.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogLocationSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogLocationSummary.java
index 0213a0c..5fb1a4b 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogLocationSummary.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogLocationSummary.java
@@ -26,6 +26,8 @@ import java.util.Set;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.collect.ImmutableSet;
 
+/** @deprecated since 0.12.0 new TypeApi returns TypeSummary */
+@Deprecated
 public class CatalogLocationSummary extends CatalogItemSummary {
 
     private static final long serialVersionUID = 8420991584336514673L;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/45261c7e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogPolicySummary.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogPolicySummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogPolicySummary.java
index 37e5786..ad67786 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogPolicySummary.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogPolicySummary.java
@@ -27,6 +27,8 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.google.common.collect.ImmutableSet;
 
+/** @deprecated since 0.12.0 new TypeApi returns TypeSummary */
+@Deprecated
 public class CatalogPolicySummary extends CatalogItemSummary {
 
     private static final long serialVersionUID = -588856488327394445L;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/45261c7e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EnricherConfigSummary.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EnricherConfigSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EnricherConfigSummary.java
index c868fb8..7b40206 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EnricherConfigSummary.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EnricherConfigSummary.java
@@ -23,7 +23,8 @@ import java.util.Map;
 
 import org.apache.brooklyn.config.ConfigKey;
 
-// TODO remove? this class has no value over its super
+/** @deprecated since 0.12.0 new {@link AdjunctConfigSummary}; this class does nothing additional */
+@Deprecated
 public class EnricherConfigSummary extends AdjunctConfigSummary {
 
     private static final long serialVersionUID = 4339330833863794513L;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/45261c7e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicyConfigSummary.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicyConfigSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicyConfigSummary.java
index 5dfb898..797bd0c 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicyConfigSummary.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicyConfigSummary.java
@@ -23,7 +23,8 @@ import java.util.Map;
 
 import org.apache.brooklyn.config.ConfigKey;
 
-//TODO remove? this class has no value over its super
+/** @deprecated since 0.12.0 new {@link AdjunctConfigSummary}; this class does nothing additional */
+@Deprecated
 public class PolicyConfigSummary extends AdjunctConfigSummary {
 
     private static final long serialVersionUID = 4339330833863794513L;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/45261c7e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicySummary.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicySummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicySummary.java
index ce9c9e0..da4a86a 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicySummary.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicySummary.java
@@ -18,29 +18,20 @@
  */
 package org.apache.brooklyn.rest.domain;
 
-import java.io.Serializable;
 import java.net.URI;
 import java.util.Map;
-import java.util.Objects;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-import com.google.common.collect.ImmutableMap;
 
+import org.apache.brooklyn.api.objs.BrooklynObjectType;
 import org.apache.brooklyn.api.objs.HighlightTuple;
 
-public class PolicySummary implements HasName, HasId, Serializable {
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/** @deprecated since 0.12.0 use {@link AdjunctSummary}; this class is identical */
+@Deprecated
+public class PolicySummary extends AdjunctSummary {
 
     private static final long serialVersionUID = -5086680835225136768L;
 
-    private final String id;
-    private final String name;
-    @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
-    private final String catalogItemId;
-    private final Status state;
-    private final Map<String, URI> links;
-    private final Map<String, HighlightTuple> highlights;
-
     public PolicySummary(
             @JsonProperty("id") String id,
             @JsonProperty("name") String name,
@@ -48,67 +39,7 @@ public class PolicySummary implements HasName, HasId, Serializable {
             @JsonProperty("state") Status state,
             @JsonProperty("highlights") Map<String, HighlightTuple> highlights,
             @JsonProperty("links") Map<String, URI> links) {
-        this.id = id;
-        this.name = name;
-        this.catalogItemId = catalogItemId;
-        this.state = state;
-        this.links = (links == null) ? ImmutableMap.<String, URI> of() : ImmutableMap.copyOf(links);
-        this.highlights = (highlights == null) ? ImmutableMap.of() : ImmutableMap.copyOf(highlights);
-    }
-
-    @Override
-    public String getId() {
-        return id;
-    }
-
-    @Override
-    public String getName() {
-        return name;
-    }
-
-    public String getCatalogItemId() {
-        return catalogItemId;
+        super(id, name, BrooklynObjectType.POLICY, catalogItemId, state, highlights, links);
     }
 
-    public Status getState() {
-        return state;
-    }
-
-    public Map<String, URI> getLinks() {
-        return links;
-    }
-
-    public Map<String, HighlightTuple> getHighlights() {
-        return highlights;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (!(o instanceof PolicySummary)) return false;
-        PolicySummary that = (PolicySummary) o;
-        return Objects.equals(id, that.id) &&
-                Objects.equals(name, that.name) &&
-                Objects.equals(catalogItemId, that.catalogItemId) &&
-                state == that.state &&
-                Objects.equals(highlights, that.highlights) &&
-                Objects.equals(links, that.links) ;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(id, name, catalogItemId, state, highlights, links);
-    }
-
-    @Override
-    public String toString() {
-        return "PolicySummary{" +
-                "id='" + id + '\'' +
-                ", name='" + name + '\'' +
-                ", catalogItemId='" + catalogItemId + '\'' +
-                ", state=" + state +
-                ", highlights=" + highlights +
-                ", links=" + links +
-                '}';
-    }
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/45261c7e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/Status.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/Status.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/Status.java
index e2b2ce4..4a998c7 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/Status.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/Status.java
@@ -18,9 +18,10 @@
  */
 package org.apache.brooklyn.rest.domain;
 
-/**
- * @author Adam Lowe
- */
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
+
+/** Canonical set, similar to {@link Lifecycle}, but cleaned up for outside consumption
+ * and more appropriate for adjunct types */
 public enum Status {
     ACCEPTED,
     STARTING,

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/45261c7e/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/BrooklynRestApi.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/BrooklynRestApi.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/BrooklynRestApi.java
index b3eb4e4..233d717 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/BrooklynRestApi.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/BrooklynRestApi.java
@@ -24,6 +24,7 @@ import java.util.List;
 import org.apache.brooklyn.rest.resources.AbstractBrooklynRestResource;
 import org.apache.brooklyn.rest.resources.AccessResource;
 import org.apache.brooklyn.rest.resources.ActivityResource;
+import org.apache.brooklyn.rest.resources.AdjunctResource;
 import org.apache.brooklyn.rest.resources.ApidocResource;
 import org.apache.brooklyn.rest.resources.ApplicationResource;
 import org.apache.brooklyn.rest.resources.BundleResource;
@@ -63,6 +64,7 @@ public class BrooklynRestApi {
         resources.add(new EntityConfigResource());
         resources.add(new SensorResource());
         resources.add(new EffectorResource());
+        resources.add(new AdjunctResource());
         resources.add(new PolicyResource());
         resources.add(new PolicyConfigResource());
         resources.add(new ActivityResource());

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/45261c7e/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java
new file mode 100644
index 0000000..9dd4c10
--- /dev/null
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java
@@ -0,0 +1,263 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.rest.resources;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec;
+import org.apache.brooklyn.api.objs.BrooklynObjectType;
+import org.apache.brooklyn.api.objs.EntityAdjunct;
+import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.api.sensor.Enricher;
+import org.apache.brooklyn.api.sensor.EnricherSpec;
+import org.apache.brooklyn.api.sensor.Feed;
+import org.apache.brooklyn.api.typereg.RegisteredType;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigPredicates;
+import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.mgmt.entitlement.Entitlements;
+import org.apache.brooklyn.rest.api.AdjunctApi;
+import org.apache.brooklyn.rest.domain.AdjunctConfigSummary;
+import org.apache.brooklyn.rest.domain.AdjunctDetail;
+import org.apache.brooklyn.rest.domain.AdjunctSummary;
+import org.apache.brooklyn.rest.domain.Status;
+import org.apache.brooklyn.rest.domain.SummaryComparators;
+import org.apache.brooklyn.rest.filter.HaHotStateRequired;
+import org.apache.brooklyn.rest.transform.AdjunctTransformer;
+import org.apache.brooklyn.rest.transform.EntityTransformer;
+import org.apache.brooklyn.rest.util.BrooklynRestResourceUtils;
+import org.apache.brooklyn.rest.util.WebResourceUtils;
+import org.apache.brooklyn.util.core.ClassLoaderUtils;
+import org.apache.brooklyn.util.core.flags.TypeCoercions;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.text.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicates;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+@HaHotStateRequired
+public class AdjunctResource extends AbstractBrooklynRestResource implements AdjunctApi {
+
+    private static final Logger log = LoggerFactory.getLogger(AdjunctResource.class);
+
+    private @Context UriInfo ui;
+
+    @Override
+    public List<AdjunctSummary> list(String application, String entityToken, String adjunctType) {
+        final Entity entity = brooklyn().getEntity(application, entityToken);
+        Iterable<? extends EntityAdjunct> source = Collections.emptyList();
+        boolean all = Strings.isBlank(adjunctType);
+        boolean any = false;
+        if (all || adjunctType.equalsIgnoreCase(BrooklynObjectType.POLICY.name())) {
+            any = true;
+            source = Iterables.concat(source, entity.policies());
+        }
+        if (all || adjunctType.equalsIgnoreCase(BrooklynObjectType.ENRICHER.name())) {
+            any = true;
+            source = Iterables.concat(source, entity.enrichers());
+        }
+        if (all || adjunctType.equalsIgnoreCase(BrooklynObjectType.FEED.name())) {
+            any = true;
+            source = Iterables.concat(source, ((EntityInternal)entity).feeds());
+        }
+        if (!any) {
+            throw WebResourceUtils.badRequest("Unknown adjunct type '%s'; use 'policy', 'enricher', or 'feed'", adjunctType);
+        }
+        return FluentIterable.from(source)
+            .transform(new Function<EntityAdjunct, AdjunctSummary>() {
+                @Override
+                public AdjunctSummary apply(EntityAdjunct adjunct) {
+                    return AdjunctTransformer.adjunctSummary(entity, adjunct, ui.getBaseUriBuilder());
+                }
+            })
+            .toSortedList(SummaryComparators.nameComparator());
+    }
+
+    // TODO would like to make 'config' arg optional but jersey complains if we do
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Override
+    public AdjunctSummary addAdjunct(String application, String entityToken, String adjunctTypeName, Map<String, String> config) {
+        Entity entity = brooklyn().getEntity(application, entityToken);
+        if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.MODIFY_ENTITY, entity)) {
+            throw WebResourceUtils.forbidden("User '%s' is not authorized to modify entity '%s'",
+                    Entitlements.getEntitlementContext().user(), entity);
+        }
+        
+        RegisteredType rt = brooklyn().getTypeRegistry().get(adjunctTypeName);
+        AbstractBrooklynObjectSpec<?, ?> spec;
+        if (rt!=null) {
+            spec = brooklyn().getTypeRegistry().createSpec(rt, null, null);
+        } else {
+            try {
+                Class<?> type = new ClassLoaderUtils(this, mgmt()).loadClass(adjunctTypeName);
+                if (Policy.class.isAssignableFrom(type)) spec = PolicySpec.create((Class) type);
+                else if (Enricher.class.isAssignableFrom(type)) spec = EnricherSpec.create((Class) type);
+                else if (Feed.class.isAssignableFrom(type)) {
+                    // TODO add FeedSpec ?  would be needed even if using the type registry
+                    throw WebResourceUtils.badRequest("Creation of feeds from java type (%s) not supported", adjunctTypeName);
+                } else {
+                    throw WebResourceUtils.badRequest("Invalid type %s; not a support adjunct type", adjunctTypeName);
+                }
+            } catch (ClassNotFoundException e) {
+                throw WebResourceUtils.badRequest("No adjunct with type %s found", adjunctTypeName);
+            } catch (ClassCastException e) {
+                throw WebResourceUtils.badRequest("No adjunct with type %s found", adjunctTypeName);
+            } catch (Exception e) {
+                throw Exceptions.propagate(e);
+            }
+        }
+
+        spec.configure(config);
+
+        EntityAdjunct instance;
+        if (spec instanceof PolicySpec) instance = entity.policies().add((PolicySpec)spec);
+        else if (spec instanceof EnricherSpec) instance = entity.enrichers().add((EnricherSpec)spec);
+        else {
+            // TODO add FeedSpec
+            throw WebResourceUtils.badRequest("Unexpected spec type %s", spec);
+        }
+
+        log.debug("REST API added adjunct " + instance + " to " + entity);
+
+        return AdjunctTransformer.adjunctDetail(brooklyn(), entity, instance, ui.getBaseUriBuilder());
+    }
+
+    @Override
+    public AdjunctDetail get(String application, String entityToken, String adjunctId) {
+        Entity entity = brooklyn().getEntity(application, entityToken);
+        EntityAdjunct adjunct = brooklyn().getAdjunct(entity, adjunctId);
+
+        return AdjunctTransformer.adjunctDetail(brooklyn(), entity, adjunct, ui.getBaseUriBuilder());
+    }
+    
+    @Override
+    public Status getStatus(String application, String entityToken, String adjunctId) {
+        return AdjunctTransformer.inferStatus( brooklyn().getAdjunct(application, entityToken, adjunctId) );
+    }
+
+    @Override
+    public Response start(String application, String entityToken, String adjunctId) {
+        EntityAdjunct adjunct = brooklyn().getAdjunct(application, entityToken, adjunctId);
+        if (adjunct instanceof Policy) ((Policy)adjunct).resume();
+        else if (adjunct instanceof Feed) ((Feed)adjunct).resume();
+        else throw WebResourceUtils.badRequest("%s does not support start/resume", adjunct);
+        
+        return Response.status(Response.Status.NO_CONTENT).build();
+    }
+
+    @Override
+    public Response stop(String application, String entityToken, String adjunctId) {
+        EntityAdjunct adjunct = brooklyn().getAdjunct(application, entityToken, adjunctId);
+        if (adjunct instanceof Policy) ((Policy)adjunct).suspend();
+        else if (adjunct instanceof Feed) ((Feed)adjunct).suspend();
+        else throw WebResourceUtils.badRequest("%s does not support suspend", adjunct);
+        
+        return Response.status(Response.Status.NO_CONTENT).build();
+    }
+
+    @Override
+    public Response destroy(String application, String entityToken, String adjunctId) {
+        Entity entity = brooklyn().getEntity(application, entityToken);
+        EntityAdjunct adjunct = brooklyn().getAdjunct(entity, adjunctId);
+
+        if (adjunct instanceof Policy) {
+            ((Policy)adjunct).suspend();
+            entity.policies().remove((Policy) adjunct);
+        } else if (adjunct instanceof Enricher) {
+            entity.enrichers().remove((Enricher) adjunct);
+        } else if (adjunct instanceof Feed) {
+            ((Feed)adjunct).suspend();
+            ((EntityInternal)entity).feeds().remove((Feed) adjunct);
+        } else {
+            throw WebResourceUtils.badRequest("Unexpected adjunct type %s", adjunct);
+        }
+        
+        return Response.status(Response.Status.NO_CONTENT).build();
+    }
+    
+    // ---- config ----
+    
+    @Override
+    public List<AdjunctConfigSummary> listConfig(
+            final String application, final String entityToken, final String adjunctToken) {
+        Entity entity = brooklyn().getEntity(application, entityToken);
+        EntityAdjunct adjunct = brooklyn().getAdjunct(entity, adjunctToken);
+
+        List<AdjunctConfigSummary> result = Lists.newArrayList();
+        for (ConfigKey<?> key : adjunct.config().findKeysPresent(Predicates.alwaysTrue())) {
+            result.add(AdjunctTransformer.configSummary(brooklyn(), entity, adjunct, key, ui.getBaseUriBuilder()));
+        }
+        return result;
+    }
+
+    // TODO support parameters  ?show=value,summary&name=xxx &format={string,json,xml}
+    // (and in sensors class)
+    @Override
+    public Map<String, Object> batchConfigRead(String application, String entityToken, String adjunctToken) {
+        // TODO: add test
+        return EntityTransformer.getConfigValues(brooklyn(), brooklyn().getAdjunct(application, entityToken, adjunctToken) );
+    }
+
+    @Override
+    public String getConfig(String application, String entityToken, String adjunctToken, String configKeyName) {
+        EntityAdjunct adjunct = brooklyn().getAdjunct(application, entityToken, adjunctToken);
+        Set<ConfigKey<?>> cki = adjunct.config().findKeysDeclared(ConfigPredicates.nameSatisfies(Predicates.equalTo(configKeyName)));
+        if (cki.isEmpty()) throw WebResourceUtils.notFound("Cannot find config key '%s' in policy '%s' of entity '%s'", configKeyName, adjunctToken, entityToken);
+
+        return brooklyn().getStringValueForDisplay(adjunct.config().get(cki.iterator().next()));
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Override
+    public Response setConfig(String application, String entityToken, String adjunctToken, String configKeyName, Object value) {
+        Entity entity = brooklyn().getEntity(application, entityToken);
+        if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.MODIFY_ENTITY, entity)) {
+            throw WebResourceUtils.forbidden("User '%s' is not authorized to modify entity '%s'",
+                    Entitlements.getEntitlementContext().user(), entity);
+        }
+
+        EntityAdjunct adjunct = brooklyn().getAdjunct(entity, adjunctToken);
+        Set<ConfigKey<?>> cki = adjunct.config().findKeysDeclared(ConfigPredicates.nameSatisfies(Predicates.equalTo(configKeyName)));
+        if (cki.isEmpty()) throw WebResourceUtils.notFound("Cannot find config key '%s' in policy '%s' of entity '%s'", configKeyName, adjunctToken, entityToken);
+        ConfigKey<?> ck = cki.iterator().next();
+        
+        adjunct.config().set((ConfigKey) cki, TypeCoercions.coerce(value, ck.getTypeToken()));
+
+        return Response.status(Response.Status.OK).build();
+    }
+
+    public static String getStringValueForDisplay(BrooklynRestResourceUtils utils, EntityAdjunct policy, Object value) {
+        return utils.getStringValueForDisplay(value);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/45261c7e/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyConfigResource.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyConfigResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyConfigResource.java
index 6dcdf19..1fca535 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyConfigResource.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyConfigResource.java
@@ -41,6 +41,7 @@ import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 
 @HaHotStateRequired
+@Deprecated
 public class PolicyConfigResource extends AbstractBrooklynRestResource implements PolicyConfigApi {
 
     @Override

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/45261c7e/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java
index 0b8d2c2..125b0b7 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java
@@ -47,6 +47,7 @@ import com.google.common.collect.FluentIterable;
 import com.google.common.collect.Maps;
 
 @HaHotStateRequired
+@Deprecated
 public class PolicyResource extends AbstractBrooklynRestResource implements PolicyApi {
 
     private static final Logger log = LoggerFactory.getLogger(PolicyResource.class);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/45261c7e/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java
new file mode 100644
index 0000000..db7d4cd
--- /dev/null
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.rest.transform;
+
+import static org.apache.brooklyn.rest.util.WebResourceUtils.serviceUriBuilder;
+
+import java.net.URI;
+import java.util.Map;
+
+import javax.ws.rs.core.UriBuilder;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.objs.EntityAdjunct;
+import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.api.sensor.Feed;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.policy.Policies;
+import org.apache.brooklyn.rest.api.AdjunctApi;
+import org.apache.brooklyn.rest.api.ApplicationApi;
+import org.apache.brooklyn.rest.api.EntityApi;
+import org.apache.brooklyn.rest.domain.AdjunctConfigSummary;
+import org.apache.brooklyn.rest.domain.AdjunctDetail;
+import org.apache.brooklyn.rest.domain.AdjunctSummary;
+import org.apache.brooklyn.rest.domain.ApplicationSummary;
+import org.apache.brooklyn.rest.domain.Status;
+import org.apache.brooklyn.rest.util.BrooklynRestResourceUtils;
+import org.apache.brooklyn.util.collections.MutableMap;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Converts from Brooklyn entities to restful API summary objects
+ */
+public class AdjunctTransformer {
+
+    public static AdjunctSummary adjunctSummary(Entity entity, EntityAdjunct adjunct, UriBuilder ub) {
+        return embellish(new AdjunctSummary(adjunct), entity, adjunct, ub);
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T extends AdjunctSummary> T embellish(T adjunctSummary, Entity entity, EntityAdjunct adjunct, UriBuilder ub) {
+        return (T) adjunctSummary.state(inferStatus(adjunct)).links( buildLinks(entity, adjunct, ub, adjunctSummary instanceof AdjunctDetail) );
+    }
+
+    public static AdjunctDetail adjunctDetail(BrooklynRestResourceUtils utils, Entity entity, EntityAdjunct adjunct, UriBuilder ub) {
+        AdjunctDetail result = embellish(new AdjunctDetail(adjunct), entity, adjunct, ub);
+        for (ConfigKey<?> key: adjunct.config().findKeysDeclared(Predicates.alwaysTrue())) {
+            result.parameter(configSummary(utils, entity, adjunct, key, ub));
+        }
+        result.config(EntityTransformer.getConfigValues(utils, adjunct));
+        return result;
+    }
+
+    protected static Map<String, URI> buildLinks(Entity entity, EntityAdjunct adjunct, UriBuilder ub, boolean detail) {
+        MutableMap<String,URI> links = MutableMap.of();
+
+        links.put("self", serviceUriBuilder(ub, AdjunctApi.class, "get").build(entity.getApplicationId(), entity.getId(), adjunct.getId()));
+        
+        if (detail) {
+            links.put("application", serviceUriBuilder(ub, ApplicationApi.class, "get").build(entity.getApplicationId()));
+            links.put("entity", serviceUriBuilder(ub, EntityApi.class, "get").build(entity.getApplicationId(), entity.getId()));
+            links.put("config", serviceUriBuilder(ub, AdjunctApi.class, "listConfig").build(entity.getApplicationId(), entity.getId(), adjunct.getId()));
+            links.put("status", serviceUriBuilder(ub, AdjunctApi.class, "getStatus").build(entity.getApplicationId(), entity.getId(), adjunct.getId()));
+            if (adjunct instanceof Policy || adjunct instanceof Feed) {
+                links.put("start", serviceUriBuilder(ub, AdjunctApi.class, "start").build(entity.getApplicationId(), entity.getId(), adjunct.getId()));
+                links.put("stop", serviceUriBuilder(ub, AdjunctApi.class, "stop").build(entity.getApplicationId(), entity.getId(), adjunct.getId()));
+            }
+            links.put("destroy", serviceUriBuilder(ub, AdjunctApi.class, "destroy").build(entity.getApplicationId(), entity.getId(), adjunct.getId()));
+        }
+        
+        return links.asUnmodifiable();
+    }
+
+    public static Status inferStatus(EntityAdjunct adjunct) {
+        return ApplicationTransformer.statusFromLifecycle( Policies.inferAdjunctStatus(adjunct) );
+    }
+
+    public static AdjunctConfigSummary configSummary(BrooklynRestResourceUtils utils, ApplicationSummary application, Entity entity, EntityAdjunct adjunct, ConfigKey<?> config, UriBuilder ub) {
+        return configSummary(utils, entity, adjunct, config, ub);
+    }
+
+    public static AdjunctConfigSummary configSummary(BrooklynRestResourceUtils utils, Entity entity, EntityAdjunct adjunct, ConfigKey<?> config, UriBuilder ub) {
+        URI applicationUri = serviceUriBuilder(ub, ApplicationApi.class, "get").build(entity.getApplicationId());
+        URI entityUri = serviceUriBuilder(ub, EntityApi.class, "get").build(entity.getApplicationId(), entity.getId());
+        URI adjunctUri = serviceUriBuilder(ub, AdjunctApi.class, "get").build(entity.getApplicationId(), entity.getId(), adjunct.getId());
+        URI configUri = serviceUriBuilder(ub, AdjunctApi.class, "getConfig").build(entity.getApplicationId(), entity.getId(), adjunct.getId(), config.getName());
+
+        Map<String, URI> links = ImmutableMap.<String, URI>builder()
+                .put("self", configUri)
+                .put("application", applicationUri)
+                .put("entity", entityUri)
+                .put("policy", adjunctUri)
+                .build();
+
+        return new AdjunctConfigSummary(config.getName(), config.getTypeName(), config.getDescription(), 
+                utils.getStringValueForDisplay(config.getDefaultValue()), 
+                config.isReconfigurable(), 
+                links);
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/45261c7e/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/EntityTransformer.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/EntityTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/EntityTransformer.java
index 6bf3f19..cb7877f 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/EntityTransformer.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/EntityTransformer.java
@@ -32,10 +32,12 @@ import javax.ws.rs.core.UriBuilder;
 import org.apache.brooklyn.api.catalog.CatalogConfig;
 import org.apache.brooklyn.api.entity.Application;
 import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.objs.BrooklynObject;
 import org.apache.brooklyn.api.objs.SpecParameter;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.config.render.RendererHints;
+import org.apache.brooklyn.core.objs.BrooklynObjectInternal;
 import org.apache.brooklyn.core.typereg.RegisteredTypes;
 import org.apache.brooklyn.rest.api.ApplicationApi;
 import org.apache.brooklyn.rest.api.CatalogApi;
@@ -46,12 +48,15 @@ import org.apache.brooklyn.rest.domain.EnricherConfigSummary;
 import org.apache.brooklyn.rest.domain.EntityConfigSummary;
 import org.apache.brooklyn.rest.domain.EntitySummary;
 import org.apache.brooklyn.rest.domain.PolicyConfigSummary;
+import org.apache.brooklyn.rest.util.BrooklynRestResourceUtils;
 import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.config.ConfigBag;
 
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
 
 /**
  * @author Adam Lowe
@@ -84,6 +89,7 @@ public class EntityTransformer {
                 .put("config", URI.create(entityUri + "/config"))
                 .put("sensors", URI.create(entityUri + "/sensors"))
                 .put("effectors", URI.create(entityUri + "/effectors"))
+                .put("adjuncts", URI.create(entityUri + "/adjuncts"))
                 .put("policies", URI.create(entityUri + "/policies"))
                 .put("activities", URI.create(entityUri + "/activities"))
                 .put("locations", URI.create(entityUri + "/locations"))
@@ -212,4 +218,19 @@ public class EntityTransformer {
         Double priority = input.isPinned() ? Double.valueOf(1d) : null;
         return enricherConfigSummary(input.getConfigKey(), input.getLabel(), priority, null);
     }
+    
+    public static Map<String, Object> getConfigValues(BrooklynRestResourceUtils utils, BrooklynObject obj) {
+        // alternatively could do this - should be the same ?
+//        for (ConfigKey<?> key: adjunct.config().findKeysPresent(Predicates.alwaysTrue())) {
+//            result.config(key.getName(), utils.getStringValueForDisplay( adjunct.config().get(key) ));
+//        }
+        
+        Map<String, Object> source = ConfigBag.newInstance(
+            ((BrooklynObjectInternal)obj).config().getInternalConfigMap().getAllConfigInheritedRawValuesIgnoringErrors() ).getAllConfig();
+        Map<String, Object> result = Maps.newLinkedHashMap();
+        for (Map.Entry<String, Object> ek : source.entrySet()) {
+            result.put(ek.getKey(), utils.getStringValueForDisplay(ek.getValue()));
+        }
+        return result;
+    }
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/45261c7e/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/PolicyTransformer.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/PolicyTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/PolicyTransformer.java
index 8dad949..294fd41 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/PolicyTransformer.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/PolicyTransformer.java
@@ -25,6 +25,7 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.policy.Policies;
+import org.apache.brooklyn.rest.domain.AdjunctSummary;
 import org.apache.brooklyn.rest.domain.ApplicationSummary;
 import org.apache.brooklyn.rest.domain.PolicyConfigSummary;
 import org.apache.brooklyn.rest.domain.PolicySummary;
@@ -42,7 +43,9 @@ import static org.apache.brooklyn.rest.util.WebResourceUtils.serviceUriBuilder;
 
 /**
  * Converts from Brooklyn entities to restful API summary objects
+ * @deprecated since 0.12.0 use {@link AdjunctTransformer} and {@link AdjunctSummary} 
  */
+@Deprecated
 public class PolicyTransformer {
 
     public static PolicySummary policySummary(Entity entity, Policy policy, UriBuilder ub) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/45261c7e/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java
index 9e1ce53..9b0a3d4 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java
@@ -38,7 +38,10 @@ import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.location.LocationRegistry;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.api.objs.EntityAdjunct;
 import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.api.sensor.Enricher;
+import org.apache.brooklyn.api.sensor.Feed;
 import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry;
 import org.apache.brooklyn.api.typereg.RegisteredType;
 import org.apache.brooklyn.camp.brooklyn.BrooklynCampConstants;
@@ -112,6 +115,16 @@ public class BrooklynRestResourceUtils {
     public Policy getPolicy(String application, String entity, String policy) {
         return getPolicy(getEntity(application, entity), policy);
     }
+    
+    /** finds the policy indicated by the given ID or name.
+     * @see {@link #getEntity(String,String)}; it then searches the policies of that
+     * entity for one whose ID or name matches that given.
+     * <p>
+     * 
+     * @throws 404 or 412 (unless input is null in which case output is null) */
+    public EntityAdjunct getAdjunct(String application, String entity, String adjunct) {
+        return getAdjunct(getEntity(application, entity), adjunct);
+    }
 
     /** finds the policy indicated by the given ID or name.
      * @see {@link #getPolicy(String,String,String)}.
@@ -130,6 +143,36 @@ public class BrooklynRestResourceUtils {
         
         throw WebResourceUtils.notFound("Cannot find policy '%s' in entity '%s'", policy, entity);
     }
+    
+    /** finds the policy indicated by the given ID or name.
+     * @see {@link #getAdjunct(String,String,String)}.
+     * <p>
+     * 
+     * @throws 404 or 412 (unless input is null in which case output is null) */
+    public EntityAdjunct getAdjunct(Entity entity, String adjunct) {
+        if (adjunct==null) return null;
+
+        for (Policy p: entity.policies()) {
+            if (adjunct.equals(p.getId())) return p;
+        }
+        for (Policy p: entity.policies()) {
+            if (adjunct.equals(p.getDisplayName())) return p;
+        }
+        for (Enricher p: entity.enrichers()) {
+            if (adjunct.equals(p.getId())) return p;
+        }
+        for (Enricher p: entity.enrichers()) {
+            if (adjunct.equals(p.getDisplayName())) return p;
+        }
+        for (Feed p: ((EntityInternal)entity).feeds()) {
+            if (adjunct.equals(p.getId())) return p;
+        }
+        for (Feed p: ((EntityInternal)entity).feeds()) {
+            if (adjunct.equals(p.getDisplayName())) return p;
+        }
+        
+        throw WebResourceUtils.notFound("Cannot find adjunct '%s' in entity '%s'", adjunct, entity);
+    }
 
     /** finds the entity indicated by the given ID or name
      * <p>


[15/35] brooklyn-server git commit: more testing of task cancel (in response to jenkins failure)

Posted by he...@apache.org.
more testing of task cancel (in response to jenkins failure)


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

Branch: refs/heads/master
Commit: 5e19dec5180cc22066f91a4c229974e09a9d1ac1
Parents: c1f78bb
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Sep 15 10:52:15 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Sep 15 10:52:15 2017 +0100

----------------------------------------------------------------------
 .../util/core/task/BasicTasksFutureTest.java    | 21 ++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/5e19dec5/core/src/test/java/org/apache/brooklyn/util/core/task/BasicTasksFutureTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/util/core/task/BasicTasksFutureTest.java b/core/src/test/java/org/apache/brooklyn/util/core/task/BasicTasksFutureTest.java
index 442813c..9d53532 100644
--- a/core/src/test/java/org/apache/brooklyn/util/core/task/BasicTasksFutureTest.java
+++ b/core/src/test/java/org/apache/brooklyn/util/core/task/BasicTasksFutureTest.java
@@ -182,21 +182,34 @@ public class BasicTasksFutureTest {
         // if cancel fires after submit but before it passes to the executor,
         // that needs handling separately; this doesn't guarantee this code path,
         // but it happens sometimes (and it should be handled)
+        
+        // have seen this fail once, not getting "before", but can't see why, may be spurious
         doTestCancelTriggersListenableFuture(Duration.ZERO);
     }
+    @Test
+    public void testCancelBeforeTriggersListenableFuture() throws Exception {
+        // if cancel fires after submit but before it passes to the executor,
+        // that needs handling separately; this doesn't guarantee this code path,
+        // but it happens sometimes (and it should be handled)
+        doTestCancelTriggersListenableFuture(Duration.millis(-50));
+    }
     public void doTestCancelTriggersListenableFuture(Duration delay) throws Exception {
         Task<String> t = waitForSemaphore(Duration.TEN_SECONDS, true, "x");
         addFutureListener(t, "before");
 
         Stopwatch watch = Stopwatch.createStarted();
-        ec.submit(t);
+        if (delay.isNegative()) {
+            new Thread(() -> { Time.sleep(delay.multiply(-1)); ec.submit(t); }).run(); 
+        } else {
+            ec.submit(t);
+        }
         
         addFutureListener(t, "during");
 
         log.info("test cancelling "+t+" ("+t.getClass()+") after "+delay);
-        // NB: two different code paths (callers to this method) for notifying futures 
-        // depending whether task is started 
-        Time.sleep(delay);
+        // NB: three different code paths (callers to this method) for notifying futures 
+        // depending whether task is started before, at, or after the cancel 
+        if (!delay.isNegative()) Time.sleep(delay);
 
         synchronized (data) {
             t.cancel(true);