1 29 30 package com.caucho.jca; 31 32 import com.caucho.log.Log; 33 import com.caucho.util.Alarm; 34 import com.caucho.util.L10N; 35 36 import javax.resource.NotSupportedException ; 37 import javax.resource.ResourceException ; 38 import javax.resource.spi.ConnectionEvent ; 39 import javax.resource.spi.ConnectionEventListener ; 40 import javax.resource.spi.ConnectionRequestInfo ; 41 import javax.resource.spi.LocalTransaction ; 42 import javax.resource.spi.ManagedConnection ; 43 import javax.resource.spi.ManagedConnectionFactory ; 44 import javax.security.auth.Subject ; 45 import javax.transaction.xa.XAException ; 46 import javax.transaction.xa.XAResource ; 47 import javax.transaction.xa.Xid ; 48 import java.util.logging.Level ; 49 import java.util.logging.Logger ; 50 51 54 class PoolItem implements ConnectionEventListener , XAResource { 55 private static final L10N L = new L10N(PoolItem.class); 56 private static final Logger log = Log.open(PoolItem.class); 57 58 private ConnectionPool _cm; 59 60 private ManagedConnectionFactory _mcf; 61 private ManagedConnection _mConn; 62 63 private UserTransactionImpl _transaction; 64 65 private String _id; 66 67 private XAResource _xaResource; 68 private LocalTransaction _localTransaction; 69 private int _defaultTransactionTimeout; 70 private int _transactionTimeout; 71 72 private Subject _subject; 73 private ConnectionRequestInfo _requestInfo; 74 75 final Object _shareLock = new Object (); 76 77 UserPoolItem _shareHead; 80 81 private PoolItem _xaHead; 83 private PoolItem _xaNext; 84 85 private boolean _hasConnectionError; 86 87 private long _poolStartTime; 88 private long _poolEventTime; 89 90 private Xid _xid; 91 private int _endFlags = -1; 92 93 private boolean _isXATransaction = true; 95 96 private boolean _isLocalTransaction; 98 99 private IllegalStateException _allocationStackTrace; 100 101 public PoolItem(ConnectionPool cm, 102 ManagedConnectionFactory mcf, 103 ManagedConnection conn) 104 { 105 _cm = cm; 106 107 _id = _cm.generateId(); 108 109 _mcf = mcf; 110 _mConn = conn; 111 112 _poolStartTime = Alarm.getCurrentTime(); 113 _poolEventTime = Alarm.getCurrentTime(); 114 115 try { 117 if (cm.isXATransaction()) { 118 XAResource xaResource = conn.getXAResource(); 119 120 try { 121 _defaultTransactionTimeout = xaResource.getTransactionTimeout(); 122 } catch (Throwable e) { 123 log.log(Level.FINE, e.toString(), e); 124 } 125 126 _xaResource = xaResource; 127 } 128 } catch (NotSupportedException e) { 129 _cm.setXATransaction(false); 130 log.log(Level.FINER, e.toString(), e); 131 } catch (Exception e) { 132 log.log(Level.FINE, e.toString(), e); 133 } 134 135 if (_xaResource == null) 136 _isXATransaction = false; 137 138 try { 140 if (_cm.isLocalTransaction()) 141 _localTransaction = conn.getLocalTransaction(); 142 } catch (NotSupportedException e) { 143 _cm.setLocalTransaction(false); 144 log.log(Level.FINE, e.toString(), e); 145 } catch (Exception e) { 146 log.log(Level.FINE, e.toString(), e); 147 } 148 149 _mConn.addConnectionEventListener(this); 150 151 if (log.isLoggable(Level.FINE)) 152 log.fine("create: " + this + 153 "(active:" + _cm.getConnectionActiveCount() + 154 ", total:" + _cm.getConnectionCount() + ")"); 155 } 156 157 160 public void setSubject(Subject subject) 161 { 162 _subject = subject; 163 } 164 165 168 public void setInfo(ConnectionRequestInfo info) 169 { 170 _requestInfo = info; 171 } 172 173 176 public boolean isActive() 177 { 178 return _shareHead != null; 179 } 180 181 184 public boolean isDead() 185 { 186 return _mConn == null; 187 } 188 189 192 public long getEventTime() 193 { 194 return _poolEventTime; 195 } 196 197 200 public long getStartTime() 201 { 202 return _poolStartTime; 203 } 204 205 208 void setTransaction(UserTransactionImpl transaction) 209 { 210 _transaction = transaction; 211 } 212 213 218 synchronized UserPoolItem toActive(Subject subject, 219 ConnectionRequestInfo info, 220 UserPoolItem userPoolItem) 221 throws ResourceException 222 { 223 long now = Alarm.getCurrentTime(); 224 225 long maxIdleTime = _cm.getMaxIdleTime(); 226 long maxPoolTime = _cm.getMaxPoolTime(); 227 228 if (_hasConnectionError) 229 return null; 230 else if (0 < maxIdleTime && _poolEventTime + maxIdleTime < now) { 231 return null; 232 } 233 else if (0 < maxPoolTime && _poolStartTime + maxPoolTime < now) 234 return null; 235 else if (_shareHead != null) 236 throw new IllegalStateException (L.l("trying to activate active pool item.")); 237 238 _poolEventTime = now; 239 _isXATransaction = _xaResource != null; 241 if (userPoolItem != null) { 242 Object uConn = userPoolItem.getUserConnection(); 243 244 if (uConn != null) 245 _mConn.associateConnection(uConn); 246 247 userPoolItem.associatePoolItem(this); 248 } 249 else 250 userPoolItem = new UserPoolItem(_cm, this); 251 252 if (! isValid(subject, info, userPoolItem)) 253 return null; 254 255 _subject = subject; 256 _requestInfo = info; 257 userPoolItem.associate(this, _mcf, subject, info); 258 259 if (log.isLoggable(Level.FINE)) 260 log.fine("allocate " + this); 261 262 if (_cm.getSaveAllocationStackTrace()) 263 _allocationStackTrace = new IllegalStateException (L.l("Connection {0} allocation stack trace", this)); 264 265 return userPoolItem; 266 } 267 268 273 synchronized boolean isValid() 274 { 275 long now = Alarm.getCurrentTime(); 276 277 long maxIdleTime = _cm.getMaxIdleTime(); 278 long maxPoolTime = _cm.getMaxPoolTime(); 279 long maxActiveTime = _cm.getMaxActiveTime(); 280 281 boolean isActive = isActive() || _xid != null; 282 boolean isDead = false; 283 284 if (! isActive && _hasConnectionError) { 285 isDead = true; 286 log.fine("closing pool item from connection error:" + this); 287 } 288 else if (! isActive && 289 0 < maxIdleTime && _poolEventTime + maxIdleTime < now) { 290 isDead = true; 291 log.fine("closing pool item from idle timeout:" + this); 292 } 293 else if (! isActive && 294 0 < maxPoolTime && _poolStartTime + maxPoolTime < now) { 295 isDead = true; 296 log.fine("closing pool item from pool timeout:" + this); 297 } 298 else if (isActive && 299 0 < maxActiveTime && _poolEventTime + maxActiveTime < now) { 300 isDead = true; 301 log.warning("closing pool item from active timeout:" + this); 302 } 303 304 if (isDead) { 305 _hasConnectionError = true; 306 return false; 307 } 308 else 309 return true; 310 } 311 312 335 UserPoolItem allocateXA(ManagedConnectionFactory mcf, 336 Subject subject, 337 ConnectionRequestInfo info) 338 { 339 if (_mConn == null) return null; 341 else if (_subject != subject) 342 return null; 343 else if (_requestInfo != info) 344 return null; 345 else if (_mcf != mcf) 346 return null; 347 else if (_shareHead != null && ! _cm.isShareable()) return null; 349 else if (_hasConnectionError) return null; 351 352 if (log.isLoggable(Level.FINER)) 353 log.finer("sharing xa-pool item: " + this); 354 355 UserPoolItem userPoolItem = new UserPoolItem(_cm); 356 userPoolItem.associate(this, _mcf, _subject, _requestInfo); 357 358 return userPoolItem; 359 } 360 361 364 boolean isJoin(PoolItem item) 365 { 366 if (this == item) 367 return false; 368 else if (_xid != item._xid) 369 return false; 370 else if (_mcf != item._mcf) 371 return false; 372 else 373 return true; 374 } 375 376 379 boolean share(UserPoolItem userPoolItem) 380 { 381 if (this == userPoolItem.getOwnPoolItem()) 382 return true; 383 else if (_mConn == null) return false; 385 else if (! _cm.isShareable()) return false; 387 else if (_mcf != userPoolItem.getManagedConnectionFactory()) 388 return false; 389 else if (_subject != userPoolItem.getSubject()) 390 return false; 391 else if (_requestInfo != userPoolItem.getInfo()) 392 return false; 393 else if (_hasConnectionError) return false; 395 396 if (true) 398 return false; 399 400 userPoolItem.associate(this, _mcf, _subject, _requestInfo); 401 402 return true; 403 } 404 405 408 ManagedConnection getManagedConnection() 409 { 410 return _mConn; 411 } 412 413 416 423 424 427 Object allocateConnection() 428 throws ResourceException 429 { 430 return _mConn.getConnection(_subject, _requestInfo); 431 } 432 433 436 boolean isValid(Subject subject, 437 ConnectionRequestInfo requestInfo, 438 UserPoolItem userPoolItem) 439 { 440 try { 441 ManagedConnection mConn = getManagedConnection(); 442 443 if (mConn == null) 444 return false; 445 446 Object userConn = userPoolItem.getUserConnection(); 447 448 if (userConn == null) { 449 userConn = mConn.getConnection(subject, requestInfo); 450 451 userPoolItem.setUserConnection(userConn); 452 } 453 454 return userConn != null; 455 } catch (ResourceException e) { 456 log.log(Level.WARNING, e.toString(), e); 457 458 return false; 459 } 460 } 461 462 465 void enableLocalTransactionOptimization(boolean enableOptimization) 466 { 467 if (_xaResource == null) 468 _isXATransaction = false; 469 else if (_localTransaction == null) 470 _isXATransaction = true; 471 else if (! _cm.isLocalTransactionOptimization()) 472 _isXATransaction = true; 473 else if (! _cm.isShareable()) 474 _isXATransaction = true; 475 else 476 _isXATransaction = ! enableOptimization; 477 } 478 479 482 boolean supportsTransaction() 483 { 484 return _xaResource != null || _localTransaction != null; 486 } 487 488 491 XAResource getXAResource() 492 { 493 return _xaResource; 494 } 495 496 499 Xid getXid() 500 { 501 return _xid; 502 } 503 504 507 public void connectionClosed(ConnectionEvent event) 508 { 509 boolean addIdle = false; 510 511 Object handle = event.getConnectionHandle(); 512 513 if (! _hasConnectionError && handle == null && _shareHead != null) { 514 log.fine(L.l("JCA close event '{0}' for {1} did not have a connection handle. Please notify the JCA resource provider.", 515 event, _mConn)); 516 } 517 518 if (_shareHead == null) { 519 toIdle(); 520 return; 521 } 522 523 UserPoolItem userPoolItem = _shareHead; 524 525 while (userPoolItem != null) { 526 UserPoolItem next = userPoolItem.getShareNext(); 527 528 Object userConn = userPoolItem.getUserConnection(); 529 530 if (userConn == handle || handle == null) 531 userPoolItem.close(); 532 533 userPoolItem = next; 534 } 535 } 536 537 540 public void localTransactionStarted(ConnectionEvent event) 541 { 542 if (_isLocalTransaction || _xid != null) 543 throw new IllegalStateException (L.l("attempted to start local transaction while transaction is in progress.")); 544 545 if (_localTransaction != null) { 546 try { 547 _localTransaction.begin(); 548 _isLocalTransaction = true; 549 } catch (ResourceException e) { 550 log.log(Level.WARNING, e.toString(), e); 551 } 552 } 553 } 554 555 558 public void localTransactionCommitted(ConnectionEvent event) 559 { 560 if (_xid != null) 561 throw new IllegalStateException (L.l("attempted to commit() local transaction from an active XA transaction.")); 562 else if (! _isLocalTransaction) 563 throw new IllegalStateException (L.l("attempted to commit() with no active local transaction.")); 564 565 if (_localTransaction != null && _isLocalTransaction) { 566 try { 567 _isLocalTransaction = false; 568 _localTransaction.commit(); 569 } catch (ResourceException e) { 570 log.log(Level.WARNING, e.toString(), e); 571 } 572 } 573 } 574 575 578 public void localTransactionRolledback(ConnectionEvent event) 579 { 580 if (_xid != null) 581 throw new IllegalStateException (L.l("attempted to rollback() local transaction from an active XA transaction.")); 582 else if (! _isLocalTransaction) 583 throw new IllegalStateException (L.l("attempted to rollback() with no active local transaction.")); 584 585 if (_localTransaction != null) { 586 try { 587 _isLocalTransaction = false; 588 _localTransaction.rollback(); 589 } catch (ResourceException e) { 590 log.log(Level.WARNING, e.toString(), e); 591 } 592 } 593 } 594 595 598 public void connectionErrorOccurred(ConnectionEvent event) 599 { 600 _hasConnectionError = true; 601 } 602 603 606 public void setConnectionError() 607 { 608 _hasConnectionError = true; 609 } 610 611 614 public boolean isConnectionError() 615 { 616 return _hasConnectionError; 617 } 618 619 622 public IllegalStateException getAllocationStackTrace() 623 { 624 return _allocationStackTrace; 625 } 626 627 630 631 633 636 public boolean isSameRM(XAResource resource) 637 throws XAException 638 { 639 if (! (resource instanceof PoolItem)) 640 return false; 641 642 PoolItem poolItem = (PoolItem) resource; 643 644 647 if (_xaResource == null) 648 return false; 649 650 boolean isSameRM = _xaResource.isSameRM(poolItem._xaResource); 651 652 if (log.isLoggable(Level.FINER)) 653 log.finer("isSameRM->" + isSameRM + " " + _xaResource); 654 655 return isSameRM; 656 } 657 658 661 public void start(Xid xid, int flags) 662 throws XAException 663 { 664 if (_xid != null) { 665 if (log.isLoggable(Level.FINER)) 666 log.finer("connection pool start XA: rejoin " + this); 667 668 return; 669 } 670 671 if (flags == TMJOIN && _xid == null) { 672 676 _xid = xid; 677 678 UserTransactionImpl trans = _cm.getTransaction(); 679 680 if (trans != null) { 681 PoolItem xaHead = trans.findJoin(this); 682 683 if (xaHead != null) { 684 _xaNext = xaHead._xaNext; 685 _xaHead = xaHead; 686 xaHead._xaNext = this; 687 } 688 } 689 690 703 704 709 } 710 711 if (! _isXATransaction && flags != TMJOIN && _localTransaction != null) { 713 try { 714 if (log.isLoggable(Level.FINER)) 715 log.finer("begin-local-XA: " + _localTransaction); 716 717 _localTransaction.begin(); 718 } catch (ResourceException e) { 719 throw new XAExceptionWrapper(e); 720 } 721 722 _xid = xid; 723 724 return; 725 } 726 727 728 if (_xaResource != null) { 729 if (log.isLoggable(Level.FINER)) 730 log.finer("start-XA: " + xid + " " + _xaResource); 731 732 try { 733 _xaResource.start(xid, flags); 734 } catch (XAException e) { 735 throw e; 736 } 737 } 738 else { 739 if (log.isLoggable(Level.FINER)) 740 log.finer("start-XA with non XA resource: " + xid + " " + _xaResource); 741 } 742 743 _xid = xid; 744 } 745 746 749 public boolean setTransactionTimeout(int seconds) 750 throws XAException 751 { 752 if (seconds == _transactionTimeout) 753 return true; 754 755 XAResource xaResource = _xaResource; 756 757 _transactionTimeout = seconds; 758 759 if (xaResource == null) 760 return true; 761 else if (seconds == 0) 762 return xaResource.setTransactionTimeout(_defaultTransactionTimeout); 763 else 764 return xaResource.setTransactionTimeout(seconds); 765 } 766 767 770 public int getTransactionTimeout() 771 throws XAException 772 { 773 return _transactionTimeout; 774 } 775 776 779 public void forget(Xid xid) 780 throws XAException 781 { 782 try { 783 if (_isXATransaction) 784 _xaResource.forget(xid); 785 } finally { 786 clearXid(); 787 } 788 } 789 790 793 public int prepare(Xid xid) 794 throws XAException 795 { 796 if (_endFlags != -1) { 797 int endFlags = _endFlags; 798 _endFlags = -1; 799 800 if (_isXATransaction) 801 endResource(xid, endFlags); 802 } 803 804 if (_isXATransaction) { 805 try { 806 if (log.isLoggable(Level.FINER)) 807 log.finer("prepare-XA: " + xid + " " + _xaResource); 808 809 return _xaResource.prepare(xid); 810 } catch (XAException e) { 811 if (log.isLoggable(Level.FINER)) 812 log.finer("failed prepare-XA: " + xid + " " + _xaResource + " " + e); 813 814 throw e; 815 } 816 } 817 else 818 return XA_OK; 819 } 820 821 824 public Xid []recover(int flag) 825 throws XAException 826 { 827 if (_isXATransaction) 828 return _xaResource.recover(flag); 829 else 830 return null; 831 } 832 833 836 public void end(Xid xid, int flags) 837 throws XAException 838 { 839 843 844 847 _endFlags = flags; 848 849 852 } 855 856 859 public void rollback(Xid xid) 860 throws XAException 861 { 862 try { 863 if (_endFlags != -1) { 864 try { 865 int endFlags = _endFlags; 866 _endFlags = -1; 867 868 if (_isXATransaction) 869 endResource(xid, endFlags); 870 } catch (Throwable e) { 871 log.log(Level.WARNING, e.toString(), e); 872 if (_isXATransaction) 873 _xaResource.rollback(xid); 874 return; 875 } 876 } 877 878 if (log.isLoggable(Level.FINER)) 879 log.finer("connection pool rollback XA: " + this); 880 881 if (_isXATransaction) 882 _xaResource.rollback(xid); 883 else if (_localTransaction != null) { 884 try { 885 _isLocalTransaction = false; 886 _localTransaction.rollback(); 887 } catch (ResourceException e) { 888 throw new XAExceptionWrapper(e); 889 } 890 } 891 } finally { 892 if (_xaResource != null) 893 _isXATransaction = true; 894 895 clearXid(); 896 } 897 } 898 899 902 public void commit(Xid xid, boolean onePhase) 903 throws XAException 904 { 905 boolean logFiner = log.isLoggable(Level.FINER); 906 907 try { 908 if (_endFlags != -1) { 909 try { 910 int endFlags = _endFlags; 911 _endFlags = -1; 912 913 if (_isXATransaction) 914 endResource(xid, endFlags); 915 } catch (XAException e) { 916 log.log(Level.WARNING, e.toString(), e); 917 _xaResource.rollback(xid); 918 throw e; 919 } catch (Throwable e) { 920 log.log(Level.WARNING, e.toString(), e); 921 _xaResource.rollback(xid); 922 throw new XAException (XAException.XA_RBOTHER); 923 } 924 } 925 926 if (_isXATransaction) { 927 if (logFiner) { 928 log.finer("commit-XA" + (onePhase ? "-1p: " : ": ") 929 + xid + " " + _xaResource); 930 } 931 932 try { 933 _xaResource.commit(xid, onePhase); 934 } catch (XAException e) { 935 if (logFiner) 936 log.finer("commit-XA failed: " + _xaResource + " " + e); 937 938 throw e; 939 } 940 } 941 else if (_localTransaction != null) { 942 if (logFiner) 943 log.finer("commit-local: " + _localTransaction); 944 945 try { 946 _isLocalTransaction = false; 947 _localTransaction.commit(); 948 } catch (ResourceException e) { 949 if (logFiner) 950 log.finer("commit failed: " + _localTransaction + " " + e); 951 952 throw new XAExceptionWrapper(e); 953 } 954 } 955 else { 956 if (logFiner) 957 log.finer("commit for resource with no XA support: " + this); 958 } 959 } finally { 960 if (_xaResource != null) 961 _isXATransaction = true; 962 963 clearXid(); 964 } 965 } 966 967 970 private void endResource(Xid xid, int flags) 971 throws XAException 972 { 973 PoolItem xaPtr = this; 974 975 for (; xaPtr != null; xaPtr = xaPtr._xaNext) { 976 if (xaPtr._xaResource != null) 977 xaPtr._xaResource.end(xid, flags); 978 } 979 } 980 981 984 private void clearXid() 985 { 986 _xid = null; 987 988 UserPoolItem shareHead = _shareHead; 989 991 PoolItem xaPtr = _xaNext; 992 _xaHead = null; 993 _xaNext = null; 994 995 boolean isClosed = true; 996 997 UserPoolItem ptr = shareHead; 998 while (ptr != null) { 999 UserPoolItem next = ptr.getShareNext(); 1000 1001 if (ptr.getOwnPoolItem() == this) 1002 isClosed = false; 1003 1004 try { 1005 ptr.reassociatePoolItem(); 1006 } catch (Throwable e) { 1007 log.log(Level.WARNING, e.toString(), e); 1008 } 1009 1010 ptr = next; 1011 } 1012 1013 while (xaPtr != null) { 1014 PoolItem next = xaPtr._xaNext; 1015 xaPtr._xaNext = null; 1016 xaPtr._xaHead = null; 1017 1018 xaPtr.clearXid(); 1019 1020 xaPtr = next; 1021 } 1022 1023 if (! isClosed) { 1024 } 1025 else if (_hasConnectionError) { 1026 toDead(); 1027 } 1028 else { 1029 toIdle(); 1030 } 1031 } 1032 1033 1036 void toIdle() 1037 { 1038 if (_shareHead != null) 1039 return; 1040 else if (_xid != null || _isLocalTransaction) 1041 return; 1042 else if (_hasConnectionError) { 1043 toDead(); 1044 return; 1045 } 1046 1047 UserTransactionImpl transaction = _transaction; 1048 _transaction = null; 1049 1050 if (transaction != null) { 1051 try { 1052 transaction.delistPoolItem(this, XAResource.TMSUCCESS); 1053 } catch (Throwable e) { 1054 log.log(Level.FINE, e.toString(), e); 1055 } 1056 } 1057 1058 _isLocalTransaction = false; 1059 1060 if (log.isLoggable(Level.FINE)) 1061 log.fine("idle " + this); 1062 1063 _poolEventTime = Alarm.getCurrentTime(); 1064 _cm.toIdle(this); 1065 } 1066 1067 1070 void abortConnection() 1071 { 1072 toDead(); 1073 } 1074 1075 1078 private void toDead() 1079 { 1080 _cm.toDead(this); 1081 } 1082 1083 1086 void destroy() 1087 throws ResourceException 1088 { 1089 ManagedConnection mConn = _mConn; 1090 _mConn = null; 1091 1092 UserTransactionImpl transaction = _transaction; 1093 _transaction = null; 1094 1095 if (mConn == null) 1096 return; 1097 1098 UserPoolItem userItem = _shareHead; 1099 1100 if (log.isLoggable(Level.FINE)) 1101 log.fine("connection pool destroy " + this); 1102 1103 try { 1104 while (userItem != null) { 1105 UserPoolItem next = userItem.getShareNext(); 1106 1107 userItem.close(); 1108 1109 userItem = next; 1110 } 1111 1112 if (transaction != null) 1113 transaction.delistPoolItem(this, XAResource.TMFAIL); 1114 } catch (Throwable e) { 1115 log.log(Level.FINE, e.toString(), e); 1116 } 1117 1118 mConn.destroy(); 1119 } 1120 1121 public String toString() 1122 { 1123 return "PoolItem[" + _cm.getName() + "," + _id + "," + _mConn + "]"; 1124 } 1125} 1126 | Popular Tags |