001 /*
002 * $Id: StasiStatement.java,v 1.4 2014/05/17 06:55:25 oboehm Exp $
003 *
004 * Copyright (c) 2014 by Oliver Boehm
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express orimplied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 *
018 * (c)reated 16.03.2014 by oliver (ob@oasd.de)
019 */
020
021 package patterntesting.runtime.monitor.db.internal;
022
023 import java.sql.*;
024
025 import org.slf4j.*;
026
027 import patterntesting.runtime.log.LogWatch;
028 import patterntesting.runtime.monitor.ProfileMonitor;
029 import patterntesting.runtime.monitor.db.SqlStatistic;
030 import patterntesting.runtime.util.Converter;
031
032 /**
033 * A simple wrapper for {@link Statement} to be able to find resource problems
034 * while reading and writing to the database. It allows us also to measure times
035 * of SQL statements.
036 * <p>
037 * Why the name "Stasi..."? The Stasi was the official state security service of
038 * Eastern Germany which controls the people (like NSA in the U.S. or KGB in
039 * Russia, see also <a href="http://en.wikipedia.org/wiki/Stasi">Wikipedia</a>).
040 * The StasiStatement controls the embedded {@link Statement} - therefore the
041 * name.
042 * </p>
043 *
044 * @author oliver
045 * @version $Revision: 1.4 $
046 * @since 1.4.1 (16.03.2014)
047 */
048 public class StasiStatement implements Statement {
049
050 private static final Logger log = LoggerFactory.getLogger(StasiStatement.class);
051 private final LogWatch logWatch = new LogWatch();
052 private final Statement statement;
053
054 /**
055 * Instantiates a new proxy statement.
056 *
057 * @param statement the statement
058 */
059 public StasiStatement(final Statement statement) {
060 this.statement = statement;
061 }
062
063 /**
064 * Gets the statement.
065 *
066 * @return the statement
067 */
068 protected final Statement getStatement() {
069 return this.statement;
070 }
071
072 /**
073 * Adds the batch.
074 *
075 * @param sql the sql
076 * @throws SQLException the sQL exception
077 * @see java.sql.Statement#addBatch(java.lang.String)
078 */
079 public final void addBatch(final String sql) throws SQLException {
080 ProfileMonitor mon = SqlStatistic.start(sql);
081 try {
082 statement.addBatch(sql);
083 SqlStatistic.stop(mon, sql);
084 } catch (SQLException ex) {
085 throw enrichedSQLException(mon, sql, ex);
086 }
087 }
088
089 /**
090 * Cancel.
091 *
092 * @throws SQLException the sQL exception
093 * @see java.sql.Statement#cancel()
094 */
095 public final void cancel() throws SQLException {
096 statement.cancel();
097 log.trace("{} cancelled.", statement);
098 }
099
100 /**
101 * Clear batch.
102 *
103 * @throws SQLException the sQL exception
104 * @see java.sql.Statement#clearBatch()
105 */
106 public final void clearBatch() throws SQLException {
107 statement.clearBatch();
108 log.trace("Batch cleared.");
109 }
110
111 /**
112 * Clear warnings.
113 *
114 * @throws SQLException the sQL exception
115 * @see java.sql.Statement#clearWarnings()
116 */
117 public final void clearWarnings() throws SQLException {
118 statement.clearWarnings();
119 log.trace("Warnings cleared.");
120 }
121
122 /**
123 * Close.
124 *
125 * @throws SQLException the sQL exception
126 * @see java.sql.Statement#close()
127 */
128 public void close() throws SQLException {
129 statement.close();
130 log.debug("Statement {} was closed after {}.", this.statement, this.logWatch);
131 }
132
133 /**
134 * Execute.
135 *
136 * @param sql the sql
137 * @param autoGeneratedKeys the auto generated keys
138 * @return true, if successful
139 * @throws SQLException the sQL exception
140 * @see java.sql.Statement#execute(java.lang.String, int)
141 */
142 public final boolean execute(final String sql, final int autoGeneratedKeys) throws SQLException {
143 ProfileMonitor mon = SqlStatistic.start(sql);
144 try {
145 boolean ok = statement.execute(sql, autoGeneratedKeys);
146 SqlStatistic.stop(mon, sql, ok);
147 return ok;
148 } catch (SQLException ex) {
149 throw enrichedSQLException(mon, sql, ex);
150 }
151 }
152
153 /**
154 * Execute.
155 *
156 * @param sql the sql
157 * @param columnIndexes the column indexes
158 * @return true, if successful
159 * @throws SQLException the sQL exception
160 * @see java.sql.Statement#execute(java.lang.String, int[])
161 */
162 public final boolean execute(final String sql, final int[] columnIndexes) throws SQLException {
163 ProfileMonitor mon = SqlStatistic.start(sql);
164 try {
165 boolean ok = statement.execute(sql, columnIndexes);
166 SqlStatistic.stop(mon, sql, ok);
167 return ok;
168 } catch (SQLException ex) {
169 throw enrichedSQLException(mon, sql, ex);
170 }
171 }
172
173 /**
174 * Execute.
175 *
176 * @param sql the sql
177 * @param columnNames the column names
178 * @return true, if successful
179 * @throws SQLException the sQL exception
180 * @see java.sql.Statement#execute(java.lang.String, java.lang.String[])
181 */
182 public final boolean execute(final String sql, final String[] columnNames) throws SQLException {
183 ProfileMonitor mon = SqlStatistic.start(sql);
184 try {
185 boolean ok = statement.execute(sql, columnNames);
186 SqlStatistic.stop(mon, sql, ok);
187 return ok;
188 } catch (SQLException ex) {
189 throw enrichedSQLException(mon, sql, ex);
190 }
191 }
192
193 /**
194 * Execute.
195 *
196 * @param sql the sql
197 * @return true, if successful
198 * @throws SQLException the sQL exception
199 * @see java.sql.Statement#execute(java.lang.String)
200 */
201 public final boolean execute(final String sql) throws SQLException {
202 ProfileMonitor mon = SqlStatistic.start(sql);
203 try {
204 boolean ok = statement.execute(sql);
205 SqlStatistic.stop(mon, sql, ok);
206 return ok;
207 } catch (SQLException ex) {
208 throw enrichedSQLException(mon, sql, ex);
209 }
210 }
211
212 /**
213 * Execute batch.
214 *
215 * @return the int[]
216 * @throws SQLException the sQL exception
217 * @see java.sql.Statement#executeBatch()
218 */
219 public final int[] executeBatch() throws SQLException {
220 LogWatch watch = new LogWatch();
221 int[] ret = statement.executeBatch();
222 if (log.isDebugEnabled()) {
223 log.debug("Batch execution returns with {} after {}.", Converter.toString(ret), watch);
224 }
225 return ret;
226 }
227
228 /**
229 * Execute query.
230 *
231 * @param sql the sql
232 * @return the result set
233 * @throws SQLException the sQL exception
234 * @see java.sql.Statement#executeQuery(java.lang.String)
235 */
236 public final ResultSet executeQuery(final String sql) throws SQLException {
237 ProfileMonitor mon = SqlStatistic.start(sql);
238 try {
239 ResultSet rs = new StasiResultSet(statement.executeQuery(sql));
240 SqlStatistic.stop(mon, sql, rs);
241 return rs;
242 } catch (SQLException ex) {
243 throw enrichedSQLException(mon, sql, ex);
244 }
245 }
246
247 /**
248 * Execute update.
249 *
250 * @param sql the sql
251 * @param autoGeneratedKeys the auto generated keys
252 * @return the int
253 * @throws SQLException the sQL exception
254 * @see java.sql.Statement#executeUpdate(java.lang.String, int)
255 */
256 public final int executeUpdate(final String sql, final int autoGeneratedKeys) throws SQLException {
257 ProfileMonitor mon = SqlStatistic.start(sql);
258 try {
259 int ret = statement.executeUpdate(sql, autoGeneratedKeys);
260 SqlStatistic.stop(mon, sql, ret);
261 return ret;
262 } catch (SQLException ex) {
263 throw enrichedSQLException(mon, sql, ex);
264 }
265 }
266
267 /**
268 * Execute update.
269 *
270 * @param sql the sql
271 * @param columnIndexes the column indexes
272 * @return the int
273 * @throws SQLException the sQL exception
274 * @see java.sql.Statement#executeUpdate(java.lang.String, int[])
275 */
276 public final int executeUpdate(final String sql, final int[] columnIndexes) throws SQLException {
277 ProfileMonitor mon = SqlStatistic.start(sql);
278 try {
279 int ret = statement.executeUpdate(sql, columnIndexes);
280 SqlStatistic.stop(mon, sql, ret);
281 return ret;
282 } catch (SQLException ex) {
283 throw enrichedSQLException(mon, sql, ex);
284 }
285 }
286
287 /**
288 * Execute update.
289 *
290 * @param sql the sql
291 * @param columnNames the column names
292 * @return the int
293 * @throws SQLException the sQL exception
294 * @see java.sql.Statement#executeUpdate(java.lang.String, java.lang.String[])
295 */
296 public final int executeUpdate(final String sql, final String[] columnNames) throws SQLException {
297 ProfileMonitor mon = SqlStatistic.start(sql);
298 try {
299 int ret = statement.executeUpdate(sql, columnNames);
300 SqlStatistic.stop(mon, sql, ret);
301 return ret;
302 } catch (SQLException ex) {
303 throw enrichedSQLException(mon, sql, ex);
304 }
305 }
306
307 /**
308 * Execute update.
309 *
310 * @param sql the sql
311 * @return the int
312 * @throws SQLException the sQL exception
313 * @see java.sql.Statement#executeUpdate(java.lang.String)
314 */
315 public final int executeUpdate(final String sql) throws SQLException {
316 ProfileMonitor mon = SqlStatistic.start(sql);
317 try {
318 int ret = statement.executeUpdate(sql);
319 SqlStatistic.stop(mon, sql, ret);
320 return ret;
321 } catch (SQLException ex) {
322 throw enrichedSQLException(mon, sql, ex);
323 }
324 }
325
326 /**
327 * For better error analysis the original {@link SQLException} will be
328 * enriched with some additional infos.
329 *
330 * @param mon the mon
331 * @param sql the sql
332 * @param original the original
333 * @return the sQL exception
334 */
335 protected SQLException enrichedSQLException(final ProfileMonitor mon, final String sql,
336 final SQLException original) {
337 mon.stop();
338 return new SQLException("SQL \"" + sql + "\" failed after " + mon.getLastTime(), original);
339 }
340
341 /**
342 * Gets the connection.
343 *
344 * @return the connection
345 * @throws SQLException the sQL exception
346 * @see java.sql.Statement#getConnection()
347 */
348 public final Connection getConnection() throws SQLException {
349 return statement.getConnection();
350 }
351
352 /**
353 * Gets the fetch direction.
354 *
355 * @return the fetch direction
356 * @throws SQLException the sQL exception
357 * @see java.sql.Statement#getFetchDirection()
358 */
359 public final int getFetchDirection() throws SQLException {
360 return statement.getFetchDirection();
361 }
362
363 /**
364 * Gets the fetch size.
365 *
366 * @return the fetch size
367 * @throws SQLException the sQL exception
368 * @see java.sql.Statement#getFetchSize()
369 */
370 public final int getFetchSize() throws SQLException {
371 return statement.getFetchSize();
372 }
373
374 /**
375 * Gets the generated keys.
376 *
377 * @return the generated keys
378 * @throws SQLException the sQL exception
379 * @see java.sql.Statement#getGeneratedKeys()
380 */
381 public final ResultSet getGeneratedKeys() throws SQLException {
382 return new StasiResultSet(statement.getGeneratedKeys());
383 }
384
385 /**
386 * Gets the max field size.
387 *
388 * @return the max field size
389 * @throws SQLException the sQL exception
390 * @see java.sql.Statement#getMaxFieldSize()
391 */
392 public final int getMaxFieldSize() throws SQLException {
393 return statement.getMaxFieldSize();
394 }
395
396 /**
397 * Gets the max rows.
398 *
399 * @return the max rows
400 * @throws SQLException the sQL exception
401 * @see java.sql.Statement#getMaxRows()
402 */
403 public final int getMaxRows() throws SQLException {
404 return statement.getMaxRows();
405 }
406
407 /**
408 * Gets the more results.
409 *
410 * @return the more results
411 * @throws SQLException the sQL exception
412 * @see java.sql.Statement#getMoreResults()
413 */
414 public final boolean getMoreResults() throws SQLException {
415 return statement.getMoreResults();
416 }
417
418 /**
419 * Gets the more results.
420 *
421 * @param current the current
422 * @return the more results
423 * @throws SQLException the sQL exception
424 * @see java.sql.Statement#getMoreResults(int)
425 */
426 public final boolean getMoreResults(final int current) throws SQLException {
427 return statement.getMoreResults(current);
428 }
429
430 /**
431 * Gets the query timeout.
432 *
433 * @return the query timeout
434 * @throws SQLException the sQL exception
435 * @see java.sql.Statement#getQueryTimeout()
436 */
437 public final int getQueryTimeout() throws SQLException {
438 return statement.getQueryTimeout();
439 }
440
441 /**
442 * Gets the result set.
443 *
444 * @return the result set
445 * @throws SQLException the sQL exception
446 * @see java.sql.Statement#getResultSet()
447 */
448 public final ResultSet getResultSet() throws SQLException {
449 return new StasiResultSet(statement.getResultSet());
450 }
451
452 /**
453 * Gets the result set concurrency.
454 *
455 * @return the result set concurrency
456 * @throws SQLException the sQL exception
457 * @see java.sql.Statement#getResultSetConcurrency()
458 */
459 public final int getResultSetConcurrency() throws SQLException {
460 return statement.getResultSetConcurrency();
461 }
462
463 /**
464 * Gets the result set holdability.
465 *
466 * @return the result set holdability
467 * @throws SQLException the sQL exception
468 * @see java.sql.Statement#getResultSetHoldability()
469 */
470 public final int getResultSetHoldability() throws SQLException {
471 return statement.getResultSetHoldability();
472 }
473
474 /**
475 * Gets the result set type.
476 *
477 * @return the result set type
478 * @throws SQLException the sQL exception
479 * @see java.sql.Statement#getResultSetType()
480 */
481 public final int getResultSetType() throws SQLException {
482 return statement.getResultSetType();
483 }
484
485 /**
486 * Gets the update count.
487 *
488 * @return the update count
489 * @throws SQLException the sQL exception
490 * @see java.sql.Statement#getUpdateCount()
491 */
492 public final int getUpdateCount() throws SQLException {
493 return statement.getUpdateCount();
494 }
495
496 /**
497 * Gets the warnings.
498 *
499 * @return the warnings
500 * @throws SQLException the sQL exception
501 * @see java.sql.Statement#getWarnings()
502 */
503 public final SQLWarning getWarnings() throws SQLException {
504 return statement.getWarnings();
505 }
506
507 /**
508 * Checks if is closed.
509 *
510 * @return true, if is closed
511 * @throws SQLException the sQL exception
512 * @see java.sql.Statement#isClosed()
513 */
514 public final boolean isClosed() throws SQLException {
515 return statement.isClosed();
516 }
517
518 /**
519 * Checks if is poolable.
520 *
521 * @return true, if is poolable
522 * @throws SQLException the sQL exception
523 * @see java.sql.Statement#isPoolable()
524 */
525 public final boolean isPoolable() throws SQLException {
526 return statement.isPoolable();
527 }
528
529 /**
530 * Checks if is wrapper for.
531 *
532 * @param arg0 the arg0
533 * @return true, if is wrapper for
534 * @throws SQLException the sQL exception
535 * @see java.sql.Wrapper#isWrapperFor(java.lang.Class)
536 */
537 public final boolean isWrapperFor(final Class<?> arg0) throws SQLException {
538 return statement.isWrapperFor(arg0);
539 }
540
541 /**
542 * Sets the cursor name.
543 *
544 * @param name the new cursor name
545 * @throws SQLException the sQL exception
546 * @see java.sql.Statement#setCursorName(java.lang.String)
547 */
548 public final void setCursorName(final String name) throws SQLException {
549 statement.setCursorName(name);
550 }
551
552 /**
553 * Sets the escape processing.
554 *
555 * @param enable the new escape processing
556 * @throws SQLException the sQL exception
557 * @see java.sql.Statement#setEscapeProcessing(boolean)
558 */
559 public final void setEscapeProcessing(final boolean enable) throws SQLException {
560 statement.setEscapeProcessing(enable);
561 }
562
563 /**
564 * Sets the fetch direction.
565 *
566 * @param direction the new fetch direction
567 * @throws SQLException the sQL exception
568 * @see java.sql.Statement#setFetchDirection(int)
569 */
570 public final void setFetchDirection(final int direction) throws SQLException {
571 statement.setFetchDirection(direction);
572 }
573
574 /**
575 * Sets the fetch size.
576 *
577 * @param rows the new fetch size
578 * @throws SQLException the sQL exception
579 * @see java.sql.Statement#setFetchSize(int)
580 */
581 public final void setFetchSize(final int rows) throws SQLException {
582 statement.setFetchSize(rows);
583 }
584
585 /**
586 * Sets the max field size.
587 *
588 * @param max the new max field size
589 * @throws SQLException the sQL exception
590 * @see java.sql.Statement#setMaxFieldSize(int)
591 */
592 public final void setMaxFieldSize(final int max) throws SQLException {
593 statement.setMaxFieldSize(max);
594 }
595
596 /**
597 * Sets the max rows.
598 *
599 * @param max the new max rows
600 * @throws SQLException the sQL exception
601 * @see java.sql.Statement#setMaxRows(int)
602 */
603 public final void setMaxRows(final int max) throws SQLException {
604 statement.setMaxRows(max);
605 }
606
607 /**
608 * Sets the poolable.
609 *
610 * @param poolable the new poolable
611 * @throws SQLException the sQL exception
612 * @see java.sql.Statement#setPoolable(boolean)
613 */
614 public final void setPoolable(final boolean poolable) throws SQLException {
615 statement.setPoolable(poolable);
616 }
617
618 /**
619 * Sets the query timeout.
620 *
621 * @param seconds the new query timeout
622 * @throws SQLException the sQL exception
623 * @see java.sql.Statement#setQueryTimeout(int)
624 */
625 public final void setQueryTimeout(final int seconds) throws SQLException {
626 statement.setQueryTimeout(seconds);
627 }
628
629 /**
630 * Unwrap.
631 *
632 * @param <T> the generic type
633 * @param arg0 the arg0
634 * @return the t
635 * @throws SQLException the sQL exception
636 * @see java.sql.Wrapper#unwrap(java.lang.Class)
637 */
638 public final <T> T unwrap(final Class<T> arg0) throws SQLException {
639 return statement.unwrap(arg0);
640 }
641
642 /**
643 * Close on completion. This method is not required for Java 6 and below
644 * but for Java 7. To be compatible with Java 6 this method has no
645 * implementation.
646 *
647 * @throws SQLException the SQL exception
648 * @since Java 7
649 */
650 public final void closeOnCompletion() throws SQLException {
651 throw new UnsupportedOperationException("not yet implemented");
652
653 }
654
655 /**
656 * Checks if is close on completion. This method is not required for Java 6
657 * and below but for Java 7. To be compatible with Java 6 this method has no
658 * implementation.
659 *
660 * @return true, if is close on completion
661 * @throws SQLException the SQL exception
662 * @since Java 7
663 */
664 public final boolean isCloseOnCompletion() throws SQLException {
665 throw new UnsupportedOperationException("not yet implemented");
666 }
667
668 }
669