View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.mina.handler.support;
21  
22  import java.io.IOException;
23  import java.io.InputStream;
24  
25  import org.apache.mina.common.ByteBuffer;
26  import org.apache.mina.common.IoHandler;
27  import org.apache.mina.common.IoSession;
28  
29  /**
30   * An {@link InputStream} that buffers data read from
31   * {@link IoHandler#messageReceived(IoSession, Object)} events.
32   *
33   * @author The Apache Directory Project (mina-dev@directory.apache.org)
34   * @version $Rev: 555855 $, $Date: 2007-07-13 12:19:00 +0900 (Fri, 13 Jul 2007) $
35   */
36  public class IoSessionInputStream extends InputStream {
37      private final Object mutex = new Object();
38  
39      private final ByteBuffer buf;
40  
41      private volatile boolean closed;
42  
43      private volatile boolean released;
44  
45      private IOException exception;
46  
47      public IoSessionInputStream() {
48          buf = ByteBuffer.allocate(16);
49          buf.setAutoExpand(true);
50          buf.limit(0);
51      }
52  
53      public int available() {
54          if (released) {
55              return 0;
56          } else {
57              synchronized (mutex) {
58                  return buf.remaining();
59              }
60          }
61      }
62  
63      public void close() {
64          if (closed) {
65              return;
66          }
67  
68          synchronized (mutex) {
69              closed = true;
70              releaseBuffer();
71  
72              mutex.notifyAll();
73          }
74      }
75  
76      public int read() throws IOException {
77          synchronized (mutex) {
78              if (!waitForData()) {
79                  return -1;
80              }
81  
82              return buf.get() & 0xff;
83          }
84      }
85  
86      public int read(byte[] b, int off, int len) throws IOException {
87          synchronized (mutex) {
88              if (!waitForData()) {
89                  return -1;
90              }
91  
92              int readBytes;
93  
94              if (len > buf.remaining()) {
95                  readBytes = buf.remaining();
96              } else {
97                  readBytes = len;
98              }
99  
100             buf.get(b, off, readBytes);
101 
102             return readBytes;
103         }
104     }
105 
106     private boolean waitForData() throws IOException {
107         if (released) {
108             return false;
109         }
110 
111         synchronized (mutex) {
112             while (!released && buf.remaining() == 0 && exception == null) {
113                 try {
114                     mutex.wait();
115                 } catch (InterruptedException e) {
116                     IOException ioe = new IOException(
117                             "Interrupted while waiting for more data");
118                     ioe.initCause(e);
119                     throw ioe;
120                 }
121             }
122         }
123 
124         if (exception != null) {
125             releaseBuffer();
126             throw exception;
127         }
128 
129         if (closed && buf.remaining() == 0) {
130             releaseBuffer();
131 
132             return false;
133         }
134 
135         return true;
136     }
137 
138     private void releaseBuffer() {
139         if (released) {
140             return;
141         }
142 
143         released = true;
144         buf.release();
145     }
146 
147     public void write(ByteBuffer src) {
148         synchronized (mutex) {
149             if (closed) {
150                 return;
151             }
152 
153             if (buf.hasRemaining()) {
154                 this.buf.compact();
155                 this.buf.put(src);
156                 this.buf.flip();
157             } else {
158                 this.buf.clear();
159                 this.buf.put(src);
160                 this.buf.flip();
161                 mutex.notifyAll();
162             }
163         }
164     }
165 
166     public void throwException(IOException e) {
167         synchronized (mutex) {
168             if (exception == null) {
169                 exception = e;
170 
171                 mutex.notifyAll();
172             }
173         }
174     }
175 }