001package org.javasimon.jdbc4; 002 003import java.sql.Array; 004import java.sql.Blob; 005import java.sql.CallableStatement; 006import java.sql.Clob; 007import java.sql.Connection; 008import java.sql.DatabaseMetaData; 009import java.sql.NClob; 010import java.sql.PreparedStatement; 011import java.sql.SQLClientInfoException; 012import java.sql.SQLException; 013import java.sql.SQLWarning; 014import java.sql.SQLXML; 015import java.sql.Savepoint; 016import java.sql.Statement; 017import java.sql.Struct; 018import java.util.Map; 019import java.util.Properties; 020import java.util.concurrent.Executor; 021 022import org.javasimon.Counter; 023import org.javasimon.SimonManager; 024import org.javasimon.Split; 025 026/** 027 * Class implements Simon JDBC proxy connection. 028 * <p> 029 * Every method of this connection is implemented as call of real connection method. 030 * Several methods have added work with Simons (starting, stopping, etc.) for monitoring 031 * purposes. 032 * </p> 033 * <p> 034 * From all statement-return-methods (<code>createStatement(*)</code>, 035 * <code>prepareStatement(*)</code>, <code>prepareCall(*)</code>) connection returns own 036 * implementation of statement classes. Those classes are also proxies and provides 037 * additional Simons for monitoring features of JDBC driver. 038 * </p> 039 * Monitoring connection ensure following Simons: 040 * <ul> 041 * <li>lifespan (<code>org.javasimon.jdbc4.conn</code>, stopwatch) - measure connection life and count</li> 042 * <li>commits (<code>org.javasimon.jdbc4.conn.commits</code>, counter) - measure executed commits of all connections</li> 043 * <li>rollbacks (<code>org.javasimon.jdbc4.conn.rollbacks</code>, counter) - measure executed rollbacks of all connections</li> 044 * </ul> 045 * 046 * @author Radovan Sninsky 047 * @see java.sql.Connection 048 * @since 2.4 049 */ 050public final class SimonConnection implements Connection { 051 private final Connection conn; 052 private final WrapperSupport<Connection> wrapperSupport; 053 private final SqlNormalizerFactory sqlNormalizerFactory; 054 private String prefix; 055 056 private Split life; 057 private Counter commits; 058 private Counter rollbacks; 059 060 /** 061 * Class constructor, initializes Simons (lifespan, active, commits 062 * and rollbacks) related to the DB connection. 063 * 064 * @param conn real DB connection 065 * @param prefix hierarchy prefix for connection Simons 066 * @param sqlNormalizerFactory factory to map queries to Simon keys 067 */ 068 public SimonConnection(Connection conn, String prefix, SqlNormalizerFactory sqlNormalizerFactory) { 069 this.conn = conn; 070 this.sqlNormalizerFactory = sqlNormalizerFactory; 071 this.wrapperSupport = new WrapperSupport<>(this.conn, Connection.class); 072 this.prefix = prefix; 073 074 commits = SimonManager.getCounter(prefix + ".conn.commits"); 075 rollbacks = SimonManager.getCounter(prefix + ".conn.rollbacks"); 076 life = SimonManager.getStopwatch(prefix + ".conn").start(); 077 } 078 079 public SimonConnection(Connection conn, String prefix) { 080 this(conn, prefix, new RegexBasedNormalizerFactory()); 081 } 082 083 /** 084 * Closes the real connection, stops lifespan Simon and decreases the active Simon. 085 * 086 * @throws java.sql.SQLException if real operation fails 087 */ 088 @Override 089 public void close() throws SQLException { 090 conn.close(); 091 092 life.stop(); 093 } 094 095 /** 096 * Commits the real connection and increases the commits Simon. 097 * 098 * @throws java.sql.SQLException if real commit fails 099 */ 100 @Override 101 public void commit() throws SQLException { 102 conn.commit(); 103 104 commits.increase(); 105 } 106 107 /** 108 * Rollback the real connection and increase the rollbacks Simon. 109 * 110 * @throws java.sql.SQLException if real operation fails 111 */ 112 @Override 113 public void rollback() throws SQLException { 114 conn.rollback(); 115 116 rollbacks.increase(); 117 } 118 119 /** 120 * Rollbacks the real connection and increases the rollbacks Simon. 121 * 122 * @param savepoint the <code>Savepoint</code> object to roll back to 123 * @throws java.sql.SQLException if real operation fails 124 */ 125 @Override 126 public void rollback(Savepoint savepoint) throws SQLException { 127 conn.rollback(savepoint); 128 129 rollbacks.increase(); 130 } 131 132 /** 133 * Calls the real createStatement and wraps the returned statement by Simon's statement. 134 * 135 * @return Simon's statement with wrapped real statement 136 * @throws java.sql.SQLException if real operation fails 137 */ 138 @Override 139 public Statement createStatement() throws SQLException { 140 return new SimonStatement(this, conn.createStatement(), prefix, sqlNormalizerFactory); 141 } 142 143 /** 144 * Calls real createStatement and wraps returned statement by Simon's statement. 145 * 146 * @param rsType result set type 147 * @param rsConcurrency result set concurrency 148 * @return Simon's statement with wrapped real statement 149 * @throws java.sql.SQLException if real operation fails 150 */ 151 @Override 152 public Statement createStatement(int rsType, int rsConcurrency) throws SQLException { 153 return new SimonStatement(this, conn.createStatement(rsType, rsConcurrency), prefix, sqlNormalizerFactory); 154 } 155 156 /** 157 * Calls real createStatement and wraps returned statement by Simon's statement. 158 * 159 * @param rsType result set type 160 * @param rsConcurrency result set concurrency 161 * @param rsHoldability result set holdability 162 * @return Simon's statement with wrapped real statement 163 * @throws java.sql.SQLException if real operation fails 164 */ 165 @Override 166 public Statement createStatement(int rsType, int rsConcurrency, int rsHoldability) throws SQLException { 167 return new SimonStatement(this, conn.createStatement(rsType, rsConcurrency, rsHoldability), prefix, sqlNormalizerFactory); 168 } 169 170 /** 171 * Calls real prepareStatement and wraps returned statement by Simon's statement. 172 * 173 * @param sql SQL statement 174 * @return Simon's statement with wrapped real statement 175 * @throws java.sql.SQLException if real operation fails 176 */ 177 @Override 178 public PreparedStatement prepareStatement(String sql) throws SQLException { 179 return new SimonPreparedStatement(this, conn.prepareStatement(sql), sql, prefix, sqlNormalizerFactory); 180 } 181 182 /** 183 * Calls real prepareStatement and wraps returned statement by Simon's statement. 184 * 185 * @param sql SQL statement 186 * @param autoGeneratedKeys auto generated keys 187 * @return Simon's statement with wrapped real statement 188 * @throws java.sql.SQLException if real operation fails 189 */ 190 @Override 191 public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { 192 return new SimonPreparedStatement(this, conn.prepareStatement(sql, autoGeneratedKeys), sql, prefix, sqlNormalizerFactory); 193 } 194 195 /** 196 * Calls real prepareStatement and wraps returned statement by Simon's statement. 197 * 198 * @param sql SQL statement 199 * @param rsType result set type 200 * @param rsConcurrency result set concurrency 201 * @return Simon's statement with wrapped real statement 202 * @throws java.sql.SQLException if real operation fails 203 */ 204 @Override 205 public PreparedStatement prepareStatement(String sql, int rsType, int rsConcurrency) throws SQLException { 206 return new SimonPreparedStatement(this, conn.prepareStatement(sql, rsType, rsConcurrency), sql, prefix, sqlNormalizerFactory); 207 } 208 209 /** 210 * Calls real prepareStatement and wraps returned statement by Simon's statement. 211 * 212 * @param sql SQL statement 213 * @param rsType result set type 214 * @param rsConcurrency result set concurrency 215 * @param rsHoldability result set holdability 216 * @return Simon's statement with wrapped real statement 217 * @throws java.sql.SQLException if real operation fails 218 */ 219 @Override 220 public PreparedStatement prepareStatement(String sql, int rsType, int rsConcurrency, int rsHoldability) throws SQLException { 221 return new SimonPreparedStatement(this, conn.prepareStatement(sql, rsType, rsConcurrency, rsHoldability), sql, prefix, sqlNormalizerFactory); 222 } 223 224 /** 225 * Calls real prepareStatement and wraps returned statement by Simon's statement. 226 * 227 * @param sql SQL statement 228 * @param columnIndexes an array of column indexes indicating the columns 229 * that should be returned from the inserted row or rows 230 * @return Simon's statement with wrapped real statement 231 * @throws java.sql.SQLException if real operation fails 232 */ 233 @Override 234 public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { 235 return new SimonPreparedStatement(this, conn.prepareStatement(sql, columnIndexes), sql, prefix, sqlNormalizerFactory); 236 } 237 238 /** 239 * Calls real prepareStatement and wraps returned statement by Simon's statement. 240 * 241 * @param sql SQL statement 242 * @param columnNames an array of column names indicating the columns 243 * that should be returned from the inserted row or rows 244 * @return Simon's statement with wrapped real statement 245 * @throws java.sql.SQLException if real operation fails 246 */ 247 @Override 248 public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { 249 return new SimonPreparedStatement(this, conn.prepareStatement(sql, columnNames), sql, prefix, sqlNormalizerFactory); 250 } 251 252 /** 253 * Calls real prepareCall and wraps returned statement by Simon's statement. 254 * 255 * @param sql an SQL statement, typically a JDBC function call escape string 256 * @return Simon's statement with wrapped real statement 257 * @throws java.sql.SQLException if real operation fails 258 */ 259 @Override 260 public CallableStatement prepareCall(String sql) throws SQLException { 261 return new SimonCallableStatement(conn, conn.prepareCall(sql), sql, prefix, sqlNormalizerFactory); 262 } 263 264 /** 265 * Calls real prepareCall and wraps returned statement by Simon's statement. 266 * 267 * @param sql an SQL statement, typically a JDBC function call escape string 268 * @param rsType result set type 269 * @param rsConcurrency result set concurrency 270 * @return Simon's statement with wrapped real statement 271 * @throws java.sql.SQLException if real operation fails 272 */ 273 @Override 274 public CallableStatement prepareCall(String sql, int rsType, int rsConcurrency) throws SQLException { 275 return new SimonCallableStatement(conn, conn.prepareCall(sql, rsType, rsConcurrency), sql, prefix, sqlNormalizerFactory); 276 } 277 278 /** 279 * Calls real prepareCall and wraps returned statement by Simon's statement. 280 * 281 * @param sql an SQL statement, typically a JDBC function call escape string 282 * @param rsType result set type 283 * @param rsConcurrency result set concurrency 284 * @param rsHoldability result set holdability 285 * @return Simon's statement with wrapped real statement 286 * @throws java.sql.SQLException if real operation fails 287 */ 288 @Override 289 public CallableStatement prepareCall(String sql, int rsType, int rsConcurrency, int rsHoldability) throws SQLException { 290 return new SimonCallableStatement(conn, conn.prepareCall(sql, rsType, rsConcurrency, rsHoldability), sql, prefix, sqlNormalizerFactory); 291 } 292 293 //// NOT MONITORED 294 295 @Override 296 public String nativeSQL(String s) throws SQLException { 297 return conn.nativeSQL(s); 298 } 299 300 @Override 301 public void setAutoCommit(boolean b) throws SQLException { 302 conn.setAutoCommit(b); 303 } 304 305 @Override 306 public boolean getAutoCommit() throws SQLException { 307 return conn.getAutoCommit(); 308 } 309 310 @Override 311 public boolean isClosed() throws SQLException { 312 return conn.isClosed(); 313 } 314 315 @Override 316 public DatabaseMetaData getMetaData() throws SQLException { 317 return conn.getMetaData(); 318 } 319 320 @Override 321 public void setReadOnly(boolean b) throws SQLException { 322 conn.setReadOnly(b); 323 } 324 325 @Override 326 public boolean isReadOnly() throws SQLException { 327 return conn.isReadOnly(); 328 } 329 330 @Override 331 public void setCatalog(String s) throws SQLException { 332 conn.setCatalog(s); 333 } 334 335 @Override 336 public String getCatalog() throws SQLException { 337 return conn.getCatalog(); 338 } 339 340 @Override 341 public void setTransactionIsolation(int i) throws SQLException { 342 conn.setTransactionIsolation(i); 343 } 344 345 @Override 346 public int getTransactionIsolation() throws SQLException { 347 return conn.getTransactionIsolation(); 348 } 349 350 @Override 351 public SQLWarning getWarnings() throws SQLException { 352 return conn.getWarnings(); 353 } 354 355 @Override 356 public void clearWarnings() throws SQLException { 357 conn.clearWarnings(); 358 } 359 360 @Override 361 public Map<String, Class<?>> getTypeMap() throws SQLException { 362 return conn.getTypeMap(); 363 } 364 365 @Override 366 public void setTypeMap(Map<String, Class<?>> stringClassMap) throws SQLException { 367 conn.setTypeMap(stringClassMap); 368 } 369 370 @Override 371 public void setHoldability(int i) throws SQLException { 372 conn.setHoldability(i); 373 } 374 375 @Override 376 public int getHoldability() throws SQLException { 377 return conn.getHoldability(); 378 } 379 380 @Override 381 public Savepoint setSavepoint() throws SQLException { 382 return conn.setSavepoint(); 383 } 384 385 @Override 386 public Savepoint setSavepoint(String s) throws SQLException { 387 return conn.setSavepoint(s); 388 } 389 390 @Override 391 public void releaseSavepoint(Savepoint savepoint) throws SQLException { 392 conn.releaseSavepoint(savepoint); 393 } 394 395 @Override 396 public Clob createClob() throws SQLException { 397 return conn.createClob(); 398 } 399 400 @Override 401 public Blob createBlob() throws SQLException { 402 return conn.createBlob(); 403 } 404 405 @Override 406 public NClob createNClob() throws SQLException { 407 return conn.createNClob(); 408 } 409 410 @Override 411 public SQLXML createSQLXML() throws SQLException { 412 return conn.createSQLXML(); 413 } 414 415 @Override 416 public boolean isValid(int i) throws SQLException { 417 return conn.isValid(i); 418 } 419 420 @Override 421 public void setClientInfo(String s, String s1) throws SQLClientInfoException { 422 conn.setClientInfo(s, s1); 423 } 424 425 @Override 426 public void setClientInfo(Properties properties) throws SQLClientInfoException { 427 conn.setClientInfo(properties); 428 } 429 430 @Override 431 public String getClientInfo(String s) throws SQLException { 432 return conn.getClientInfo(s); 433 } 434 435 @Override 436 public Properties getClientInfo() throws SQLException { 437 return conn.getClientInfo(); 438 } 439 440 @Override 441 public Array createArrayOf(String s, Object[] objects) throws SQLException { 442 return conn.createArrayOf(s, objects); 443 } 444 445 @Override 446 public Struct createStruct(String s, Object[] objects) throws SQLException { 447 return conn.createStruct(s, objects); 448 } 449 450 @Override 451 public void setSchema(String schema) throws SQLException { 452 conn.setSchema(schema); 453 } 454 455 @Override 456 public String getSchema() throws SQLException { 457 return conn.getSchema(); 458 } 459 460 @Override 461 public void abort(Executor executor) throws SQLException { 462 conn.abort(executor); 463 } 464 465 @Override 466 public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { 467 conn.setNetworkTimeout(executor, milliseconds); 468 } 469 470 @Override 471 public int getNetworkTimeout() throws SQLException { 472 return conn.getNetworkTimeout(); 473 } 474 475 @Override 476 public <T> T unwrap(Class<T> iface) throws SQLException { 477 return wrapperSupport.unwrap(iface); 478 } 479 480 @Override 481 public boolean isWrapperFor(Class<?> iface) throws SQLException { 482 return wrapperSupport.isWrapperFor(iface); 483 } 484}