1 /***
2 *
3 * Copyright 2004 Hiram Chirino
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 **/
18
19 package org.activeio.net;
20
21 import java.io.IOException;
22 import java.io.InterruptedIOException;
23 import java.net.InetAddress;
24 import java.net.Socket;
25 import java.net.SocketAddress;
26 import java.net.SocketException;
27 import java.nio.ByteBuffer;
28
29 import org.activeio.AsynchChannel;
30 import org.activeio.AsynchChannelListener;
31 import org.activeio.Packet;
32 import org.activeio.packet.ByteBufferPacket;
33 import org.activeio.packet.EOSPacket;
34
35 import EDU.oswego.cs.dl.util.concurrent.Latch;
36 import EDU.oswego.cs.dl.util.concurrent.SynchronizedBoolean;
37
38 import com.ibm.io.async.AsyncSocketChannel;
39 import com.ibm.io.async.IAbstractAsyncFuture;
40 import com.ibm.io.async.IAsyncFuture;
41 import com.ibm.io.async.ICompletionListener;
42
43 /***
44 * @version $Revision$
45 */
46 final public class AIOAsynchChannel implements AsynchChannel, ICompletionListener, SocketMetadata {
47
48 protected static final int DEFAULT_BUFFER_SIZE = ByteBufferPacket.DEFAULT_DIRECT_BUFFER_SIZE;
49
50 private final AsyncSocketChannel socketChannel;
51 private final Socket socket;
52
53 private AsynchChannelListener channelListener;
54 private ByteBuffer inputByteBuffer;
55
56 private final SynchronizedBoolean running = new SynchronizedBoolean(false);
57 private Latch doneLatch;
58
59 protected AIOAsynchChannel(AsyncSocketChannel socketChannel) throws IOException {
60 this.socketChannel = socketChannel;
61 this.socket = socketChannel.socket();
62 this.socket.setSendBufferSize(DEFAULT_BUFFER_SIZE);
63 this.socket.setReceiveBufferSize(DEFAULT_BUFFER_SIZE);
64 this.socket.setSoTimeout(0);
65 }
66
67 private ByteBuffer allocateBuffer() {
68 return ByteBuffer.allocateDirect(DEFAULT_BUFFER_SIZE);
69 }
70
71 public void setAsynchChannelListener(AsynchChannelListener channelListener) {
72 this.channelListener = channelListener;
73 }
74
75 public AsynchChannelListener getAsynchChannelListener() {
76 return channelListener;
77 }
78
79 public Object narrow(Class target) {
80 if( target.isAssignableFrom(getClass()) ) {
81 return this;
82 }
83 return null;
84 }
85
86 public void dispose() {
87 if( running.get() && channelListener!=null ) {
88 channelListener.onPacketError(new SocketException("Socket closed."));
89 }
90 try {
91 stop(NO_WAIT_TIMEOUT);
92 } catch (IOException e) {
93 }
94 try {
95 socketChannel.close();
96 } catch (IOException e) {
97 }
98 }
99
100 public void start() throws IOException {
101 if( running.commit(false, true) ) {
102 doneLatch = new Latch();
103 requestNextRead();
104 }
105 }
106
107 public void stop(long timeout) throws IOException {
108 if( running.commit(true, false) ) {
109 try {
110 if( timeout == NO_WAIT_TIMEOUT ) {
111 doneLatch.attempt(0);
112 } else if( timeout == WAIT_FOREVER_TIMEOUT ) {
113 doneLatch.acquire();
114 } else {
115 doneLatch.attempt(timeout);
116 }
117 } catch (InterruptedException e) {
118 throw new InterruptedIOException();
119 }
120 }
121 }
122
123 public void write(Packet packet) throws IOException {
124 ByteBuffer data = ((ByteBufferPacket)packet).getByteBuffer();
125 while( data.hasRemaining() ) {
126 IAsyncFuture future = socketChannel.write(data);
127 try {
128 future.getByteCount();
129 } catch (InterruptedException e) {
130 throw new InterruptedIOException();
131 }
132 }
133 }
134
135 public void flush() throws IOException {
136 }
137
138 public void futureCompleted(IAbstractAsyncFuture abstractFuture, Object attribute) {
139 IAsyncFuture future = (IAsyncFuture)abstractFuture;
140 try {
141
142 if( inputByteBuffer.position()>0 ) {
143 ByteBuffer remaining = inputByteBuffer.slice();
144 Packet data = new ByteBufferPacket(((ByteBuffer)inputByteBuffer.flip()).slice());
145
146 channelListener.onPacket(data);
147
148 inputByteBuffer = remaining;
149 requestNextRead();
150
151 } else {
152 channelListener.onPacket(EOSPacket.EOS_PACKET);
153 }
154
155 } catch (IOException e) {
156 channelListener.onPacketError(e);
157 }
158 }
159
160 private void requestNextRead() throws InterruptedIOException {
161
162
163 if( !running.get() ) {
164 doneLatch.release();
165 return;
166 }
167
168 try {
169
170 if( inputByteBuffer==null || !inputByteBuffer.hasRemaining() ) {
171 inputByteBuffer = allocateBuffer();
172 }
173
174 IAsyncFuture future = socketChannel.read(inputByteBuffer);
175 future.addCompletionListener(this, null, false);
176
177 } catch (InterruptedException e) {
178 throw new InterruptedIOException();
179 }
180
181 }
182
183 public InetAddress getInetAddress() {
184 return socket.getInetAddress();
185 }
186 public boolean getKeepAlive() throws SocketException {
187 return socket.getKeepAlive();
188 }
189 public InetAddress getLocalAddress() {
190 return socket.getLocalAddress();
191 }
192 public int getLocalPort() {
193 return socket.getLocalPort();
194 }
195 public SocketAddress getLocalSocketAddress() {
196 return socket.getLocalSocketAddress();
197 }
198 public boolean getOOBInline() throws SocketException {
199 return socket.getOOBInline();
200 }
201 public int getPort() {
202 return socket.getPort();
203 }
204 public int getReceiveBufferSize() throws SocketException {
205 return socket.getReceiveBufferSize();
206 }
207 public SocketAddress getRemoteSocketAddress() {
208 return socket.getRemoteSocketAddress();
209 }
210 public boolean getReuseAddress() throws SocketException {
211 return socket.getReuseAddress();
212 }
213 public int getSendBufferSize() throws SocketException {
214 return socket.getSendBufferSize();
215 }
216 public int getSoLinger() throws SocketException {
217 return socket.getSoLinger();
218 }
219 public int getSoTimeout() throws SocketException {
220 return socket.getSoTimeout();
221 }
222 public boolean getTcpNoDelay() throws SocketException {
223 return socket.getTcpNoDelay();
224 }
225 public int getTrafficClass() throws SocketException {
226 return socket.getTrafficClass();
227 }
228 public boolean isBound() {
229 return socket.isBound();
230 }
231 public boolean isClosed() {
232 return socket.isClosed();
233 }
234 public boolean isConnected() {
235 return socket.isConnected();
236 }
237 public void setKeepAlive(boolean on) throws SocketException {
238 socket.setKeepAlive(on);
239 }
240 public void setOOBInline(boolean on) throws SocketException {
241 socket.setOOBInline(on);
242 }
243 public void setReceiveBufferSize(int size) throws SocketException {
244 socket.setReceiveBufferSize(size);
245 }
246 public void setReuseAddress(boolean on) throws SocketException {
247 socket.setReuseAddress(on);
248 }
249 public void setSendBufferSize(int size) throws SocketException {
250 socket.setSendBufferSize(size);
251 }
252 public void setSoLinger(boolean on, int linger) throws SocketException {
253 socket.setSoLinger(on, linger);
254 }
255 public void setTcpNoDelay(boolean on) throws SocketException {
256 socket.setTcpNoDelay(on);
257 }
258 public void setTrafficClass(int tc) throws SocketException {
259 socket.setTrafficClass(tc);
260 }
261 public String toString() {
262 return "AIO Connection: "+getLocalSocketAddress()+" -> "+getRemoteSocketAddress();
263 }
264 }