Friday, July 17, 2009

Instance tracking in Oracle SOA Suite 11g

An quick and easy solution to the question - Where is my purchase order? -
with Oracle SOA Suite 11g.

In this simple scenario we will process a purchase order via Mediator - BPEL -Human Workflow-File Adapter(Write2File)

The xsd is as follows -




Start JDev and create an empty composite -

1. Create a New Application of type SOA
2. Composite template = Empty Composite
3. Add a Mediator component. Template = 1 way interface. Check the checkbox "Create Composite Service with SOAP bindings". Set the input type to purchase order.



4. Add a BPEL component - ProcessOrder




5. Wire the Mediator to the BPEL process



6. Create the transformation in the Mediator



7. Add an Assign activity to the BPEL process. In this first draft I simply
assign input to output and then set the element of the output to "valid"



8. Deploy and Test



7. View audit trail



Very nice overview, but still no easy way to find out what has happened to order nr "123" for example.

8. Return to JDev and add a composite sensor (skittle icon)



9. Set as follows -



10. Re-deploy and Test



11. Click on the Instances tab



12. Click on the "Add Fields" button and select the sensor we just created



13. Search for Order Nr "1234"

Thursday, July 16, 2009

Buy this book - Oracle SOA Suite Developers Guide

I've just being going through this book, written by 2 of my Oracle colleagues - Matt Wright and the champion hill climber himself - Antony Reynolds.

The book goes well beyond the mechanics of how to use the Oracle SOA Suite components. There are plenty of architectural recommendations,implementation tips and tricks etc. that make this book really worthwhile reading.

As James Joyce would say - " a veritable fount of knowledge" -

http://www.packtpub.com/developers-guide-for-oracle-soa-suite-10gr3/book

Wednesday, July 15, 2009

Auto-refreshing ADF11g Gantt Project control

The scenario is as follows - I have 2 simple tables - TASK and SUBTASK
(SQL ddl script is at the end of this post)

I want to display the data in a Gantt project control as follows -



I also want this control to auto-refresh when the underlying data changes.

Step 1. Create an ADF Fusion APP in JDev 11g

Step 2. In the Model Project - add ADF Business Components --> Business Components for Tables. Select the tables - TASK and SUBTASK.

Step 3. Add an extra ViewObject based on SUBTASK specifically for the Gantt chart.

Step 4. Create a new ViewLink between the new ViewObject and the TaskView


You should end up with something like this -



Step 5. Set the property AUTO-REFRESH = true for all the View Objects.
Step 6. Create the Java ViewObjectImpl classes for TaskView and SubtaskView.
Step 7. Add the following code after the constructor in TaskViewImpl.


long lastRequeryTask = 0;
public long getLastRequeryTask() {
return lastRequeryTask;
}
@Override
protected void bindParametersForCollection(QueryCollection queryCollection,
Object[] object,
PreparedStatement preparedStatement) throws SQLException {
super.bindParametersForCollection(queryCollection, object, preparedStatement);
if (queryCollection != null) {
lastRequeryTask = System.currentTimeMillis();
}
System.out.println("Re-execute "+(queryCollection == null?"count ":"")+"query for VO "+getName());
}

@Override
protected void processDatabaseChangeNotification(QueryCollection queryCollection) {
System.out.println("*** TaskViewImpl DatabaseChangeNotification");
lastRequeryTask = System.currentTimeMillis();
super.processDatabaseChangeNotification(queryCollection);
}

Step 8. Add the following code after the constructor in SubtaskViewImpl.

long lastRequerySubTask = 0;
public long getLastRequerySubTask() {
System.out.println("SubtaskViewImpl: getLastRequerySubTask() returns " + lastRequerySubTask);
return lastRequerySubTask;
}
@Override
protected void bindParametersForCollection(QueryCollection queryCollection,
Object[] object,
PreparedStatement preparedStatement) throws SQLException {
super.bindParametersForCollection(queryCollection, object, preparedStatement);
if (queryCollection != null) {
lastRequerySubTask = System.currentTimeMillis();
System.out.println("SubtaskViewImpl: bindParametersForCollection() set lastRequerySubTask to " + lastRequerySubTask);
}
System.out.println("Re-execute "+(queryCollection == null?"count ":"")+"query for VO "+getName());
}

@Override
protected void processDatabaseChangeNotification(QueryCollection queryCollection) {
System.out.println("*** TaskViewImpl DatabaseChangeNotification");
lastRequerySubTask = System.currentTimeMillis();
System.out.println("SubtaskViewImpl: processDatabaseChangeNotification() set lastRequerySubTask to " + lastRequerySubTask);

super.processDatabaseChangeNotification(queryCollection);
}

Step 9. Expose both methods via the Client Interfaces

Step 10. Create a new JSPX page - MyGantt.jspx with Managed Bean

Step 11. You should have the following in your Data Control Palette



Step 12. Drop the SubTaskView1 DataControl as a Read Only Table on the page

Step 13. Drop the SubTaskView1 DataControl as a Read Only Table on the page

In the Table properties set content delivery = immediate

Step 14. Drop the method getLastRequerySubtask() as an ADF button above the table
We do this to get the method binding. Later we will delete the button.

Step 15. Add a Poll control to the page
The poll control will contact the middle tier ViewObject every 2 seconds to see if it has received database notifications.

Step 16. Add the following Poll logic to the managed bean

public void onPollTimerExpired(PollEvent pollEvent) {
Long lastRequerySubTask = (Long)AdfFacesContext.getCurrentInstance().getViewScope().get("lastRequerySubTask");
Long lastRequerySubTaskFromVO = (Long)BindingContext.getCurrent().getCurrentBindingsEntry().getOperationBinding("getLastRequerySubTask").execute();
System.out.println("+++++ Sub Task Timer expired: lastRequerySubTask = "+lastRequerySubTask+", lastRequerySubTaskFromVO = "+lastRequerySubTaskFromVO);
if (lastRequerySubTask == null || (!lastRequerySubTask.equals(lastRequerySubTaskFromVO))) {
AdfFacesContext.getCurrentInstance().getViewScope().put("lastRequerySubTask",lastRequerySubTaskFromVO);
AdfFacesContext.getCurrentInstance().addPartialTarget(getT1());

System.out.println("++++ Data requeried in VO. PPR'ing the table");
}
}

Set the poll control properties as follows -



Step 17. Test

Add a couple of rows to the DB tables -

delete from subtask;
delete from task;
commit;

insert into task values ('Task 1', 'Task Nr 1', sysdate, sysdate + 10);
insert into subtask values ('SUBTask 1', 'SUBTask Nr 1', sysdate, sysdate + 5, 'Task 1');
insert into subtask values ('SUBTask 2', 'SUBTask Nr 2', sysdate+5, sysdate + 10, 'Task 1');
commit;

Run the page

You should see the following -




Now add a new row to the table via SQLPLUS -

insert into subtask values ('SUBTask 3', 'SUBTask Nr 3', sysdate+5, sysdate + 10, 'Task 1');
commit;

The table should auto-refresh.

So Auto-Refresh is working fine for the table, so let's apply the same logic to the Gantt Project control.

Step 18. Add a Gantt Project Control to the page

Drag and Drop TaskView1 as a Gantt Project Control above the table control (use the Structure panel for this)

Set Task Id = TaskId
Start Time = Start Date
End Time = End Date

Click on the Subtasks tab -

For Subtasks Accessor select the View SubTask4Gantt
Set Sub Task Id = TaskId
Start Time = Start Date
End Time = End Date

Step 19. Drop the method getLastRequeryTask() as an ADF button above the Gantt control
We do this to get the method binding. Later we will delete the button.

Step 20. Add another poll control which will call this method via backing bean method
We do this to get the method binding. Later we will delete the button.

Your structure panel should look something like this -



Step 21. Add the following method to the backing bean for polling on Task changes

public void onPollTimerExpired1(PollEvent pollEvent) {
Long lastRequeryTask = (Long)AdfFacesContext.getCurrentInstance().getViewScope().get("lastRequeryTask");
Long lastRequeryTaskFromVO = (Long)BindingContext.getCurrent().getCurrentBindingsEntry().getOperationBinding("getLastRequeryTask").execute();
System.out.println("*** Task Timer expired: lastRequeryTask = "+lastRequeryTask+", lastRequeryTaskFromVO = "+lastRequeryTaskFromVO);
if (lastRequeryTask == null || (!lastRequeryTask.equals(lastRequeryTaskFromVO))) {
AdfFacesContext.getCurrentInstance().getViewScope().put("lastRequeryTask",lastRequeryTaskFromVO);
AdfFacesContext.getCurrentInstance().addPartialTarget(getPg1());
System.out.println("**** Data requeried in VO. PPR'ing the gantt");
}

Also add this line of code to the method onPollTimerExpired to PPR on the Gannt as well

AdfFacesContext.getCurrentInstance().addPartialTarget(getPg1());

Step 22. Set the 2nd poll control properties as follows -


Step 23. set Databinding.cpx to use Shared AppModule



Step 24. Run the Page

Set up test data -

delete from subtask;
delete from task;
commit;

insert into task values ('Task 1', 'Task Nr 1', sysdate, sysdate + 10);
insert into subtask values ('SUBTask 1', 'SUBTask Nr 1', sysdate, sysdate + 5, 'Task 1');
insert into subtask values ('SUBTask 2', 'SUBTask Nr 2', sysdate+5, sysdate + 10, 'Task 1');
commit;

View the control and open to see the subtasks -




Add a new Subtask via SQLPLUS
insert into subtask values ('SUBTask 3', 'SUBTask Nr 3', sysdate+5, sysdate + 10, 'Task 1');
commit;

The Gantt chart will auto-refresh.

Add a new Task via SQLPLUS

insert into task values ('Task 2', 'Task Nr 2', sysdate, sysdate + 10);
commit;

The Gantt chart will auto-refresh.

25. Cleanup the app
We only need 1 poll control and 1 managed bean onPollTimerExpired method.
So include the code from onPollTimerExpired1() in onPollTimerExpired().
Delete the second poll control.

I only use the table control here because I have some issues with auto-refresh on the SubTask4Gantt view. All we really need is the iterator SubtaskView1Iterator and
the following code -

In SubtaskViewImpl -
public void executeTheQuery(){
ViewObject vo = this.getViewObject();
vo.executeQuery();
}
expose this method thru the client interface.

drop this method as a Button on the page and double-click to generate
the code in the backing bean -

public String executeTheQuery_action() {
BindingContainer bindings = getBindings();
OperationBinding operationBinding = bindings.getOperationBinding("executeTheQuery");
Object result = operationBinding.execute();
if (!operationBinding.getErrors().isEmpty()) {
return null;
}
return null;
}

We can call this method as the page is being instantiated.

So now we can delete the table control.

Why do I need the 2nd SubTask Iterator?
Essentially we shouldn't need this, I just had issues getting the database notification to work with the subtaskView in the Gantt. This my workaround of creating the 2nd iterator "independent" of the Gantt.

In a further post I will hopefully be able to report on what was causing this issue
and how I fixed it!




SQL for Table Creation

Use Oracle DB 11g
activate database notification for schema owner

CREATE TABLE TASK
(
TASK_ID VARCHAR2(10 BYTE) NOT NULL,
TASK_NAME VARCHAR2(20 BYTE) NOT NULL,
START_DATE DATE NOT NULL,
END_DATE DATE
, CONSTRAINT TASK_PK PRIMARY KEY
(
TASK_ID
)
ENABLE
)
;
CREATE TABLE SUBTASK
(
SUBTASK_ID VARCHAR2(10 BYTE) NOT NULL,
SUBTASK_NAME VARCHAR2(20 BYTE) NOT NULL,
START_DATE DATE NOT NULL,
END_DATE DATE,
TASK_ID VARCHAR2(10 BYTE) NOT NULL
, CONSTRAINT SUBTASK_PK PRIMARY KEY
(
SUBTASK_ID
)
ENABLE
)
;
ALTER TABLE SUBTASK
ADD CONSTRAINT SUBTASK_TASK_FK1 FOREIGN KEY
(
TASK_ID
)
REFERENCES TASK
(
TASK_ID
)
ENABLE
;

Tuesday, June 16, 2009

Auto-refreshing ADF chart objects in JDev 11g

BTW. Today is Bloomsday - James Joyce abù

This sample uses JDev 11g and ORCL DB11g

In this simple scenario I will detail how to auto refresh a pie chart based on the following query. We will then amend the query where clause to exclude a particular department.




--------------------------------------------------------

SELECT sum(Emp.sal) SalaryTotal,
Dept.deptno,
Dept.dname

FROM Emp, Dept

WHERE Emp.deptno = Dept.deptno

GROUP BY Dept.Dname, Dept.Deptno
--------------------------------------------------------

Pre-requisite on the DB Side

in SQLPLUS --> conn system/manager

grant change notification to scott;

Step 1 - Creating the Model

Create a new Fusion Web Application (ADF) in JDev 11g

In the Model Project - Create new ADF Business Components --> Business Components from Tables

Create a connection to SCOTT's schema on your 11g DB and create Entity Objects based on the tables - Dept & Emp



Create the ViewObjects -



Accept the defaults on the following pages.



Create a new ViewObject for the Chart


Enter the following query on the next page-

SELECT sum(Emp.sal) SalaryTotal,
Dept.deptno,
Dept.dname

FROM Emp, Dept

WHERE Emp.deptno = Dept.deptno

GROUP BY Dept.Dname, Dept.Deptno




Accept defaults on the following steps.
At step 7 - select checkbox - Generate View Object Class: SalByDeptViewImpl



At Step 8 - select checkbox to add the new view to the Application Module



For the new view - Set auto-refresh property = true




Copy and paste the following code into the ...impl class you generated earlier
(after the constructor)

long lastRequery = 0;
public long getLastRequery() {
return lastRequery;
}
@Override
protected void bindParametersForCollection(QueryCollection queryCollection,
Object[] object,
PreparedStatement preparedStatement) throws SQLException {
super.bindParametersForCollection(queryCollection, object, preparedStatement);
if (queryCollection != null) {
lastRequery = System.currentTimeMillis();
}
System.out.println("Re-execute "+(queryCollection == null?"count ":"")+"query for VO "+getName());
}

@Override
protected void processDatabaseChangeNotification(QueryCollection queryCollection) {
lastRequery = System.currentTimeMillis();
super.processDatabaseChangeNotification(queryCollection);
}
}



We have just done the following -

We have created a long value lastRequery
We have overridden the following methods –
-bindParametersForCollection
-processDatabaseChangeNotification

The long value represents the last time the query was executed or it has handled a database change notification event. The value of this long has been exposed so the client can reference it as a custom method, see the getLastRequery() method
bindParametersForCollection() and processDatabaseChangeNotification() update this flag.

Expose the getLastRequery() method via the client interface



Step 2 - Creating the UI

Create a new JSF page via the faces-config.xml (graphical mode)



Double-click on the image to create the page, selecting auto-creation of backing bean.


You are now in the visual editor.

-Drag and Drop a Poll control onto the page.



-Drag and Drop SalByDeptView as a Graph --> Pie Chart onto the page







-Drag and Drop getLastRequery()as a method somewhere on the page




-Edit the jspx source and comment out the button you just dropped as we only need it's binding.




-Go to the pagedef file's overview.




-Click on the SalByDeptView iterator binding.
- In the Property Inspector, change the rangeSize to 100



- Edit the page by selecting the graph component in the structure pane

In the Property Inspector set the ContentDelivery flag to "immediate".



Now we need to poll on lastRequery()
So add the following method to the end of the page's backing bean.

public void onPollTimerExpired(PollEvent pollEvent) {
Long lastRequery = (Long)AdfFacesContext.getCurrentInstance().getViewScope().get("lastRequery");
Long lastRequeryFromVO = (Long)BindingContext.getCurrent().getCurrentBindingsEntry().getOperationBinding("getLastRequery").execute();
System.out.println("Timer expired: lastRequery = "+lastRequery+", lastRequeryFromVO = "+lastRequeryFromVO);
if (lastRequery == null (!lastRequery.equals(lastRequeryFromVO))) {
AdfFacesContext.getCurrentInstance().getViewScope().put("lastRequery",lastRequeryFromVO);
AdfFacesContext.getCurrentInstance().addPartialTarget(getPieGraph1());
System.out.println("Data requeried in VO. PPR'ing the pie chart");
}
}

-Select the Poll operation in the structure window
-- Set the Id to pollTimer
-- Select onPollTimerExpired() in the PollListener propety
-- Set the Interval property to 2000




The onPollTimerExpired poll listener event handler invokes a method action binding to get the lastRequery() long value. It stores this value in the view scope. If it notices that the value has changed, then it PPR's the pie chart.

- In the DataBindings.cpx file, for the "AppModuleDataControl" data control usage, set the configuration to use the "AppModuleShared" configuration. This configuration is automatically created for you by ADF design time, along with the "AppModuleLocal" configuration. Auto-refresh view objects only work when they are in a shared AM.



Step 3 - Test

Run the page from the faces-config.xml diagrammer



Open a cmd window and start sqlplus as scott

Insert a new emp with a large salary e.g.
insert into emp values (
8881,
'Jim',
null,
null,
sysdate,
9999,
100,
30);

commit;

The pie chart will be updated automatically.



Now we will amend the WHERE clause to ignore Department 10.

Step 4 - Dynamically Changing the WHERE clause

To avoid getting an ORA-29983

ORA-29983: Unsupported query for Continuous Query Notification
Cause: The query cannot be registered for Continuous Query Notification.
Action: The query has some constructs that make it incompatible with Continous Query Notification like synonyms or views. Please check the documentation for complete list.

we must deactivate the default use of inline views by calling setNestedSelectForFullSql()
in the create() method of the ...viewImpl class.

Open SalByDeptViewImpl.
We must override the create method so Menu --> Source --> Override Methods.
Select the create() method
Add the following after the line super.create();
this.setNestedSelectForFullSql(false);

We will now add a method to amend the WHERE clause to ignore Department 10.

public void excludeDept10(){
ViewObject vo = this.getViewObject();

// get the original query
String query = vo.getQuery();
System.out.println("VO query is = " + query);

// let's find the WHERE clause
int startOfWhere = query.indexOf("WHERE");
int startOfGroupBy = query.indexOf("GROUP BY");
String whereClause = query.substring(startOfWhere, startOfGroupBy);
System.out.println("Original WHERE Clause = " + whereClause);

// amend the WHERE clause to exclude Dept 10
whereClause = whereClause + " and Dept.deptno > 10 ";
String newQuery = query.substring(0, startOfWhere-1);
newQuery = newQuery + whereClause;
System.out.println("New Query with WHERE = "+ newQuery);

newQuery = newQuery + query.substring(startOfGroupBy, query.length());
System.out.println("New Query with Group BY = "+ newQuery);

this.setQuery(newQuery);
vo.executeQuery();
}

I'm sure there's a much more elegant way on doing this --)
- Expose this method (as we did getLastRequery()) via the client interface
- Refresh the DataControl
- Drop the method as an ADF button on the page

- re-test



Press the button to exclude Dept 10



- Enter a new Emp with a large salary




Tuesday, March 24, 2009

Installing MLR#3 on SOA Suite 10.1.3.4

Unzip MLR3 patch to a directory of your choice.
copy the directory 7586063 to the soaSuiteHome\opatches directory

Open a CMD window in this directory

set Oracle_home=d:\soa10134\appserver
set PERL5LIB=d:\soa10134\appserver\perl\5.8.3\lib
set OPATCH_PLATFORM_ID=0
set path=d:\soa10134\appserver\OPatch;%path%

Apply the patch -
opatch apply

Post-Steps
DB Schema upgrade

ORABPEL- according to the patch README, if you're pure 10.1.3.4 then you must run the following to update the schema
upgrade_10134_10134mlr_above_mlr11_oracle.sql
In my case the file is located at -
D:\SOA10134\AppServer\bpel\system\database\scripts

ORAESB - run the following -
SQL> @$ORACLE_HOME/integration/esb/sql/oracle/upgrade_10134_10134MLR.sql

In my case the file is located at -
D:\SOA10134\AppServer\integration\esb\sql\oracle

XREF: xREF Schema update. I've not used ESB xrefs so they don't need updating

Restart Soa Suite 10.1.3.4
opmnctl startall

Tuesday, March 10, 2009

Calling async BPEL process from JDEV 11g

Here is a simple example

· Create a simple asynchronous BPEL process
o Accept a String as input
o Do some simple processing and return the string as output



· Deploy to BPEL
· Get BPEL wsdl




· Create a new Application & Project in JDev 11g
In the project, create a Web Service Proxy



· Select Initiate Service à SimpleAsyncHello



· Click Finish

· The following artifacts are created



The 2 interesting files in respect of this lab are –

· SimpleAsyncHelloPortClient
o à Initiate BPEL process

· SimpleAsyncHelloCallbackImpl
o à Receive Callback from BPEL Server

As mentioned in the JDEV 11g release notes, we will have to make some changes to the SimpleAsyncHelloPortClient as BPEL 10.1.3.4 uses 2003 style addressing.


Original SimpleAsyncHelloPortClient –

public static void main(String [] args)
{
simpleAsyncHello_Service = new SimpleAsyncHello_Service();
SimpleAsyncHello simpleAsyncHello = simpleAsyncHello_Service.getSimpleAsyncHelloPort();
// Get the request context to set the outgoing addressing properties
WSBindingProvider wsbp = (WSBindingProvider)simpleAsyncHello;
WSEndpointReference replyTo =
new WSEndpointReference("http://", WS_ADDR_VER);
String uuid = "uuid:" + UUID.randomUUID();

wsbp.setOutboundHeaders( new StringHeader(WS_ADDR_VER.messageIDTag, uuid), new StringHeader(WS_ADDR_VER.actionTag, "action" ), replyTo.createHeader(WS_ADDR_VER.replyToTag));

// Add your code to call the desired methods.
}



Revised SimpleAsyncHelloPortClient –

· Imports

import com.oracle.xmlns.simpleasynchello.SimpleAsyncHello;
import com.oracle.xmlns.simpleasynchello.SimpleAsyncHello_Service;

import com.sun.xml.ws.api.addressing.AddressingVersion;
import com.sun.xml.ws.api.addressing.WSEndpointReference;
import com.sun.xml.ws.developer.WSBindingProvider;
import com.sun.xml.ws.message.StringHeader;

import java.util.UUID;

import javax.xml.namespace.QName;
import javax.xml.ws.WebServiceRef;

import org.xmlsoap.schemas.ws._2003._03.addressing.AttributedURI;
import org.xmlsoap.schemas.ws._2003._03.addressing.EndpointReferenceType;

· Main method

public static void main(String [] args)
{
simpleAsyncHello_Service = new SimpleAsyncHello_Service();
SimpleAsyncHello simpleAsyncHello = simpleAsyncHello_Service.getSimpleAsyncHelloPort();
// Get the request context to set the outgoing addressing properties
WSBindingProvider wsbp = (WSBindingProvider)simpleAsyncHello;

String uuid = "uuid:" + UUID.randomUUID();

// Add your code to call the desired methods.
//
AttributedURI messageId = new AttributedURI();
messageId.setValue( "uuid:" + UUID.randomUUID() );

// prepare ReplyTo
AttributedURI address = new AttributedURI();
address.setValue("http://localhost:7101/MyBPELAsyncClient-MyBPELClient-context-root/SimpleAsyncHelloCallbackPort");
EndpointReferenceType replyTo = new EndpointReferenceType();
replyTo.setAddress( address );

// prepare action header
wsbp.setOutboundHeaders(new StringHeader(
new QName( "http://schemas.xmlsoap.org/ws/2003/03/addressing", "Action" ),
"http://xmlns.oracle.com/SimpleAsyncHello/SimpleAsyncHello/initiate" ));

// Prepare payload
SimpleAsyncHelloProcessRequest asyncHelloProcessRequest = new SimpleAsyncHelloProcessRequest();
asyncHelloProcessRequest.setInput("Hi There");
simpleAsyncHello.initiate(asyncHelloProcessRequest, replyTo,messageId );

}

So what have we done here?

· Prepare ReplyTo:
· http://localhost:7101/MyBPELAsyncClient-MyBPELClient-context-root/SimpleAsyncHelloCallbackPort
o BPEL will reply to a service running on WLS. This service has been generated for us SimpleAsyncCallbackImpl.
o To test this, simply select this class and Right-mouse Click Run.This will deploy it to the embedded WLS that comes with JDev.

· Test the URL in a browser




· Check the wsdl for the port location




· http://localhost:7101/MyBPELAsyncClient-MyBPELClient-context-root/SimpleAsyncHelloCallbackPort


· Prepare Action Header (for 2003 compatability)
wsbp.setOutboundHeaders(new StringHeader(
new QName( "http://schemas.xmlsoap.org/ws/2003/03/addressing", "Action" ),
"http://xmlns.oracle.com/SimpleAsyncHello/SimpleAsyncHello/initiate" ));

· Prepare Payload (BPEL process input) and invoke the initiate method
SimpleAsyncHelloProcessRequest asyncHelloProcessRequest = new SimpleAsyncHelloProcessRequest();
asyncHelloProcessRequest.setInput("Hi There");
simpleAsyncHello.initiate(asyncHelloProcessRequest, replyTo,messageId );


· Test
o Run SimpleAsyncHelloPortClient
o Check BPEL Console




So now it’s time to look at the implementation of the Callback

· Original SimpleAsyncHelloCallbackImpl


package com.oracle.xmlns.simpleasynchello;

import com.sun.xml.ws.api.addressing.AddressingVersion;
import com.sun.xml.ws.api.message.Header;
import com.sun.xml.ws.api.message.HeaderList;
import com.sun.xml.ws.developer.JAXWSProperties;

import javax.annotation.Resource;

import javax.jws.Oneway;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.ParameterStyle;
import javax.jws.soap.SOAPBinding.Style;

import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.ws.Action;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.soap.Addressing;
// !THE CHANGES MADE TO THIS FILE WILL BE DESTROYED IF REGENERATED!
// This source file is generated by Oracle tools
// Contents may be subject to change
// For reporting problems, use the following
// Version = Oracle WebServices (11.1.1.0.0, build 080922.1045.35800)

@WebService(targetNamespace="http://xmlns.oracle.com/SimpleAsyncHello",
name="SimpleAsyncHelloCallback")
@XmlSeeAlso(
{ org.xmlsoap.schemas.ws._2003._03.addressing.ObjectFactory.class, com.oracle.xmlns.simpleasynchello.ObjectFactory.class })
@SOAPBinding(style=Style.DOCUMENT, parameterStyle=ParameterStyle.BARE)
@Addressing(enabled=true, required=true)
public class SimpleAsyncHelloCallbackImpl
{
@Resource
private WebServiceContext wsContext;

private static final AddressingVersion WS_ADDR_VER = AddressingVersion.W3C;

@WebMethod(action="onResult")
@SOAPBinding(parameterStyle=ParameterStyle.BARE)
@Action(input="onResult")
@Oneway
public void onResult(@WebParam(targetNamespace="http://xmlns.oracle.com/SimpleAsyncHello",
partName="payload", name="SimpleAsyncHelloProcessResponse")
com.oracle.xmlns.simpleasynchello.SimpleAsyncHelloProcessResponse payload,
@WebParam(targetNamespace="http://schemas.xmlsoap.org/ws/2003/03/addressing",
partName="RelatesTo", name="RelatesTo", header=true)
org.xmlsoap.schemas.ws._2003._03.addressing.Relationship RelatesTo)
{
// Use the sample code to extract the relatesTo id for correlation and then add your rest of the logic

System.out.println("Received the asynchronous reply");

// get the messageId to correlate this reply with the original request
HeaderList headerList = (HeaderList)wsContext.getMessageContext().get(JAXWSProperties.INBOUND_HEADER_LIST_PROPERTY);
Header realtesToheader = headerList.get(WS_ADDR_VER.relatesToTag, true);
String relatesToMessageId = realtesToheader.getStringContent();
System.out.println("RelatesTo message id: " + relatesToMessageId);

System.out.println("payload: '" + payload + "'");
System.out.println("RelatesTo: '" + RelatesTo + "'");
// Add your implementation here.
}
}

· Revised SimpleAsyncHelloCallbackImpl


package com.oracle.xmlns.simpleasynchello;

import com.sun.xml.ws.api.addressing.AddressingVersion;
import com.sun.xml.ws.api.message.Header;
import com.sun.xml.ws.api.message.HeaderList;
import com.sun.xml.ws.developer.JAXWSProperties;

import javax.annotation.Resource;

import javax.jws.Oneway;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.ParameterStyle;
import javax.jws.soap.SOAPBinding.Style;

import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.ws.Action;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.soap.Addressing;
// !THE CHANGES MADE TO THIS FILE WILL BE DESTROYED IF REGENERATED!
// This source file is generated by Oracle tools
// Contents may be subject to change
// For reporting problems, use the following
// Version = Oracle WebServices (11.1.1.0.0, build 080922.1045.35800)

@SOAPBinding(style=Style.DOCUMENT, parameterStyle=ParameterStyle.BARE)
@WebService(name = "SimpleAsyncHelloCallback", targetNamespace = "http://xmlns.oracle.com/SimpleAsyncHello", portName = "SimpleAsyncHelloCallbackPort")
public class SimpleAsyncHelloCallbackImpl
{
@Resource
private WebServiceContext wsContext;

private static final AddressingVersion WS_ADDR_VER = AddressingVersion.W3C;

@SOAPBinding(parameterStyle=ParameterStyle.BARE)
@Action(input="onResult")
@Oneway
@WebMethod(action = "onResult")
public void onResult(@WebParam(targetNamespace="http://xmlns.oracle.com/SimpleAsyncHello",
partName="payload", name="SimpleAsyncHelloProcessResponse")
com.oracle.xmlns.simpleasynchello.SimpleAsyncHelloProcessResponse payload,
@WebParam(targetNamespace="http://schemas.xmlsoap.org/ws/2003/03/addressing",
partName="RelatesTo", name="RelatesTo", header=true)
org.xmlsoap.schemas.ws._2003._03.addressing.Relationship RelatesTo)
{
// Use the sample code to extract the relatesTo id for correlation and then add your rest of the logic

System.out.println("Received the asynchronous reply");

// get the messageId to correlate this reply with the original request
HeaderList headerList = (HeaderList)wsContext.getMessageContext().get(JAXWSProperties.INBOUND_HEADER_LIST_PROPERTY);
Header relatesToheader = headerList.get(WS_ADDR_VER.relatesToTag, true);

if (relatesToheader == null){
System.out.println("Header null");
}
// String relatesToMessageId = relatesToheader.getStringContent();
// System.out.println("RelatesTo message id: " + relatesToMessageId);

System.out.println("payload: '" + payload + "'" + payload.getResult());
System.out.println("RelatesTo: '" + RelatesTo + "'");
// Add your implementation here.
}
}

· Test and review output in the WLS console tab in JDEV

Monday, February 23, 2009

BPEL - Embedded Java - JAXB

A simple how-to on leveraging JAXB within your BPEL process - with help from my colleague Flavius!

Step 1 - create a project in JDev to hold the JAXB artifacts for your XSD e.g. order.xsd
Menu --> Tools--> JAXB Compilation

Jar up the classes e.g. orderjaxb.jar

Step 2 - create the BPEL project e.g. with input/output set to order from order.xsd
Add an Assign to copy input to output
After the Assign, add the Java embedding with the following code -

addAuditTrailEntry("Java Embedding JAXB");
try{

// get the output Order element
Element element = (Element)getVariableData("outputVariable", "payload", "/ns1:order");
// Create the JAXB Context for Order
JAXBContext jc = JAXBContext.newInstance("orderjaxb");
Unmarshaller u = jc.createUnmarshaller();
// Cast the output order element as an object of class Order
Order order = (Order)u.unmarshal((org.w3c.dom.Node)element);

// Display customer
addAuditTrailEntry("Order: " + order.getCustomer());
}



catch (Exception e){
addAuditTrailEntry("Java embedding Exception thrown...." + e.toString());
}

Add the imports -





Add the following 2 libraries to your BPEL project (via project properties)
Oracle XMLParser V2
orderJaxb (Create a new library entry pointing to the jar file created in step 1)

That's it!