CavalliumDBEngine/src/main/java/it/cavallium/dbengine/utils/SimpleResource.java

83 lines
2.2 KiB
Java
Raw Normal View History

2022-06-14 18:05:26 +02:00
package it.cavallium.dbengine.utils;
import it.cavallium.dbengine.database.SafeCloseable;
2022-06-29 01:14:05 +02:00
import java.lang.ref.Cleaner;
2022-06-14 18:05:26 +02:00
import java.util.concurrent.atomic.AtomicBoolean;
2022-06-29 01:14:05 +02:00
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
2022-06-30 17:05:32 +02:00
import org.jetbrains.annotations.Nullable;
2022-06-14 18:05:26 +02:00
public abstract class SimpleResource implements SafeCloseable {
2022-06-29 01:14:05 +02:00
protected static final boolean ENABLE_LEAK_DETECTION
= Boolean.parseBoolean(System.getProperty("it.cavallium.dbengine.leakdetection.enable", "true"));
protected static final boolean ADVANCED_LEAK_DETECTION
= Boolean.parseBoolean(System.getProperty("it.cavallium.dbengine.leakdetection.advanced", "false"));
private static final Logger LOG = LogManager.getLogger(SimpleResource.class);
public static final Cleaner CLEANER = Cleaner.create();
private final AtomicBoolean closed;
2022-06-20 23:31:42 +02:00
private final boolean canClose;
public SimpleResource() {
2022-06-29 01:14:05 +02:00
this(true);
2022-06-20 23:31:42 +02:00
}
2022-06-30 17:05:32 +02:00
public SimpleResource(@Nullable Runnable cleanerAction) {
this(true, cleanerAction);
}
2022-06-20 23:31:42 +02:00
protected SimpleResource(boolean canClose) {
2022-06-30 17:05:32 +02:00
this(canClose, null);
}
private SimpleResource(boolean canClose, @Nullable Runnable cleanerAction) {
2022-06-20 23:31:42 +02:00
this.canClose = canClose;
var closed = new AtomicBoolean();
2022-06-29 01:14:05 +02:00
this.closed = closed;
if (ENABLE_LEAK_DETECTION && canClose) {
var resourceClass = this.getClass();
Exception initializationStackTrace;
if (ADVANCED_LEAK_DETECTION) {
var stackTrace = Thread.currentThread().getStackTrace();
initializationStackTrace = new Exception("Initialization point");
initializationStackTrace.setStackTrace(stackTrace);
} else {
initializationStackTrace = null;
}
CLEANER.register(this, () -> {
if (!closed.get()) {
LOG.error("Resource leak of type {}", resourceClass, initializationStackTrace);
2022-06-30 17:05:32 +02:00
if (cleanerAction != null) {
cleanerAction.run();
}
2022-06-29 01:14:05 +02:00
}
});
}
2022-06-20 23:31:42 +02:00
}
2022-06-14 18:05:26 +02:00
@Override
public final void close() {
2022-06-20 23:31:42 +02:00
if (canClose && closed.compareAndSet(false, true)) {
2022-06-14 18:05:26 +02:00
onClose();
}
}
2022-07-19 23:45:39 +02:00
public boolean isClosed() {
2022-06-20 23:31:42 +02:00
return canClose && closed.get();
2022-06-14 18:05:26 +02:00
}
2022-06-30 13:54:55 +02:00
protected AtomicBoolean getClosed() {
return closed;
}
2022-06-14 18:05:26 +02:00
protected void ensureOpen() {
2022-07-19 23:45:39 +02:00
if (isClosed()) {
2022-06-14 18:05:26 +02:00
throw new IllegalStateException("Resource is closed");
}
}
protected abstract void onClose();
}