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