Skip to content

Commit

Permalink
Added a simple ResourceMgr for collecting a set of objects that need …
Browse files Browse the repository at this point in the history
…to be cleaned up
  • Loading branch information
Aklakan committed May 9, 2024
1 parent c4a1cf4 commit 613dbe5
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 43 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package org.aksw.commons.util.exception;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import org.aksw.commons.util.function.ThrowingRunnable;
Expand Down Expand Up @@ -39,6 +39,13 @@
public class FinallyRunAll
implements Runnable
{
// TODO Consolidate with the identical interface from the lambda module
@FunctionalInterface
public interface ThrowingConsumer<T> extends Serializable {
void accept(T t) throws Exception;
}

// XXX Could change to an Iterator or Stream of actions.
protected List<ThrowingRunnable> actions;

public static FinallyRunAll create() {
Expand Down Expand Up @@ -87,47 +94,47 @@ protected void runAction(int index) {
public static void run(ThrowingRunnable ... actions) {
new FinallyRunAll(Arrays.asList(actions)).run();
}
public static <T> void runAll(Collection<T> actions, Consumer<T> runner, ThrowingRunnable finallyAction) {
ThrowingRunnable[] runnables = actions.stream().map(action -> {
ThrowingRunnable r = () -> {
runner.accept(action);
};
return r;
}).collect(Collectors.toList()).toArray(new ThrowingRunnable[0]);
try {
run(runnables);
} finally {
if (finallyAction != null) {
try {
finallyAction.run();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
// Alternative approach using a loop
if (false) {
List<Exception> exceptions = null;
for (T action : actions) {
try {
runner.accept(action);
} catch (Exception e) {
if (exceptions == null) {
exceptions = new ArrayList<>();
}
exceptions.add(e);
}
}
if (exceptions != null) {
RuntimeException e = new RuntimeException();
exceptions.forEach(e::addSuppressed);
throw e;
}
}
}

public static <T> void runAll(Collection<T> actions, ThrowingConsumer<T> runner, ThrowingRunnable finallyAction) {
ThrowingRunnable[] runnables = actions.stream().map(action -> {
ThrowingRunnable r = () -> {
runner.accept(action);
};
return r;
}).collect(Collectors.toList()).toArray(new ThrowingRunnable[0]);

try {
run(runnables);
} finally {
if (finallyAction != null) {
try {
finallyAction.run();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

// Alternative approach using a loop
if (false) {
List<Exception> exceptions = null;
for (T action : actions) {
try {
runner.accept(action);
} catch (Exception e) {
if (exceptions == null) {
exceptions = new ArrayList<>();
}
exceptions.add(e);
}
}

if (exceptions != null) {
RuntimeException e = new RuntimeException();
exceptions.forEach(e::addSuppressed);
throw e;
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package org.aksw.commons.util.lifecycle;

import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Map;

import org.aksw.commons.util.exception.FinallyRunAll;
import org.aksw.commons.util.exception.FinallyRunAll.ThrowingConsumer;
import org.aksw.commons.util.function.ThrowingRunnable;

/**
* A class where resources can be added.
* Upon closing the resource manager, all registered resources will be freed.
*
* @implNote
* This implementation closes resources sequentially.
*/
public class ResourceMgr
implements AutoCloseable
{
private final Map<Object, ThrowingRunnable> resourceToCloser =
Collections.synchronizedMap(new IdentityHashMap<>());

public ResourceMgr() {
super();
}

public <T extends AutoCloseable> T register(T closable) {
return register(closable, AutoCloseable::close);
}

public <T> T register(T obj, ThrowingConsumer<? super T> closer) {
return register(obj, () -> closer.accept(obj));
}

public <T> T register(T obj, ThrowingRunnable closeAction) {
resourceToCloser.put(obj, closeAction);
return obj;
}

@Override
public void close() {
FinallyRunAll.runAll(resourceToCloser.entrySet(), e -> e.getValue().run(), null);
}
}

0 comments on commit 613dbe5

Please sign in to comment.