This documentation is for WSO2 ESB version 4.5.1. View documentation for the latest release.

Transaction Mediator Example

A new synapse mediator (Transaction Mediator) has been added to support the distributed transactions using Java transaction API(JTA). JTA allows applications to perform a distributed transaction, that is, transactions that access and update data on two or more networked computer resources (an example would be to have two databases or a database and a message queue such as JMS). This mediator can be used to perform a distributed transaction. The synapse configuration has been extended to add explicit transaction markers. This means that you can use the synapse configuration language to define the start, end etc. of your transaction. It is the responsibility of the user to define when to start, commit or rollback the transaction. For example, you can mark the start of a transaction at the start of a database commit, end of the transaction at the end of the database commit and you can mark rollback transaction if a failure occurs.



Transaction Mediator Configuration

<transaction action="new|use-existing-or-new|fault-if-no-tx|commit|rollback|suspend|resume"/>

The action attribute has the following meanings:

Value

Meaning

new

Creates a new JTA transaction. Generates an error if a transaction already exist.

use-existing-or-new

Creates a new JTA transaction. Does nothing if a transaction exist.

fault-if-no-tx

Generates an error if no transaction exist. Does nothing if a transaction exist.

commit

Commits transaction. Generates an error if no transaction exist.

rollback

Rollback transaction. Generates an error if no transaction exist.

suspend

Suspends transaction. Generates an error if no transaction exist.

resume

Resumes transaction. Generates an error if no transaction exist.

Note

To use the Transaction Mediator, you need to have a JTA provider in your environment, for example, JBoss.


Transaction Mediator Scenario

Use the following scenario to show how the Transaction Mediator works. Assume we have a record in one database and we want to delete that record from the first database and add it to the second database (these two databases can be run on the same server or they can be in two remote servers). The database tables are defined in such a way that the same entry cannot be added twice. So, in the successful scenario, the record will be deleted from the first table (of the first database) and will be added to the second table (of the second database). In a failure scenario (the record is already in the second database), no record will be deleted from first table and no record will be added into the second database.


System Requirements

Note

This scenario applies to version 3.0. In versions after, there is a Transaction Manager in Carbon itself, so you don't have to put the ESB in an application server to get it working.

Since the Transaction Mediator is implemented using JTA, you need to have a JTA provider. Here we used JBoss J2EE application server (which implements the transaction support through Arjuna TS) as the JTA provider, so it is necessary to deploy the WSO2 ESB in JBoss Application server (AS). Apache Derby as the database server.

JBoss server and the Derby database server have the characteristics mentioned above.


Running the Example

1. Unzip the WSO2 ESB distribution to a place of your choice. And then remove the geronimo-jta_1.1_spec-1.1.0.wso2v1.jar ( This JAR file can be found in $ESB_HOME/repository/components/plugins).

Tip

The reason is that the implementation of javax.transaction.UserTransaction of JTA provider (here JBoss) is used there and if they both are in class path, there is a classloading issue which causes the transaction mediator to fail.

2. Deploy the WSO2 ESB on JBoss AS. The JBOSS installation path will be referred to as $JBOSS_HOME and the WSO2 ESB repo location as $CARBON_HOME.

3. Drop the derby client JARs (derby.jar, derbynet.jar and derbyclient.jar) into $CARBON_HOME/repository/components/lib folder and also into $JBOSS_HOME/server/default/lib (here is used the default JBoss configuration) folder.

4. We use here a sample similar to #361, and the full Synapse configuration is shown below. (you can directly paste the following configuration into synapse configuration in $ESB_HOME/repository/conf/synapse-config/synapse.xml). In the "In" sequence, we will send a message to the service and in the "Out" sequence we will delete an entry from the first database and update the second database with that entry. If we try to add an entry, which is already there in the second database, the whole transaction will rollback.

<definitions xmlns="http://ws.apache.org/ns/synapse">
   <sequence name="myFaultHandler">
        <log level="custom">
            <property name="text" value="** Rollback Transaction**"/>
        </log>
        <transaction action="rollback"/>
        <send/>
    </sequence>
    <sequence name="main" onError="myFaultHandler">
        <in>
            <send>
                <endpoint>
                    <address uri="http://localhost:9000/services/SimpleStockQuoteService"/>
                </endpoint>
            </send>
        </in>
         <out>
            <transaction action="new"/>
            <log level="custom">
                <property name="text" value="** Reporting to the Database esbdb**"/>
            </log>
            <dbreport useTransaction="true" xmlns="http://ws.apache.org/ns/synapse">
                <connection>
                    <pool>
                        <dsName>java:jdbc/XADerbyDS</dsName>
                        <icClass>org.jnp.interfaces.NamingContextFactory</icClass>
                        <url>localhost:1099</url>
                        <user>esb</user>
                        <password>esb</password>
                    </pool>
                </connection>
                <statement>
                     <sql>delete from company where name =?</sql>
                     <parameter expression="//m0:return/m1:symbol/child::text()"
                       xmlns:m0="http://services.samples" xmlns:m1="http://services.samples/xsd"
                                 type="VARCHAR"/>
                </statement>
            </dbreport>
            <log level="custom">
                <property name="text" value="** Reporting to the Database esbdb1**"/>
            </log>
            <dbreport useTransaction="true" xmlns="http://ws.apache.org/ns/synapse">
                <connection>
                    <pool>
                        <dsName>java:jdbc/XADerbyDS1</dsName>
                        <icClass>org.jnp.interfaces.NamingContextFactory</icClass>
                        <url>localhost:1099</url>
                        <user>esb</user>
                        <password>esb</password>
                    </pool>
                </connection>
                <statement>
                    <sql>INSERT into company values (?,'c4',?)</sql>
                    <parameter expression="//m0:return/m1:symbol/child::text()"
         xmlns:m1="http://services.samples/xsd" xmlns:m0="http://services.samples"
                               type="VARCHAR"/>
                    <parameter expression="//m0:return/m1:last/child::text()"
         xmlns:m1="http://services.samples/xsd" xmlns:m0="http://services.samples"
                               type="DOUBLE"/>
                </statement>
            </dbreport>
            <transaction action="commit"/>
            <send/>
        </out>
    </sequence>
</definitions>

5. To run the sample, you need two distributed Derby databases ("esbdb" and "esbdb1"). Refer here for details to set up the databases. The database table was created using the following SQL query.

Note

In the table schema we cannot have the same entry twice.

CREATE table company(name varchar(10) primary key, id varchar(10), price double);

Add few records to the two tables:

Database1:

INSERT into company values ('IBM','c1',0.0);
INSERT into company values ('SUN','c2',0.0);

Database2:

INSERT into company values ('SUN','c2',0.0);
INSERT into company values ('MSFT','c3',0.0);

Note

The order of the record matters.

6. Create two data source declarations for JBoss AS for the two distributed databases.

Datasource1:esb-derby-xa-ds.xml

<?xml version="1.0" encoding="UTF-8"?>
<datasources>
    <xa-datasource>
        <jndi-name>jdbc/XADerbyDS</jndi-name>
        <isSameRM-override-value>false</isSameRM-override-value>
        <xa-datasource-class>org.apache.derby.jdbc.ClientXADataSource</xa-datasource-class>
        <xa-datasource-property name="portNumber">1527</xa-datasource-property>
        <xa-datasource-property name="DatabaseName">esbdb</xa-datasource-property>
        <xa-datasource-property name="User">esb</xa-datasource-property>
        <xa-datasource-property name="Password">esb</xa-datasource-property>
        <metadata>
            <type-mapping>Derby</type-mapping>
        </metadata>
    </xa-datasource>
</datasources>

Datasource2:esb-derby1-xa-ds.xml

<?xml version="1.0" encoding="UTF-8"?>
<datasources>
    <xa-datasource>
        <jndi-name>jdbc/XADerbyDS1</jndi-name>
        <isSameRM-override-value>false</isSameRM-override-value>
        <xa-datasource-class>org.apache.derby.jdbc.ClientXADataSource</xa-datasource-class>
        <xa-datasource-property name="portNumber">1527</xa-datasource-property>
        <xa-datasource-property name="DatabaseName">esbdb1</xa-datasource-property>
        <xa-datasource-property name="User">esb</xa-datasource-property>
        <xa-datasource-property name="Password">esb</xa-datasource-property>
        <metadata>
            <type-mapping>Derby</type-mapping>
        </metadata>
    </xa-datasource>
</datasources>

Note

The two datasource file names should be *-xa-ds.xml.

Drop the two datasource declarations above into $JBOSS_HOME/server/default/deploy folder. Map the above jndi names: drop the following jboss-web.xml configuration into $JBOSS_HOME/serer/default/deploy/esb.war/WEB-INF/.

<!DOCTYPE jboss-web PUBLIC
         "-//JBoss//DTD Web Application 5.0//EN"
         "http://www.jboss.org/j2ee/dtd/jboss-web_5_0.dtd">
 <jboss-web>
     <resource-ref>
         <res-ref-name>jdbc/XADerbyDS</res-ref-name>
         <jndi-name>java:/XADerbyDS</jndi-name>
     </resource-ref>
     <resource-ref>
         <res-ref-name>jdbc/XADerbyDS1</res-ref-name>
         <jndi-name>java:/XADerbyDS1</jndi-name>
     </resource-ref>
 </jboss-web>

7. Go into $JBOSS_HOME/bin and start the server. Run the run.sh (run.bat) script.

Note

You need to set the CARBON_HOME environment variable pointing to the Carbon repository location.

8. Try the samples. Refer to sample set up guide to know how you can set up the server. Deploy the SimpleStockQuote service which comes with the WSO2 ESB samples.

Successful Scenario

1. To remove the IBM record from the first database and add it to the second database, run the sample with the following options.

ant stockquote -Daddurl=http://localhost:9000/services/SimpleStockQuoteService
-Dtrpurl=http://localhost:8280/ -Dsymbol=IBM

2. Check both databases to see how the record is deleted from the first database and added to the second database.

Failure Scenario

1. Try to add an entry which is already there in the second database. This time use Symbol SUN.

ant stockquote -Daddurl=http://localhost:9000/services/SimpleStockQuoteService
-Dtrpurl=http://localhost:8280/ -Dsymbol=SUN

2. You will see how the fault sequence is executed and the whole transaction rollback. Check both databases again; there is no record deleted from the first database and no record added into the second database.