0 Replies Latest reply on Mar 21, 2013 11:58 AM by him-bhar

    Datasource in JBoss not picking the right class

    him-bhar

      Hi All,

       

      I am facing a very weird problem using JBoss 6.

      The problem is basically I have configured, a data source in standalone.xml

                  <datasource jndi-name="java:jboss/jdbc/ejb/testconn" pool-name="test-cluster-Pool" enabled="true" use-java-context="true">
                     
      <connection-url>jdbc:sqlserver://127.0.0.1:1433;databaseName=testdb;</connection-url>
                     
      <driver>sqlserver-jdbc</driver>
                     
      <pool>
                         
      <min-pool-size>10</min-pool-size>
                         
      <max-pool-size>100</max-pool-size>
                         
      <prefill>true</prefill>
                     
      </pool>
                     
      <security>
                         
      <user-name>sa</user-name>
                         
      <password>sa</password>
                     
      </security>
                     
      <statement>
                         
      <prepared-statement-cache-size>32</prepared-statement-cache-size>
                         
      <share-prepared-statements>true</share-prepared-statements>
                     
      </statement>
                 
      </datasource>

       

      This is the configuration of the driver, I have installed the same as a module:

       

                  <drivers>
                     
      <driver name="h2" module="com.h2database.h2">
                         
      <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
                     
      </driver>
                     
      <driver name="sqlserver-jdbc" module="com.himanshu.jdbc">
                         
      <datasource-class>com.himanshu.jdbcdriver.datasource.DataSource</datasource-class>
                     
      </driver>
                 
      </drivers>

       

      com.himanshu.jdbcdriver.datasource.DataSource class basically extends com.microsoft.sqlserver.jdbc.SQLServerDataSource:

      But when I run a test, I can conclude that its not using the datasource-class that I have mentioned. Because for the two method,

       

      @Override
      public Connection getConnection() throws SQLServerException {
         
      System.out.println("TRYING TO GET CONNECTION");
         
      return null;
      }

      @Override
      public Connection getConnection(String arg0, String arg1)
             
      throws SQLServerException {
         
      System.out.println("TRYING TO GET CONNECTION");
         
      return null;
      }

      And so Ideally the connection should have returned null, but neither the connection is returned as null nor I get these SOP printed, so can't understand where I am actually wrong.

       

      DId more analysis to the issue:

       

       

       

      Use Case: Implemented a custom datasource for some extension purposes over sqljdbc4.jar (JDBC-4 compliant).

      Now when configuring the datasource, the module was loaded successfully, the configuration used in standalone.xml:

          <datasource jta="true" jndi-name="java:jboss/datasources/ejb/testdbjndi" pool-name="test-cluster-Pool" enabled="true" use-java-context="true" use-ccm="false">
      <connection-url>jdbc:sqlserver://localhost:1433;databaseName=cm-6.5;</connection-url>
      <datasource-class>com.himanshu.jdbcdriver.datasource.DataSource</datasource-class>
      <connection-property name="serverName">
      <!-- IP of the database server -->
      </connection-property>
      <driver>test-jdbc</driver>
      <new-connection-sql>SET DATEFIRST 1</new-connection-sql>
      <pool>
      <min-pool-size>10</min-pool-size>
      <max-pool-size>100</max-pool-size>
      <prefill>false</prefill>
      </pool>
      <security>
      <user-name>sa</user-name>
      <password>sa</password>
      </security>
      <statement>
      <prepared-statement-cache-size>32</prepared-statement-cache-size>
      <share-prepared-statements>true</share-prepared-statements>
      </statement>
      </datasource>

          <driver name="test-jdbc" module="com.himanshu.jdbc"/>

      Now on doing testing the connections were successfully established and queries were getting executed.

      But it turns out the my custom datasource class is not used, rather the connection is made via driverClass, DriverManager.getConnection() kind of method.

      On debugging code for ironjacamar:

      org.jboss.ironjacamar
      ironjacamar-jdbc
      1.0.13.Final-redhat-1

      On looking code for "org.jboss.jca.adapters.jdbc.local.LocalManagedConnectionFactory", it turns out that both the driverClass property (META-INF/services/java.sql.driver file) and dataSourceClass property (from standalone.xml) is read.

      Now the way connection is made is bit confusing here.

      Looking into method:  private LocalManagedConnection getLocalManagedConnection(Properties props, Properties copy); in class
      "LocalManagedConnectionFactory"

      private LocalManagedConnection getLocalManagedConnection(Properties props, Properties copy)
      throws ResourceException
      {
      Connection con = null;
      try
      {
      if (driverClass != null)

      { String url = getConnectionURL(); Driver d = getDriver(url); con = d.connect(url, copy); if (con == null) throw new ResourceException("Wrong driver class [" + d.getClass() + "] for this connection URL [" + url + "]"); }

               else

      { DataSource d = getDataSource(); con = d.getConnection(copy.getProperty("user"), copy.getProperty("password")); if (con == null) throw new ResourceException("Unable to create connection from datasource"); } 

               return new LocalManagedConnection(this, con, props, transactionIsolation, preparedStatementCacheSize);
      }
      catch (Throwable e)
      {
      if (con != null)
      {
      try

      { con.close(); }

                  catch (Throwable ignored)

      { // Ignore }

               }
      throw new ResourceException("Could not create connection", e);
      }
      }

      Now the if-else block condition here is difficult to understand:

      If I have driverClass available then all the connections are made via driverClass property, even if I mention datasourceClass or not.

      This is because the first if condition always checks for driverClass the dataSourceClass check never executes.

      So the question is how this can be avoided, becuase the DriverClass is picked automatically from the java.sql.driver file (being JDBC-4 compliant).

      If there is no configuration for the same for giving priority to datasource class or explicitly setting the driver class to null, then definitely something's amiss.

       

      Now the question is there any way I can make sure that dataSourceClass is used for making connections rather than the driverClass