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