Showing posts with label BPM 11g. Show all posts
Showing posts with label BPM 11g. Show all posts

Sunday, 6 November 2016

Fixing ORABPEL-02117 Variable already declared. A variable with key "XXXX" is already declared in the current scope.

A surprise error message occurs after the successful deploy of the BPM project. To resolve it look for duplicate definitions in the BPMN process files. In my case I had:

<ns5:Conversation id="CONVERSATION155142191537" type="service_call">
          <ns5:ServiceCallConversationDefinition service="Services.Externals.GetApplicationData"/>
         </ns5:Conversation>
         <ns5:Conversation id="CONVERSATION176785361049" type="service_call">
          <ns5:ServiceCallConversationDefinition service="Services.Externals.GetApplicationData"/>
         </ns5:Conversation>

Removed the first occurrence and updated Conversation id to the value of the second occurrence and redeployed. The error has been resolved!

Sunday, 24 April 2016

End BPM process instance on a given day of month

Use case:
We need to end (close) a process instance on a given day of month. To further complicate things let's assume that a day is not fixed. An admin should be able to change the end day without re-deploying the BPM project.

With 11gR1 (11.1.1.7) you can achieve the purpose by adding timer boundary event (make it the "Interrupting Event"), choosing a "Time Cycle" type and setting the boundary timer event to kick in, let's say every 12 hours. This does exactly what you want, but it kicks in every 12 hours and creates a task every 12 hours and closes it if the down the flow condition is not met.

Instead we can try another approach.

Set the timer type to "Time Cycle" and check the "Use Expression" attribute.

Write an expression, in my case it is:

oraext:query-database(concat('SELECT GET_CLOSURE_DURATION(', "'", bpmn:getDataObject('applicationDataDO')/ns:applicationId, "'" ,') NEXTDAY FROM dual'),false(),false(),'jdbc/DATASOURCE')

where get_closure_duration(applicationid in varchar2) is a function, which returns duration in the P1Y1DT1H1S - One year, one day, one hour and one second form. The function parameter applicationid is used to further fine tune the result.

Now we write the get_closure_duration function in a such a way, that it returns the duration. For demonstration purposes, I set the end date to be 7th day of the next month at 10 PM:

FUNCTION GET_CLOSURE_DURATION(
    APPLICATIONID VARCHAR2)
  RETURN VARCHAR2
IS
  NEXTDAY   NUMBER;
  NEXTDATE  DATE;
BEGIN
NEXTDAY:=7;
NEXTDATE:=TRUNC(LAST_DAY(SYSDATE) +NEXTDAY) + 22/24;

RETURN 'P'|| TRUNC(months_between(NEXTDATE, SYSDATE) /12) ||'Y'|| mod(TRUNC(months_between(NEXTDATE, SYSDATE)),
  12) ||'M'|| TRUNC(NEXTDATE-SYSDATE) || 'DT'|| TRUNC(mod((NEXTDATE-SYSDATE) *24, 24)) ||'H'|| TRUNC(mod((NEXTDATE  -  SYSDATE) *24*60, 60)) ||'M';

END GET_CLOSURE_DURATION;

E.g, to close the application on 07-MAY-16 at 22:00 the GET_CLOSURE_DURATION function gave P0Y0M6DT7H14M when run at 24-APR-16 14:45.


Friday, 15 January 2016

How to set current user in BPM tasks

To obtain current user in BPM tasks (especially when page fragments are being used) you can follow below approach.

1. First create the following java class, the current user's login is stored in HttpSession (this survives AM activation/passivation events).

package home.common.ext;

import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;

import javax.servlet.http.HttpSession;

import oracle.bpel.services.workflow.WorkflowException;
import oracle.bpel.services.workflow.client.IWorkflowServiceClient;
import oracle.bpel.services.workflow.query.ITaskQueryService;
import oracle.bpel.services.workflow.verification.IWorkflowContext;
import oracle.bpel.services.workflow.worklist.adf.ADFWorklistBeanUtil;

import oracle.jbo.client.Configuration;


public class ContextUtils {
    public ContextUtils() {
        super();
    }

    public void initializeUserContextData(String applicationId) {
        FacesContext context = FacesContext.getCurrentInstance();
        ExternalContext ectx = context.getExternalContext();
        HttpSession userSession = (HttpSession)ectx.getSession(true);
        try {
            String ctx =
                (String)context.getApplication().evaluateExpressionGet(context,
                                                                       "#{pageFlowScope.bpmWorklistContext}",
                                                                       String.class);
            IWorkflowServiceClient workflowSvcClient =
                ADFWorklistBeanUtil.getWorkflowServiceClient();
            ITaskQueryService wfQueryService =
                workflowSvcClient.getTaskQueryService();
            IWorkflowContext wfContext;
            String userName = "";
            try {
                wfContext = wfQueryService.getWorkflowContext(ctx);
                userName = wfContext.getUser();
            } catch (WorkflowException e) {
                e.printStackTrace();
            }
            if (userName != null) {
                userSession.setAttribute("currentUserLogin", userName);
                System.out.println("Current user's login from workspace is: " +
                                   userName);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2. Create data control from this class (Just right click on this class and choose "Create Data Control" from the context menu);

3. Add this method as a default activity into the Task UI project.

4. The value is also available in Model project, so you can populate your WHO columns with current user login.



How to update programmatically a BPM task acquired by field

To update a BPM task programmatically one can leverage BPM APIs. Here is a short example to update an acquired by field.
Find tasknumber, for this you need to issue a select query against WFTASK table.

E.g, let's find latest task for a given instance Id:

select taskNumber, acquiredBy from wftask
where compositeInstanceId=(instance Id)
order by taskNumber desc;

The java code itself. To have this working to you have to complete the prerequisite steps.
I forgot to mention, that this is tested with BPM 11.1.1.7.8.

package home.generic;

import java.util.HashMap;
import java.util.Map;

import oracle.bpel.services.workflow.StaleObjectException;
import oracle.bpel.services.workflow.WorkflowException;
import oracle.bpel.services.workflow.client.IWorkflowServiceClient;
import oracle.bpel.services.workflow.client.IWorkflowServiceClientConstants;
import oracle.bpel.services.workflow.client.WorkflowServiceClientFactory;
import oracle.bpel.services.workflow.query.ITaskQueryService;
import oracle.bpel.services.workflow.task.ITaskService;
import oracle.bpel.services.workflow.task.model.SystemAttributesType;
import oracle.bpel.services.workflow.task.model.Task;
import oracle.bpel.services.workflow.verification.IWorkflowContext;


public class UpdateTaskAssignees {
    public static void main(String[] args) throws WorkflowException,
                                                  StaleObjectException {
        String userid = "username";
        String password = "password";
        String serverUrl =
            "t3://localhost:8001"; // host:port of the soa server
        Map connProperties =
            new HashMap();
        connProperties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.CLIENT_TYPE,
                           WorkflowServiceClientFactory.REMOTE_CLIENT);
        connProperties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.EJB_PROVIDER_URL,
                           serverUrl);
        connProperties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.EJB_INITIAL_CONTEXT_FACTORY,
                           "weblogic.jndi.WLInitialContextFactory");
        IWorkflowServiceClient wfSvcClient =
            WorkflowServiceClientFactory.getWorkflowServiceClient(connProperties,
                                                                  null, null);
        IWorkflowContext ctx =
            wfSvcClient.getTaskQueryService().authenticate(userid,
                                                           password.toCharArray(),
                                                           "jazn.com");
        ITaskQueryService querySvc = wfSvcClient.getTaskQueryService();
        ITaskService taskSvc = wfSvcClient.getTaskService();
        // Get task by its tasknumber
        Task currentTask = querySvc.getTaskDetailsByNumber(ctx, 239120);
        SystemAttributesType types = currentTask.getSystemAttributes();
        System.out.println("Currently task is acquired by: " +
                           types.getAcquiredBy());
        types.setAcquiredBy("new_login");
        currentTask.setSystemAttributes(types);
        taskSvc.updateTask(ctx, currentTask);
    }
}