package fr.openwide.core.commons.util.context;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Deque;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import fr.openwide.core.commons.util.context.IExecutionContext.ITearDownHandle;
public final class ExecutionContexts {
private ExecutionContexts() {
}
public static IExecutionContext noOp() {
return NoOpExecutionContext.INSTANCE;
}
private static class NoOpExecutionContext extends AbstractExecutionContext {
private static final IExecutionContext INSTANCE = new NoOpExecutionContext();
@Override
public ITearDownHandle open() {
return NoOpTearDownHandle.INSTANCE;
}
}
private static enum NoOpTearDownHandle implements ITearDownHandle {
INSTANCE;
@Override
public void close() {
// No-op
}
}
public static CompositeExecutionContextBuilder composite() {
return new CompositeExecutionContextBuilder();
}
public static class CompositeExecutionContextBuilder {
private final Collection<IExecutionContext> components = new ArrayList<IExecutionContext>();
private CompositeExecutionContextBuilder() {
}
public CompositeExecutionContextBuilder add(IExecutionContext context) {
components.add(context);
return this;
}
public IExecutionContext build() {
return new CompositeExecutionContext(components);
}
}
private static final class CompositeExecutionContext extends AbstractExecutionContext {
private final Collection<? extends IExecutionContext> components;
public CompositeExecutionContext(Collection<? extends IExecutionContext> components) {
super();
this.components = components;
}
@Override
public ITearDownHandle open() {
Deque<ITearDownHandle> handles = new ArrayDeque<>(components.size());
try {
for (IExecutionContext context : components) {
// Make sure the closing order will be reversed
handles.addFirst(context.open());
}
return new CompositeTearDownHandle(handles);
} catch (RuntimeException e) {
for (ITearDownHandle handle : handles) {
try {
handle.close();
} catch (RuntimeException e2) {
e.addSuppressed(e2);
}
}
throw e;
}
}
@Override
public boolean equals(Object obj) {
if (obj instanceof CompositeExecutionContext) {
if (obj == this) {
return true;
}
CompositeExecutionContext other = (CompositeExecutionContext) obj;
return new EqualsBuilder()
.append(components, other.components)
.build();
}
return false;
}
@Override
public int hashCode() {
return new HashCodeBuilder()
.append(components)
.build();
}
};
private static final class CompositeTearDownHandle implements ITearDownHandle {
private final Collection<? extends ITearDownHandle> components;
public CompositeTearDownHandle(Collection<? extends ITearDownHandle> components) {
super();
this.components = components;
}
@Override
public void close() {
RuntimeException exception = null;
for (ITearDownHandle handle : components) {
try {
handle.close();
} catch (RuntimeException e2) {
if (exception == null) {
exception = e2;
} else {
exception.addSuppressed(e2);
}
}
}
if (exception != null) {
throw exception;
}
}
}
}