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