001    package org.crsh.util;
002    
003    import java.io.IOException;
004    import java.io.InterruptedIOException;
005    import java.util.LinkedList;
006    
007    /**
008     * A combination of an {@link InputStream} and an {@link OutputStream}, simpler than what java provides
009     * and more suitable for unit testing. This class is not optimized for performance.
010     *
011     * @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a>
012     */
013    public class PipedChannel {
014    
015      /** . */
016      private final LinkedList<Integer> queue;
017    
018      /** . */
019      private final Object lock;
020    
021      /** . */
022      private boolean closed;
023    
024      /** . */
025      private InputStream in;
026    
027      /** . */
028      private OutputStream out;
029    
030      public PipedChannel() {
031        this.queue = new LinkedList<Integer>();
032        this.lock = new Object();
033        this.closed = false;
034        in = new InputStream();
035        out = new OutputStream();
036      }
037    
038      public InputStream getIn() {
039        return in;
040      }
041    
042      public OutputStream getOut() {
043        return out;
044      }
045    
046      class InputStream extends java.io.InputStream {
047        @Override
048        public int read() throws IOException {
049          synchronized (lock) {
050            while (true) {
051              if (queue.size() > 0) {
052                return queue.removeFirst();
053              } else {
054                if (closed) {
055                  throw new IOException("closed");
056                } else {
057                  try {
058                    lock.wait();
059                  }
060                  catch (InterruptedException e) {
061                    InterruptedIOException iioe = new InterruptedIOException();
062                    iioe.initCause(e);
063                    throw iioe;
064                  }
065                }
066              }
067            }
068          }
069        }
070    
071        @Override
072        public void close() throws IOException {
073          synchronized (lock) {
074            if (!closed) {
075              closed = true;
076              lock.notifyAll();
077            }
078          }
079        }
080      }
081    
082      class OutputStream extends java.io.OutputStream {
083        @Override
084        public void write(int b) throws IOException {
085          synchronized (lock) {
086            if (closed) {
087              throw new IOException("closed");
088            }
089            queue.add(b);
090          }
091        }
092    
093        @Override
094        public void flush() throws IOException {
095          synchronized (lock) {
096            if (closed) {
097              throw new IOException("closed");
098            }
099            lock.notifyAll();
100          }
101        }
102    
103        @Override
104        public void close() throws IOException {
105          synchronized (lock) {
106            if (!closed) {
107              closed = true;
108              lock.notifyAll();
109            }
110          }
111        }
112      }
113    }