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.SelectableChannel;
25 import java.nio.channels.SelectionKey;
26 import java.nio.channels.Selector;
27 import java.util.Iterator;
28 import java.util.Set;
29 import java.util.concurrent.Executor;
30
31 import org.apache.mina.core.RuntimeIoException;
32 import org.apache.mina.core.buffer.IoBuffer;
33 import org.apache.mina.core.file.FileRegion;
34 import org.apache.mina.core.polling.AbstractPollingIoProcessor;
35
36
37
38
39
40
41
42 public final class NioProcessor extends AbstractPollingIoProcessor<NioSession> {
43
44 private final Selector selector;
45
46
47
48
49
50
51
52 public NioProcessor(Executor executor) {
53 super(executor);
54 try {
55
56 selector = Selector.open();
57 } catch (IOException e) {
58 throw new RuntimeIoException("Failed to open a selector.", e);
59 }
60 }
61
62 @Override
63 protected void dispose0() throws Exception {
64 selector.close();
65 }
66
67 @Override
68 protected int select(int timeout) throws Exception {
69 return selector.select(timeout);
70 }
71
72 @Override
73 protected int select() throws Exception {
74 return selector.select();
75 }
76
77 @Override
78 protected boolean isSelectorEmpty() {
79 return selector.keys().isEmpty();
80 }
81
82 @Override
83 protected void wakeup() {
84 selector.wakeup();
85 }
86
87 @Override
88 protected Iterator<NioSession> allSessions() {
89 return new IoSessionIterator(selector.keys());
90 }
91
92 @Override
93 protected Iterator<NioSession> selectedSessions() {
94 return new IoSessionIterator(selector.selectedKeys());
95 }
96
97 @Override
98 protected void init(NioSession session) throws Exception {
99 SelectableChannel ch = (SelectableChannel) session.getChannel();
100 ch.configureBlocking(false);
101 session.setSelectionKey(ch.register(selector, SelectionKey.OP_READ, session));
102 }
103
104 @Override
105 protected void destroy(NioSession session) throws Exception {
106 ByteChannel ch = session.getChannel();
107 SelectionKey key = session.getSelectionKey();
108 if (key != null) {
109 key.cancel();
110 }
111 ch.close();
112 }
113
114 @Override
115 protected SessionState state(NioSession session) {
116 SelectionKey key = session.getSelectionKey();
117 if (key == null) {
118 return SessionState.PREPARING;
119 }
120
121 return key.isValid()? SessionState.OPEN : SessionState.CLOSED;
122 }
123
124 @Override
125 protected boolean isReadable(NioSession session) {
126 SelectionKey key = session.getSelectionKey();
127 return key.isValid() && key.isReadable();
128 }
129
130 @Override
131 protected boolean isWritable(NioSession session) {
132 SelectionKey key = session.getSelectionKey();
133 return key.isValid() && key.isWritable();
134 }
135
136 @Override
137 protected boolean isInterestedInRead(NioSession session) {
138 SelectionKey key = session.getSelectionKey();
139 return key.isValid() && (key.interestOps() & SelectionKey.OP_READ) != 0;
140 }
141
142 @Override
143 protected boolean isInterestedInWrite(NioSession session) {
144 SelectionKey key = session.getSelectionKey();
145 return key.isValid() && (key.interestOps() & SelectionKey.OP_WRITE) != 0;
146 }
147
148 @Override
149 protected void setInterestedInRead(NioSession session, boolean value) throws Exception {
150 SelectionKey key = session.getSelectionKey();
151 int oldInterestOps = key.interestOps();
152 int newInterestOps;
153 if (value) {
154 newInterestOps = oldInterestOps | SelectionKey.OP_READ;
155 } else {
156 newInterestOps = oldInterestOps & ~SelectionKey.OP_READ;
157 }
158 if (oldInterestOps != newInterestOps) {
159 key.interestOps(newInterestOps);
160 }
161 }
162
163 @Override
164 protected void setInterestedInWrite(NioSession session, boolean value) throws Exception {
165 SelectionKey key = session.getSelectionKey();
166 int oldInterestOps = key.interestOps();
167 int newInterestOps;
168 if (value) {
169 newInterestOps = oldInterestOps | SelectionKey.OP_WRITE;
170 } else {
171 newInterestOps = oldInterestOps & ~SelectionKey.OP_WRITE;
172 }
173 if (oldInterestOps != newInterestOps) {
174 key.interestOps(newInterestOps);
175 }
176 }
177
178 @Override
179 protected int read(NioSession session, IoBuffer buf) throws Exception {
180 return session.getChannel().read(buf.buf());
181 }
182
183 @Override
184 protected int write(NioSession session, IoBuffer buf, int length) throws Exception {
185 if (buf.remaining() <= length) {
186 return session.getChannel().write(buf.buf());
187 } else {
188 int oldLimit = buf.limit();
189 buf.limit(buf.position() + length);
190 try {
191 return session.getChannel().write(buf.buf());
192 } finally {
193 buf.limit(oldLimit);
194 }
195 }
196 }
197
198 @Override
199 protected int transferFile(NioSession session, FileRegion region, int length) throws Exception {
200 try {
201 return (int) region.getFileChannel().transferTo(region.getPosition(), length, session.getChannel());
202 } catch (IOException e) {
203
204
205 String message = e.getMessage();
206 if (message != null && message.contains("temporarily unavailable")) {
207 return 0;
208 } else {
209 throw e;
210 }
211 }
212 }
213
214
215
216
217
218 protected static class IoSessionIterator implements Iterator<NioSession> {
219 private final Iterator<SelectionKey> iterator;
220
221
222
223
224
225
226 private IoSessionIterator(Set<SelectionKey> keys) {
227 iterator = keys.iterator();
228 }
229
230
231
232
233 public boolean hasNext() {
234 return iterator.hasNext();
235 }
236
237
238
239
240 public NioSession next() {
241 SelectionKey key = iterator.next();
242 NioSession nioSession = (NioSession) key.attachment();
243 return nioSession;
244 }
245
246
247
248
249 public void remove() {
250 iterator.remove();
251 }
252 }
253 }