diff --git a/src/main/java/org/ultramine/core/util/Undoable.java b/src/main/java/org/ultramine/core/util/Undoable.java new file mode 100644 index 0000000..4be3a9f --- /dev/null +++ b/src/main/java/org/ultramine/core/util/Undoable.java @@ -0,0 +1,42 @@ +package org.ultramine.core.util; + +import com.google.common.base.Throwables; + +import java.util.Arrays; +import java.util.Collection; + +public interface Undoable +{ + void undo(); + + static Undoable ofAll(Undoable... undoables) + { + undoables.getClass(); // NPE + return ofAll(Arrays.asList(undoables)); + } + + static Undoable ofAll(Collection undoables) + { + undoables.getClass(); // NPE + return () -> { + Throwable toRethrow = null; + for(Undoable undoable : undoables) + { + try + { + if(undoable != null) + undoable.undo(); + } + catch(Throwable t) + { + if(toRethrow == null) + toRethrow = t; + else + toRethrow.addSuppressed(t); + } + } + if(toRethrow != null) + Throwables.propagate(toRethrow); + }; + } +} diff --git a/src/main/java/org/ultramine/core/util/UndoableAction.java b/src/main/java/org/ultramine/core/util/UndoableAction.java new file mode 100644 index 0000000..b4eda31 --- /dev/null +++ b/src/main/java/org/ultramine/core/util/UndoableAction.java @@ -0,0 +1,52 @@ +package org.ultramine.core.util; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +public interface UndoableAction +{ + Undoable apply(); + + static UndoableAction ofAll(UndoableAction... actions) + { + actions.getClass(); //NPE + return ofAll(Arrays.asList(actions)); + } + + static UndoableAction ofAll(Collection actions) + { + actions.getClass(); //NPE + for(UndoableAction action : actions) + action.getClass(); // NPE + return () -> { + for(UndoableAction action : actions) + action.getClass(); // NPE (again, collection may be mutable) + List undoables = new ArrayList<>(actions.size()); + for(UndoableAction action : actions) + { + try + { + undoables.add(action.apply()); + } + catch(Throwable t) + { + try + { + Undoable.ofAll(undoables).undo(); + } + catch(Throwable t1) + { + t.addSuppressed(t1); + throw t; + } + + throw t; + } + } + + return Undoable.ofAll(undoables); + }; + } +} diff --git a/src/main/java/org/ultramine/core/util/UndoableValue.java b/src/main/java/org/ultramine/core/util/UndoableValue.java new file mode 100644 index 0000000..5147dca --- /dev/null +++ b/src/main/java/org/ultramine/core/util/UndoableValue.java @@ -0,0 +1,24 @@ +package org.ultramine.core.util; + +public interface UndoableValue extends Undoable +{ + T getValue(); + + static UndoableValue of(T value, Undoable undoable) + { + return new UndoableValue() + { + @Override + public T getValue() + { + return value; + } + + @Override + public void undo() + { + undoable.undo(); + } + }; + } +}