Wednesday, August 31, 2011

BPM11g looping Subprocess

Scenario:
the ubiquitous example of an order and its order lines -

XSD





Test XML input



In the BPM process I need to loop thru the order lines.

The basic process looks as follows -




I created a fileAdapter(Read) which triggers the process.

I created the following process variables -



To begin with, I copy the incoming order to the v_order variable.



Then I get the count of incoming order lines -



Now to the looping subprocess -

The loop condition is defined as follows -







Note we have this sub-process variable loopCounter generated for us.

Now to the actual processing - I just copy the orderLine[n] to a variable.





Deploy and test





Wednesday, August 10, 2011

Adding ADF BC components to a BPM Human Task Form

Here is what we need to do...
The BPM process only contains the orderID in the payload. We will need to retrieve the order details from the database via ADF BC and display them on the task form page. My table is called am_order and is defined as follows -




Thanks to Mireille D. and Angelo S. for their input!

The high level steps are as follows –

Auto-generate the Human Task form from the BPM task definition.
- This creates a new project in your JDeveloper application.

In the new project, expose the am_order table as an ADF BC
- Tailor it to add a View Criteria
- e.g. Am_order.order_id = orderID

Add a new bounded ADF task flow to the project
- Here we will display the order details
- The task flow will include a parameter (#pageFlowScope.in_orderID)
-- The view used will be a page fragment

Add the new bounded ADF task flow to the auto-generated taskDetails.jspx
- It will be dropped as a Region
-- Specify the bindings to orderID

Auto-generating the task form is a piece of cake - the real "baking" (pardon the pun) is in the creation of the extra ADF Task form to display the order details.

Amend the ADF BC View as follows -

1. Add a bind variable e.g. (bpm_orderID)
2. Add a new View Criteria that will leverage it.



3. Specify use at app module level



So to execute a query on the view we need to pass in a value for
bpm_orderID


Create the new task flow

This bounded task flow will have the following parameter-



So the task flow expects to be passed in a String (orderID). We call this in_orderID and it is stored in the variable pageFlowScope.in_orderID




Drop the ExecuteWithParams operation from the ViewObject on to the task flow diagram.



Here we specify the value for the view bind variable (bpm_orderID). Naturally this is set to pageFlowScope.in_orderID

We then add a view to the task flow to display the order details



That's it for the task flow.

Now open the auto-generated task form and drop in the new task flow as a region.



I position it after after the orderID.

When dropping we will need to bind the input parameter (in_orderID) we defined earlier. So we bind it to the the existing orderID on the page -






Monday, August 8, 2011

Using timers in BPM 11g Part 2

Scenario:

A typical batch style process -
The process starts at 10 am and writes out a report every hour.
It ends 6 hours later at 4 pm.

Now for testing purposes I will start at 2:40 pm, write a report every 1 minute and then end 5 minutes later - but you can extrapolate as required.

The process is as follows -



Start is set to 14:40



The variable v_endTimeString will be set to startTime (i.e. 14:40) + 5 minutes.
I use this later for comparison purposes. I'm not the XPath guru so I essentially
store the end date as a String in the format YYYYMMDDHHMM and then exit the reporting loop when currentDateTime > v_endTimeString.








Wait 1 minute configured as follows -




The COB? (Close Of Business) condition for "Still within business hours" is set as follows -



xp20:format-dateTime(string(xp20:current-dateTime()), '[Y0001][M01][D01][H01][m01]') < bpmn:getDataObject('v_endTimeString')

Deploy and test

The output report should contain 5 entries for the time period 14:40 - 14:45.










Wednesday, August 3, 2011

Using Timers in BPM11g

Here is the only occasion where I must admit the official docs left me somewhat puzzled.

It shows examples such as 'now' + 20 which one could take as an indication on how to set a timer for current date time + 20 (hours, seconds ??)

My scenario is very simple - accept a file, wait a certain amount of time and then write the file.



So now I want to set this wait to 15 seconds -



This may seem pretty cryptic -

xp20:add-dayTimeDuration-to-dateTime(xp20:current-dateTime(), string('PT15S'))

PT15S - PT are just constants -

P1Y1DT1H1S

so 3 days are P3D
3 hours PT3H

Check out Antony's blog posting for the why's etc.

http://blogs.oracle.com/reynolds/entry/whats_the_time_mr_bpel

Monday, July 18, 2011

Leveraging SDOs in BPM11g

In this simple scenario we will process orders that adhere to the following XSD

btw. a great resource that I often refer to is Antony Reynolds/Matt Wright --> Oracle SOA Suite 11g Developers Guide. If you don't already have it - then get it!

Ok back to business...



The underlying DB tables are as follows (I've created them in SCOTT's schema)–



DDL is available at Appendx A

Scenario
We are used to having payloads that contain all of the order attributes. We can imagine an Order Entry UI where the Order & customer details are entered. We could pass all of this on to BPM via the payload. However a more efficient way may be to leverage SDOs and just pass the keys e.g. OrderId, CustID on to BPM. BPM can then load the data in just in time mode from the DB using the SDO.

Setup
You need to have your DB schema installed. I create 1 customer so that I’ve something to test.



Create an ADF App in JDeveloper
This app will contain ADF-BC artifacts that we will expose via a Service Interface.



Set App name in project properties to something more readable as the default.



Create a BC App Module based on the tables we created.







Open the AppModule and click on Service Interface, then the +







Do the same for the other views.

FYI: Here is an extract from the official docs, detailing the operations.






The following files are generated



Test

We can test the SDO using OrdersAMServiceImpl




Running this app will deploy it to the integrated WLS and open the test page in your browser.
Select the getAmCustomerView1 operation
- Enter 1 as the cust id






Deploy to SOA Admin Server
Change the wsdl url to point to the target port
- Per default it is generated for 7101 (the JDev integrated WLS).



Add the following to the weblogic-application.xml






This enables us to register the SDO as an RMI Service.

The Datasource used by ADF-BC (jdbc/scottDS) needs to be XA aware.
The default generated/deployed by ADF-BC is not what we require, so we have to do 2 things - de-activate auto-generation of the weblogic-jdbc.xml and create the necessary datasource on our target WLS.




Using the WLS console, create a datasource jdbc/scottDS.
Per default it will be XA aware.

Create a new deployment profile of type Business Components Service Interface




Give the application a more meaningful name



Deploy from the Application Menu




Test



Leverage SDO in a BPM Composite

Create a BPM app



In Composite.xml --> add an ADF-BC Service (Reference).



Note: Registry name set to ADF app name + _JBOServiceRegistry.



Now we add a FileAdapter(ReadOrders) which will pass in the custID.
In the BPM designer, set Start implementation to ReadOrders.



Add a Service activity to retrieve the customer from the DB.





Deploy & test






Appendix A

ALTER TABLE AM_PRODUCT
DROP CONSTRAINT AM_PRODUCT_AM_ORDER_LINE_FK;

ALTER TABLE AM_ORDER_LINE
DROP CONSTRAINT AM_ORDER_LINE_AM_ORDER_FK;

ALTER TABLE AM_ORDER
DROP CONSTRAINT AM_ORDER_AM_CUSTOMER_FK;

DROP TABLE AM_PRODUCT CASCADE CONSTRAINTS;

DROP TABLE AM_ORDER_LINE CASCADE CONSTRAINTS;

DROP TABLE AM_ORDER CASCADE CONSTRAINTS;

DROP TABLE AM_CUSTOMER CASCADE CONSTRAINTS;

CREATE TABLE AM_PRODUCT
(
PRODUCT_ID VARCHAR2(20) NOT NULL
, PRODUCT_NAME VARCHAR2(20) NOT NULL
, PRODUCT_PRICE DECIMAL NOT NULL
, PRODUCT_DESCRIPTION VARCHAR2(255)
, ORDER_LINE_ID VARCHAR2(20)
, CONSTRAINT AM_PRODUCT_PK PRIMARY KEY
(
PRODUCT_ID
)
ENABLE
);

CREATE TABLE AM_ORDER_LINE
(
ORDER_LINE_ID VARCHAR2(20) NOT NULL
, ORDER_LINE_ITEM_DISCOUNT DECIMAL NOT NULL
, ORDER_LINE_ITEM_QUANTITY NUMBER NOT NULL
, ORDER_ID VARCHAR2(20)
, CONSTRAINT AM_ORDER_LINE_PK PRIMARY KEY
(
ORDER_LINE_ID
)
ENABLE
);

CREATE TABLE AM_ORDER
(
ORDER_ID VARCHAR2(20) NOT NULL
, ORDER_STATUS VARCHAR2(20) NOT NULL
, ORDER_DISCOUNT DECIMAL
, ORDER_COMMENTS VARCHAR2(255)
, CUST_ID VARCHAR2(20)
, CONSTRAINT AM_ORDER_PK PRIMARY KEY
(
ORDER_ID
)
ENABLE
);

CREATE TABLE AM_CUSTOMER
(
CUST_ID VARCHAR2(20) NOT NULL
, CUST_NAME VARCHAR2(20) NOT NULL
, CUST_EMAIL VARCHAR2(20) NOT NULL
, CUST_CREDITCARD_TYPE VARCHAR2(20) NOT NULL
, CUST_CREDITCARD_NR VARCHAR2(20) NOT NULL
, CONSTRAINT AM_CUSTOMER_PK PRIMARY KEY
(
CUST_ID
)
ENABLE
);

ALTER TABLE AM_PRODUCT
ADD CONSTRAINT AM_PRODUCT_AM_ORDER_LINE_FK FOREIGN KEY
(
ORDER_LINE_ID
)
REFERENCES AM_ORDER_LINE
(
ORDER_LINE_ID
)
ENABLE;

ALTER TABLE AM_ORDER_LINE
ADD CONSTRAINT AM_ORDER_LINE_AM_ORDER_FK FOREIGN KEY
(
ORDER_ID
)
REFERENCES AM_ORDER
(
ORDER_ID
)
ENABLE;

ALTER TABLE AM_ORDER
ADD CONSTRAINT AM_ORDER_AM_CUSTOMER_FK FOREIGN KEY
(
CUST_ID
)
REFERENCES AM_CUSTOMER
(
CUST_ID
)
ENABLE;