Wednesday, May 11, 2011

Split Join in OSB


Split Join :
This is one of an interesting feature in OSB , however if you know how FlowN works in Bpel this will appears to be same.
Use Case:
Orders -> Multiple Items
Services :
1. Get each Item Status (Instock/outStock)
2. Get Order Status.

Now split join splits the input request to multiple threads and executes parallely.
Like in this case for an Order with 10 items , 10 threads will get spawned.

Resources:
XSD : Order/Item Element
WSDL : for ItemStatus Service and Order Status service
Bpel : Implement the getItemStatus service for inividual item

OSB :
1. create a project for split join
2. Import XSD and both WSDl
   While importing wsdl it may create xsd as well , update the source with imported xsd from xsd folder and then delete the
   created one.
3. Create a Buss Service based on Item WSDL (get url from EM), this will be invoked as part of split join
   http://localhost:8001/soa-infra/services/default/SplitJoinRrcs/getitemstatusbpel_client_ep?WSDL
   
4. Create split join based on getOrderStatus Service , select operation.

- It will create Receive and Reply activity and request and response variables as well
- initialize the response variable by adding an assign action , Put this Assign action right after Receive
   <ord:Order xmlns:ord="http://pchanel/Orders">
   </ord:Order>
- add a ForEach Flow Control to iterate each item in Order
  parallel = yes
  counter var = loop
  start counter = 1
  final counter = count($request.payload/Items)
 
- Add invoke service for the check Item status for each Item inside for each

Before invoke and inside scope
---------------------------------------------
- create input/output scope variable for the service invoke
- Add another var "Param" to pass the value to the Service
- Add assign action inside the for each , initialize input variable for service

  <ord:Item xmlns:ord="http://pchanel/Orders">
  </ord:Item>
 
- Add copy operation to copy items to Param
 from exp : $request.payload/Items[$loop]
 to exp : $Param.payload

- Add replace to replace the service input with Param
Replace "." in input.payload with Exp : $Param.payload
Replace entire node
---------------------------------------------

- After the service invoke add Insert
Exp : $output.payload
LOcation : as first chil of
Xpath : .
Variable : response.payload
5. Right click split join.flow -> OSB -> Generate BS

Thats it split join is done !!

This is how it will look like in eclipse:



Transactions - One way Bpel


The first thing that comes to mind while testing the transaction management using 1 way Bpel is its Asynchronous and Transaction will not span across process.

However there are good amount of properties that actually impacts this , here are the properties from Dev guide that will actually makes lot of difference :
http://docs.oracle.com/cd/E21764_01/integration.1111/e10224/soa_transactions.htm#CHDHEAIC

- onewayDeliveryPolicy=async.persist
- onewayDeliveryPolicy=sync and transaction=requiresNew
- onewayDeliveryPolicy=sync and transaction=required

These properties doesn't actually behaves as it seems from there name :
transaction=requiresNew , This works in combination with onewayDeliveryPolicy=sync if we want the callee BPEL to execute in a different Transaction and all the BPEL involved will work in there atomic boundaries.

We also got confused with other Partner link properties :
idempotent = false
startnonblockinginvoke = true

These will force the Callee bpel to start a new transaction but will force the caller to dehyderate and commit the transaction before calling the second process.


Bottom Line : Use these properties with caution and as per your requirement.

Installing Oracle service registry


Oracle service registry is one of the usefull tool for SOA governance, here are the steps to install it.

1.   Use Weblogic 10.1.2, as the OSR version is 11.1.1.2, using the same version will not cause any   issue.
·         If we don’t use this then while opening the registry web , linking error and other error will come, the suggestion is to use Patch 9499508, however that again didn’t solved the error for me
-          Error 500--Internal Server Error org.idoox.wasp.WaspInternalException: java.lang.RuntimeException: Updates to config files not supported
-          registry: Error initializing servlet
-          Error 500--Internal Server Error
java.lang.LinkageError: loader constraint violation in interface itable initialization: when resolving method "com.idoox.wsdl.DefinitionImpl.getMessage(Ljavax/xml/namespace/QName;)Ljavax

2. Install WLS  10.1.2 and then use the same home for OSR installation.

3.  Use create schema option during installation, if you already have a Database setup normally if you are using the same database as for SOA

4.       If get error during re-install use option of connect to  existing schema
5.       The registry home should be inside wls home like
D:\Oracle\Mdw_Reg\home_11gR1
D:\Oracle\Mdw_Reg\home_11gR1\registry111
If this is not set the registry option will not show up while creating domain

6. After installing OSR , create/extend the existing domain.

7. In Jdeveloper create UDDI connection , give inquiry url as :

http://localhost:7101/registry/uddi/inquiry
default port for OSR os 7101

To login :
http://localhost:7101/registry/uddi/web
user/pwd : admin/welcome1

8. To publish the service from Jdev , open the Application server navigation.
Create Business entity: my_uddi_business



- publish wsdl to buss entity , use admin account

- use the service end point from UDDI to create Bpel



If get following error:

java.lang.Exception: oracle.sysman.emSDK.webservices.wsdlapi.SoapTestException: oracle.fabric.common.FabricInvocationException: Could not lookup the service endpoint

from UDDI either due to a UDDI connection error or the provided



Remove user/pwd from EM enquiry url.



Best practice is to install OSR in a separate server than SOA , you wont get any issue. if you need SOA + OSR to coexist than need to apply the patch and modify the domainENV file.

A great post about how to use OSR in your composite application is here :
http://biemond.blogspot.com/2009/12/using-oracle-service-registry-in-soa.html


This works !!

Java Callout with Collection in OSB


Java callout in OSB normally works well with primitives , however at times you may need to call java callout for custom objects/collections.
The guide says "You can also use Java callouts to create Java objects to store in the pipeline and to pass Java objects as parameters to other Java callouts. "

What does that mean: To pass a Collection to a java callout , call another java callout that returns the collection and pass this to the main java callout. Like :

- I have list of Strings
- And the java method1 takes ArrayList as input

What i did :
1. Created another java callout for method2 to convert strings to Arraylist
2. passed this Arraylist to method1

This approach looks tedious but strangely thats the way out .

Happy coding !!

The Strange Flow activity in Bpel


As per the dev guide and docs , Flow activity is supposed to execute the sequences inside in multiple threads , however it doesnt actually behave that way normally.
Does Setting non Blocking invoke for partner links really helps ?

Here is a very good article about it and the summary by Luccas Jellema:
-----------------------------------------------------------------------------------------------------------------------------
Flow in BPEL (or at least Oracle BPEL PM) allows for parallel branches of activities. When executed, the branches in the Flow get their turn to execute the next step. Steps are not truly executed at the same time – which may be a blessing in disguise in situations where activities in various branches access the same variables. Even synchronous calls with nonBlockingInvoke set to true (however, I may have set that property in an incorrect way or TP4 of BPEL may not yet provide proper support for that property) block other activities from being processed. Only asynchronous activities such as Receive (wait for response to invoke of an Asynchronous Service) will allow other activities in other branches to be executed. I had expected this also to apply to Wait – but that turned out not be the case in TP4.

-----------------------------------------------------------------------------------------------------------------------------
It looks a peformance hit at first sight and a blessing in disguise at second .

Custom SDO method with View Criteria using IN clause


IN Clause in Custom method:

1. Create type:
CREATE OR REPLACE TYPE  "IDTABTYPE"  as table of varchar2(4000);

2. Create a bind variable that will hold all the input ID's
dept_names_var -> oracle.jbo.Array
ColumnType="IDTABTYPE"
ElemType="java.lang.String"
Like :

  <Variable
    Name="dept_names_var"
    Kind="where"
    Type="oracle.jbo.domain.Array"
    ElemType="java.lang.String"
    ColumnType="IDTABTYPE"/>

3. Create VC using this variable: DepartmentNameVC
DepartmentName = Bind Var -> dept_names_var
Like :
 ( ( ( UPPER(DepartmentsEO.DEPARTMENT_NAME) = UPPER(:dept_names_var)  )  OR  ( :dept_names_var IS NULL ) ) )


4. Generate VORowImpl and VOImpl

5. In VOImpl create methods for creating IN Clause , one for fetch from DataBase and one for cache
 
  Like :
  whereCluase =this.getEntityDef(0).getAliasName() + ".DEPARTMENT_NAME IN (SELECT * FROM TABLE(CAST(:dept_names_var AS IDTABTYPE)))";  


   
6. In VOImpl

 Override:
 - protected void bindParametersForCollection [Can avoid overriding this]
 - public String getCriteriaItemClause

 Inside getCriteraItemClause fetch the IN clause created in methods created in step 5

6. Generate AMImpl class

 Create custom method that will be exposed in SDO for fetching departments based on list of department names.

   //custom Method
     public List<DepartmentsVORowImpl> findDeptsByNames(List<String> listOfNames) {
   
         List<DepartmentsVORowImpl> dept_list = new ArrayList<DepartmentsVORowImpl> ();
         DepartmentsVOImpl vo = (DepartmentsVOImpl)this.getDepartmentsVO1();
         vo.setApplyViewCriteriaName("DepartmentNameVC");
         vo.setNamedWhereClauseParam("dept_names_var", listOfNames.toArray());
         vo.executeQuery();
         while (vo.hasNext()) {
           DepartmentsVORowImpl r = (DepartmentsVORowImpl)vo.next();
          dept_list.add(r);
         }
           return dept_list;
     }
7. create service interface for AM

 - select the custom method, select the DepartmentVO from LOV

Define Bind variable as optional (uncheck required while creating Bind var), else you will get this error while executing any other operation on same VO
JBO-27122: SQL error during statement preparation.

Thats all !! it works

Setting MDS for Shared artifacts


With lots of artifacts (xsd,wsdl,dvm,rules..) in an organization , its very important to have a proper repository to strore them . Oracle MDS is a light weight repository with inherit support for SOA . Below are the steps needed to have it set up . MDS facilitates reusability and also makes the code independent of services deployed on any server being down. The other major benefit of MDS is to have dvm,rules persisted to memory once the changes are done to these artifacts from soa composer.

Steps :
1. create seed folder inside the Integration folder
D:\Oracle\Middleware\11114\jdev1114\jdeveloper\integration\seed
Inside seed-> apps
Here create project specific folders like :
LocalMDS -> xsd/dvm etc

This can be some other folder , like in source control like ADE/SCS :
WSH_MDS -> apps -> My_proj -> [xsd,dvm,rules,wsdl]

2. Copy the xsd, dvm inside the folders
Like in :
apps -> My_proj ->xsd
apps -> My_proj ->wsdl

3. Inside Jdev create connection for file based MDS
My_MDS  ->    MDS Root folder : C:\WSH_MDS\ This has to be one level above the apps folder

4. Use the artifacts wsdl,xsd,dvm from the MDS inside the SOA projects , dont copy the artifacts to project.

The usage should look like : oramds:/apps/My_proj/xsd/shipment_advice.xsd

5. The adf-config.xml will get updated as:
<namespace metadata-store-usage="mstore-usage_1" path="/apps"/>
and
       <metadata-store-usage id="mstore-usage_1">
       <metadata-store class-name="oracle.mds.persistence.stores.file.FileMetadataStore">
       <property value="C:/WSH_MDS/" name="metadata-path"/>
       <property value="apps" name="partition-name"/>
       </metadata-store>
      </metadata-store-usage>      
6. Deploy both MDS to server , use ANT scripts to deploy the MDS to server MDS.

7. Deploy composite to server.

Modification to referenced artifacts can be done directly inside MDS.

VO based on RefCursor returned from a stored procedure


ADF view objects can be heavily customized and works well most of the times. There may be sitautions when we need to create VO based on ref cusor returned by a stored procedure/function. Althogh there is no shortcut for this but definitely an extension to existing VO.

Steps:
- Create Proc/Function that returns ref cursor
   Function get_empdata(p_emp_id number,p_cursor OUT ref_cursor);
- Create a VO , select rows populated programmatically
- Dont create any attrs
- Once done with wizard and VOImpl is generated
Create the attrs in VO that you want (these are transient var)
    Like:
    Emp_id Number
    FirstName,LastName as string

- create a bind variable , this is used to pass the param for proc/function call dept_id Number

override the following methods in VOImpl
  -create
  -executeQueryForCollection
  -hasNextForCollection
  -createRowFromResultSet
  -getQueryHitCount
  -releaseUserDataForCollection
 
  write your custom method for calling the stored proc/function, like i created something like :
protected Object callStoredFunction(int sqlReturnType, String stmt,
        Object[] bindVars) {
        CallableStatement st = null;
        try {
          st = getDBTransaction().createCallableStatement("begin ? := " + stmt +
              "; end;", 0);
          st.registerOutParameter(1, sqlReturnType);
          if (bindVars != null) {
            for (int z = 0; z < bindVars.length; z++) {
              st.setObject(z + 2, bindVars[z]);
            }
          }
          st.executeUpdate();
          return st.getObject(1);
        }
        catch (SQLException e) {
          throw new JboException(e);
        }
      }

This VO is just like any other Read only VO and can have links to other view objects as well.

This works !!