/* * This file is part of ComputerCraft - http://www.computercraft.info * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.test.core; import javax.annotation.Nullable; import java.util.ArrayDeque; import java.util.Deque; import java.util.Objects; /** * An {@link AutoCloseable} implementation which can be used to combine other [AutoCloseable] instances. *

* Values which implement {@link AutoCloseable} can be dynamically registered with [CloseScope.add]. When the scope is * closed, each value is closed in the opposite order. *

* This is largely intended for cases where it's not appropriate to nest try-with-resources blocks, for instance when * nested would be too deep or when objects are dynamically created. */ public class CloseScope implements AutoCloseable { private final Deque toClose = new ArrayDeque<>(); /** * Add a value to be closed when this scope exists. * * @param value The value to be closed. * @param The type of the provided value. * @return The provided value. */ public T add(T value) { Objects.requireNonNull(value, "Value cannot be null"); toClose.add(value); return value; } @Override public void close() throws Exception { close(null); } public void close(@Nullable Exception baseException) throws Exception { while (true) { var close = toClose.pollLast(); if (close == null) break; try { close.close(); } catch (Exception e) { if (baseException == null) { baseException = e; } else { baseException.addSuppressed(e); } } } if (baseException != null) throw baseException; } }