1 11 12 13 package org.jivesoftware.database; 14 15 import org.jivesoftware.util.ClassUtils; 16 import org.jivesoftware.util.JiveGlobals; 17 import org.jivesoftware.util.Log; 18 19 import java.io.*; 20 import java.sql.*; 21 22 34 public class DbConnectionManager { 35 36 private static final String CHECK_VERSION = 37 "SELECT majorVersion, minorVersion FROM jiveVersion"; 38 39 44 private static final int CURRENT_MAJOR_VERSION = 2; 45 46 49 private static final int CURRENT_MINOR_VERSION = 2; 50 51 private static ConnectionProvider connectionProvider; 52 private static Object providerLock = new Object (); 53 54 private static boolean profilingEnabled = false; 56 57 private static boolean transactionsSupported; 59 private static boolean streamTextRequired; 61 private static boolean maxRowsSupported; 63 private static boolean fetchSizeSupported; 65 private static boolean subqueriesSupported; 67 private static boolean scrollResultsSupported; 69 private static boolean batchUpdatesSupported; 71 72 private static DatabaseType databaseType = DatabaseType.unknown; 73 74 78 public static Connection getConnection() throws SQLException { 79 if (connectionProvider == null) { 80 synchronized (providerLock) { 81 if (connectionProvider == null) { 82 String className = JiveGlobals.getXMLProperty("connectionProvider.className"); 85 if (className != null) { 86 try { 88 Class conClass = ClassUtils.forName(className); 89 setConnectionProvider((ConnectionProvider)conClass.newInstance()); 90 } 91 catch (Exception e) { 92 Log.error("Warning: failed to create the " + 93 "connection provider specified by connection" + 94 "Provider.className. Using the default pool.", e); 95 setConnectionProvider(new DefaultConnectionProvider()); 96 } 97 } 98 else { 99 setConnectionProvider(new DefaultConnectionProvider()); 100 } 101 } 102 } 103 } 104 Connection con = connectionProvider.getConnection(); 105 106 if (con == null) { 107 Log.error("WARNING: ConnectionManager.getConnection() " + 108 "failed to obtain a connection."); 109 } 110 if (profilingEnabled) { 113 return new ProfiledConnection(con); 114 } 115 else { 116 return con; 117 } 118 } 119 120 124 public static Connection getTransactionConnection() throws SQLException { 125 Connection con = getConnection(); 126 if (isTransactionsSupported()) { 127 con.setAutoCommit(false); 128 } 129 return con; 130 } 131 132 136 public static void closeTransactionConnection(Connection con, boolean abortTransaction) { 137 if (con == null) { 139 return; 140 } 141 142 if (isTransactionsSupported()) { 144 try { 145 if (abortTransaction) { 146 con.rollback(); 147 } 148 else { 149 con.commit(); 150 } 151 } 152 catch (Exception e) { 153 Log.error(e); 154 } 155 } 156 try { 157 if (isTransactionsSupported()) { 159 con.setAutoCommit(true); 160 } 161 } 162 catch (Exception e) { 163 Log.error(e); 164 } 165 try { 166 con.close(); 168 } 169 catch (Exception e) { 170 Log.error(e); 171 } 172 } 173 174 197 public static void closeConnection(PreparedStatement pstmt, Connection con) { 198 try { 199 if (pstmt != null) { 200 pstmt.close(); 201 } 202 } 203 catch (Exception e) { 204 Log.error(e); 205 } 206 closeConnection(con); 207 } 208 209 230 public static void closeConnection(Connection con) { 231 try { 232 if (con != null) { 233 con.close(); 234 } 235 } 236 catch (Exception e) { 237 Log.error(e); 238 } 239 } 240 241 249 public static Statement createScrollableStatement(Connection con) throws SQLException { 250 if (isScrollResultsSupported()) { 251 return con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, 252 ResultSet.CONCUR_READ_ONLY); 253 } 254 else { 255 return con.createStatement(); 256 } 257 } 258 259 268 public static PreparedStatement createScrollablePreparedStatement(Connection con, String sql) 269 throws SQLException { 270 if (isScrollResultsSupported()) { 271 return con.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, 272 ResultSet.CONCUR_READ_ONLY); 273 } 274 else { 275 return con.prepareStatement(sql); 276 } 277 } 278 279 288 public static void scrollResultSet(ResultSet rs, int rowNumber) throws SQLException { 289 if (isScrollResultsSupported()) { 291 if (rowNumber > 0) { 292 rs.setFetchDirection(ResultSet.FETCH_FORWARD); 293 rs.relative(rowNumber); 294 } 295 } 296 else { 298 for (int i = 0; i < rowNumber; i++) { 299 rs.next(); 300 } 301 } 302 } 303 304 310 public static ConnectionProvider getConnectionProvider() { 311 return connectionProvider; 312 } 313 314 323 public static void setConnectionProvider(ConnectionProvider provider) { 324 synchronized (providerLock) { 325 if (connectionProvider != null) { 326 connectionProvider.destroy(); 327 connectionProvider = null; 328 } 329 connectionProvider = provider; 330 connectionProvider.start(); 331 Connection con = null; 333 try { 334 con = connectionProvider.getConnection(); 335 setMetaData(con); 336 337 try { 339 upgradeDatabase(con); 340 } 341 catch (Exception e) { 342 Log.error("Database upgrade failed. Please manually upgrade your database.", e); 343 System.out.println("Database upgrade failed. Please manually upgrade your " + 344 "database."); 345 } 346 } 347 catch (Exception e) { 348 Log.error(e); 349 } 350 finally { 351 try { if (con != null) { con.close(); } } 352 catch (Exception e) { Log.error(e); } 353 } 354 } 355 JiveGlobals.setXMLProperty("connectionProvider.className", provider.getClass().getName()); 357 } 358 359 369 public static String getLargeTextField(ResultSet rs, int columnIndex) throws SQLException { 370 if (isStreamTextRequired()) { 371 Reader bodyReader = null; 372 String value = null; 373 try { 374 bodyReader = rs.getCharacterStream(columnIndex); 375 if (bodyReader == null) { 376 return null; 377 } 378 char[] buf = new char[256]; 379 int len; 380 StringWriter out = new StringWriter(256); 381 while ((len = bodyReader.read(buf)) >= 0) { 382 out.write(buf, 0, len); 383 } 384 value = out.toString(); 385 out.close(); 386 } 387 catch (Exception e) { 388 Log.error(e); 389 throw new SQLException("Failed to load text field"); 390 } 391 finally { 392 try { 393 bodyReader.close(); 394 } 395 catch (Exception e) { 396 } 397 } 398 return value; 399 } 400 else { 401 return rs.getString(columnIndex); 402 } 403 } 404 405 415 public static void setLargeTextField(PreparedStatement pstmt, int parameterIndex, 416 String value) throws SQLException 417 { 418 if (isStreamTextRequired()) { 419 Reader bodyReader = null; 420 try { 421 bodyReader = new StringReader(value); 422 pstmt.setCharacterStream(parameterIndex, bodyReader, value.length()); 423 } 424 catch (Exception e) { 425 Log.error(e); 426 throw new SQLException("Failed to set text field."); 427 } 428 } 431 else { 432 pstmt.setString(parameterIndex, value); 433 } 434 } 435 436 444 public static void setMaxRows(Statement stmt, int maxRows) { 445 if (isMaxRowsSupported()) { 446 try { 447 stmt.setMaxRows(maxRows); 448 } 449 catch (Throwable t) { 450 maxRowsSupported = false; 456 } 457 } 458 } 459 460 468 public static void setFetchSize(ResultSet rs, int fetchSize) { 469 if (isFetchSizeSupported()) { 470 try { 471 rs.setFetchSize(fetchSize); 472 } 473 catch (Throwable t) { 474 fetchSizeSupported = false; 480 } 481 } 482 } 483 484 488 private static void setMetaData(Connection con) throws SQLException { 489 DatabaseMetaData metaData = con.getMetaData(); 490 transactionsSupported = metaData.supportsTransactions(); 492 subqueriesSupported = metaData.supportsCorrelatedSubqueries(); 494 try { 498 scrollResultsSupported = metaData.supportsResultSetType( 499 ResultSet.TYPE_SCROLL_INSENSITIVE); 500 } 501 catch (Exception e) { 502 scrollResultsSupported = false; 503 } 504 batchUpdatesSupported = metaData.supportsBatchUpdates(); 506 507 streamTextRequired = false; 509 maxRowsSupported = true; 510 fetchSizeSupported = true; 511 512 String dbName = metaData.getDatabaseProductName().toLowerCase(); 514 String driverName = metaData.getDriverName().toLowerCase(); 515 516 if (dbName.indexOf("oracle") != -1) { 518 databaseType = DatabaseType.oracle; 519 streamTextRequired = true; 520 scrollResultsSupported = false; 521 if (driverName.indexOf("auguro") != -1) { 523 streamTextRequired = false; 524 fetchSizeSupported = true; 525 maxRowsSupported = false; 526 } 527 } 528 else if (dbName.indexOf("postgres") != -1) { 530 databaseType = DatabaseType.postgres; 531 scrollResultsSupported = false; 533 fetchSizeSupported = false; 534 } 535 else if (dbName.indexOf("interbase") != -1) { 537 databaseType = DatabaseType.interbase; 538 fetchSizeSupported = false; 539 maxRowsSupported = false; 540 } 541 else if (dbName.indexOf("sql server") != -1 && 543 driverName.indexOf("una") != -1) 544 { 545 databaseType = DatabaseType.sqlserver; 546 fetchSizeSupported = true; 547 maxRowsSupported = false; 548 } 549 else if (dbName.indexOf("mysql") != -1) { 551 databaseType = DatabaseType.mysql; 552 transactionsSupported = false; 553 } 554 else if (dbName.indexOf("hsql") != -1) { 556 databaseType = DatabaseType.hsqldb; 557 scrollResultsSupported = false; 558 } 559 else if (dbName.indexOf("db2") != 1) { 561 databaseType = DatabaseType.db2; 562 } 563 } 564 565 572 public static DatabaseType getDatabaseType() { 573 return databaseType; 574 } 575 576 583 public static boolean isProfilingEnabled() { 584 return profilingEnabled; 585 } 586 587 594 public static void setProfilingEnabled(boolean enable) { 595 if (!profilingEnabled && enable) { 597 ProfiledConnection.start(); 598 } 599 else if (profilingEnabled && !enable) { 601 ProfiledConnection.stop(); 602 } 603 profilingEnabled = enable; 604 } 605 606 public static boolean isTransactionsSupported() { 607 return transactionsSupported; 608 } 609 610 public static boolean isStreamTextRequired() { 611 return streamTextRequired; 612 } 613 614 public static boolean isMaxRowsSupported() { 615 return maxRowsSupported; 616 } 617 618 public static boolean isFetchSizeSupported() { 619 620 return fetchSizeSupported; 621 } 622 623 public static boolean isSubqueriesSupported() { 624 return subqueriesSupported; 625 } 626 627 public static boolean isScrollResultsSupported() { 628 return scrollResultsSupported; 629 } 630 631 public static boolean isBatchUpdatesSupported() { 632 return batchUpdatesSupported; 633 } 634 635 642 public static enum DatabaseType { 643 644 oracle, 645 646 postgres, 647 648 mysql, 649 650 hsqldb, 651 652 db2, 653 654 sqlserver, 655 656 interbase, 657 658 unknown; 659 } 660 661 667 private static boolean upgradeDatabase(Connection con) throws Exception { 668 int majorVersion; 669 int minorVersion; 670 PreparedStatement pstmt = null; 671 try { 672 pstmt = con.prepareStatement(CHECK_VERSION); 673 ResultSet rs = pstmt.executeQuery(); 674 if (!rs.next()) { 676 majorVersion = 2; 677 minorVersion = 0; 678 } 679 majorVersion = rs.getInt(1); 680 minorVersion = rs.getInt(2); 681 rs.close(); 682 } 683 catch (SQLException sqle) { 684 majorVersion = 2; 687 minorVersion = 0; 688 } 689 finally { 690 try { if (pstmt != null) { pstmt.close(); } } 691 catch (Exception e) { Log.error(e); } 692 } 693 if (majorVersion == CURRENT_MAJOR_VERSION && minorVersion == CURRENT_MINOR_VERSION) { 694 return false; 695 } 696 Log.info("Found old database schema (" + majorVersion + "." + minorVersion + "). " + 698 "Upgrading to latest schema."); 699 System.out.println("Found old database schema (" + majorVersion + "." + 700 minorVersion + "). " + "Upgrading to latest schema."); 701 if (databaseType == DatabaseType.unknown) { 702 Log.info("Warning: database type unknown. You must manually upgrade your database."); 703 System.out.println("Warning: database type unknown. You must manually upgrade your " + 704 "database."); 705 return false; 706 } 707 else if (databaseType == DatabaseType.interbase) { 708 Log.info("Warning: automatic upgrades of Interbase are not supported. You " + 709 "must manually upgrade your database."); 710 System.out.println("Warning: automatic upgrades of Interbase are not supported. You " + 711 "must manually upgrade your database."); 712 return false; 713 } 714 for (int i=minorVersion; i<CURRENT_MINOR_VERSION; i++) { 716 BufferedReader in = null; 717 Statement stmt = null; 718 try { 719 String resourceName = "/database/upgrade/" + CURRENT_MAJOR_VERSION + "." + i + 721 "_to_" + CURRENT_MAJOR_VERSION + "." + (i+1) + "/messenger_" + 722 databaseType + ".sql"; 723 in = new BufferedReader(new InputStreamReader( 724 new DbConnectionManager().getClass().getResourceAsStream(resourceName))); 725 boolean done = false; 726 while (!done) { 727 StringBuilder command = new StringBuilder (); 728 while (true) { 729 String line = in.readLine(); 730 if (line == null) { 731 done = true; 732 break; 733 } 734 if (isSQLCommandPart(line)) { 736 command.append(line); 737 } 738 if (line.endsWith(";")) { 739 break; 740 } 741 } 742 if (!done && command != null) { 744 stmt = con.createStatement(); 745 stmt.execute(command.toString()); 746 stmt.close(); 747 } 748 } 749 } 750 finally { 751 try { if (pstmt != null) { pstmt.close(); } } 752 catch (Exception e) { Log.error(e); } 753 if (in != null) { 754 try { in.close(); } 755 catch (Exception e) { } 756 } 757 } 758 } 759 Log.info("Database upgraded successfully."); 760 System.out.println("Database upgraded successfully."); 761 return true; 762 } 763 764 770 public static boolean isSQLCommandPart(String line) { 771 line = line.trim(); 772 if (line.equals("")) { 773 return false; 774 } 775 if (line.startsWith("//") || line.startsWith("--") || line.startsWith("#") || 782 line.startsWith("REM") || line.startsWith("/*")) 783 { 784 return false; 785 } 786 return true; 787 } 788 789 private DbConnectionManager() { 790 } 792 } | Popular Tags |