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}