blob: 8901f1c55a872033eb8047344d5c18111bb9ddd9 [file] [log] [blame]
/*
* Copyright 2016 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package java.util.stream;
import java.util.ArrayList;
import java.util.List;
// package protected, as not part of jre
class TerminatableStream<T extends TerminatableStream<T>> {
// root-only fields, ignored for non-root instances
private boolean terminated = false;
private final List<Runnable> onClose;
private final TerminatableStream<?> root;
public TerminatableStream(TerminatableStream<?> previous) {
if (previous == null) {
root = null;
onClose = new ArrayList<>();
} else {
root = previous;
onClose = null;
}
}
void throwIfTerminated() {
if (root != null) {
root.throwIfTerminated();
} else if (terminated) {
throw new IllegalStateException("Stream already terminated, can't be modified or used");
}
}
// note that not all terminals directly call this, but they must use it indirectly
void terminate() {
if (root == null) {
throwIfTerminated();
terminated = true;
} else {
root.terminate();
}
}
public T onClose(Runnable closeHandler) {
if (root == null) {
onClose.add(closeHandler);
} else {
root.onClose(closeHandler);
}
return (T) this;
}
public void close() {
if (root == null) {
terminated = true;
runClosers();
} else {
root.close();
}
}
private void runClosers() {
ArrayList<Throwable> throwables = new ArrayList<>();
onClose.forEach(
runnable -> {
try {
runnable.run();
} catch (Throwable e) {
throwables.add(e);
}
});
onClose.clear();
if (!throwables.isEmpty()) {
Throwable e = throwables.get(0);
for (int i = 1, size = throwables.size(); i < size; ++i) {
Throwable suppressed = throwables.get(i);
if (suppressed != e) {
e.addSuppressed(suppressed);
}
}
if (e instanceof RuntimeException) {
throw (RuntimeException) e;
}
if (e instanceof Error) {
throw (Error) e;
}
assert false : "Couldn't have caught this exception from a Runnable! " + e;
}
}
}