You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2015/06/15 09:41:28 UTC

[04/10] incubator-brooklyn git commit: better REST coercion and coerce String->Date

better REST coercion and coerce String->Date

wrt REST this improves how deferred suppliers are evaluated,
both timing and in entity's execution context


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

Branch: refs/heads/master
Commit: 30c3029ef22bb387ef121cc043bcfd495cfc9837
Parents: 9fe4c7c
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Thu Jun 4 16:53:41 2015 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Jun 10 18:38:17 2015 +0100

----------------------------------------------------------------------
 .../java/brooklyn/catalog/BrooklynCatalog.java  |  1 +
 .../brooklyn/config/render/RendererHints.java   | 10 +--
 .../brooklyn/enricher/basic/Transformer.java    |  3 +-
 .../java/brooklyn/util/flags/TypeCoercions.java |  8 +++
 .../java/brooklyn/util/task/ValueResolver.java  | 11 +++
 .../resources/AbstractBrooklynRestResource.java | 72 +++++++++++++++++---
 .../rest/resources/EffectorResource.java        |  2 +-
 .../rest/resources/EntityConfigResource.java    | 15 ++--
 .../brooklyn/rest/resources/EntityResource.java |  4 +-
 .../brooklyn/rest/resources/SensorResource.java | 13 ++--
 .../brooklyn/rest/resources/UsageResource.java  |  2 +-
 .../rest/transform/EffectorTransformer.java     |  2 +-
 12 files changed, 102 insertions(+), 41 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/30c3029e/api/src/main/java/brooklyn/catalog/BrooklynCatalog.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/catalog/BrooklynCatalog.java b/api/src/main/java/brooklyn/catalog/BrooklynCatalog.java
index 82b865d..19d0fa9 100644
--- a/api/src/main/java/brooklyn/catalog/BrooklynCatalog.java
+++ b/api/src/main/java/brooklyn/catalog/BrooklynCatalog.java
@@ -75,6 +75,7 @@ public interface BrooklynCatalog {
     public ClassLoader getRootClassLoader();
 
     /** creates a spec for the given catalog item, throwing exceptions if any problems */
+    // TODO this should be cached on the item and renamed getSpec(...), else we re-create it too often (every time catalog is listed)
     <T,SpecT> SpecT createSpec(CatalogItem<T,SpecT> item);
     
     /** throws exceptions if any problems 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/30c3029e/core/src/main/java/brooklyn/config/render/RendererHints.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/config/render/RendererHints.java b/core/src/main/java/brooklyn/config/render/RendererHints.java
index 247b4f4..60f89d7 100644
--- a/core/src/main/java/brooklyn/config/render/RendererHints.java
+++ b/core/src/main/java/brooklyn/config/render/RendererHints.java
@@ -113,13 +113,15 @@ public class RendererHints {
     }
 
     /** Applies the (first) display value hint registered against the given target to the given initialValue */  
-    public static Object applyDisplayValueHint(AttributeSensor<?> target, Object initialValue) { return _applyDisplayValueHint(target, initialValue); }
+    public static Object applyDisplayValueHint(AttributeSensor<?> target, Object initialValue) { return applyDisplayValueHintUnchecked(target, initialValue); }
     /** as {@link #applyDisplayValueHint(AttributeSensor, Object)} */
-    public static Object applyDisplayValueHint(ConfigKey<?> target, Object initialValue) { return _applyDisplayValueHint(target, initialValue); }
+    public static Object applyDisplayValueHint(ConfigKey<?> target, Object initialValue) { return applyDisplayValueHintUnchecked(target, initialValue); }
     /** as {@link #applyDisplayValueHint(AttributeSensor, Object)} */
-    public static Object applyDisplayValueHint(Class<?> target, Object initialValue) { return _applyDisplayValueHint(target, initialValue); }
+    public static Object applyDisplayValueHint(Class<?> target, Object initialValue) { return applyDisplayValueHintUnchecked(target, initialValue); }
     
-    private static Object _applyDisplayValueHint(Object target, Object initialValue) { return _applyDisplayValueHint(target, initialValue, true); }
+    /** as {@link #applyDisplayValueHint(AttributeSensor, Object)}, but without type checking; public for those few cases where we may have lost the type */
+    @Beta
+    public static Object applyDisplayValueHintUnchecked(Object target, Object initialValue) { return _applyDisplayValueHint(target, initialValue, true); }
     @SuppressWarnings("rawtypes")
     private static Object _applyDisplayValueHint(Object target, Object initialValue, boolean includeClass) {
         Iterable<RendererHints.DisplayValue> hints = RendererHints._getHintsFor(target, RendererHints.DisplayValue.class);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/30c3029e/core/src/main/java/brooklyn/enricher/basic/Transformer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/Transformer.java b/core/src/main/java/brooklyn/enricher/basic/Transformer.java
index 224f201..c6c88a6 100644
--- a/core/src/main/java/brooklyn/enricher/basic/Transformer.java
+++ b/core/src/main/java/brooklyn/enricher/basic/Transformer.java
@@ -26,7 +26,6 @@ import org.slf4j.LoggerFactory;
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.Entity;
 import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.basic.EntityInternal;
 import brooklyn.entity.basic.EntityLocal;
 import brooklyn.event.AttributeSensor;
 import brooklyn.event.Sensor;
@@ -135,7 +134,7 @@ public class Transformer<T,U> extends AbstractEnricher implements SensorEventLis
                 // external events; they can submit tasks and block on them (or even better, have a callback architecture);
                 // however that is a non-trivial refactoring
                 return (U) Tasks.resolving(targetValueRaw).as(targetSensor.getType())
-                    .context( ((EntityInternal)entity).getExecutionContext() )
+                    .context(entity)
                     .description("Computing sensor "+targetSensor+" from "+targetValueRaw)
                     .timeout(Duration.millis(200))
                     .getMaybe().orNull();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/30c3029e/core/src/main/java/brooklyn/util/flags/TypeCoercions.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/flags/TypeCoercions.java b/core/src/main/java/brooklyn/util/flags/TypeCoercions.java
index d93528a..dcc00e8 100644
--- a/core/src/main/java/brooklyn/util/flags/TypeCoercions.java
+++ b/core/src/main/java/brooklyn/util/flags/TypeCoercions.java
@@ -32,6 +32,7 @@ import java.net.InetAddress;
 import java.net.URI;
 import java.net.URL;
 import java.util.Collection;
+import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -63,6 +64,7 @@ import brooklyn.util.net.UserAndHostAndPort;
 import brooklyn.util.text.StringEscapes.JavaStringEscapes;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;
+import brooklyn.util.time.Time;
 import brooklyn.util.yaml.Yamls;
 
 import com.google.common.base.CaseFormat;
@@ -695,6 +697,12 @@ public class TypeCoercions {
                 return BigInteger.valueOf(input);
             }
         });
+        registerAdapter(String.class, Date.class, new Function<String,Date>() {
+            @Override
+            public Date apply(final String input) {
+                return Time.parseDate(input);
+            }
+        });
         registerAdapter(String.class, Class.class, new Function<String,Class>() {
             @Override
             public Class apply(final String input) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/30c3029e/core/src/main/java/brooklyn/util/task/ValueResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ValueResolver.java b/core/src/main/java/brooklyn/util/task/ValueResolver.java
index cf95650..3a15bbd 100644
--- a/core/src/main/java/brooklyn/util/task/ValueResolver.java
+++ b/core/src/main/java/brooklyn/util/task/ValueResolver.java
@@ -28,6 +28,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import brooklyn.entity.Entity;
+import brooklyn.entity.basic.EntityInternal;
 import brooklyn.management.ExecutionContext;
 import brooklyn.management.Task;
 import brooklyn.management.TaskAdaptable;
@@ -130,6 +132,10 @@ public class ValueResolver<T> implements DeferredSupplier<T> {
         this.exec = exec;
         return this;
     }
+    /** as {@link #context(ExecutionContext)} for use from an entity */
+    public ValueResolver<T> context(Entity entity) {
+        return context(entity!=null ? ((EntityInternal)entity).getExecutionContext() : null);
+    }
     
     /** sets a message which will be displayed in status reports while it waits (e.g. the name of the config key being looked up) */
     public ValueResolver<T> description(String description) {
@@ -279,6 +285,11 @@ public class ValueResolver<T> implements DeferredSupplier<T> {
                         
                     String description = getDescription();
                     Task<Object> vt = exec.submit(Tasks.<Object>builder().body(callable).name("Resolving dependent value").description(description).build());
+                    // TODO to handle immediate resolution, it would be nice to be able to submit 
+                    // so it executes in the current thread,
+                    // or put a marker in the target thread or task while it is running that the task 
+                    // should never wait on anything other than another value being resolved 
+                    // (though either could recurse infinitely) 
                     Maybe<Object> vm = Durations.get(vt, timer);
                     vt.cancel(true);
                     if (vm.isAbsent()) return (Maybe<T>)vm;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/30c3029e/usage/rest-server/src/main/java/brooklyn/rest/resources/AbstractBrooklynRestResource.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/resources/AbstractBrooklynRestResource.java b/usage/rest-server/src/main/java/brooklyn/rest/resources/AbstractBrooklynRestResource.java
index 0f49caf..d9dee55 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/resources/AbstractBrooklynRestResource.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/resources/AbstractBrooklynRestResource.java
@@ -20,6 +20,7 @@ package brooklyn.rest.resources;
 
 import io.brooklyn.camp.CampPlatform;
 
+import javax.annotation.Nullable;
 import javax.servlet.ServletContext;
 import javax.ws.rs.core.Context;
 
@@ -27,6 +28,9 @@ import org.codehaus.jackson.map.ObjectMapper;
 
 import brooklyn.config.BrooklynServerConfig;
 import brooklyn.config.BrooklynServiceAttributes;
+import brooklyn.config.render.RendererHints;
+import brooklyn.entity.Entity;
+import brooklyn.entity.basic.EntityLocal;
 import brooklyn.management.ManagementContext;
 import brooklyn.management.ManagementContextInjectable;
 import brooklyn.rest.util.BrooklynRestResourceUtils;
@@ -36,13 +40,8 @@ import brooklyn.util.guava.Maybe;
 import brooklyn.util.task.Tasks;
 import brooklyn.util.time.Duration;
 
-import com.google.common.annotations.VisibleForTesting;
-
 public abstract class AbstractBrooklynRestResource implements ManagementContextInjectable {
 
-    @VisibleForTesting
-    public static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZ";
-    
     // can be injected by jersey when ManagementContext in not injected manually
     // (seems there is no way to make this optional so note it _must_ be injected;
     // most of the time that happens for free, but with test framework it doesn't,
@@ -85,15 +84,66 @@ public abstract class AbstractBrooklynRestResource implements ManagementContextI
         return mapper;
     }
 
-    /** returns an object which jersey will handle nicely, converting to json,
-     * sometimes wrapping in quotes if needed (for outermost json return types) */ 
+    /** @deprecated since 0.7.0 use {@link #getValueForDisplay(Object, boolean, boolean, Boolean, EntityLocal, Duration)} */ @Deprecated
     protected Object getValueForDisplay(Object value, boolean preferJson, boolean isJerseyReturnValue) {
-        Object immediate = getImmediateValue(value);
-        return WebResourceUtils.getValueForDisplay(mapper(), immediate, preferJson, isJerseyReturnValue);
+        return resolving(value).preferJson(preferJson).asJerseyOutermostReturnValue(isJerseyReturnValue).resolve();
+    }
+
+    protected RestValueResolver resolving(Object v) {
+        return new RestValueResolver(v).mapper(mapper());
     }
 
-    private Object getImmediateValue(Object value) {
-        return Tasks.resolving(value).as(Object.class).defaultValue(null).timeout(Duration.ZERO).swallowExceptions().get();
+    public static class RestValueResolver {
+        final private Object valueToResolve;
+        private @Nullable ObjectMapper mapper;
+        private boolean preferJson;
+        private boolean isJerseyReturnValue;
+        private @Nullable Boolean raw; 
+        private @Nullable Entity entity;
+        private @Nullable Duration timeout;
+        private @Nullable Object rendererHintSource;
+        
+        public static RestValueResolver resolving(Object v) { return new RestValueResolver(v); }
+        
+        private RestValueResolver(Object v) { valueToResolve = v; }
+        
+        public RestValueResolver mapper(ObjectMapper mapper) { this.mapper = mapper; return this; }
+        
+        /** whether JSON is the ultimate product; 
+         * main effect here is to give null for null if true, else to give empty string 
+         * <p>
+         * conversion to JSON for complex types is done subsequently (often by the framework)
+         * <p>
+         * default is true */
+        public RestValueResolver preferJson(boolean preferJson) { this.preferJson = preferJson; return this; }
+        /** whether an outermost string must be wrapped in quotes, because a String return object is treated as
+         * already JSON-encoded
+         * <p>
+         * default is false */
+        public RestValueResolver asJerseyOutermostReturnValue(boolean asJerseyReturnJson) {
+            isJerseyReturnValue = asJerseyReturnJson;
+            return this;
+        }
+        public RestValueResolver raw(Boolean raw) { this.raw = raw; return this; }
+        public RestValueResolver context(Entity entity) { this.entity = entity; return this; }
+        public RestValueResolver timeout(Duration timeout) { this.timeout = timeout; return this; }
+        public RestValueResolver renderAs(Object rendererHintSource) { this.rendererHintSource = rendererHintSource; return this; }
+
+        public Object resolve() {
+            Object valueResult = getImmediateValue(valueToResolve, entity);
+            if (valueResult==UNRESOLVED) valueResult = valueToResolve;
+            if (rendererHintSource!=null && Boolean.FALSE.equals(raw)) {
+                valueResult = RendererHints.applyDisplayValueHintUnchecked(rendererHintSource, valueResult);
+            }
+            return WebResourceUtils.getValueForDisplay(mapper, valueResult, preferJson, isJerseyReturnValue);
+        }
+        
+        private static Object UNRESOLVED = "UNRESOLVED".toCharArray();
+        
+        private static Object getImmediateValue(Object value, @Nullable Entity context) {
+            return Tasks.resolving(value).as(Object.class).defaultValue(UNRESOLVED).timeout(Duration.ZERO).context(context).swallowExceptions().get();
+        }
+
     }
 
     protected CampPlatform camp() {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/30c3029e/usage/rest-server/src/main/java/brooklyn/rest/resources/EffectorResource.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/resources/EffectorResource.java b/usage/rest-server/src/main/java/brooklyn/rest/resources/EffectorResource.java
index 2cfd8f6..69ded4e 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/resources/EffectorResource.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/resources/EffectorResource.java
@@ -98,7 +98,7 @@ public class EffectorResource extends AbstractBrooklynRestResource implements Ef
             if (timeout == null || timeout.isEmpty() || "never".equalsIgnoreCase(timeout)) {
                 result = t.get();
             } else {
-                long timeoutMillis = "always".equalsIgnoreCase(timeout) ? 0 : Time.parseTimeString(timeout);
+                long timeoutMillis = "always".equalsIgnoreCase(timeout) ? 0 : Time.parseElapsedTime(timeout);
                 try {
                     if (timeoutMillis == 0) throw new TimeoutException();
                     result = t.get(timeoutMillis, TimeUnit.MILLISECONDS);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/30c3029e/usage/rest-server/src/main/java/brooklyn/rest/resources/EntityConfigResource.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/resources/EntityConfigResource.java b/usage/rest-server/src/main/java/brooklyn/rest/resources/EntityConfigResource.java
index 0984ebf..219d67a 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/resources/EntityConfigResource.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/resources/EntityConfigResource.java
@@ -27,7 +27,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.config.ConfigKey;
-import brooklyn.config.render.RendererHints;
 import brooklyn.entity.Entity;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.EntityInternal;
@@ -41,6 +40,7 @@ import brooklyn.rest.transform.EntityTransformer;
 import brooklyn.rest.util.WebResourceUtils;
 import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.text.Strings;
+import brooklyn.util.time.Duration;
 
 import com.google.common.base.Function;
 import com.google.common.base.Predicates;
@@ -55,7 +55,7 @@ public class EntityConfigResource extends AbstractBrooklynRestResource implement
     @Override
     public List<EntityConfigSummary> list(final String application, final String entityToken) {
         final EntityLocal entity = brooklyn().getEntity(application, entityToken);
-
+        // TODO merge with keys which have values
         return Lists.newArrayList(transform(
                 entity.getEntityType().getConfigKeys(),
                 new Function<ConfigKey<?>, EntityConfigSummary>() {
@@ -76,10 +76,8 @@ public class EntityConfigResource extends AbstractBrooklynRestResource implement
         Map<String, Object> result = Maps.newLinkedHashMap();
         for (Map.Entry<ConfigKey<?>, ?> ek : source.entrySet()) {
             Object value = ek.getValue();
-            if (Boolean.FALSE.equals(raw)) {
-                value = RendererHints.applyDisplayValueHint(ek.getKey(), value);
-            }
-            result.put(ek.getKey().getName(), getValueForDisplay(value, true, false));
+            result.put(ek.getKey().getName(), 
+                resolving(value).preferJson(true).asJerseyOutermostReturnValue(false).raw(raw).context(entity).timeout(Duration.ZERO).renderAs(ek.getKey()).resolve());
         }
         return result;
     }
@@ -98,10 +96,7 @@ public class EntityConfigResource extends AbstractBrooklynRestResource implement
         EntityLocal entity = brooklyn().getEntity(application, entityToken);
         ConfigKey<?> ck = findConfig(entity, configKeyName);
         Object value = ((EntityInternal)entity).config().getRaw(ck).orNull();
-        if (Boolean.FALSE.equals(raw)) {
-            value = RendererHints.applyDisplayValueHint(ck, value);
-        }
-        return getValueForDisplay(value, preferJson, true);
+        return resolving(value).preferJson(preferJson).asJerseyOutermostReturnValue(true).raw(raw).context(entity).timeout(Duration.millis(100)).renderAs(ck).resolve();
     }
 
     private ConfigKey<?> findConfig(EntityLocal entity, String configKeyName) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/30c3029e/usage/rest-server/src/main/java/brooklyn/rest/resources/EntityResource.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/resources/EntityResource.java b/usage/rest-server/src/main/java/brooklyn/rest/resources/EntityResource.java
index 3e94068..eb677e2 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/resources/EntityResource.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/resources/EntityResource.java
@@ -155,7 +155,7 @@ public class EntityResource extends AbstractBrooklynRestResource implements Enti
     @Override
     public List<Object> listTags(String applicationId, String entityId) {
         Entity entity = brooklyn().getEntity(applicationId, entityId);
-        return (List<Object>) getValueForDisplay(MutableList.copyOf(entity.tags().getTags()), true, true);
+        return (List<Object>) resolving(MutableList.copyOf(entity.tags().getTags())).preferJson(true).resolve();
     }
 
     @Override
@@ -220,6 +220,6 @@ public class EntityResource extends AbstractBrooklynRestResource implements Enti
         NamedStringTag spec = BrooklynTags.findFirst(BrooklynTags.YAML_SPEC_KIND, entity.tags().getTags());
         if (spec == null)
             return null;
-        return (String) getValueForDisplay(spec.getContents(), true, true);
+        return (String) WebResourceUtils.getValueForDisplay(spec.getContents(), true, true);
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/30c3029e/usage/rest-server/src/main/java/brooklyn/rest/resources/SensorResource.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/resources/SensorResource.java b/usage/rest-server/src/main/java/brooklyn/rest/resources/SensorResource.java
index 708685d..6e49acc 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/resources/SensorResource.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/resources/SensorResource.java
@@ -27,7 +27,6 @@ import java.util.Map;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import brooklyn.config.render.RendererHints;
 import brooklyn.entity.basic.EntityInternal;
 import brooklyn.entity.basic.EntityLocal;
 import brooklyn.event.AttributeSensor;
@@ -40,6 +39,7 @@ import brooklyn.rest.filter.HaHotStateRequired;
 import brooklyn.rest.transform.SensorTransformer;
 import brooklyn.rest.util.WebResourceUtils;
 import brooklyn.util.text.Strings;
+import brooklyn.util.time.Duration;
 
 import com.google.common.base.Function;
 import com.google.common.collect.Lists;
@@ -73,10 +73,8 @@ public class SensorResource extends AbstractBrooklynRestResource implements Sens
 
         for (AttributeSensor<?> sensor : sensors) {
             Object value = entity.getAttribute(findSensor(entity, sensor.getName()));
-            if (Boolean.FALSE.equals(raw)) {
-                value = RendererHints.applyDisplayValueHint(sensor, value);
-            }
-            sensorMap.put(sensor.getName(), getValueForDisplay(value, true, false));
+            sensorMap.put(sensor.getName(), 
+                resolving(value).preferJson(true).asJerseyOutermostReturnValue(false).raw(raw).context(entity).timeout(Duration.ZERO).renderAs(sensor).resolve());
         }
         return sensorMap;
     }
@@ -85,10 +83,7 @@ public class SensorResource extends AbstractBrooklynRestResource implements Sens
         final EntityLocal entity = brooklyn().getEntity(application, entityToken);
         AttributeSensor<?> sensor = findSensor(entity, sensorName);
         Object value = entity.getAttribute(sensor);
-        if (Boolean.FALSE.equals(raw)) {
-            value = RendererHints.applyDisplayValueHint(sensor, value);
-        }
-        return getValueForDisplay(value, preferJson, true);
+        return resolving(value).preferJson(preferJson).asJerseyOutermostReturnValue(true).raw(raw).context(entity).timeout(Duration.millis(100)).renderAs(sensor).resolve();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/30c3029e/usage/rest-server/src/main/java/brooklyn/rest/resources/UsageResource.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/resources/UsageResource.java b/usage/rest-server/src/main/java/brooklyn/rest/resources/UsageResource.java
index 88dfe3a..4251712 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/resources/UsageResource.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/resources/UsageResource.java
@@ -256,7 +256,7 @@ public class UsageResource extends AbstractBrooklynRestResource implements Usage
     }
 
     private Date parseDate(String toParse, Date def) {
-        return (toParse == null) ? def : Time.parseDateString(toParse, DATE_FORMATTER.get());
+        return (toParse == null) ? def : Time.parseDate(toParse, DATE_FORMATTER.get());
     }
     
     private String format(Date date) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/30c3029e/usage/rest-server/src/main/java/brooklyn/rest/transform/EffectorTransformer.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/transform/EffectorTransformer.java b/usage/rest-server/src/main/java/brooklyn/rest/transform/EffectorTransformer.java
index 1d15abe..925ed8f 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/transform/EffectorTransformer.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/transform/EffectorTransformer.java
@@ -76,7 +76,7 @@ public class EffectorTransformer {
     protected static EffectorSummary.ParameterSummary<?> parameterSummary(Entity entity, ParameterType<?> parameterType) {
         try {
             Maybe<?> defaultValue = Tasks.resolving(parameterType.getDefaultValue()).as(parameterType.getParameterClass())
-                .context(entity!=null ? ((EntityInternal)entity).getExecutionContext() : null).timeout(Duration.millis(50)).getMaybe();
+                .context(entity).timeout(Duration.millis(50)).getMaybe();
             return new ParameterSummary(parameterType.getName(), parameterType.getParameterClassName(), 
                 parameterType.getDescription(), 
                 WebResourceUtils.getValueForDisplay(defaultValue.orNull(), true, false));