이 콘텐츠는 선택한 언어로 제공되지 않습니다.

10.4. Define a Transactional Route


Overview

This section describes how to create a transactional route and package it as an OSGi bundle. The route described here is based on the AccountService class (see Appendix A), implementing a transfer of funds from one account to another, where the account data is stored in an Apache Derby database instance.

Database schema

The database schema for the accounts consists of just two columns: the name column (identifying the account holder) and the amount column (specifying the amount of money left in the account). Formally, the schema is defined by the following SQL command:
CREATE TABLE accounts (name VARCHAR(50), amount INT);
Copy to Clipboard Toggle word wrap

Sample incoming message

The following XML snippet demonstrates the format of a typical message that is processed by the route:
<transaction>
  <transfer>
    <sender>Major Clanger</sender>
    <receiver>Tiny Clanger</receiver>
    <amount>90</amount>
  </transfer>
</transaction>
Copy to Clipboard Toggle word wrap
The message requests a transfer of money from one account to another. It specifies that 90 units should be subtracted from the Major Clanger account and 90 units should be added to the Tiny Clanger account.

The transactional route

The incoming messages are processed by the following transactional route:
<route>
  <from uri="jmstx:queue:giro"/>
  <bean ref="accountService" method="credit"/>
  <bean ref="accountService" method="debit"/>
  <bean ref="accountService" method="dumpTable"/>
  <to uri="jmstx:queue:statusLog"/>
</route>
Copy to Clipboard Toggle word wrap
Money is transferred by calling the AccountService.credit and AccountService.debit bean methods (which access the Derby database). The AccountService.dumpTable method then dumps the complete contents of the database table into the current exchange and the route sends this to the statusLog queue.

Provoking a transaction rollback

The AccountService.debit method imposes a limit of 100 on the amount that can be withdrawn from any account and throws an exception if this limit is exceeded. This provides a simple means of provoking a transaction rollback, by sending a message containing a transfer request that exceeds 100.

Steps to define a transactional route

Perform the following steps to define a route that uses XA to coordinate global transactions across a JMS XA resource and an Apache Derby XA resource:
  1. Use the quickstart archetype to create a basic Maven project for the route bundle. Open a new command prompt, change directory to a convenient location, and enter the following command:
     mvn archetype:create
    -DarchetypeArtifactId=maven-archetype-quickstart
    -DgroupId=org.fusesource.example
    -DartifactId=tx-xa
    Copy to Clipboard Toggle word wrap
    The preceding command creates a new Maven project for the org.fusesource.example/tx-xa artifact under the tx-xa directory.
  2. Change the project packaging type to bundle. Under the tx-xa directory, open the pom.xml file with a text editor and change the contents of the packaging element from jar to bundle, as shown in the following highlighted line:
    <project ...>
      ...
      <groupId>org.fusesource.example</groupId>
      <artifactId>tx-xa</artifactId>
      <version>1.0-SNAPSHOT</version>
     <packaging>bundle</packaging>
      ...
    </project>
    Copy to Clipboard Toggle word wrap
  3. Add the bundle configuration to the POM. In the pom.xml file, add the following build element as a child of the project element:
    <project ...>
      ...
      <build>
        <defaultGoal>install</defaultGoal>
    
        <plugins>
    
          <plugin>
            <groupId>org.apache.felix</groupId>
            <artifactId>maven-bundle-plugin</artifactId>
            <extensions>true</extensions>
            <configuration>
              <instructions>
                <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
                <Import-Package>
                  org.springframework.core,
                  org.apache.camel,
                  org.apache.camel.component.jms,
                  org.apache.activemq,
                  org.apache.activemq.xbean,
                  org.apache.activemq.pool,
                  org.apache.xbean.spring,
                  org.apache.commons.pool,
                  org.hsqldb,
                  *
                </Import-Package>
                <Private-Package>
                  com.fusesource.demo.*
                </Private-Package>
                <DynamicImport-Package>
                  org.apache.activemq.*
                </DynamicImport-Package>
              </instructions>
            </configuration>
          </plugin>
          
        </plugins>
      </build>
    
    </project>
    Copy to Clipboard Toggle word wrap
  4. Customize the Maven compiler plug-in to enforce JDK 1.6 coding syntax. In the pom.xml file, add the following plugin element as a child of the plugins element, to configure the Maven compiler plug-in:
    <project ...>
      ...
      <build>
        <defaultGoal>install</defaultGoal>
    
        <plugins>
    
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
              <source>1.6</source>
              <target>1.6</target>
            </configuration>
          </plugin>
          ...
        </plugins>
      </build>
    
    </project>
    Copy to Clipboard Toggle word wrap
  5. Add the requisite dependencies to the POM. In the pom.xml file, add the following elements as children of the project element:
    <project ...>
      ...
      <name>Global transactions demo</name>
      <url>redhat.com</url>
    
      <properties>
        <camel-version>2.8.0-fuse-00-08</camel-version>
        <activemq-version>5.5.1-fuse-00-08</activemq-version>
        <log4j-version>1.2.16</log4j-version>
        <slf4j-version>1.6.4</slf4j-version>
        <spring-version>3.0.5.RELEASE</spring-version>
        <derby-version>10.8.2.2</derby-version>
        <xbean-spring-version>3.5</xbean-spring-version>
        <junit-version>4.8.1</junit-version>
        <aries-version>0.3</aries-version>
      </properties>
    
      <dependencies>
        <dependency>
          <groupId>org.apache.camel</groupId>
          <artifactId>camel-core</artifactId>
          <version>${camel-version}</version>
        </dependency>
        <dependency>
          <groupId>org.apache.camel</groupId>
          <artifactId>camel-spring</artifactId>
          <version>${camel-version}</version>
        </dependency>
        <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-log4j12</artifactId>
          <version>${slf4j-version}</version>
        </dependency>
        <dependency>
          <groupId>log4j</groupId> 
          <artifactId>log4j</artifactId> 
          <version>${log4j-version}</version> 
        </dependency>
        
        <!-- Spring transaction dependencies -->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-core</artifactId>
          <version>${spring-version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>${spring-version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-tx</artifactId>
          <version>${spring-version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-aop</artifactId>
          <version>${spring-version}</version>
        </dependency>
        
        <!-- Spring JDBC adapter -->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-jdbc</artifactId>
          <version>${spring-version}</version>
        </dependency>
    
        <!-- Database dependencies -->
        <dependency>
          <groupId>org.apache.derby</groupId>
          <artifactId>derby</artifactId>
          <version>${derby-version}</version>
        </dependency>
    
        <!-- JMS/ActiveMQ artifacts -->
        <dependency> 
          <groupId>org.apache.camel</groupId> 
          <artifactId>camel-jms</artifactId> 
          <version>${camel-version}</version>
        </dependency> 
        <dependency> 
          <groupId>org.apache.activemq</groupId> 
          <artifactId>activemq-camel</artifactId> 
          <version>${activemq-version}</version> 
        </dependency>
        <!--  This is needed by the camel-jms component -->
        <dependency> 
          <groupId>org.apache.xbean</groupId> 
          <artifactId>xbean-spring</artifactId> 
          <version>${xbean-spring-version}</version> 
        </dependency>
        
      </dependencies>
      ...
    </project>
    Copy to Clipboard Toggle word wrap
    Customize the dependency versions as required (by editing the properties defined in the properties element).
  6. Define the AccountService class. Under the tx-xa project directory, create the following directory:
    src/main/java/org/fusesource/example/tx/xa
    Copy to Clipboard Toggle word wrap
    Create the file, AccountService.java, in this directory and add the contents of the listing from Example A.1, “The AccountService Class” to this file.
  7. Define the beans and resources needed by the route in a Spring XML file. Under the tx-xa project directory, create the following directory:
    src/main/resources/META-INF/spring
    Copy to Clipboard Toggle word wrap
    Using a text editor, create the file, beans.xml, in this directory and add the following contents to the file:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:amq="http://activemq.apache.org/schema/core"
           xmlns:osgi="http://www.springframework.org/schema/osgi"
           xsi:schemaLocation="
       http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
       http://camel.apache.org/schema/spring
           http://camel.apache.org/schema/spring/camel-spring.xsd
       http://activemq.apache.org/schema/core
           http://activemq.apache.org/schema/core/activemq-core.xsd
       http://www.springframework.org/schema/osgi  
           http://www.springframework.org/schema/osgi/spring-osgi.xsd    
    ">
        
        <!-- Local ActiveMQ broker instance -->
        <amq:broker brokerName="TxXaDemo">
            <amq:persistenceAdapter>
                <amq:kahaDB directory="txXaDemo-data"/>
            </amq:persistenceAdapter>
            <amq:transportConnectors>
                <amq:transportConnector name="openwire" uri="tcp://localhost:51616"/>
                <amq:transportConnector name="vm" uri="vm:local"/>
            </amq:transportConnectors>
        </amq:broker>      
    
        
        <!--
            JMS non-TX endpoint configuration
        -->
        <bean id="jms" class="org.apache.camel.component.jms.JmsComponent"> 
            <property name="configuration" ref="jmsConfig" /> 
        </bean> 
        
        <bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration"> 
            <property name="connectionFactory" ref="jmsPoolConnectionFactory"/> 
        </bean>
        
        <!-- connection factory wrapper to support pooling -->
        <bean id="jmsPoolConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">
            <property name="connectionFactory" ref="jmsConnectionFactory" />
        </bean>
        
        <bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
            <property name="brokerURL" value="vm:local"/>
        </bean>
    
    
        <!--
            OSGi TM Service
        -->
        <!-- access through Spring's PlatformTransactionManager -->
        <osgi:reference id="osgiPlatformTransactionManager"
                        interface="org.springframework.transaction.PlatformTransactionManager"/>
        <!-- access through PlatformTransactionManager -->
        <osgi:reference id="osgiJtaTransactionManager"
                        interface="javax.transaction.TransactionManager"/>
        
        <!--
            JMS TX endpoint configuration
        -->
        <bean id="jmstx" class="org.apache.activemq.camel.component.ActiveMQComponent"> 
            <property name="configuration" ref="jmsTxConfig" /> 
        </bean> 
        
        <bean id="jmsTxConfig" class="org.apache.camel.component.jms.JmsConfiguration"> 
            <property name="connectionFactory" ref="jmsXaPoolConnectionFactory"/> 
            <property name="transactionManager" ref="osgiPlatformTransactionManager"/> 
            <property name="transacted" value="false"/>
            <property name="cacheLevelName" value="CACHE_CONNECTION"/>
        </bean> 
        
        <!-- connection factory wrapper to support auto-enlisting of XA resource -->
        <bean id="jmsXaPoolConnectionFactory" class="org.apache.activemq.pool.XaPooledConnectionFactory">
            <property name="maxConnections" value="1" />
            <property name="connectionFactory" ref="jmsXaConnectionFactory" />
            <property name="transactionManager" ref="osgiJtaTransactionManager" />
        </bean>
        
        <bean id="jmsXaConnectionFactory" class="org.apache.activemq.ActiveMQXAConnectionFactory">
            <property name="brokerURL" value="vm:local"/>
            <property name="redeliveryPolicy">
                <bean class="org.apache.activemq.RedeliveryPolicy">
                    <property name="maximumRedeliveries" value="0"/>
                </bean>
            </property>
        </bean>
        
        <!--
            ActiveMQ XA Resource Manager
        -->
        <bean id="resourceManager" class="org.apache.activemq.pool.ActiveMQResourceManager" init-method="recoverResource">
            <property name="transactionManager" ref="osgiJtaTransactionManager" />
            <property name="connectionFactory" ref="jmsXaPoolConnectionFactory" />
            <property name="resourceName" value="activemq.default" />
        </bean>
        
        <!--
            Import Derby data sources as OSGi services
        -->
        <osgi:reference id="derbyXADataSource"
                        interface="javax.sql.DataSource"
                        filter="(datasource.name=derbyXADB)"/>
        <osgi:reference id="derbyDataSource"
                        interface="javax.sql.DataSource"
                        filter="(datasource.name=derbyDB)"/>
        
    
        <!-- bean for account business logic -->
        <bean id="accountService" class="com.fusesource.demo.tx.xa.AccountService">
            <property name="dataSource" ref="derbyXADataSource"/>
        </bean>
    
    </beans>
    Copy to Clipboard Toggle word wrap
  8. Define the transactional route. In the src/main/resources/META-INF/spring directory, create the new file, camelContext.xml, and add the following contents:
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
    
      <camelContext xmlns="http://camel.apache.org/schema/spring" trace="false">
        <!-- Transactional route -->
        <route>
          <from uri="jmstx:queue:giro"/>
          <bean ref="accountService" method="credit"/>
          <bean ref="accountService" method="debit"/>
          <bean ref="accountService" method="dumpTable"/>
          <to uri="jmstx:queue:statusLog"/>
        </route>
        
        <!-- Feeder route -->
        <route>
          <from uri="file:PathNameToMsgDir"/>
          <to uri="jms:queue:giro"/>
        </route>
      </camelContext>
    
    </beans>
    Copy to Clipboard Toggle word wrap
    Important
    Replace PathNameToMsgDir with the absolute path name of a temporary directory. When the application is running, you will use this directory as a convenient way of feeding XML messages into the route.
  9. To build the tx-xa bundle and install it in the local Maven repository, enter the following Maven command from the tx-xa directory:
    mvn install
    Copy to Clipboard Toggle word wrap
맨 위로 이동
Red Hat logoGithubredditYoutubeTwitter

자세한 정보

평가판, 구매 및 판매

커뮤니티

Red Hat 문서 정보

Red Hat을 사용하는 고객은 신뢰할 수 있는 콘텐츠가 포함된 제품과 서비스를 통해 혁신하고 목표를 달성할 수 있습니다. 최신 업데이트를 확인하세요.

보다 포괄적 수용을 위한 오픈 소스 용어 교체

Red Hat은 코드, 문서, 웹 속성에서 문제가 있는 언어를 교체하기 위해 최선을 다하고 있습니다. 자세한 내용은 다음을 참조하세요.Red Hat 블로그.

Red Hat 소개

Red Hat은 기업이 핵심 데이터 센터에서 네트워크 에지에 이르기까지 플랫폼과 환경 전반에서 더 쉽게 작업할 수 있도록 강화된 솔루션을 제공합니다.

Theme

© 2025 Red Hat