View Javadoc

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.net.DatagramPacket;
23  import java.net.DatagramSocket;
24  import java.net.SocketException;
25  import java.net.SocketTimeoutException;
26  
27  import org.activeio.Packet;
28  import org.activeio.SynchChannel;
29  import org.activeio.SynchChannelServer;
30  import org.activeio.Packet.ByteSequence;
31  import org.activeio.packet.ByteArrayPacket;
32  import org.activeio.packet.FilterPacket;
33  
34  /***
35   * A {@see org.activeio.SynchChannel}implementation that uses
36   * TCP to talk to the network.
37   * 
38   * @version $Revision$
39   */
40  final public class DatagramSocketSynchChannel implements SynchChannel {
41  
42      private final class UDPFilterPacket extends FilterPacket {
43          private final DatagramPacket packet;
44  
45          private UDPFilterPacket(Packet next, DatagramPacket packet) {
46              super(next);
47              this.packet = packet;
48          }
49  
50          public Object narrow(Class target) {
51              if( target == DatagramContext.class ) {
52                  return new DatagramContext(packet);
53              }
54              return super.narrow(target);
55          }
56  
57          public Packet filter(Packet packet) {
58              return new UDPFilterPacket(packet, this.packet);
59          }
60      }
61  
62      private static final int DEFAULT_BUFFER_SIZE = 64 * 1024;
63  
64      private final DatagramSocket socket;
65  
66      private boolean disposed;
67  
68      private int curentSoTimeout;
69  
70      /***
71       * Construct basic helpers
72       * 
73       * @param wireFormat
74       * @throws IOException
75       */
76      protected DatagramSocketSynchChannel(DatagramSocket socket) throws IOException {
77          this.socket = socket;
78          socket.setReceiveBufferSize(DEFAULT_BUFFER_SIZE);
79          socket.setSendBufferSize(DEFAULT_BUFFER_SIZE);
80      }
81      
82      /***
83       * @see org.activeio.SynchChannel#read(long)
84       */
85      public org.activeio.Packet read(long timeout) throws IOException {
86          try {
87  
88              if (timeout == SynchChannelServer.WAIT_FOREVER_TIMEOUT)
89                  setSoTimeout(0);
90              else if (timeout == SynchChannelServer.NO_WAIT_TIMEOUT)
91                  setSoTimeout(1);
92              else
93                  setSoTimeout((int) timeout);
94  
95              // FYI: message data is truncated if biger than this buffer.
96              final byte data[] = new byte[DEFAULT_BUFFER_SIZE];
97              final DatagramPacket packet = new DatagramPacket(data, data.length);
98              socket.receive(packet);
99              
100             // A FilterPacket is used to provide the UdpDatagramContext via narrow.
101             return new UDPFilterPacket(new ByteArrayPacket(data, 0, packet.getLength()), packet);
102             
103         } catch (SocketTimeoutException e) {
104             return null;
105         }
106     }
107 
108     private void setSoTimeout(int i) throws SocketException {
109         if (curentSoTimeout != i) {
110             socket.setSoTimeout(i);
111             curentSoTimeout = i;
112         }
113     }
114 
115     /***
116      * @see org.activeio.Channel#write(org.activeio.channel.Packet)
117      */
118     public void write(org.activeio.Packet packet) throws IOException {
119         ByteSequence sequence = packet.asByteSequence();
120 
121         DatagramContext context = (DatagramContext) packet.narrow(DatagramContext.class);
122         if( context!=null ) {
123             socket.send(new DatagramPacket(sequence.getData(),sequence.getOffset(), sequence.getLength(), context.address, context.port.intValue()));
124         } else {
125             socket.send(new DatagramPacket(sequence.getData(),sequence.getOffset(), sequence.getLength()));
126         }
127     }
128 
129     /***
130      * @see org.activeio.Channel#flush()
131      */
132     public void flush() throws IOException {
133     }
134 
135     /***
136      * @see org.activeio.Disposable#dispose()
137      */
138     public void dispose() {
139         if (disposed)
140             return;
141         socket.close();
142         disposed = true;
143     }
144 
145     public void start() throws IOException {
146     }
147 
148     public void stop(long timeout) throws IOException {
149     }
150 
151     
152     public Object narrow(Class target) {
153         if( target.isAssignableFrom(getClass()) ) {
154             return this;
155         }
156         return null;
157     }
158 
159     public String toString() {
160         return "Datagram Connection: "+socket.getLocalSocketAddress()+" -> "+socket.getRemoteSocketAddress();
161     }
162 }