Delete deprecated Repeater class Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/7350fd62 Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/7350fd62 Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/7350fd62
Branch: refs/heads/master Commit: 7350fd621d8b97ab5e98e20d1e7fa4aa399a4ec0 Parents: 858fba4 Author: Aled Sage <[email protected]> Authored: Wed May 17 20:39:43 2017 +0200 Committer: Aled Sage <[email protected]> Committed: Fri May 19 10:46:35 2017 +0100 ---------------------------------------------------------------------- .../brooklyn/util/core/internal/Repeater.java | 367 ------------------- .../util/core/internal/RepeaterTest.java | 251 ------------- 2 files changed, 618 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/7350fd62/core/src/main/java/org/apache/brooklyn/util/core/internal/Repeater.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/util/core/internal/Repeater.java b/core/src/main/java/org/apache/brooklyn/util/core/internal/Repeater.java deleted file mode 100644 index 5f7973f..0000000 --- a/core/src/main/java/org/apache/brooklyn/util/core/internal/Repeater.java +++ /dev/null @@ -1,367 +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.internal; - -import static com.google.common.base.Preconditions.checkNotNull; - -import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - -import org.apache.brooklyn.util.JavaGroovyEquivalents; -import org.apache.brooklyn.util.collections.MutableMap; -import org.apache.brooklyn.util.core.flags.FlagUtils; -import org.apache.brooklyn.util.core.flags.SetFromFlag; -import org.apache.brooklyn.util.exceptions.Exceptions; -import org.apache.brooklyn.util.time.Duration; -import org.apache.brooklyn.util.time.Time; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Preconditions; -import com.google.common.util.concurrent.Callables; - -/** - * Simple DSL to repeat a fragment of code periodically until a condition is satisfied. - * - * In its simplest case, it is passed two {@link groovy.lang.Closure}s / {@link Callable} - - * the first is executed, then the second. If the second closure returns false, the loop - * is repeated; if true, it finishes. Further customization can be applied to set the period - * between loops and place a maximum limit on how long the loop should run for. - * <p> - * It is configured in a <em>fluent</em> manner. For example, in Groovy: - * <pre> - * {@code - * Repeater.create("Wait until the Frobnitzer is ready") - * .repeat { - * status = frobnitzer.getStatus() - * } - * .until { - * status == "Ready" || status == "Failed" - * } - * .limitIterationsTo(30) - * .run() - * } - * </pre> - * - * Or in Java: - * <pre> - * {@code - * Repeater.create("Wait until the Frobnitzer is ready") - * .until(new Callable<Boolean>() { - * public Boolean call() { - * String status = frobnitzer.getStatus() - * return "Ready".equals(status) || "Failed".equals(status); - * }}) - * .limitIterationsTo(30) - * .run() - * } - * </pre> - * - * @deprecated since 0.7.0, use {@link org.apache.brooklyn.util.repeat.Repeater} instead - */ -@Deprecated -public class Repeater { - - // TODO Was converted to Java, from groovy. Needs thorough review and improvements - // to use idiomatic java - - private static final Logger log = LoggerFactory.getLogger(Repeater.class); - - @SetFromFlag - private String description; - private Callable<?> body = Callables.returning(null); - private Callable<Boolean> exitCondition; - @SetFromFlag - private Long period = null; - @SetFromFlag("timeout") - private Long durationLimit = null; - private int iterationLimit = 0; - private boolean rethrowException = false; - private boolean rethrowExceptionImmediately = false; - private boolean warnOnUnRethrownException = true; - - public Repeater() { - this(MutableMap.of(), null); - } - - public Repeater(Map<?,?> flags) { - this(flags, null); - } - - public Repeater(String description) { - this(MutableMap.of(), description); - } - - /** - * Construct a new instance of Repeater. - * - * @param flags can include period, timeout, description - * @param description a description of the operation that will appear in debug logs. - */ - public Repeater(Map<?,?> flags, String description) { - setFromFlags(flags); - this.description = JavaGroovyEquivalents.elvis(description, this.description, "Repeater"); - } - - public void setFromFlags(Map<?,?> flags) { - FlagUtils.setFieldsFromFlags(flags, this); - } - - public static Repeater create() { - return create(MutableMap.of()); - } - public static Repeater create(Map<?,?> flags) { - return create(flags, null); - } - public static Repeater create(String description) { - return create(MutableMap.of(), description); - } - public static Repeater create(Map<?,?> flags, String description) { - return new Repeater(flags, description); - } - - /** - * Sets the main body of the loop to be a no-op. - * - * @return {@literal this} to aid coding in a fluent style. - */ - public Repeater repeat() { - return repeat(Callables.returning(null)); - } - - /** - * Sets the main body of the loop. - * - * @param body a closure or other Runnable that is executed in the main body of the loop. - * @return {@literal this} to aid coding in a fluent style. - */ - public Repeater repeat(Runnable body) { - checkNotNull(body, "body must not be null"); - this.body = (body instanceof Callable) ? (Callable<?>)body : Executors.callable(body); - return this; - } - - /** - * Sets the main body of the loop. - * - * @param body a closure or other Callable that is executed in the main body of the loop. - * @return {@literal this} to aid coding in a fluent style. - */ - public Repeater repeat(Callable<?> body) { - checkNotNull(body, "body must not be null"); - this.body = body; - return this; - } - - /** - * Set how long to wait between loop iterations. - * - * @param period how long to wait between loop iterations. - * @param unit the unit of measurement of the period. - * @return {@literal this} to aid coding in a fluent style. - */ - public Repeater every(long period, TimeUnit unit) { - Preconditions.checkArgument(period > 0, "period must be positive: %s", period); - checkNotNull(unit, "unit must not be null"); - this.period = unit.toMillis(period); - return this; - } - - /** - * @see #every(long, TimeUnit) - */ - public Repeater every(Duration duration) { - Preconditions.checkNotNull(duration, "duration must not be null"); - Preconditions.checkArgument(duration.toMilliseconds()>0, "period must be positive: %s", duration); - this.period = duration.toMilliseconds(); - return this; - } - - public Repeater every(groovy.time.Duration duration) { - return every(Duration.of(duration)); - } - - /** - * @see #every(long, TimeUnit) - * @deprecated specify unit - */ - @Deprecated - public Repeater every(long duration) { - return every(duration, TimeUnit.MILLISECONDS); - } - - /** - * Set code fragment that tests if the loop has completed. - * - * @param exitCondition a closure or other Callable that returns a boolean. If this code returns {@literal true} then the - * loop will stop executing. - * @return {@literal this} to aid coding in a fluent style. - */ - public Repeater until(Callable<Boolean> exitCondition) { - Preconditions.checkNotNull(exitCondition, "exitCondition must not be null"); - this.exitCondition = exitCondition; - return this; - } - - /** - * If the exit condition check throws an exception, it will be recorded and the last exception will be thrown on failure. - * - * @return {@literal this} to aid coding in a fluent style. - */ - public Repeater rethrowException() { - this.rethrowException = true; - return this; - } - - /** - * If the repeated body or the exit condition check throws an exception, then propagate that exception immediately. - * - * @return {@literal this} to aid coding in a fluent style. - */ - public Repeater rethrowExceptionImmediately() { - this.rethrowExceptionImmediately = true; - return this; - } - - public Repeater suppressWarnings() { - this.warnOnUnRethrownException = false; - return this; - } - - /** - * Set the maximum number of iterations. - * - * The loop will exit if the condition has not been satisfied after this number of iterations. - * - * @param iterationLimit the maximum number of iterations. - * @return {@literal this} to aid coding in a fluent style. - */ - public Repeater limitIterationsTo(int iterationLimit) { - Preconditions.checkArgument(iterationLimit > 0, "iterationLimit must be positive: %s", iterationLimit); - this.iterationLimit = iterationLimit; - return this; - } - - /** - * Set the amount of time to wait for the condition. - * The repeater will wait at least this long for the condition to be true, - * and will exit soon after even if the condition is false. - * - * @param deadline the time that the loop should wait. - * @param unit the unit of measurement of the period. - * @return {@literal this} to aid coding in a fluent style. - */ - public Repeater limitTimeTo(long deadline, TimeUnit unit) { - Preconditions.checkArgument(deadline > 0, "deadline must be positive: %s", deadline); - Preconditions.checkNotNull(unit, "unit must not be null"); - this.durationLimit = unit.toMillis(deadline); - return this; - } - - /** - * @see #limitTimeTo(long, TimeUnit) - */ - public Repeater limitTimeTo(Duration duration) { - Preconditions.checkNotNull(duration, "duration must not be null"); - Preconditions.checkArgument(duration.toMilliseconds() > 0, "deadline must be positive: %s", duration); - this.durationLimit = duration.toMilliseconds(); - return this; - } - - /** - * Run the loop. - * - * @return true if the exit condition was satisfied; false if the loop terminated for any other reason. - */ - public boolean run() { - Preconditions.checkState(body != null, "repeat() method has not been called to set the body"); - Preconditions.checkState(exitCondition != null, "until() method has not been called to set the exit condition"); - Preconditions.checkState(period != null, "every() method has not been called to set the loop period time units"); - - Throwable lastError = null; - int iterations = 0; - long endTime = -1; - if (durationLimit != null) { - endTime = System.currentTimeMillis() + durationLimit; - } - - while (true) { - iterations++; - - try { - body.call(); - } catch (Exception e) { - log.warn(description, e); - if (rethrowExceptionImmediately) throw Exceptions.propagate(e); - } - - boolean done = false; - try { - lastError = null; - done = exitCondition.call(); - } catch (Exception e) { - if (log.isDebugEnabled()) log.debug(description, e); - lastError = e; - if (rethrowExceptionImmediately) throw Exceptions.propagate(e); - } - if (done) { - if (log.isDebugEnabled()) log.debug("{}: condition satisfied", description); - return true; - } else { - if (log.isDebugEnabled()) { - String msg = String.format("%s: unsatisfied during iteration %s %s", description, iterations, - (iterationLimit > 0 ? "(max "+iterationLimit+" attempts)" : "") + - (endTime > 0 ? "("+Time.makeTimeStringRounded(endTime - System.currentTimeMillis())+" remaining)" : "")); - if (iterations == 1) { - log.debug(msg); - } else { - log.trace(msg); - } - } - } - - if (iterationLimit > 0 && iterations == iterationLimit) { - if (log.isDebugEnabled()) log.debug("{}: condition not satisfied and exceeded iteration limit", description); - if (rethrowException && lastError != null) { - log.warn("{}: error caught checking condition (rethrowing): {}", description, lastError.getMessage()); - throw Exceptions.propagate(lastError); - } - if (warnOnUnRethrownException && lastError != null) - log.warn("{}: error caught checking condition: {}", description, lastError.getMessage()); - return false; - } - - if (endTime > 0) { - if (System.currentTimeMillis() > endTime) { - if (log.isDebugEnabled()) log.debug("{}: condition not satisfied and deadline {} passed", - description, Time.makeTimeStringRounded(endTime - System.currentTimeMillis())); - if (rethrowException && lastError != null) { - log.error("{}: error caught checking condition: {}", description, lastError.getMessage()); - throw Exceptions.propagate(lastError); - } - return false; - } - } - - Time.sleep(period); - } - } -} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/7350fd62/core/src/test/java/org/apache/brooklyn/util/core/internal/RepeaterTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/util/core/internal/RepeaterTest.java b/core/src/test/java/org/apache/brooklyn/util/core/internal/RepeaterTest.java deleted file mode 100644 index de26857..0000000 --- a/core/src/test/java/org/apache/brooklyn/util/core/internal/RepeaterTest.java +++ /dev/null @@ -1,251 +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.internal; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; - -import java.util.concurrent.Callable; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.brooklyn.util.time.Duration; -import org.testng.annotations.Test; - -import com.google.common.base.Stopwatch; -import com.google.common.collect.ImmutableMap; -import com.google.common.util.concurrent.Callables; - -@SuppressWarnings("deprecation") -public class RepeaterTest { - - @Test - public void sanityTest() { - new Repeater("Sanity test") - .repeat() - .until(Callables.returning(true)) - .every(Duration.millis(10)); - } - - @Test - public void sanityTestDescription() { - new Repeater() - .repeat() - .until(Callables.returning(true)) - .every(Duration.millis(10)); - } - - @Test - public void sanityTestBuilder() { - Repeater.create("Sanity test") - .repeat() - .until(Callables.returning(true)) - .every(Duration.millis(10)); - } - - @Test - public void sanityTestBuilderDescription() { - Repeater.create() - .repeat() - .until(Callables.returning(true)) - .every(Duration.millis(10)); - } - - @Test(expectedExceptions = NullPointerException.class) - public void repeatFailsIfClosureIsNull() { - new Repeater("repeatFailsIfClosureIsNull").repeat((Callable<?>)null); - } - - @Test - public void repeatSucceedsIfClosureIsNonNull() { - new Repeater("repeatSucceedsIfClosureIsNonNull").repeat(Callables.returning(true)); - } - - @Test(expectedExceptions = NullPointerException.class) - public void untilFailsIfClosureIsNull() { - new Repeater("untilFailsIfClosureIsNull").until(null); - } - - @Test - public void untilSucceedsIfClosureIsNonNull() { - new Repeater("untilSucceedsIfClosureIsNonNull").until(Callables.returning(true)); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void everyFailsIfPeriodIsZero() { - new Repeater("everyFailsIfPeriodIsZero").every(Duration.ZERO); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void everyFailsIfPeriodIsNegative() { - new Repeater("everyFailsIfPeriodIsNegative").every(Duration.millis(-1)); - } - - @Test(expectedExceptions = NullPointerException.class) - public void everyFailsIfUnitsIsNull() { - new Repeater("everyFailsIfUnitsIsNull").every(10, null); - } - - @Test - public void everySucceedsIfPeriodIsPositiveAndUnitsIsNonNull() { - new Repeater("repeatSucceedsIfClosureIsNonNull").every(Duration.millis(10)); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void limitTimeToFailsIfPeriodIsZero() { - new Repeater("limitTimeToFailsIfPeriodIsZero").limitTimeTo(0, TimeUnit.MILLISECONDS); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void limitTimeToFailsIfPeriodIsNegative() { - new Repeater("limitTimeToFailsIfPeriodIsNegative").limitTimeTo(-1, TimeUnit.MILLISECONDS); - } - - @Test(expectedExceptions = NullPointerException.class) - public void limitTimeToFailsIfUnitsIsNull() { - new Repeater("limitTimeToFailsIfUnitsIsNull").limitTimeTo(10, null); - } - - @Test - public void limitTimeToSucceedsIfPeriodIsPositiveAndUnitsIsNonNull() { - new Repeater("limitTimeToSucceedsIfClosureIsNonNull").limitTimeTo(10, TimeUnit.MILLISECONDS); - } - - @Test - public void everyAcceptsDuration() { - new Repeater("everyAcceptsDuration").every(Duration.ONE_SECOND); - } - - @Test - public void everyAcceptsLong() { - new Repeater("everyAcceptsLong").every(1000L); - } - - @Test - public void everyAcceptsTimeUnit() { - new Repeater("everyAcceptsTimeUnit").every(1000000L, TimeUnit.MICROSECONDS); - } - - @Test - public void runReturnsTrueIfExitConditionIsTrue() { - assertTrue(new Repeater("runReturnsTrueIfExitConditionIsTrue") - .repeat() - .every(Duration.millis(1)) - .until(Callables.returning(true)) - .run()); - } - - @Test - public void runRespectsMaximumIterationLimitAndReturnsFalseIfReached() { - final AtomicInteger iterations = new AtomicInteger(); - assertFalse(new Repeater("runRespectsMaximumIterationLimitAndReturnsFalseIfReached") - .repeat(new Runnable() {@Override public void run() {iterations.incrementAndGet();}}) - .every(Duration.millis(1)) - .until(Callables.returning(false)) - .limitIterationsTo(5) - .run()); - assertEquals(iterations.get(), 5); - } - - /** - * Check that the {@link Repeater} will stop after a time limit. - * - * The repeater is configured to run every 100ms and never stop until the limit is reached. - * This is given as {@link Repeater#limitTimeTo(groovy.time.Duration)} and the execution time - * is then checked to ensure it is between 100% and 400% of the specified value. Due to scheduling - * delays and other factors in a non RTOS system it is expected that the repeater will take much - * longer to exit occasionally. - * - * @see #runRespectsMaximumIterationLimitAndReturnsFalseIfReached() - */ - @Test(groups="Integration") - public void runRespectsTimeLimitAndReturnsFalseIfReached() { - final long LIMIT = 2000l; - Repeater repeater = new Repeater("runRespectsTimeLimitAndReturnsFalseIfReached") - .repeat() - .every(Duration.millis(100)) - .until(Callables.returning(false)) - .limitTimeTo(LIMIT, TimeUnit.MILLISECONDS); - - Stopwatch stopwatch = Stopwatch.createStarted(); - boolean result = repeater.run(); - stopwatch.stop(); - - assertFalse(result); - - long difference = stopwatch.elapsed(TimeUnit.MILLISECONDS); - assertTrue(difference >= LIMIT, "Difference was: " + difference); - assertTrue(difference < 4 * LIMIT, "Difference was: " + difference); - } - - @Test(expectedExceptions = IllegalStateException.class) - public void runFailsIfUntilWasNotSet() { - new Repeater("runFailsIfUntilWasNotSet") - .repeat() - .every(Duration.millis(10)) - .run(); - } - - @Test(expectedExceptions = IllegalStateException.class) - public void runFailsIfEveryWasNotSet() { - new Repeater("runFailsIfEveryWasNotSet") - .repeat() - .until(Callables.returning(true)) - .run(); - } - - @Test(expectedExceptions = UnsupportedOperationException.class) - public void testRethrowsException() { - new Repeater("throwRuntimeException") - .repeat() - .every(Duration.millis(10)) - .until(new Callable<Boolean>() {@Override public Boolean call() {throw new UnsupportedOperationException("fail"); }}) - .rethrowException() - .limitIterationsTo(2) - .run(); - } - - @Test - public void testNoRethrowsException() { - try { - boolean result = new Repeater("throwRuntimeException") - .repeat() - .every(Duration.millis(10)) - .until(new Callable<Boolean>() {@Override public Boolean call() {throw new UnsupportedOperationException("fail"); }}) - .limitIterationsTo(2) - .run(); - assertFalse(result); - } catch (RuntimeException re) { - fail("Exception should not have been thrown: " + re.getMessage(), re); - } - } - - public void testFlags() { - final AtomicInteger count = new AtomicInteger(); - new Repeater(ImmutableMap.of("period", Duration.millis(5), "timeout", Duration.millis(100))) - .repeat(new Runnable() {@Override public void run() {count.incrementAndGet();}}) - .until(new Callable<Boolean>() { @Override public Boolean call() {return count.get() > 0;}}) - .run(); - assertTrue(count.get()>10); - assertTrue(count.get()<30); - } - -}
