diff --git a/src/main/java/org/cobbzilla/util/cache/AutoRefreshingReference.java b/src/main/java/org/cobbzilla/util/cache/AutoRefreshingReference.java index 612e2ea..d655df4 100644 --- a/src/main/java/org/cobbzilla/util/cache/AutoRefreshingReference.java +++ b/src/main/java/org/cobbzilla/util/cache/AutoRefreshingReference.java @@ -7,6 +7,10 @@ import java.util.concurrent.atomic.AtomicReference; import static org.cobbzilla.util.daemon.ZillaRuntime.now; +// Wraps an AtomicReference and presents a similar 'get' method, but will refresh the underlying +// object via the 'refresh' method if it is null or stale. +// +// Consider using Refreshable, a subclass with a more functional approach public abstract class AutoRefreshingReference { @Getter private final AtomicReference object = new AtomicReference<>(); diff --git a/src/main/java/org/cobbzilla/util/cache/BackgroundRefreshable.java b/src/main/java/org/cobbzilla/util/cache/BackgroundRefreshable.java new file mode 100644 index 0000000..bcf5467 --- /dev/null +++ b/src/main/java/org/cobbzilla/util/cache/BackgroundRefreshable.java @@ -0,0 +1,28 @@ +package org.cobbzilla.util.cache; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +import java.util.concurrent.Callable; +import java.util.function.Function; + +@Slf4j +public class BackgroundRefreshable extends BackgroundRefreshingReference { + + @Getter private final String name; + @Getter private final long timeout; + @Getter private final Callable refresher; + @Getter private final Function errorRefreshing; + + public BackgroundRefreshable(String name, long timeout, Callable refresher) { this(name, timeout, refresher, e -> null); } + + public BackgroundRefreshable(String name, long timeout, Callable refresher, Function errorRefreshing) { + this.name = name; + this.timeout = timeout; + this.refresher = refresher; + this.errorRefreshing = errorRefreshing; + } + + @Override public T refresh() { return Refreshable.refresh(name, refresher, errorRefreshing); } + +} diff --git a/src/main/java/org/cobbzilla/util/cache/Refreshable.java b/src/main/java/org/cobbzilla/util/cache/Refreshable.java new file mode 100644 index 0000000..145ad3e --- /dev/null +++ b/src/main/java/org/cobbzilla/util/cache/Refreshable.java @@ -0,0 +1,45 @@ +package org.cobbzilla.util.cache; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +import java.util.concurrent.Callable; +import java.util.function.Function; + +import static org.cobbzilla.util.daemon.ZillaRuntime.die; +import static org.cobbzilla.util.daemon.ZillaRuntime.shortError; + +@Slf4j +public class Refreshable extends AutoRefreshingReference { + + @Getter private final String name; + @Getter private final long timeout; + @Getter private final Callable refresher; + @Getter private final Function errorRefreshing; + + public Refreshable(String name, long timeout, Callable refresher) { this(name, timeout, refresher, e -> null); } + + public Refreshable(String name, long timeout, Callable refresher, Function errorRefreshing) { + this.name = name; + this.timeout = timeout; + this.refresher = refresher; + this.errorRefreshing = errorRefreshing; + } + + @Override public T refresh() { return refresh(name, refresher, errorRefreshing); } + + public static T refresh(String name, Callable refresher, Function errorRefreshing) { + try { + return refresher.call(); + } catch (Exception e) { + final String msg = "refresh(" + name + "): " + shortError(e); + log.error(msg); + try { + return errorRefreshing.apply(e); + } catch (Exception ex) { + return die("refresh("+name+") failed with: "+shortError(e)+", and then errorRefreshing failed with "+shortError(ex)); + } + } + } + +}