11d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/*
21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copyright (C) 2007 The Guava Authors
31d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
41d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License");
51d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * you may not use this file except in compliance with the License.
61d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * You may obtain a copy of the License at
71d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
81d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0
91d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Unless required by applicable law or agreed to in writing, software
111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS,
121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * See the License for the specific language governing permissions and
141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * limitations under the License.
151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */
161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpackage com.google.common.io;
181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.collect.Sets;
201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.io.IOException;
221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Set;
231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/**
251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * The purpose of the CheckCloseSupplier is to report when all closeable objects
261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * supplied by the delegate supplier are closed. To do this, the factory method
271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * returns a decorated version of the {@code delegate} supplied in the
281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * constructor. The decoration mechanism is left up to the subclass via the
291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * abstract {@link #wrap} method.
301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>The decorated object returned from {@link #wrap} should ideally override
321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * its {@code close} method to not only call {@code super.close()} but to also
331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * call {@code callback.delegateClosed()}.
341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Chris Nokleberg
361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */
371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertabstract class CheckCloseSupplier<T> {
381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private final Set<Callback> open = Sets.newHashSet();
391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  abstract static class Input<T> extends CheckCloseSupplier<T>
411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      implements InputSupplier<T> {
421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private final InputSupplier<? extends T> delegate;
431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public Input(InputSupplier<? extends T> delegate) {
451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.delegate = delegate;
461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override public T getInput() throws IOException {
491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return wrap(delegate.getInput(), newCallback());
501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  abstract static class Output<T> extends CheckCloseSupplier<T>
541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      implements OutputSupplier<T> {
551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private final OutputSupplier<? extends T> delegate;
561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public Output(OutputSupplier<? extends T> delegate) {
581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.delegate = delegate;
591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override public T getOutput() throws IOException {
621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return wrap(delegate.getOutput(), newCallback());
631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public final class Callback {
671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public void delegateClosed() {
681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      open.remove(this);
691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  protected Callback newCallback() {
731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Callback callback = new Callback();
741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    open.add(callback);
751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return callback;
761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Subclasses should wrap the given object and call
801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * {@link Callback#delegateClosed} when the close method of the delegate is
811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * called, to inform the supplier that the underlying
821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * {@code Closeable} is not longer open.
831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   *
841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * @param object the object to wrap.
851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * @param callback the object that the wrapper should call to signal that the
861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  protected abstract T wrap(T object, Callback callback);
881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /** Returns true if all the closeables have been closed closed */
901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public boolean areClosed() {
911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return open.isEmpty();
921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert}
94