Home | History | Annotate | Download | only in io
      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 
     44     public Input(InputSupplier<? extends T> delegate) {
     45       this.delegate = delegate;
     46     }
     47 
     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 
     57     public Output(OutputSupplier<? extends T> delegate) {
     58       this.delegate = delegate;
     59     }
     60 
     61     @Override public T getOutput() throws IOException {
     62       return wrap(delegate.getOutput(), newCallback());
     63     }
     64   }
     65 
     66   public final class Callback {
     67     public void delegateClosed() {
     68       open.remove(this);
     69     }
     70   }
     71 
     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    */
     87   protected abstract T wrap(T object, Callback callback);
     88 
     89   /** Returns true if all the closeables have been closed closed */
     90   public boolean areClosed() {
     91     return open.isEmpty();
     92   }
     93 }
     94