Pages

Showing posts with label web services. Show all posts
Showing posts with label web services. Show all posts

Tuesday, April 2, 2013

Token Configurations in Oracle SOA Suite PS6 ( 11.1.1.7.0)

Oracle Soa Suite PatchSet 6 or 11.1.1.7.0  now has support for Token configurations which really can help administrators in configuring or overriding external Web Service Reference parameters like the protocol ( http, oramds or https ),  the remote host etc. And more important if you do it right you can kick out the all those Soa Suite deployment plans :-)

Important to know this only works on the location attribute of the binding.ws element of the composite.xml file. But when you use Metadata Service (MDS) and call a Web Service like a Java WS, .Net WS,  OSB or SOA Suite Reference Services then you can use this new feature.

In this blogpost I will show you all the steps.

First step is to make all these services in depended of each other ( Don't want invalid composites or want to use deployment plans ), I followed this great AIA blog about Best Practices for Decoupling Services and Avoiding Invalid Composites at Server Startup

In this demo I created a workspace with a MDS project which contains some WSDL's with a XML Schema. This WSDL is used in the Helloworld Reference Soa project. Deployed it together with the MDS soa sar and I put the Impl of the Reference WSDL back to the MDS so it can be used in my other main project ( I downloaded it from the EM and changed the xml schema import ).

The main project will call this helloworld reference service and in this project we will use a server name token in the WSDL url ( location attribute of the binding.ws element ).


In my main project I added this externel reference web service to my composite by selecting the Reference Impl from the MDS  ( First add a File MDS in the Resource Palette and map this to your local MDS location and finally lookup the WSDL, for compiling you also need to add an extra MDS location to the adf-config.xml )

After adding the reference service, we need to fix some hard references in the composite.xml to this remote service.
  • Change the location attribute of the composite import to oramds://
  • Do the same for ui:wsdlLocation attribute of the Reference element.
  • In the location attribute of the Binding.WS element we need to use the real reference WSDL url ( see the EM for the reference WSDL url  ). 



Do the same for the Reference Wrapper WSDL



Now our main Soa Suite project only needs this reference service at runtime and we won't have any deployment issues or invalid composites after a reboot of the Soa Suite Service.

Next step is to create a Token file which contains some server host entries, we can use this file in the JDeveloper Token wizard or later when we want to import these Tokens in the Oracle Enterprise Manager.  See this url for an Token xml example http://docs.oracle.com/cd/E28280_01/dev.1111/e10224/sca_bindingcomps.htm#CIHFJFJC

I added two host key values entries 


Click the token button of the composite.xml editor.


Select our reference service and click on edit.

Lookup the just created Token file and on the Host field we can lookup our LocalSoaServer entry.




This will change the location attribute to http://${LocalSoaServer}:8001.....


We are ready to compile the project.


The Soa Suite server does not know this LocalSoaServer token so we need to create this token in the Enterprise Manager.

Go to SOA Infrastructure -> SOA Administration -> Token Configurations.


Click on Modify Configuration File and add a new token.



Add the LocalSoaServer Token with its value.


Commit this token.



 This will update the mdm-url-resolver.xml file located in the config/fmwconfig folder of the weblogic soa domain.


 We can also upload the Token file of JDeveloper, this will add the missing tokens.



You need to reboot the Soa Server, after this you can deploy the main project and test the main project.

here is the demo workspace with all the above code.

Thursday, August 2, 2012

Return a fault from an Asynchronous Web Service

In an asynchronous web service we can't return a soap fault like a synchronous service but that does not mean you can't report back the fault to the calling asynchronous process.

basically you got three options.

  • Off course handle the fault in the error hospital and give back the response. 
  • In the response message you can add a section ( a XSD choice with success and fault section) which can be used for faults.
  • Do a callback to a common fault operation of the calling process. This can be a JMS message with the messageId/correlationId or a Web Service invocation where we use the correlation of BPEL to match the fault message with the right process. 

In this blogpost I will show how to implement the last two options in Oracle BPEL.

First we start with returning the fault in a response message.

For this I added a status element to the response and a choice for a success and a fault .


In the catch section you can also invoke the callback response and in the Assign activity you can fill the fault section of the response message.




Do a fault callback to the calling process,  for this we need to do the following.

Create an Asynchronous BPEL process.

Define a fault response schema. The EmployeeId element is necessary, we need this for the correlation of the BPEL processes.


Then make a new WSDL with the fault callback operation and add a fake endpoint. ( we will override this endpoint from BPEL, because we don't know the endpoint of the calling process).


Add a FaultCallback reference web service based on this WSDL and add a wire to the BPEL process.


In the BPEL receive activity, we need to capture the fault callback url. We can optional use this for the fault response endpoint.  Go the properties tab and capture the value of the faultToAddress property. Put the value in the faultCallBackUrl variable.



In the Catch section of the BPEL process we can invoke the fault reference service. Off course use an assign to add the EmployeeId and provide a fault message.


Open the fault invoke activity and go to the properties tab.


We need to set the endpointURI property with the faultCallBackUrl variable value.


That is all for the Asynchronous Service.

Next step is to use this Asynchronous Fault Service in an other asynchronous BPEL process.

We need to make a WSDL ( contract first ) with a portType which also contains the fault operation, this must match with the reference WSDL of the Asynchronous Fault Process. So operationName, Message and namespace must match.

Create a new BPEL process which is based on this WSDL ( expose this BPEL as a service ) and also add wire the Asynchronous Fault process.


This is the process with InvokeEmployee activity which calls the Asynchronous Service.



Open this invoke activity and go to the properties tab where we set the faultToAddress property. This is the endpoint of this BPEL process and will be used for the fault callback.


After the invoke we need to use a pick activity and add an extra onMessage to the pick activity.
First OnMessage will be used for the normal callback situation.


The second will be used for the fault Response.


The last step is to setup correlation in this BPEL for the returning fault message.

on the receive add a correlation set and initiate this ( I got a NPE when I tried to set it on the invoke ). The Set is based on the employeeId element.



Add two Property Aliases , first is based on the employeeId element of the Fault Message and second is the employeeId of the request message.


On the fault OnMessage we need to add the same correlation set and this time we don't need to initiate it.



If everything is Ok we will see the following in the Enterprise Manager.

on the invoke we set the faultToAddress, the normal response OnMessage is cancelled and the fault OnMessage gets a response with the fault message.



On github you can download this example https://github.com/biemond/soa11g_examples/tree/master/AsynchronousFaultHandling

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.