Sunday Mar 09, 2014

Building custom audit trails for human workflow monitoring

Business Process Management applications usually have a lot of human interaction steps. Whenever somebody does something most probably ou there is another person who will need to be informed about this. As a result, the need of delivering customized and comprehensive control tools would always be an important requirement for somebody using BPM.

This article will explain in a few simple steps how you can create you own audit trail which delivers data about all the human interactions inside your BPM process. The main mechanism used is the business events callbacks made available by the human workflow component inside the SOA infrastructure.

[Read More]

Monday Apr 02, 2012

Handling HumanTask attachments in Oracle BPM 11g PS4FP+ (II)

Retrieving uploaded attachments -UCM-

As stated in my previous blog entry, Oracle BPM 11g 11.1.1.5.1 (aka PS4FP) introduced a new cool feature whereby you can use Oracle WebCenter Content (previously known as Oracle UCM) as the repository for the human task attached documents. For more information about how to use or enable this feature, have a look here.

The attachment scope (either TASK or PROCESS) also applies to UCM-attachments. But even with this other feature, one question might arise when using UCM attachments. How can I get them from within the process?

The first answer would be to use the same getTaskAttachmentContents() XPath function already explained in my previous blog entry. In fact, that's the way it should be. But in Oracle BPM 11g 11.1.1.5.1 (PS4FP) and 11.1.1.6.0 (PS5) there's a bug that prevents you to do that. If you invoke such function against a UCM-attachment, you'll get a null content response (bug#13907552). Even if the attachment was correctly uploaded.

While this bug gets fixed, next I will show a workaround that lets me to retrieve the UCM-attached documents from within a BPM process. Besides, the sample will show how to interact with WCC API from within a BPM process.


Aside note: I suggest you to read my previous blog entry about Human Task attachments where I briefly describe some concepts that are used next, such as the execData/attachment[] structure.

Sample Process

I will be using the following sample process:


A dummy UserTask using "HumanTask2" Human Task, followed by an Embedded Subprocess that will retrieve the attachments payload. In this case, and here's the key point of the sample, we will retrieve such payload using WebCenter Content WebService API (IDC):


and once retrieved, we will write each of them back to a file in the server using a File Adapter service:


In detail:

  •  We will use the same attachmentCollection XSD structure and same BusinessObject definition as in the previous blog entry. However we create a separate variable, named attachmentUCM, based on such BusinessObject.
  • We will still need to keep a copy of the HumanTask output's execData structure. Therefore we need to create a new variable of type TaskExecutionData (different one than the other used for non-UCM attachments):

  • As in the non-UCM attachments flow, in the output tab of the UserTask mapping, we'll keep a copy of the execData structure:

  • Now we get into the embedded subprocess that will retrieve the attachments' payload. First, and using an XSLT transformation, we feed the attachmentUCM variable with the following information:
    • The name of each attachment (from execData/attachment/name element)
    • The WebCenter Content ID of the uploaded attachment. This info is stored in execData/attachment/URI element with the format ecm://<id>. As we just want the numeric <id>, we need to get rid of the protocol prefix ("ecm://"). We do so with some XPath functions as detailed below:

with these two functions being invoked, respectively:



    • We, again, set the target payload element with an empty string, to get the <payload></payload> tag created.
The complete XSLT transformation is shown below. Remember that we're using the XSLT for-each node to create as many target structures as necessary. 


  • Once we have fed the attachmentsUCM structure and so it now contains the name of each of the attachments along with each WCC unique id (dID), it is time to iterate through it and get the payload. Therefore we will use a new embedded subprocess of type MultiInstance, that will iterate over the attachmentsUCM/attachment[] element:

  • In each iteration we will use a Service activity that invokes WCC API through a WebService. Follow these steps to create and configure the Partner Link needed:
    • Login to WCC console with an administrator user (i.e. weblogic). Go to Administration menu and click on "Soap Wsdls" link. We will use the GetFile service to retrieve a file based on its dID. Thus we'll need such service WSDL definition that can be downloaded by clicking the GetFile link. Save the WSDL file in your JDev project folder.

    • In the BPM project's composite view, drag & drop a WebService adapter to create a new External Reference, based on the just added GetFile.wsdl. Name it UCM_GetFile.
    • WCC services are secured through basic HTTP authentication. Therefore we need to enable the just created reference for that:
      • Right-click the reference and click on Configure WS Policies.
      • Under the Security section, click "+" to add the "oracle/wss_username_token_client_policy" policy

    • The last step is to set the credentials for the security policy. For the sample we will use the admin user for WCC (weblogic/welcome1). Open the composite.xml file and select the Source view.
    • Search for the UCM_GetFile entry and add the following highlighted elements into it:
  <reference name="UCM_GetFile" ui:wsdlLocation="GetFile.wsdl">
    <interface.wsdl interface="http://www.stellent.com/GetFile/#wsdl.interface(GetFileSoap)"/>
    <binding.ws port="http://www.stellent.com/GetFile/#wsdl.endpoint(GetFile/GetFileSoap)"
                location="GetFile.wsdl" soapVersion="1.1">
      <wsp:PolicyReference URI="oracle/wss_username_token_client_policy"
                           orawsp:category="security" orawsp:status="enabled"/>
      <property name="weblogic.wsee.wsat.transaction.flowOption"
                type="xs:string" many="false">WSDLDriven</property>
      <property name="oracle.webservices.auth.username"
                type="xs:string">weblogic</property>
      <property name="oracle.webservices.auth.password"
                type="xs:string">welcome1</property>
    </binding.ws>
  </reference>
    • Now the new external reference is ready:

  • Once the reference has just been created, we should be able now to use it from our BPM process. However we find here a problem. The WCC GetFile service operation that we will use, GetFileByID, accepts as input a structure similar to this one, where all element tags are optional:
<get:GetFileByID xmlns:get="http://www.stellent.com/GetFile/">
   <get:dID>?</get:dID>
   <get:rendition>?</get:rendition>
   <get:extraProps>
      <get:property>
         <get:name>?</get:name>
         <get:value>?</get:value>
      </get:property>
   </get:extraProps>
</get:GetFileByID>

and we need to fill up just the <get:dID> tag element. Due to some kind of restriction or bug on WCC, the rest of the tag elements must NOT be sent, not even empty (i.e.: <get:rendition></get:rendition> or <get:rendition/>). A sample request that performs the query just by the dID, must be in the following format:

<get:GetFileByID xmlns:get="http://www.stellent.com/GetFile/">
   <get:dID>12345</get:dID>
</get:GetFileByID>

The issue here is that the simple mapping in BPM does create empty tags being a sample result as follows:

<get:GetFileByID xmlns:get="http://www.stellent.com/GetFile/">
   <get:dID>12345</get:dID>
   <get:rendition/>
   <get:extraProps/>
</get:GetFileByID>

Although the above structure is perfectly valid, it is not accepted by WCC. Therefore, we need to bypass the problem. The workaround we use (many others are available) is to add a Mediator component between the BPM process and the Service that simply copies the input structure from BPM but getting rid of the empty tags. Follow these steps to configure the Mediator:

    • Drag & drop a new Mediator component into the composite.
    • Uncheck the creation of the SOAP bindings and use the Interface Definition from WSDL template and select the existing GetFile.wsdl

    • Double click in the mediator to edit it. Add a static routing rule to the GetFileByID operation, of type Service and select References/UCM_GetFile/GetFileByID target service:

    • Create the request and reply XSLT mappers:

Make sure you map only the dID element in the request:


And do an Auto-mapper for the whole response:


  • Finally, we can now add and configure the Service activity in the BPM process. Drag & drop it to the embedded subprocess and select the NormalizedGetFile service and getFileByID operation:

  • Map both the input:

  • ...and the output:

  • Once this embedded subprocess ends, we will have all attachments (name + payload) in the attachmentsUCM variable, which is the main goal of this sample. But in order to test everything runs fine, we finish the sample writing each attachment to a file. To that end we include a final embedded subprocess to concurrently iterate through each attachmentsUCM/attachment[] element:

  • On each iteration we will use a Service activity that invokes a File Adapter write service. In here we have two important parameters to set. First, the payload itself. The file adapter awaits binary data in base64 format (string). We have to map it using XPath (Simple mapping doesn't recognize a String as a base64-binary valid target):

Second, we must set the target filename using the Service Properties dialog box:


Again, note how we're making use of the loopCounter index variable to get the right element within the embedded subprocess iteration.

Final blog entry about attachments will handle how to inject documents to Human Tasks from the BPM process and how to share attachments between different User Tasks. Will come soon.

Again, once I finish will all posts on this matter, I will upload the whole sample project to java.net.

Thursday Mar 29, 2012

Handling HumanTask attachments in Oracle BPM 11g PS4FP+ (I)

Adding attachments to a HumanTask is a feature that exists in Oracle HWF (Human Workflow) since 10g.

However, in 11g there have been many improvements on this feature and this entry will try to summarize them.

Oracle BPM 11g 11.1.1.5.1 (aka PS4 Feature Pack or PS4FP) introduced two great features:

  • Ability to link attachments at a Task scope or at a Process scope:
    • "Task" attachments are only visible within the scope (lifetime) of a task. This means that, initially, any member of the assignment pattern of the Human Task will be able to handle (add, review or remove) attachments. However, once the task is completed, subsequent human tasks will not have access to them. This does not mean those attachments got lost. Once the human task is completed, attachments can be retrieved in order to, i.e., check them in to a Content Server or to inject them to a new and different human task.

    Aside note: a "re-initiated" human task will inherit comments and attachments, along with history and -optionally- payload. See here for more info.

      • "Process" attachments are visible within the scope of the process. This means that subsequent human tasks in the same process instance will have access to them.
    • Ability to use Oracle WebCenter Content (previously known as "Oracle UCM") as the backend for the attachments instead of using HWF database backend. This feature adds all content server document lifecycle capabilities to HWF attachments (versioning, RBAC, metadata management, etc). As of today, only Oracle WCC is supported. However, Oracle BPM Suite does include a license of Oracle WCC for the solely usage of document management within BPM scope.

    Here are some code samples that leverage the above features.

    Retrieving uploaded attachments -Non UCM-

    Non UCM attachments (default ones or those that have existed from 10g, and are stored "as-is" in HWK database backend) can be retrieved after the completion of the Human Task. Firstly, we need to know whether any attachment has been effectively uploaded to the human task. There are two ways to find it out:

    • Through an XPath function:

    • Checking the execData/attachment[] structure. For example:

    Once we are sure one ore more attachments were uploaded to the Human Task, we want to get them. In this example, by "get" I mean to get the attachment name and the payload of the file. 


    Aside note: Oracle HWF lets you to upload two kind of [non-UCM] attachments: a desktop document and a Web URL. This example focuses just on the desktop document one. In order to "retrieve" an uploaded Web URL, you can get it directly from the execData/attachment[] structure.

    Attachment content (payload) is retrieved through the getTaskAttachmentContents() XPath function:

    This example shows how to retrieve as many attachments as those had been uploaded to the Human Task and write them to the server using the File Adapter service.

    The sample process excerpt is as follows:

     A dummy UserTask using "HumanTask1" Human Task followed by a Embedded Subprocess that will retrieve the attachments (we're assuming at least one attachment is uploaded):

    and once retrieved, we will write each of them back to a file in the server using a File Adapter service:

    In detail:

    • We've defined an XSD structure that will hold the attachments (both name and payload):

    • Then, we can create a BusinessObject based on such element (attachmentCollection) and create a variable (named attachmentBPM) of such BusinessObject type.
    • We will also need to keep a copy of the HumanTask output's execData structure. Therefore we need to create a variable of type TaskExecutionData...

    • ...and copy the HumanTask output execData to it:

    • Now we get into the embedded subprocess that will retrieve the attachments' payload. First, and using an XSLT transformation, we feed the attachmentBPM variable with the name of each attachment and setting an empty value to the payload:

    Please note that we're using the XSLT for-each node to create as many target structures as necessary. Also note that we're setting an Empty text to the payload variable. The reason for this is to make sure the <payload></payload> tag gets created. This is needed when we map the payload to the XML variable later.


    Aside note: We are assuming that we're retrieving non-UCM attachments. However in real life you might want to check the type of attachment you're handling. The execData/attachment[]/storageType contains the values "UCM" for UCM type attachments, "TASK" for non-UCM ones or "URL" for Web URL ones. Those values are part of the "Ext.Com.Oracle.Xmlns.Bpel.Workflow.Task.StorageTypeEnum" enumeration.
    • Once we have fed the attachmentsBPM structure and so it now contains the name of each of the attachments, it is time to iterate through it and get the payload. Therefore we will use a new embedded subprocess of type MultiInstance, that will iterate over the attachmentsBPM/attachment[] element:

    • In every iteration we will use a Script activity to map the corresponding payload element with the result of the XPath function getTaskAttachmentContents(). Please, note how the target array element is indexed with the loopCounter predefined variable, so that we make sure we're feeding the right element during the array iteration:

     The XPath function used looks as follows:

    hwf:getTaskAttachmentContents(bpmn:getDataObject('UserTask1LocalExecData')/ns1:systemAttributes/ns1:taskId, bpmn:getDataObject('attachmentsBPM')/ns:attachment[bpmn:getActivityInstanceAttribute('SUBPROCESS3067107484296', 'loopCounter')]/ns:fileName

    where the input parameters are:

    taskId of the just completed Human Task

    attachment name we're retrieving the payload from

    array index (loopCounter predefined variable) 


    Aside note: The reason whereby we're iterating the execData/attachment[] structure through embedded subprocess and not, i.e., using XSLT and for-each nodes, is mostly because the getTaskAttachmentContents() XPath function is currently not available in XSLT mappings. So all this example might be considered as a workaround until this gets fixed/enhanced in future releases.

    • Once this embedded subprocess ends, we will have all attachments (name + payload) in the attachmentsBPM variable, which is the main goal of this sample. But in order to test everything runs fine, we finish the sample writing each attachment to a file. To that end we include a final embedded subprocess to concurrently iterate through each attachmentsBPM/attachment[] element:


    • On each iteration we will use a Service activity that invokes a File Adapter write service. In here we have two important parameters to set. First, the payload itself. The file adapter awaits binary data in base64 format (string). We have to map it using XPath (Simple mapping doesn't recognize a String as a base64-binary valid target):

     Second, we must set the target filename using the Service Properties dialog box:

     Again, note how we're making use of the loopCounter index variable to get the right element within the embedded subprocess iteration.

    Handling UCM attachments will be part of a different and upcoming blog entry. Once I finish will all posts on this matter, I will upload the whole sample project to java.net.

    Saturday Feb 18, 2012

    Withdrawing Tasks

    Oracle BPM has a pre-defined action (also known as system action) that allows an user to withdraw a task. This article will provide a quick summary of how the BPMN process should handle withdrawn tasks.

    Concept(s)

    The BPMN process should check the state of the task (and not the outcome) to know that the task was withdrawn.

    Withdraw for Initiate Tasks

    Withdraw for initiate tasks should be handled just like withdraw for any other task. Note that in the Initiate Task pattern the process is created before the form is launched; this is quite useful in initializing the form data. If abandonment of tasks is a particular concern, then instead of using the Initiate Task pattern, an UI external to the process should be used that kicks off the process via service or event interface.

    Details

    Business Object based on State

    To hold the state result of a task we will need data objects in the process to which we can assign the value. Therefore, we will need to create a business object corresponding to Task.StateEnum type. This can be easily done in the business object create wizard by selecting the Based on External Schema option, clicking on the ellipsis, and then selecting StateEnum as shown below.

    Example Process

    In the process, after the task whose withdrawal we need to handle, we need to use a gateway to test the state and branch accordingly. A small example is shown below where if the task is withdrawn, we end the process.

    Assigning the value of state

    In the task's ouput data association, assign the value of execData.systemAttributes.state to the process data object meant for holding this value, in this example, taskState, as shown below.

    Test for Withdrawal

    The test for withdrawal would be of the form "taskState == State.WITHDRAWN". Note that since the State business object is based on an enumeration, we don't need to know the exact values and typing State. in the expression editor will show the different enumeration values.

    About

    Technical and in-depth articles and samples on BPM 11g.

    Search

    Archives
    « April 2014
    SunMonTueWedThuFriSat
      
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
       
           
    Today