1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.core.polling;
21
22 import java.io.IOException;
23 import java.net.PortUnreachableException;
24 import java.nio.channels.ClosedSelectorException;
25 import java.util.ArrayList;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Queue;
30 import java.util.concurrent.ConcurrentHashMap;
31 import java.util.concurrent.ConcurrentLinkedQueue;
32 import java.util.concurrent.Executor;
33 import java.util.concurrent.atomic.AtomicBoolean;
34 import java.util.concurrent.atomic.AtomicInteger;
35 import java.util.concurrent.atomic.AtomicReference;
36
37 import org.apache.mina.core.buffer.IoBuffer;
38 import org.apache.mina.core.file.FileRegion;
39 import org.apache.mina.core.filterchain.IoFilterChain;
40 import org.apache.mina.core.filterchain.IoFilterChainBuilder;
41 import org.apache.mina.core.future.DefaultIoFuture;
42 import org.apache.mina.core.service.AbstractIoService;
43 import org.apache.mina.core.service.IoProcessor;
44 import org.apache.mina.core.service.IoServiceListenerSupport;
45 import org.apache.mina.core.session.AbstractIoSession;
46 import org.apache.mina.core.session.IoSession;
47 import org.apache.mina.core.session.IoSessionConfig;
48 import org.apache.mina.core.session.SessionState;
49 import org.apache.mina.core.write.WriteRequest;
50 import org.apache.mina.core.write.WriteRequestQueue;
51 import org.apache.mina.core.write.WriteToClosedSessionException;
52 import org.apache.mina.transport.socket.AbstractDatagramSessionConfig;
53 import org.apache.mina.util.ExceptionMonitor;
54 import org.apache.mina.util.NamePreservingRunnable;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57
58
59
60
61
62
63
64
65
66
67
68 public abstract class AbstractPollingIoProcessor<S extends AbstractIoSession> implements IoProcessor<S> {
69
70 private final static Logger LOG = LoggerFactory.getLogger(IoProcessor.class);
71
72
73
74
75
76
77
78 private static final int WRITE_SPIN_COUNT = 256;
79
80
81
82
83
84 private static final long SELECT_TIMEOUT = 1000L;
85
86
87 private static final Map<Class<?>, AtomicInteger> threadIds = new ConcurrentHashMap<Class<?>, AtomicInteger>();
88
89
90 private final String threadName;
91
92
93 private final Executor executor;
94
95
96 private final Queue<S> newSessions = new ConcurrentLinkedQueue<S>();
97
98
99 private final Queue<S> removingSessions = new ConcurrentLinkedQueue<S>();
100
101
102 private final Queue<S> flushingSessions = new ConcurrentLinkedQueue<S>();
103
104
105
106
107
108 private final Queue<S> trafficControllingSessions = new ConcurrentLinkedQueue<S>();
109
110
111 private final AtomicReference<Processor> processorRef = new AtomicReference<Processor>();
112
113 private long lastIdleCheckTime;
114
115 private final Object disposalLock = new Object();
116
117 private volatile boolean disposing;
118
119 private volatile boolean disposed;
120
121 private final DefaultIoFuture disposalFuture = new DefaultIoFuture(null);
122
123 protected AtomicBoolean wakeupCalled = new AtomicBoolean(false);
124
125
126
127
128
129
130
131
132 protected AbstractPollingIoProcessor(Executor executor) {
133 if (executor == null) {
134 throw new IllegalArgumentException("executor");
135 }
136
137 this.threadName = nextThreadName();
138 this.executor = executor;
139 }
140
141
142
143
144
145
146
147
148
149 private String nextThreadName() {
150 Class<?> cls = getClass();
151 int newThreadId;
152
153
154
155
156 synchronized (threadIds) {
157
158 AtomicInteger threadId = threadIds.get(cls);
159
160 if (threadId == null) {
161
162
163
164 newThreadId = 1;
165 threadIds.put(cls, new AtomicInteger(newThreadId));
166 } else {
167
168 newThreadId = threadId.incrementAndGet();
169 }
170 }
171
172
173 return cls.getSimpleName() + '-' + newThreadId;
174 }
175
176
177
178
179 public final boolean isDisposing() {
180 return disposing;
181 }
182
183
184
185
186 public final boolean isDisposed() {
187 return disposed;
188 }
189
190
191
192
193 public final void dispose() {
194 if (disposed || disposing) {
195 return;
196 }
197
198 synchronized (disposalLock) {
199 disposing = true;
200 startupProcessor();
201 }
202
203 disposalFuture.awaitUninterruptibly();
204 disposed = true;
205 }
206
207
208
209
210
211
212
213 protected abstract void doDispose() throws Exception;
214
215
216
217
218
219
220
221
222
223
224 protected abstract int select(long timeout) throws Exception;
225
226
227
228
229
230
231
232
233 protected abstract int select() throws Exception;
234
235
236
237
238
239
240
241 protected abstract boolean isSelectorEmpty();
242
243
244
245
246 protected abstract void wakeup();
247
248
249
250
251
252
253
254 protected abstract Iterator<S> allSessions();
255
256
257
258
259
260
261 protected abstract Iterator<S> selectedSessions();
262
263
264
265
266
267
268
269
270 protected abstract SessionState getState(S session);
271
272
273
274
275
276
277
278
279 protected abstract boolean isWritable(S session);
280
281
282
283
284
285
286
287
288 protected abstract boolean isReadable(S session);
289
290
291
292
293
294
295
296
297
298 protected abstract void setInterestedInWrite(S session, boolean isInterested)
299 throws Exception;
300
301
302
303
304
305
306
307
308
309 protected abstract void setInterestedInRead(S session, boolean isInterested)
310 throws Exception;
311
312
313
314
315
316
317
318
319 protected abstract boolean isInterestedInRead(S session);
320
321
322
323
324
325
326
327
328 protected abstract boolean isInterestedInWrite(S session);
329
330
331
332
333
334
335
336 protected abstract void init(S session) throws Exception;
337
338
339
340
341
342
343
344
345
346 protected abstract void destroy(S session) throws Exception;
347
348
349
350
351
352
353
354
355
356
357
358
359
360 protected abstract int read(S session, IoBuffer buf) throws Exception;
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377 protected abstract int write(S session, IoBuffer buf, int length)
378 throws Exception;
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396 protected abstract int transferFile(S session, FileRegion region, int length)
397 throws Exception;
398
399
400
401
402 public final void add(S session) {
403 if (disposed || disposing) {
404 throw new IllegalStateException("Already disposed.");
405 }
406
407
408 newSessions.add(session);
409 startupProcessor();
410 }
411
412
413
414
415 public final void remove(S session) {
416 scheduleRemove(session);
417 startupProcessor();
418 }
419
420 private void scheduleRemove(S session) {
421 removingSessions.add(session);
422 }
423
424
425
426
427 public final void flush(S session) {
428
429
430 if (session.setScheduledForFlush( true )) {
431 flushingSessions.add(session);
432 wakeup();
433 }
434 }
435
436 private void scheduleFlush(S session) {
437
438
439 if (session.setScheduledForFlush(true)) {
440 flushingSessions.add(session);
441 }
442 }
443
444
445
446
447 public final void updateTrafficMask(S session) {
448 trafficControllingSessions.add(session);
449 wakeup();
450 }
451
452
453
454
455
456 private void startupProcessor() {
457 Processor processor = processorRef.get();
458
459 if (processor == null) {
460 processor = new Processor();
461
462 if (processorRef.compareAndSet(null, processor)) {
463 executor.execute(new NamePreservingRunnable(processor, threadName));
464 }
465 }
466
467
468
469 wakeup();
470 }
471
472
473
474
475
476
477
478
479
480 abstract protected void registerNewSelector() throws IOException;
481
482
483
484
485
486
487
488
489
490
491 abstract protected boolean isBrokenConnection() throws IOException;
492
493
494
495
496
497
498
499 private int handleNewSessions() {
500 int addedSessions = 0;
501
502 for (S session = newSessions.poll(); session != null; session = newSessions.poll()) {
503 if (addNow(session)) {
504
505 addedSessions++;
506 }
507 }
508
509 return addedSessions;
510 }
511
512
513
514
515
516
517
518
519
520
521 private boolean addNow(S session) {
522 boolean registered = false;
523
524 try {
525 init(session);
526 registered = true;
527
528
529 IoFilterChainBuilder chainBuilder = session.getService().getFilterChainBuilder();
530 chainBuilder.buildFilterChain(session.getFilterChain());
531
532
533
534
535 IoServiceListenerSupport listeners = ((AbstractIoService) session.getService()).getListeners();
536 listeners.fireSessionCreated(session);
537 } catch (Throwable e) {
538 ExceptionMonitor.getInstance().exceptionCaught(e);
539
540 try {
541 destroy(session);
542 } catch (Exception e1) {
543 ExceptionMonitor.getInstance().exceptionCaught(e1);
544 } finally {
545 registered = false;
546 }
547 }
548
549 return registered;
550 }
551
552 private int removeSessions() {
553 int removedSessions = 0;
554
555 for (S session = removingSessions.poll(); session != null; session = removingSessions.poll()) {
556 SessionState state = getState(session);
557
558
559 switch (state) {
560 case OPENED:
561
562 if (removeNow(session)) {
563 removedSessions++;
564 }
565
566 break;
567
568 case CLOSING:
569
570 break;
571
572 case OPENING:
573
574
575 newSessions.remove(session);
576
577 if (removeNow(session)) {
578 removedSessions++;
579 }
580
581 break;
582
583 default:
584 throw new IllegalStateException(String.valueOf(state));
585 }
586 }
587
588 return removedSessions;
589 }
590
591 private boolean removeNow(S session) {
592 clearWriteRequestQueue(session);
593
594 try {
595 destroy(session);
596 return true;
597 } catch (Exception e) {
598 IoFilterChain filterChain = session.getFilterChain();
599 filterChain.fireExceptionCaught(e);
600 } finally {
601 clearWriteRequestQueue(session);
602 ((AbstractIoService) session.getService()).getListeners()
603 .fireSessionDestroyed(session);
604 }
605 return false;
606 }
607
608 private void clearWriteRequestQueue(S session) {
609 WriteRequestQueue writeRequestQueue = session.getWriteRequestQueue();
610 WriteRequest req;
611
612 List<WriteRequest> failedRequests = new ArrayList<WriteRequest>();
613
614 if ((req = writeRequestQueue.poll(session)) != null) {
615 Object message = req.getMessage();
616
617 if (message instanceof IoBuffer) {
618 IoBuffer buf = (IoBuffer)message;
619
620
621
622 if (buf.hasRemaining()) {
623 buf.reset();
624 failedRequests.add(req);
625 } else {
626 IoFilterChain filterChain = session.getFilterChain();
627 filterChain.fireMessageSent(req);
628 }
629 } else {
630 failedRequests.add(req);
631 }
632
633
634 while ((req = writeRequestQueue.poll(session)) != null) {
635 failedRequests.add(req);
636 }
637 }
638
639
640 if (!failedRequests.isEmpty()) {
641 WriteToClosedSessionException cause = new WriteToClosedSessionException(
642 failedRequests);
643
644 for (WriteRequest r : failedRequests) {
645 session.decreaseScheduledBytesAndMessages(r);
646 r.getFuture().setException(cause);
647 }
648
649 IoFilterChain filterChain = session.getFilterChain();
650 filterChain.fireExceptionCaught(cause);
651 }
652 }
653
654 private void process() throws Exception {
655 for (Iterator<S> i = selectedSessions(); i.hasNext();) {
656 S session = i.next();
657 process(session);
658 i.remove();
659 }
660 }
661
662
663
664
665 private void process(S session) {
666
667 if (isReadable(session) && !session.isReadSuspended()) {
668 read(session);
669 }
670
671
672 if (isWritable(session) && !session.isWriteSuspended()) {
673
674 if (session.setScheduledForFlush(true)) {
675 flushingSessions.add(session);
676 }
677 }
678 }
679
680 private void read(S session) {
681 IoSessionConfig config = session.getConfig();
682 int bufferSize = config.getReadBufferSize();
683 IoBuffer buf = IoBuffer.allocate(bufferSize);
684
685 final boolean hasFragmentation = session.getTransportMetadata()
686 .hasFragmentation();
687
688 try {
689 int readBytes = 0;
690 int ret;
691
692 try {
693 if (hasFragmentation) {
694
695 while ((ret = read(session, buf)) > 0) {
696 readBytes += ret;
697
698 if (!buf.hasRemaining()) {
699 break;
700 }
701 }
702 } else {
703 ret = read(session, buf);
704
705 if (ret > 0) {
706 readBytes = ret;
707 }
708 }
709 } finally {
710 buf.flip();
711 }
712
713 if (readBytes > 0) {
714 IoFilterChain filterChain = session.getFilterChain();
715 filterChain.fireMessageReceived(buf);
716 buf = null;
717
718 if (hasFragmentation) {
719 if (readBytes << 1 < config.getReadBufferSize()) {
720 session.decreaseReadBufferSize();
721 } else if (readBytes == config.getReadBufferSize()) {
722 session.increaseReadBufferSize();
723 }
724 }
725 }
726
727 if (ret < 0) {
728 scheduleRemove(session);
729 }
730 } catch (Throwable e) {
731 if (e instanceof IOException) {
732 if (!(e instanceof PortUnreachableException)
733 || !AbstractDatagramSessionConfig.class.isAssignableFrom(config.getClass())
734 || ((AbstractDatagramSessionConfig) config).isCloseOnPortUnreachable()) {
735 scheduleRemove(session);
736 }
737 }
738
739 IoFilterChain filterChain = session.getFilterChain();
740 filterChain.fireExceptionCaught(e);
741 }
742 }
743
744
745 private static String byteArrayToHex( byte[] barray )
746 {
747 char[] c = new char[barray.length * 2];
748 int pos = 0;
749
750 for ( byte b : barray )
751 {
752 int bb = ( b & 0x00FF ) >> 4;
753 c[pos++] = ( char ) ( bb > 9 ? bb + 0x37 : bb + 0x30 );
754 bb = b & 0x0F;
755 c[pos++] = ( char ) ( bb > 9 ? bb + 0x37 : bb + 0x30 );
756 if ( pos > 60 )
757 {
758 break;
759 }
760 }
761
762 return new String( c );
763 }
764
765
766 private void notifyIdleSessions(long currentTime) throws Exception {
767
768 if (currentTime - lastIdleCheckTime >= SELECT_TIMEOUT) {
769 lastIdleCheckTime = currentTime;
770 AbstractIoSession.notifyIdleness(allSessions(), currentTime);
771 }
772 }
773
774
775
776
777 private void flush(long currentTime) {
778 if (flushingSessions.isEmpty()) {
779 return;
780 }
781
782 do {
783 S session = flushingSessions.poll();
784
785 if (session == null) {
786
787 break;
788 }
789
790
791
792 session.unscheduledForFlush();
793
794 SessionState state = getState(session);
795
796 switch (state) {
797 case OPENED:
798 try {
799 boolean flushedAll = flushNow(session, currentTime);
800
801 if (flushedAll
802 && !session.getWriteRequestQueue().isEmpty(session)
803 && !session.isScheduledForFlush()) {
804 scheduleFlush(session);
805 }
806 } catch (Exception e) {
807 scheduleRemove(session);
808 IoFilterChain filterChain = session.getFilterChain();
809 filterChain.fireExceptionCaught(e);
810 }
811
812 break;
813
814 case CLOSING:
815
816 break;
817
818 case OPENING:
819
820
821
822 scheduleFlush(session);
823 return;
824
825 default:
826 throw new IllegalStateException(String.valueOf(state));
827 }
828
829 } while (!flushingSessions.isEmpty());
830 }
831
832 private boolean flushNow(S session, long currentTime) {
833 if (!session.isConnected()) {
834 scheduleRemove(session);
835 return false;
836 }
837
838 final boolean hasFragmentation = session.getTransportMetadata()
839 .hasFragmentation();
840
841 final WriteRequestQueue writeRequestQueue = session
842 .getWriteRequestQueue();
843
844
845
846
847 final int maxWrittenBytes = session.getConfig().getMaxReadBufferSize()
848 + (session.getConfig().getMaxReadBufferSize() >>> 1);
849 int writtenBytes = 0;
850 WriteRequest req = null;
851
852 try {
853
854 setInterestedInWrite(session, false);
855
856 do {
857
858 req = session.getCurrentWriteRequest();
859
860 if (req == null) {
861 req = writeRequestQueue.poll(session);
862
863 if (req == null) {
864 break;
865 }
866
867 session.setCurrentWriteRequest(req);
868 }
869
870 int localWrittenBytes = 0;
871 Object message = req.getMessage();
872
873 if (message instanceof IoBuffer) {
874 localWrittenBytes = writeBuffer(session, req,
875 hasFragmentation, maxWrittenBytes - writtenBytes,
876 currentTime);
877
878 if (( localWrittenBytes > 0 )
879 && ((IoBuffer) message).hasRemaining()) {
880
881 writtenBytes += localWrittenBytes;
882 setInterestedInWrite(session, true);
883 return false;
884 }
885 } else if (message instanceof FileRegion) {
886 localWrittenBytes = writeFile(session, req,
887 hasFragmentation, maxWrittenBytes - writtenBytes,
888 currentTime);
889
890
891
892
893
894
895 if (( localWrittenBytes > 0 )
896 && ( ((FileRegion) message).getRemainingBytes() > 0 )) {
897 writtenBytes += localWrittenBytes;
898 setInterestedInWrite(session, true);
899 return false;
900 }
901 } else {
902 throw new IllegalStateException(
903 "Don't know how to handle message of type '"
904 + message.getClass().getName()
905 + "'. Are you missing a protocol encoder?");
906 }
907
908 if (localWrittenBytes == 0) {
909
910 setInterestedInWrite(session, true);
911 return false;
912 }
913
914 writtenBytes += localWrittenBytes;
915
916 if (writtenBytes >= maxWrittenBytes) {
917
918 scheduleFlush(session);
919 return false;
920 }
921 } while (writtenBytes < maxWrittenBytes);
922 } catch (Exception e) {
923 if (req != null) {
924 req.getFuture().setException(e);
925 }
926
927 IoFilterChain filterChain = session.getFilterChain();
928 filterChain.fireExceptionCaught(e);
929 return false;
930 }
931
932 return true;
933 }
934
935 private int writeBuffer(S session, WriteRequest req,
936 boolean hasFragmentation, int maxLength, long currentTime)
937 throws Exception {
938 IoBuffer buf = (IoBuffer) req.getMessage();
939 int localWrittenBytes = 0;
940
941 if (buf.hasRemaining()) {
942 int length;
943
944 if (hasFragmentation) {
945 length = Math.min(buf.remaining(), maxLength);
946 } else {
947 length = buf.remaining();
948 }
949
950 localWrittenBytes = write(session, buf, length);
951 }
952
953 session.increaseWrittenBytes(localWrittenBytes, currentTime);
954
955 if (!buf.hasRemaining() || ( !hasFragmentation && ( localWrittenBytes != 0 ) )) {
956
957 int pos = buf.position();
958 buf.reset();
959
960 fireMessageSent(session, req);
961
962
963 buf.position(pos);
964 }
965 return localWrittenBytes;
966 }
967
968 private int writeFile(S session, WriteRequest req,
969 boolean hasFragmentation, int maxLength, long currentTime)
970 throws Exception {
971 int localWrittenBytes;
972 FileRegion region = (FileRegion) req.getMessage();
973
974 if (region.getRemainingBytes() > 0) {
975 int length;
976
977 if (hasFragmentation) {
978 length = (int) Math.min(region.getRemainingBytes(), maxLength);
979 } else {
980 length = (int) Math.min(Integer.MAX_VALUE, region
981 .getRemainingBytes());
982 }
983
984 localWrittenBytes = transferFile(session, region, length);
985 region.update(localWrittenBytes);
986 } else {
987 localWrittenBytes = 0;
988 }
989
990 session.increaseWrittenBytes(localWrittenBytes, currentTime);
991
992 if (( region.getRemainingBytes() <= 0 ) || ( !hasFragmentation
993 && ( localWrittenBytes != 0 ) )) {
994 fireMessageSent(session, req);
995 }
996
997 return localWrittenBytes;
998 }
999
1000 private void fireMessageSent(S session, WriteRequest req) {
1001 session.setCurrentWriteRequest(null);
1002 IoFilterChain filterChain = session.getFilterChain();
1003 filterChain.fireMessageSent(req);
1004 }
1005
1006
1007
1008
1009 private void updateTrafficMask() {
1010 int queueSize = trafficControllingSessions.size();
1011
1012 while (queueSize > 0) {
1013 S session = trafficControllingSessions.poll();
1014
1015 if (session == null) {
1016
1017 return;
1018 }
1019
1020 SessionState state = getState(session);
1021
1022 switch (state) {
1023 case OPENED:
1024 updateTrafficControl(session);
1025
1026 break;
1027
1028 case CLOSING:
1029 break;
1030
1031 case OPENING:
1032
1033
1034
1035
1036 trafficControllingSessions.add(session);
1037 break;
1038
1039 default:
1040 throw new IllegalStateException(String.valueOf(state));
1041 }
1042
1043
1044
1045
1046
1047 queueSize--;
1048 }
1049 }
1050
1051
1052
1053
1054 public void updateTrafficControl(S session) {
1055
1056 try {
1057 setInterestedInRead(session, !session.isReadSuspended());
1058 } catch (Exception e) {
1059 IoFilterChain filterChain = session.getFilterChain();
1060 filterChain.fireExceptionCaught(e);
1061 }
1062
1063 try {
1064 setInterestedInWrite(session, !session.getWriteRequestQueue()
1065 .isEmpty(session)
1066 && !session.isWriteSuspended());
1067 } catch (Exception e) {
1068 IoFilterChain filterChain = session.getFilterChain();
1069 filterChain.fireExceptionCaught(e);
1070 }
1071 }
1072
1073
1074
1075
1076
1077
1078
1079 private class Processor implements Runnable {
1080 public void run() {
1081 assert (processorRef.get() == this);
1082
1083 int nSessions = 0;
1084 lastIdleCheckTime = System.currentTimeMillis();
1085
1086 for (;;) {
1087 try {
1088
1089
1090
1091
1092 long t0 = System.currentTimeMillis();
1093 int selected = select(SELECT_TIMEOUT);
1094 long t1 = System.currentTimeMillis();
1095 long delta = (t1 - t0);
1096
1097 if ((selected == 0) && !wakeupCalled.get() && (delta < 100)) {
1098
1099
1100 if (isBrokenConnection()) {
1101 LOG.warn("Broken connection");
1102
1103
1104
1105 wakeupCalled.getAndSet(false);
1106
1107 continue;
1108 } else {
1109 LOG.warn("Create a new selector. Selected is 0, delta = "
1110 + (t1 - t0));
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122 registerNewSelector();
1123 }
1124
1125
1126 wakeupCalled.getAndSet(false);
1127
1128
1129 continue;
1130 }
1131
1132
1133 nSessions += handleNewSessions();
1134
1135 updateTrafficMask();
1136
1137
1138
1139 if (selected > 0) {
1140
1141 process();
1142 }
1143
1144
1145 long currentTime = System.currentTimeMillis();
1146 flush(currentTime);
1147
1148
1149 nSessions -= removeSessions();
1150
1151
1152 notifyIdleSessions(currentTime);
1153
1154
1155
1156 if (nSessions == 0) {
1157 processorRef.set(null);
1158
1159 if (newSessions.isEmpty() && isSelectorEmpty()) {
1160
1161 assert (processorRef.get() != this);
1162 break;
1163 }
1164
1165 assert (processorRef.get() != this);
1166
1167 if (!processorRef.compareAndSet(null, this)) {
1168
1169 assert (processorRef.get() != this);
1170 break;
1171 }
1172
1173 assert (processorRef.get() == this);
1174 }
1175
1176
1177
1178 if (isDisposing()) {
1179 for (Iterator<S> i = allSessions(); i.hasNext();) {
1180 scheduleRemove(i.next());
1181 }
1182
1183 wakeup();
1184 }
1185 } catch (ClosedSelectorException cse) {
1186
1187 break;
1188 } catch (Throwable t) {
1189 ExceptionMonitor.getInstance().exceptionCaught(t);
1190
1191 try {
1192 Thread.sleep(1000);
1193 } catch (InterruptedException e1) {
1194 ExceptionMonitor.getInstance().exceptionCaught(e1);
1195 }
1196 }
1197 }
1198
1199 try {
1200 synchronized (disposalLock) {
1201 if (disposing) {
1202 doDispose();
1203 }
1204 }
1205 } catch (Throwable t) {
1206 ExceptionMonitor.getInstance().exceptionCaught(t);
1207 } finally {
1208 disposalFuture.setValue(true);
1209 }
1210 }
1211 }
1212 }