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.session;
21
22 import java.io.File;
23 import java.io.FileInputStream;
24 import java.io.IOException;
25 import java.net.SocketAddress;
26 import java.nio.channels.FileChannel;
27 import java.util.Iterator;
28 import java.util.Queue;
29 import java.util.Set;
30 import java.util.concurrent.atomic.AtomicBoolean;
31 import java.util.concurrent.atomic.AtomicInteger;
32
33 import org.apache.mina.core.buffer.IoBuffer;
34 import org.apache.mina.core.file.DefaultFileRegion;
35 import org.apache.mina.core.filterchain.IoFilterChain;
36 import org.apache.mina.core.future.CloseFuture;
37 import org.apache.mina.core.future.DefaultCloseFuture;
38 import org.apache.mina.core.future.DefaultReadFuture;
39 import org.apache.mina.core.future.DefaultWriteFuture;
40 import org.apache.mina.core.future.IoFutureListener;
41 import org.apache.mina.core.future.ReadFuture;
42 import org.apache.mina.core.future.WriteFuture;
43 import org.apache.mina.core.service.AbstractIoService;
44 import org.apache.mina.core.service.IoAcceptor;
45 import org.apache.mina.core.service.IoProcessor;
46 import org.apache.mina.core.service.IoService;
47 import org.apache.mina.core.service.TransportMetadata;
48 import org.apache.mina.core.write.DefaultWriteRequest;
49 import org.apache.mina.core.write.WriteException;
50 import org.apache.mina.core.write.WriteRequest;
51 import org.apache.mina.core.write.WriteRequestQueue;
52 import org.apache.mina.core.write.WriteTimeoutException;
53 import org.apache.mina.core.write.WriteToClosedSessionException;
54 import org.apache.mina.util.CircularQueue;
55 import org.apache.mina.util.ExceptionMonitor;
56
57
58
59
60
61
62
63
64 public abstract class AbstractIoSession implements IoSession {
65
66 private static final AttributeKey READY_READ_FUTURES_KEY =
67 new AttributeKey(AbstractIoSession.class, "readyReadFutures");
68
69 private static final AttributeKey WAITING_READ_FUTURES_KEY =
70 new AttributeKey(AbstractIoSession.class, "waitingReadFutures");
71
72 private static final IoFutureListener<CloseFuture> SCHEDULED_COUNTER_RESETTER =
73 new IoFutureListener<CloseFuture>() {
74 public void operationComplete(CloseFuture future) {
75 AbstractIoSession s = (AbstractIoSession) future.getSession();
76 s.scheduledWriteBytes.set(0);
77 s.scheduledWriteMessages.set(0);
78 s.readBytesThroughput = 0;
79 s.readMessagesThroughput = 0;
80 s.writtenBytesThroughput = 0;
81 s.writtenMessagesThroughput = 0;
82 }
83 };
84
85
86
87
88
89 private static final WriteRequest CLOSE_REQUEST =
90 new DefaultWriteRequest(new Object());
91
92 private final Object lock = new Object();
93
94 private IoSessionAttributeMap attributes;
95 private WriteRequestQueue writeRequestQueue;
96 private WriteRequest currentWriteRequest;
97
98
99 private final long creationTime;
100
101
102
103
104 private final CloseFuture closeFuture = new DefaultCloseFuture(this);
105
106 private volatile boolean closing;
107
108
109 private boolean readSuspended=false;
110 private boolean writeSuspended=false;
111
112
113 private final AtomicBoolean scheduledForFlush = new AtomicBoolean();
114 private final AtomicInteger scheduledWriteBytes = new AtomicInteger();
115 private final AtomicInteger scheduledWriteMessages = new AtomicInteger();
116
117 private long readBytes;
118 private long writtenBytes;
119 private long readMessages;
120 private long writtenMessages;
121 private long lastReadTime;
122 private long lastWriteTime;
123
124 private long lastThroughputCalculationTime;
125 private long lastReadBytes;
126 private long lastWrittenBytes;
127 private long lastReadMessages;
128 private long lastWrittenMessages;
129 private double readBytesThroughput;
130 private double writtenBytesThroughput;
131 private double readMessagesThroughput;
132 private double writtenMessagesThroughput;
133
134 private int idleCountForBoth;
135 private int idleCountForRead;
136 private int idleCountForWrite;
137
138 private long lastIdleTimeForBoth;
139 private long lastIdleTimeForRead;
140 private long lastIdleTimeForWrite;
141
142 private boolean deferDecreaseReadBuffer = true;
143
144
145
146
147 protected AbstractIoSession() {
148
149 long currentTime = System.currentTimeMillis();
150 creationTime = currentTime;
151 lastThroughputCalculationTime = currentTime;
152 lastReadTime = currentTime;
153 lastWriteTime = currentTime;
154 lastIdleTimeForBoth = currentTime;
155 lastIdleTimeForRead = currentTime;
156 lastIdleTimeForWrite = currentTime;
157
158
159 closeFuture.addListener(SCHEDULED_COUNTER_RESETTER);
160 }
161
162
163
164
165
166
167
168 public final long getId() {
169 return hashCode() & 0xFFFFFFFFL;
170 }
171
172
173
174
175 public abstract IoProcessor getProcessor();
176
177
178
179
180 public final boolean isConnected() {
181 return !closeFuture.isClosed();
182 }
183
184
185
186
187 public final boolean isClosing() {
188 return closing || closeFuture.isClosed();
189 }
190
191
192
193
194 public final CloseFuture getCloseFuture() {
195 return closeFuture;
196 }
197
198
199
200
201 public final boolean isScheduledForFlush() {
202 return scheduledForFlush.get();
203 }
204
205
206
207
208 public final boolean setScheduledForFlush(boolean flag) {
209 if (flag) {
210 return scheduledForFlush.compareAndSet(false, true);
211 } else {
212 scheduledForFlush.set(false);
213 return true;
214 }
215 }
216
217
218
219
220 public final CloseFuture close(boolean rightNow) {
221 if (rightNow) {
222 return close();
223 } else {
224 return closeOnFlush();
225 }
226 }
227
228
229
230
231 public final CloseFuture close() {
232 synchronized (lock) {
233 if (isClosing()) {
234 return closeFuture;
235 } else {
236 closing = true;
237 }
238 }
239
240 getFilterChain().fireFilterClose();
241 return closeFuture;
242 }
243
244 private final CloseFuture closeOnFlush() {
245 getWriteRequestQueue().offer(this, CLOSE_REQUEST);
246 getProcessor().flush(this);
247 return closeFuture;
248 }
249
250
251
252
253 public final ReadFuture read() {
254 if (!getConfig().isUseReadOperation()) {
255 throw new IllegalStateException("useReadOperation is not enabled.");
256 }
257
258 Queue<ReadFuture> readyReadFutures = getReadyReadFutures();
259 ReadFuture future;
260 synchronized (readyReadFutures) {
261 future = readyReadFutures.poll();
262 if (future != null) {
263 if (future.isClosed()) {
264
265 readyReadFutures.offer(future);
266 }
267 } else {
268 future = new DefaultReadFuture(this);
269 getWaitingReadFutures().offer(future);
270 }
271 }
272
273 return future;
274 }
275
276
277
278
279 public final void offerReadFuture(Object message) {
280 newReadFuture().setRead(message);
281 }
282
283
284
285
286 public final void offerFailedReadFuture(Throwable exception) {
287 newReadFuture().setException(exception);
288 }
289
290
291
292
293 public final void offerClosedReadFuture() {
294 Queue<ReadFuture> readyReadFutures = getReadyReadFutures();
295 synchronized (readyReadFutures) {
296 newReadFuture().setClosed();
297 }
298 }
299
300
301
302
303 private ReadFuture newReadFuture() {
304 Queue<ReadFuture> readyReadFutures = getReadyReadFutures();
305 Queue<ReadFuture> waitingReadFutures = getWaitingReadFutures();
306 ReadFuture future;
307 synchronized (readyReadFutures) {
308 future = waitingReadFutures.poll();
309 if (future == null) {
310 future = new DefaultReadFuture(this);
311 readyReadFutures.offer(future);
312 }
313 }
314 return future;
315 }
316
317
318
319
320 private Queue<ReadFuture> getReadyReadFutures() {
321 Queue<ReadFuture> readyReadFutures =
322 (Queue<ReadFuture>) getAttribute(READY_READ_FUTURES_KEY);
323 if (readyReadFutures == null) {
324 readyReadFutures = new CircularQueue<ReadFuture>();
325
326 Queue<ReadFuture> oldReadyReadFutures =
327 (Queue<ReadFuture>) setAttributeIfAbsent(
328 READY_READ_FUTURES_KEY, readyReadFutures);
329 if (oldReadyReadFutures != null) {
330 readyReadFutures = oldReadyReadFutures;
331 }
332 }
333 return readyReadFutures;
334 }
335
336
337
338
339 private Queue<ReadFuture> getWaitingReadFutures() {
340 Queue<ReadFuture> waitingReadyReadFutures =
341 (Queue<ReadFuture>) getAttribute(WAITING_READ_FUTURES_KEY);
342 if (waitingReadyReadFutures == null) {
343 waitingReadyReadFutures = new CircularQueue<ReadFuture>();
344
345 Queue<ReadFuture> oldWaitingReadyReadFutures =
346 (Queue<ReadFuture>) setAttributeIfAbsent(
347 WAITING_READ_FUTURES_KEY, waitingReadyReadFutures);
348 if (oldWaitingReadyReadFutures != null) {
349 waitingReadyReadFutures = oldWaitingReadyReadFutures;
350 }
351 }
352 return waitingReadyReadFutures;
353 }
354
355
356
357
358 public WriteFuture write(Object message) {
359 return write(message, null);
360 }
361
362
363
364
365 public WriteFuture write(Object message, SocketAddress remoteAddress) {
366 if (message == null) {
367 throw new NullPointerException("message");
368 }
369
370
371
372 if (!getTransportMetadata().isConnectionless() &&
373 remoteAddress != null) {
374 throw new UnsupportedOperationException();
375 }
376
377
378
379
380
381 if (isClosing() || !isConnected()) {
382 WriteFuture future = new DefaultWriteFuture(this);
383 WriteRequest request = new DefaultWriteRequest(message, future, remoteAddress);
384 WriteException writeException = new WriteToClosedSessionException(request);
385 future.setException(writeException);
386 return future;
387 }
388
389 FileChannel openedFileChannel = null;
390
391
392
393 try {
394 if (message instanceof IoBuffer
395 && !((IoBuffer) message).hasRemaining()) {
396
397 throw new IllegalArgumentException(
398 "message is empty. Forgot to call flip()?");
399 } else if (message instanceof FileChannel) {
400 FileChannel fileChannel = (FileChannel) message;
401 message = new DefaultFileRegion(fileChannel, 0, fileChannel.size());
402 } else if (message instanceof File) {
403 File file = (File) message;
404 openedFileChannel = new FileInputStream(file).getChannel();
405 message = new DefaultFileRegion(openedFileChannel, 0, openedFileChannel.size());
406 }
407 } catch (IOException e) {
408 ExceptionMonitor.getInstance().exceptionCaught(e);
409 return DefaultWriteFuture.newNotWrittenFuture(this, e);
410 }
411
412
413 WriteFuture writeFuture = new DefaultWriteFuture(this);
414 WriteRequest writeRequest = new DefaultWriteRequest(message, writeFuture, remoteAddress);
415
416
417 IoFilterChain filterChain = getFilterChain();
418 filterChain.fireFilterWrite(writeRequest);
419
420
421
422 if (openedFileChannel != null) {
423
424 final FileChannel finalChannel = openedFileChannel;
425 writeFuture.addListener(new IoFutureListener<WriteFuture>() {
426 public void operationComplete(WriteFuture future) {
427 try {
428 finalChannel.close();
429 } catch (IOException e) {
430 ExceptionMonitor.getInstance().exceptionCaught(e);
431 }
432 }
433 });
434 }
435
436
437 return writeFuture;
438 }
439
440
441
442
443 public final Object getAttachment() {
444 return getAttribute("");
445 }
446
447
448
449
450 public final Object setAttachment(Object attachment) {
451 return setAttribute("", attachment);
452 }
453
454
455
456
457 public final Object getAttribute(Object key) {
458 return getAttribute(key, null);
459 }
460
461
462
463
464 public final Object getAttribute(Object key, Object defaultValue) {
465 return attributes.getAttribute(this, key, defaultValue);
466 }
467
468
469
470
471 public final Object setAttribute(Object key, Object value) {
472 return attributes.setAttribute(this, key, value);
473 }
474
475
476
477
478 public final Object setAttribute(Object key) {
479 return setAttribute(key, Boolean.TRUE);
480 }
481
482
483
484
485 public final Object setAttributeIfAbsent(Object key, Object value) {
486 return attributes.setAttributeIfAbsent(this, key, value);
487 }
488
489
490
491
492 public final Object setAttributeIfAbsent(Object key) {
493 return setAttributeIfAbsent(key, Boolean.TRUE);
494 }
495
496
497
498
499 public final Object removeAttribute(Object key) {
500 return attributes.removeAttribute(this, key);
501 }
502
503
504
505
506 public final boolean removeAttribute(Object key, Object value) {
507 return attributes.removeAttribute(this, key, value);
508 }
509
510
511
512
513 public final boolean replaceAttribute(Object key, Object oldValue, Object newValue) {
514 return attributes.replaceAttribute(this, key, oldValue, newValue);
515 }
516
517
518
519
520 public final boolean containsAttribute(Object key) {
521 return attributes.containsAttribute(this, key);
522 }
523
524
525
526
527 public final Set<Object> getAttributeKeys() {
528 return attributes.getAttributeKeys(this);
529 }
530
531
532
533
534 public final IoSessionAttributeMap getAttributeMap() {
535 return attributes;
536 }
537
538
539
540
541 public final void setAttributeMap(IoSessionAttributeMap attributes) {
542 this.attributes = attributes;
543 }
544
545
546
547
548 public final void setWriteRequestQueue(WriteRequestQueue writeRequestQueue) {
549 this.writeRequestQueue =
550 new CloseRequestAwareWriteRequestQueue(writeRequestQueue);
551 }
552
553
554
555
556
557 public final void suspendRead() {
558 readSuspended = true;
559 if (isClosing() || !isConnected()) {
560 return;
561 }
562 getProcessor().updateTrafficControl(this);
563 }
564
565
566
567
568 public final void suspendWrite() {
569 writeSuspended = true;
570 if (isClosing() || !isConnected()) {
571 return;
572 }
573 getProcessor().updateTrafficControl(this);
574 }
575
576
577
578
579 @SuppressWarnings("unchecked")
580 public final void resumeRead() {
581 readSuspended = false;
582 if (isClosing() || !isConnected()) {
583 return;
584 }
585 getProcessor().updateTrafficControl(this);
586 }
587
588
589
590
591 @SuppressWarnings("unchecked")
592 public final void resumeWrite() {
593 writeSuspended = false;
594 if (isClosing() || !isConnected()) {
595 return;
596 }
597 getProcessor().updateTrafficControl(this);
598 }
599
600
601
602
603 public boolean isReadSuspended() {
604 return readSuspended;
605 }
606
607
608
609
610 public boolean isWriteSuspended() {
611 return writeSuspended;
612 }
613
614
615
616
617 public final long getReadBytes() {
618 return readBytes;
619 }
620
621
622
623
624 public final long getWrittenBytes() {
625 return writtenBytes;
626 }
627
628
629
630
631 public final long getReadMessages() {
632 return readMessages;
633 }
634
635
636
637
638 public final long getWrittenMessages() {
639 return writtenMessages;
640 }
641
642
643
644
645 public final double getReadBytesThroughput() {
646 return readBytesThroughput;
647 }
648
649
650
651
652 public final double getWrittenBytesThroughput() {
653 return writtenBytesThroughput;
654 }
655
656
657
658
659 public final double getReadMessagesThroughput() {
660 return readMessagesThroughput;
661 }
662
663
664
665
666 public final double getWrittenMessagesThroughput() {
667 return writtenMessagesThroughput;
668 }
669
670
671
672
673 public final void updateThroughput(long currentTime, boolean force) {
674 int interval = (int) (currentTime - lastThroughputCalculationTime);
675
676 long minInterval = getConfig().getThroughputCalculationIntervalInMillis();
677 if (minInterval == 0 || interval < minInterval) {
678 if (!force) {
679 return;
680 }
681 }
682
683 readBytesThroughput = (readBytes - lastReadBytes) * 1000.0 / interval;
684 writtenBytesThroughput = (writtenBytes - lastWrittenBytes) * 1000.0 / interval;
685 readMessagesThroughput = (readMessages - lastReadMessages) * 1000.0 / interval;
686 writtenMessagesThroughput = (writtenMessages - lastWrittenMessages) * 1000.0 / interval;
687
688 lastReadBytes = readBytes;
689 lastWrittenBytes = writtenBytes;
690 lastReadMessages = readMessages;
691 lastWrittenMessages = writtenMessages;
692
693 lastThroughputCalculationTime = currentTime;
694 }
695
696
697
698
699 public final long getScheduledWriteBytes() {
700 return scheduledWriteBytes.get();
701 }
702
703
704
705
706 public final int getScheduledWriteMessages() {
707 return scheduledWriteMessages.get();
708 }
709
710
711
712
713 protected void setScheduledWriteBytes(int byteCount){
714 scheduledWriteBytes.set(byteCount);
715 }
716
717
718
719
720 protected void setScheduledWriteMessages(int messages) {
721 scheduledWriteMessages.set(messages);
722 }
723
724
725
726
727 public final void increaseReadBytes(long increment, long currentTime) {
728 if (increment <= 0) {
729 return;
730 }
731
732 readBytes += increment;
733 lastReadTime = currentTime;
734 idleCountForBoth = 0;
735 idleCountForRead = 0;
736
737 if (getService() instanceof AbstractIoService) {
738 ((AbstractIoService) getService()).getStatistics().increaseReadBytes(increment, currentTime);
739 }
740 }
741
742
743
744
745 public final void increaseReadMessages(long currentTime) {
746 readMessages++;
747 lastReadTime = currentTime;
748 idleCountForBoth = 0;
749 idleCountForRead = 0;
750
751 if (getService() instanceof AbstractIoService) {
752 ((AbstractIoService) getService()).getStatistics().increaseReadMessages(currentTime);
753 }
754 }
755
756
757
758
759 public final void increaseWrittenBytes(int increment, long currentTime) {
760 if (increment <= 0) {
761 return;
762 }
763
764 writtenBytes += increment;
765 lastWriteTime = currentTime;
766 idleCountForBoth = 0;
767 idleCountForWrite = 0;
768
769 if (getService() instanceof AbstractIoService) {
770 ((AbstractIoService) getService()).getStatistics().increaseWrittenBytes(increment, currentTime);
771 }
772
773 increaseScheduledWriteBytes(-increment);
774 }
775
776
777
778
779 public final void increaseWrittenMessages(
780 WriteRequest request, long currentTime) {
781 Object message = request.getMessage();
782 if (message instanceof IoBuffer) {
783 IoBuffer b = (IoBuffer) message;
784 if (b.hasRemaining()) {
785 return;
786 }
787 }
788
789 writtenMessages++;
790 lastWriteTime = currentTime;
791 if (getService() instanceof AbstractIoService) {
792 ((AbstractIoService) getService()).getStatistics().increaseWrittenMessages(currentTime);
793 }
794
795 decreaseScheduledWriteMessages();
796 }
797
798
799
800
801 public final void increaseScheduledWriteBytes(int increment) {
802 scheduledWriteBytes.addAndGet(increment);
803 if (getService() instanceof AbstractIoService) {
804 ((AbstractIoService) getService()).getStatistics().increaseScheduledWriteBytes(increment);
805 }
806 }
807
808
809
810
811 public final void increaseScheduledWriteMessages() {
812 scheduledWriteMessages.incrementAndGet();
813 if (getService() instanceof AbstractIoService) {
814 ((AbstractIoService) getService()).getStatistics().increaseScheduledWriteMessages();
815 }
816 }
817
818
819
820
821 private void decreaseScheduledWriteMessages() {
822 scheduledWriteMessages.decrementAndGet();
823 if (getService() instanceof AbstractIoService) {
824 ((AbstractIoService) getService()).getStatistics().decreaseScheduledWriteMessages();
825 }
826 }
827
828
829
830
831 public final void decreaseScheduledBytesAndMessages(WriteRequest request) {
832 Object message = request.getMessage();
833 if (message instanceof IoBuffer) {
834 IoBuffer b = (IoBuffer) message;
835 if (b.hasRemaining()) {
836 increaseScheduledWriteBytes(-((IoBuffer) message).remaining());
837 } else {
838 decreaseScheduledWriteMessages();
839 }
840 } else {
841 decreaseScheduledWriteMessages();
842 }
843 }
844
845
846
847
848 public final WriteRequestQueue getWriteRequestQueue() {
849 if (writeRequestQueue == null) {
850 throw new IllegalStateException();
851 }
852 return writeRequestQueue;
853 }
854
855
856
857
858 public final WriteRequest getCurrentWriteRequest() {
859 return currentWriteRequest;
860 }
861
862
863
864
865 public final Object getCurrentWriteMessage() {
866 WriteRequest req = getCurrentWriteRequest();
867 if (req == null) {
868 return null;
869 }
870 return req.getMessage();
871 }
872
873
874
875
876 public final void setCurrentWriteRequest(WriteRequest currentWriteRequest) {
877 this.currentWriteRequest = currentWriteRequest;
878 }
879
880
881
882
883 public final void increaseReadBufferSize() {
884 int newReadBufferSize = getConfig().getReadBufferSize() << 1;
885 if (newReadBufferSize <= getConfig().getMaxReadBufferSize()) {
886 getConfig().setReadBufferSize(newReadBufferSize);
887 } else {
888 getConfig().setReadBufferSize(getConfig().getMaxReadBufferSize());
889 }
890
891 deferDecreaseReadBuffer = true;
892 }
893
894
895
896
897 public final void decreaseReadBufferSize() {
898 if (deferDecreaseReadBuffer) {
899 deferDecreaseReadBuffer = false;
900 return;
901 }
902
903 if (getConfig().getReadBufferSize() > getConfig().getMinReadBufferSize()) {
904 getConfig().setReadBufferSize(getConfig().getReadBufferSize() >>> 1);
905 }
906
907 deferDecreaseReadBuffer = true;
908 }
909
910
911
912
913 public final long getCreationTime() {
914 return creationTime;
915 }
916
917
918
919
920 public final long getLastIoTime() {
921 return Math.max(lastReadTime, lastWriteTime);
922 }
923
924
925
926
927 public final long getLastReadTime() {
928 return lastReadTime;
929 }
930
931
932
933
934 public final long getLastWriteTime() {
935 return lastWriteTime;
936 }
937
938
939
940
941 public final boolean isIdle(IdleStatus status) {
942 if (status == IdleStatus.BOTH_IDLE) {
943 return idleCountForBoth > 0;
944 }
945
946 if (status == IdleStatus.READER_IDLE) {
947 return idleCountForRead > 0;
948 }
949
950 if (status == IdleStatus.WRITER_IDLE) {
951 return idleCountForWrite > 0;
952 }
953
954 throw new IllegalArgumentException("Unknown idle status: " + status);
955 }
956
957
958
959
960 public final boolean isBothIdle() {
961 return isIdle(IdleStatus.BOTH_IDLE);
962 }
963
964
965
966
967 public final boolean isReaderIdle() {
968 return isIdle(IdleStatus.READER_IDLE);
969 }
970
971
972
973
974 public final boolean isWriterIdle() {
975 return isIdle(IdleStatus.WRITER_IDLE);
976 }
977
978
979
980
981 public final int getIdleCount(IdleStatus status) {
982 if (getConfig().getIdleTime(status) == 0) {
983 if (status == IdleStatus.BOTH_IDLE) {
984 idleCountForBoth = 0;
985 }
986
987 if (status == IdleStatus.READER_IDLE) {
988 idleCountForRead = 0;
989 }
990
991 if (status == IdleStatus.WRITER_IDLE) {
992 idleCountForWrite = 0;
993 }
994 }
995
996 if (status == IdleStatus.BOTH_IDLE) {
997 return idleCountForBoth;
998 }
999
1000 if (status == IdleStatus.READER_IDLE) {
1001 return idleCountForRead;
1002 }
1003
1004 if (status == IdleStatus.WRITER_IDLE) {
1005 return idleCountForWrite;
1006 }
1007
1008 throw new IllegalArgumentException("Unknown idle status: " + status);
1009 }
1010
1011
1012
1013
1014 public final long getLastIdleTime(IdleStatus status) {
1015 if (status == IdleStatus.BOTH_IDLE) {
1016 return lastIdleTimeForBoth;
1017 }
1018
1019 if (status == IdleStatus.READER_IDLE) {
1020 return lastIdleTimeForRead;
1021 }
1022
1023 if (status == IdleStatus.WRITER_IDLE) {
1024 return lastIdleTimeForWrite;
1025 }
1026
1027 throw new IllegalArgumentException("Unknown idle status: " + status);
1028 }
1029
1030
1031
1032
1033 public final void increaseIdleCount(IdleStatus status, long currentTime) {
1034 if (status == IdleStatus.BOTH_IDLE) {
1035 idleCountForBoth++;
1036 lastIdleTimeForBoth = currentTime;
1037 } else if (status == IdleStatus.READER_IDLE) {
1038 idleCountForRead++;
1039 lastIdleTimeForRead = currentTime;
1040 } else if (status == IdleStatus.WRITER_IDLE) {
1041 idleCountForWrite++;
1042 lastIdleTimeForWrite = currentTime;
1043 } else {
1044 throw new IllegalArgumentException("Unknown idle status: " + status);
1045 }
1046 }
1047
1048
1049
1050
1051 public final int getBothIdleCount() {
1052 return getIdleCount(IdleStatus.BOTH_IDLE);
1053 }
1054
1055
1056
1057
1058 public final long getLastBothIdleTime() {
1059 return getLastIdleTime(IdleStatus.BOTH_IDLE);
1060 }
1061
1062
1063
1064
1065 public final long getLastReaderIdleTime() {
1066 return getLastIdleTime(IdleStatus.READER_IDLE);
1067 }
1068
1069
1070
1071
1072 public final long getLastWriterIdleTime() {
1073 return getLastIdleTime(IdleStatus.WRITER_IDLE);
1074 }
1075
1076
1077
1078
1079 public final int getReaderIdleCount() {
1080 return getIdleCount(IdleStatus.READER_IDLE);
1081 }
1082
1083
1084
1085
1086 public final int getWriterIdleCount() {
1087 return getIdleCount(IdleStatus.WRITER_IDLE);
1088 }
1089
1090
1091
1092
1093 public SocketAddress getServiceAddress() {
1094 IoService service = getService();
1095 if (service instanceof IoAcceptor) {
1096 return ((IoAcceptor) service).getLocalAddress();
1097 } else {
1098 return getRemoteAddress();
1099 }
1100 }
1101
1102
1103
1104
1105 @Override
1106 public final int hashCode() {
1107 return super.hashCode();
1108 }
1109
1110
1111
1112
1113
1114 @Override
1115 public final boolean equals(Object o) {
1116 return super.equals(o);
1117 }
1118
1119
1120
1121
1122 @Override
1123 public String toString() {
1124 if (getService() instanceof IoAcceptor) {
1125 return "(" + getIdAsString() + ": " + getServiceName() + ", server, " +
1126 getRemoteAddress() + " => " + getLocalAddress() + ')';
1127 } else {
1128 return "(" + getIdAsString() + ": " + getServiceName() + ", client, " +
1129 getLocalAddress() + " => " + getRemoteAddress() + ')';
1130 }
1131 }
1132
1133
1134
1135
1136 private String getIdAsString() {
1137 String id = Long.toHexString(getId()).toUpperCase();
1138
1139
1140
1141 while (id.length() < 8) {
1142 id = '0' + id;
1143 }
1144 id = "0x" + id;
1145
1146 return id;
1147 }
1148
1149
1150
1151
1152 private String getServiceName() {
1153 TransportMetadata tm = getTransportMetadata();
1154 if (tm == null) {
1155 return "null";
1156 } else {
1157 return tm.getProviderName() + ' ' + tm.getName();
1158 }
1159 }
1160
1161
1162
1163
1164
1165
1166
1167 public static void notifyIdleness(Iterator<? extends IoSession> sessions, long currentTime) {
1168 IoSession s = null;
1169 while (sessions.hasNext()) {
1170 s = sessions.next();
1171 notifyIdleSession(s, currentTime);
1172 }
1173 }
1174
1175
1176
1177
1178
1179
1180
1181 public static void notifyIdleSession(IoSession session, long currentTime) {
1182 notifyIdleSession0(
1183 session, currentTime,
1184 session.getConfig().getIdleTimeInMillis(IdleStatus.BOTH_IDLE),
1185 IdleStatus.BOTH_IDLE, Math.max(
1186 session.getLastIoTime(),
1187 session.getLastIdleTime(IdleStatus.BOTH_IDLE)));
1188
1189 notifyIdleSession0(
1190 session, currentTime,
1191 session.getConfig().getIdleTimeInMillis(IdleStatus.READER_IDLE),
1192 IdleStatus.READER_IDLE, Math.max(
1193 session.getLastReadTime(),
1194 session.getLastIdleTime(IdleStatus.READER_IDLE)));
1195
1196 notifyIdleSession0(
1197 session, currentTime,
1198 session.getConfig().getIdleTimeInMillis(IdleStatus.WRITER_IDLE),
1199 IdleStatus.WRITER_IDLE, Math.max(
1200 session.getLastWriteTime(),
1201 session.getLastIdleTime(IdleStatus.WRITER_IDLE)));
1202
1203 notifyWriteTimeout(session, currentTime);
1204 }
1205
1206 private static void notifyIdleSession0(
1207 IoSession session, long currentTime,
1208 long idleTime, IdleStatus status, long lastIoTime) {
1209 if (idleTime > 0 && lastIoTime != 0
1210 && currentTime - lastIoTime >= idleTime) {
1211 session.getFilterChain().fireSessionIdle(status);
1212 }
1213 }
1214
1215 private static void notifyWriteTimeout(
1216 IoSession session, long currentTime) {
1217
1218 long writeTimeout = session.getConfig().getWriteTimeoutInMillis();
1219 if (writeTimeout > 0 &&
1220 currentTime - session.getLastWriteTime() >= writeTimeout &&
1221 !session.getWriteRequestQueue().isEmpty(session)) {
1222 WriteRequest request = session.getCurrentWriteRequest();
1223 if (request != null) {
1224 session.setCurrentWriteRequest(null);
1225 WriteTimeoutException cause = new WriteTimeoutException(request);
1226 request.getFuture().setException(cause);
1227 session.getFilterChain().fireExceptionCaught(cause);
1228
1229 session.close(true);
1230 }
1231 }
1232 }
1233
1234
1235
1236
1237
1238
1239 private class CloseRequestAwareWriteRequestQueue implements WriteRequestQueue {
1240
1241 private final WriteRequestQueue q;
1242
1243 public CloseRequestAwareWriteRequestQueue(WriteRequestQueue q) {
1244 this.q = q;
1245 }
1246
1247 public synchronized WriteRequest poll(IoSession session) {
1248 WriteRequest answer = q.poll(session);
1249 if (answer == CLOSE_REQUEST) {
1250 AbstractIoSession.this.close();
1251 dispose(session);
1252 answer = null;
1253 }
1254 return answer;
1255 }
1256
1257 public void offer(IoSession session, WriteRequest e) {
1258 q.offer(session, e);
1259 }
1260
1261 public boolean isEmpty(IoSession session) {
1262 return q.isEmpty(session);
1263 }
1264
1265 public void clear(IoSession session) {
1266 q.clear(session);
1267 }
1268
1269 public void dispose(IoSession session) {
1270 q.dispose(session);
1271 }
1272 }
1273 }