0 Replies Latest reply on Jul 25, 2013 4:01 AM by Gareth Eley

    Can AS7 deploy Derby 'embedded' and 'client' application datasources concurrently?

    Gareth Eley Newbie

      Hi all,

       

      I've come across an issue that causes deployment failure to JBoss As 7.1.1.FINAL with the simplest of applications initially generated form the 'jboss-javaee6-webapp-archetype'.

       

      When two applications are developed both with Derby datasources configurations where one is configured for an 'embedded' datasource and the other configured for a 'client' datasource - the second application to be deployed always fails.

       

      I've attached a zip file containing both my Eclipse (4.3) projects plus the necessary JBoss configuration files but not the Derby jars as those will need to be specific to your own install and will need to be copied from your derby/bin directory into the appropriate 'modules' directory of your AS7 install itself.

       

      Here are the configuration changes required to expose the issue to reproduce without looking at the zip file:

       

      File: standalone.xml add "derby-mem" and "derby-client" driver elements shown here:

       

       

       

      {code:xml}

      <subsystem xmlns="urn:jboss:domain:datasources:1.0">

          <datasources>

              <drivers>

                  <driver name="h2" module="com.h2database.h2">

                      <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>

                  </driver>

                  <driver name="derby-mem" module="org.apache.derby.mem"/>

                  <driver name="derby-client" module="org.apache.derby.client"/>

              </drivers>

          </datasources>

      </subsystem>

      {code}

       

      ...I chose this configuration as different driver classes are required to use Derby against either an 'embedded' or 'server' instance.

       

      An 'embedded' (or in memory database) datasource requires this jar: derby.jar

       

      modules\org\apache\derby\mem\main\module.xml file is therefore:

       

      {code:xml}

      <module xmlns="urn:jboss:module:1.0" name="org.apache.derby.mem">

          <resources>

              <resource-root path="derby.jar"/>

          </resources>

          <dependencies>

              <module name="javax.api"/>

              <module name="javax.transaction.api"/>

              <module name="javax.servlet.api" optional="true"/>

          </dependencies>

      </module>

      {code}

       

      A 'client' (where you needed to have started a independent Derby 'server' instance running) datasource requires this jar: derbyclient.jar

       

      modules\org\apache\derby\client\main\module.xml file is therefore:

       

      {code:xml}

      <module xmlns="urn:jboss:module:1.0" name="org.apache.derby.client">

          <resources>

              <resource-root path="derbyclient.jar"/>

          </resources>

          <dependencies>

              <module name="javax.api"/>

              <module name="javax.transaction.api"/>

              <module name="javax.servlet.api" optional="true"/>

          </dependencies>

      </module>

      {code}

       

      My datasource -DS.xml file for the 'embedded' application contains this configuration:

       

      {code:xml}

      <datasources>

          <datasource jndi-name="java:jboss/datasources/Derby-embeddedDS" pool-name="Derby-embedded"

              enabled="true" use-java-context="true">

              <connection-url>jdbc:derby:derby-embeddedDB;create=true</connection-url>

              <driver>derby-mem</driver>

              <security>

                  <user-name>user</user-name>

                  <password>password</password>

              </security>

          </datasource>

      </datasources>

      {code}

       

      My datasource -DS.xml file for the 'client' application looks like this:

       

      {code:xml}

      <datasources>

          <datasource jndi-name="java:jboss/datasources/Derby-clientDS" pool-name="Derby-client"

              enabled="true" use-java-context="true">

              <connection-url>jdbc:derby://localhost:1527/derby-serverDB;create=true</connection-url>

              <driver>derby-client</driver>

              <security>

                  <user-name>user</user-name>

                  <password>password</password>

              </security>

          </datasource>

      </datasources>

      {code}
       

       

      Individually both applications can be deployed and executed successfully on the Server - but never together. The second application to be deployed always fails with a stacktrace message as follows:

       

      If Derby-client is deployed successfully first, deploying Derby-embedded second receives this error:

       

      Wrong driver class [class org.apache.derby.jdbc.ClientDriver] for this connection URL [jdbc:derby:derby-embeddedDB;create=true]

       

      If Derby-embedded is deployed successfully first, deploying Derby-client second receives this error:

       

      Wrong driver class [class org.apache.derby.jdbc.AutoloadedDriver] for this connection URL [jdbc:derby://localhost:1527/derby-serverDB;create=true]

       

       

      ...I've traced the problem to class LocalManagedConnectionFactory (package: org.jboss.jca.adapters.jdbc.local within ironjacamar-jdbc-1.0.9.Final.jar) but whether this behaviour is by design or is perhaps a genuine problem - I'm not sure so this is why I'm posting this question...

       

       

      With the connection-uls's shown above in the -DS.xml files, both result in the same 'key' of "jdbc:derby" being produced by this code:

       

       

      {code}
      private
      static Map<String, Driver> driverCache = new ConcurrentHashMap<String, Driver>();

      .

      .

      .

      String driverKey = url.substring(0, url.indexOf(":", 6));

       

      // Check if the driver is already loaded, if not then try to load it

      driver = driverCache.get(driverKey);


      {code}

       

       

      ...so only the first connection configuration processed by the Server actually makes it into the driverCache map. The second configuration processed is simply discarded as the driverCashe believes it already holds this configuration...but it does not.

       

      The Server deployment software eventually tries to establish the database connection for the second application using the defined connection-url but retrieves the driver class from driverCache with a 'key' of "jdbc:derby" which holds the driver class for the first deployed datasource....not the datasource the second application needs and now we get our deployment failure and the anticipated stacktrace.

       

      My initial thoughts are that this is simply a coding issue where the 'key' of the driverCache map is just not granular enough (to distinguish between datasource modules and/or 'embedded' or 'Client/server' connections) as both the Derby connection-url's result in the same key' of "jdbc:derby" being generated.

       

      Not being familiar with the specifics of datasource configuration perhaps it's just not possible to deploy both an 'embedded' and a 'Client/server' datasource from the same vendor to a JBoss AS7 instance unless their connection-url signatures are quite different...???