Repository: brooklyn-server
Updated Branches:
  refs/heads/master dc5bc6d19 -> a4e69956e


Add iterator to ValueResolver

Resolves the initial object iteratively until either failure or object can't be 
resolved any more.


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

Branch: refs/heads/master
Commit: 5f66e8fe4ecdf91a8121ff6e16da4ca0607cf0f1
Parents: 972a0d8
Author: Svetoslav Neykov <svetoslav.ney...@cloudsoftcorp.com>
Authored: Mon Jan 16 18:37:46 2017 +0200
Committer: Svetoslav Neykov <svetoslav.ney...@cloudsoftcorp.com>
Committed: Mon Jan 23 18:16:49 2017 +0200

----------------------------------------------------------------------
 .../spi/dsl/DslDeferredFunctionCall.java        |  30 +--
 .../brooklyn/util/core/task/ValueResolver.java  |  37 +++-
 .../util/core/task/ValueResolverIterator.java   | 196 +++++++++++++++++
 .../core/task/ValueResolverIteratorTest.java    | 217 +++++++++++++++++++
 .../util/core/task/ValueResolverTest.java       |   4 +-
 5 files changed, 451 insertions(+), 33 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/5f66e8fe/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslDeferredFunctionCall.java
----------------------------------------------------------------------
diff --git 
a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslDeferredFunctionCall.java
 
b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslDeferredFunctionCall.java
index f511926..0b2963d 100644
--- 
a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslDeferredFunctionCall.java
+++ 
b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslDeferredFunctionCall.java
@@ -25,7 +25,6 @@ import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.BrooklynDslCommon;
-import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
 import org.apache.brooklyn.util.core.task.Tasks;
 import org.apache.brooklyn.util.exceptions.Exceptions;
@@ -142,29 +141,12 @@ public class DslDeferredFunctionCall extends 
BrooklynDslDeferredSupplier<Object>
     }
 
     protected Maybe<?> resolve(Object object, boolean immediate) {
-        if (object instanceof DslFunctionSource || object == null) {
-            return Maybe.of(object);
-        }
-
-        Maybe<?> resultMaybe = Tasks.resolving(object, Object.class)
-                .context(entity().getExecutionContext())
-                .deep(true)
-                .immediately(immediate)
-                .recursive(false)
-                .getMaybe();
-
-        if (resultMaybe.isPresent()) {
-            // No nice way to figure out whether the object is deferred. Try 
to resolve it
-            // until it matches the input value as a poor man's replacement.
-            Object result = resultMaybe.get();
-            if (result == object) {
-                return resultMaybe;
-            } else {
-                return resolve(result, immediate);
-            }
-        } else {
-            return resultMaybe;
-        }
+        return Tasks.resolving(object, Object.class)
+            .context(entity().getExecutionContext())
+            .deep(true)
+            .immediately(immediate)
+            .iterator()
+            .nextOrLast(DslFunctionSource.class);
     }
 
     private static void checkCallAllowed(Method m) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/5f66e8fe/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 650ccc9..f81594e 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
@@ -56,7 +56,7 @@ import com.google.common.reflect.TypeToken;
  * <p>
  * Fluent-style API exposes a number of other options.
  */
-public class ValueResolver<T> implements DeferredSupplier<T> {
+public class ValueResolver<T> implements DeferredSupplier<T>, 
Iterable<Maybe<Object>> {
 
     // TODO most of these usages should be removed when we have
     // an ability to run resolution in a non-blocking mode
@@ -166,14 +166,29 @@ public class ValueResolver<T> implements 
DeferredSupplier<T> {
     /** returns a copy of this resolver which can be queried, even if the 
original (single-use instance) has already been copied */
     @Override
     public ValueResolver<T> clone() {
-        ValueResolver<T> result = new ValueResolver<T>(value, type)
+        return cloneReplacingValueAndType(value, type);
+    }
+    
+    <S> ValueResolver<S> cloneReplacingValueAndType(Object newValue, Class<S> 
superType) {
+        // superType expected to be either type or Object.class
+        if (!superType.isAssignableFrom(type)) {
+            throw new IllegalStateException("superType must be assignable from 
" + type);
+        }
+        ValueResolver<S> result = new ValueResolver<S>(newValue, superType)
             .context(exec).description(description)
             .embedResolutionInTask(embedResolutionInTask)
             .deep(forceDeep)
             .timeout(timeout)
             .immediately(immediately)
             .recursive(recursive);
-        if (returnDefaultOnGet) result.defaultValue(defaultValue);
+        if (returnDefaultOnGet) {
+            if (!superType.isInstance(defaultValue)) {
+                throw new IllegalStateException("Existing default value " + 
defaultValue + " not compatible with new type " + superType);
+            }
+            @SuppressWarnings("unchecked")
+            S typedDefaultValue = (S)defaultValue;
+            result.defaultValue(typedDefaultValue);
+        }
         if (swallowExceptions) result.swallowExceptions();
         return result;
     }
@@ -287,13 +302,18 @@ public class ValueResolver<T> implements 
DeferredSupplier<T> {
     }
 
     @Override
+    public ValueResolverIterator<T> iterator() {
+        return new ValueResolverIterator<T>(this);
+    }
+
+    @Override
     public T get() {
         Maybe<T> m = getMaybe();
         if (m.isPresent()) return m.get();
         if (returnDefaultOnGet) return defaultValue;
         return m.get();
     }
-    
+
     public Maybe<T> getMaybe() {
         Maybe<T> result = getMaybeInternal();
         if (log.isTraceEnabled()) {
@@ -324,7 +344,7 @@ public class ValueResolver<T> implements 
DeferredSupplier<T> {
         if (timerU==null && timeout!=null)
             timerU = timeout.countdownTimer();
         final CountdownTimer timer = timerU;
-        if (timer!=null && !timer.isRunning())
+        if (timer!=null && !timer.isNotPaused())
             timer.start();
         
         checkTypeNotNull();
@@ -499,9 +519,12 @@ public class ValueResolver<T> implements 
DeferredSupplier<T> {
         if (parentOriginalValue!=null) return parentOriginalValue;
         return value;
     }
-    
+    protected Class<T> getType() {
+        return type;
+    }
+
     @Override
     public String toString() {
         return 
JavaClassNames.cleanSimpleClassName(this)+"["+JavaClassNames.cleanSimpleClassName(type)+"
 "+value+"]";
     }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/5f66e8fe/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolverIterator.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolverIterator.java
 
b/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolverIterator.java
new file mode 100644
index 0000000..0e6fe4d
--- /dev/null
+++ 
b/core/src/main/java/org/apache/brooklyn/util/core/task/ValueResolverIterator.java
@@ -0,0 +1,196 @@
+/*
+ * 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.Iterator;
+import java.util.NoSuchElementException;
+
+import org.apache.brooklyn.util.core.flags.TypeCoercions;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.guava.Maybe;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+
+/**
+ * Resolve one step at a time, returning intermediate results or absent if 
there's a resolve error.
+ * Each step is a single one-level evaluation of the previous value.
+ * Use this if you are interested in intermediate suppliers wrapping the end 
result. Use ValueResolver if you need the deeper-most value.
+ */
+public class ValueResolverIterator<T> implements Iterator<Maybe<Object>> {
+    private static final Maybe<Object> NEXT_VALUE = Maybe.absent();
+    private ValueResolver<T> resolver;
+    private Maybe<Object> prev;
+
+    // * Present when resolving is successful
+    // * Absent when resolving failed
+    // * null when last value reached; can't resolve further either due to 
error or value is non-resolvable
+    private Maybe<Object> next;
+
+    public ValueResolverIterator(ValueResolver<T> resolver) {
+        this.resolver = resolver;
+        this.prev = Maybe.of(resolver.getOriginalValue());
+        this.next = prev;
+    }
+
+    /**
+     * @return the current element in the iterator. If {@link Maybe#absent()} 
there was a resolve error.
+     */
+    public Maybe<Object> peek() {
+        return prev;
+    }
+
+    /**
+     * Returns {@code true} if the current value is resolvable.
+     */
+    @Override
+    public boolean hasNext() {
+        fetchNext();
+        return next != null;
+    }
+
+    /**
+     * Resolves the value recursively, returning the immediately resolved 
value.
+     * If there's a resolve failure a {@link Maybe#absent()} is returned 
containing
+     * the failure description as the last element.
+     */
+    @Override
+    public Maybe<Object> next() {
+        if (!hasNext()) {
+            if (prev.isPresent()) {
+                throw new NoSuchElementException("The value " + prev.get() + " 
is non-resolvable");
+            } else {
+                throw new NoSuchElementException("Last resolve failed: " + 
prev);
+            }
+        }
+        prev = next;
+        next = NEXT_VALUE;
+        return prev;
+    }
+
+    private void fetchNext() {
+        if (next == NEXT_VALUE) {
+            if (prev.isPresent()) {
+                Object prevValue = prev.get();
+                if (prevValue != null) {
+                    ValueResolver<Object> nextResolver = 
createIterativeResolver(prevValue);
+                    try {
+                        next = nextResolver.getMaybe();
+                    } catch (Exception e) {
+                        Exceptions.propagateIfFatal(e);
+                        next = Maybe.absent("Failed resolving " + prev + " 
with resolver " + resolver, e);
+                    }
+                    if (next.isPresent() && next.get() == prev.get()) {
+                        // Resolved value same as previous value, last element 
reached
+                        next = null;
+                    }
+                } else {
+                    // Can't resolve null further
+                    // Same as previous case, just cuts on on the resolver 
calls
+                    next = null;
+                }
+            } else {
+                // Resolve error, can't continue
+                next = null;
+            }
+        }
+    }
+
+    @Override
+    public void remove() {
+        throw new IllegalStateException("Operation not supported");
+    }
+
+    private ValueResolver<Object> createIterativeResolver(Object value) {
+        return resolver.cloneReplacingValueAndType(value, Object.class)
+            .recursive(false);
+    }
+
+    /**
+     * @return the first resolved value satisfying the {@code stopCondition}.
+     * If none is found return the last element.
+     */
+    public Maybe<Object> nextOrLast(Predicate<Object> stopCondition) {
+        if (!hasNext()) {
+            return prev;
+        }
+        Maybe<Object> item;
+        do {
+            item = next();
+            if (item.isAbsent() || stopCondition.apply(item.get())) {
+                return item;
+            }
+        } while (hasNext());
+        return item;
+    }
+
+    /**
+     * @return the first resolved value instance of {@code type}.
+     * If none is found return the last element.
+     */
+    public Maybe<Object> nextOrLast(Class<?> type) {
+        return nextOrLast(Predicates.instanceOf(type));
+    }
+
+    /**
+     * @return the first resolved value instance of {@code type}.
+     * If not found returns {@link Maybe#absent()} either due to
+     * the end reached or a resolve error. To check if there was a
+     * resolve error call {@code peek().isAbsent()}.
+     */
+    public <S> Maybe<S> next(Class<S> type) {
+        while (hasNext()) {
+            Maybe<Object> item = next();
+            if (item.isAbsent() || type.isInstance(item.get())) {
+                @SuppressWarnings("unchecked")
+                Maybe<S> typedItem = (Maybe<S>) item;
+                return typedItem;
+            }
+        }
+        return Maybe.absent("Did not find items of type " + type + " in " + 
resolver);
+    }
+
+    /**
+     * @return the last element of the iterator reached either because
+     * resolving no longer possible or there was a resolve error.
+     */
+    @SuppressWarnings("unchecked")
+    public Maybe<T> last() {
+        Maybe<Object> last = peek();
+        while (hasNext()) {
+            last = next();
+            if (last.isAbsent()) {
+                return (Maybe<T>) last;
+            }
+        }
+        return coerceValue(last, resolver.getType());
+    }
+
+    private Maybe<T> coerceValue(Maybe<Object> valueMaybe, Class<T> type) {
+        if (valueMaybe.isPresent()) {
+            T coercedValue = TypeCoercions.coerce(valueMaybe.get(), type);
+            return Maybe.of(coercedValue);
+        } else {
+            @SuppressWarnings("unchecked")
+            Maybe<T> uncheckedValue = (Maybe<T>) valueMaybe;
+            return uncheckedValue;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/5f66e8fe/core/src/test/java/org/apache/brooklyn/util/core/task/ValueResolverIteratorTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/brooklyn/util/core/task/ValueResolverIteratorTest.java
 
b/core/src/test/java/org/apache/brooklyn/util/core/task/ValueResolverIteratorTest.java
new file mode 100644
index 0000000..c6ea9dd
--- /dev/null
+++ 
b/core/src/test/java/org/apache/brooklyn/util/core/task/ValueResolverIteratorTest.java
@@ -0,0 +1,217 @@
+/*
+ * 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 static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.NoSuchElementException;
+
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.test.Asserts;
+import 
org.apache.brooklyn.util.core.task.ValueResolverTest.FailingImmediateAndDeferredSupplier;
+import 
org.apache.brooklyn.util.core.task.ValueResolverTest.WrappingImmediateAndDeferredSupplier;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicates;
+
+public class ValueResolverIteratorTest extends BrooklynAppUnitTestSupport {
+    enum ResolveType {
+        IMMEDIATE(true),
+        BLOCKING(false);
+
+        private boolean immediate;
+
+        ResolveType(boolean immediate) {
+            this.immediate = immediate;
+        }
+
+        public boolean isImmediate() {
+            return immediate;
+        }
+    }
+
+    @DataProvider
+    public Object[][] resolveTypes() {
+        return new Object[][] {{ResolveType.IMMEDIATE}, 
{ResolveType.BLOCKING}};
+    }
+
+    @Test(dataProvider="resolveTypes")
+    public void testIteratorFailing(ResolveType resolveType) {
+        FailingImmediateAndDeferredSupplier failingExpected = new 
FailingImmediateAndDeferredSupplier();
+        WrappingImmediateAndDeferredSupplier wrapperExpected = new 
WrappingImmediateAndDeferredSupplier(failingExpected);
+        ValueResolver<Object> resolver = Tasks.resolving(wrapperExpected)
+                .as(Object.class)
+                .context(app)
+                .immediately(resolveType.isImmediate());
+        ValueResolverIterator<Object> iter = resolver.iterator();
+        assertTrue(iter.hasNext(), "expected wrapper");
+        Maybe<Object> wrapperActual = iter.next();
+        assertEquals(wrapperActual.get(), wrapperExpected);
+        assertEquals(wrapperActual, iter.peek());
+        assertTrue(iter.hasNext());
+        Maybe<Object> failingActual = iter.next();
+        assertEquals(failingActual.get(), failingExpected);
+        assertEquals(failingActual, iter.peek());
+        assertTrue(iter.hasNext());
+        Maybe<Object> absent = iter.next();
+        assertTrue(absent.isAbsent());
+
+        assertFalse(iter.hasNext(), "expected absent due to resolve failure");
+        try {
+            iter.next();
+            Asserts.shouldHaveFailedPreviously("no more elements in iterator");
+        } catch (NoSuchElementException e) {
+            // expected
+        }
+
+        Maybe<Object> last = iter.nextOrLast(Predicates.alwaysTrue());
+        assertTrue(last.isAbsent(), "expected absent because previous resolve 
failed");
+        assertEquals(last, iter.peek());
+
+        try {
+            iter.remove();
+            Asserts.shouldHaveFailedPreviously("can't remove elements");
+        } catch (IllegalStateException e) {
+            // expected
+        }
+    }
+
+    @Test(dataProvider="resolveTypes")
+    public void testIterator(ResolveType resolveType) {
+        Integer o3ExpectedLast = Integer.valueOf(10);
+        String o3Expected = o3ExpectedLast.toString(); //test coercion
+        WrappingImmediateAndDeferredSupplier o2Expected = new 
WrappingImmediateAndDeferredSupplier(o3Expected);
+        WrappingImmediateAndDeferredSupplier o1Expected = new 
WrappingImmediateAndDeferredSupplier(o2Expected);
+        ValueResolver<Integer> resolver = Tasks.resolving(o1Expected)
+                .as(Integer.class)
+                .context(app)
+                .immediately(resolveType.isImmediate());
+        ValueResolverIterator<Integer> iter = resolver.iterator();
+        assertTrue(iter.hasNext(), "expected o1");
+        Maybe<Object> o1Actual = iter.next();
+        assertEquals(o1Actual.get(), o1Expected);
+        assertEquals(o1Actual, iter.peek());
+        assertTrue(iter.hasNext());
+        Maybe<Object> o2Actual = iter.next();
+        assertEquals(o2Actual.get(), o2Expected);
+        assertEquals(o2Actual, iter.peek());
+        assertTrue(iter.hasNext());
+        Maybe<Object> o3Actual = iter.next();
+        assertEquals(o3Actual.get(), o3Expected);
+        assertEquals(o3Actual, iter.peek());
+
+        assertFalse(iter.hasNext(), "expected no more elements");
+        try {
+            iter.next();
+            Asserts.shouldHaveFailedPreviously("no more elements in iterator");
+        } catch (NoSuchElementException e) {
+            // expected
+        }
+
+        Maybe<Object> lastUntyped = iter.nextOrLast(Predicates.alwaysTrue());
+        assertTrue(lastUntyped.isPresent(), "expected present - all resolves 
successful");
+        // Note these are NOT equal because peek doesn't coerce
+        assertEquals(lastUntyped, iter.peek());
+        assertEquals(lastUntyped.get(), o3Expected);
+    }
+
+    @Test(dataProvider="resolveTypes")
+    public void testNull(ResolveType resolveType) {
+        ValueResolver<Void> resolver = Tasks.resolving(null)
+            .as(Void.class)
+            .context(app)
+            .immediately(resolveType.isImmediate());
+        assertNull(resolver.get());
+        ValueResolverIterator<Void> iter = resolver.iterator();
+        assertTrue(iter.hasNext());
+        assertNull(iter.next().get());
+        assertFalse(iter.hasNext());
+
+        Maybe<Object> voidOrLast = resolver.iterator().nextOrLast(Void.class);
+        assertNull(voidOrLast.get());
+
+        Maybe<Void> voidItem = resolver.iterator().next(Void.class);
+        assertTrue(voidItem.isAbsent());
+
+        Maybe<Void> lastItem = resolver.iterator().last();
+        assertNull(lastItem.get());
+    }
+
+    @Test(dataProvider="resolveTypes")
+    public void testNextOrLastFound(ResolveType resolveType) {
+        FailingImmediateAndDeferredSupplier failingExpected = new 
FailingImmediateAndDeferredSupplier();
+        WrappingImmediateAndDeferredSupplier wrapperExpected = new 
WrappingImmediateAndDeferredSupplier(failingExpected);
+        ValueResolver<Object> resolver = Tasks.resolving(wrapperExpected)
+                .as(Object.class)
+                .context(app)
+                .immediately(resolveType.isImmediate());
+        ValueResolverIterator<Object> iter = resolver.iterator();
+        Maybe<Object> actual = 
iter.nextOrLast(FailingImmediateAndDeferredSupplier.class);
+        assertTrue(actual.isPresent());
+        assertNotEquals(actual, iter.last());
+    }
+
+    @Test(dataProvider="resolveTypes")
+    public void testNextOrLastNotFound(ResolveType resolveType) {
+        FailingImmediateAndDeferredSupplier failingExpected = new 
FailingImmediateAndDeferredSupplier();
+        WrappingImmediateAndDeferredSupplier wrapperExpected = new 
WrappingImmediateAndDeferredSupplier(failingExpected);
+        ValueResolver<Object> resolver = Tasks.resolving(wrapperExpected)
+                .as(Object.class)
+                .context(app)
+                .immediately(resolveType.isImmediate());
+        ValueResolverIterator<Object> iter = resolver.iterator();
+        Maybe<Object> actual = iter.nextOrLast(Void.class);
+        assertFalse(actual.isPresent());
+        assertEquals(actual, iter.last());
+    }
+    
+    @Test(dataProvider="resolveTypes")
+    public void testNextTypeFound(ResolveType resolveType) {
+        FailingImmediateAndDeferredSupplier failingExpected = new 
FailingImmediateAndDeferredSupplier();
+        WrappingImmediateAndDeferredSupplier wrapperExpected = new 
WrappingImmediateAndDeferredSupplier(failingExpected);
+        ValueResolver<Object> resolver = Tasks.resolving(wrapperExpected)
+                .as(Object.class)
+                .context(app)
+                .immediately(resolveType.isImmediate());
+        ValueResolverIterator<Object> iter = resolver.iterator();
+        Maybe<FailingImmediateAndDeferredSupplier> actual = 
iter.next(FailingImmediateAndDeferredSupplier.class);
+        assertTrue(actual.isPresent());
+        assertNotEquals(actual, iter.last());
+    }
+
+    @Test(dataProvider="resolveTypes")
+    public void testNextTypeNotFound(ResolveType resolveType) {
+        FailingImmediateAndDeferredSupplier failingExpected = new 
FailingImmediateAndDeferredSupplier();
+        WrappingImmediateAndDeferredSupplier wrapperExpected = new 
WrappingImmediateAndDeferredSupplier(failingExpected);
+        ValueResolver<Object> resolver = Tasks.resolving(wrapperExpected)
+                .as(Object.class)
+                .context(app)
+                .immediately(resolveType.isImmediate());
+        ValueResolverIterator<Object> iter = resolver.iterator();
+        Maybe<Void> actual = iter.next(Void.class);
+        assertFalse(actual.isPresent());
+        assertEquals(actual, iter.last());
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/5f66e8fe/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 8e2581c..e47e4c9 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
@@ -249,7 +249,7 @@ public class ValueResolverTest extends 
BrooklynAppUnitTestSupport {
         }
     }
     
-    private static class WrappingImmediateAndDeferredSupplier implements 
ImmediateSupplier<Object>, DeferredSupplier<Object> {
+    static class WrappingImmediateAndDeferredSupplier implements 
ImmediateSupplier<Object>, DeferredSupplier<Object> {
         private Object value;
 
         public WrappingImmediateAndDeferredSupplier(Object value) {
@@ -268,7 +268,7 @@ public class ValueResolverTest extends 
BrooklynAppUnitTestSupport {
         
     }
 
-    private static class FailingImmediateAndDeferredSupplier implements 
ImmediateSupplier<Object>, DeferredSupplier<Object> {
+    static class FailingImmediateAndDeferredSupplier implements 
ImmediateSupplier<Object>, DeferredSupplier<Object> {
 
         @Override
         public Object get() {

Reply via email to