001    package org.crsh.util;
002    
003    import org.slf4j.Logger;
004    import org.slf4j.LoggerFactory;
005    
006    import java.io.Closeable;
007    import java.util.ArrayList;
008    import java.util.concurrent.atomic.AtomicBoolean;
009    
010    /** @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> */
011    public final class CloseableList implements Closeable {
012    
013      /** . */
014      final Logger log = LoggerFactory.getLogger(CloseableList.class);
015    
016      /** . */
017      private final ArrayList<Closeable> closeables;
018    
019      /** . */
020      private final AtomicBoolean closed;
021    
022      public CloseableList() {
023        this.closeables = new ArrayList<Closeable>();
024        this.closed = new AtomicBoolean(false);
025      }
026    
027      public boolean isClosed() {
028        return closed.get();
029      }
030    
031      /**
032       * Add a closeable to the list.
033       *
034       * @param closeable the closeable to add
035       * @throws IllegalStateException if the list is already closed
036       * @throws NullPointerException if the argument is null
037       */
038      public void add(Closeable closeable) throws IllegalStateException, NullPointerException {
039        if (closed.get()) {
040          throw new IllegalStateException("Already closed");
041        }
042        if (closeable == null) {
043          throw new NullPointerException("No null closeable accepted");
044        }
045        if (!closeables.contains(closeable)) {
046          closeables.add(closeable);
047        }
048      }
049    
050      public void close() {
051        if (closed.compareAndSet(false, true)) {
052          for (Closeable closeable : closeables) {
053            log.debug("Closing " + closeable.getClass().getSimpleName());
054            Safe.close(closeable);
055          }
056        }
057      }
058    }