mirror of
https://github.com/AuthMe/AuthMeReloaded.git
synced 2024-11-08 03:29:41 +01:00
Create Duration class and ExpiringSet#getExpiration (prep for #1073)
- Move expiring collections to util.expiring package - Change ExpiringSet to remove expired entries during normal calls
This commit is contained in:
parent
4edb4e68c2
commit
72c5cfac68
@ -5,7 +5,7 @@ import fr.xephi.authme.initialization.SettingsDependent;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||
import fr.xephi.authme.util.RandomStringUtils;
|
||||
import fr.xephi.authme.util.TimedCounter;
|
||||
import fr.xephi.authme.util.expiring.TimedCounter;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
@ -5,7 +5,7 @@ import fr.xephi.authme.initialization.HasCleanup;
|
||||
import fr.xephi.authme.initialization.SettingsDependent;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.properties.PluginSettings;
|
||||
import fr.xephi.authme.util.ExpiringSet;
|
||||
import fr.xephi.authme.util.expiring.ExpiringSet;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -7,8 +7,8 @@ import fr.xephi.authme.message.Messages;
|
||||
import fr.xephi.authme.service.BukkitService;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||
import fr.xephi.authme.util.TimedCounter;
|
||||
import fr.xephi.authme.util.PlayerUtils;
|
||||
import fr.xephi.authme.util.expiring.TimedCounter;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
@ -4,8 +4,8 @@ import fr.xephi.authme.initialization.HasCleanup;
|
||||
import fr.xephi.authme.initialization.SettingsDependent;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||
import fr.xephi.authme.util.ExpiringMap;
|
||||
import fr.xephi.authme.util.RandomStringUtils;
|
||||
import fr.xephi.authme.util.expiring.ExpiringMap;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -3,6 +3,7 @@ package fr.xephi.authme.util;
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
@ -70,4 +71,36 @@ public final class Utils {
|
||||
return Runtime.getRuntime().availableProcessors();
|
||||
}
|
||||
|
||||
public static Duration convertMillisToSuitableUnit(long duration) {
|
||||
TimeUnit targetUnit;
|
||||
if (duration > 1000L * 60L * 60L * 24L) {
|
||||
targetUnit = TimeUnit.DAYS;
|
||||
} else if (duration > 1000L * 60L * 60L) {
|
||||
targetUnit = TimeUnit.HOURS;
|
||||
} else if (duration > 1000L * 60L) {
|
||||
targetUnit = TimeUnit.MINUTES;
|
||||
} else if (duration > 1000L) {
|
||||
targetUnit = TimeUnit.SECONDS;
|
||||
} else {
|
||||
targetUnit = TimeUnit.MILLISECONDS;
|
||||
}
|
||||
|
||||
return new Duration(targetUnit, duration);
|
||||
}
|
||||
|
||||
public static final class Duration {
|
||||
|
||||
private final long duration;
|
||||
private final TimeUnit unit;
|
||||
|
||||
Duration(TimeUnit targetUnit, long durationMillis) {
|
||||
this(targetUnit, durationMillis, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
Duration(TimeUnit targetUnit, long sourceDuration, TimeUnit sourceUnit) {
|
||||
this.duration = targetUnit.convert(sourceDuration, sourceUnit);
|
||||
this.unit = targetUnit;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
72
src/main/java/fr/xephi/authme/util/expiring/Duration.java
Normal file
72
src/main/java/fr/xephi/authme/util/expiring/Duration.java
Normal file
@ -0,0 +1,72 @@
|
||||
package fr.xephi.authme.util.expiring;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Represents a duration in time, defined by a time unit and a duration.
|
||||
*/
|
||||
public class Duration {
|
||||
|
||||
private final long duration;
|
||||
private final TimeUnit unit;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param duration the duration
|
||||
* @param unit the time unit in which {@code duration} is expressed
|
||||
*/
|
||||
public Duration(long duration, TimeUnit unit) {
|
||||
this.duration = duration;
|
||||
this.unit = unit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Duration object for the given duration and unit in the most suitable time unit.
|
||||
* For example, {@code createWithSuitableUnit(120, TimeUnit.SECONDS)} will return a Duration
|
||||
* object of 2 minutes.
|
||||
* <p>
|
||||
* This method only considers the time units days, hours, minutes, and seconds for the objects
|
||||
* it creates. Conversion is done with {@link TimeUnit#convert} and so always rounds the
|
||||
* results down.
|
||||
* <p>
|
||||
* Further examples:
|
||||
* <code>createWithSuitableUnit(299, TimeUnit.MINUTES); // 4 hours</code>
|
||||
* <code>createWithSuitableUnit(700, TimeUnit.MILLISECONDS); // 0 seconds</code>
|
||||
*
|
||||
* @param sourceDuration the duration
|
||||
* @param sourceUnit the time unit the duration is expressed in
|
||||
* @return Duration object using the most suitable time unit
|
||||
*/
|
||||
public static Duration createWithSuitableUnit(long sourceDuration, TimeUnit sourceUnit) {
|
||||
long durationMillis = Math.abs(TimeUnit.MILLISECONDS.convert(sourceDuration, sourceUnit));
|
||||
|
||||
TimeUnit targetUnit;
|
||||
if (durationMillis > 1000L * 60L * 60L * 24L) {
|
||||
targetUnit = TimeUnit.DAYS;
|
||||
} else if (durationMillis > 1000L * 60L * 60L) {
|
||||
targetUnit = TimeUnit.HOURS;
|
||||
} else if (durationMillis > 1000L * 60L) {
|
||||
targetUnit = TimeUnit.MINUTES;
|
||||
} else {
|
||||
targetUnit = TimeUnit.SECONDS;
|
||||
}
|
||||
|
||||
long durationInTargetUnit = targetUnit.convert(sourceDuration, sourceUnit);
|
||||
return new Duration(durationInTargetUnit, targetUnit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the duration
|
||||
*/
|
||||
public long getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the time unit in which the duration is expressed
|
||||
*/
|
||||
public TimeUnit getTimeUnit() {
|
||||
return unit;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package fr.xephi.authme.util;
|
||||
package fr.xephi.authme.util.expiring;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
@ -1,4 +1,4 @@
|
||||
package fr.xephi.authme.util;
|
||||
package fr.xephi.authme.util.expiring;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@ -9,9 +9,10 @@ import java.util.concurrent.TimeUnit;
|
||||
* has expired, the set will act as if the entry no longer exists. Time starts
|
||||
* counting after the entry has been inserted.
|
||||
* <p>
|
||||
* Internally, expired entries are not cleared automatically. A cleanup can be
|
||||
* triggered with {@link #removeExpiredEntries()}. Adding an entry that is
|
||||
* already present effectively resets its expiration.
|
||||
* Internally, expired entries are not guaranteed to be cleared automatically.
|
||||
* A cleanup of all expired entries may be triggered with
|
||||
* {@link #removeExpiredEntries()}. Adding an entry that is already present
|
||||
* effectively resets its expiration.
|
||||
*
|
||||
* @param <E> the type of the entries
|
||||
*/
|
||||
@ -47,7 +48,14 @@ public class ExpiringSet<E> {
|
||||
*/
|
||||
public boolean contains(E entry) {
|
||||
Long expiration = entries.get(entry);
|
||||
return expiration != null && expiration > System.currentTimeMillis();
|
||||
if (expiration == null) {
|
||||
return false;
|
||||
} else if (expiration > System.currentTimeMillis()) {
|
||||
return true;
|
||||
} else {
|
||||
entries.remove(entry);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -73,6 +81,27 @@ public class ExpiringSet<E> {
|
||||
entries.entrySet().removeIf(entry -> System.currentTimeMillis() > entry.getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the duration of the entry until it expires (provided it is not removed or re-added).
|
||||
* If the entry does not exist, -1 is returned.
|
||||
*
|
||||
* @param entry the entry whose duration before it expires should be returned
|
||||
* @param unit the unit in which to return the duration
|
||||
* @return duration the entry will remain in the set (if there are not modifications)
|
||||
*/
|
||||
public long getExpiration(E entry, TimeUnit unit) {
|
||||
Long expiration = entries.get(entry);
|
||||
if (expiration == null) {
|
||||
return -1;
|
||||
}
|
||||
long stillPresentMillis = expiration - System.currentTimeMillis();
|
||||
if (stillPresentMillis < 0) {
|
||||
entries.remove(entry);
|
||||
return -1;
|
||||
}
|
||||
return unit.convert(stillPresentMillis, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new expiration duration. Note that already present entries
|
||||
* will still make use of the old expiration.
|
@ -1,4 +1,4 @@
|
||||
package fr.xephi.authme.util;
|
||||
package fr.xephi.authme.util.expiring;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
@ -3,7 +3,7 @@ package fr.xephi.authme.data;
|
||||
import fr.xephi.authme.ReflectionTestUtils;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||
import fr.xephi.authme.util.TimedCounter;
|
||||
import fr.xephi.authme.util.expiring.TimedCounter;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
@ -3,7 +3,7 @@ package fr.xephi.authme.data;
|
||||
import fr.xephi.authme.ReflectionTestUtils;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.properties.PluginSettings;
|
||||
import fr.xephi.authme.util.ExpiringSet;
|
||||
import fr.xephi.authme.util.expiring.ExpiringSet;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
@ -7,7 +7,7 @@ import fr.xephi.authme.message.Messages;
|
||||
import fr.xephi.authme.service.BukkitService;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||
import fr.xephi.authme.util.TimedCounter;
|
||||
import fr.xephi.authme.util.expiring.TimedCounter;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
@ -6,7 +6,7 @@ import ch.jalu.injector.testing.InjectDelayed;
|
||||
import fr.xephi.authme.ReflectionTestUtils;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||
import fr.xephi.authme.util.ExpiringMap;
|
||||
import fr.xephi.authme.util.expiring.ExpiringMap;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
|
@ -0,0 +1,43 @@
|
||||
package fr.xephi.authme.util.expiring;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* Test for {@link Duration}.
|
||||
*/
|
||||
public class DurationTest {
|
||||
|
||||
@Test
|
||||
public void shouldConvertToAppropriateTimeUnit() {
|
||||
check(Duration.createWithSuitableUnit(0, TimeUnit.HOURS),
|
||||
0, TimeUnit.SECONDS);
|
||||
|
||||
check(Duration.createWithSuitableUnit(124, TimeUnit.MINUTES),
|
||||
2, TimeUnit.HOURS);
|
||||
|
||||
check(Duration.createWithSuitableUnit(300, TimeUnit.HOURS),
|
||||
12, TimeUnit.DAYS);
|
||||
|
||||
check(Duration.createWithSuitableUnit(60 * 24 * 50 + 8, TimeUnit.MINUTES),
|
||||
50, TimeUnit.DAYS);
|
||||
|
||||
check(Duration.createWithSuitableUnit(1000L * 60 * 60 * 24 * 7 + 3000, TimeUnit.MILLISECONDS),
|
||||
7, TimeUnit.DAYS);
|
||||
|
||||
check(Duration.createWithSuitableUnit(1000L * 60 * 60 * 3 + 1400, TimeUnit.MILLISECONDS),
|
||||
3, TimeUnit.HOURS);
|
||||
|
||||
check(Duration.createWithSuitableUnit(248, TimeUnit.SECONDS),
|
||||
4, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
private static void check(Duration duration, long expectedDuration, TimeUnit expectedUnit) {
|
||||
assertThat(duration.getTimeUnit(), equalTo(expectedUnit));
|
||||
assertThat(duration.getDuration(), equalTo(expectedDuration));
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package fr.xephi.authme.util;
|
||||
package fr.xephi.authme.util.expiring;
|
||||
|
||||
import org.junit.Test;
|
||||
|
@ -1,9 +1,10 @@
|
||||
package fr.xephi.authme.util;
|
||||
package fr.xephi.authme.util.expiring;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.hamcrest.Matchers.either;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
@ -88,4 +89,34 @@ public class ExpiringSetTest {
|
||||
assertThat(set.contains(3), equalTo(false));
|
||||
assertThat(set.contains(6), equalTo(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnExpiration() {
|
||||
// given
|
||||
ExpiringSet<String> set = new ExpiringSet<>(123, TimeUnit.MINUTES);
|
||||
set.add("my entry");
|
||||
|
||||
// when
|
||||
long expiresInHours = set.getExpiration("my entry", TimeUnit.HOURS);
|
||||
long expiresInMinutes = set.getExpiration("my entry", TimeUnit.MINUTES);
|
||||
long unknownExpires = set.getExpiration("bogus", TimeUnit.SECONDS);
|
||||
|
||||
// then
|
||||
assertThat(expiresInHours, equalTo(2L));
|
||||
assertThat(expiresInMinutes, either(equalTo(122L)).or(equalTo(123L)));
|
||||
assertThat(unknownExpires, equalTo(-1L));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnMinusOneForExpiredEntry() {
|
||||
// given
|
||||
ExpiringSet<Integer> set = new ExpiringSet<>(-100, TimeUnit.SECONDS);
|
||||
set.add(23);
|
||||
|
||||
// when
|
||||
long expiresInSeconds = set.getExpiration(23, TimeUnit.SECONDS);
|
||||
|
||||
// then
|
||||
assertThat(expiresInSeconds, equalTo(-1L));
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package fr.xephi.authme.util;
|
||||
package fr.xephi.authme.util.expiring;
|
||||
|
||||
import org.junit.Test;
|
||||
|
Loading…
Reference in New Issue
Block a user