1 23 24 package org.continuent.sequoia.controller.connection; 25 26 import java.sql.Connection ; 27 import java.sql.SQLException ; 28 import java.util.Hashtable ; 29 import java.util.LinkedList ; 30 31 import org.continuent.sequoia.common.exceptions.UnreachableBackendException; 32 import org.continuent.sequoia.common.i18n.Translate; 33 import org.continuent.sequoia.common.log.Trace; 34 import org.continuent.sequoia.common.xml.DatabasesXmlTags; 35 import org.continuent.sequoia.common.xml.XmlComponent; 36 import org.continuent.sequoia.controller.core.ControllerConstants; 37 import org.continuent.sequoia.controller.requests.AbstractRequest; 38 39 49 public abstract class AbstractConnectionManager 50 implements 51 XmlComponent, 52 Cloneable 53 { 54 63 64 static Trace logger = Trace 65 .getLogger("org.continuent.sequoia.controller.connection"); 66 67 68 protected String backendUrl; 69 70 73 protected String backendName; 74 75 76 protected String rLogin; 77 78 79 protected String rPassword; 80 81 82 protected String driverClassName; 83 84 87 protected String driverPath; 88 89 90 protected boolean initialized; 91 92 96 protected boolean isShutdown; 97 98 99 private transient Hashtable connectionForTransaction; 100 101 105 protected transient Hashtable persistentConnections; 106 107 108 private String vLogin; 109 110 protected String connectionTestStatement; 111 112 115 protected LinkedList persistentConnectionsIdleTime; 116 117 120 protected LinkedList idlePersistentConnections; 121 122 125 protected IdlePersistentConnectionsPingerThread persistentConnectionPingerThread; 126 127 130 protected int idlePersistentConnectionPingInterval; 131 132 135 protected boolean idlePersistentConnectionPingRunning = false; 136 137 140 141 156 protected AbstractConnectionManager(String backendUrl, String backendName, 157 String rLogin, String rPassword, String driverPath, String driverClassName) 158 { 159 if (backendUrl == null) 160 throw new IllegalArgumentException ( 161 "Illegal null database backend URL in AbstractConnectionManager constructor"); 162 163 if (backendName == null) 164 throw new IllegalArgumentException ( 165 "Illegal null database backend name in AbstractConnectionManager constructor"); 166 167 if (rLogin == null) 168 throw new IllegalArgumentException ( 169 "Illegal null database backend login in AbstractConnectionManager constructor"); 170 171 if (rPassword == null) 172 throw new IllegalArgumentException ( 173 "Illegal null database backend password in AbstractConnectionManager constructor"); 174 175 if (driverPath != null) 176 { 177 if (driverClassName == null) 178 { 179 throw new IllegalArgumentException ( 180 "Illegal null database backend driverClassName in AbstractConnectionManager constructor"); 181 } 182 } 183 this.backendUrl = backendUrl; 184 this.backendName = backendName; 185 this.rLogin = rLogin; 186 this.rPassword = rPassword; 187 this.driverPath = driverPath; 188 this.driverClassName = driverClassName; 189 connectionForTransaction = new Hashtable (); 190 persistentConnections = new Hashtable (); 191 192 idlePersistentConnectionPingInterval = ControllerConstants.IDLE_PERSISTENT_CONNECTION_PING_INTERVAL * 1000; 194 if (idlePersistentConnectionPingInterval > 0) 195 { 196 this.idlePersistentConnections = new LinkedList (); 197 this.persistentConnectionsIdleTime = new LinkedList (); 198 } 199 200 } 201 202 208 protected void finalize() throws Throwable 209 { 210 if (isInitialized()) 211 finalizeConnections(); 212 213 if (idlePersistentConnectionPingRunning) 214 { 215 stopPersistentConnectionPingerThread(); 216 synchronized (this) 217 { 218 idlePersistentConnections.clear(); 219 persistentConnectionsIdleTime.clear(); 220 } 221 } 222 223 super.finalize(); 224 } 225 226 229 protected abstract Object clone() throws CloneNotSupportedException ; 230 231 239 public abstract AbstractConnectionManager clone(String rLogin, 240 String rPassword); 241 242 251 public AbstractConnectionManager copy(String url, String name) 252 throws Exception 253 { 254 AbstractConnectionManager connectionManager = (AbstractConnectionManager) this 255 .clone(); 256 connectionManager.backendName = name; 257 connectionManager.backendUrl = url; 258 return connectionManager; 259 } 260 261 264 265 270 public abstract void deleteConnection(PooledConnection connection); 271 272 278 protected void closeConnection(PooledConnection connection) 279 { 280 try 281 { 282 Connection conn = connection.getConnection(); 283 if (!conn.isClosed()) 284 { 285 conn.close(); 286 } 287 } 288 catch (SQLException e) 289 { 290 291 } 292 } 293 294 302 public void deleteConnection(long transactionId) 303 { 304 PooledConnection c = (PooledConnection) connectionForTransaction 306 .remove(new Long (transactionId)); 307 308 if (c == null) 309 logger.error(Translate.get("connection.transaction.unknown", 310 transactionId)); 311 else 312 deleteConnection(c); 313 } 314 315 322 public void deletePersistentConnection(long persistentConnectionId) 323 { 324 Long connectionId = new Long (persistentConnectionId); 325 if (idlePersistentConnectionPingRunning 326 && idlePersistentConnections.contains(persistentConnections 327 .get(connectionId))) 328 { 329 PooledConnection c = (PooledConnection) persistentConnections 330 .get(connectionId); 331 synchronized (this) 332 { 333 persistentConnectionsIdleTime.remove(idlePersistentConnections 334 .indexOf(c)); 335 idlePersistentConnections.remove(c); 336 } 337 } 338 persistentConnections.remove(connectionId); 339 } 340 341 346 public final void finalizeConnections() throws SQLException 347 { 348 connectionForTransaction.clear(); 349 doConnectionFinalization(); 350 } 351 352 358 protected abstract void doConnectionFinalization() throws SQLException ; 359 360 364 public abstract void flagAllConnectionsForRenewal(); 365 366 372 public Connection getConnectionFromDriver() 373 { 374 try 375 { 376 return DriverManager.getConnection(backendUrl, rLogin, rPassword, 377 driverPath, driverClassName); 378 } 379 catch (SQLException ignore) 380 { 381 if (logger.isDebugEnabled()) 382 { 383 logger.debug("failed to get connection for driver ", ignore); 384 } 385 return null; 386 } 387 } 388 389 396 protected abstract PooledConnection getConnection() 397 throws UnreachableBackendException; 398 399 404 protected abstract void releaseConnection(PooledConnection connection); 405 406 415 private PooledConnection getRenewedConnectionInAutoCommit() 416 throws UnreachableBackendException 417 { 418 PooledConnection c; 419 while (true) 420 { c = getConnection(); 422 if (c != null) 423 { 424 if (c.mustBeRenewed()) 425 deleteConnection(c); 426 else 427 break; 428 } 429 else 430 break; 431 } 432 433 return c; 434 } 435 436 450 public PooledConnection getConnectionForTransaction(long transactionId) 451 throws UnreachableBackendException 452 { 453 PooledConnection c = getRenewedConnectionInAutoCommit(); 454 registerConnectionForTransaction(c, transactionId); 455 return c; 456 } 457 458 464 public final void initializeConnections() throws SQLException 465 { 466 isShutdown = false; 467 connectionForTransaction.clear(); 468 doConnectionInitialization(); 469 } 470 471 478 public synchronized void shutdown() 479 { 480 isShutdown = true; 481 notifyAll(); 482 } 483 484 490 protected abstract void doConnectionInitialization() throws SQLException ; 491 492 499 public void registerConnectionForTransaction(PooledConnection c, 500 long transactionId) 501 { 502 if (c != null) 503 { 504 Long lTid = new Long (transactionId); 506 if (connectionForTransaction.put(lTid, c) != null) 507 { 508 logger 509 .error("A new connection for transaction " 510 + lTid 511 + " has been opened but there was a remaining connection for this transaction that has not been closed."); 512 } 513 } 514 } 515 516 525 public PooledConnection retrieveConnectionForTransaction(long transactionId) 526 { 527 Long id = new Long (transactionId); 528 return (PooledConnection) connectionForTransaction.get(id); 530 } 531 532 539 public void releaseConnectionForTransaction(long transactionId) 540 { 541 PooledConnection c = (PooledConnection) connectionForTransaction 543 .remove(new Long (transactionId)); 544 545 if (c == null) 546 logger.error(Translate.get("connection.transaction.unknown", 547 transactionId)); 548 else 549 { 550 if (!c.isDefaultTransactionIsolation()) 551 { try 553 { 554 c.restoreDefaultTransactionIsolation(); 555 } 556 catch (Throwable e) 557 { 558 logger.error("Error while resetting transaction ", e); 559 } 560 } 561 562 if (!persistentConnections.containsValue(c)) 564 releaseConnection(c); 565 } 566 } 567 568 579 public PooledConnection retrieveConnectionInAutoCommit(AbstractRequest request) 580 throws UnreachableBackendException 581 { 582 if ((request != null) && request.isPersistentConnection()) 583 { 584 Long id = new Long (request.getPersistentConnectionId()); 585 PooledConnection c = (PooledConnection) persistentConnections.get(id); 587 if (c == null) 588 { 589 c = getRenewedConnectionInAutoCommit(); 590 if (c != null) 591 persistentConnections.put(id, c); 592 } 593 if (idlePersistentConnectionPingRunning 594 && idlePersistentConnections.contains(c)) 595 { 596 synchronized (this) 597 { 598 persistentConnectionsIdleTime.remove(idlePersistentConnections 599 .indexOf(c)); 600 idlePersistentConnections.remove(c); 601 } 602 } 603 604 return c; 605 } 606 else 607 return getRenewedConnectionInAutoCommit(); 608 } 609 610 619 public void releaseConnectionInAutoCommit(AbstractRequest request, 620 PooledConnection c) 621 { 622 if ((request != null) && request.isPersistentConnection()) 623 { 624 if (idlePersistentConnectionPingRunning) 625 synchronized (this) 626 { 627 persistentConnectionsIdleTime.addLast(new Long (System 628 .currentTimeMillis())); 629 idlePersistentConnections.addLast(c); 630 if (persistentConnectionsIdleTime.size() > 0) 631 notifyPersistentConnectionPingerThread(); 632 } 633 return; 634 } 635 636 try 637 { 638 if (!c.getConnection().getAutoCommit()) 639 { 640 c.getConnection().setAutoCommit(true); 641 if (logger.isDebugEnabled()) 642 { 643 Exception e = new Exception ("Connection returned with autocommit off"); 644 logger.debug(e); 645 } 646 } 647 } 648 catch (SQLException e) 649 { 650 } 652 releaseConnection(c); 653 } 654 655 protected void notifyPersistentConnectionPingerThread() 656 { 657 synchronized (persistentConnectionPingerThread) 658 { 659 persistentConnectionPingerThread.notify(); 660 } 661 } 662 663 671 public void releasePersistentConnectionInAutoCommit( 672 long persistentConnectionId) 673 { 674 PooledConnection c = (PooledConnection) persistentConnections 676 .remove(new Long (persistentConnectionId)); 677 678 if (c == null) 679 logger.error(Translate.get("connection.persistent.id.unknown", 680 persistentConnectionId)); 681 else 682 { 683 if (idlePersistentConnectionPingRunning 684 && idlePersistentConnections.contains(c)) 685 { 686 synchronized (this) 687 { 688 persistentConnectionsIdleTime.remove(idlePersistentConnections 689 .indexOf(c)); 690 idlePersistentConnections.remove(c); 691 } 692 } 693 releaseConnection(c); 694 } 695 } 696 697 702 public boolean isInitialized() 703 { 704 return initialized; 705 } 706 707 710 711 716 public abstract int getCurrentNumberOfConnections(); 717 718 723 public String getDriverClassName() 724 { 725 return driverClassName; 726 } 727 728 733 public String getDriverPath() 734 { 735 return driverPath; 736 } 737 738 743 public String getLogin() 744 { 745 return rLogin; 746 } 747 748 753 public String getPassword() 754 { 755 return rPassword; 756 } 757 758 761 762 765 public String getVLogin() 766 { 767 return vLogin; 768 } 769 770 773 public void setVLogin(String login) 774 { 775 vLogin = login; 776 } 777 778 784 public void setConnectionTestStatement(String connectionTestStatement) 785 { 786 this.connectionTestStatement = connectionTestStatement; 787 } 788 789 794 protected abstract String getXmlImpl(); 795 796 799 public String getXml() 800 { 801 StringBuffer info = new StringBuffer (); 802 info.append("<" + DatabasesXmlTags.ELT_ConnectionManager + " " 803 + DatabasesXmlTags.ATT_vLogin + "=\"" + vLogin + "\" " + "" 804 + DatabasesXmlTags.ATT_rLogin + "=\"" + rLogin + "\" " + "" 805 + DatabasesXmlTags.ATT_rPassword + "=\"" + rPassword + "\" " + ">"); 806 info.append(this.getXmlImpl()); 807 info.append("</" + DatabasesXmlTags.ELT_ConnectionManager + ">"); 808 return info.toString(); 809 } 810 811 protected void stopPersistentConnectionPingerThread() 812 { 813 synchronized (persistentConnectionPingerThread) 814 { 815 persistentConnectionPingerThread.isKilled = true; 816 idlePersistentConnectionPingRunning = false; 817 persistentConnectionPingerThread.notify(); 818 } 819 try 820 { 821 persistentConnectionPingerThread.join(); 822 } 823 catch (InterruptedException e) 824 { 825 } 826 } 827 828 832 class IdlePersistentConnectionsPingerThread extends Thread 833 { 834 private boolean isKilled = false; 835 private AbstractConnectionManager thisPool; 836 837 protected IdlePersistentConnectionsPingerThread(String pBackendName, 838 AbstractConnectionManager thisPool) 839 { 840 super("IdlePersistentConnectionsPingerThread for backend:" + pBackendName); 841 this.thisPool = thisPool; 842 } 843 844 847 public void run() 848 { 849 long idleTime, releaseTime; 850 synchronized (this) 851 { 852 try 853 { 854 while (!isKilled) 855 { 856 if (idlePersistentConnections.isEmpty()) 857 { 858 this.wait(); 859 } 860 861 if (isKilled) 862 continue; 864 PooledConnection c = null; 865 866 if (persistentConnectionsIdleTime.isEmpty()) 867 { 868 continue; } 870 releaseTime = ((Long ) persistentConnectionsIdleTime.getFirst()) 871 .longValue(); 872 idleTime = System.currentTimeMillis() - releaseTime; 873 874 if (idleTime >= idlePersistentConnectionPingInterval) 875 { 876 synchronized (thisPool) 877 { 878 c = (PooledConnection) idlePersistentConnections.removeFirst(); 879 persistentConnectionsIdleTime.removeFirst(); 880 } 881 } 882 883 if (c == null) 884 { wait(idlePersistentConnectionPingInterval - idleTime); 886 } 887 else 888 { 889 try 890 { 891 c.getConnection().createStatement().execute( 893 connectionTestStatement); 894 synchronized (thisPool) 896 { 897 persistentConnectionsIdleTime.addLast(new Long (System 898 .currentTimeMillis())); 899 idlePersistentConnections.addLast(c); 900 } 901 } 902 catch (SQLException e) 903 { 904 try 906 { 907 c.getConnection().close(); 908 } 909 catch (SQLException e1) 910 { 911 String msg = "An error occured while closing idle connection after the timeout: " 912 + e; 913 logger.error(msg); 914 } 915 } 916 } 917 } 918 } 919 catch (InterruptedException e) 920 { 921 logger 922 .error("Wait on IdlePersistentConnectionsPingerThread interrupted in ConnectionManager: " 923 + e); 924 } 925 } 926 } 927 } 928 } | Popular Tags |