The previous sample (Part 2) only contained a call to one web service from a SOA composite. It really gets interesting only when multiple distributed web services join one atomic transaction. To be able to execute this including rollbacks, we will implement 2 web services using SOA composites and the Oracle Database adapter.
Lets assume we have a CRM System (CustomerService) and and Order Fulfillment System (OrderService). The requirement should be that an order is only stored in the Order System if the customer has been stored successfully in the CRM system. Also, if a new order is placed incorrectly, the customer should not be stored in the CRM System.
Please be aware that with a single Weblogic server domain and when not using TcpMon, you will not see any WS-AT transactions because the local optimization kicks in and SOAP will not be used….
Lets design first the CustomerService. You can find the complete source code here. (Again please click on any image to enlarge)
Create the Database User and Schema
For the 2 services we will need one schema with 2 tables:
create user wstest identified by wstest;
grant connect, resource to wstest;
create table orders (orderid varchar2(255) primary key, quantity int, description varchar2(20));
create table customers (customerid varchar2(255) primary key, firstname varchar2(20), lastname varchar2(20))
Modify Weblogic Configuration
Create a new data source “jdbc/wstest” in the Weblogic console and enter the connection settings. Be sure to add a target Weblogic server/domain…
After that, create a new connection factory in the deployed DBAdapter and point this to the wstest data source:
Design and test of the CustomerService
First create an new SOA composite named CustomerService with one synchronous BPEL component:
Change the CustomerService.xsd to pass customerid, first name and last name as parameters:
<?xml version="1.0" encoding="UTF-8"?>
<element name="customerid" type="string"/>
<element name="firstname" type="string"/>
<element name="lastname" type="string"/>
<element name="result" type="string"/>
Then create a new Database Adapter on the right hand composite side:
Select the db connection and schema wstest which you have created before and select CUSTOMERS as target. Select Insert or Update as operation. After the DB Adapter wizard, create an Input Variable as inidicated below:
Your SOA Composite should now look like:
Edit the BPEL Process to insert an Invoke activity to call the newly created Partnerlink:
Use a Transform activity before the Invoke to map the input parameters to the variables of the Invoke:
You now can deploy and test the CustomerService using the SOA Console Test Page and should see a inserted row in the customers table.
Design and test of the OrderService
Repeat each step of CustomerService to create a similar OrderService. Just select in the DB Adapter Wizard the table ORDERS.
In addition to the CustomerService I have selected the genuid function as input for the orderid variable. So add an additional copy rule in an Assign activity before the Transform.
This leaves only the Order Item Description as input (for simplicity each time “one “ is assumed for the order amount).
The resulting SOA composite should look like
Deploy and the the OrderService using the SOA Console and verify that an Order has been created in the ORDERS table.
Start TcpMon with 8081 as forwarding port and the server:port where you have deployed the CustomerService (i.e. http://localhost:7001) as target.
Testing both webservice in one atomic transaction
Create a new SOA composite CreationService using a synchronous BPEL component which calls both web services – CustomerService and OrderService – sequentially:
Insert 2 web service references in the right side of the SOA composite editor and enter the WSDL URLs of CustomerService and OrderService – but be sure to use the port where TcpMon listens (8081).
Edit the XSD of CreationService and modify it to use customerid, firstname, lastname and orderitem as input parameters.
Then edit the BPEL process, insert 2 Invoke activities, calling the Partnerlinks – first for CustomerService, then Orderservice.
Map the variables so that customerid, firstname and lastname are fed into teh input variable for CustomerService and orderitem for OrderService.
Last 2 steps are:
Insert bpel.config.transaction=RequiresNew (or Required) in the CreationService BPEL component to start the transaction when the composite is called (see Part 2).
Modify the WS-AT settings to a MANDATORY transaction flow
Now you can deploy and test the CreationService.
Try first one Order Item (a arbitrary string) with less than 20 characters. This should create a new customer and a new order.
Then try with an Order Item string longer than 20 chars: this results in an SQL exception at the OrderService call and also roll backs the CustomerService as designed:
You can verify in TcpMon that the SOAP request used WS-AT.
This concludes the hands-on parts on WS-AtomicTransaction.