Coverage Report - net.admin4j.jdbc.driver.Admin4jJdbcDriverJdk5Base
 
Classes in this File Line Coverage Branch Coverage Complexity
Admin4jJdbcDriverJdk5Base
57%
32/56
46%
12/26
3.111
 
 1  
 /*
 2  
  * This software is licensed under the Apache License, Version 2.0
 3  
  * (the "License") agreement; you may not use this file except in compliance with
 4  
  * the License.  You may obtain a copy of the License at
 5  
  * 
 6  
  *      http://www.apache.org/licenses/LICENSE-2.0
 7  
  * 
 8  
  * Unless required by applicable law or agreed to in writing, software
 9  
  * distributed under the License is distributed on an "AS IS" BASIS,
 10  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 11  
  * See the License for the specific language governing permissions and
 12  
  * limitations under the License.
 13  
  */
 14  
 package net.admin4j.jdbc.driver;
 15  
 
 16  
 import java.sql.Connection;
 17  
 import java.sql.Driver;
 18  
 import java.sql.DriverManager;
 19  
 import java.sql.DriverPropertyInfo;
 20  
 import java.sql.SQLException;
 21  
 import java.util.Properties;
 22  
 import java.util.StringTokenizer;
 23  
 
 24  
 import net.admin4j.deps.commons.lang3.StringUtils;
 25  
 import net.admin4j.deps.commons.lang3.Validate;
 26  
 import net.admin4j.jdbc.driver.sql.SQLWrappingUtils;
 27  
 import net.admin4j.util.Admin4jRuntimeException;
 28  
 import net.admin4j.util.annotate.PackageRestrictions;
 29  
 
 30  
 /**
 31  
  * Proxy JDBC driver that allows JMX view into JDBC connection content and tracks
 32  
  * SQL statement performance.
 33  
  * 
 34  
  * <p>The connection URL for this driver is in the following format:</p>
 35  
  * <pre>
 36  
  *         jdbcx:admin4j:[admin4J properties]::[underlying driver URL]
 37  
  * </pre>
 38  
  * <p>For example:</p>
 39  
  * <pre>
 40  
  *         jdbcx:admin4j:driver=org.hsqldb.jdbcDriver,poolName=mainPoolDB::jdbc:hsqldb:mem:Admin4JTestDb
 41  
  * </pre>
 42  
  * 
 43  
  * <p>Supported Admin4J driver properties are the following:</p>
 44  
  * <li>driver - Required.  Class name of the underlying JDBC driver</li>
 45  
  * <li>poolName - Optional.  Default none.  Name of the connection pool to which this driver is being assigned.  
 46  
  * This is displayed with performance metrics.</li>
 47  
  * <li>stackTrace - Optional (true/false).  Default true.  Specifies if execution stack traces are tracked so you know where
 48  
  * in your code a SQL statement is being executed.  Tests show setting to false will save 
 49  
  * approximately 1 millisecond per seven SQL Statement executions.</li>
 50  
  * 
 51  
  * <p>Top resource intensive SQL statements can be browsed via the SqlDisplayServlet.  By default, the top 50
 52  
  * statements are shown.  This is configurable (see PropertyConfigurator)</p>
 53  
  * 
 54  
  * <p>Connection activity is also viewable via JMX or via the JmxServlet.</p>
 55  
  * 
 56  
  * <p>This driver honors the following configuration settings (see PropertyConfigurator):</p>
 57  
  * <li>sql.nbr.retained.sql.statements</li>
 58  
  * <li>sql.retention.time.in.millis</li>
 59  
  * 
 60  
  * @author D. Ashmore
 61  
  * @since 1.0
 62  
  * @see net.admin4j.ui.servlets.SqlDisplayServlet
 63  
  * @see net.admin4j.ui.servlets.JmxServlet
 64  
  * @see net.admin4j.ui.config.PropertyConfigurator
 65  
  */
 66  
 @PackageRestrictions({"net.admin4j","java","javax"})
 67  
 public abstract class Admin4jJdbcDriverJdk5Base implements Driver {
 68  
         
 69  
         private static final String URL_PREFIX="jdbcx:admin4j:";
 70  
         private static final String URL_SEPARATOR="::";
 71  
         
 72  6
         private static boolean inUse = false;
 73  
 
 74  24
         public Admin4jJdbcDriverJdk5Base() {
 75  
             
 76  
                 try {
 77  24
                     if (DriverManager.getLogWriter() != null) {
 78  0
                         DriverManager.getLogWriter().println("Admin4jJdbcDriver initialization started.");
 79  
                     }
 80  24
                         DriverManager.registerDriver(this);
 81  24
                         Admin4jJdbcJmxMBean.registerMBean();
 82  24
                         if (DriverManager.getLogWriter() != null) {
 83  0
                             DriverManager.getLogWriter().println("Admin4jJdbcDriver initialization finished.");
 84  
                         }
 85  
                         
 86  24
                         inUse = true;
 87  0
                 } catch (SQLException e) {
 88  0
                         throw new RuntimeException("Cannot register driver", e);
 89  24
                 }
 90  24
         }
 91  
 
 92  
         public boolean acceptsURL(String url) throws SQLException {
 93  0
                 return !StringUtils.isEmpty(url) && url.startsWith(URL_PREFIX) && url.indexOf(URL_SEPARATOR) > 0;
 94  
         }
 95  
 
 96  
         public Connection connect(String url, Properties info) throws SQLException {
 97  
             Validate.notEmpty(url, "Null of blank url not allowed.");
 98  
                 Validate.isTrue(this.acceptsURL(url), "Url not accepted by this driver.  url=" + url);
 99  15
                 String configSpec=url.substring(URL_PREFIX.length(), url.indexOf(URL_SEPARATOR));
 100  15
                 String driverUrlSpec=url.substring(url.indexOf(URL_SEPARATOR) + 2);
 101  15
                 Properties config = this.findDriverProperties(configSpec);
 102  15
                 String poolName = config.getProperty("poolName");
 103  15
                 String stackTraceStr = config.getProperty("stackTrace");
 104  15
                 String driverName = config.getProperty("driver");
 105  
                 
 106  0
                 Validate.isTrue( !config.contains("driver"), "Url doesn't contain driver spec listing class name for JDBC driver.");
 107  
                 
 108  15
                 Driver driver = null;
 109  
                 
 110  
                 try {
 111  15
                         driver = (Driver)Class.forName(driverName).newInstance();
 112  0
                 } catch (Exception e) {
 113  0
                         throw new RuntimeException(e);
 114  15
                 }
 115  
                 
 116  15
                 DriverContext driverContext = new DriverContextImpl(driverName, driver.getMajorVersion(), driver.getMinorVersion(), poolName);
 117  0
                 if ( !StringUtils.isEmpty(stackTraceStr) && !DriverContextRegistry.hasSettings(driverContext)) {
 118  0
                     DriverContextRegistry.setTrackExecutionStacks(driverContext, Boolean.parseBoolean(stackTraceStr));
 119  
                 }
 120  
                 
 121  
             try {
 122  15
             Connection wrappedConnection =  (Connection)SQLWrappingUtils.wrap(driver.connect(driverUrlSpec, info));
 123  15
             SQLWrappingUtils.encodeDriverContext(wrappedConnection
 124  
                     , driverName
 125  
                     , poolName
 126  
                     , driver.getMajorVersion()
 127  
                     , driver.getMinorVersion());
 128  
             
 129  15
             return wrappedConnection;
 130  0
         } catch (Exception e) {
 131  0
            if (e instanceof SQLException) {
 132  0
                throw (SQLException)e;
 133  
            }
 134  
            
 135  0
            Admin4jRuntimeException ae = null;
 136  0
            if (e instanceof Admin4jRuntimeException) {
 137  0
                ae = (Admin4jRuntimeException)e;
 138  
            }
 139  
            else {
 140  0
                ae = new Admin4jRuntimeException("Error creating connection");
 141  
            }
 142  
            throw ae
 143  
                .addContextValue("driverUrlSpec", driverUrlSpec)
 144  
                .addContextValue("info", info)
 145  
                .addContextValue("url", url);
 146  
         } 
 147  
 
 148  
         }
 149  
         
 150  
         private Properties findDriverProperties(String spec) {
 151  15
                 Properties props = new Properties();
 152  
                 
 153  15
                 StringTokenizer allPropToken = new StringTokenizer(spec, ",");
 154  
                 StringTokenizer propToken;
 155  
                 String key,value;
 156  42
                 while (allPropToken.hasMoreTokens()) {
 157  27
                         propToken = new StringTokenizer(allPropToken.nextToken(), "="); 
 158  27
                         if (propToken.hasMoreTokens()) {
 159  27
                                 key = propToken.nextToken();
 160  
                         }
 161  0
                         else key = "";
 162  
                         
 163  27
                         if (propToken.hasMoreTokens()) {
 164  27
                                 value = propToken.nextToken();
 165  
                         }
 166  0
                         else value="";
 167  27
                         props.put(key, value);
 168  
                 }
 169  
                 
 170  15
                 return props;
 171  
         }
 172  
 
 173  
         public int getMajorVersion() {
 174  0
                 return 0;
 175  
         }
 176  
 
 177  
         public int getMinorVersion() {
 178  0
                 return 1;
 179  
         }
 180  
 
 181  
         public DriverPropertyInfo[] getPropertyInfo(String url, Properties info)
 182  
                         throws SQLException {
 183  0
                 return new DriverPropertyInfo[0];
 184  
         }
 185  
 
 186  
         public boolean jdbcCompliant() {
 187  0
                 return false;
 188  
         }
 189  
 
 190  
     public static boolean isInUse() {
 191  0
         return inUse;
 192  
     }
 193  
 
 194  
 }