001package com.hfg.sql.jdbc; 002 003import java.io.IOException; 004import java.io.Reader; 005import java.io.StringReader; 006import java.sql.*; 007import java.util.List; 008import java.util.Map; 009import java.util.Properties; 010import java.util.concurrent.Executor; 011import java.util.logging.Level; 012import java.util.logging.Logger; 013 014import com.hfg.security.LoginCredentials; 015import com.hfg.sql.SQLUtil; 016import com.hfg.util.StackTraceUtil; 017 018//------------------------------------------------------------------------------ 019/** 020 Represents an RDBMS database connection. 021 <div> 022 @author J. Alex Taylor, hairyfatguy.com 023 </div> 024 */ 025//------------------------------------------------------------------------------ 026// com.hfg XML/HTML Coding Library 027// 028// This library is free software; you can redistribute it and/or 029// modify it under the terms of the GNU Lesser General Public 030// License as published by the Free Software Foundation; either 031// version 2.1 of the License, or (at your option) any later version. 032// 033// This library is distributed in the hope that it will be useful, 034// but WITHOUT ANY WARRANTY; without even the implied warranty of 035// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 036// Lesser General Public License for more details. 037// 038// You should have received a copy of the GNU Lesser General Public 039// License along with this library; if not, write to the Free Software 040// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 041// 042// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com 043// jataylor@hairyfatguy.com 044//------------------------------------------------------------------------------ 045 046public abstract class JDBCConnection implements Connection 047{ 048 private final Connection mInnerConn; 049 private JDBCServer mServer; 050 private String mDatabaseName; 051 private LoginCredentials mCredentials; 052 private JDBCConnectionSettings mSettings = new JDBCConnectionSettings(); 053 054 private final static Logger LOGGER = Logger.getLogger(JDBCConnection.class.getName()); 055 056 static 057 { 058 LOGGER.setLevel(Level.INFO); 059 } 060 061 //########################################################################### 062 // CONSTRUCTORS 063 //########################################################################### 064 065 //--------------------------------------------------------------------------- 066 protected JDBCConnection(Connection inConnection) 067 { 068 mInnerConn = inConnection; 069 } 070 071 //--------------------------------------------------------------------------- 072 protected JDBCConnection(JDBCServer inServer, String inDatabaseName, LoginCredentials inCredentials) 073 { 074 this(inServer, inDatabaseName, inCredentials, null); 075 } 076 077 //--------------------------------------------------------------------------- 078 protected JDBCConnection(JDBCServer inServer, String inDatabaseName, LoginCredentials inCredentials, JDBCConnectionSettings inSettings) 079 { 080 mServer = inServer; 081 mDatabaseName = inDatabaseName; 082 mCredentials = inCredentials; 083 mSettings = inSettings; 084 085 mInnerConn = establishConnection(); 086 } 087 088 089 //########################################################################### 090 // PUBLIC METHODS 091 //########################################################################### 092 093 //--------------------------------------------------------------------------- 094 public static Logger getLogger() 095 { 096 return LOGGER; 097 } 098 099 //--------------------------------------------------------------------------- 100 public boolean tableExists(String inTablename) 101 throws SQLException 102 { 103 boolean tableExists; 104 105 DatabaseMetaData metaData = getMetaData(); 106 ResultSet rs = null; 107 try 108 { 109 rs = metaData.getTables(null, null, inTablename.toLowerCase(), null); 110 111 tableExists = (rs.next() 112 && rs.getString("TABLE_NAME").equalsIgnoreCase(inTablename)); 113 } 114 finally 115 { 116 if (rs != null) rs.close(); 117 } 118 119 return tableExists; 120 } 121 122 //--------------------------------------------------------------------------- 123 public boolean dropTable(String inTablename) 124 throws SQLException 125 { 126 return SQLUtil.execute(this, "DROP TABLE " + inTablename); 127 } 128 129 //--------------------------------------------------------------------------- 130 public abstract String getCurrentUser() 131 throws SQLException; 132 133 //--------------------------------------------------------------------------- 134 public boolean execute(String inSQL) 135 throws SQLException 136 { 137 return SQLUtil.execute(this, inSQL); 138 } 139 140 //--------------------------------------------------------------------------- 141 public int[] batchExecute(String inSQL) 142 throws IOException, SQLException 143 { 144 return batchExecute(new StringReader(inSQL)); 145 } 146 147 //--------------------------------------------------------------------------- 148 public int[] batchExecute(Reader inSQL) 149 { 150 int[] results; 151 152 try 153 { 154 Statement stmt = null; 155 try 156 { 157 stmt = createStatement(); 158 159 List<String> sqlCmds = SQLUtil.splitBatchSQL(inSQL); 160 for (String sql : sqlCmds) 161 { 162 stmt.addBatch(sql); 163 } 164 165 results = stmt.executeBatch(); 166 } 167 finally 168 { 169 SQLUtil.close(stmt); 170 } 171 } 172 catch (SQLException e) 173 { 174 // SQLExceptions are broken out separately so that we can expose the next exception if present. 175 throw new JDBCException(e); 176 } 177 catch (IOException e) 178 { 179 throw new JDBCException(e); 180 } 181 182 return results; 183 } 184 185 //--------------------------------------------------------------------------- 186 public String name() 187 { 188 String connName = toString(); 189 int index = connName.lastIndexOf("."); 190 if (index >= 0) 191 { 192 connName = connName.substring(index+ 1); 193 } 194 195 return connName; 196 } 197 198 //--------------------------------------------------------------------------- 199 @Override 200 public Statement createStatement() 201 throws SQLException 202 { 203 return mInnerConn.createStatement(); 204 } 205 206 @Override 207 public PreparedStatement prepareStatement(String inSQL) 208 throws SQLException 209 { 210 return mInnerConn.prepareStatement(inSQL); 211 } 212 213 @Override 214 public CallableStatement prepareCall(String inSQL) 215 throws SQLException 216 { 217 return mInnerConn.prepareCall(inSQL); 218 } 219 220 @Override 221 public String nativeSQL(String inSQL) 222 throws SQLException 223 { 224 return mInnerConn.nativeSQL(inSQL); 225 } 226 227 @Override 228 public void setAutoCommit(boolean inAutoCommit) 229 throws SQLException 230 { 231 // Don't spend time extracting the stack trace if it won't be logged anyway 232 if (LOGGER.getLevel() != null 233 && LOGGER.getLevel().intValue() <= Level.FINE.intValue() 234 && ! StackTraceUtil.getCallingMethodName().equals("setAutoCommit")) // Avoid double logging if the connection is wrapped 235 { 236 LOGGER.fine(name() + " autocommit set from " + mInnerConn.getAutoCommit() + " to " + inAutoCommit + " by " + StackTraceUtil.getCallingStackTraceElement(null).toString()); 237 } 238 239 mInnerConn.setAutoCommit(inAutoCommit); 240 } 241 242 243 @Override 244 public boolean getAutoCommit() 245 throws SQLException 246 { 247 return mInnerConn.getAutoCommit(); 248 } 249 250 @Override 251 public void commit() 252 throws SQLException 253 { 254 mInnerConn.commit(); 255 } 256 257 @Override 258 public void rollback() 259 throws SQLException 260 { 261 mInnerConn.rollback(); 262 } 263 264 @Override 265 public void close() 266 throws SQLException 267 { 268 mInnerConn.close(); 269 } 270 271 @Override 272 public boolean isClosed() 273 throws SQLException 274 { 275 return mInnerConn.isClosed(); 276 } 277 278 @Override 279 public DatabaseMetaData getMetaData() 280 throws SQLException 281 { 282 return mInnerConn.getMetaData(); 283 } 284 285 @Override 286 public void setReadOnly(boolean inValue) 287 throws SQLException 288 { 289 mInnerConn.setReadOnly(inValue); 290 } 291 292 @Override 293 public boolean isReadOnly() 294 throws SQLException 295 { 296 return mInnerConn.isReadOnly(); 297 } 298 299 @Override 300 public void setCatalog(String inValue) 301 throws SQLException 302 { 303 mInnerConn.setCatalog(inValue); 304 } 305 306 @Override 307 public String getCatalog() 308 throws SQLException 309 { 310 return mInnerConn.getCatalog(); 311 } 312 313 @Override 314 public void setTransactionIsolation(int inLevel) 315 throws SQLException 316 { 317 mInnerConn.setTransactionIsolation(inLevel); 318 } 319 320 @Override 321 public int getTransactionIsolation() 322 throws SQLException 323 { 324 return mInnerConn.getTransactionIsolation(); 325 } 326 327 @Override 328 public SQLWarning getWarnings() 329 throws SQLException 330 { 331 return mInnerConn.getWarnings(); 332 } 333 334 @Override 335 public void clearWarnings() 336 throws SQLException 337 { 338 mInnerConn.clearWarnings(); 339 } 340 341 @Override 342 public Statement createStatement(int resultSetType, int resultSetConcurrency) 343 throws SQLException 344 { 345 return mInnerConn.createStatement(resultSetType, resultSetConcurrency); 346 } 347 348 @Override 349 public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) 350 throws SQLException 351 { 352 return mInnerConn.prepareStatement(sql, resultSetType, resultSetConcurrency); 353 } 354 355 @Override 356 public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) 357 throws SQLException 358 { 359 return mInnerConn.prepareCall(sql, resultSetType, resultSetConcurrency); 360 } 361 362 @Override 363 public Map<String, Class<?>> getTypeMap() 364 throws SQLException 365 { 366 return mInnerConn.getTypeMap(); 367 } 368 369 @Override 370 public void setTypeMap(Map<String, Class<?>> map) 371 throws SQLException 372 { 373 mInnerConn.setTypeMap(map); 374 } 375 376 @Override 377 public void setHoldability(int inValue) 378 throws SQLException 379 { 380 mInnerConn.setHoldability(inValue); 381 } 382 383 @Override 384 public int getHoldability() 385 throws SQLException 386 { 387 return mInnerConn.getHoldability(); 388 } 389 390 @Override 391 public Savepoint setSavepoint() 392 throws SQLException 393 { 394 return mInnerConn.setSavepoint(); 395 } 396 397 @Override 398 public Savepoint setSavepoint(String name) 399 throws SQLException 400 { 401 return mInnerConn.setSavepoint(name); 402 } 403 404 @Override 405 public void rollback(Savepoint savepoint) 406 throws SQLException 407 { 408 mInnerConn.rollback(savepoint); 409 } 410 411 @Override 412 public void releaseSavepoint(Savepoint savepoint) 413 throws SQLException 414 { 415 mInnerConn.releaseSavepoint(savepoint); 416 } 417 418 @Override 419 public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) 420 throws SQLException 421 { 422 return mInnerConn.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); 423 } 424 425 @Override 426 public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) 427 throws SQLException 428 { 429 return mInnerConn.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability); 430 } 431 432 @Override 433 public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) 434 throws SQLException 435 { 436 return mInnerConn.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); 437 } 438 439 @Override 440 public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) 441 throws SQLException 442 { 443 return mInnerConn.prepareStatement(sql, autoGeneratedKeys); 444 } 445 446 @Override 447 public PreparedStatement prepareStatement(String sql, int[] columnIndexes) 448 throws SQLException 449 { 450 return mInnerConn.prepareStatement(sql, columnIndexes); 451 } 452 453 @Override 454 public PreparedStatement prepareStatement(String sql, String[] columnNames) 455 throws SQLException 456 { 457 return mInnerConn.prepareStatement(sql, columnNames); 458 } 459 460 @Override 461 public Clob createClob() 462 throws SQLException 463 { 464 return mInnerConn.createClob(); 465 } 466 467 @Override 468 public Blob createBlob() 469 throws SQLException 470 { 471 return mInnerConn.createBlob(); 472 } 473 474 @Override 475 public NClob createNClob() 476 throws SQLException 477 { 478 return mInnerConn.createNClob(); 479 } 480 481 @Override 482 public SQLXML createSQLXML() 483 throws SQLException 484 { 485 return mInnerConn.createSQLXML(); 486 } 487 488 @Override 489 public boolean isValid(int timeout) 490 throws SQLException 491 { 492 return mInnerConn.isValid(timeout); 493 } 494 495 @Override 496 public void setClientInfo(String name, String value) 497 throws SQLClientInfoException 498 { 499 mInnerConn.setClientInfo(name, value); 500 } 501 502 @Override 503 public void setClientInfo(Properties properties) 504 throws SQLClientInfoException 505 { 506 mInnerConn.setClientInfo(properties); 507 } 508 509 @Override 510 public String getClientInfo(String name) 511 throws SQLException 512 { 513 return mInnerConn.getClientInfo(name); 514 } 515 516 @Override 517 public Properties getClientInfo() 518 throws SQLException 519 { 520 return mInnerConn.getClientInfo(); 521 } 522 523 @Override 524 public Array createArrayOf(String typeName, Object[] elements) 525 throws SQLException 526 { 527 return mInnerConn.createArrayOf(typeName, elements); 528 } 529 530 @Override 531 public Struct createStruct(String typeName, Object[] attributes) 532 throws SQLException 533 { 534 return mInnerConn.createStruct(typeName, attributes); 535 } 536 537 @Override 538 public void setSchema(String schema) 539 throws SQLException 540 { 541 mInnerConn.setSchema(schema); 542 } 543 544 @Override 545 public String getSchema() 546 throws SQLException 547 { 548 return mInnerConn.getSchema(); 549 } 550 551 @Override 552 public void abort(Executor executor) 553 throws SQLException 554 { 555 mInnerConn.abort(executor); 556 } 557 558 @Override 559 public void setNetworkTimeout(Executor executor, int milliseconds) 560 throws SQLException 561 { 562 mInnerConn.setNetworkTimeout(executor, milliseconds); 563 } 564 565 @Override 566 public int getNetworkTimeout() 567 throws SQLException 568 { 569 return mInnerConn.getNetworkTimeout(); 570 } 571 572 @Override 573 public <T> T unwrap(Class<T> iface) 574 throws SQLException 575 { 576 return mInnerConn.unwrap(iface); 577 } 578 579 @Override 580 public boolean isWrapperFor(Class<?> iface) 581 throws SQLException 582 { 583 return mInnerConn.isWrapperFor(iface); 584 } 585 586 //########################################################################### 587 // PROTECTED METHODS 588 //########################################################################### 589 590 //--------------------------------------------------------------------------- 591 protected Connection getInnerConnection() 592 { 593 return mInnerConn; 594 } 595 596 //########################################################################### 597 // PRIVATE METHODS 598 //########################################################################### 599 600 //--------------------------------------------------------------------------- 601 private Connection establishConnection() 602 { 603 return mServer.getConnection(mDatabaseName, mCredentials, mSettings); 604 } 605 606}