You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by ge...@apache.org on 2016/12/20 11:10:22 UTC

[04/13] brooklyn-server git commit: Non-recursive ValueResolver

Non-recursive ValueResolver


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

Branch: refs/heads/master
Commit: 42bc7c136ec885cc43125edfee86a741793aa64b
Parents: ddfe733
Author: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Authored: Mon Dec 12 18:02:16 2016 +0200
Committer: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Committed: Tue Dec 13 09:15:36 2016 +0200

----------------------------------------------------------------------
 .../brooklyn/util/core/task/ValueResolver.java  | 37 ++++++++-
 .../util/core/task/ValueResolverTest.java       | 83 +++++++++++++++++++-
 2 files changed, 116 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/42bc7c13/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 6775a44..4dcf5be 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
@@ -31,6 +31,7 @@ import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.api.mgmt.TaskAdaptable;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
+import org.apache.brooklyn.core.mgmt.rebind.ImmediateDeltaChangeListener;
 import org.apache.brooklyn.util.core.flags.TypeCoercions;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.guava.Maybe;
@@ -110,6 +111,7 @@ public class ValueResolver<T> implements DeferredSupplier<T> {
     /** timeout on execution, if possible, or if embedResolutionInTask is true */
     Duration timeout;
     boolean immediately;
+    boolean recursive = true;
     boolean isTransientTask = true;
     
     T defaultValue = null;
@@ -144,6 +146,7 @@ public class ValueResolver<T> implements DeferredSupplier<T> {
 
         timeout = parent.timeout;
         immediately = parent.immediately;
+        // not copying recursive as we want deep resolving to be recursive, only top-level values should be non-recursive
         parentTimer = parent.parentTimer;
         if (parentTimer!=null && parentTimer.isExpired())
             expired = true;
@@ -167,7 +170,9 @@ public class ValueResolver<T> implements DeferredSupplier<T> {
             .context(exec).description(description)
             .embedResolutionInTask(embedResolutionInTask)
             .deep(forceDeep)
-            .timeout(timeout);
+            .timeout(timeout)
+            .immediately(immediately)
+            .recursive(recursive);
         if (returnDefaultOnGet) result.defaultValue(defaultValue);
         if (swallowExceptions) result.swallowExceptions();
         return result;
@@ -264,6 +269,18 @@ public class ValueResolver<T> implements DeferredSupplier<T> {
         return this;
     }
 
+    /**
+     * Whether the value should be resolved recursively. When true the result of
+     * the resolving will be resolved again recursively until the value is an immediate object.
+     * When false will try to resolve the value a single time and return the result even if it
+     * can be resolved further (e.x. it is DeferredSupplier).
+     */
+    @Beta
+    public ValueResolver<T> recursive(boolean val) {
+        this.recursive = val;
+        return this;
+    }
+
     protected void checkTypeNotNull() {
         if (type==null) 
             throw new NullPointerException("type must be set to resolve, for '"+value+"'"+(description!=null ? ", "+description : ""));
@@ -297,6 +314,11 @@ public class ValueResolver<T> implements DeferredSupplier<T> {
             exec = BasicExecutionContext.getCurrentExecutionContext();
         }
         
+        if (!recursive && type != Object.class) {
+            throw new IllegalStateException("When non-recursive resolver requested the return type must be Object " +
+                    "as the immediately resolved value could be a number of (deferred) types.");
+        }
+        
         CountdownTimer timerU = parentTimer;
         if (timerU==null && timeout!=null)
             timerU = timeout.countdownTimer();
@@ -319,7 +341,11 @@ public class ValueResolver<T> implements DeferredSupplier<T> {
                     Maybe<?> result = supplier.getImmediately();
                     
                     // Recurse: need to ensure returned value is cast, etc
-                    return (result.isPresent()) ? new ValueResolver(result.get(), type, this).getMaybe() : Maybe.<T>absent();
+                    return (result.isPresent())
+                            ? recursive
+                                ? new ValueResolver(result.get(), type, this).getMaybe()
+                                : result
+                            : Maybe.<T>absent();
                 } catch (ImmediateSupplier.ImmediateUnsupportedException e) {
                     log.debug("Unable to resolve-immediately for "+description+" ("+v+"); falling back to executing with timeout", e);
                 }
@@ -455,7 +481,12 @@ public class ValueResolver<T> implements DeferredSupplier<T> {
             throw problem;
         }
         
-        return new ValueResolver(v, type, this).getMaybe();
+        if (recursive) {
+            return new ValueResolver(v, type, this).getMaybe();
+        } else {
+            // T expected to be Object.class
+            return (Maybe<T>) Maybe.of(v);
+        }
     }
 
     protected String getDescription() {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/42bc7c13/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 b7e9085..ffe6762 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
@@ -172,7 +172,55 @@ public class ValueResolverTest extends BrooklynAppUnitTestSupport {
         assertEquals(BrooklynTaskTags.getContextEntity(callInfo.task), app);
         assertNotContainsCallingMethod(callInfo.stackTrace, "testGetImmediatelyFallsBackToDeferredCallInTask");
     }
-    
+
+    public void testNonRecursiveBlockingFailsOnNonObjectType() throws Exception {
+        try {
+            Tasks.resolving(new WrappingImmediateAndDeferredSupplier(new FailingImmediateAndDeferredSupplier()))
+                .as(FailingImmediateAndDeferredSupplier.class)
+                .context(app)
+                .immediately(false)
+                .recursive(false)
+                .get();
+            Asserts.shouldHaveFailedPreviously("recursive(true) accepts only as(Object.class)");
+        } catch (IllegalStateException e) {
+            Asserts.expectedFailureContains(e, "must be Object");
+        }
+    }
+
+    public void testNonRecursiveBlocking() throws Exception {
+        Object result = Tasks.resolving(new WrappingImmediateAndDeferredSupplier(new FailingImmediateAndDeferredSupplier()))
+            .as(Object.class)
+            .context(app)
+            .immediately(false)
+            .recursive(false)
+            .get();
+        assertEquals(result.getClass(), FailingImmediateAndDeferredSupplier.class);
+    }
+
+    public void testNonRecursiveImmediateFailsOnNonObjectType() throws Exception {
+        try {
+            Tasks.resolving(new WrappingImmediateAndDeferredSupplier(new FailingImmediateAndDeferredSupplier()))
+                .as(FailingImmediateAndDeferredSupplier.class)
+                .context(app)
+                .immediately(true)
+                .recursive(false)
+                .get();
+            Asserts.shouldHaveFailedPreviously("recursive(true) accepts only as(Object.class)");
+        } catch (IllegalStateException e) {
+            Asserts.expectedFailureContains(e, "must be Object");
+        }
+    }
+
+    public void testNonRecursiveImmediately() throws Exception {
+        Object result = Tasks.resolving(new WrappingImmediateAndDeferredSupplier(new FailingImmediateAndDeferredSupplier()))
+                .as(Object.class)
+                .context(app)
+                .immediately(true)
+                .recursive(false)
+                .get();
+            assertEquals(result.getClass(), FailingImmediateAndDeferredSupplier.class);
+    }
+
     private static class MyImmediateAndDeferredSupplier implements ImmediateSupplier<CallInfo>, DeferredSupplier<CallInfo> {
         private final boolean failImmediately;
         
@@ -198,6 +246,39 @@ public class ValueResolverTest extends BrooklynAppUnitTestSupport {
         }
     }
     
+    private static class WrappingImmediateAndDeferredSupplier implements ImmediateSupplier<Object>, DeferredSupplier<Object> {
+        private Object value;
+
+        public WrappingImmediateAndDeferredSupplier(Object value) {
+            this.value = value;
+        }
+
+        @Override
+        public Object get() {
+            return getImmediately().get();
+        }
+
+        @Override
+        public Maybe<Object> getImmediately() {
+            return Maybe.of(value);
+        }
+        
+    }
+
+    private static class FailingImmediateAndDeferredSupplier implements ImmediateSupplier<Object>, DeferredSupplier<Object> {
+
+        @Override
+        public Object get() {
+            throw new IllegalStateException("Not to be called");
+        }
+
+        @Override
+        public Maybe<Object> getImmediately() {
+            throw new IllegalStateException("Not to be called");
+        }
+        
+    }
+
     private static class CallInfo {
         final StackTraceElement[] stackTrace;
         final Task<?> task;