1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.transport.socket.nio;
21
22 import java.net.InetSocketAddress;
23 import java.net.SocketAddress;
24 import java.nio.channels.DatagramChannel;
25 import java.nio.channels.SelectionKey;
26 import java.nio.channels.Selector;
27 import java.util.Collection;
28 import java.util.Iterator;
29 import java.util.concurrent.Executor;
30
31 import org.apache.mina.core.buffer.IoBuffer;
32 import org.apache.mina.core.polling.AbstractPollingConnectionlessIoAcceptor;
33 import org.apache.mina.core.service.IoAcceptor;
34 import org.apache.mina.core.service.IoProcessor;
35 import org.apache.mina.core.service.TransportMetadata;
36 import org.apache.mina.transport.socket.DatagramAcceptor;
37 import org.apache.mina.transport.socket.DatagramSessionConfig;
38 import org.apache.mina.transport.socket.DefaultDatagramSessionConfig;
39
40
41
42
43
44
45
46 public final class NioDatagramAcceptor
47 extends AbstractPollingConnectionlessIoAcceptor<NioSession, DatagramChannel>
48 implements DatagramAcceptor {
49
50 private volatile Selector selector;
51
52
53
54
55 public NioDatagramAcceptor() {
56 super(new DefaultDatagramSessionConfig());
57 }
58
59
60
61
62 public NioDatagramAcceptor(Executor executor) {
63 super(new DefaultDatagramSessionConfig(), executor);
64 }
65
66 @Override
67 protected void init() throws Exception {
68 this.selector = Selector.open();
69 }
70
71 @Override
72 protected void destroy() throws Exception {
73 if (selector != null) {
74 selector.close();
75 }
76 }
77
78 public TransportMetadata getTransportMetadata() {
79 return NioDatagramSession.METADATA;
80 }
81
82 @Override
83 public DatagramSessionConfig getSessionConfig() {
84 return (DatagramSessionConfig) super.getSessionConfig();
85 }
86
87 @Override
88 public InetSocketAddress getLocalAddress() {
89 return (InetSocketAddress) super.getLocalAddress();
90 }
91
92 @Override
93 public InetSocketAddress getDefaultLocalAddress() {
94 return (InetSocketAddress) super.getDefaultLocalAddress();
95 }
96
97 public void setDefaultLocalAddress(InetSocketAddress localAddress) {
98 setDefaultLocalAddress((SocketAddress) localAddress);
99 }
100
101 @Override
102 protected DatagramChannel open(SocketAddress localAddress) throws Exception {
103 final DatagramChannel c = DatagramChannel.open();
104 boolean success = false;
105 try {
106 new NioDatagramSessionConfig(c).setAll(getSessionConfig());
107 c.configureBlocking(false);
108 c.socket().bind(localAddress);
109 c.register(selector, SelectionKey.OP_READ);
110 success = true;
111 } finally {
112 if (!success) {
113 close(c);
114 }
115 }
116
117 return c;
118 }
119
120 @Override
121 protected boolean isReadable(DatagramChannel handle) {
122 SelectionKey key = handle.keyFor(selector);
123
124 if ((key == null) || (!key.isValid())) {
125 return false;
126 }
127
128 return key.isReadable();
129 }
130
131 @Override
132 protected boolean isWritable(DatagramChannel handle) {
133 SelectionKey key = handle.keyFor(selector);
134
135 if ((key == null) || (!key.isValid())) {
136 return false;
137 }
138
139 return key.isWritable();
140 }
141
142 @Override
143 protected SocketAddress localAddress(DatagramChannel handle)
144 throws Exception {
145 return handle.socket().getLocalSocketAddress();
146 }
147
148 @Override
149 protected NioSession newSession(
150 IoProcessor<NioSession> processor, DatagramChannel handle,
151 SocketAddress remoteAddress) {
152 SelectionKey key = handle.keyFor(selector);
153
154 if ((key == null) || (!key.isValid())) {
155 return null;
156 }
157
158 NioDatagramSession newSession = new NioDatagramSession(
159 this, handle, processor, remoteAddress);
160 newSession.setSelectionKey(key);
161
162 return newSession;
163 }
164
165 @Override
166 protected SocketAddress receive(DatagramChannel handle, IoBuffer buffer)
167 throws Exception {
168 return handle.receive(buffer.buf());
169 }
170
171 @Override
172 protected int select() throws Exception {
173 return selector.select();
174 }
175
176 @Override
177 protected int select(long timeout) throws Exception {
178 return selector.select(timeout);
179 }
180
181 @Override
182 protected Iterator<DatagramChannel> selectedHandles() {
183 return new DatagramChannelIterator(selector.selectedKeys());
184 }
185
186 @Override
187 protected int send(NioSession session, IoBuffer buffer,
188 SocketAddress remoteAddress) throws Exception {
189 return ((DatagramChannel) session.getChannel()).send(
190 buffer.buf(), remoteAddress);
191 }
192
193 @Override
194 protected void setInterestedInWrite(NioSession session, boolean isInterested)
195 throws Exception {
196 SelectionKey key = session.getSelectionKey();
197
198 if (key == null) {
199 return;
200 }
201
202 int newInterestOps = key.interestOps();
203
204 if (isInterested) {
205 newInterestOps |= SelectionKey.OP_WRITE;
206
207 } else {
208 newInterestOps &= ~SelectionKey.OP_WRITE;
209
210 }
211
212 key.interestOps(newInterestOps);
213 }
214
215 @Override
216 protected void close(DatagramChannel handle) throws Exception {
217 SelectionKey key = handle.keyFor(selector);
218
219 if (key != null) {
220 key.cancel();
221 }
222
223 handle.disconnect();
224 handle.close();
225 }
226
227 @Override
228 protected void wakeup() {
229 selector.wakeup();
230 }
231
232 private static class DatagramChannelIterator implements Iterator<DatagramChannel> {
233
234 private final Iterator<SelectionKey> i;
235
236 private DatagramChannelIterator(Collection<SelectionKey> keys) {
237 this.i = keys.iterator();
238 }
239
240 public boolean hasNext() {
241 return i.hasNext();
242 }
243
244 public DatagramChannel next() {
245 return (DatagramChannel) i.next().channel();
246 }
247
248 public void remove() {
249 i.remove();
250 }
251
252 }
253 }