package sk.stuba.fiit.perconik.activity.probes; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.concurrent.atomic.AtomicBoolean; import javax.annotation.Nullable; import com.google.common.base.Supplier; import static com.google.common.base.Objects.equal; import static com.google.common.base.Preconditions.checkNotNull; public final class Probes { private Probes() {} private static final class CachedProbe<T> extends ForwardingProbe<T> implements Serializable { private static final long serialVersionUID = 0L; private final Probe<T> delegate; private final AtomicBoolean probed; private T value; CachedProbe(final Probe<T> delegate) { this.delegate = checkNotNull(delegate); this.probed = new AtomicBoolean(false); } @Override protected Probe<T> delegate() { return this.delegate; } @Override public T get() { if (this.probed.compareAndSet(false, true)) { this.value = this.delegate.get(); } return this.value; } } private static final class SynchronizedProbe<T> implements Probe<T>, Serializable { private static final long serialVersionUID = 0L; private final Probe<T> delegate; private final Object mutex; SynchronizedProbe(final Probe<T> delegate, final Object mutex) { this.delegate = checkNotNull(delegate); this.mutex = (mutex == null) ? this : mutex; } @Override public boolean equals(@Nullable final Object object) { if (object == this) { return true; } synchronized (this.mutex) { return this.delegate.equals(object); } } @Override public int hashCode() { synchronized (this.mutex) { return this.delegate.hashCode(); } } @Override public String toString() { synchronized (this.mutex) { return this.delegate.toString(); } } private void writeObject(final ObjectOutputStream stream) throws IOException { synchronized (this.mutex) { stream.defaultWriteObject(); } } public T get() { synchronized (this.mutex) { return this.delegate.get(); } } } public static <T> Probe<T> cachedProbe(final Probe<T> probe) { return new CachedProbe<>(probe); } public static <T> Probe<T> synchronizedProbe(final Probe<T> probe) { return new SynchronizedProbe<>(probe, null); } private static final class ConstantProbe<T> implements Probe<T>, Serializable { private static final long serialVersionUID = 0L; private final T value; ConstantProbe(final T value) { this.value = value; } @Override public boolean equals(@Nullable final Object object) { return object == this || ((object instanceof ConstantProbe) && equal(this.value, ((ConstantProbe<?>) object).value)); } @Override public int hashCode() { return this.value != null ? this.value.hashCode() : 0; } @Override public String toString() { return "forConstant(" + this.value + ")"; } public T get() { return this.value; } } private static final class SupplierProbe<T> implements Probe<T>, Serializable { private static final long serialVersionUID = 0L; private final Supplier<T> supplier; SupplierProbe(final Supplier<T> supplier) { this.supplier = checkNotNull(supplier); } @Override public boolean equals(@Nullable final Object object) { return object == this || ((object instanceof SupplierProbe) && equal(this.supplier, ((SupplierProbe<?>) object).supplier)); } @Override public int hashCode() { return this.supplier.hashCode(); } @Override public String toString() { return "forSupplier(" + this.supplier + ")"; } public T get() { return this.supplier.get(); } } public static <T> Probe<T> forConstant(final T value) { return new ConstantProbe<>(value); } public static <T> Probe<T> forSupplier(final Supplier<T> supplier) { return new SupplierProbe<>(supplier); } }