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

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.