com.softicar.platform.common.core.singleton.Singleton Maven / Gradle / Ivy
Show all versions of platform-common Show documentation
package com.softicar.platform.common.core.singleton;
import com.softicar.platform.common.core.interfaces.Consumers;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
/**
* Represents a thread local variable of a singleton.
*
* This class should only be used to declare private static final fields.
*
* @author Oliver Richers
* @param
* the type of the singleton instance
*/
public class Singleton {
private Supplier initialValueSupplier;
private UnaryOperator inheritOperator;
private Consumer scopeCloseHandler;
/**
* Constructs this {@link Singleton} with an initial value of null.
*/
public Singleton() {
this(() -> null);
}
/**
* Constructs this {@link Singleton} with the given initial value supplier.
*
* @param initialValueSupplier
* the initial value supplier (never null)
*/
public Singleton(Supplier initialValueSupplier) {
this.initialValueSupplier = Objects.requireNonNull(initialValueSupplier);
this.inheritOperator = parentValue -> initialValueSupplier.get();
this.scopeCloseHandler = Consumers.noOperation();
}
/**
* Defines the supplier for the initial value of this {@link Singleton}.
*
* The default implementation returns null.
*
* @param initialValueSupplier
* the initial value supplier (never null)
* @return this object
*/
public Singleton setInitialValueSupplier(Supplier initialValueSupplier) {
this.initialValueSupplier = Objects.requireNonNull(initialValueSupplier);
return this;
}
/**
* Defines an operator, how to transform the value of this {@link Singleton}
* from the parent {@link SingletonSet} into the value in the child
* {@link SingletonSet}.
*
* The default implementation drops the parent {@link SingletonSet} value
* and uses the value given by the initial value supplier.
*
* Usually, this mechanism is used when inheriting the {@link SingletonSet}
* from a parent {@link Thread}. Be careful when inheriting non-primitive
* {@link Singleton} values: Those must be either immutable, deeply copied,
* or thread safe (regarding both read and write access). Otherwise,
* race-conditions may occur.
*
* @param inheritOperator
* the inheriting operator
* @return this object
*/
public Singleton setInheritOperator(UnaryOperator inheritOperator) {
this.inheritOperator = Objects.requireNonNull(inheritOperator);
return this;
}
/**
* Calls {@link #setInheritOperator} with {@link UnaryOperator#identity()}.
*
* @return this object
*/
public Singleton setInheritByIdentity() {
return setInheritOperator(UnaryOperator.identity());
}
/**
* Defines a handler which is called when a {@link SingletonSetScope} is
* closed.
*
* The given handler is called when {@link SingletonSetScope#close()} is
* called, before {@link CurrentSingletonSet} is changed.
*
* The handler is only called if the current {@link Singleton} value is not
* null. The current value is provided to the handler as
* {@link Consumer} argument, and thus, the value is never null.
*
* This handler provides the opportunity to the {@link Singleton} to clean
* up resources. Be aware that closing a {@link SingletonSetScope} does not
* necessarily imply that the current singleton value will never be used
* again. For example, short-lived resources like database connections might
* be closed by such a handler.
*
* @param scopeCloseHandler
* the handler (never null)
* @return this object
*/
public Singleton setScopeCloseHandler(Consumer scopeCloseHandler) {
this.scopeCloseHandler = Objects.requireNonNull(scopeCloseHandler);
return this;
}
/**
* Returns the current value of this {@link Singleton}.
*
* @return the current value (may be null)
*/
public T get() {
return CurrentSingletonSet.get().getSingletonValue(this);
}
/**
* Sets the current value of this {@link Singleton}.
*
* @param value
* the new value (may be null)
*/
public void set(T value) {
CurrentSingletonSet.get().setSingletonValue(this, value);
}
/**
* Resets the current value of this {@link Singleton} to its initial value.
*
* Resetting this {@link Singleton} will not reset its value to the
* value inherited from a parent {@link SingletonSet}. In any case, the
* value of the initial value supplier will be used.
*/
public void reset() {
CurrentSingletonSet.get().resetSingletonValue(this);
}
// ------------------------------ package private ------------------------------ //
T getInitalValue() {
return initialValueSupplier.get();
}
T getInheritedValue(T parentValue) {
return inheritOperator.apply(parentValue);
}
void callScopeCloseHandler(T value) {
scopeCloseHandler.accept(value);
}
}