1 25 26 package org.objectweb.easybeans.component.jdbcpool; 27 28 import java.io.PrintWriter ; 29 import java.io.Serializable ; 30 import java.sql.Connection ; 31 import java.sql.DriverManager ; 32 import java.sql.SQLException ; 33 import java.util.HashMap ; 34 import java.util.Iterator ; 35 import java.util.LinkedList ; 36 import java.util.Map ; 37 import java.util.TreeSet ; 38 39 import javax.naming.NamingException ; 40 import javax.naming.Reference ; 41 import javax.naming.Referenceable ; 42 import javax.naming.StringRefAddr ; 43 import javax.sql.ConnectionEvent ; 44 import javax.sql.ConnectionEventListener ; 45 import javax.sql.DataSource ; 46 import javax.sql.XAConnection ; 47 import javax.sql.XADataSource ; 48 import javax.transaction.RollbackException ; 49 import javax.transaction.SystemException ; 50 import javax.transaction.Transaction ; 51 import javax.transaction.TransactionManager ; 52 import javax.transaction.xa.XAResource ; 53 54 import org.objectweb.easybeans.log.JLog; 55 import org.objectweb.easybeans.log.JLogFactory; 56 57 62 public class ConnectionManager implements DataSource , XADataSource , Referenceable , Serializable , ConnectionEventListener { 63 64 67 private static final long serialVersionUID = -7159546694962248547L; 68 69 72 private JLog logger = JLogFactory.getLog(ConnectionManager.class); 73 74 77 private static final long MILLI = 1000L; 78 79 82 private static final long ONE_MIN_MILLI = 60L * MILLI; 83 84 87 private static final int DEFAULT_TIMEOUT = 60; 88 89 92 private static final long WAITER_TIMEOUT = 10 * MILLI; 93 94 97 private static final int DEFAULT_MAX_WAITERS = 1000; 98 99 102 private static final int DEFAULT_PSTMT = 12; 103 104 107 private static final int DEFAULT_SAMPLING = 60; 108 109 110 113 private static Map <String , ConnectionManager> cmList = new HashMap <String , ConnectionManager>(); 114 115 118 private TransactionManager tm = null; 119 120 125 private TreeSet <JManagedConnection> freeList = new TreeSet <JManagedConnection>(); 126 127 130 private LinkedList <JManagedConnection> mcList = new LinkedList <JManagedConnection>(); 131 132 136 private Map <Transaction , JManagedConnection> tx2mc = new HashMap <Transaction , JManagedConnection>(); 137 138 141 private int loginTimeout = DEFAULT_TIMEOUT; 142 143 146 private PrintWriter log = null; 147 148 151 public ConnectionManager() { 152 153 } 154 155 160 public static ConnectionManager getConnectionManager(final String dsname) { 161 ConnectionManager cm = cmList.get(dsname); 162 return cm; 163 } 164 165 168 private String dSName = null; 169 170 173 public String getDSName() { 174 return dSName; 175 } 176 177 180 public void setDSName(final String s) { 181 dSName = s; 182 cmList.put(s, this); 184 } 185 186 189 private String dataSourceName; 190 191 195 public String getDatasourceName() { 196 return dataSourceName; 197 } 198 199 203 public void setDatasourceName(final String dataSourceName) { 204 this.dataSourceName = dataSourceName; 205 } 206 207 210 private String url = null; 211 212 215 public String getUrl() { 216 return url; 217 } 218 219 223 public void setUrl(final String url) { 224 this.url = url; 225 } 226 227 230 private String className = null; 231 232 235 public String getClassName() { 236 return className; 237 } 238 239 244 public void setClassName(final String className) throws ClassNotFoundException { 245 this.className = className; 246 247 logger.debug("Load JDBC driver {0}", className); 249 try { 250 Class.forName(className); 251 } catch (java.lang.ClassNotFoundException e) { 252 logger.error("Cannot load JDBC driver", e); 253 throw e; 254 } 255 } 256 257 260 private String userName = null; 261 262 265 public String getUserName() { 266 return userName; 267 } 268 269 273 public void setUserName(final String userName) { 274 this.userName = userName; 275 } 276 277 280 private String password = null; 281 282 285 public String getPassword() { 286 return password; 287 } 288 289 293 public void setPassword(final String password) { 294 this.password = password; 295 } 296 297 300 private int isolationLevel = -1; 301 302 305 private String isolationStr = null; 306 307 311 public void setTransactionIsolation(final String level) { 312 if (level.equals("serializable")) { 313 isolationLevel = Connection.TRANSACTION_SERIALIZABLE; 314 } else if (level.equals("none")) { 315 isolationLevel = Connection.TRANSACTION_NONE; 316 } else if (level.equals("read_committed")) { 317 isolationLevel = Connection.TRANSACTION_READ_COMMITTED; 318 } else if (level.equals("read_uncommitted")) { 319 isolationLevel = Connection.TRANSACTION_READ_UNCOMMITTED; 320 } else if (level.equals("repeatable_read")) { 321 isolationLevel = Connection.TRANSACTION_REPEATABLE_READ; 322 } else { 323 isolationStr = "default"; 324 return; 325 } 326 isolationStr = level; 327 } 328 329 333 public String getTransactionIsolation() { 334 return isolationStr; 335 } 336 337 340 private int waiterCount = 0; 341 342 345 private long waitingTime = 0; 346 347 350 private int busyMax = 0; 351 352 355 private int busyMin = 0; 356 357 360 private static final int NO_LIMIT = 99999; 361 362 365 private static final long ONE_DAY = 1440L * 60L * 1000L; 366 367 371 private static final int MAX_REMOVE_FREELIST = 10; 372 373 376 private int poolMin = 0; 377 378 381 public int getPoolMin() { 382 return poolMin; 383 } 384 385 388 public synchronized void setPoolMin(final int min) { 389 if (poolMin != min) { 390 poolMin = min; 391 adjust(); 392 } 393 } 394 395 398 private int poolMax = NO_LIMIT; 399 400 403 public int getPoolMax() { 404 return poolMax; 405 } 406 407 410 public synchronized void setPoolMax(final int max) { 411 if (poolMax != max) { 412 if (max < 0 || max > NO_LIMIT) { 413 if (currentWaiters > 0) { 414 notify(); 415 } 416 poolMax = NO_LIMIT; 417 } else { 418 if (currentWaiters > 0 && poolMax < max) { 419 notify(); 420 } 421 poolMax = max; 422 adjust(); 423 } 424 } 425 } 426 427 432 private long maxAge = ONE_DAY; 433 434 437 private int maxAgeMn; 438 439 442 public int getMaxAge() { 443 return maxAgeMn; 444 } 445 446 449 public long getMaxAgeMilli() { 450 return maxAge; 451 } 452 453 456 public void setMaxAge(final int mn) { 457 maxAgeMn = mn; 458 maxAge = mn * ONE_MIN_MILLI; 460 } 461 462 465 private long maxOpenTime = ONE_DAY; 466 467 470 private int maxOpenTimeMn; 471 472 475 public int getMaxOpenTime() { 476 return maxOpenTimeMn; 477 } 478 479 482 public long getMaxOpenTimeMilli() { 483 return maxOpenTime; 484 } 485 486 489 public void setMaxOpenTime(final int mn) { 490 maxOpenTimeMn = mn; 491 maxOpenTime = mn * ONE_MIN_MILLI; 493 } 494 495 498 private long waiterTimeout = WAITER_TIMEOUT; 499 500 503 public int getMaxWaitTime() { 504 return (int) (waiterTimeout / MILLI); 505 } 506 507 510 public void setMaxWaitTime(final int sec) { 511 waiterTimeout = sec * MILLI; 512 } 513 514 517 private int maxWaiters = DEFAULT_MAX_WAITERS; 518 519 522 public int getMaxWaiters() { 523 return maxWaiters; 524 } 525 526 529 public void setMaxWaiters(final int nb) { 530 maxWaiters = nb; 531 } 532 533 536 private int samplingPeriod = DEFAULT_SAMPLING; 538 541 public int getSamplingPeriod() { 542 return samplingPeriod; 543 } 544 545 548 public void setSamplingPeriod(final int sec) { 549 if (sec > 0) { 550 samplingPeriod = sec; 551 } 552 } 553 554 560 private int checkLevel = 0; 562 565 public int getCheckLevel() { 566 return checkLevel; 567 } 568 569 572 public void setCheckLevel(final int level) { 573 checkLevel = level; 574 } 575 576 579 private int pstmtMax = DEFAULT_PSTMT; 580 581 584 public int getPstmtMax() { 585 return pstmtMax; 586 } 587 588 591 public void setPstmtMax(final int nb) { 592 pstmtMax = nb; 593 for (Iterator i = mcList.iterator(); i.hasNext();) { 595 JManagedConnection mc = (JManagedConnection) i.next(); 596 mc.setPstmtMax(pstmtMax); 597 } 598 } 599 600 603 private String testStatement; 604 605 608 public String getTestStatement() { 609 return testStatement; 610 } 611 612 615 public void setTestStatement(final String s) { 616 testStatement = s; 617 } 618 619 633 @SuppressWarnings ("boxing") 634 public void poolConfigure(final String connchecklevel, final String connmaxage, final String maxopentime, 635 final String connteststmt, final String pstmtmax, final String minconpool, final String maxconpool, 636 final String maxwaittime, final String maxwaiters, final String samplingperiod) { 637 638 setCheckLevel((new Integer (connchecklevel)).intValue()); 640 setMaxAge((new Integer (connmaxage)).intValue()); 642 setMaxOpenTime((new Integer (maxopentime)).intValue()); 643 setTestStatement(connteststmt); 644 setPstmtMax((new Integer (pstmtmax)).intValue()); 645 setPoolMin((new Integer (minconpool)).intValue()); 646 setPoolMax((new Integer (maxconpool)).intValue()); 647 setMaxWaitTime((new Integer (maxwaittime)).intValue()); 648 setMaxWaiters((new Integer (maxwaiters)).intValue()); 649 setSamplingPeriod((new Integer (samplingperiod)).intValue()); 650 if (logger.isDebugEnabled()) { 651 logger.debug("ConnectionManager configured with:"); 652 logger.debug(" jdbcConnCheckLevel = {0}", connchecklevel); 653 logger.debug(" jdbcConnMaxAge = {0}", connmaxage); 654 logger.debug(" jdbcMaxOpenTime = {0}", maxopentime); 655 logger.debug(" jdbcTestStmt = {0}", connteststmt); 656 logger.debug(" jdbcPstmtMax = {0}", pstmtmax); 657 logger.debug(" minConPool = {0}", getPoolMin()); 658 logger.debug(" maxConPool = {0}", getPoolMax()); 659 logger.debug(" maxWaitTime = {0}", getMaxWaitTime()); 660 logger.debug(" maxWaiters = {0}", getMaxWaiters()); 661 logger.debug(" samplingPeriod = {0}", getSamplingPeriod()); 662 } 663 } 664 665 668 private int busyMaxRecent = 0; 669 670 673 public int getBusyMaxRecent() { 674 return busyMaxRecent; 675 } 676 677 680 private int busyMinRecent = 0; 681 682 685 public int getBusyMinRecent() { 686 return busyMinRecent; 687 } 688 689 692 private int currentWaiters = 0; 693 694 697 public int getCurrentWaiters() { 698 return currentWaiters; 699 } 700 701 705 private int openedCount = 0; 706 707 710 public int getOpenedCount() { 711 return openedCount; 712 } 713 714 717 private int connectionFailures = 0; 718 719 722 public int getConnectionFailures() { 723 return connectionFailures; 724 } 725 726 730 private int connectionLeaks = 0; 731 732 735 public int getConnectionLeaks() { 736 return connectionLeaks; 737 } 738 739 742 private int servedOpen = 0; 743 744 747 public int getServedOpen() { 748 return servedOpen; 749 } 750 751 754 private int rejectedFull = 0; 755 756 760 public int getRejectedFull() { 761 return rejectedFull; 762 } 763 764 767 private int rejectedTimeout = 0; 768 769 772 public int getRejectedTimeout() { 773 return rejectedTimeout; 774 } 775 776 779 private int rejectedOther = 0; 780 781 784 public int getRejectedOther() { 785 return rejectedOther; 786 } 787 788 791 public int getRejectedOpen() { 792 return rejectedFull + rejectedTimeout + rejectedOther; 793 } 794 795 798 private int waitersHigh = 0; 799 800 803 public int getWaitersHigh() { 804 return waitersHigh; 805 } 806 807 810 private int waitersHighRecent = 0; 811 812 815 public int getWaitersHighRecent() { 816 return waitersHighRecent; 817 } 818 819 822 private int totalWaiterCount = 0; 823 824 827 public int getWaiterCount() { 828 return totalWaiterCount; 829 } 830 831 834 private long totalWaitingTime = 0; 835 836 839 public long getWaitingTime() { 840 return totalWaitingTime; 841 } 842 843 846 private long waitingHigh = 0; 847 848 851 public long getWaitingHigh() { 852 return waitingHigh; 853 } 854 855 858 private long waitingHighRecent = 0; 859 860 863 public long getWaitingHighRecent() { 864 return waitingHighRecent; 865 } 866 867 870 public int getLoginTimeout() throws SQLException { 871 return loginTimeout; 872 } 873 874 877 public void setLoginTimeout(final int seconds) throws SQLException { 878 loginTimeout = seconds; 879 } 880 881 884 public PrintWriter getLogWriter() throws SQLException { 885 return log; 886 } 887 888 891 public void setLogWriter(final PrintWriter out) throws SQLException { 892 log = out; 893 } 894 895 898 public Connection getConnection() throws SQLException { 899 return getConnection(userName, password); 900 } 901 902 912 public Connection getConnection(final String username, final String password) throws SQLException { 913 JManagedConnection mc = null; 914 915 Transaction tx = null; 917 try { 918 tx = tm.getTransaction(); 919 } catch (NullPointerException n) { 920 logger.error("ConnectionManager: should not be used outside a EasyBeans Server"); 922 } catch (SystemException e) { 923 logger.error("ConnectionManager: getTransaction failed", e); 924 } 925 logger.debug("Tx = {0}", tx); 926 927 mc = openConnection(username, tx); 929 Connection ret = mc.getConnection(); 930 931 if (tx != null) { 933 if (mc.getOpenCount() == 1) { try { 935 logger.debug("enlist XAResource on {0}", tx); 936 tx.enlistResource(mc.getXAResource()); 937 ret.setAutoCommit(false); 938 } catch (RollbackException e) { 939 logger.warn("XAResource enlisted, but tx is marked rollback", e); 942 } catch (IllegalStateException e) { 943 ret.setAutoCommit(true); 945 } catch (Exception e) { 946 logger.error("Cannot enlist XAResource", e); 947 logger.error("Connection will not be enlisted in a transaction"); 948 throw new SQLException ("Cannot enlist XAResource"); 950 } 951 } 952 } else { 953 ret.setAutoCommit(true); } 955 956 return ret; 958 } 959 960 969 public XAConnection getXAConnection() throws SQLException { 970 return getXAConnection(userName, password); 971 } 972 973 985 @SuppressWarnings ("boxing") 986 public XAConnection getXAConnection(final String user, final String passwd) throws SQLException { 987 Connection conn = null; 989 try { 990 if (user.length() == 0) { 991 conn = DriverManager.getConnection(url); 992 logger.debug(" * New Connection on {0}", url); 993 } else { 994 conn = DriverManager.getConnection(url, user, passwd); 996 logger.debug(" * New Connection on {0} for user {1}", url, user); 997 } 998 } catch (SQLException e) { 999 logger.error("Could not get Connection on {0}", url, e); 1000 throw new SQLException ("Could not get Connection on url : " + url + " for user : " + user + " inner exception" 1001 + e.getMessage()); 1002 } 1003 1004 if (isolationLevel != -1) { 1007 try { 1008 logger.debug("set transaction isolation to {0}", isolationLevel); 1009 conn.setTransactionIsolation(isolationLevel); 1010 } catch (SQLException e) { 1011 String ilstr = "?"; 1012 switch (isolationLevel) { 1013 case Connection.TRANSACTION_SERIALIZABLE: 1014 ilstr = "SERIALIZABLE"; 1015 break; 1016 case Connection.TRANSACTION_NONE: 1017 ilstr = "NONE"; 1018 break; 1019 case Connection.TRANSACTION_READ_COMMITTED: 1020 ilstr = "READ_COMMITTED"; 1021 break; 1022 case Connection.TRANSACTION_READ_UNCOMMITTED: 1023 ilstr = "READ_UNCOMMITTED"; 1024 break; 1025 case Connection.TRANSACTION_REPEATABLE_READ: 1026 ilstr = "REPEATABLE_READ"; 1027 break; 1028 default: 1029 throw new SQLException ("Invalid isolation level '" + ilstr + "'."); 1030 } 1031 logger.error("Cannot set transaction isolation to {0} for this DataSource url {1}", ilstr, url, e); 1032 isolationLevel = -1; 1033 } 1034 } 1035 1036 JManagedConnection mc = new JManagedConnection(conn, this); 1038 1039 return mc; 1041 } 1042 1043 1047 1054 public Reference getReference() throws NamingException { 1055 1056 Reference ref = new Reference (this.getClass().getName(), DataSourceFactory.class.getName(), null); 1057 ref.add(new StringRefAddr ("datasource.name", getDSName())); 1059 ref.add(new StringRefAddr ("datasource.url", getUrl())); 1060 ref.add(new StringRefAddr ("datasource.classname", getClassName())); 1061 ref.add(new StringRefAddr ("datasource.username", getUserName())); 1062 ref.add(new StringRefAddr ("datasource.password", getPassword())); 1063 ref.add(new StringRefAddr ("datasource.isolationlevel", getTransactionIsolation())); 1064 Integer checklevel = new Integer (getCheckLevel()); 1065 ref.add(new StringRefAddr ("connchecklevel", checklevel.toString())); 1066 Integer maxage = new Integer (getMaxAge()); 1067 ref.add(new StringRefAddr ("connmaxage", maxage.toString())); 1068 Integer maxopentime = new Integer (getMaxOpenTime()); 1069 ref.add(new StringRefAddr ("maxopentime", maxopentime.toString())); 1070 ref.add(new StringRefAddr ("connteststmt", getTestStatement())); 1071 Integer pstmtmax = new Integer (getPstmtMax()); 1072 ref.add(new StringRefAddr ("pstmtmax", pstmtmax.toString())); 1073 Integer minpool = new Integer (getPoolMin()); 1074 ref.add(new StringRefAddr ("minconpool", minpool.toString())); 1075 Integer maxpool = new Integer (getPoolMax()); 1076 ref.add(new StringRefAddr ("maxconpool", maxpool.toString())); 1077 Integer maxwaittime = new Integer (getMaxWaitTime()); 1078 ref.add(new StringRefAddr ("maxwaittime", maxwaittime.toString())); 1079 Integer maxwaiters = new Integer (getMaxWaiters()); 1080 ref.add(new StringRefAddr ("maxwaiters", maxwaiters.toString())); 1081 Integer samplingperiod = new Integer (getSamplingPeriod()); 1082 ref.add(new StringRefAddr ("samplingperiod", samplingperiod.toString())); 1083 return ref; 1084 } 1085 1086 1094 public void connectionClosed(final ConnectionEvent event) { 1095 JManagedConnection mc = (JManagedConnection) event.getSource(); 1096 closeConnection(mc, XAResource.TMSUCCESS); 1097 } 1098 1099 1110 @SuppressWarnings ("boxing") 1111 public void connectionErrorOccurred(final ConnectionEvent event) { 1112 1113 JManagedConnection mc = (JManagedConnection) event.getSource(); 1114 logger.debug("mc= {0}", mc.getIdentifier()); 1115 1116 closeConnection(mc, XAResource.TMFAIL); 1119 } 1120 1121 1124 public int getCurrentOpened() { 1125 return mcList.size(); 1126 } 1127 1128 1131 public int getCurrentBusy() { 1132 return mcList.size() - freeList.size(); 1133 } 1134 1135 1138 public void recomputeBusy() { 1139 int busy = getCurrentBusy(); 1140 if (busyMax < busy) { 1141 busyMax = busy; 1142 } 1143 if (busyMin > busy) { 1144 busyMin = busy; 1145 } 1146 } 1147 1148 1151 public int getCurrentInTx() { 1152 return tx2mc.size(); 1153 } 1154 1155 1158 public synchronized void sampling() { 1159 waitingHighRecent = waitingTime; 1160 if (waitingHigh < waitingTime) { 1161 waitingHigh = waitingTime; 1162 } 1163 waitingTime = 0; 1164 1165 waitersHighRecent = waiterCount; 1166 if (waitersHigh < waiterCount) { 1167 waitersHigh = waiterCount; 1168 } 1169 waiterCount = 0; 1170 1171 busyMaxRecent = busyMax; 1172 busyMax = getCurrentBusy(); 1173 busyMinRecent = busyMin; 1174 busyMin = getCurrentBusy(); 1175 } 1176 1177 1181 @SuppressWarnings ("boxing") 1182 public synchronized void adjust() { 1183 logger.debug(dSName); 1184 1185 int count = mcList.size() - poolMin; 1189 if (count >= 0) { 1192 if (count > MAX_REMOVE_FREELIST) { 1193 count = MAX_REMOVE_FREELIST; 1194 } 1195 for (Iterator i = freeList.iterator(); i.hasNext();) { 1196 JManagedConnection mc = (JManagedConnection) i.next(); 1197 if (mc.isAged()) { 1198 logger.debug("remove a timed out connection"); 1199 i.remove(); 1200 destroyItem(mc); 1201 count--; 1202 if (count <= 0) { 1203 break; 1204 } 1205 } 1206 } 1207 } 1208 recomputeBusy(); 1209 1210 for (Iterator i = mcList.iterator(); i.hasNext();) { 1212 JManagedConnection mc = (JManagedConnection) i.next(); 1213 if (mc.inactive()) { 1214 if (logger.isWarnEnabled()) { 1215 logger.warn("close a timed out open connection {0}", mc.getIdentifier()); 1216 } 1217 i.remove(); 1218 mc.remove(); 1220 connectionLeaks++; 1221 if (currentWaiters > 0) { 1223 notify(); 1224 } 1225 } 1226 } 1227 1228 if (poolMax != NO_LIMIT) { 1231 while (freeList.size() > poolMin && mcList.size() > poolMax) { 1232 JManagedConnection mc = freeList.first(); 1233 freeList.remove(mc); 1234 destroyItem(mc); 1235 } 1236 } 1237 recomputeBusy(); 1238 1239 while (mcList.size() < poolMin) { 1241 JManagedConnection mc = null; 1242 try { 1243 mc = (JManagedConnection) getXAConnection(); 1244 openedCount++; 1245 } catch (SQLException e) { 1246 throw new IllegalStateException ("Could not create " + poolMin + " mcs in the pool : ", e); 1247 } 1248 freeList.add(mc); 1250 mcList.add(mc); 1251 mc.addConnectionEventListener(this); 1252 } 1253 } 1254 1255 1263 @SuppressWarnings ("boxing") 1264 public synchronized JManagedConnection openConnection(final String user, final Transaction tx) throws SQLException { 1265 JManagedConnection mc = null; 1266 if (tx != null) { 1269 mc = tx2mc.get(tx); 1270 if (mc != null) { 1271 logger.debug("Reuse a Connection for same tx"); 1272 mc.hold(); 1273 servedOpen++; 1274 return mc; 1275 } 1276 } 1277 long timetowait = waiterTimeout; 1279 long starttime = 0; 1280 while (mc == null) { 1281 if (freeList.isEmpty()) { 1283 if (mcList.size() >= poolMax) { 1286 boolean stoplooping = true; 1287 if (timetowait > 0) { 1290 if (currentWaiters < maxWaiters) { 1291 currentWaiters++; 1292 if (waiterCount < currentWaiters) { 1294 waiterCount = currentWaiters; 1295 } 1296 if (starttime == 0) { 1297 starttime = System.currentTimeMillis(); 1298 logger.debug("Wait for a free Connection, {0}", mcList.size()); 1299 } 1300 try { 1301 wait(timetowait); 1302 } catch (InterruptedException ign) { 1303 logger.warn("Interrupted"); 1304 } finally { 1305 currentWaiters--; 1306 } 1307 long stoptime = System.currentTimeMillis(); 1308 long stillwaited = stoptime - starttime; 1309 timetowait = waiterTimeout - stillwaited; 1310 stoplooping = (timetowait <= 0); 1311 if (stoplooping) { 1312 totalWaiterCount++; 1314 totalWaitingTime += stillwaited; 1315 if (waitingTime < stillwaited) { 1316 waitingTime = stillwaited; 1317 } 1318 } else { 1319 if (!freeList.isEmpty() || mcList.size() < poolMax) { 1320 logger.debug("Notified after {0}", stillwaited); 1323 totalWaiterCount++; 1324 totalWaitingTime += stillwaited; 1325 if (waitingTime < stillwaited) { 1326 waitingTime = stillwaited; 1327 } 1328 } 1329 continue; 1330 } 1331 } 1332 } 1333 if (stoplooping && freeList.isEmpty() && mcList.size() >= poolMax) { 1334 if (starttime > 0) { 1335 rejectedTimeout++; 1336 logger.warn("Cannot create a Connection - timeout"); 1337 } else { 1338 rejectedFull++; 1339 logger.warn("Cannot create a Connection"); 1340 } 1341 throw new SQLException ("No more connections in " + getDatasourceName()); 1342 } 1343 continue; 1344 } 1345 logger.debug("empty free list: Create a new Connection"); 1346 try { 1347 mc = (JManagedConnection) getXAConnection(); 1349 openedCount++; 1350 } catch (SQLException e) { 1351 connectionFailures++; 1352 rejectedOther++; 1353 logger.warn("Cannot create new Connection for tx", e); 1354 throw e; 1355 } 1356 mc.addConnectionEventListener(this); 1358 mcList.add(mc); 1359 } else { 1360 mc = freeList.last(); 1361 freeList.remove(mc); 1362 if (checkLevel > 0) { 1364 try { 1365 JConnection conn = (JConnection) mc.getConnection(); 1366 if (conn.isPhysicallyClosed()) { 1367 logger.warn("The JDBC connection has been closed!"); 1368 destroyItem(mc); 1369 starttime = 0; 1370 mc = null; 1371 continue; 1372 } 1373 if (checkLevel > 1) { 1374 java.sql.Statement stmt = conn.createStatement(); 1375 stmt.execute(testStatement); 1376 stmt.close(); 1377 } 1378 } catch (Exception e) { 1379 logger.error("DataSource " + getDatasourceName() + " error: removing invalid mc", e); 1380 destroyItem(mc); 1381 starttime = 0; 1382 mc = null; 1383 continue; 1384 } 1385 } 1386 } 1387 } 1388 recomputeBusy(); 1389 mc.setTx(tx); 1390 if (tx == null) { 1391 logger.debug("Got a Connection - no TX: "); 1392 } else { 1393 logger.debug("Got a Connection for TX: "); 1394 try { 1396 tx.registerSynchronization(mc); 1397 tx2mc.put(tx, mc); } catch (javax.transaction.RollbackException e) { 1399 logger.warn("DataSource " + getDatasourceName() + " error: Pool mc registered, but tx is rollback only", e); 1401 } catch (javax.transaction.SystemException e) { 1402 logger.error("DataSource " + getDatasourceName() + " error in pool: system exception from transaction manager ", 1403 e); 1404 } catch (IllegalStateException e) { 1405 logger.warn("Got a Connection - committed TX: ", e); 1407 mc.setTx(null); 1408 } 1409 } 1410 mc.hold(); 1411 servedOpen++; 1412 return mc; 1413 } 1414 1415 1420 public synchronized void freeConnections(final Transaction tx) { 1421 logger.debug("free connection for Tx = " + tx); 1422 JManagedConnection mc = tx2mc.remove(tx); 1423 if (mc == null) { 1424 logger.error("pool: no connection found to free for Tx = " + tx); 1425 return; 1426 } 1427 mc.setTx(null); 1428 if (mc.isOpen()) { 1429 logger.debug("Connection not closed by caller"); 1431 return; 1432 } 1433 freeItem(mc); 1434 } 1435 1436 1439 public synchronized void closeAllConnection() { 1440 Iterator it = mcList.iterator(); 1442 try { 1443 while (it.hasNext()) { 1444 JManagedConnection mc = (JManagedConnection) it.next(); 1445 mc.close(); 1446 } 1447 } catch (java.sql.SQLException e) { 1448 logger.error("Error while closing a Connection:", e); 1449 } 1450 } 1451 1452 1456 1463 private boolean closeConnection(final JManagedConnection mc, final int flag) { 1464 if (!mc.release()) { 1468 return false; 1469 } 1470 if (mc.getTx() != null) { 1471 logger.debug("keep connection for same tx"); 1472 } else { 1473 freeItem(mc); 1474 } 1475 1476 Transaction tx = null; 1478 try { 1479 tx = tm.getTransaction(); 1480 } catch (NullPointerException n) { 1481 logger.error("Pool: should not be used outside a EasyBeans Server", n); 1483 } catch (SystemException e) { 1484 logger.error("Pool: getTransaction failed:", e); 1485 } 1486 if (tx != null && mc.isClosed()) { 1487 try { 1488 tx.delistResource(mc.getXAResource(), flag); 1489 } catch (Exception e) { 1490 logger.error("Pool: Exception while delisting resource:", e); 1491 } 1492 } 1493 return true; 1494 } 1495 1496 1500 @SuppressWarnings ("boxing") 1501 private synchronized void freeItem(final JManagedConnection item) { 1502 freeList.add(item); 1507 if (logger.isDebugEnabled()) { 1508 logger.debug("item added to freeList: " + item.getIdentifier()); 1509 } 1510 1511 if (currentWaiters > 0) { 1513 notify(); 1514 } 1515 recomputeBusy(); 1516 } 1517 1518 1522 private synchronized void destroyItem(final JManagedConnection mc) { 1523 mcList.remove(mc); 1524 mc.remove(); 1525 if (currentWaiters > 0) { 1527 notify(); 1528 } 1529 recomputeBusy(); 1530 } 1531 1532 1540 public String checkConnection(final String testStatement) throws SQLException { 1541 String noError = testStatement; 1542 JManagedConnection mc = null; 1543 boolean jmcCreated = false; 1544 if (!freeList.isEmpty()) { 1545 Iterator it = freeList.iterator(); 1547 while (it.hasNext()) { 1548 mc = (JManagedConnection) it.next(); 1549 try { 1550 JConnection conn = (JConnection) mc.getConnection(); 1551 if (!conn.isPhysicallyClosed()) { 1552 logger.debug("Use a free JManagedConnection to test with " + testStatement); 1554 break; 1555 } 1556 mc = null; 1557 } catch (SQLException e) { 1558 mc = null; 1560 } 1561 } 1562 } 1563 if (mc == null) { 1564 logger.debug("Create a JManagedConnection to test with " + testStatement); 1566 Connection conn = null; 1567 try { 1568 conn = DriverManager.getConnection(url, userName, password); 1569 } catch (SQLException e) { 1570 logger.error("Could not get Connection on " + url + ":", e); 1571 } 1572 mc = new JManagedConnection(conn, this); 1573 jmcCreated = true; 1574 } 1575 if (mc != null) { 1576 JConnection conn = (JConnection) mc.getConnection(); 1578 java.sql.Statement stmt = conn.createStatement(); 1579 try { 1580 stmt.execute(testStatement); 1581 } catch (SQLException e) { 1582 return e.getMessage(); 1584 } 1585 stmt.close(); 1586 if (jmcCreated) { 1587 mc.close(); 1588 } 1589 } 1590 return noError; 1591 } 1592 1593 1597 protected void setTm(final TransactionManager tm) { 1598 this.tm = tm; 1599 } 1600 1601} 1602 | Popular Tags |