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 dispose0() 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,
107 session));
108 }
109
110 @Override
111 protected void destroy(NioSession session) throws Exception {
112 ByteChannel ch = session.getChannel();
113 SelectionKey key = session.getSelectionKey();
114 if (key != null) {
115 key.cancel();
116 }
117 ch.close();
118 }
119
120
121
122
123
124
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 protected boolean isBrokenConnection() throws IOException {
152
153 boolean brokenSession = false;
154
155 synchronized (selector) {
156
157 Set<SelectionKey> keys = selector.keys();
158
159
160
161 for (SelectionKey key : keys) {
162 SelectableChannel channel = key.channel();
163
164 if ((((channel instanceof DatagramChannel) && ((DatagramChannel) channel)
165 .isConnected()))
166 || ((channel instanceof SocketChannel) && ((SocketChannel) channel)
167 .isConnected())) {
168
169
170 key.cancel();
171
172
173 brokenSession = true;
174 }
175 }
176 }
177
178 return brokenSession;
179 }
180
181
182
183
184 @Override
185 protected SessionState getState(NioSession session) {
186 SelectionKey key = session.getSelectionKey();
187
188 if (key == null) {
189
190 return SessionState.OPENING;
191 }
192
193 if (key.isValid()) {
194
195 return SessionState.OPENED;
196 } else {
197
198 return SessionState.CLOSING;
199 }
200 }
201
202 @Override
203 protected boolean isReadable(NioSession session) {
204 SelectionKey key = session.getSelectionKey();
205 return key.isValid() && key.isReadable();
206 }
207
208 @Override
209 protected boolean isWritable(NioSession session) {
210 SelectionKey key = session.getSelectionKey();
211 return key.isValid() && key.isWritable();
212 }
213
214 @Override
215 protected boolean isInterestedInRead(NioSession session) {
216 SelectionKey key = session.getSelectionKey();
217 return key.isValid() && (key.interestOps() & SelectionKey.OP_READ) != 0;
218 }
219
220 @Override
221 protected boolean isInterestedInWrite(NioSession session) {
222 SelectionKey key = session.getSelectionKey();
223 return key.isValid()
224 && (key.interestOps() & SelectionKey.OP_WRITE) != 0;
225 }
226
227
228
229
230 @Override
231 protected void setInterestedInRead(NioSession session, boolean isInterested)
232 throws Exception {
233 SelectionKey key = session.getSelectionKey();
234 int oldInterestOps = key.interestOps();
235 int newInterestOps = oldInterestOps;
236
237 if (isInterested) {
238 newInterestOps |= SelectionKey.OP_READ;
239 } else {
240 newInterestOps &= ~SelectionKey.OP_READ;
241 }
242
243 if (oldInterestOps != newInterestOps) {
244 key.interestOps(newInterestOps);
245 }
246 }
247
248
249
250
251 @Override
252 protected void setInterestedInWrite(NioSession session, boolean isInterested)
253 throws Exception {
254 SelectionKey key = session.getSelectionKey();
255
256 if (key == null) {
257 return;
258 }
259
260 int newInterestOps = key.interestOps();
261
262 if (isInterested) {
263 newInterestOps |= SelectionKey.OP_WRITE;
264
265 } else {
266 newInterestOps &= ~SelectionKey.OP_WRITE;
267
268 }
269
270 key.interestOps(newInterestOps);
271 }
272
273 @Override
274 protected int read(NioSession session, IoBuffer buf) throws Exception {
275 ByteChannel channel = session.getChannel();
276
277 return session.getChannel().read(buf.buf());
278 }
279
280 @Override
281 protected int write(NioSession session, IoBuffer buf, int length)
282 throws Exception {
283 if (buf.remaining() <= length) {
284 return session.getChannel().write(buf.buf());
285 }
286
287 int oldLimit = buf.limit();
288 buf.limit(buf.position() + length);
289 try {
290 return session.getChannel().write(buf.buf());
291 } finally {
292 buf.limit(oldLimit);
293 }
294 }
295
296 @Override
297 protected int transferFile(NioSession session, FileRegion region, int length)
298 throws Exception {
299 try {
300 return (int) region.getFileChannel().transferTo(
301 region.getPosition(), length, session.getChannel());
302 } catch (IOException e) {
303
304
305 String message = e.getMessage();
306 if (message != null && message.contains("temporarily unavailable")) {
307 return 0;
308 }
309
310 throw e;
311 }
312 }
313
314
315
316
317
318 protected static class IoSessionIterator<NioSession> implements
319 Iterator<NioSession> {
320 private final Iterator<SelectionKey> iterator;
321
322
323
324
325
326
327
328 private IoSessionIterator(Set<SelectionKey> keys) {
329 iterator = keys.iterator();
330 }
331
332
333
334
335 public boolean hasNext() {
336 return iterator.hasNext();
337 }
338
339
340
341
342 public NioSession next() {
343 SelectionKey key = iterator.next();
344 NioSession nioSession = (NioSession) key.attachment();
345 return nioSession;
346 }
347
348
349
350
351 public void remove() {
352 iterator.remove();
353 }
354 }
355 }