001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.mina.core.filterchain; 021 022import java.util.ArrayList; 023import java.util.List; 024import java.util.Map; 025import java.util.concurrent.ConcurrentHashMap; 026 027import org.apache.mina.core.buffer.IoBuffer; 028import org.apache.mina.core.filterchain.IoFilter.NextFilter; 029import org.apache.mina.core.future.ConnectFuture; 030import org.apache.mina.core.future.IoFuture; 031import org.apache.mina.core.service.AbstractIoService; 032import org.apache.mina.core.session.AbstractIoSession; 033import org.apache.mina.core.session.AttributeKey; 034import org.apache.mina.core.session.IdleStatus; 035import org.apache.mina.core.session.IoSession; 036import org.apache.mina.core.write.WriteRequest; 037import org.apache.mina.core.write.WriteRequestQueue; 038import org.slf4j.Logger; 039import org.slf4j.LoggerFactory; 040 041/** 042 * A default implementation of {@link IoFilterChain} that provides 043 * all operations for developers who want to implement their own 044 * transport layer once used with {@link AbstractIoSession}. 045 * 046 * @author <a href="http://mina.apache.org">Apache MINA Project</a> 047 */ 048public class DefaultIoFilterChain implements IoFilterChain { 049 /** 050 * A session attribute that stores an {@link IoFuture} related with 051 * the {@link IoSession}. {@link DefaultIoFilterChain} clears this 052 * attribute and notifies the future when {@link #fireSessionCreated()} 053 * or {@link #fireExceptionCaught(Throwable)} is invoked. 054 */ 055 public static final AttributeKey SESSION_CREATED_FUTURE = new AttributeKey(DefaultIoFilterChain.class, 056 "connectFuture"); 057 058 /** The associated session */ 059 private final AbstractIoSession session; 060 061 /** The mapping between the filters and their associated name */ 062 private final Map<String, Entry> name2entry = new ConcurrentHashMap<String, Entry>(); 063 064 /** The chain head */ 065 private final EntryImpl head; 066 067 /** The chain tail */ 068 private final EntryImpl tail; 069 070 /** The logger for this class */ 071 private final static Logger LOGGER = LoggerFactory.getLogger(DefaultIoFilterChain.class); 072 073 /** 074 * Create a new default chain, associated with a session. It will only contain a 075 * HeadFilter and a TailFilter. 076 * 077 * @param session The session associated with the created filter chain 078 */ 079 public DefaultIoFilterChain(AbstractIoSession session) { 080 if (session == null) { 081 throw new IllegalArgumentException("session"); 082 } 083 084 this.session = session; 085 head = new EntryImpl(null, null, "head", new HeadFilter()); 086 tail = new EntryImpl(head, null, "tail", new TailFilter()); 087 head.nextEntry = tail; 088 } 089 090 public IoSession getSession() { 091 return session; 092 } 093 094 public Entry getEntry(String name) { 095 Entry e = name2entry.get(name); 096 097 if (e == null) { 098 return null; 099 } 100 101 return e; 102 } 103 104 public Entry getEntry(IoFilter filter) { 105 EntryImpl e = head.nextEntry; 106 107 while (e != tail) { 108 if (e.getFilter() == filter) { 109 return e; 110 } 111 112 e = e.nextEntry; 113 } 114 115 return null; 116 } 117 118 public Entry getEntry(Class<? extends IoFilter> filterType) { 119 EntryImpl e = head.nextEntry; 120 121 while (e != tail) { 122 if (filterType.isAssignableFrom(e.getFilter().getClass())) { 123 return e; 124 } 125 126 e = e.nextEntry; 127 } 128 129 return null; 130 } 131 132 public IoFilter get(String name) { 133 Entry e = getEntry(name); 134 135 if (e == null) { 136 return null; 137 } 138 139 return e.getFilter(); 140 } 141 142 public IoFilter get(Class<? extends IoFilter> filterType) { 143 Entry e = getEntry(filterType); 144 145 if (e == null) { 146 return null; 147 } 148 149 return e.getFilter(); 150 } 151 152 public NextFilter getNextFilter(String name) { 153 Entry e = getEntry(name); 154 155 if (e == null) { 156 return null; 157 } 158 159 return e.getNextFilter(); 160 } 161 162 public NextFilter getNextFilter(IoFilter filter) { 163 Entry e = getEntry(filter); 164 165 if (e == null) { 166 return null; 167 } 168 169 return e.getNextFilter(); 170 } 171 172 public NextFilter getNextFilter(Class<? extends IoFilter> filterType) { 173 Entry e = getEntry(filterType); 174 175 if (e == null) { 176 return null; 177 } 178 179 return e.getNextFilter(); 180 } 181 182 public synchronized void addFirst(String name, IoFilter filter) { 183 checkAddable(name); 184 register(head, name, filter); 185 } 186 187 public synchronized void addLast(String name, IoFilter filter) { 188 checkAddable(name); 189 register(tail.prevEntry, name, filter); 190 } 191 192 public synchronized void addBefore(String baseName, String name, IoFilter filter) { 193 EntryImpl baseEntry = checkOldName(baseName); 194 checkAddable(name); 195 register(baseEntry.prevEntry, name, filter); 196 } 197 198 public synchronized void addAfter(String baseName, String name, IoFilter filter) { 199 EntryImpl baseEntry = checkOldName(baseName); 200 checkAddable(name); 201 register(baseEntry, name, filter); 202 } 203 204 public synchronized IoFilter remove(String name) { 205 EntryImpl entry = checkOldName(name); 206 deregister(entry); 207 return entry.getFilter(); 208 } 209 210 public synchronized void remove(IoFilter filter) { 211 EntryImpl e = head.nextEntry; 212 213 while (e != tail) { 214 if (e.getFilter() == filter) { 215 deregister(e); 216 217 return; 218 } 219 220 e = e.nextEntry; 221 } 222 223 throw new IllegalArgumentException("Filter not found: " + filter.getClass().getName()); 224 } 225 226 public synchronized IoFilter remove(Class<? extends IoFilter> filterType) { 227 EntryImpl e = head.nextEntry; 228 229 while (e != tail) { 230 if (filterType.isAssignableFrom(e.getFilter().getClass())) { 231 IoFilter oldFilter = e.getFilter(); 232 deregister(e); 233 234 return oldFilter; 235 } 236 237 e = e.nextEntry; 238 } 239 240 throw new IllegalArgumentException("Filter not found: " + filterType.getName()); 241 } 242 243 public synchronized IoFilter replace(String name, IoFilter newFilter) { 244 EntryImpl entry = checkOldName(name); 245 IoFilter oldFilter = entry.getFilter(); 246 247 // Call the preAdd method of the new filter 248 try { 249 newFilter.onPreAdd(this, name, entry.getNextFilter()); 250 } catch (Exception e) { 251 throw new IoFilterLifeCycleException("onPreAdd(): " + name + ':' + newFilter + " in " + getSession(), e); 252 } 253 254 // Now, register the new Filter replacing the old one. 255 entry.setFilter(newFilter); 256 257 // Call the postAdd method of the new filter 258 try { 259 newFilter.onPostAdd(this, name, entry.getNextFilter()); 260 } catch (Exception e) { 261 entry.setFilter(oldFilter); 262 throw new IoFilterLifeCycleException("onPostAdd(): " + name + ':' + newFilter + " in " + getSession(), e); 263 } 264 265 return oldFilter; 266 } 267 268 public synchronized void replace(IoFilter oldFilter, IoFilter newFilter) { 269 EntryImpl entry = head.nextEntry; 270 271 // Search for the filter to replace 272 while (entry != tail) { 273 if (entry.getFilter() == oldFilter) { 274 String oldFilterName = null; 275 276 // Get the old filter name. It's not really efficient... 277 for (Map.Entry<String, Entry> mapping : name2entry.entrySet()) { 278 if (entry == mapping.getValue() ) { 279 oldFilterName = mapping.getKey(); 280 281 break; 282 } 283 } 284 285 // Call the preAdd method of the new filter 286 try { 287 newFilter.onPreAdd(this, oldFilterName, entry.getNextFilter()); 288 } catch (Exception e) { 289 throw new IoFilterLifeCycleException("onPreAdd(): " + oldFilterName + ':' + newFilter + " in " 290 + getSession(), e); 291 } 292 293 // Now, register the new Filter replacing the old one. 294 entry.setFilter(newFilter); 295 296 // Call the postAdd method of the new filter 297 try { 298 newFilter.onPostAdd(this, oldFilterName, entry.getNextFilter()); 299 } catch (Exception e) { 300 entry.setFilter(oldFilter); 301 throw new IoFilterLifeCycleException("onPostAdd(): " + oldFilterName + ':' + newFilter + " in " 302 + getSession(), e); 303 } 304 305 return; 306 } 307 308 entry = entry.nextEntry; 309 } 310 311 throw new IllegalArgumentException("Filter not found: " + oldFilter.getClass().getName()); 312 } 313 314 public synchronized IoFilter replace(Class<? extends IoFilter> oldFilterType, IoFilter newFilter) { 315 EntryImpl entry = head.nextEntry; 316 317 while (entry != tail) { 318 if (oldFilterType.isAssignableFrom(entry.getFilter().getClass())) { 319 IoFilter oldFilter = entry.getFilter(); 320 321 String oldFilterName = null; 322 323 // Get the old filter name. It's not really efficient... 324 for (Map.Entry<String, Entry> mapping : name2entry.entrySet()) { 325 if (entry == mapping.getValue() ) { 326 oldFilterName = mapping.getKey(); 327 328 break; 329 } 330 } 331 332 // Call the preAdd method of the new filter 333 try { 334 newFilter.onPreAdd(this, oldFilterName, entry.getNextFilter()); 335 } catch (Exception e) { 336 throw new IoFilterLifeCycleException("onPreAdd(): " + oldFilterName + ':' + newFilter + " in " 337 + getSession(), e); 338 } 339 340 entry.setFilter(newFilter); 341 342 // Call the postAdd method of the new filter 343 try { 344 newFilter.onPostAdd(this, oldFilterName, entry.getNextFilter()); 345 } catch (Exception e) { 346 entry.setFilter(oldFilter); 347 throw new IoFilterLifeCycleException("onPostAdd(): " + oldFilterName + ':' + newFilter + " in " 348 + getSession(), e); 349 } 350 351 return oldFilter; 352 } 353 354 entry = entry.nextEntry; 355 } 356 357 throw new IllegalArgumentException("Filter not found: " + oldFilterType.getName()); 358 } 359 360 public synchronized void clear() throws Exception { 361 List<IoFilterChain.Entry> l = new ArrayList<IoFilterChain.Entry>(name2entry.values()); 362 363 for (IoFilterChain.Entry entry : l) { 364 try { 365 deregister((EntryImpl) entry); 366 } catch (Exception e) { 367 throw new IoFilterLifeCycleException("clear(): " + entry.getName() + " in " + getSession(), e); 368 } 369 } 370 } 371 372 /** 373 * Register the newly added filter, inserting it between the previous and 374 * the next filter in the filter's chain. We also call the preAdd and 375 * postAdd methods. 376 */ 377 private void register(EntryImpl prevEntry, String name, IoFilter filter) { 378 EntryImpl newEntry = new EntryImpl(prevEntry, prevEntry.nextEntry, name, filter); 379 380 try { 381 filter.onPreAdd(this, name, newEntry.getNextFilter()); 382 } catch (Exception e) { 383 throw new IoFilterLifeCycleException("onPreAdd(): " + name + ':' + filter + " in " + getSession(), e); 384 } 385 386 prevEntry.nextEntry.prevEntry = newEntry; 387 prevEntry.nextEntry = newEntry; 388 name2entry.put(name, newEntry); 389 390 try { 391 filter.onPostAdd(this, name, newEntry.getNextFilter()); 392 } catch (Exception e) { 393 deregister0(newEntry); 394 throw new IoFilterLifeCycleException("onPostAdd(): " + name + ':' + filter + " in " + getSession(), e); 395 } 396 } 397 398 private void deregister(EntryImpl entry) { 399 IoFilter filter = entry.getFilter(); 400 401 try { 402 filter.onPreRemove(this, entry.getName(), entry.getNextFilter()); 403 } catch (Exception e) { 404 throw new IoFilterLifeCycleException("onPreRemove(): " + entry.getName() + ':' + filter + " in " 405 + getSession(), e); 406 } 407 408 deregister0(entry); 409 410 try { 411 filter.onPostRemove(this, entry.getName(), entry.getNextFilter()); 412 } catch (Exception e) { 413 throw new IoFilterLifeCycleException("onPostRemove(): " + entry.getName() + ':' + filter + " in " 414 + getSession(), e); 415 } 416 } 417 418 private void deregister0(EntryImpl entry) { 419 EntryImpl prevEntry = entry.prevEntry; 420 EntryImpl nextEntry = entry.nextEntry; 421 prevEntry.nextEntry = nextEntry; 422 nextEntry.prevEntry = prevEntry; 423 424 name2entry.remove(entry.name); 425 } 426 427 /** 428 * Throws an exception when the specified filter name is not registered in this chain. 429 * 430 * @return An filter entry with the specified name. 431 */ 432 private EntryImpl checkOldName(String baseName) { 433 EntryImpl e = (EntryImpl) name2entry.get(baseName); 434 435 if (e == null) { 436 throw new IllegalArgumentException("Filter not found:" + baseName); 437 } 438 439 return e; 440 } 441 442 /** 443 * Checks the specified filter name is already taken and throws an exception if already taken. 444 */ 445 private void checkAddable(String name) { 446 if (name2entry.containsKey(name)) { 447 throw new IllegalArgumentException("Other filter is using the same name '" + name + "'"); 448 } 449 } 450 451 public void fireSessionCreated() { 452 callNextSessionCreated(head, session); 453 } 454 455 private void callNextSessionCreated(Entry entry, IoSession session) { 456 try { 457 IoFilter filter = entry.getFilter(); 458 NextFilter nextFilter = entry.getNextFilter(); 459 filter.sessionCreated(nextFilter, session); 460 } catch (Exception e) { 461 fireExceptionCaught(e); 462 } catch (Error e) { 463 fireExceptionCaught(e); 464 throw e; 465 } 466 } 467 468 public void fireSessionOpened() { 469 callNextSessionOpened(head, session); 470 } 471 472 private void callNextSessionOpened(Entry entry, IoSession session) { 473 try { 474 IoFilter filter = entry.getFilter(); 475 NextFilter nextFilter = entry.getNextFilter(); 476 filter.sessionOpened(nextFilter, session); 477 } catch (Exception e) { 478 fireExceptionCaught(e); 479 } catch (Error e) { 480 fireExceptionCaught(e); 481 throw e; 482 } 483 } 484 485 public void fireSessionClosed() { 486 // Update future. 487 try { 488 session.getCloseFuture().setClosed(); 489 } catch (Exception e) { 490 fireExceptionCaught(e); 491 } catch (Error e) { 492 fireExceptionCaught(e); 493 throw e; 494 } 495 496 // And start the chain. 497 callNextSessionClosed(head, session); 498 } 499 500 private void callNextSessionClosed(Entry entry, IoSession session) { 501 try { 502 IoFilter filter = entry.getFilter(); 503 NextFilter nextFilter = entry.getNextFilter(); 504 filter.sessionClosed(nextFilter, session); 505 } catch (Exception e) { 506 fireExceptionCaught(e); 507 } catch (Error e) { 508 fireExceptionCaught(e); 509 } 510 } 511 512 public void fireSessionIdle(IdleStatus status) { 513 session.increaseIdleCount(status, System.currentTimeMillis()); 514 callNextSessionIdle(head, session, status); 515 } 516 517 private void callNextSessionIdle(Entry entry, IoSession session, IdleStatus status) { 518 try { 519 IoFilter filter = entry.getFilter(); 520 NextFilter nextFilter = entry.getNextFilter(); 521 filter.sessionIdle(nextFilter, session, status); 522 } catch (Exception e) { 523 fireExceptionCaught(e); 524 } catch (Error e) { 525 fireExceptionCaught(e); 526 throw e; 527 } 528 } 529 530 public void fireMessageReceived(Object message) { 531 if (message instanceof IoBuffer) { 532 session.increaseReadBytes(((IoBuffer) message).remaining(), System.currentTimeMillis()); 533 } 534 535 callNextMessageReceived(head, session, message); 536 } 537 538 private void callNextMessageReceived(Entry entry, IoSession session, Object message) { 539 try { 540 IoFilter filter = entry.getFilter(); 541 NextFilter nextFilter = entry.getNextFilter(); 542 filter.messageReceived(nextFilter, session, message); 543 } catch (Exception e) { 544 fireExceptionCaught(e); 545 } catch (Error e) { 546 fireExceptionCaught(e); 547 throw e; 548 } 549 } 550 551 public void fireMessageSent(WriteRequest request) { 552 try { 553 request.getFuture().setWritten(); 554 } catch (Exception e) { 555 fireExceptionCaught(e); 556 } catch (Error e) { 557 fireExceptionCaught(e); 558 throw e; 559 } 560 561 if (!request.isEncoded()) { 562 callNextMessageSent(head, session, request); 563 } 564 } 565 566 private void callNextMessageSent(Entry entry, IoSession session, WriteRequest writeRequest) { 567 try { 568 IoFilter filter = entry.getFilter(); 569 NextFilter nextFilter = entry.getNextFilter(); 570 filter.messageSent(nextFilter, session, writeRequest); 571 } catch (Exception e) { 572 fireExceptionCaught(e); 573 } catch (Error e) { 574 fireExceptionCaught(e); 575 throw e; 576 } 577 } 578 579 public void fireExceptionCaught(Throwable cause) { 580 callNextExceptionCaught(head, session, cause); 581 } 582 583 private void callNextExceptionCaught(Entry entry, IoSession session, Throwable cause) { 584 // Notify the related future. 585 ConnectFuture future = (ConnectFuture) session.removeAttribute(SESSION_CREATED_FUTURE); 586 if (future == null) { 587 try { 588 IoFilter filter = entry.getFilter(); 589 NextFilter nextFilter = entry.getNextFilter(); 590 filter.exceptionCaught(nextFilter, session, cause); 591 } catch (Throwable e) { 592 LOGGER.warn("Unexpected exception from exceptionCaught handler.", e); 593 } 594 } else { 595 // Please note that this place is not the only place that 596 // calls ConnectFuture.setException(). 597 if (!session.isClosing()) { 598 // Call the closeNow method only if needed 599 session.closeNow(); 600 } 601 602 future.setException(cause); 603 } 604 } 605 606 public void fireInputClosed() { 607 Entry head = this.head; 608 callNextInputClosed(head, session); 609 } 610 611 private void callNextInputClosed(Entry entry, IoSession session) { 612 try { 613 IoFilter filter = entry.getFilter(); 614 NextFilter nextFilter = entry.getNextFilter(); 615 filter.inputClosed(nextFilter, session); 616 } catch (Throwable e) { 617 fireExceptionCaught(e); 618 } 619 } 620 621 public void fireFilterWrite(WriteRequest writeRequest) { 622 callPreviousFilterWrite(tail, session, writeRequest); 623 } 624 625 private void callPreviousFilterWrite(Entry entry, IoSession session, WriteRequest writeRequest) { 626 try { 627 IoFilter filter = entry.getFilter(); 628 NextFilter nextFilter = entry.getNextFilter(); 629 filter.filterWrite(nextFilter, session, writeRequest); 630 } catch (Exception e) { 631 writeRequest.getFuture().setException(e); 632 fireExceptionCaught(e); 633 } catch (Error e) { 634 writeRequest.getFuture().setException(e); 635 fireExceptionCaught(e); 636 throw e; 637 } 638 } 639 640 public void fireFilterClose() { 641 callPreviousFilterClose(tail, session); 642 } 643 644 private void callPreviousFilterClose(Entry entry, IoSession session) { 645 try { 646 IoFilter filter = entry.getFilter(); 647 NextFilter nextFilter = entry.getNextFilter(); 648 filter.filterClose(nextFilter, session); 649 } catch (Exception e) { 650 fireExceptionCaught(e); 651 } catch (Error e) { 652 fireExceptionCaught(e); 653 throw e; 654 } 655 } 656 657 public List<Entry> getAll() { 658 List<Entry> list = new ArrayList<Entry>(); 659 EntryImpl e = head.nextEntry; 660 661 while (e != tail) { 662 list.add(e); 663 e = e.nextEntry; 664 } 665 666 return list; 667 } 668 669 public List<Entry> getAllReversed() { 670 List<Entry> list = new ArrayList<Entry>(); 671 EntryImpl e = tail.prevEntry; 672 673 while (e != head) { 674 list.add(e); 675 e = e.prevEntry; 676 } 677 678 return list; 679 } 680 681 public boolean contains(String name) { 682 return getEntry(name) != null; 683 } 684 685 public boolean contains(IoFilter filter) { 686 return getEntry(filter) != null; 687 } 688 689 public boolean contains(Class<? extends IoFilter> filterType) { 690 return getEntry(filterType) != null; 691 } 692 693 @Override 694 public String toString() { 695 StringBuilder buf = new StringBuilder(); 696 buf.append("{ "); 697 698 boolean empty = true; 699 700 EntryImpl e = head.nextEntry; 701 702 while (e != tail) { 703 if (!empty) { 704 buf.append(", "); 705 } else { 706 empty = false; 707 } 708 709 buf.append('('); 710 buf.append(e.getName()); 711 buf.append(':'); 712 buf.append(e.getFilter()); 713 buf.append(')'); 714 715 e = e.nextEntry; 716 } 717 718 if (empty) { 719 buf.append("empty"); 720 } 721 722 buf.append(" }"); 723 724 return buf.toString(); 725 } 726 727 private class HeadFilter extends IoFilterAdapter { 728 @SuppressWarnings("unchecked") 729 @Override 730 public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) throws Exception { 731 732 AbstractIoSession s = (AbstractIoSession) session; 733 734 // Maintain counters. 735 if (writeRequest.getMessage() instanceof IoBuffer) { 736 IoBuffer buffer = (IoBuffer) writeRequest.getMessage(); 737 // I/O processor implementation will call buffer.reset() 738 // it after the write operation is finished, because 739 // the buffer will be specified with messageSent event. 740 buffer.mark(); 741 int remaining = buffer.remaining(); 742 743 if (remaining > 0) { 744 s.increaseScheduledWriteBytes(remaining); 745 } 746 } else { 747 s.increaseScheduledWriteMessages(); 748 } 749 750 WriteRequestQueue writeRequestQueue = s.getWriteRequestQueue(); 751 752 if (!s.isWriteSuspended()) { 753 if (writeRequestQueue.isEmpty(session)) { 754 // We can write directly the message 755 s.getProcessor().write(s, writeRequest); 756 } else { 757 s.getWriteRequestQueue().offer(s, writeRequest); 758 s.getProcessor().flush(s); 759 } 760 } else { 761 s.getWriteRequestQueue().offer(s, writeRequest); 762 } 763 } 764 765 @SuppressWarnings("unchecked") 766 @Override 767 public void filterClose(NextFilter nextFilter, IoSession session) throws Exception { 768 ((AbstractIoSession) session).getProcessor().remove(session); 769 } 770 } 771 772 private static class TailFilter extends IoFilterAdapter { 773 @Override 774 public void sessionCreated(NextFilter nextFilter, IoSession session) throws Exception { 775 try { 776 session.getHandler().sessionCreated(session); 777 } finally { 778 // Notify the related future. 779 ConnectFuture future = (ConnectFuture) session.removeAttribute(SESSION_CREATED_FUTURE); 780 781 if (future != null) { 782 future.setSession(session); 783 } 784 } 785 } 786 787 @Override 788 public void sessionOpened(NextFilter nextFilter, IoSession session) throws Exception { 789 session.getHandler().sessionOpened(session); 790 } 791 792 @Override 793 public void sessionClosed(NextFilter nextFilter, IoSession session) throws Exception { 794 AbstractIoSession s = (AbstractIoSession) session; 795 796 try { 797 s.getHandler().sessionClosed(session); 798 } finally { 799 try { 800 s.getWriteRequestQueue().dispose(session); 801 } finally { 802 try { 803 s.getAttributeMap().dispose(session); 804 } finally { 805 try { 806 // Remove all filters. 807 session.getFilterChain().clear(); 808 } finally { 809 if (s.getConfig().isUseReadOperation()) { 810 s.offerClosedReadFuture(); 811 } 812 } 813 } 814 } 815 } 816 } 817 818 @Override 819 public void sessionIdle(NextFilter nextFilter, IoSession session, IdleStatus status) throws Exception { 820 session.getHandler().sessionIdle(session, status); 821 } 822 823 @Override 824 public void exceptionCaught(NextFilter nextFilter, IoSession session, Throwable cause) throws Exception { 825 AbstractIoSession s = (AbstractIoSession) session; 826 827 try { 828 s.getHandler().exceptionCaught(s, cause); 829 } finally { 830 if (s.getConfig().isUseReadOperation()) { 831 s.offerFailedReadFuture(cause); 832 } 833 } 834 } 835 836 @Override 837 public void inputClosed(NextFilter nextFilter, IoSession session) throws Exception { 838 session.getHandler().inputClosed(session); 839 } 840 841 @Override 842 public void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception { 843 AbstractIoSession s = (AbstractIoSession) session; 844 845 if (!(message instanceof IoBuffer)) { 846 s.increaseReadMessages(System.currentTimeMillis()); 847 } else if (!((IoBuffer) message).hasRemaining()) { 848 s.increaseReadMessages(System.currentTimeMillis()); 849 } 850 851 // Update the statistics 852 if (session.getService() instanceof AbstractIoService) { 853 ((AbstractIoService) session.getService()).getStatistics().updateThroughput(System.currentTimeMillis()); 854 } 855 856 // Propagate the message 857 try { 858 session.getHandler().messageReceived(s, message); 859 } finally { 860 if (s.getConfig().isUseReadOperation()) { 861 s.offerReadFuture(message); 862 } 863 } 864 } 865 866 @Override 867 public void messageSent(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) throws Exception { 868 ((AbstractIoSession) session).increaseWrittenMessages(writeRequest, System.currentTimeMillis()); 869 870 // Update the statistics 871 if (session.getService() instanceof AbstractIoService) { 872 ((AbstractIoService) session.getService()).getStatistics().updateThroughput(System.currentTimeMillis()); 873 } 874 875 // Propagate the message 876 session.getHandler().messageSent(session, writeRequest.getMessage()); 877 } 878 879 @Override 880 public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) throws Exception { 881 nextFilter.filterWrite(session, writeRequest); 882 } 883 884 @Override 885 public void filterClose(NextFilter nextFilter, IoSession session) throws Exception { 886 nextFilter.filterClose(session); 887 } 888 } 889 890 private final class EntryImpl implements Entry { 891 private EntryImpl prevEntry; 892 893 private EntryImpl nextEntry; 894 895 private final String name; 896 897 private IoFilter filter; 898 899 private final NextFilter nextFilter; 900 901 private EntryImpl(EntryImpl prevEntry, EntryImpl nextEntry, String name, IoFilter filter) { 902 if (filter == null) { 903 throw new IllegalArgumentException("filter"); 904 } 905 906 if (name == null) { 907 throw new IllegalArgumentException("name"); 908 } 909 910 this.prevEntry = prevEntry; 911 this.nextEntry = nextEntry; 912 this.name = name; 913 this.filter = filter; 914 this.nextFilter = new NextFilter() { 915 public void sessionCreated(IoSession session) { 916 Entry nextEntry = EntryImpl.this.nextEntry; 917 callNextSessionCreated(nextEntry, session); 918 } 919 920 public void sessionOpened(IoSession session) { 921 Entry nextEntry = EntryImpl.this.nextEntry; 922 callNextSessionOpened(nextEntry, session); 923 } 924 925 public void sessionClosed(IoSession session) { 926 Entry nextEntry = EntryImpl.this.nextEntry; 927 callNextSessionClosed(nextEntry, session); 928 } 929 930 public void sessionIdle(IoSession session, IdleStatus status) { 931 Entry nextEntry = EntryImpl.this.nextEntry; 932 callNextSessionIdle(nextEntry, session, status); 933 } 934 935 public void exceptionCaught(IoSession session, Throwable cause) { 936 Entry nextEntry = EntryImpl.this.nextEntry; 937 callNextExceptionCaught(nextEntry, session, cause); 938 } 939 940 public void inputClosed(IoSession session) { 941 Entry nextEntry = EntryImpl.this.nextEntry; 942 callNextInputClosed(nextEntry, session); 943 } 944 945 public void messageReceived(IoSession session, Object message) { 946 Entry nextEntry = EntryImpl.this.nextEntry; 947 callNextMessageReceived(nextEntry, session, message); 948 } 949 950 public void messageSent(IoSession session, WriteRequest writeRequest) { 951 Entry nextEntry = EntryImpl.this.nextEntry; 952 callNextMessageSent(nextEntry, session, writeRequest); 953 } 954 955 public void filterWrite(IoSession session, WriteRequest writeRequest) { 956 Entry nextEntry = EntryImpl.this.prevEntry; 957 callPreviousFilterWrite(nextEntry, session, writeRequest); 958 } 959 960 public void filterClose(IoSession session) { 961 Entry nextEntry = EntryImpl.this.prevEntry; 962 callPreviousFilterClose(nextEntry, session); 963 } 964 965 public String toString() { 966 return EntryImpl.this.nextEntry.name; 967 } 968 }; 969 } 970 971 public String getName() { 972 return name; 973 } 974 975 public IoFilter getFilter() { 976 return filter; 977 } 978 979 private void setFilter(IoFilter filter) { 980 if (filter == null) { 981 throw new IllegalArgumentException("filter"); 982 } 983 984 this.filter = filter; 985 } 986 987 public NextFilter getNextFilter() { 988 return nextFilter; 989 } 990 991 @Override 992 public String toString() { 993 StringBuilder sb = new StringBuilder(); 994 995 // Add the current filter 996 sb.append("('").append(getName()).append('\''); 997 998 // Add the previous filter 999 sb.append(", prev: '"); 1000 1001 if (prevEntry != null) { 1002 sb.append(prevEntry.name); 1003 sb.append(':'); 1004 sb.append(prevEntry.getFilter().getClass().getSimpleName()); 1005 } else { 1006 sb.append("null"); 1007 } 1008 1009 // Add the next filter 1010 sb.append("', next: '"); 1011 1012 if (nextEntry != null) { 1013 sb.append(nextEntry.name); 1014 sb.append(':'); 1015 sb.append(nextEntry.getFilter().getClass().getSimpleName()); 1016 } else { 1017 sb.append("null"); 1018 } 1019 1020 sb.append("')"); 1021 1022 return sb.toString(); 1023 } 1024 1025 public void addAfter(String name, IoFilter filter) { 1026 DefaultIoFilterChain.this.addAfter(getName(), name, filter); 1027 } 1028 1029 public void addBefore(String name, IoFilter filter) { 1030 DefaultIoFilterChain.this.addBefore(getName(), name, filter); 1031 } 1032 1033 public void remove() { 1034 DefaultIoFilterChain.this.remove(getName()); 1035 } 1036 1037 public void replace(IoFilter newFilter) { 1038 DefaultIoFilterChain.this.replace(getName(), newFilter); 1039 } 1040 } 1041}