1 /* 2 * Copyright (C) 2007 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.io; 18 19 import com.google.common.collect.Sets; 20 21 import java.io.IOException; 22 import java.util.Set; 23 24 /** 25 * The purpose of the CheckCloseSupplier is to report when all closeable objects 26 * supplied by the delegate supplier are closed. To do this, the factory method 27 * returns a decorated version of the {@code delegate} supplied in the 28 * constructor. The decoration mechanism is left up to the subclass via the 29 * abstract {@link #wrap} method. 30 * 31 * <p>The decorated object returned from {@link #wrap} should ideally override 32 * its {@code close} method to not only call {@code super.close()} but to also 33 * call {@code callback.delegateClosed()}. 34 * 35 * @author Chris Nokleberg 36 */ 37 abstract class CheckCloseSupplier<T> { 38 private final Set<Callback> open = Sets.newHashSet(); 39 40 abstract static class Input<T> extends CheckCloseSupplier<T> 41 implements InputSupplier<T> { 42 private final InputSupplier<? extends T> delegate; 43 Input(InputSupplier<? extends T> delegate)44 public Input(InputSupplier<? extends T> delegate) { 45 this.delegate = delegate; 46 } 47 getInput()48 @Override public T getInput() throws IOException { 49 return wrap(delegate.getInput(), newCallback()); 50 } 51 } 52 53 abstract static class Output<T> extends CheckCloseSupplier<T> 54 implements OutputSupplier<T> { 55 private final OutputSupplier<? extends T> delegate; 56 Output(OutputSupplier<? extends T> delegate)57 public Output(OutputSupplier<? extends T> delegate) { 58 this.delegate = delegate; 59 } 60 getOutput()61 @Override public T getOutput() throws IOException { 62 return wrap(delegate.getOutput(), newCallback()); 63 } 64 } 65 66 public final class Callback { delegateClosed()67 public void delegateClosed() { 68 open.remove(this); 69 } 70 } 71 newCallback()72 protected Callback newCallback() { 73 Callback callback = new Callback(); 74 open.add(callback); 75 return callback; 76 } 77 78 /** 79 * Subclasses should wrap the given object and call 80 * {@link Callback#delegateClosed} when the close method of the delegate is 81 * called, to inform the supplier that the underlying 82 * {@code Closeable} is not longer open. 83 * 84 * @param object the object to wrap. 85 * @param callback the object that the wrapper should call to signal that the 86 */ wrap(T object, Callback callback)87 protected abstract T wrap(T object, Callback callback); 88 89 /** Returns true if all the closeables have been closed closed */ areClosed()90 public boolean areClosed() { 91 return open.isEmpty(); 92 } 93 } 94