diff --git a/.travis.yml b/.travis.yml
index dff5f3a..9bcf999 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1 +1,3 @@
language: java
+jdk:
+ - oraclejdk8
diff --git a/pom.xml b/pom.xml
index 4555bd2..b8e8e99 100644
--- a/pom.xml
+++ b/pom.xml
@@ -25,6 +25,8 @@
+ 1.8
+ 1.8
UTF-8
UTF-8
@@ -65,6 +67,12 @@
18.0
+
+ org.threeten
+ threeten-extra
+ 1.2
+
+
junit
junit
diff --git a/src/main/java/org/isomorphism/util/FixedIntervalRefillStrategy.java b/src/main/java/org/isomorphism/util/FixedIntervalRefillStrategy.java
index 0639a70..89d1616 100644
--- a/src/main/java/org/isomorphism/util/FixedIntervalRefillStrategy.java
+++ b/src/main/java/org/isomorphism/util/FixedIntervalRefillStrategy.java
@@ -16,9 +16,16 @@
package org.isomorphism.util;
import com.google.common.base.Ticker;
+import org.threeten.extra.Temporals;
+import java.time.Duration;
+import java.time.temporal.ChronoUnit;
import java.util.concurrent.TimeUnit;
+import static java.time.temporal.ChronoUnit.NANOS;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+import static org.threeten.extra.Temporals.chronoUnit;
+
/**
* A token bucket refill strategy that will provide N tokens for a token bucket to consume every T units of time.
* The tokens are refilled in bursts rather than at a fixed rate. This refill strategy will never allow more than
@@ -39,14 +46,29 @@ public class FixedIntervalRefillStrategy implements TokenBucketImpl.RefillStrate
* @param numTokensPerPeriod The number of tokens to add to the bucket every period.
* @param period How often to refill the bucket.
* @param unit Unit for period.
+ *
+ * @deprecated since 1.8 use {@link FixedIntervalRefillStrategy#FixedIntervalRefillStrategy(Ticker, long, Duration)}.
*/
+ @Deprecated
public FixedIntervalRefillStrategy(Ticker ticker, long numTokensPerPeriod, long period, TimeUnit unit)
+ {
+ this(ticker, numTokensPerPeriod, Duration.of(period, chronoUnit(unit)));
+ }
+
+ /**
+ * Create a FixedIntervalRefillStrategy.
+ *
+ * @param ticker A ticker to use to measure time.
+ * @param numTokensPerPeriod The number of tokens to add to the bucket every period.
+ * @param period How often to refill the bucket.
+ */
+ public FixedIntervalRefillStrategy(Ticker ticker, long numTokensPerPeriod, Duration period)
{
this.ticker = ticker;
this.numTokensPerPeriod = numTokensPerPeriod;
- this.periodDurationInNanos = unit.toNanos(period);
- this.lastRefillTime = -periodDurationInNanos;
- this.nextRefillTime = -periodDurationInNanos;
+ this.periodDurationInNanos = period.toNanos();
+ this.lastRefillTime = -period.toNanos();
+ this.nextRefillTime = -period.toNanos();
}
@Override
@@ -72,9 +94,15 @@ public synchronized long refill()
@Override
public long getDurationUntilNextRefill(TimeUnit unit)
+ {
+ return unit.convert(getDurationUntilNextRefill().toNanos(), NANOSECONDS);
+ }
+
+ @Override
+ public Duration getDurationUntilNextRefill()
{
long now = ticker.read();
- return unit.convert(Math.max(0, nextRefillTime - now), TimeUnit.NANOSECONDS);
+ return Duration.of(Math.max(0, nextRefillTime - now), NANOS);
}
}
diff --git a/src/main/java/org/isomorphism/util/TokenBucket.java b/src/main/java/org/isomorphism/util/TokenBucket.java
index 232fb95..c18c17f 100644
--- a/src/main/java/org/isomorphism/util/TokenBucket.java
+++ b/src/main/java/org/isomorphism/util/TokenBucket.java
@@ -15,6 +15,7 @@
*/
package org.isomorphism.util;
+import java.time.Duration;
import java.util.concurrent.TimeUnit;
/**
@@ -47,9 +48,20 @@ public interface TokenBucket
* @see org.isomorphism.util.TokenBucket.RefillStrategy#getDurationUntilNextRefill(java.util.concurrent.TimeUnit)
* @param unit The time unit to express the return value in.
* @return The amount of time until the next group of tokens can be added to the token bucket.
+ *
+ * @deprecated since 1.8, see {@link TokenBucket#getDurationUntilNextRefill()}
*/
+ @Deprecated
long getDurationUntilNextRefill(TimeUnit unit) throws UnsupportedOperationException;
+ /**
+ * Returns the amount of time until the next group of tokens can be added to the token bucket.
+ *
+ * @see org.isomorphism.util.TokenBucket.RefillStrategy#getDurationUntilNextRefill()
+ * @return The amount of time until the next group of tokens can be added to the token bucket.
+ */
+ Duration getDurationUntilNextRefill() throws UnsupportedOperationException;
+
/**
* Attempt to consume a single token from the bucket. If it was consumed then {@code true} is returned, otherwise
* {@code false} is returned.
@@ -110,8 +122,24 @@ static interface RefillStrategy
*
* @param unit The time unit to express the return value in.
* @return The amount of time until the next group of tokens can be added to the token bucket.
+ *
+ * @deprecated since 1.8, see {@link RefillStrategy#getDurationUntilNextRefill()}
*/
+ @Deprecated
long getDurationUntilNextRefill(TimeUnit unit) throws UnsupportedOperationException;
+
+ /**
+ * Returns the amount of time until the next group of tokens can be added to the token
+ * bucket. Please note, depending on the {@code SleepStrategy} used by the token bucket, tokens may not actually
+ * be added until much after the returned duration. If for some reason the implementation of
+ * {@code RefillStrategy} doesn't support knowing when the next batch of tokens will be added, then an
+ * {@code UnsupportedOperationException} may be thrown. Lastly, if the duration until the next time tokens will
+ * be added to the token bucket is less than a single unit of the passed in time unit then this method will
+ * return 0.
+ *
+ * @return The amount of time until the next group of tokens can be added to the token bucket.
+ */
+ Duration getDurationUntilNextRefill();
}
/** Encapsulation of a strategy for relinquishing control of the CPU. */
diff --git a/src/main/java/org/isomorphism/util/TokenBucketImpl.java b/src/main/java/org/isomorphism/util/TokenBucketImpl.java
index c27cefb..f4707b7 100644
--- a/src/main/java/org/isomorphism/util/TokenBucketImpl.java
+++ b/src/main/java/org/isomorphism/util/TokenBucketImpl.java
@@ -15,10 +15,12 @@
*/
package org.isomorphism.util;
+import java.time.Duration;
import java.util.concurrent.TimeUnit;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
/**
* A token bucket implementation that is of a leaky bucket in the sense that it has a finite capacity and any added
@@ -80,17 +82,31 @@ public synchronized long getNumTokens()
}
/**
- * Returns the amount of time in the specified time unit until the next group of tokens can be added to the token
- * bucket.
- *
- * @see org.isomorphism.util.TokenBucket.RefillStrategy#getDurationUntilNextRefill(java.util.concurrent.TimeUnit)
- * @param unit The time unit to express the return value in.
- * @return The amount of time until the next group of tokens can be added to the token bucket.
- */
+ * Returns the amount of time in the specified time unit until the next group of tokens can be added to the token
+ * bucket.
+ *
+ * @see org.isomorphism.util.TokenBucket.RefillStrategy#getDurationUntilNextRefill(java.util.concurrent.TimeUnit)
+ * @param unit The time unit to express the return value in.
+ * @return The amount of time until the next group of tokens can be added to the token bucket.
+ */
@Override
+ @Deprecated
public long getDurationUntilNextRefill(TimeUnit unit) throws UnsupportedOperationException
{
- return refillStrategy.getDurationUntilNextRefill(unit);
+ return unit.convert(getDurationUntilNextRefill().toNanos(), NANOSECONDS);
+ }
+
+ /**
+ * Returns the amount of time in the specified time unit until the next group of tokens can be added to the token
+ * bucket.
+ *
+ * @see org.isomorphism.util.TokenBucket.RefillStrategy#getDurationUntilNextRefill()
+ * @return The amount of time until the next group of tokens can be added to the token bucket.
+ */
+ @Override
+ public Duration getDurationUntilNextRefill() throws UnsupportedOperationException
+ {
+ return refillStrategy.getDurationUntilNextRefill();
}
/**
diff --git a/src/main/java/org/isomorphism/util/TokenBuckets.java b/src/main/java/org/isomorphism/util/TokenBuckets.java
index ffedcad..851505d 100644
--- a/src/main/java/org/isomorphism/util/TokenBuckets.java
+++ b/src/main/java/org/isomorphism/util/TokenBuckets.java
@@ -17,11 +17,14 @@
import com.google.common.base.Ticker;
import com.google.common.util.concurrent.Uninterruptibles;
+import org.threeten.extra.Temporals;
+import java.time.Duration;
import java.util.concurrent.TimeUnit;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
+import static org.threeten.extra.Temporals.chronoUnit;
/** Static utility methods pertaining to creating {@link TokenBucketImpl} instances. */
public final class TokenBuckets
@@ -58,10 +61,21 @@ public Builder withInitialTokens(long numTokens)
return this;
}
- /** Refill tokens at a fixed interval. */
+ /**
+ * Refill tokens at a fixed interval.
+ *
+ * @deprecated since 1.8, see {@link TokenBuckets.Builder#withFixedIntervalRefillStrategy(long, Duration)}
+ */
+ @Deprecated
public Builder withFixedIntervalRefillStrategy(long refillTokens, long period, TimeUnit unit)
{
- return withRefillStrategy(new FixedIntervalRefillStrategy(ticker, refillTokens, period, unit));
+ return withFixedIntervalRefillStrategy(refillTokens, Duration.of(period, chronoUnit(unit)));
+ }
+
+ /** Refill tokens at a fixed interval. */
+ public Builder withFixedIntervalRefillStrategy(long refillTokens, Duration period)
+ {
+ return withRefillStrategy(new FixedIntervalRefillStrategy(ticker, refillTokens, period));
}
/** Use a user defined refill strategy. */
diff --git a/src/test/java/org/isomorphism/util/FixedIntervalRefillStrategyTest.java b/src/test/java/org/isomorphism/util/FixedIntervalRefillStrategyTest.java
index 861a986..408cfeb 100644
--- a/src/test/java/org/isomorphism/util/FixedIntervalRefillStrategyTest.java
+++ b/src/test/java/org/isomorphism/util/FixedIntervalRefillStrategyTest.java
@@ -18,18 +18,22 @@
import com.google.common.base.Ticker;
import org.junit.Test;
+import java.time.Duration;
+import java.time.temporal.ChronoUnit;
import java.util.concurrent.TimeUnit;
+import static java.time.temporal.ChronoUnit.SECONDS;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
public class FixedIntervalRefillStrategyTest
{
private static final long N = 5; // 5 tokens
- private static final long P = 10; // every 10
+ private static final Duration P = Duration.of(10, SECONDS); // every 10
private static final TimeUnit U = TimeUnit.SECONDS; // seconds
private final MockTicker ticker = new MockTicker();
- private final FixedIntervalRefillStrategy strategy = new FixedIntervalRefillStrategy(ticker, N, P, U);
+ private final FixedIntervalRefillStrategy strategy = new FixedIntervalRefillStrategy(ticker, N, P);
@Test
public void testFirstRefill()
@@ -43,8 +47,8 @@ public void testNoRefillUntilPeriodUp()
strategy.refill();
// Another refill shouldn't come for P time units.
- for (int i = 0; i < P - 1; i++) {
- ticker.advance(1, U);
+ for (int i = 0; i < P.getSeconds() - 1; i++) {
+ ticker.advance(Duration.of(1, SECONDS));
assertEquals(0, strategy.refill());
}
}
@@ -54,13 +58,13 @@ public void testRefillEveryPeriod()
{
strategy.refill();
- ticker.advance(P, U);
+ ticker.advance(P);
assertEquals(N, strategy.refill());
- ticker.advance(P, U);
+ ticker.advance(P);
assertEquals(N, strategy.refill());
- ticker.advance(P, U);
+ ticker.advance(P);
assertEquals(N, strategy.refill());
}
@@ -70,10 +74,10 @@ public void testRefillEveryOtherPeriod()
strategy.refill();
// Move time forward two periods, since we're skipping a period next time we should add double the tokens.
- ticker.advance(2 * P, U);
+ ticker.advance(P.multipliedBy(2));
assertEquals(2 * N, strategy.refill());
- ticker.advance(2 * P, U);
+ ticker.advance(P.multipliedBy(2));
assertEquals(2 * N, strategy.refill());
}
@@ -87,23 +91,23 @@ public void testRefillOnNonEvenPeriods()
assertEquals(N, strategy.refill());
// t = P+1
- ticker.advance(P + 1, U);
+ ticker.advance(P.plus(1, SECONDS));
assertEquals(N, strategy.refill());
// t = 2P+1
- ticker.advance(P, U);
+ ticker.advance(P);
assertEquals(N, strategy.refill());
// t = 3P
- ticker.advance(P - 1, U);
+ ticker.advance(P.minus(1, SECONDS));
assertEquals(N, strategy.refill());
// t = 4P-1
- ticker.advance(P - 1, U);
+ ticker.advance(P.minus(1, SECONDS));
assertEquals(0, strategy.refill());
// t = 4P
- ticker.advance(1, U);
+ ticker.advance(Duration.of(1, SECONDS));
assertEquals(N, strategy.refill());
}
@@ -119,9 +123,9 @@ public void testDurationAfterFirstRefill()
{
strategy.refill();
- for (int i = 0; i < P - 1; i++) {
- assertEquals(P - i, strategy.getDurationUntilNextRefill(TimeUnit.SECONDS));
- ticker.advance(1, U);
+ for (int i = 0; i < P.getSeconds() - 1; i++) {
+ assertEquals(P.getSeconds() - i, strategy.getDurationUntilNextRefill().getSeconds());
+ ticker.advance(Duration.of(1, SECONDS));
}
}
@@ -129,9 +133,9 @@ public void testDurationAfterFirstRefill()
public void testDurationAtSecondRefillTime()
{
strategy.refill();
- ticker.advance(P, U);
+ ticker.advance(P);
- assertEquals(0, strategy.getDurationUntilNextRefill(TimeUnit.SECONDS));
+ assertTrue(strategy.getDurationUntilNextRefill().isZero());
}
@Test
@@ -139,7 +143,7 @@ public void testDurationInProperUnits()
{
strategy.refill();
- assertEquals(10000, strategy.getDurationUntilNextRefill(TimeUnit.MILLISECONDS));
+ assertEquals(P, strategy.getDurationUntilNextRefill());
}
private static final class MockTicker extends Ticker
@@ -152,9 +156,9 @@ public long read()
return now;
}
- public void advance(long delta, TimeUnit unit)
+ public void advance(Duration delta)
{
- now += unit.toNanos(delta);
+ now += delta.toNanos();
}
}
}
diff --git a/src/test/java/org/isomorphism/util/TokenBucketImplTest.java b/src/test/java/org/isomorphism/util/TokenBucketImplTest.java
index e339c61..661b446 100644
--- a/src/test/java/org/isomorphism/util/TokenBucketImplTest.java
+++ b/src/test/java/org/isomorphism/util/TokenBucketImplTest.java
@@ -17,6 +17,7 @@
import org.junit.Test;
+import java.time.Duration;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertEquals;
@@ -234,6 +235,11 @@ public long getDurationUntilNextRefill(TimeUnit unit) throws UnsupportedOperatio
throw new UnsupportedOperationException();
}
+ @Override
+ public Duration getDurationUntilNextRefill() {
+ throw new UnsupportedOperationException();
+ }
+
public void addToken()
{
numTokensToAdd++;