public ProcessInstance lockProcessInstance ( final ProcessInstance processInstance , final boolean techSupport , final String userName ) { List < Lock > locks = ContextUtils . getLocks ( processInstance , getLockFactory ( ) , "nz.co.senanque.workflow.WorkflowClient.lock(ProcessInstance)" ) ; LockTemplate lockTemplate = new LockTemplate ( locks , new LockAction ( ) { public void doAction ( ) { String taskId = ProcessInstanceUtils . getTaskId ( processInstance ) ; ProcessInstance pi = getWorkflowDAO ( ) . refreshProcessInstance ( processInstance ) ; // if (log.isDebugEnabled()) { // log.debug("taskId {} ProcessInstanceUtils.getTaskId(pi) {} {}",taskId,ProcessInstanceUtils.getTaskId(pi),(!taskId.equals(ProcessInstanceUtils.getTaskId(pi)))); // log.debug("pi.getStatus() {} techSupport {} {}",pi.getStatus(),techSupport,((pi.getStatus() != TaskStatus.WAIT) && !techSupport)); // log.debug("pi.getStatus() {} userName {} pi.getLockedBy() {} {}",pi.getStatus(),userName,pi.getLockedBy(),(pi.getStatus() == TaskStatus.BUSY) && !userName.equals(pi.getLockedBy()) && !techSupport); // } if ( ! techSupport ) { if ( ! ( taskId . equals ( ProcessInstanceUtils . getTaskId ( pi ) ) && ( ( pi . getStatus ( ) == TaskStatus . WAIT ) || ( ( pi . getStatus ( ) == TaskStatus . BUSY ) && userName . equals ( pi . getLockedBy ( ) ) ) ) ) ) { // // In this case we did not actually fail to get the lock but // // the process is not in the state // // it was in when we saw it in the table because another // // user (probably) has updated it. // // Therefore it is dangerous to proceed (unless we are tech support) throw new RuntimeException ( "ProcessInstance is already busy" ) ; } } pi . setStatus ( TaskStatus . BUSY ) ; pi . setLockedBy ( userName ) ; TaskBase task = getCurrentTask ( pi ) ; Audit audit = createAudit ( pi , task ) ; getWorkflowDAO ( ) . mergeProcessInstance ( pi ) ; } } ) ; boolean weAreOkay = true ; try { weAreOkay = lockTemplate . doAction ( ) ; } catch ( Exception e ) { weAreOkay = false ; } if ( ! weAreOkay ) { return null ; } return getWorkflowDAO ( ) . refreshProcessInstance ( processInstance ) ; }
This manages the transition of the process instance from Waiting to Busy with appropriate locking and unlocking . Once it is busy it is ours but we have to check that it was not changed since we last saw it . The situation we are protecting against is that although the process instance looked to be in wait state in the table we might have sat on that for a while and someone else may have updated it meanwhile . In that case we reject the request unless we are TECHSUPPORT . Those guys can do anything .