Thursday, August 13, 2009

How to convert a web application using a datasource defined in Tomcat's context.xml into a web application running on Jboss and using an internal one

Example is for an Oracle Datasource and a MyApp web application, but is identical for other vendor types/web applications.

Initial situation on Tomcat 6

  • JDBC driver in $TOMCAT/lib

  • context.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <Context path="/MyApp">
    <Loader delegate="true"/>

    <!-- Name must match resource-ref in web.xml and bean with id="datasource" in applicationContext.xml!
    <Resource name="jdbc/MyDs"
    auth="Container" type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver"
    url="jdbc:oracle:thin:@192.168.0.107:1521:XE" username="vatengine" password="vatengine"
    removeAbandoned="true" maxActive="-1" maxIdle="-1" maxWait="-1"/>
    </Context>


  • web.xml:

    ...
    <resource-ref>
    <description>MyDs Oracle Datasource</description>
    <res-ref-name>jdbc/MyDs</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
    </resource-ref>
    ...


  • Spring's applicationContext.xml:

    ...
    <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="java:comp/env/jdbc/MyDs"/>
    </bean>
    ...



Final situation on Jboss 5

  • add JDBC driver to $JBOSS/server/type_of_server/lib, in our case $JBOSS/server/default/lib


  • MyDs-ds.xml: this file defines the Jboss datasource and has to be added to $JBOSS/server/type_of_server/deploy, in our case $JBOSS/server/default/deploy

    <?xml version="1.0" encoding="UTF-8"?>
    <datasources>
    <local-tx-datasource>
    <jndi-name>jdbc/MyDs</jndi-name>
    <connection-url>jdbc:oracle:thin:@192.168.0.107:1521:XE</connection-url>
    <driver-class>oracle.jdbc.OracleDriver</driver-class>
    <user-name>vatengine</user-name>
    <password>vatengine</password>
    <valid-connection-checker-class-name>org.jboss.resource.adapter.jdbc.vendor.OracleValidConnectionChecker</valid-connection-checker-class-name>
    </local-tx-datasource>
    </datasources>


  • web.xml and applicationContext.xml stay identical


  • context.xml: the datasource declaration can be removed, since we will be creating one in Jboss (but it seems leaving it doesn't do harm)

    <?xml version="1.0" encoding="UTF-8"?>
    <Context path="/MyApp">
    <Loader delegate="true"/>
    </Context>


  • jboss.web.xml: this file has to be added to the web application's WEB-INF directory contains glue logic between web.xml and Jboss resource declarations

    <?xml version="1.0" encoding="UTF-8"?>
    <jboss-web>
    <resource-ref>
    <res-ref-name>jdbc/MyDs</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <jndi-name>java:jdbc/MyDs</jndi-name>
    </resource-ref>
    </jboss-web>


Tuesday, August 11, 2009

Converting an application using an internal datasource to one using a JNDI datasource

Elaboration for Tomcat 6 and Oracle 10; other application or db servers are similar.

1. Copy the jdbc driver jar (ojdbc14.jar) to $TOMCAT_HOME/lib

2. To the application's context.xml, add the following lines:

<Resource name="jdbc/XXX"
auth="Container" type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver"
url="url" username="usr" password="pass"
removeAbandoned="true" maxActive="-1" maxIdle="-1" maxWait="-1"/>

where XXX is the name the datasource will take in the JNDI tree, and url, username and password keep the real values used before.
The other parameters may be finetuned at will. removeAbandoned="true" makes sure that that abandoned dB connections are removed and recycled.

3. To the application's web.xml, add the following:

<resource-ref>
<description>Oracle Datasource</description>
<res-ref-name>jdbc/XXX</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>

where XXX matches the JNDI name chosen before.

4. Within the application, use the datasource's JNDI name when referring to it: java:comp/env/jdbc/XXX
for instance, in Spring's applicationContext.xml, one can add:

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/XXX"/>
</bean>

and inject this bean in other beans that need a datasource.

5. Since the Oracle driver will already be loaded by Tomcat's classloader at the startup of the application, it isn't needed to deploy it with the application, it's only needed to compile. Hence, in Eclipse, in the project's properties->Java EE Module Dependencies, unmark the dependency on the oracle driver (ojdbc14.jar), or remove it from the dist target within a custom Ant script.

Source: http://tomcat.apache.org/tomcat-6.0-doc/jndi-datasource-examples-howto.html

Wednesday, July 22, 2009

Tips and hints when using Spring Web Services

Some things I noted while trying to set up a Spring web services application, that obeys to WS-Addressing and SoapAction headers.


  • Bottom-up approach:

    • Write WSDL and XSD, adding soapAction descriptors and enabling WS-Addressing (see below)

    • Use JAXB to generate beans

    • Set up Spring WS configuration: marshaller, interceptors, endpoint and endpoint mapping

    • Create the endpoint class (@endpoint) and start populating it with web methods, making them match with the WSDL operations, adding annotations @Action and @SoapAction for resp. SoapAction and WS-Addressing endpoints. Use the generated beans for input/output




  • When calling the application, if an "argument type mismatch" SoapFault is returned:

    • logically, check if you're calling the correct Action

    • sometimes it is/isn't needed to nest arguments/return parameters in a JAXBElement; if it isn't needed, this error is returned



  • To make WS-Addressing work

    • add the WSAW namespace in the wsdl: xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"

    • in the same WSDL, add >wsaw:UsingAddressing wsdl:required="true"/< in the binding part. It's not needed to define Actions in the WSDL, IF you're already defining a SoapAction: as a default this one will be used for the WS-Addressing too.

    • using Spring WS annotations, add @org.springframework.ws.server.endpoint.annotation.Endpoint at the beginning of the class to declare the class as an endpoint; and for each web method, add @org.springframework.ws.soap.addressing.server.annotation.Action and
      @org.springframework.ws.soap.server.endpoint.annotation.SoapAction
      annotations on top of them, ex.

      @SoapAction(Constants.SOAP_LOCATION_URL_CONSULTA_CONTRATO)
      @Action(value=Constants.SOAP_LOCATION_URL_CONSULTA_CONTRATO)
      public JAXBElement consultaContrato(final ConsultaContrato consultaContrato) {
      ...
      }




Monday, June 15, 2009

Struts2: form not submitting

When using Struts2, here are some hints about what may be happening if after submit the data of your form isn't available within the corresponding action:


  • Check if on click you're effectively performing a submit and not just merely following a link; only the <s:submit> tag should be used or a link which calls a javascript:form.submit()!


  • Be sure that you have a public setter (and getter) within your action for all the variables you're submitting, otherwise the (private) member variables within your action will never receive a value!

Thursday, June 11, 2009

Changes needed when switching from Struts2 v.2.0.11.2 to v.2.1.6

When using an old and working application, based upon Struts2 v.2.0.11.2, as the base for a new application using Struts2 v.2.1.6, I encountered I had to make the following modifications in struts.xml:

  • change all type="redirect-action" into type="redirectAction"

  • Because the org.apache.struts2.views.tiles.TilesResult isn't included anymore in the struts jar, I had to comment

    <result-types>
    <result-type name="tiles" class="org.apache.struts2.views.tiles.TilesResult"/>
    </result-types>


    Update: on hindsight, the second error was caused by a missing tiles jar!