AnsweredAssumed Answered

Error with timer in a workflow

Question asked by mlagneaux on Sep 14, 2011
Latest reply on Sep 20, 2011 by mlagneaux
Hello,

I'm using Alfresco 3.4e.
I've modified Alfresco content model adding a new property status (Draft, Validate, …) to cm:content node. I've developped the following workflow in order to change the status of the document related to the workflow.

Here is the workflow process definition :

<?xml version="1.0" encoding="UTF-8"?>

<process-definition  xmlns="urn:jbpm.org:jpdl-3.1"  name="mbswf:validateByTeam">

   <!–Definition des swimlanes–>
   <swimlane name="initiator">
   </swimlane>
   
   <swimlane name="validationTeam">
        <assignment class="org.alfresco.repo.workflow.jbpm.AlfrescoAssignment">
            <actor>#{mbswf_validationTeam}</actor>
        </assignment>   
    </swimlane>

   <!– Definition des etapes –>
   <start-state name="start-state1">
      <task name="mbswf:readPermissionStartTask" swimlane="initiator"/>
      <transition to="teamSelection">
         <action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript">
            <script>
               <variable name="oldStatusName" access="write" />
               <expression>
                  var doc = bpm_package.children[0];
                  oldStatusName = doc.properties["mbs:statusName"] ;
               </expression>
            </script>
         </action>
         <action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript">
            <script>
               <variable name="newStatusName" access="write" />
               <expression>
                  newStatusName = "Validate";
               </expression>
            </script>
         </action>
         <action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript">
            <script>
               <variable name="statusNameValue" access="write" />
               <expression>
                  statusNameValue = "In Progress";
               </expression>
            </script>
         </action>
      </transition>
   </start-state>


   <task-node name="teamSelection">
      <task name="mbswf:validateByTeam_teamSelection" swimlane="initiator"/>
      <transition to="teamTaskAssignment" name="teamSelected">
         <action class="fr.mbs.bpm.SetStatusNameAction"/>
      </transition>
   </task-node>

   <node name="teamTaskAssignment">
      <action class="org.alfresco.repo.workflow.jbpm.ForEachFork">
         <foreach>#{mbswf_validationTeam}</foreach>
         <var>validator</var>
      </action>
      <event type="node-enter">
         <script>
            <variable name="reject_count" access="write" />
            <expression>
               reject_count = 0;
            </expression>
         </script>
      </event>
      <transition to="validation"></transition>
   </node>

   <task-node name="validation">
      <task name="mbswf:validateByTeam_validation">
         <assignment class="org.alfresco.repo.workflow.jbpm.AlfrescoAssignment">
              <actor>#{validator}</actor>
            </assignment>
         <timer name="validationTimer" duedate="5 minutes" transition="ok">
            <action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript">
               <script>
                  logger.log("Validation timer expired");
               </script>
            </action>
         </timer>
      </task>
      <transition to="join1" name="ok"></transition>
      <transition to="join1" name="ko">
         <action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript">
            <script>
               <variable name="reject_count" access="read,write" />
               <expression>
                  reject_count = reject_count + 1;
               </expression>
            </script>
         </action>
      </transition>
   </task-node>

   <join name="join1">
      <transition to="isRejected"></transition>
   </join>

   <decision name="isRejected">
      <transition to="end-state1" name="documentValidated">
         <condition>#{reject_count == 0}</condition>
         <action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript">
            <script>
               <variable name="newStatusName" access="read" />
               <variable name="statusNameValue" access="write" />
               <expression>
                  statusNameValue = newStatusName;
               </expression>
            </script>
         </action>
         <action class="fr.mbs.bpm.SetStatusNameAndDateAction"/>
      </transition>
      <transition to="end-state2" name="documentValidationRejected">
         <action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript">
            <script>
               <variable name="oldStatusName" access="read" />
               <variable name="statusNameValue" access="write" />
               <expression>
                  statusNameValue = oldStatusName;
               </expression>
            </script>
         </action>
         <action class="fr.mbs.bpm.SetStatusNameAction"/>
      </transition>
   </decision>

   <end-state name="end-state1"></end-state>

   <end-state name="end-state2"></end-state>


</process-definition>
teamSelection task asks to select diffrent users (association with many cm:person in type mbswf:validateByTeam_teamSelection). Each selected user has a validation task.

validation task has a timer which triggers "ok" transition after 5 minutes.

SetStatusNameAction and SetStatusNameAndDateAction classes change properties of document in the workflow package (status and status validity date).
As an example, here is my SetStatusNameAndDateAction class :

package fr.mbs.bpm;

import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Properties;

import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.workflow.WorkflowModel;
import org.alfresco.repo.workflow.jbpm.JBPMNode;
import org.alfresco.repo.workflow.jbpm.JBPMSpringActionHandler;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.apache.log4j.Logger;
import org.jbpm.graph.exe.ExecutionContext;
import org.springframework.beans.factory.BeanFactory;

import fr.mbs.model.MbsModel;

public class SetStatusNameAndDateAction extends JBPMSpringActionHandler {
   
   private static final long serialVersionUID = 1L;

   private static Logger logger = Logger.getLogger(SetStatusNameAndDateAction.class);
   
   private static final String VAR_STATUS_NAME_VALUE = "statusNameValue";
   private static final String VAR_BPM_PACKAGE = "bpm_package";
   private static final String PROP_STATUS_VALIDITY_DURATION = "status.validity.duration";
   private static final int DEFAULT_STATUS_VALIDITY_DURATION = 12;
   
   private NodeService nodeService;
   private Properties mbsProperties;

   public void execute(ExecutionContext executionContext) throws Exception {
      logger.debug("Inside SetStatusNameAndDateAction.execute()");
      
      // get the status name
      final String statusName = (String)executionContext.getContextInstance().getVariable(VAR_STATUS_NAME_VALUE);
      
      // get the workflow package
      NodeRef pkg = ((JBPMNode)executionContext.getContextInstance().getVariable(VAR_BPM_PACKAGE)).getNodeRef();
            
      List<ChildAssociationRef> childrenList = this.nodeService.getChildAssocs(pkg, 
            WorkflowModel.ASSOC_PACKAGE_CONTAINS, RegexQNamePattern.MATCH_ALL);
      for(ChildAssociationRef childAssoc:childrenList){
         // get child node ref
         final NodeRef nodeRef = childAssoc.getChildRef();
         final Calendar statusDate = getStatusDate();
         logger.debug("Inside SetStatusNameAndDateAction.execute() - processing nodeRef : "+nodeRef);
         
         AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>(){
            public Object doWork() throws Exception
            {
               nodeService.setProperty(nodeRef, MbsModel.PROP_STATUS_NAME, statusName);
               nodeService.setProperty(nodeRef, MbsModel.PROP_STATUS_DATE, statusDate);

               return null;
            }
         }, AuthenticationUtil.getAdminUserName());
         
      }
   }

   @Override
   protected void initialiseHandler(BeanFactory factory) {
      this.nodeService = (NodeService)factory.getBean("nodeService");
      this.mbsProperties = (Properties)factory.getBean("mbs-properties");
   }
   
   //————————————————————————————————————-
   // Helpers
   
   private Calendar getStatusDate() {
      Calendar statusDate = new GregorianCalendar();
      int statusValidityDuration = getStatusValidityDuration();
      statusDate.add(Calendar.MONTH, statusValidityDuration);
      
      return statusDate;
   }
   
   private int getStatusValidityDuration() {
      int statusValidityDuration;
      
      String statusValidityDurationProperty = this.mbsProperties.getProperty(PROP_STATUS_VALIDITY_DURATION);
      
      try{
         statusValidityDuration = Integer.parseInt(statusValidityDurationProperty);
         
         if(statusValidityDuration < 1){
            statusValidityDuration = DEFAULT_STATUS_VALIDITY_DURATION;
         }
      }
      catch(NumberFormatException e){
         statusValidityDuration = DEFAULT_STATUS_VALIDITY_DURATION;
      }
      
      return statusValidityDuration;
   }

}

When the transition "ok" is triggered by the timer, I get the following error in my logs :

09:23:48,826  ERROR [workflow.jbpm.AlfrescoJobExecutorThread] failed to execute Timer(validationTimer,2011-09-13 09:22:47,000,TaskInstance(mbswf:validateByTeam_validation),Token(/FOREACHFORK.0))
org.alfresco.error.AlfrescoRuntimeException: 08130003 Failed to execute transaction-level behaviour public abstract void org.alfresco.repo.node.NodeServicePolicies$OnUpdatePropertiesPolicy.onUpdateProperties(org.alfresco.service.cmr.repository.NodeRef,java.util.Map,java.util.Map) in transaction 4a4923d1-7dd2-4920-9a3b-56ebb3b05a59
   at org.alfresco.repo.policy.TransactionBehaviourQueue.execute(TransactionBehaviourQueue.java:195)
   at org.alfresco.repo.policy.TransactionBehaviourQueue.beforeCommit(TransactionBehaviourQueue.java:127)
   at org.alfresco.repo.transaction.AlfrescoTransactionSupport$TransactionSynchronizationImpl.doBeforeCommit(AlfrescoTransactionSupport.java:732)
   at org.alfresco.repo.transaction.AlfrescoTransactionSupport$TransactionSynchronizationImpl.doBeforeCommit(AlfrescoTransactionSupport.java:712)
   at org.alfresco.repo.transaction.AlfrescoTransactionSupport$TransactionSynchronizationImpl.beforeCommit(AlfrescoTransactionSupport.java:672)
   at org.springframework.transaction.support.TransactionSynchronizationUtils.triggerBeforeCommit(TransactionSynchronizationUtils.java:95)
   at org.springframework.transaction.support.AbstractPlatformTransactionManager.triggerBeforeCommit(AbstractPlatformTransactionManager.java:927)
   at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:737)
   at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
   at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:394)
   at org.alfresco.util.transaction.SpringAwareUserTransaction.commit(SpringAwareUserTransaction.java:472)
   at org.alfresco.repo.transaction.RetryingTransactionHelper.doInTransaction(RetryingTransactionHelper.java:403)
   at org.alfresco.repo.transaction.RetryingTransactionHelper.doInTransaction(RetryingTransactionHelper.java:253)
   at org.alfresco.repo.workflow.jbpm.AlfrescoJobExecutorThread.executeJob(AlfrescoJobExecutorThread.java:187)
   at org.jbpm.job.executor.JobExecutorThread.run(JobExecutorThread.java:60)
Caused by: net.sf.acegisecurity.AuthenticationCredentialsNotFoundException: A valid SecureContext was not provided in the RequestContext
   at net.sf.acegisecurity.intercept.AbstractSecurityInterceptor.credentialsNotFound(AbstractSecurityInterceptor.java:477)
   at net.sf.acegisecurity.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:355)
   at net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:77)
   at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
   at org.alfresco.repo.security.permissions.impl.ExceptionTranslatorMethodInterceptor.invoke(ExceptionTranslatorMethodInterceptor.java:44)
   at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
   at org.alfresco.repo.audit.AuditMethodInterceptor.proceedWithAudit(AuditMethodInterceptor.java:217)
   at org.alfresco.repo.audit.AuditMethodInterceptor.proceed(AuditMethodInterceptor.java:184)
   at org.alfresco.repo.audit.AuditMethodInterceptor.invoke(AuditMethodInterceptor.java:137)
   at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
   at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:107)
   at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
   at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
   at $Proxy8.exists(Unknown Source)
   at org.alfresco.repo.rendition.RenditionedAspect.onUpdateProperties(RenditionedAspect.java:140)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
   at java.lang.reflect.Method.invoke(Unknown Source)
   at org.alfresco.repo.policy.JavaBehaviour$JavaMethodInvocationHandler.invoke(JavaBehaviour.java:173)
   at $Proxy12.onUpdateProperties(Unknown Source)
   at sun.reflect.GeneratedMethodAccessor402.invoke(Unknown Source)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
   at java.lang.reflect.Method.invoke(Unknown Source)
   at org.alfresco.repo.policy.TransactionBehaviourQueue.execute(TransactionBehaviourQueue.java:183)
   … 14 more
Do you know the cause of that problem

Developments related to this workflow are the only changes made to Alfresco 3.4e.
I have no error when a user is taking my transitions.

Thanks for your help. Do not hesitate if you need further informatios.

Outcomes