1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.core.polling;
21
22 import java.net.SocketAddress;
23 import java.nio.channels.ClosedSelectorException;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Queue;
31 import java.util.Set;
32 import java.util.concurrent.ConcurrentHashMap;
33 import java.util.concurrent.ConcurrentLinkedQueue;
34 import java.util.concurrent.Executor;
35 import java.util.concurrent.Executors;
36 import java.util.concurrent.atomic.AtomicReference;
37
38 import org.apache.mina.core.RuntimeIoException;
39 import org.apache.mina.core.filterchain.IoFilter;
40 import org.apache.mina.core.service.AbstractIoAcceptor;
41 import org.apache.mina.core.service.IoAcceptor;
42 import org.apache.mina.core.service.IoHandler;
43 import org.apache.mina.core.service.IoProcessor;
44 import org.apache.mina.core.service.SimpleIoProcessorPool;
45 import org.apache.mina.core.session.AbstractIoSession;
46 import org.apache.mina.core.session.IoSession;
47 import org.apache.mina.core.session.IoSessionConfig;
48 import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
49 import org.apache.mina.util.ExceptionMonitor;
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67 public abstract class AbstractPollingIoAcceptor<S extends AbstractIoSession, H>
68 extends AbstractIoAcceptor {
69
70 private final IoProcessor<S> processor;
71
72 private final boolean createdProcessor;
73
74 private final Queue<AcceptorOperationFuture> registerQueue = new ConcurrentLinkedQueue<AcceptorOperationFuture>();
75
76 private final Queue<AcceptorOperationFuture> cancelQueue = new ConcurrentLinkedQueue<AcceptorOperationFuture>();
77
78 private final Map<SocketAddress, H> boundHandles = Collections
79 .synchronizedMap(new HashMap<SocketAddress, H>());
80
81 private final ServiceOperationFuture disposalFuture = new ServiceOperationFuture();
82
83
84 private volatile boolean selectable;
85
86
87 private AtomicReference<Acceptor> acceptorRef = new AtomicReference<Acceptor>();
88
89 protected boolean reuseAddress = false;
90
91
92
93
94
95 protected int backlog = 50;
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110 protected AbstractPollingIoAcceptor(IoSessionConfig sessionConfig,
111 Class<? extends IoProcessor<S>> processorClass) {
112 this(sessionConfig, null, new SimpleIoProcessorPool<S>(processorClass),
113 true);
114 }
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130 protected AbstractPollingIoAcceptor(IoSessionConfig sessionConfig,
131 Class<? extends IoProcessor<S>> processorClass, int processorCount) {
132 this(sessionConfig, null, new SimpleIoProcessorPool<S>(processorClass,
133 processorCount), true);
134 }
135
136
137
138
139
140
141
142
143
144
145
146
147
148 protected AbstractPollingIoAcceptor(IoSessionConfig sessionConfig,
149 IoProcessor<S> processor) {
150 this(sessionConfig, null, processor, false);
151 }
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169 protected AbstractPollingIoAcceptor(IoSessionConfig sessionConfig,
170 Executor executor, IoProcessor<S> processor) {
171 this(sessionConfig, executor, processor, false);
172 }
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193 private AbstractPollingIoAcceptor(IoSessionConfig sessionConfig,
194 Executor executor, IoProcessor<S> processor,
195 boolean createdProcessor) {
196 super(sessionConfig, executor);
197
198 if (processor == null) {
199 throw new IllegalArgumentException("processor");
200 }
201
202 this.processor = processor;
203 this.createdProcessor = createdProcessor;
204
205 try {
206
207 init();
208
209
210
211 selectable = true;
212 } catch (RuntimeException e) {
213 throw e;
214 } catch (Exception e) {
215 throw new RuntimeIoException("Failed to initialize.", e);
216 } finally {
217 if (!selectable) {
218 try {
219 destroy();
220 } catch (Exception e) {
221 ExceptionMonitor.getInstance().exceptionCaught(e);
222 }
223 }
224 }
225 }
226
227
228
229
230
231 protected abstract void init() throws Exception;
232
233
234
235
236
237
238 protected abstract void destroy() throws Exception;
239
240
241
242
243
244
245
246 protected abstract int select() throws Exception;
247
248
249
250
251 protected abstract void wakeup();
252
253
254
255
256
257
258 protected abstract Iterator<H> selectedHandles();
259
260
261
262
263
264
265
266 protected abstract H open(SocketAddress localAddress) throws Exception;
267
268
269
270
271
272
273
274 protected abstract SocketAddress localAddress(H handle) throws Exception;
275
276
277
278
279
280
281
282
283
284 protected abstract S accept(IoProcessor<S> processor, H handle)
285 throws Exception;
286
287
288
289
290
291
292 protected abstract void close(H handle) throws Exception;
293
294
295
296
297 @Override
298 protected void dispose0() throws Exception {
299 unbind();
300
301 startupAcceptor();
302 wakeup();
303 }
304
305
306
307
308 @Override
309 protected final Set<SocketAddress> bindInternal(
310 List<? extends SocketAddress> localAddresses) throws Exception {
311
312
313 AcceptorOperationFuture request = new AcceptorOperationFuture(
314 localAddresses);
315
316
317
318 registerQueue.add(request);
319
320
321
322 startupAcceptor();
323
324
325
326
327 wakeup();
328
329
330 request.awaitUninterruptibly();
331
332 if (request.getException() != null) {
333 throw request.getException();
334 }
335
336
337
338
339 Set<SocketAddress> newLocalAddresses = new HashSet<SocketAddress>();
340
341 for (H handle:boundHandles.values()) {
342 newLocalAddresses.add(localAddress(handle));
343 }
344
345 return newLocalAddresses;
346 }
347
348
349
350
351
352
353
354
355
356 private void startupAcceptor() {
357
358
359 if (!selectable) {
360 registerQueue.clear();
361 cancelQueue.clear();
362 }
363
364
365 Acceptor acceptor = acceptorRef.get();
366
367 if (acceptor == null) {
368 acceptor = new Acceptor();
369
370 if (acceptorRef.compareAndSet(null, acceptor)) {
371 executeWorker(acceptor);
372 }
373 }
374 }
375
376
377
378
379 @Override
380 protected final void unbind0(List<? extends SocketAddress> localAddresses)
381 throws Exception {
382 AcceptorOperationFuture future = new AcceptorOperationFuture(
383 localAddresses);
384
385 cancelQueue.add(future);
386 startupAcceptor();
387 wakeup();
388
389 future.awaitUninterruptibly();
390 if (future.getException() != null) {
391 throw future.getException();
392 }
393 }
394
395
396
397
398
399
400
401 private class Acceptor implements Runnable {
402 public void run() {
403 assert (acceptorRef.get() == this);
404
405 int nHandles = 0;
406
407 while (selectable) {
408 try {
409
410
411
412
413 int selected = select();
414
415
416
417
418 nHandles += registerHandles();
419
420
421
422
423 if (nHandles == 0) {
424 acceptorRef.set(null);
425
426 if (registerQueue.isEmpty() && cancelQueue.isEmpty()) {
427 assert (acceptorRef.get() != this);
428 break;
429 }
430
431 if (!acceptorRef.compareAndSet(null, this)) {
432 assert (acceptorRef.get() != this);
433 break;
434 }
435
436 assert (acceptorRef.get() == this);
437 }
438
439 if (selected > 0) {
440
441
442 processHandles(selectedHandles());
443 }
444
445
446 nHandles -= unregisterHandles();
447 } catch (ClosedSelectorException cse) {
448
449 break;
450 } catch (Throwable e) {
451 ExceptionMonitor.getInstance().exceptionCaught(e);
452
453 try {
454 Thread.sleep(1000);
455 } catch (InterruptedException e1) {
456 ExceptionMonitor.getInstance().exceptionCaught(e1);
457 }
458 }
459 }
460
461
462 if (selectable && isDisposing()) {
463 selectable = false;
464 try {
465 if (createdProcessor) {
466 processor.dispose();
467 }
468 } finally {
469 try {
470 synchronized (disposalLock) {
471 if (isDisposing()) {
472 destroy();
473 }
474 }
475 } catch (Exception e) {
476 ExceptionMonitor.getInstance().exceptionCaught(e);
477 } finally {
478 disposalFuture.setDone();
479 }
480 }
481 }
482 }
483
484
485
486
487
488
489
490
491
492
493 @SuppressWarnings("unchecked")
494 private void processHandles(Iterator<H> handles) throws Exception {
495 while (handles.hasNext()) {
496 H handle = handles.next();
497 handles.remove();
498
499
500
501 S session = accept(processor, handle);
502
503 if (session == null) {
504 break;
505 }
506
507 initSession(session, null, null);
508
509
510 session.getProcessor().add(session);
511 }
512 }
513 }
514
515
516
517
518
519
520
521
522
523
524 private int registerHandles() {
525 for (;;) {
526
527
528 AcceptorOperationFuture future = registerQueue.poll();
529
530 if (future == null) {
531 return 0;
532 }
533
534
535
536
537 Map<SocketAddress, H> newHandles = new ConcurrentHashMap<SocketAddress, H>();
538 List<SocketAddress> localAddresses = future.getLocalAddresses();
539
540 try {
541
542 for (SocketAddress a : localAddresses) {
543 H handle = open(a);
544 newHandles.put(localAddress(handle), handle);
545 }
546
547
548
549 boundHandles.putAll(newHandles);
550
551
552 future.setDone();
553 return newHandles.size();
554 } catch (Exception e) {
555
556 future.setException(e);
557 } finally {
558
559 if (future.getException() != null) {
560 for (H handle : newHandles.values()) {
561 try {
562 close(handle);
563 } catch (Exception e) {
564 ExceptionMonitor.getInstance().exceptionCaught(e);
565 }
566 }
567
568
569 wakeup();
570 }
571 }
572 }
573 }
574
575
576
577
578
579
580
581 private int unregisterHandles() {
582 int cancelledHandles = 0;
583 for (;;) {
584 AcceptorOperationFuture future = cancelQueue.poll();
585 if (future == null) {
586 break;
587 }
588
589
590 for (SocketAddress a : future.getLocalAddresses()) {
591 H handle = boundHandles.remove(a);
592
593 if (handle == null) {
594 continue;
595 }
596
597 try {
598 close(handle);
599 wakeup();
600 } catch (Throwable e) {
601 ExceptionMonitor.getInstance().exceptionCaught(e);
602 } finally {
603 cancelledHandles++;
604 }
605 }
606
607 future.setDone();
608 }
609
610 return cancelledHandles;
611 }
612
613
614
615
616 public final IoSession newSession(SocketAddress remoteAddress,
617 SocketAddress localAddress) {
618 throw new UnsupportedOperationException();
619 }
620
621
622
623
624 public int getBacklog() {
625 return backlog;
626 }
627
628
629
630
631 public void setBacklog(int backlog) {
632 synchronized (bindLock) {
633 if (isActive()) {
634 throw new IllegalStateException(
635 "backlog can't be set while the acceptor is bound.");
636 }
637
638 this.backlog = backlog;
639 }
640 }
641
642
643
644
645 public boolean isReuseAddress() {
646 return reuseAddress;
647 }
648
649
650
651
652 public void setReuseAddress(boolean reuseAddress) {
653 synchronized (bindLock) {
654 if (isActive()) {
655 throw new IllegalStateException(
656 "backlog can't be set while the acceptor is bound.");
657 }
658
659 this.reuseAddress = reuseAddress;
660 }
661 }
662 }