1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.common;
21
22 import java.util.AbstractSet;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.Set;
26 import java.util.concurrent.atomic.AtomicLong;
27
28
29
30
31
32
33
34
35 public abstract class AbstractIoService implements IoService {
36 private static final IoServiceListener SERVICE_ACTIVATION_LISTENER =
37 new IoServiceListener() {
38 public void serviceActivated(IoService service) {
39
40 AbstractIoService s = (AbstractIoService) service;
41 s.setLastReadTime(s.getActivationTime());
42 s.setLastWriteTime(s.getActivationTime());
43 s.lastThroughputCalculationTime = s.getActivationTime();
44
45
46 IdleStatusChecker.getInstance().addService(s);
47 }
48
49 public void serviceDeactivated(IoService service) {
50 IdleStatusChecker.getInstance().removeService(
51 (AbstractIoService) service);
52 }
53
54 public void serviceIdle(IoService service, IdleStatus idleStatus) {}
55 public void sessionCreated(IoSession session) {}
56 public void sessionDestroyed(IoSession session) {}
57 };
58
59
60
61
62 private IoFilterChainBuilder filterChainBuilder = new DefaultIoFilterChainBuilder();
63
64
65
66
67 private IoHandler handler;
68
69 private IoSessionDataStructureFactory sessionDataStructureFactory =
70 new DefaultIoSessionDataStructureFactory();
71
72
73
74
75 private final IoServiceListenerSupport listeners;
76
77 private final Object disposalLock = new Object();
78 private volatile boolean disposing;
79 private volatile boolean disposed;
80 private IoFuture disposalFuture;
81
82 private final AtomicLong readBytes = new AtomicLong();
83 private final AtomicLong writtenBytes = new AtomicLong();
84 private final AtomicLong readMessages = new AtomicLong();
85 private final AtomicLong writtenMessages = new AtomicLong();
86 private long lastReadTime;
87 private long lastWriteTime;
88
89 private final AtomicLong scheduledWriteBytes = new AtomicLong();
90 private final AtomicLong scheduledWriteMessages = new AtomicLong();
91
92 private final Object throughputCalculationLock = new Object();
93 private int throughputCalculationInterval = 3;
94
95 private long lastThroughputCalculationTime;
96 private long lastReadBytes;
97 private long lastWrittenBytes;
98 private long lastReadMessages;
99 private long lastWrittenMessages;
100 private double readBytesThroughput;
101 private double writtenBytesThroughput;
102 private double readMessagesThroughput;
103 private double writtenMessagesThroughput;
104 private double largestReadBytesThroughput;
105 private double largestWrittenBytesThroughput;
106 private double largestReadMessagesThroughput;
107 private double largestWrittenMessagesThroughput;
108
109 private final Object idlenessCheckLock = new Object();
110 private int idleTimeForRead;
111 private int idleTimeForWrite;
112 private int idleTimeForBoth;
113
114 private int idleCountForBoth;
115 private int idleCountForRead;
116 private int idleCountForWrite;
117
118 private long lastIdleTimeForBoth;
119 private long lastIdleTimeForRead;
120 private long lastIdleTimeForWrite;
121
122
123
124
125 private IoSessionConfig sessionConfig;
126
127 protected AbstractIoService(IoSessionConfig sessionConfig) {
128 if (sessionConfig == null) {
129 throw new NullPointerException("sessionConfig");
130 }
131
132 if (!getTransportMetadata().getSessionConfigType().isAssignableFrom(
133 sessionConfig.getClass())) {
134 throw new IllegalArgumentException("sessionConfig type: "
135 + sessionConfig.getClass() + " (expected: "
136 + getTransportMetadata().getSessionConfigType() + ")");
137 }
138
139 this.listeners = new IoServiceListenerSupport(this);
140 this.listeners.add(SERVICE_ACTIVATION_LISTENER);
141 this.sessionConfig = sessionConfig;
142
143
144
145 ExceptionMonitor.getInstance();
146 }
147
148 public final IoFilterChainBuilder getFilterChainBuilder() {
149 return filterChainBuilder;
150 }
151
152 public final void setFilterChainBuilder(IoFilterChainBuilder builder) {
153 if (builder == null) {
154 builder = new DefaultIoFilterChainBuilder();
155 }
156 filterChainBuilder = builder;
157 }
158
159 public final DefaultIoFilterChainBuilder getFilterChain() {
160 if (filterChainBuilder instanceof DefaultIoFilterChainBuilder) {
161 return (DefaultIoFilterChainBuilder) filterChainBuilder;
162 } else {
163 throw new IllegalStateException(
164 "Current filter chain builder is not a DefaultIoFilterChainBuilder.");
165 }
166 }
167
168 public final void addListener(IoServiceListener listener) {
169 listeners.add(listener);
170 }
171
172 public final void removeListener(IoServiceListener listener) {
173 listeners.remove(listener);
174 }
175
176 public final boolean isActive() {
177 return listeners.isActive();
178 }
179
180 public final boolean isDisposing() {
181 return disposing;
182 }
183
184 public final boolean isDisposed() {
185 return disposed;
186 }
187
188 public final void dispose() {
189 if (disposed) {
190 return;
191 }
192
193 IoFuture disposalFuture;
194 synchronized (disposalLock) {
195 disposalFuture = this.disposalFuture;
196 if (!disposing) {
197 disposing = true;
198 try {
199 this.disposalFuture = disposalFuture = dispose0();
200 } catch (Exception e) {
201 ExceptionMonitor.getInstance().exceptionCaught(e);
202 } finally {
203 if (disposalFuture == null) {
204 disposed = true;
205 }
206 }
207 }
208 }
209
210 if (disposalFuture != null) {
211 disposalFuture.awaitUninterruptibly();
212 }
213
214 disposed = true;
215 }
216
217
218
219
220
221 protected abstract IoFuture dispose0() throws Exception;
222
223 public final Set<IoSession> getManagedSessions() {
224 return listeners.getManagedSessions();
225 }
226
227 public final long getCumulativeManagedSessionCount() {
228 return listeners.getCumulativeManagedSessionCount();
229 }
230
231 public final int getLargestManagedSessionCount() {
232 return listeners.getLargestManagedSessionCount();
233 }
234
235 public final int getManagedSessionCount() {
236 return listeners.getManagedSessionCount();
237 }
238
239 public final IoHandler getHandler() {
240 return handler;
241 }
242
243 public final void setHandler(IoHandler handler) {
244 if (handler == null) {
245 throw new NullPointerException("handler");
246 }
247
248 if (isActive()) {
249 throw new IllegalStateException("handler cannot be set while the service is active.");
250 }
251
252 this.handler = handler;
253 }
254
255 public IoSessionConfig getSessionConfig() {
256 return sessionConfig;
257 }
258
259 public final IoSessionDataStructureFactory getSessionDataStructureFactory() {
260 return sessionDataStructureFactory;
261 }
262
263 public final void setSessionDataStructureFactory(IoSessionDataStructureFactory sessionDataStructureFactory) {
264 if (sessionDataStructureFactory == null) {
265 throw new NullPointerException("sessionDataStructureFactory");
266 }
267
268 if (isActive()) {
269 throw new IllegalStateException(
270 "sessionDataStructureFactory cannot be set while the service is active.");
271 }
272
273 this.sessionDataStructureFactory = sessionDataStructureFactory;
274 }
275
276 public final long getReadBytes() {
277 return readBytes.get();
278 }
279
280 protected final void increaseReadBytes(long increment, long currentTime) {
281 readBytes.addAndGet(increment);
282 lastReadTime = currentTime;
283 idleCountForBoth = 0;
284 idleCountForRead = 0;
285 }
286
287 public final long getReadMessages() {
288 return readMessages.get();
289 }
290
291 protected final void increaseReadMessages(long currentTime) {
292 readMessages.incrementAndGet();
293 lastReadTime = currentTime;
294 idleCountForBoth = 0;
295 idleCountForRead = 0;
296 }
297
298 public final int getThroughputCalculationInterval() {
299 return throughputCalculationInterval;
300 }
301
302 public final void setThroughputCalculationInterval(int throughputCalculationInterval) {
303 if (throughputCalculationInterval < 0) {
304 throw new IllegalArgumentException(
305 "throughputCalculationInterval: " + throughputCalculationInterval);
306 }
307
308 this.throughputCalculationInterval = throughputCalculationInterval;
309 }
310
311 public final long getThroughputCalculationIntervalInMillis() {
312 return throughputCalculationInterval * 1000L;
313 }
314
315 public final double getReadBytesThroughput() {
316 resetThroughput();
317 return readBytesThroughput;
318 }
319
320 public final double getWrittenBytesThroughput() {
321 resetThroughput();
322 return writtenBytesThroughput;
323 }
324
325 public final double getReadMessagesThroughput() {
326 resetThroughput();
327 return readMessagesThroughput;
328 }
329
330 public final double getWrittenMessagesThroughput() {
331 resetThroughput();
332 return writtenMessagesThroughput;
333 }
334
335 public final double getLargestReadBytesThroughput() {
336 return largestReadBytesThroughput;
337 }
338
339 public final double getLargestWrittenBytesThroughput() {
340 return largestWrittenBytesThroughput;
341 }
342
343 public final double getLargestReadMessagesThroughput() {
344 return largestReadMessagesThroughput;
345 }
346
347 public final double getLargestWrittenMessagesThroughput() {
348 return largestWrittenMessagesThroughput;
349 }
350
351 private void resetThroughput() {
352 if (getManagedSessionCount() == 0) {
353 readBytesThroughput = 0;
354 writtenBytesThroughput = 0;
355 readMessagesThroughput = 0;
356 writtenMessagesThroughput = 0;
357 }
358 }
359
360 private void updateThroughput(long currentTime) {
361 synchronized (throughputCalculationLock) {
362 int interval = (int) (currentTime - lastThroughputCalculationTime);
363 long minInterval = getThroughputCalculationIntervalInMillis();
364 if (minInterval == 0 || interval < minInterval) {
365 return;
366 }
367
368 long readBytes = this.readBytes.get();
369 long writtenBytes = this.writtenBytes.get();
370 long readMessages = this.readMessages.get();
371 long writtenMessages = this.writtenMessages.get();
372
373 readBytesThroughput = (readBytes - lastReadBytes) * 1000.0 / interval;
374 writtenBytesThroughput = (writtenBytes - lastWrittenBytes) * 1000.0 / interval;
375 readMessagesThroughput = (readMessages - lastReadMessages) * 1000.0 / interval;
376 writtenMessagesThroughput = (writtenMessages - lastWrittenMessages) * 1000.0 / interval;
377
378 if (readBytesThroughput > largestReadBytesThroughput) {
379 largestReadBytesThroughput = readBytesThroughput;
380 }
381 if (writtenBytesThroughput > largestWrittenBytesThroughput) {
382 largestWrittenBytesThroughput = writtenBytesThroughput;
383 }
384 if (readMessagesThroughput > largestReadMessagesThroughput) {
385 largestReadMessagesThroughput = readMessagesThroughput;
386 }
387 if (writtenMessagesThroughput > largestWrittenMessagesThroughput) {
388 largestWrittenMessagesThroughput = writtenMessagesThroughput;
389 }
390
391 lastReadBytes = readBytes;
392 lastWrittenBytes = writtenBytes;
393 lastReadMessages = readMessages;
394 lastWrittenMessages = writtenMessages;
395
396 lastThroughputCalculationTime = currentTime;
397 }
398 }
399
400 public final long getScheduledWriteBytes() {
401 return scheduledWriteBytes.get();
402 }
403
404 protected final void increaseScheduledWriteBytes(long increment) {
405 scheduledWriteBytes.addAndGet(increment);
406 }
407
408 public final long getScheduledWriteMessages() {
409 return scheduledWriteMessages.get();
410 }
411
412 protected final void increaseScheduledWriteMessages() {
413 scheduledWriteMessages.incrementAndGet();
414 }
415
416 protected final void decreaseScheduledWriteMessages() {
417 scheduledWriteMessages.decrementAndGet();
418 }
419
420 public final long getActivationTime() {
421 return listeners.getActivationTime();
422 }
423
424 public final long getLastIoTime() {
425 return Math.max(lastReadTime, lastWriteTime);
426 }
427
428 public final long getLastReadTime() {
429 return lastReadTime;
430 }
431
432 protected final void setLastReadTime(long lastReadTime) {
433 this.lastReadTime = lastReadTime;
434 }
435
436 public final long getLastWriteTime() {
437 return lastWriteTime;
438 }
439
440 protected final void setLastWriteTime(long lastWriteTime) {
441 this.lastWriteTime = lastWriteTime;
442 }
443
444 public final long getWrittenBytes() {
445 return writtenBytes.get();
446 }
447
448 protected final void increaseWrittenBytes(long increment, long currentTime) {
449 writtenBytes.addAndGet(increment);
450 lastWriteTime = currentTime;
451 idleCountForBoth = 0;
452 idleCountForWrite = 0;
453 }
454
455 public final long getWrittenMessages() {
456 return writtenMessages.get();
457 }
458
459 protected final void increaseWrittenMessages(long currentTime) {
460 writtenMessages.incrementAndGet();
461 lastWriteTime = currentTime;
462 idleCountForBoth = 0;
463 idleCountForWrite = 0;
464 }
465
466 public final int getIdleTime(IdleStatus status) {
467 if (status == IdleStatus.BOTH_IDLE) {
468 return idleTimeForBoth;
469 }
470
471 if (status == IdleStatus.READER_IDLE) {
472 return idleTimeForRead;
473 }
474
475 if (status == IdleStatus.WRITER_IDLE) {
476 return idleTimeForWrite;
477 }
478
479 throw new IllegalArgumentException("Unknown idle status: " + status);
480 }
481
482 public final long getIdleTimeInMillis(IdleStatus status) {
483 return getIdleTime(status) * 1000L;
484 }
485
486 public final void setIdleTime(IdleStatus status, int idleTime) {
487 if (idleTime < 0) {
488 throw new IllegalArgumentException("Illegal idle time: " + idleTime);
489 }
490
491 if (status == IdleStatus.BOTH_IDLE) {
492 idleTimeForBoth = idleTime;
493 } else if (status == IdleStatus.READER_IDLE) {
494 idleTimeForRead = idleTime;
495 } else if (status == IdleStatus.WRITER_IDLE) {
496 idleTimeForWrite = idleTime;
497 } else {
498 throw new IllegalArgumentException("Unknown idle status: " + status);
499 }
500
501 if (idleTime == 0) {
502 if (status == IdleStatus.BOTH_IDLE) {
503 idleCountForBoth = 0;
504 } else if (status == IdleStatus.READER_IDLE) {
505 idleCountForRead = 0;
506 } else if (status == IdleStatus.WRITER_IDLE) {
507 idleCountForWrite = 0;
508 }
509 }
510 }
511
512 public final boolean isIdle(IdleStatus status) {
513 if (status == IdleStatus.BOTH_IDLE) {
514 return idleCountForBoth > 0;
515 }
516
517 if (status == IdleStatus.READER_IDLE) {
518 return idleCountForRead > 0;
519 }
520
521 if (status == IdleStatus.WRITER_IDLE) {
522 return idleCountForWrite > 0;
523 }
524
525 throw new IllegalArgumentException("Unknown idle status: " + status);
526 }
527
528 public final int getIdleCount(IdleStatus status) {
529 if (status == IdleStatus.BOTH_IDLE) {
530 return idleCountForBoth;
531 }
532
533 if (status == IdleStatus.READER_IDLE) {
534 return idleCountForRead;
535 }
536
537 if (status == IdleStatus.WRITER_IDLE) {
538 return idleCountForWrite;
539 }
540
541 throw new IllegalArgumentException("Unknown idle status: " + status);
542 }
543
544 public final long getLastIdleTime(IdleStatus status) {
545 if (status == IdleStatus.BOTH_IDLE) {
546 return lastIdleTimeForBoth;
547 }
548
549 if (status == IdleStatus.READER_IDLE) {
550 return lastIdleTimeForRead;
551 }
552
553 if (status == IdleStatus.WRITER_IDLE) {
554 return lastIdleTimeForWrite;
555 }
556
557 throw new IllegalArgumentException("Unknown idle status: " + status);
558 }
559
560 private void increaseIdleCount(IdleStatus status, long currentTime) {
561 if (status == IdleStatus.BOTH_IDLE) {
562 idleCountForBoth++;
563 lastIdleTimeForBoth = currentTime;
564 } else if (status == IdleStatus.READER_IDLE) {
565 idleCountForRead++;
566 lastIdleTimeForRead = currentTime;
567 } else if (status == IdleStatus.WRITER_IDLE) {
568 idleCountForWrite++;
569 lastIdleTimeForWrite = currentTime;
570 } else {
571 throw new IllegalArgumentException("Unknown idle status: " + status);
572 }
573 }
574
575 protected final void notifyIdleness(long currentTime) {
576 updateThroughput(currentTime);
577
578 synchronized (idlenessCheckLock) {
579 notifyIdleness(
580 currentTime,
581 getIdleTimeInMillis(IdleStatus.BOTH_IDLE),
582 IdleStatus.BOTH_IDLE, Math.max(
583 getLastIoTime(),
584 getLastIdleTime(IdleStatus.BOTH_IDLE)));
585
586 notifyIdleness(
587 currentTime,
588 getIdleTimeInMillis(IdleStatus.READER_IDLE),
589 IdleStatus.READER_IDLE, Math.max(
590 getLastReadTime(),
591 getLastIdleTime(IdleStatus.READER_IDLE)));
592
593 notifyIdleness(
594 currentTime,
595 getIdleTimeInMillis(IdleStatus.WRITER_IDLE),
596 IdleStatus.WRITER_IDLE, Math.max(
597 getLastWriteTime(),
598 getLastIdleTime(IdleStatus.WRITER_IDLE)));
599 }
600 }
601
602 private void notifyIdleness(
603 long currentTime, long idleTime, IdleStatus status, long lastIoTime) {
604 if (idleTime > 0 && lastIoTime != 0
605 && currentTime - lastIoTime >= idleTime) {
606 increaseIdleCount(status, currentTime);
607 listeners.fireServiceIdle(status);
608 }
609 }
610
611 public final int getBothIdleCount() {
612 return getIdleCount(IdleStatus.BOTH_IDLE);
613 }
614
615 public final long getLastBothIdleTime() {
616 return getLastIdleTime(IdleStatus.BOTH_IDLE);
617 }
618
619 public final long getLastReaderIdleTime() {
620 return getLastIdleTime(IdleStatus.READER_IDLE);
621 }
622
623 public final long getLastWriterIdleTime() {
624 return getLastIdleTime(IdleStatus.WRITER_IDLE);
625 }
626
627 public final int getReaderIdleCount() {
628 return getIdleCount(IdleStatus.READER_IDLE);
629 }
630
631 public final int getWriterIdleCount() {
632 return getIdleCount(IdleStatus.WRITER_IDLE);
633 }
634
635 public final int getBothIdleTime() {
636 return getIdleTime(IdleStatus.BOTH_IDLE);
637 }
638
639 public final long getBothIdleTimeInMillis() {
640 return getIdleTimeInMillis(IdleStatus.BOTH_IDLE);
641 }
642
643 public final int getReaderIdleTime() {
644 return getIdleTime(IdleStatus.READER_IDLE);
645 }
646
647 public final long getReaderIdleTimeInMillis() {
648 return getIdleTimeInMillis(IdleStatus.READER_IDLE);
649 }
650
651 public final int getWriterIdleTime() {
652 return getIdleTime(IdleStatus.WRITER_IDLE);
653 }
654
655 public final long getWriterIdleTimeInMillis() {
656 return getIdleTimeInMillis(IdleStatus.WRITER_IDLE);
657 }
658
659 public final boolean isBothIdle() {
660 return isIdle(IdleStatus.BOTH_IDLE);
661 }
662
663 public final boolean isReaderIdle() {
664 return isIdle(IdleStatus.READER_IDLE);
665 }
666
667 public final boolean isWriterIdle() {
668 return isIdle(IdleStatus.WRITER_IDLE);
669 }
670
671 public final void setBothIdleTime(int idleTime) {
672 setIdleTime(IdleStatus.BOTH_IDLE, idleTime);
673 }
674
675 public final void setReaderIdleTime(int idleTime) {
676 setIdleTime(IdleStatus.READER_IDLE, idleTime);
677 }
678
679 public final void setWriterIdleTime(int idleTime) {
680 setIdleTime(IdleStatus.WRITER_IDLE, idleTime);
681 }
682
683 public final Set<WriteFuture> broadcast(Object message) {
684
685
686
687 final List<WriteFuture> futures = IoUtil.broadcast(
688 message, getManagedSessions());
689 return new AbstractSet<WriteFuture>() {
690 @Override
691 public Iterator<WriteFuture> iterator() {
692 return futures.iterator();
693 }
694
695 @Override
696 public int size() {
697 return futures.size();
698 }
699 };
700 }
701
702 protected final IoServiceListenerSupport getListeners() {
703 return listeners;
704 }
705
706
707 @SuppressWarnings("unchecked")
708 protected final void finishSessionInitialization(
709 IoSession session, IoFuture future, IoSessionInitializer sessionInitializer) {
710
711 if (getLastReadTime() == 0) {
712 setLastReadTime(getActivationTime());
713 }
714 if (getLastWriteTime() == 0) {
715 setLastWriteTime(getActivationTime());
716 }
717
718
719
720
721
722 try {
723 ((AbstractIoSession) session).setAttributeMap(
724 session.getService().getSessionDataStructureFactory().getAttributeMap(session));
725 } catch (IoSessionInitializationException e) {
726 throw e;
727 } catch (Exception e) {
728 throw new IoSessionInitializationException(
729 "Failed to initialize an attributeMap.", e);
730 }
731
732 try {
733 ((AbstractIoSession) session).setWriteRequestQueue(
734 session.getService().getSessionDataStructureFactory().getWriteRequestQueue(session));
735 } catch (IoSessionInitializationException e) {
736 throw e;
737 } catch (Exception e) {
738 throw new IoSessionInitializationException(
739 "Failed to initialize a writeRequestQueue.", e);
740 }
741
742 if (future != null && future instanceof ConnectFuture) {
743
744 session.setAttribute(DefaultIoFilterChain.SESSION_OPENED_FUTURE, future);
745 }
746
747 if (sessionInitializer != null) {
748 sessionInitializer.initializeSession(session, future);
749 }
750
751 finishSessionInitialization0(session, future);
752 }
753
754
755
756
757
758
759
760 @SuppressWarnings("unused")
761 protected void finishSessionInitialization0(IoSession session, IoFuture future) {}
762
763 protected static class ServiceOperationFuture extends DefaultIoFuture {
764 public ServiceOperationFuture() {
765 super(null);
766 }
767
768 public final boolean isDone() {
769 return getValue() == Boolean.TRUE;
770 }
771
772 public final void setDone() {
773 setValue(Boolean.TRUE);
774 }
775
776 public final Exception getException() {
777 if (getValue() instanceof Exception) {
778 return (Exception) getValue();
779 } else {
780 return null;
781 }
782 }
783
784 public final void setException(Exception exception) {
785 if (exception == null) {
786 throw new NullPointerException("exception");
787 }
788 setValue(exception);
789 }
790 }
791 }