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 }