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.io.IOException;
23 import java.nio.channels.ByteChannel;
24 import java.nio.channels.DatagramChannel;
25 import java.nio.channels.SelectableChannel;
26 import java.nio.channels.SelectionKey;
27 import java.nio.channels.Selector;
28 import java.nio.channels.SocketChannel;
29 import java.util.Iterator;
30 import java.util.Set;
31 import java.util.concurrent.Executor;
32
33 import org.apache.mina.core.RuntimeIoException;
34 import org.apache.mina.core.buffer.IoBuffer;
35 import org.apache.mina.core.file.FileRegion;
36 import org.apache.mina.core.polling.AbstractPollingIoProcessor;
37 import org.apache.mina.core.session.SessionState;
38
39
40
41
42
43
44 public final class NioProcessor extends AbstractPollingIoProcessor<NioSession> {
45
46 private Selector selector;
47
48
49
50
51
52
53
54 public NioProcessor(Executor executor) {
55 super(executor);
56
57 try {
58
59 selector = Selector.open();
60 } catch (IOException e) {
61 throw new RuntimeIoException("Failed to open a selector.", e);
62 }
63 }
64
65 @Override
66 protected void doDispose() throws Exception {
67 selector.close();
68 }
69
70 @Override
71 protected int select(long timeout) throws Exception {
72 return selector.select(timeout);
73 }
74
75 @Override
76 protected int select() throws Exception {
77 return selector.select();
78 }
79
80 @Override
81 protected boolean isSelectorEmpty() {
82 return selector.keys().isEmpty();
83 }
84
85 @Override
86 protected void wakeup() {
87 wakeupCalled.getAndSet(true);
88 selector.wakeup();
89 }
90
91 @Override
92 protected Iterator<NioSession> allSessions() {
93 return new IoSessionIterator(selector.keys());
94 }
95
96 @SuppressWarnings("synthetic-access")
97 @Override
98 protected Iterator<NioSession> selectedSessions() {
99 return new IoSessionIterator(selector.selectedKeys());
100 }
101
102 @Override
103 protected void init(NioSession session) throws Exception {
104 SelectableChannel ch = (SelectableChannel) session.getChannel();
105 ch.configureBlocking(false);
106 session.setSelectionKey(ch.register(selector, SelectionKey.OP_READ, session));
107 }
108
109 @Override
110 protected void destroy(NioSession session) throws Exception {
111 ByteChannel ch = session.getChannel();
112 SelectionKey key = session.getSelectionKey();
113 if (key != null) {
114 key.cancel();
115 }
116 ch.close();
117 }
118
119
120
121
122
123
124 @Override
125 protected void registerNewSelector() throws IOException {
126 synchronized (selector) {
127 Set<SelectionKey> keys = selector.keys();
128
129
130 Selector newSelector = Selector.open();
131
132
133 for (SelectionKey key : keys) {
134 SelectableChannel ch = key.channel();
135
136
137 NioSession session = (NioSession) key.attachment();
138 SelectionKey newKey = ch.register(newSelector, key.interestOps(), session);
139 session.setSelectionKey(newKey);
140 }
141
142
143 selector.close();
144 selector = newSelector;
145 }
146 }
147
148
149
150
151 @Override
152 protected boolean isBrokenConnection() throws IOException {
153
154 boolean brokenSession = false;
155
156 synchronized (selector) {
157
158 Set<SelectionKey> keys = selector.keys();
159
160
161
162 for (SelectionKey key : keys) {
163 SelectableChannel channel = key.channel();
164
165 if ((((channel instanceof DatagramChannel) && !((DatagramChannel) channel).isConnected()))
166 || ((channel instanceof SocketChannel) && !((SocketChannel) channel).isConnected())) {
167
168
169 key.cancel();
170
171
172 brokenSession = true;
173 }
174 }
175 }
176
177 return brokenSession;
178 }
179
180
181
182
183 @Override
184 protected SessionState getState(NioSession session) {
185 SelectionKey key = session.getSelectionKey();
186
187 if (key == null) {
188
189 return SessionState.OPENING;
190 }
191
192 if (key.isValid()) {
193
194 return SessionState.OPENED;
195 } else {
196
197 return SessionState.CLOSING;
198 }
199 }
200
201 @Override
202 protected boolean isReadable(NioSession session) {
203 SelectionKey key = session.getSelectionKey();
204 return key.isValid() && key.isReadable();
205 }
206
207 @Override
208 protected boolean isWritable(NioSession session) {
209 SelectionKey key = session.getSelectionKey();
210 return key.isValid() && key.isWritable();
211 }
212
213 @Override
214 protected boolean isInterestedInRead(NioSession session) {
215 SelectionKey key = session.getSelectionKey();
216 return key.isValid() && ((key.interestOps() & SelectionKey.OP_READ) != 0);
217 }
218
219 @Override
220 protected boolean isInterestedInWrite(NioSession session) {
221 SelectionKey key = session.getSelectionKey();
222 return key.isValid() && ((key.interestOps() & SelectionKey.OP_WRITE) != 0);
223 }
224
225
226
227
228 @Override
229 protected void setInterestedInRead(NioSession session, boolean isInterested) throws Exception {
230 SelectionKey key = session.getSelectionKey();
231 int oldInterestOps = key.interestOps();
232 int newInterestOps = oldInterestOps;
233
234 if (isInterested) {
235 newInterestOps |= SelectionKey.OP_READ;
236 } else {
237 newInterestOps &= ~SelectionKey.OP_READ;
238 }
239
240 if (oldInterestOps != newInterestOps) {
241 key.interestOps(newInterestOps);
242 }
243 }
244
245
246
247
248 @Override
249 protected void setInterestedInWrite(NioSession session, boolean isInterested) throws Exception {
250 SelectionKey key = session.getSelectionKey();
251
252 if (key == null) {
253 return;
254 }
255
256 int newInterestOps = key.interestOps();
257
258 if (isInterested) {
259 newInterestOps |= SelectionKey.OP_WRITE;
260
261 } else {
262 newInterestOps &= ~SelectionKey.OP_WRITE;
263
264 }
265
266 key.interestOps(newInterestOps);
267 }
268
269 @Override
270 protected int read(NioSession session, IoBuffer buf) throws Exception {
271 ByteChannel channel = session.getChannel();
272
273 return channel.read(buf.buf());
274 }
275
276 @Override
277 protected int write(NioSession session, IoBuffer buf, int length) throws Exception {
278 if (buf.remaining() <= length) {
279 return session.getChannel().write(buf.buf());
280 }
281
282 int oldLimit = buf.limit();
283 buf.limit(buf.position() + length);
284 try {
285 return session.getChannel().write(buf.buf());
286 } finally {
287 buf.limit(oldLimit);
288 }
289 }
290
291 @Override
292 protected int transferFile(NioSession session, FileRegion region, int length) throws Exception {
293 try {
294 return (int) region.getFileChannel().transferTo(region.getPosition(), length, session.getChannel());
295 } catch (IOException e) {
296
297
298 String message = e.getMessage();
299 if ((message != null) && message.contains("temporarily unavailable")) {
300 return 0;
301 }
302
303 throw e;
304 }
305 }
306
307
308
309
310
311 protected static class IoSessionIterator<NioSession> implements Iterator<NioSession> {
312 private final Iterator<SelectionKey> iterator;
313
314
315
316
317
318
319
320 private IoSessionIterator(Set<SelectionKey> keys) {
321 iterator = keys.iterator();
322 }
323
324
325
326
327 public boolean hasNext() {
328 return iterator.hasNext();
329 }
330
331
332
333
334 public NioSession next() {
335 SelectionKey key = iterator.next();
336 NioSession nioSession = (NioSession) key.attachment();
337 return nioSession;
338 }
339
340
341
342
343 public void remove() {
344 iterator.remove();
345 }
346 }
347 }