1 22 package org.jboss.resource.connectionmanager; 23 24 import java.io.PrintWriter ; 25 import java.io.Serializable ; 26 import java.security.Principal ; 27 import java.security.PrivilegedAction ; 28 import java.security.AccessController ; 29 import java.util.Collection ; 30 import java.util.HashMap ; 31 import java.util.HashSet ; 32 import java.util.Iterator ; 33 import java.util.LinkedList ; 34 import java.util.List ; 35 import java.util.Map ; 36 import java.util.Set ; 37 38 import javax.management.MBeanNotificationInfo ; 39 import javax.management.MBeanServer ; 40 import javax.management.Notification ; 41 import javax.management.ObjectName ; 42 import javax.naming.InitialContext ; 43 import javax.resource.ResourceException ; 44 import javax.resource.spi.ConnectionEvent ; 45 import javax.resource.spi.ConnectionManager ; 46 import javax.resource.spi.ConnectionRequestInfo ; 47 import javax.resource.spi.ManagedConnection ; 48 import javax.resource.spi.ManagedConnectionFactory ; 49 import javax.security.auth.Subject ; 50 import javax.transaction.RollbackException ; 51 import javax.transaction.SystemException ; 52 import javax.transaction.Transaction ; 53 import javax.transaction.TransactionManager ; 54 55 import org.jboss.deployment.DeploymentException; 56 import org.jboss.logging.Logger; 57 import org.jboss.logging.util.LoggerPluginWriter; 58 import org.jboss.mx.util.JMXExceptionDecoder; 59 import org.jboss.mx.util.MBeanServerLocator; 60 import org.jboss.resource.JBossResourceException; 61 import org.jboss.resource.connectionmanager.JBossManagedConnectionPool.BasePool; 62 import org.jboss.security.SecurityAssociation; 63 import org.jboss.security.SubjectSecurityManager; 64 import org.jboss.system.ServiceMBeanSupport; 65 import org.jboss.tm.TransactionTimeoutConfiguration; 66 import org.jboss.util.NestedRuntimeException; 67 import org.jboss.util.NotImplementedException; 68 69 85 public abstract class BaseConnectionManager2 extends ServiceMBeanSupport 86 implements 87 BaseConnectionManager2MBean, 88 ConnectionCacheListener, 89 ConnectionListenerFactory, 90 TransactionTimeoutConfiguration 91 { 92 96 private static final String SECURITY_MGR_PATH = "java:/jaas/"; 97 98 99 public static final String STOPPING_NOTIFICATION = "jboss.jca.connectionmanagerstopping"; 100 101 102 protected ObjectName managedConnectionPoolName; 103 104 protected ManagedConnectionPool poolingStrategy; 105 106 protected String jndiName; 107 108 protected String securityDomainJndiName; 109 110 protected SubjectSecurityManager securityDomain; 111 112 protected ObjectName jaasSecurityManagerService; 113 114 protected ObjectName ccmName; 115 116 protected CachedConnectionManager ccm; 117 118 protected boolean trace; 119 120 125 protected static void rethrowAsResourceException(String message, Throwable t) throws ResourceException 126 { 127 JBossResourceException.rethrowAsResourceException(message, t); 128 } 129 130 133 public BaseConnectionManager2() 134 { 135 super(); 136 trace = log.isTraceEnabled(); 137 } 138 139 145 public BaseConnectionManager2(CachedConnectionManager ccm, ManagedConnectionPool poolingStrategy) 146 { 147 super(); 148 this.ccm = ccm; 149 this.poolingStrategy = poolingStrategy; 150 trace = log.isTraceEnabled(); 151 } 152 153 156 public ManagedConnectionPool getPoolingStrategy() 157 { 158 return poolingStrategy; 159 } 160 161 public String getJndiName() 162 { 163 return jndiName; 164 } 165 166 public void setJndiName(String jndiName) 167 { 168 this.jndiName = jndiName; 169 } 170 171 public ObjectName getManagedConnectionPool() 172 { 173 return managedConnectionPoolName; 174 } 175 176 public void setManagedConnectionPool(ObjectName newManagedConnectionPool) 177 { 178 this.managedConnectionPoolName = newManagedConnectionPool; 179 } 180 181 public void setCachedConnectionManager(ObjectName ccmName) 182 { 183 this.ccmName = ccmName; 184 } 185 186 public ObjectName getCachedConnectionManager() 187 { 188 return ccmName; 189 } 190 191 public void setSecurityDomainJndiName(String securityDomainJndiName) 192 { 193 if (securityDomainJndiName != null && securityDomainJndiName.startsWith(SECURITY_MGR_PATH)) 194 { 195 securityDomainJndiName = securityDomainJndiName.substring(SECURITY_MGR_PATH.length()); 196 log.warn("WARNING: UPDATE YOUR SecurityDomainJndiName! REMOVE " + SECURITY_MGR_PATH); 197 } 198 this.securityDomainJndiName = securityDomainJndiName; 199 } 200 201 public String getSecurityDomainJndiName() 202 { 203 return securityDomainJndiName; 204 } 205 206 public ObjectName getJaasSecurityManagerService() 207 { 208 return jaasSecurityManagerService; 209 } 210 211 public void setJaasSecurityManagerService(final ObjectName jaasSecurityManagerService) 212 { 213 this.jaasSecurityManagerService = jaasSecurityManagerService; 214 } 215 216 public ManagedConnectionFactory getManagedConnectionFactory() 217 { 218 return poolingStrategy.getManagedConnectionFactory(); 219 } 220 221 public BaseConnectionManager2 getInstance() 222 { 223 return this; 224 } 225 226 public long getTimeLeftBeforeTransactionTimeout(boolean errorRollback) throws RollbackException 227 { 228 return -1; 229 } 230 231 public int getTransactionTimeout() throws SystemException 232 { 233 throw new NotImplementedException("NYI: getTransactionTimeout()"); 234 } 235 236 238 protected void startService() throws Exception 239 { 240 try 241 { 242 ccm = (CachedConnectionManager) server.getAttribute(ccmName, "Instance"); 243 } 244 catch (Exception e) 245 { 246 JMXExceptionDecoder.rethrow(e); 247 } 248 249 if (ccm == null) 250 throw new DeploymentException("cached ConnectionManager not found: " + ccmName); 251 252 if (securityDomainJndiName != null && jaasSecurityManagerService == null) 253 throw new DeploymentException("You must supply both securityDomainJndiName and jaasSecurityManagerService to use container managed security"); 254 255 if (securityDomainJndiName != null) 256 securityDomain = (SubjectSecurityManager) new InitialContext ().lookup(SECURITY_MGR_PATH 257 + securityDomainJndiName); 258 259 if (managedConnectionPoolName == null) 260 throw new DeploymentException("managedConnectionPool not set!"); 261 try 262 { 263 poolingStrategy = (ManagedConnectionPool) server.getAttribute(managedConnectionPoolName, 264 "ManagedConnectionPool"); 265 } 266 catch (Exception e) 267 { 268 JMXExceptionDecoder.rethrow(e); 269 } 270 271 poolingStrategy.setConnectionListenerFactory(this); 272 273 String categoryName = poolingStrategy.getManagedConnectionFactory().getClass().getName() + "." + jndiName; 275 Logger log = Logger.getLogger(categoryName); 276 PrintWriter logWriter = new LoggerPluginWriter(log.getLoggerPlugin()); 277 try 278 { 279 poolingStrategy.getManagedConnectionFactory().setLogWriter(logWriter); 280 } 281 catch (ResourceException re) 282 { 283 log.warn("Unable to set log writer '" + logWriter + "' on " + "managed connection factory", re); 284 log.warn("Linked exception:", re.getLinkedException()); 285 } 286 if (poolingStrategy instanceof PreFillPoolSupport) 287 { 288 289 PreFillPoolSupport prefill = (PreFillPoolSupport) poolingStrategy; 290 291 if(prefill.shouldPreFill()){ 292 293 prefill.prefill(); 294 295 } 296 297 } 298 299 } 300 301 protected void stopService() throws Exception 302 { 303 sendNotification(new Notification (STOPPING_NOTIFICATION, getServiceName(), getNextNotificationSequenceNumber())); 305 if (jaasSecurityManagerService != null && securityDomainJndiName != null) 306 server.invoke(jaasSecurityManagerService, "flushAuthenticationCache", new Object [] { securityDomainJndiName }, new String [] { String .class.getName() }); 307 308 poolingStrategy.setConnectionListenerFactory(null); 309 310 poolingStrategy = null; 311 securityDomain = null; 312 ccm = null; 313 } 314 315 324 public ConnectionListener getManagedConnection(Subject subject, ConnectionRequestInfo cri) throws ResourceException 325 { 326 return getManagedConnection(null, subject, cri); 327 } 328 329 338 protected ConnectionListener getManagedConnection(Transaction transaction, Subject subject, ConnectionRequestInfo cri) 339 throws ResourceException 340 { 341 return poolingStrategy.getConnection(transaction, subject, cri); 342 } 343 344 public void returnManagedConnection(ConnectionListener cl, boolean kill) 345 { 346 ManagedConnectionPool localStrategy = cl.getManagedConnectionPool(); 347 if (localStrategy != poolingStrategy) 348 kill = true; 349 350 try 351 { 352 if (kill == false && cl.getState() == ConnectionListener.NORMAL) 353 cl.tidyup(); 354 } 355 catch (Throwable t) 356 { 357 log.warn("Error during tidyup " + cl, t); 358 kill = true; 359 } 360 361 try 362 { 363 localStrategy.returnConnection(cl, kill); 364 } 365 catch (ResourceException re) 366 { 367 if (kill) 371 log.debug("resourceException killing connection (error retrieving from pool?)", re); 372 else 373 log.warn("resourceException returning connection: " + cl.getManagedConnection(), re); 374 } 375 } 376 377 public int getConnectionCount() 378 { 379 return poolingStrategy.getConnectionCount(); 380 } 381 382 public Object allocateConnection(ManagedConnectionFactory mcf, ConnectionRequestInfo cri) throws ResourceException 383 { 384 if (poolingStrategy == null) 385 throw new ResourceException ( 386 "You are trying to use a connection factory that has been shut down: ManagedConnectionFactory is null."); 387 388 if (!poolingStrategy.getManagedConnectionFactory().equals(mcf)) 390 throw new ResourceException ("Wrong ManagedConnectionFactory sent to allocateConnection!"); 391 392 Subject subject = getSubject(); 394 ConnectionListener cl = getManagedConnection(subject, cri); 395 396 reconnectManagedConnection(cl); 398 399 Object connection = null; 401 try 402 { 403 connection = cl.getManagedConnection().getConnection(subject, cri); 404 } 405 catch (Throwable t) 406 { 407 managedConnectionDisconnected(cl); 408 JBossResourceException.rethrowAsResourceException( 409 "Unchecked throwable in ManagedConnection.getConnection() cl=" + cl, t); 410 } 411 412 registerAssociation(cl, connection); 414 if (ccm != null) 415 ccm.registerConnection(this, cl, connection, cri); 416 return connection; 417 } 418 419 421 public void transactionStarted(Collection conns) throws SystemException 422 { 423 } 425 426 public void reconnect(Collection conns, Set unsharableResources) throws ResourceException 427 { 428 if (unsharableResources.contains(jndiName)) 431 { 432 log.trace("reconnect for unshareable connection: nothing to do"); 433 return; 434 } 435 436 Map criToCLMap = new HashMap (); 437 for (Iterator i = conns.iterator(); i.hasNext();) 438 { 439 ConnectionRecord cr = (ConnectionRecord) i.next(); 440 if (cr.cl != null) 441 { 442 log.warn("reconnecting a connection handle that still has a managedConnection! " 444 + cr.cl.getManagedConnection() + " " + cr.connection); 445 } 446 ConnectionListener cl = (ConnectionListener) criToCLMap.get(cr.cri); 447 if (cl == null) 448 { 449 cl = getManagedConnection(getSubject(), cr.cri); 450 criToCLMap.put(cr.cri, cl); 451 reconnectManagedConnection(cl); 453 } 454 455 cl.getManagedConnection().associateConnection(cr.connection); 456 registerAssociation(cl, cr.connection); 457 cr.setConnectionListener(cl); 458 } 459 criToCLMap.clear(); } 461 462 public void disconnect(Collection crs, Set unsharableResources) throws ResourceException 463 { 464 if (unsharableResources.contains(jndiName)) 467 { 468 log.trace("disconnect for unshareable connection: nothing to do"); 469 return; 470 } 471 472 Set cls = new HashSet (); 473 for (Iterator i = crs.iterator(); i.hasNext();) 474 { 475 ConnectionRecord cr = (ConnectionRecord) i.next(); 476 ConnectionListener cl = cr.cl; 477 cr.setConnectionListener(null); 478 unregisterAssociation(cl, cr.connection); 479 if (!cls.contains(cl)) 480 { 481 cls.add(cl); 482 } 483 } 484 for (Iterator i = cls.iterator(); i.hasNext();) 485 disconnectManagedConnection((ConnectionListener) i.next()); 486 } 487 488 490 public MBeanNotificationInfo [] getNotificationInfo() 491 { 492 return super.getNotificationInfo(); 494 } 495 496 498 protected void unregisterAssociation(ConnectionListener cl, Object c) throws ResourceException 502 { 503 cl.unregisterConnection(c); 504 } 505 506 511 protected void reconnectManagedConnection(ConnectionListener cl) throws ResourceException 512 { 513 try 514 { 515 managedConnectionReconnected(cl); 517 } 518 catch (Throwable t) 519 { 520 disconnectManagedConnection(cl); 521 JBossResourceException.rethrowAsResourceException("Unchecked throwable in managedConnectionReconnected() cl=" 522 + cl, t); 523 } 524 } 525 526 531 protected void disconnectManagedConnection(ConnectionListener cl) 532 { 533 try 534 { 535 managedConnectionDisconnected(cl); 536 } 537 catch (Throwable t) 538 { 539 log.warn("Unchecked throwable in managedConnectionDisconnected() cl=" + cl, t); 540 } 541 } 542 543 protected final CachedConnectionManager getCcm() 544 { 545 return ccm; 546 } 547 548 554 protected void managedConnectionReconnected(ConnectionListener cl) throws ResourceException 555 { 556 } 557 558 564 protected void managedConnectionDisconnected(ConnectionListener cl) throws ResourceException 565 { 566 } 567 568 private void registerAssociation(ConnectionListener cl, Object c) throws ResourceException 569 { 570 cl.registerConnection(c); 571 } 572 573 private Subject getSubject() 574 { 575 Subject subject = null; 576 if (securityDomain != null) 577 { 578 583 Principal principal = GetPrincipalAction.getPrincipal(); 584 Object credential = GetCredentialAction.getCredential(); 585 subject = new Subject (); 586 if (securityDomain.isValid(principal, credential, subject) == false) 587 throw new SecurityException ("Invalid authentication attempt, principal=" + principal); 588 } 589 if (trace) 590 log.trace("subject: " + subject); 591 return subject; 592 } 593 594 596 public boolean isTransactional() 597 { 598 return false; 599 } 600 601 public TransactionManager getTransactionManagerInstance() 602 { 603 return null; 604 } 605 606 608 protected abstract class BaseConnectionEventListener implements ConnectionListener 609 { 610 private final ManagedConnection mc; 611 612 private final ManagedConnectionPool mcp; 613 614 private final Object context; 615 616 private int state = NORMAL; 617 618 private final List handles = new LinkedList (); 619 620 private long lastUse; 621 622 private boolean trackByTx = false; 623 624 private boolean permit = false; 625 626 protected Logger log; 627 628 protected boolean trace; 629 630 protected long lastValidated; 631 632 protected BaseConnectionEventListener(ManagedConnection mc, ManagedConnectionPool mcp, Object context, Logger log) 633 { 634 this.mc = mc; 635 this.mcp = mcp; 636 this.context = context; 637 this.log = log; 638 trace = log.isTraceEnabled(); 639 lastUse = System.currentTimeMillis(); 640 } 641 642 public ManagedConnection getManagedConnection() 643 { 644 return mc; 645 } 646 647 public ManagedConnectionPool getManagedConnectionPool() 648 { 649 return mcp; 650 } 651 652 public Object getContext() 653 { 654 return context; 655 } 656 657 public int getState() 658 { 659 return state; 660 } 661 662 public void setState(int newState) 663 { 664 this.state = newState; 665 } 666 667 public boolean isTimedOut(long timeout) 668 { 669 return lastUse < timeout; 670 } 671 672 public void used() 673 { 674 lastUse = System.currentTimeMillis(); 675 } 676 677 public boolean isTrackByTx() 678 { 679 return trackByTx; 680 } 681 682 public void setTrackByTx(boolean trackByTx) 683 { 684 this.trackByTx = trackByTx; 685 } 686 687 public void tidyup() throws ResourceException 688 { 689 } 690 691 public synchronized void registerConnection(Object handle) 692 { 693 handles.add(handle); 694 } 695 696 public synchronized void unregisterConnection(Object handle) 697 { 698 if (!handles.remove(handle)) 699 { 700 log.info("Unregistered handle that was not registered! " + handle + " for managedConnection: " + mc); 701 } 702 if (trace) 703 log.trace("unregisterConnection: " + handles.size() + " handles left"); 704 } 705 706 public synchronized boolean isManagedConnectionFree() 707 { 708 return handles.isEmpty(); 709 } 710 711 protected synchronized void unregisterConnections() 712 { 713 try 714 { 715 for (Iterator i = handles.iterator(); i.hasNext();) 716 { 717 getCcm().unregisterConnection(BaseConnectionManager2.this, i.next()); 718 } 719 } 720 finally 721 { 722 handles.clear(); 723 } 724 } 725 726 public void connectionErrorOccurred(ConnectionEvent ce) 727 { 728 if (state == NORMAL) 729 { 730 if (ce != null) 731 { 732 Throwable t = ce.getException(); 733 if (t == null) 734 t = new Exception ("No exception was reported"); 735 log.warn("Connection error occured: " + this, t); 736 } 737 else 738 { 739 Throwable t = new Exception ("No exception was reported"); 740 log.warn("Unknown Connection error occured: " + this, t); 741 } 742 } 743 try 744 { 745 unregisterConnections(); 746 } 747 catch (Throwable t) 748 { 749 } 751 if (ce != null && ce.getSource() != getManagedConnection()) 752 log.warn("Notified of error on a different managed connection?"); 753 returnManagedConnection(this, true); 754 } 755 756 public void enlist() throws SystemException 757 { 758 } 759 760 public void delist() throws ResourceException 761 { 762 } 763 764 public boolean hasPermit() 765 { 766 return permit; 767 } 768 769 public void grantPermit(boolean value) 770 { 771 this.permit = value; 772 } 773 774 public long getLastValidatedTime() 775 { 776 return this.lastValidated; 777 } 778 779 public void setLastValidatedTime(long lastValidated) 780 { 781 this.lastValidated = lastValidated; 782 } 783 public String toString() 785 { 786 StringBuffer buffer = new StringBuffer (100); 787 buffer.append(getClass().getName()).append('@').append(Integer.toHexString(System.identityHashCode(this))); 788 buffer.append("[state="); 789 if (state == ConnectionListener.NORMAL) 790 buffer.append("NORMAL"); 791 else if (state == ConnectionListener.DESTROY) 792 buffer.append("DESTROY"); 793 else if (state == ConnectionListener.DESTROYED) 794 buffer.append("DESTROYED"); 795 else 796 buffer.append("UNKNOWN?"); 797 buffer.append(" mc=").append(mc); 798 buffer.append(" handles=").append(handles.size()); 799 buffer.append(" lastUse=").append(lastUse); 800 buffer.append(" permit=").append(permit); 801 buffer.append(" trackByTx=").append(trackByTx); 802 buffer.append(" mcp=").append(mcp); 803 buffer.append(" context=").append(context); 804 toString(buffer); 805 buffer.append(']'); 806 return buffer.toString(); 807 } 808 809 protected void toString(StringBuffer buffer) 811 { 812 } 813 } 814 815 public static class ConnectionManagerProxy 816 implements 817 ConnectionManager , 818 Serializable , 819 TransactionTimeoutConfiguration 820 { 821 static final long serialVersionUID = -528322728929261214L; 822 823 private transient BaseConnectionManager2 realCm; 824 825 private final ObjectName cmName; 826 827 ConnectionManagerProxy(final BaseConnectionManager2 realCm, final ObjectName cmName) 828 { 829 this.realCm = realCm; 830 this.cmName = cmName; 831 } 832 833 835 public Object allocateConnection(ManagedConnectionFactory mcf, ConnectionRequestInfo cri) 836 throws ResourceException 837 { 838 return getCM().allocateConnection(mcf, cri); 839 } 840 841 public long getTimeLeftBeforeTransactionTimeout(boolean errorRollback) throws RollbackException 842 { 843 try 844 { 845 return getCM().getTimeLeftBeforeTransactionTimeout(errorRollback); 846 } 847 catch (ResourceException e) 848 { 849 throw new NestedRuntimeException("Unable to retrieve connection manager", e); 850 } 851 } 852 853 public int getTransactionTimeout() throws SystemException 854 { 855 try 856 { 857 return getCM().getTransactionTimeout(); 858 } 859 catch (ResourceException e) 860 { 861 throw new NestedRuntimeException("Unable to retrieve connection manager", e); 862 } 863 } 864 865 private BaseConnectionManager2 getCM() throws ResourceException 866 { 867 if (realCm == null) 868 { 869 try 870 { 871 MBeanServer server = MBeanServerLocator.locateJBoss(); 872 realCm = (BaseConnectionManager2) server.getAttribute(cmName, "Instance"); 873 } 874 catch (Throwable t) 875 { 876 Throwable t2 = JMXExceptionDecoder.decode(t); 877 JBossResourceException.rethrowAsResourceException("Problem locating real ConnectionManager: " + cmName, 878 t2); 879 } 880 } 881 return realCm; 882 } 883 } 884 885 private static class GetPrincipalAction implements PrivilegedAction 886 { 887 static PrivilegedAction ACTION = new GetPrincipalAction(); 888 889 public Object run() 890 { 891 Principal principal = SecurityAssociation.getPrincipal(); 892 return principal; 893 } 894 895 static Principal getPrincipal() 896 { 897 Principal principal = (Principal ) AccessController.doPrivileged(ACTION); 898 return principal; 899 } 900 } 901 902 private static class GetCredentialAction implements PrivilegedAction 903 { 904 static PrivilegedAction ACTION = new GetCredentialAction(); 905 906 public Object run() 907 { 908 Object credential = SecurityAssociation.getCredential(); 909 return credential; 910 } 911 912 static Object getCredential() 913 { 914 Object credential = AccessController.doPrivileged(ACTION); 915 return credential; 916 } 917 } 918 } 919 | Popular Tags |