Pages

Thursday, April 26, 2012

Publish EDN JMS events from ADF BC

With ADF BC ( Business Components ) you can fire Event Delivery Network CRUD events from ADF BC entities which can be captured and handled by the Oracle SOA Suite. In this blogpost we will use the JMS implementation of EDN plus WebLogic Store and Forward for the reliable delivery to the SOA Suite server ( this way we can bounce SOA without effecting the Web Applications ).

To make this possible on a different ADF WebLogic server then the SOA Suite Server, we need to do the following steps.

First we need to add a WebLogic shared Library.  Copy the oracle.soa.fabric_11.1.1 and oracle.soa.workflow_11.1.1 folders from the SOA Suite Oracle Home (  Oracle_SOA1\soa\modules ) to your own WebLogic Middleware home. Put those two folders on the same level directory level.

Then we can add these jars to our own WebLogic Server. Go to deployments and add the following jar  oracle.soa.workflow_11.1.1\oracle.soa.workflow.wc.jar ( this contains a manifest which loads the other jars ). Target this shared library to the right WebLogic servers.



We need to add this shared library reference to the weblogic-application.xml deployment descriptor of the ADF Web application. This is the only place where it works ( WEB-INF/lib does not work )



Now we can create an EDN definition and add a publication to an ADF BC entity. Go the Business Events part of your entity editor.



We need to decide if we want to use EDN-AQ or EDN-JMS. The AQ implementation is the default EDN implementation but this requires some datasources to the soa-infra database. This can be Ok in a small server network but I don't want this dependency to this SOA Suite Server in my WebLogic Server. 

So I will go for the JMS implementation and create the required Queue and Connection Factories on my own WebLogic Server ( you can also do this with JMS Foreign Server ). 
Then those JMS message are stored locally and we will use WebLogic Store and Forward for the reliable delivery to the SOA Suite server. This way we can bounce the SOA Suite server without effecting our Web Applications.

For the EDN-AQ implementation read this blogpost

To enable the EDN-JMS implementation you need to do the following steps which are described in this blogpost

We need to create the following JMS artefacts.

Create a JMS Server with a file or jdbc persistence.
Create a JMS Modules with a sub-deployment targeted to this JMS server.

Create a JMS Connection Factory called EDNConnectionFactory with JNDI name jms/fabric/EDNConnectionFactory, disable XA and targeted this to your WebLogic server.

Create a JMS Connection Factory called xaEDNConnectionFactory with JNDI name jms/fabric/xaEDNConnectionFactory, enable XA and targeted this to your WebLogic server.

Create a Queue called EDNQueue with JNDI name jms/fabric/EDNQueue and use the subdeployment so its targeted to the JMS server.

When we start our ADF Web application and change some data, we can take a look at the Queue. Here we will see the EDN events.



Last step is to setup Store and Forward. For this we can follow this Middleware Magic blogpost

See this blogpost how to fire EDN events  from Java and OSB instead of ADF BC. 

cheers

Saturday, April 14, 2012

Retrieve or set a HTTP header from Oracle BPEL

With Oracle SOA Suite 11g patch 12928372  you can finally retrieve or set a HTTP header from BPEL. This patch comes with Patch Set 5 ( 11.1.1.6 )  and this patch can also be applied on PS3 ( 11.1.1.4 ), please download it from http://support.oracle.com

I made a simple test case with soapUI which adds an username and a message as HTTP header to the  service invocation.  In a second testcase I will mock this service in soapUI and BPEL will invoke this service and set an extra HTTP header property.

First step is to add a property to the binding.ws element of the service in the composite.xml. Add a property with name oracle.webservices.http.headers and as value the HTTP headers you want to use in BPEL
<property name="oracle.webservices.http.headers">username,message</property>


Next step is to define some BPEL variables for those HTTP Headers


In the receive activity of the BPEL process we can use fromProperty to copy the HTTP header property value to the BPEL variable. 

Do this in the BPEL source mode. 


Now you can use these variables in BPEL, I will use these vars in the return message.

Let's invoke the service from soapUI, we need to set the HTTP header properties with their values.



When we want to invoke a reference service and we also want to set some HTTP header properties.

We need also need to set the http.headers property on the binding.ws element on the reference in the composite.xml

<property name="oracle.webservices.http.headers">username,message,message2</property>


On the invoke of the reference service we need to use the toProperty and set the BPEL vars to these HTTP header properties.


When we test it again in soapUI we can see the invoke request of the soapUI mockservice, this contains the HTTP headers which we set in the BPEL process.


Wednesday, April 4, 2012

Deploy your ADF UIX applications to WebLogic

Just a quick blogpost how you can deploy your old ADF UIX ( 10.1.2)  applications to the WebLogic 11g ( 10.3.5 ) application server. Off course this is not supported by Oracle, who cares, your old 10.1.2 OC4J container is also end of life.  When it works, it works :-)

First you need to create a JDBC DataSource in the WebLogic Console.

You need to use the oracle.jdbc.OracleDriver driver class ( don't use XA, disable global commit ) else you will get some strange oracle BLOB errors.

Set Statement cache size to 0 ( in the connection pool Tab of the datasource )

also in the advanced options of the datasource you should de-select Wrap Data Types.
By default, data type objects for Array, Blob, Clob, NClob, Ref, SQLXML, and Struct, plus ParameterMetaData and ResultSetMetaData objects are wrapped with a WebLogic wrapper.


If you don't do this then ADF BC ( BC4J ) can't do its passivation in the ps_txn table ( this contains a BLOB datatype) and your applications behaves very strange
or you can set jbo.passivationstore to file


Next step is to make a shared library ( just use a war template ), For this I use an exploded folder so I can easily add and remove some jars.

I have a folder called adf.uix ( or a war with this name )

Folder META-INF
   File MANIFEST.MF with the following content

     Manifest-Version: 1.0
     Extension-Name: adf.uix
     Specification-Title: adf.uix
     Specification-Version: 1.0
     Implementation-Version: 10.1.2


Folder WEB-INF
  A empty web.xml file with the following content

     <?xml version = '1.0' encoding = 'windows-1252'?>
     <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"     "http://java.sun.com/dtd/web-app_2_3.dtd">
     <web-app>
     </web-app>
  
  Folder lib with all the 10.1.2 jars which I needed.



Deploy the shared library to WebLogic.

Next step is to unpack the war of your uix application ( we don't need the ear )

We need to create a weblogic deployment descriptor called weblogic.xml and put this in the WEB-INF folder. ( you can delete the orion one )

This weblogic descriptor contains a reference to our just created shared library. Also set the WEB-INF/lib as preferred classloading.


<?xml version = '1.0' encoding = 'windows-1252'?>
<weblogic-web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://www.bea.com/ns/weblogic/weblogic-web-app
     http://www.bea.com/ns/weblogic/weblogic-web-app/1.0/weblogic-web-app.xsd"
     xmlns="http://www.bea.com/ns/weblogic/weblogic-web-app">
  <container-descriptor>
    <prefer-web-inf-classes>true</prefer-web-inf-classes>
  </container-descriptor>
  <library-ref>
    <library-name>adf.uix</library-name>
  </library-ref>
</weblogic-web-app>

This is the content of my WEB-INF/lib folder 




Zip everything to a new war file or use the exploded folder.

When you use jdk1.6 or higher you can set -Djava.awt.headless=true so cabo uix does not need X-Windows or Windows desktop to generate gif images.

And when you don't see the images then you should also use an exploded folder instead of a war so cabo uix has a file path to store the generated images. Or make an UIX configuration class which contains cabo paths to a folder of the weblogic server.

Deploy the war or exploded folder  to weblogic, test it and delete your own OC4J Container.


Tuesday, April 3, 2012

How to use the Human WorkFlow Web Services

There are different ways to interact with the Human WorkFlow services of the Oracle SOA Suite or  BPM. You can use java and use it in your own application, like I did in this blogpost, use the BPM Worklist application or invoke the Human WorkFlow web services.

In this blogpost I will describe how you can do that and especially how you can query the Human task with your own ordering and restrictions.

You can try these examples from soapUI or any other web service framework / tool.

In this blogpost we will invoke these two WF web services

TaskQueryService, This WS can be used for task retrieval or do a query on the WorkFlow service.
The WSDL url = http://soa-server:8001/integration/services/TaskQueryService/TaskQueryService?WSDL

TaskService, This WS can be used for CRUD actions on the human tasks.
The WSDL url = http://soa-server:8001/integration/services/TaskService/TaskServicePort?WSDL

Both services got two endpoints, be aware you should always use the endpoint of TaskQueryServicePort and not the SAML port unless you like to use SAML authentication.


<service name="TaskQueryService">
<port name="TaskQueryServicePortSAML" binding="tns:TaskQueryServiceSOAPBinding">
<soap:address location="http://172.16.0.4:8001/integration/services/TaskQueryService/TaskQueryService2/*"/>
</port>
<port name="TaskQueryServicePort" binding="tns:TaskQueryServiceSOAPBinding">
<soap:address location="http://172.16.0.4:8001/integration/services/TaskQueryService/TaskQueryService"/>
</port>
</service>


When we know our Human TaskId  ( something like this 3fa4e9f7-5719-4efa-8215-ad2b47fcbace )
then you can use the getTaskDetailsById operation.


<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/
   <soapenv:Header/>
   <soapenv:Body>
      <tas:taskDetailsByIdRequest>
         <com:workflowContext>
            <com:credential>
               <com:login>weblogic</com:login>
               <com:password>weblogic1</com:password>
            </com:credential>
         </com:workflowContext>
         <tas:taskId>3fa4e9f7-5719-4efa-8215-ad2b47fcbace</tas:taskId>
      </tas:taskDetailsByIdRequest>
   </soapenv:Body>
</soapenv:Envelope>


In this case I use workflowContext for authentication. You can also do it on behalf of someone else.

Sometimes you only got a Human WorkFlow number then you can use the getTaskDetailsByNumber operation.


<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/
   <soapenv:Header/>
   <soapenv:Body>
      <tas:taskDetailsByNumberRequest>
         <com:workflowContext>
            <com:credential>
               <com:login>weblogic</com:login>
               <com:password>weblogic1</com:password>
            </com:credential>
         </com:workflowContext>
         <tas:taskNumber>200000</tas:taskNumber>
      </tas:taskDetailsByNumberRequest>
   </soapenv:Body>
</soapenv:Envelope>


When you don't know the taskId or the task number or want to do bulk operations then you can do a search on the humantask services.  The queryTasks operation is very powerful and there is not really a restriction.

let's start with a simple one. In this request I want to search for a task number and also want to have some extra attributes ( blue part )  in the response together with the Comments, Attachments and the Payloads ( red part ).

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/
   <soapenv:Header/>
   <soapenv:Body>
      <tas:taskListRequest>
         <com:workflowContext>
            <com:credential>
               <com:login>weblogic</com:login>
               <com:password>weblogic1</com:password>
            </com:credential>
         </com:workflowContext>
         <tas1:taskPredicateQuery>
            <tas1:displayColumnList>
               <tas1:displayColumn>textAttribute1</tas1:displayColumn>
               <tas1:displayColumn>textAttribute2</tas1:displayColumn>
               <tas1:displayColumn>textAttribute3</tas1:displayColumn>
            </tas1:displayColumnList>
            <tas1:optionalInfoList>
               <tas1:taskOptionalInfo>Comments</tas1:taskOptionalInfo>
               <tas1:taskOptionalInfo>Attachments</tas1:taskOptionalInfo>
               <tas1:taskOptionalInfo>Payload</tas1:taskOptionalInfo>
            </tas1:optionalInfoList>
            <tas1:predicate>
               <tas1:assignmentFilter>All</tas1:assignmentFilter>
               <tas1:clause>
                  <tas1:column>taskNumber</tas1:column>
                  <tas1:operator>EQ</tas1:operator>
                  <tas1:value>200001</tas1:value>
               </tas1:clause>
            </tas1:predicate>
         </tas1:taskPredicateQuery>
      </tas:taskListRequest>
   </soapenv:Body>
</soapenv:Envelope>

In the predicate part we are using the old style for defining our restriction ( clause after predicate ). In the next queryTasks examples I will show the ones which also will be supported in the coming soa suite releases.  

assignmentFilter can have the following values: All, My, Group, My+Group, My+Group+All, Reportees, Creator, Owner, Previous, Admin

operator can have the following values: EQ, NEQ, GT, GTE, LT, LTE, LIKE, NOT_LIKE, IN, NOT_IN, CONTAINS, NOT_CONTAINS, BEGINS, NOT_BEGINS, ENDS, NOT_ENDS, BEFORE, AFTER, ON, NEXT_N_DAYS, LAST_N_DAYS, IS_IN_FUTURE, IS_IN_PAST, IS_NULL, IS_NOT_NULL

To know all the possible displayColumn values you can decompile the TableConstants class located in the oracle.bpel.services.workflow.repos package. Or look at the WF tables in the soa-infra schema.

The optionalInfoList can contain the following values: Actions, GroupActions, CustomActions, Attachments, Comments, Payload, ShortHistory, TemplateTasks

In this query I have a predicate with two clauses which do a search on the text attributes ( tableName attribute is in almost all cases WFTask , check the soa-infa database or the TableConstants class ) and the second one has an AND operator on the first one.


<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/
   <soapenv:Header/>
   <soapenv:Body>
      <tas:taskListRequest>
         <com:workflowContext>
            <com:credential>
               <com:login>weblogic</com:login>
               <com:password>weblogic1</com:password>
            </com:credential>
         </com:workflowContext>
         <tas1:taskPredicateQuery startRow="1" endRow="10">
            <tas1:displayColumnList>
               <tas1:displayColumn>textAttribute1</tas1:displayColumn>
               <tas1:displayColumn>textAttribute2</tas1:displayColumn>
               <tas1:displayColumn>textAttribute3</tas1:displayColumn>
            </tas1:displayColumnList>
            <tas1:optionalInfoList>
               <tas1:taskOptionalInfo>Comments</tas1:taskOptionalInfo>
               <tas1:taskOptionalInfo>Attachments</tas1:taskOptionalInfo>
               <tas1:taskOptionalInfo>Payload</tas1:taskOptionalInfo>
            </tas1:optionalInfoList>
            <tas1:predicate>
               <tas1:assignmentFilter>All</tas1:assignmentFilter>
               <tas1:predicate>
                  <tas1:clause>
                     <tas1:column tableName="WFTask">
                        <tas1:columnName>textAttribute1</tas1:columnName>
                     </tas1:column>
                     <tas1:operator>EQ</tas1:operator>
                     <tas1:value>MyTask</tas1:value>
                  </tas1:clause>
                  <tas1:clause joinOperator="AND">
                     <tas1:column  tableName="WFTask">
                        <tas1:columnName>textAttribute2</tas1:columnName>
                     </tas1:column>
                     <tas1:operator>EQ</tas1:operator>
                     <tas1:value>1234</tas1:value>
                  </tas1:clause>
               </tas1:predicate>
            </tas1:predicate>
         </tas1:taskPredicateQuery>
      </tas:taskListRequest>
   </soapenv:Body>
</soapenv:Envelope>


In the next example we will add some ordering and use a valuelist in a predicate clause ( for this we need to use the IN operator).


<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/
   <soapenv:Header/>
   <soapenv:Body>
      <tas:taskListRequest>
         <com:workflowContext>
            <com:credential>
               <com:login>weblogic</com:login>
               <com:password>weblogic1</com:password>
            </com:credential>
         </com:workflowContext>
         <tas1:taskPredicateQuery>
            <tas1:displayColumnList>
               <tas1:displayColumn>textAttribute1</tas1:displayColumn>
               <tas1:displayColumn>textAttribute2</tas1:displayColumn>
               <tas1:displayColumn>textAttribute3</tas1:displayColumn>
            </tas1:displayColumnList>
            <tas1:optionalInfoList>
               <tas1:taskOptionalInfo>Comments</tas1:taskOptionalInfo>
               <tas1:taskOptionalInfo>Attachments</tas1:taskOptionalInfo>
               <tas1:taskOptionalInfo>Payload</tas1:taskOptionalInfo>
            </tas1:optionalInfoList>
            <tas1:predicate>
               <tas1:assignmentFilter>My+Group</tas1:assignmentFilter>
               <tas1:predicate>
                  <tas1:clause>
                     <tas1:column tableName="WFTask">
                        <tas1:columnName>state</tas1:columnName>
                     </tas1:column>
                     <tas1:operator>IN</tas1:operator>
                     <tas1:valueList>
                        <tas1:value>ASSIGNED</tas1:value>
                        <tas1:value>INFO_REQUESTED</tas1:value>
                        <tas1:value>OUTCOME_UPDATED</tas1:value>
                     </tas1:valueList>
                  </tas1:clause>
               </tas1:predicate>
            </tas1:predicate>
            <tas1:ordering>
               <tas1:clause>
                  <tas1:column>priority</tas1:column>
                  <tas1:table>WFTask</tas1:table>
                  <tas1:sortOrder>ASCENDING</tas1:sortOrder>
                  <tas1:nullFirst>false</tas1:nullFirst>
               </tas1:clause>
               <tas1:clause>
                  <tas1:column>taskNumber</tas1:column>
                  <tas1:table>WFTask</tas1:table>
                  <tas1:sortOrder>DESCENDING</tas1:sortOrder>
                  <tas1:nullFirst>false</tas1:nullFirst>
               </tas1:clause>
            </tas1:ordering>
         </tas1:taskPredicateQuery>
      </tas:taskListRequest>
   </soapenv:Body>
</soapenv:Envelope>


For the Ordering I need to provide the column and table values ( table element is in almost all cases WFTask , check the soa-infa database or the TableConstants class )

The last query task has a more complex predicate, for this we need to use lhs , logicalOperator and rhs elements. And the rhs element contains an another lhs , logicalOperator and rhs section.


<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/
   <soapenv:Header/>
   <soapenv:Body>
      <tas:taskListRequest>
         <com:workflowContext>
            <com:credential>
               <com:login>weblogic</com:login>
               <com:password>weblogic1</com:password>
            </com:credential>
         </com:workflowContext>
         <tas1:taskPredicateQuery startRow="1" endRow="10">
            <tas1:displayColumnList>
               <tas1:displayColumn>textAttribute1</tas1:displayColumn>
               <tas1:displayColumn>textAttribute2</tas1:displayColumn>
               <tas1:displayColumn>textAttribute3</tas1:displayColumn>
            </tas1:displayColumnList>
            <tas1:optionalInfoList>
               <tas1:taskOptionalInfo>Comments</tas1:taskOptionalInfo>
               <tas1:taskOptionalInfo>Attachments</tas1:taskOptionalInfo>
               <tas1:taskOptionalInfo>Payload</tas1:taskOptionalInfo>
            </tas1:optionalInfoList>
            <tas1:predicate>
               <tas1:assignmentFilter>My+Group</tas1:assignmentFilter>
               <tas1:predicate>
                  <tas1:lhs>
                     <tas1:clause>
                        <tas1:column tableName="WFTask">
                           <tas1:columnName>state</tas1:columnName>
                        </tas1:column>
                        <tas1:operator>IN</tas1:operator>
                        <tas1:valueList>
                           <tas1:value>ASSIGNED</tas1:value>
                           <tas1:value>INFO_REQUESTED</tas1:value>
                           <tas1:value>OUTCOME_UPDATED</tas1:value>
                        </tas1:valueList>
                     </tas1:clause>
                  </tas1:lhs>
                  <tas1:logicalOperator>AND</tas1:logicalOperator>
                  <tas1:rhs>
                     <tas1:lhs>
                        <tas1:clause>
                           <tas1:column tableName="WFTask">
                              <tas1:columnName>textAttribute1</tas1:columnName>
                           </tas1:column>
                           <tas1:operator>EQ</tas1:operator>
                           <tas1:value>MyTask</tas1:value>
                        </tas1:clause>
                        <tas1:clause joinOperator="AND">
                           <tas1:column tableName="WFTask">
                              <tas1:columnName>textAttribute2</tas1:columnName>
                           </tas1:column>
                           <tas1:operator>EQ</tas1:operator>
                           <tas1:value>1234</tas1:value>
                        </tas1:clause>
                     </tas1:lhs>
                     <tas1:logicalOperator>OR</tas1:logicalOperator>
                     <tas1:rhs>
                        <tas1:clause>
                           <tas1:column tableName="WFTask">
                              <tas1:columnName>textAttribute2</tas1:columnName>
                           </tas1:column>
                           <tas1:operator>EQ</tas1:operator>
                           <tas1:value>123</tas1:value>
                        </tas1:clause>
                     </tas1:rhs>
                  </tas1:rhs>
               </tas1:predicate>
            </tas1:predicate>
         </tas1:taskPredicateQuery>
      </tas:taskListRequest>
   </soapenv:Body>
</soapenv:Envelope>



At last we can also try update a Task with a particular outcome. For this we need to use the TaskService
http://soa-server:8001/integration/services/TaskService/TaskServicePort?WSDL

Use the right endpoint ( not the SAML one ) and use the operation updateTaskOutcome ( this is the easiest way )


<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:tas="http://xmlns.oracle.com/bpel/workflow/taskService"
    xmlns:com="http://xmlns.oracle.com/bpel/workflow/common"
    xmlns:task="http://xmlns.oracle.com/bpel/workflow/task"
    xmlns:tas1="http://xmlns.oracle.com/bpel/workflow/TaskEvidenceService">
   <soapenv:Header/>
   <soapenv:Body>
      <tas:updateTaskOutcome>
         <com:workflowContext>
            <com:credential>
               <com:login>humantask</com:login>
               <com:password>Welcome01</com:password>
            </com:credential>
         </com:workflowContext>
         <tas:taskId>3e80842f-75c9-4e3d-b441-a7f339df4109</tas:taskId>
         <tas:outcome>OK</tas:outcome>
      </tas:updateTaskOutcome>
   </soapenv:Body>
</soapenv:Envelope>



Just provide the taskId and what the outcome should be.