1
18 package net.bull.javamelody;
19
20 import java.io.Serializable;
21 import java.lang.reflect.InvocationHandler;
22 import java.lang.reflect.InvocationTargetException;
23 import java.lang.reflect.Method;
24 import java.lang.reflect.Proxy;
25 import java.sql.Connection;
26 import java.sql.Driver;
27 import java.sql.SQLException;
28 import java.sql.Statement;
29 import java.util.ArrayList;
30 import java.util.Collections;
31 import java.util.Comparator;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.concurrent.ConcurrentHashMap;
35 import java.util.concurrent.atomic.AtomicInteger;
36 import java.util.concurrent.atomic.AtomicLong;
37
38 import javax.naming.Context;
39 import javax.naming.NamingException;
40 import javax.servlet.ServletContext;
41 import javax.sql.DataSource;
42
43 import net.bull.javamelody.internal.common.LOG;
44 import net.bull.javamelody.internal.common.Parameters;
45 import net.bull.javamelody.internal.model.ConnectionInformations;
46 import net.bull.javamelody.internal.model.Counter;
47
48
54 public final class JdbcWrapper {
55
58 public static final JdbcWrapper SINGLETON = new JdbcWrapper(
59 new Counter(Counter.SQL_COUNTER_NAME, "db.png"));
60
61
62 static final AtomicInteger ACTIVE_CONNECTION_COUNT = new AtomicInteger();
63 static final AtomicInteger USED_CONNECTION_COUNT = new AtomicInteger();
64 static final AtomicLong TRANSACTION_COUNT = new AtomicLong();
65 static final AtomicInteger ACTIVE_THREAD_COUNT = new AtomicInteger();
66 static final AtomicInteger RUNNING_BUILD_COUNT = new AtomicInteger();
67 static final AtomicInteger BUILD_QUEUE_LENGTH = new AtomicInteger();
68 static final AtomicLong BUILD_QUEUE_WAITING_DURATIONS_SUM = new AtomicLong();
69 static final Map<Integer, ConnectionInformations> USED_CONNECTION_INFORMATIONS = new ConcurrentHashMap<>();
70
71 private static final int MAX_USED_CONNECTION_INFORMATIONS = 500;
72
73
74 private final Counter sqlCounter;
75 private ServletContext servletContext;
76 private boolean connectionInformationsEnabled;
77 private boolean jboss;
78 private boolean glassfish;
79 private boolean weblogic;
80
81 static final class ConnectionInformationsComparator
82 implements Comparator<ConnectionInformations>, Serializable {
83 private static final long serialVersionUID = 1L;
84
85
86 @Override
87 public int compare(ConnectionInformations connection1, ConnectionInformations connection2) {
88 return connection1.getOpeningDate().compareTo(connection2.getOpeningDate());
89 }
90 }
91
92
95 private class StatementInvocationHandler implements InvocationHandler {
96
97
98
99
100
101
102 private String requestName;
103 private final Statement statement;
104
105 StatementInvocationHandler(String query, Statement statement) {
106 super();
107 assert statement != null;
108
109 this.requestName = query;
110 this.statement = statement;
111 }
112
113
114 @Override
115 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
116
117 final String methodName = method.getName();
118 if (isEqualsMethod(methodName, args)) {
119 return statement.equals(args[0]);
120 } else if (isHashCodeMethod(methodName, args)) {
121 return statement.hashCode();
122 } else if (methodName.startsWith("execute")) {
123 if (isFirstArgAString(args)) {
124
125
126
127 requestName = (String) args[0];
128 } else if (("executeBatch".equals(methodName)
129 || "executeLargeBatch".equals(methodName)) && requestName != null
130 && !requestName.startsWith(" ")) {
131
132
133
134
135
136 requestName = " " + requestName;
137 }
138
139
140 requestName = String.valueOf(requestName);
141
142 return doExecute(requestName, statement, method, args);
143 } else if ("addBatch".equals(methodName) && isFirstArgAString(args)) {
144
145
146
147
148
149
150
151
152
153
154 requestName = (String) args[0];
155 }
156
157
158 return method.invoke(statement, args);
159 }
160
161 private boolean isFirstArgAString(Object[] args) {
162 return args != null && args.length > 0 && args[0] instanceof String;
163 }
164 }
165
166
169 private class ConnectionInvocationHandler implements InvocationHandler {
170 private final Connection connection;
171 private boolean alreadyClosed;
172
173 ConnectionInvocationHandler(Connection connection) {
174 super();
175 assert connection != null;
176 this.connection = connection;
177 }
178
179 void init() {
180
181 if (isConnectionInformationsEnabled()
182 && USED_CONNECTION_INFORMATIONS.size() < MAX_USED_CONNECTION_INFORMATIONS) {
183 USED_CONNECTION_INFORMATIONS.put(
184 ConnectionInformations.getUniqueIdOfConnection(connection),
185 new ConnectionInformations());
186 }
187 USED_CONNECTION_COUNT.incrementAndGet();
188 TRANSACTION_COUNT.incrementAndGet();
189 }
190
191
192 @Override
193 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
194
195 final String methodName = method.getName();
196 if (isEqualsMethod(methodName, args)) {
197 return areConnectionsEquals(args[0]);
198 } else if (isHashCodeMethod(methodName, args)) {
199 return connection.hashCode();
200 }
201 try {
202 Object result = method.invoke(connection, args);
203 if (result instanceof Statement) {
204 final String requestName;
205 if ("prepareStatement".equals(methodName) || "prepareCall".equals(methodName)) {
206
207
208 requestName = (String) args[0];
209 } else {
210 requestName = null;
211 }
212 result = createStatementProxy(requestName, (Statement) result);
213 }
214 return result;
215 } finally {
216 if ("close".equals(methodName) && !alreadyClosed) {
217 USED_CONNECTION_COUNT.decrementAndGet();
218 USED_CONNECTION_INFORMATIONS
219 .remove(ConnectionInformations.getUniqueIdOfConnection(connection));
220 alreadyClosed = true;
221 }
222 }
223 }
224
225 private boolean areConnectionsEquals(Object object) {
226
227
228 if (Proxy.isProxyClass(object.getClass())) {
229 final InvocationHandler invocationHandler = Proxy.getInvocationHandler(object);
230 if (invocationHandler instanceof DelegatingInvocationHandler) {
231 final DelegatingInvocationHandler d = (DelegatingInvocationHandler) invocationHandler;
232 if (d.getDelegate() instanceof ConnectionInvocationHandler) {
233 final ConnectionInvocationHandler c = (ConnectionInvocationHandler) d
234 .getDelegate();
235 return connection.equals(c.connection);
236 }
237 }
238 }
239 return connection.equals(object);
240 }
241 }
242
243 private static class ConnectionManagerInvocationHandler
244 extends AbstractInvocationHandler<Object> {
245
246 private static final long serialVersionUID = 1L;
247
248 ConnectionManagerInvocationHandler(Object javaxConnectionManager) {
249 super(javaxConnectionManager);
250 }
251
252 @Override
253 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
254 final Object result = method.invoke(getProxiedObject(), args);
255 if (result instanceof Connection) {
256 return SINGLETON
257 .createConnectionProxyOrRewrapIfJBossOrGlassfish((Connection) result);
258 }
259 return result;
260 }
261 }
262
263 private abstract static class AbstractInvocationHandler<T>
264 implements InvocationHandler, Serializable {
265 private static final long serialVersionUID = 1L;
266
267 @SuppressWarnings("all")
268 private final T proxiedObject;
269
270 AbstractInvocationHandler(T proxiedObject) {
271 super();
272 this.proxiedObject = proxiedObject;
273 }
274
275 T getProxiedObject() {
276 return proxiedObject;
277 }
278 }
279
280
281 private static class DelegatingInvocationHandler implements InvocationHandler, Serializable {
282
283 private static final long serialVersionUID = 7515240588169084785L;
284 @SuppressWarnings("all")
285 private final InvocationHandler delegate;
286
287 DelegatingInvocationHandler(InvocationHandler delegate) {
288 super();
289 this.delegate = delegate;
290 }
291
292 InvocationHandler getDelegate() {
293 return delegate;
294 }
295
296
297 @Override
298 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
299 try {
300 return delegate.invoke(proxy, method, args);
301 } catch (final InvocationTargetException e) {
302 if (e.getTargetException() != null) {
303 throw e.getTargetException();
304 }
305 throw e;
306 }
307 }
308 }
309
310 private JdbcWrapper(Counter sqlCounter) {
311 super();
312 assert sqlCounter != null;
313 this.sqlCounter = sqlCounter;
314
315 this.servletContext = null;
316 connectionInformationsEnabled = Parameters.isSystemActionsEnabled()
317 && !Parameters.isNoDatabase();
318 }
319
320 void initServletContext(ServletContext context) {
321 assert context != null;
322 this.servletContext = context;
323 final String serverInfo = servletContext.getServerInfo();
324 jboss = serverInfo.contains("JBoss") || serverInfo.contains("WildFly");
325 glassfish = serverInfo.contains("GlassFish")
326 || serverInfo.contains("Sun Java System Application Server")
327 || serverInfo.contains("Payara");
328 weblogic = serverInfo.contains("WebLogic");
329 connectionInformationsEnabled = Parameters.isSystemActionsEnabled()
330 && !Parameters.isNoDatabase();
331 }
332
333 public static int getUsedConnectionCount() {
334 return USED_CONNECTION_COUNT.get();
335 }
336
337 public static int getActiveConnectionCount() {
338 return ACTIVE_CONNECTION_COUNT.get();
339 }
340
341 public static long getTransactionCount() {
342 return TRANSACTION_COUNT.get();
343 }
344
345 public static int getActiveThreadCount() {
346 return ACTIVE_THREAD_COUNT.get();
347 }
348
349 public static int getRunningBuildCount() {
350 return RUNNING_BUILD_COUNT.get();
351 }
352
353 public static int getBuildQueueLength() {
354 return BUILD_QUEUE_LENGTH.get();
355 }
356
357 public static long getBuildQueueWaitingDurationsSum() {
358 return BUILD_QUEUE_WAITING_DURATIONS_SUM.get();
359 }
360
361 public static List<ConnectionInformations> getConnectionInformationsList() {
362 final List<ConnectionInformations> result = new ArrayList<>(
363 USED_CONNECTION_INFORMATIONS.values());
364 Collections.sort(result, new ConnectionInformationsComparator());
365 return Collections.unmodifiableList(result);
366 }
367
368 public Counter getSqlCounter() {
369 return sqlCounter;
370 }
371
372 boolean isConnectionInformationsEnabled() {
373 return connectionInformationsEnabled;
374 }
375
376 public static int getMaxConnectionCount() {
377 return JdbcWrapperHelper.getMaxConnectionCount();
378 }
379
380 public static Map<String, Map<String, Object>> getBasicDataSourceProperties() {
381 return JdbcWrapperHelper.getBasicDataSourceProperties();
382 }
383
384 public static Map<String, DataSource> getJndiAndSpringDataSources() throws NamingException {
385 return JdbcWrapperHelper.getJndiAndSpringDataSources();
386 }
387
388
393 public static void registerSpringDataSource(String name, DataSource dataSource) {
394 JdbcWrapperHelper.registerSpringDataSource(name, dataSource);
395 }
396
397 Object doExecute(String requestName, Statement statement, Method method, Object[] args)
398 throws IllegalAccessException, InvocationTargetException {
399 assert requestName != null;
400 assert statement != null;
401 assert method != null;
402
403
404 if (!sqlCounter.isDisplayed() || requestName.startsWith("explain ")) {
405 ACTIVE_CONNECTION_COUNT.incrementAndGet();
406 try {
407 return method.invoke(statement, args);
408 } finally {
409 ACTIVE_CONNECTION_COUNT.decrementAndGet();
410 }
411 }
412
413 final long start = System.currentTimeMillis();
414 boolean systemError = true;
415 try {
416 ACTIVE_CONNECTION_COUNT.incrementAndGet();
417
418
419
420 sqlCounter.bindContext(requestName, requestName, null, -1, -1);
421
422 final Object result = method.invoke(statement, args);
423 systemError = false;
424 return result;
425 } catch (final InvocationTargetException e) {
426 if (e.getCause() instanceof SQLException) {
427 final int errorCode = ((SQLException) e.getCause()).getErrorCode();
428 if (errorCode >= 20000 && errorCode < 30000) {
429
430
431
432
433 systemError = false;
434 }
435 }
436 throw e;
437 } finally {
438
439
440
441
442
443 ACTIVE_CONNECTION_COUNT.decrementAndGet();
444 final long duration = Math.max(System.currentTimeMillis() - start, 0);
445 sqlCounter.addRequest(requestName, duration, -1, -1, systemError, -1);
446 }
447 }
448
449 boolean rebindDataSources() {
450 boolean ok;
451
452
453 try {
454 final boolean rewrapDataSources = Parameter.REWRAP_DATASOURCES.getValueAsBoolean();
455 if (rewrapDataSources || Parameter.DATASOURCES.getValue() != null) {
456
457
458 stop();
459 }
460 final Map<String, DataSource> jndiDataSources = JdbcWrapperHelper.getJndiDataSources();
461 LOG.debug("datasources found in JNDI: " + jndiDataSources.keySet());
462 for (final Map.Entry<String, DataSource> entry : jndiDataSources.entrySet()) {
463 final String jndiName = entry.getKey();
464 final DataSource dataSource = entry.getValue();
465 try {
466 if (rewrapDataSources || isServerNeedsRewrap(jndiName)) {
467 rewrapDataSource(jndiName, dataSource);
468 JdbcWrapperHelper.registerRewrappedDataSource(jndiName, dataSource);
469 } else if (!isProxyAlready(dataSource)) {
470
471 final DataSource dataSourceProxy = createDataSourceProxy(jndiName,
472 dataSource);
473 JdbcWrapperHelper.rebindDataSource(servletContext, jndiName, dataSource,
474 dataSourceProxy);
475 LOG.debug("datasource rebinded: " + jndiName + " from class "
476 + dataSource.getClass().getName() + " to class "
477 + dataSourceProxy.getClass().getName());
478 }
479 } catch (final Throwable t) {
480
481 LOG.debug("rebinding datasource " + jndiName + " failed, skipping it", t);
482 }
483 }
484 ok = true;
485 } catch (final Throwable t) {
486
487 LOG.debug("rebinding datasources failed, skipping", t);
488 ok = false;
489 }
490 return ok;
491 }
492
493 private void rewrapDataSource(String jndiName, DataSource dataSource)
494 throws IllegalAccessException {
495 final String dataSourceClassName = dataSource.getClass().getName();
496 LOG.debug("Datasource needs rewrap: " + jndiName + " of class " + dataSourceClassName);
497 final String dataSourceRewrappedMessage = "Datasource rewrapped: " + jndiName;
498 if (isJBossOrGlassfishDataSource(dataSourceClassName)) {
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513 Object javaxConnectionManager = JdbcWrapperHelper.getFieldValue(dataSource, "cm");
514 javaxConnectionManager = createJavaxConnectionManagerProxy(javaxConnectionManager);
515 JdbcWrapperHelper.setFieldValue(dataSource, "cm", javaxConnectionManager);
516 LOG.debug(dataSourceRewrappedMessage);
517 } else if (isWildfly9DataSource(dataSourceClassName)) {
518 Object delegateDataSource = JdbcWrapperHelper.getFieldValue(dataSource, "delegate");
519 delegateDataSource = createDataSourceProxy((DataSource) delegateDataSource);
520 JdbcWrapperHelper.setFieldValue(dataSource, "delegate", delegateDataSource);
521 LOG.debug(dataSourceRewrappedMessage);
522 } else if (weblogic
523 && "weblogic.jdbc.common.internal.RmiDataSource".equals(dataSourceClassName)) {
524
525
526 rewrapWebLogicDataSource(dataSource);
527 LOG.debug(dataSourceRewrappedMessage);
528 } else if (isDbcpDataSource(dataSourceClassName)) {
529
530
531
532
533
534
535
536 rewrapBasicDataSource(dataSource);
537 LOG.debug(dataSourceRewrappedMessage);
538 } else if ("org.apache.openejb.resource.jdbc.managed.local.ManagedDataSource"
539 .equals(dataSourceClassName)) {
540
541 rewrapTomEEDataSource(dataSource);
542 LOG.debug(dataSourceRewrappedMessage);
543 } else {
544 LOG.info("Datasource can't be rewrapped: " + jndiName + " of class "
545 + dataSourceClassName);
546 }
547 }
548
549 private boolean isServerNeedsRewrap(String jndiName) {
550 return glassfish || jboss || weblogic || jndiName.contains("openejb");
551 }
552
553 private boolean isDbcpDataSource(String dataSourceClassName) {
554 return "org.apache.tomcat.dbcp.dbcp.BasicDataSource".equals(dataSourceClassName)
555 || "org.apache.tomcat.dbcp.dbcp2.BasicDataSource".equals(dataSourceClassName)
556 || "org.apache.commons.dbcp.BasicDataSource".equals(dataSourceClassName)
557 || "org.apache.commons.dbcp2.BasicDataSource".equals(dataSourceClassName)
558 || "org.apache.openejb.resource.jdbc.BasicManagedDataSource"
559 .equals(dataSourceClassName)
560 || "org.apache.openejb.resource.jdbc.BasicDataSource".equals(dataSourceClassName);
561 }
562
563 private boolean isJBossOrGlassfishDataSource(String dataSourceClassName) {
564 return jboss
565 && "org.jboss.resource.adapter.jdbc.WrapperDataSource".equals(dataSourceClassName)
566 || jboss && "org.jboss.jca.adapters.jdbc.WrapperDataSource"
567 .equals(dataSourceClassName)
568 || glassfish && "com.sun.gjc.spi.jdbc40.DataSource40".equals(dataSourceClassName);
569 }
570
571 private boolean isWildfly9DataSource(String dataSourceClassName) {
572 return jboss && "org.jboss.as.connector.subsystems.datasources.WildFlyDataSource"
573 .equals(dataSourceClassName);
574 }
575
576 private void rewrapWebLogicDataSource(DataSource dataSource) throws IllegalAccessException {
577 if (JdbcWrapperHelper.hasField(dataSource, "delegate")) {
578
579 final Object delegate = JdbcWrapperHelper.getFieldValue(dataSource, "delegate");
580 rewrapWebLogicDataSource((DataSource) delegate);
581 } else {
582 Object jdbcCtx = JdbcWrapperHelper.getFieldValue(dataSource, "jdbcCtx");
583 if (jdbcCtx != null) {
584 jdbcCtx = createContextProxy((Context) jdbcCtx);
585 JdbcWrapperHelper.setFieldValue(dataSource, "jdbcCtx", jdbcCtx);
586 }
587 Object driverInstance = JdbcWrapperHelper.getFieldValue(dataSource, "driverInstance");
588 if (driverInstance != null) {
589 driverInstance = createDriverProxy((Driver) driverInstance);
590 JdbcWrapperHelper.setFieldValue(dataSource, "driverInstance", driverInstance);
591 }
592 }
593 }
594
595 private void rewrapBasicDataSource(DataSource dataSource) throws IllegalAccessException {
596
597
598
599 try {
600 dataSource.getConnection().close();
601 } catch (final Exception e) {
602 LOG.debug(e.toString());
603
604
605 }
606 Object innerDataSource = JdbcWrapperHelper.getFieldValue(dataSource, "dataSource");
607 if (innerDataSource != null) {
608 innerDataSource = createDataSourceProxy((DataSource) innerDataSource);
609 JdbcWrapperHelper.setFieldValue(dataSource, "dataSource", innerDataSource);
610 }
611 }
612
613 private void rewrapTomEEDataSource(DataSource dataSource) throws IllegalAccessException {
614
615
616
617 try {
618 dataSource.getConnection().close();
619 } catch (final Exception e) {
620 LOG.debug(e.toString());
621
622
623 }
624 Object innerDataSource = JdbcWrapperHelper.getFieldValue(dataSource, "delegate");
625 if (innerDataSource != null) {
626 innerDataSource = createDataSourceProxy((DataSource) innerDataSource);
627 JdbcWrapperHelper.setFieldValue(dataSource, "delegate", innerDataSource);
628 }
629 }
630
631 boolean stop() {
632 boolean ok;
633 try {
634 JdbcWrapperHelper.rebindInitialDataSources(servletContext);
635
636
637 final Map<String, DataSource> rewrappedDataSources = JdbcWrapperHelper
638 .getRewrappedDataSources();
639 for (final Map.Entry<String, DataSource> entry : rewrappedDataSources.entrySet()) {
640 final String jndiName = entry.getKey();
641 final DataSource dataSource = entry.getValue();
642 unwrapDataSource(jndiName, dataSource);
643 }
644 rewrappedDataSources.clear();
645
646 JdbcWrapperHelper.clearProxyCache();
647
648 ok = true;
649 } catch (final Throwable t) {
650
651 LOG.debug("rebinding initial datasources failed, skipping", t);
652 ok = false;
653 }
654 return ok;
655 }
656
657 private void unwrapDataSource(String jndiName, DataSource dataSource)
658 throws IllegalAccessException {
659 final String dataSourceClassName = dataSource.getClass().getName();
660 LOG.debug("Datasource needs unwrap: " + jndiName + " of class " + dataSourceClassName);
661 final String dataSourceUnwrappedMessage = "Datasource unwrapped: " + jndiName;
662 if (isJBossOrGlassfishDataSource(dataSourceClassName)) {
663 unwrap(dataSource, "cm", dataSourceUnwrappedMessage);
664 } else if (isWildfly9DataSource(dataSourceClassName)) {
665 unwrap(dataSource, "delegate", dataSourceUnwrappedMessage);
666 } else if (weblogic
667 && "weblogic.jdbc.common.internal.RmiDataSource".equals(dataSourceClassName)) {
668 if (JdbcWrapperHelper.hasField(dataSource, "delegate")) {
669
670 final Object delegate = JdbcWrapperHelper.getFieldValue(dataSource, "delegate");
671 unwrap(delegate, "jdbcCtx", dataSourceUnwrappedMessage);
672 unwrap(delegate, "driverInstance", dataSourceUnwrappedMessage);
673 } else {
674 unwrap(dataSource, "jdbcCtx", dataSourceUnwrappedMessage);
675 unwrap(dataSource, "driverInstance", dataSourceUnwrappedMessage);
676 }
677 } else if (isDbcpDataSource(dataSourceClassName)) {
678 unwrap(dataSource, "dataSource", dataSourceUnwrappedMessage);
679 }
680 }
681
682 private void unwrap(Object parentObject, String fieldName, String unwrappedMessage)
683 throws IllegalAccessException {
684 final Object proxy = JdbcWrapperHelper.getFieldValue(parentObject, fieldName);
685 if (Proxy.isProxyClass(proxy.getClass())) {
686 InvocationHandler invocationHandler = Proxy.getInvocationHandler(proxy);
687 if (invocationHandler instanceof DelegatingInvocationHandler) {
688 invocationHandler = ((DelegatingInvocationHandler) invocationHandler).getDelegate();
689 if (invocationHandler instanceof AbstractInvocationHandler) {
690 final Object proxiedObject = ((AbstractInvocationHandler<?>) invocationHandler)
691 .getProxiedObject();
692 JdbcWrapperHelper.setFieldValue(parentObject, fieldName, proxiedObject);
693 LOG.debug(unwrappedMessage);
694 }
695 }
696 }
697 }
698
699 Context createContextProxy(final Context context) {
700 assert context != null;
701 final InvocationHandler invocationHandler = new AbstractInvocationHandler<Context>(
702 context) {
703 private static final long serialVersionUID = 1L;
704
705
706 @Override
707 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
708 Object result = method.invoke(context, args);
709 if (result instanceof DataSource) {
710 result = createDataSourceProxy((DataSource) result);
711 }
712 return result;
713 }
714 };
715 return createProxy(context, invocationHandler);
716 }
717
718
719 private Driver createDriverProxy(final Driver driver) {
720 assert driver != null;
721 final InvocationHandler invocationHandler = new AbstractInvocationHandler<Driver>(driver) {
722 private static final long serialVersionUID = 1L;
723
724
725 @Override
726 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
727 Object result = method.invoke(driver, args);
728 if (result instanceof Connection) {
729 result = createConnectionProxy((Connection) result);
730 }
731 return result;
732 }
733 };
734 return createProxy(driver, invocationHandler);
735 }
736
737
738 private Object createJavaxConnectionManagerProxy(Object javaxConnectionManager) {
739 assert javaxConnectionManager != null;
740 final InvocationHandler invocationHandler = new ConnectionManagerInvocationHandler(
741 javaxConnectionManager);
742 return createProxy(javaxConnectionManager, invocationHandler);
743 }
744
745 void rewrapConnection(Connection connection) throws IllegalAccessException {
746 assert connection != null;
747 if (jboss && connection.getClass().getSimpleName().startsWith("WrappedConnection")) {
748
749
750
751 final Object baseWrapperManagedConnection = JdbcWrapperHelper.getFieldValue(connection,
752 "mc");
753 final String conFieldName = "con";
754 Connection con = (Connection) JdbcWrapperHelper
755 .getFieldValue(baseWrapperManagedConnection, conFieldName);
756
757 if (!isProxyAlready(con)) {
758 con = createConnectionProxy(con);
759 JdbcWrapperHelper.setFieldValue(baseWrapperManagedConnection, conFieldName, con);
760 }
761 } else if (glassfish && ("com.sun.gjc.spi.jdbc40.ConnectionHolder40"
762 .equals(connection.getClass().getName())
763 || "com.sun.gjc.spi.jdbc40.ConnectionWrapper40"
764 .equals(connection.getClass().getName()))) {
765
766
767
768
769 final String conFieldName = "con";
770 Connection con = (Connection) JdbcWrapperHelper.getFieldValue(connection, conFieldName);
771
772 if (!isProxyAlready(con)) {
773 con = createConnectionProxy(con);
774 JdbcWrapperHelper.setFieldValue(connection, conFieldName, con);
775 }
776 }
777 }
778
779
784 public DataSource createDataSourceProxy(DataSource dataSource) {
785 return createDataSourceProxy(null, dataSource);
786 }
787
788
794 public DataSource createDataSourceProxy(String name, final DataSource dataSource) {
795 assert dataSource != null;
796 JdbcWrapperHelper.pullDataSourceProperties(name, dataSource);
797 final InvocationHandler invocationHandler = new AbstractInvocationHandler<DataSource>(
798 dataSource) {
799 private static final long serialVersionUID = 1L;
800
801
802 @Override
803 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
804 Object result = method.invoke(dataSource, args);
805 if (result instanceof Connection) {
806 result = createConnectionProxy((Connection) result);
807 }
808 return result;
809 }
810 };
811 return createProxy(dataSource, invocationHandler);
812 }
813
814 Connection createConnectionProxyOrRewrapIfJBossOrGlassfish(Connection connection)
815 throws IllegalAccessException {
816 if (jboss || glassfish) {
817 rewrapConnection(connection);
818 return connection;
819 }
820 return createConnectionProxy(connection);
821 }
822
823
828 public Connection createConnectionProxy(Connection connection) {
829 assert connection != null;
830
831
832 if (isMonitoringDisabled()) {
833 return connection;
834 }
835 final ConnectionInvocationHandler invocationHandler = new ConnectionInvocationHandler(
836 connection);
837 final Connection result = createProxy(connection, invocationHandler);
838 if (result != connection) {
839 invocationHandler.init();
840 }
841 return result;
842 }
843
844 boolean isSqlMonitoringDisabled() {
845 return isMonitoringDisabled() || !sqlCounter.isDisplayed();
846 }
847
848 private static boolean isMonitoringDisabled() {
849
850
851 return Parameter.DISABLED.getValueAsBoolean();
852 }
853
854 Statement createStatementProxy(String query, Statement statement) {
855 assert statement != null;
856
857
858
859
860
861
862
863
864 final InvocationHandler invocationHandler = new StatementInvocationHandler(query,
865 statement);
866 return createProxy(statement, invocationHandler);
867 }
868
869 static boolean isEqualsMethod(Object methodName, Object[] args) {
870
871 return "equals" == methodName && args != null && args.length == 1;
872 }
873
874 static boolean isHashCodeMethod(Object methodName, Object[] args) {
875
876 return "hashCode" == methodName && (args == null || args.length == 0);
877 }
878
879 static <T> T createProxy(T object, InvocationHandler invocationHandler) {
880 return createProxy(object, invocationHandler, null);
881 }
882
883 static <T> T createProxy(T object, InvocationHandler invocationHandler,
884 List<Class<?>> interfaces) {
885 if (isProxyAlready(object)) {
886
887
888
889 return object;
890 }
891 final InvocationHandler ih = new DelegatingInvocationHandler(invocationHandler);
892 return JdbcWrapperHelper.createProxy(object, ih, interfaces);
893 }
894
895 static boolean isProxyAlready(Object object) {
896 return Proxy.isProxyClass(object.getClass()) && Proxy.getInvocationHandler(object)
897 .getClass().getName().equals(DelegatingInvocationHandler.class.getName());
898
899
900
901 }
902
903 }
904