/** * @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()); }
/** * @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)); }
@Override public ValueResolverIterator<T> iterator() { return new ValueResolverIterator<T>(this); }
/** * @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; }
.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) { Maybe<Object> lastUntyped = iter.nextOrLast(Predicates.alwaysTrue()); assertTrue(lastUntyped.isPresent(), "expected present - all resolves successful"); 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()); }
private static ReleaseableLatch waitForLatch(EntityInternal entity, ConfigKey<Boolean> configKey) { Maybe<?> rawValue = entity.config().getRaw(configKey); if (rawValue.isAbsent()) { return ReleaseableLatch.NOP; } else { ValueResolverIterator<Boolean> iter = resolveLatchIterator(entity, rawValue.get(), configKey); // The iterator is used to prevent coercion; the value should always be the last one, but iter.last() will return a coerced Boolean Maybe<ReleaseableLatch> releasableLatchMaybe = iter.next(ReleaseableLatch.class); if (releasableLatchMaybe.isPresent()) { ReleaseableLatch latch = releasableLatchMaybe.get(); log.debug("{} finished waiting for {} (value {}); waiting to acquire the latch", new Object[] {entity, configKey, latch}); Tasks.setBlockingDetails("Acquiring " + configKey + " " + latch); try { latch.acquire(entity); } finally { Tasks.resetBlockingDetails(); } log.debug("{} Acquired latch {} (value {}); continuing...", new Object[] {entity, configKey, latch}); return latch; } else { // If iter.next() above returned absent due to a resolve error next line will throw with the cause Boolean val = iter.last().get(); if (rawValue != null) log.debug("{} finished waiting for {} (value {}); continuing...", new Object[] {entity, configKey, val}); return ReleaseableLatch.NOP; } } }
@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()); }
/** * 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; }
/** * Returns {@code true} if the current value is resolvable. */ @Override public boolean hasNext() { fetchNext(); return next != null; }
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; } } }
.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) { Maybe<Object> last = iter.nextOrLast(Predicates.alwaysTrue()); assertTrue(last.isAbsent(), "expected absent because previous resolve failed"); assertEquals(last, iter.peek()); iter.remove(); Asserts.shouldHaveFailedPreviously("can't remove elements"); } catch (IllegalStateException e) {
@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()); }
/** * @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); }
@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 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()); } }