cancel
Showing results for 
Search instead for 
Did you mean: 

NullPointerException on TimerBoundaryEvent trigger

sckempgowda
Champ in-the-making
Champ in-the-making

Hi, 

We recently upgraded from Activiti 5.18 to 6.0.0.

We had a requirement to capture Activiti history only for certain workflow types. As per the suggestion from Activiti team, we had overridden the org.activiti.engine.impl.history.DefaultHistoryManager to provide overridden implementation only for the method isHistoryLevelAtLeast(HistoryLevel level)

The suggested code changes were done as follows

import org.activiti.engine.ProcessEngine;

import org.activiti.spring.SpringProcessEngineConfiguration;

import com.abc.dms.activiti.persistence.DMSHistoryManagerSessionFactory;

   public class CustomSpringProcessEngineConfiguration extends SpringProcessEngineConfiguration {

      @Override public ProcessEngine buildProcessEngine() {

         ProcessEngine processEngine = super.buildProcessEngine();

         addSessionFactory(new CustomHistoryManagerSessionFactory());

         return processEngine;

   }

}

import org.activiti.engine.impl.interceptor.Session;
import org.activiti.engine.impl.persistence.DefaultHistoryManagerSessionFactory;

import com.abc.dms.activiti.history.DMSCustomHistoryManager;

public class CustomHistoryManagerSessionFactory extends DefaultHistoryManagerSessionFactory {
   @Override
   public Session openSession() {
      return new CustomHistoryManager();
   }

}

import org.activiti.engine.impl.history.DefaultHistoryManager;
import org.activiti.engine.impl.history.HistoryLevel;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.abc.dms.activiti.cache.ActivitiThreadCache;
import com.abc.dms.activiti.constant.ActivitiConstantManager;

public class CustomHistoryManager extends DefaultHistoryManager implements ActivitiConstantManager {

   @Override
   public boolean isHistoryLevelAtLeast(HistoryLevel level) {
      // TODO Auto-generated method stub
      boolean atLeast = true;
      String hlevel = ActivitiThreadCache.get(HISTORY_LEVEL);

      HistoryLevel historyLevel = null;
      if(hlevel != null)
         historyLevel = HistoryLevel.getHistoryLevelForKey(hlevel.toLowerCase());

         if(null != historyLevel){
              atLeast = historyLevel.isAtLeast(level);
         }
         else {
            atLeast = super.isHistoryLevelAtLeast(level);
         }
      return atLeast;
   }

   @Override
   public void recordProcessInstanceStart(ExecutionEntity processInstance) {
      super.recordProcessInstanceStart(processInstance);
   }

}

After upgrading the Activiti to 6.0.0

We did the following changes,

import org.activiti.engine.ProcessEngine;
import org.activiti.spring.SpringProcessEngineConfiguration;

import com.abc.dms.activiti.history.DMSCustomHistoryManager;

public class CustomSpringProcessEngineConfiguration extends SpringProcessEngineConfiguration {

   @Override
   public ProcessEngine buildProcessEngine() {
      ProcessEngine processEngine = super.buildProcessEngine();
      return processEngine;
   }

   @Override
   public void initHistoryManager() {
      if (historyManager == null) {
         historyManager = new CustomHistoryManager(this);
      }
   }
}

import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.activiti.engine.impl.history.DefaultHistoryManager;
import org.activiti.engine.impl.history.HistoryLevel;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class DMSCustomHistoryManager extends DefaultHistoryManager implements ActivitiConstantManager {

   public DMSCustomHistoryManager(ProcessEngineConfigurationImpl processEngineConfiguration) {
      super(processEngineConfiguration, HistoryLevel.getHistoryLevelForKey(processEngineConfiguration.getHistory()));
   }

   @Override
   public boolean isHistoryLevelAtLeast(HistoryLevel level) {
      boolean atLeast = true;
      String hlevel = ActivitiThreadCache.get(HISTORY_LEVEL);

      HistoryLevel historyLevel = null;
      if(hlevel != null)
         historyLevel = HistoryLevel.getHistoryLevelForKey(hlevel.toLowerCase());

         if(null != historyLevel){
            atLeast = historyLevel.isAtLeast(level);
         }
         else {
               atLeast = super.isHistoryLevelAtLeast(level);
         }
      return atLeast;
   }

}

With these changes, in Activiti 6.0.0 we are able to achieve to capture History only for intended workflow types, where as workflows for which Boundary timer events are attached, the trigger on timeout fails with below exception

java.lang.NullPointerException
at org.activiti.engine.impl.db.DbSqlSession.delete(DbSqlSession.java:226)
at org.activiti.engine.impl.persistence.entity.data.AbstractDataManager.delete(AbstractDataManager.java:87)
at org.activiti.engine.impl.persistence.entity.AbstractEntityManager.delete(AbstractEntityManager.java:92)
at org.activiti.engine.impl.persistence.entity.HistoricProcessInstanceEntityManagerImpl.delete(HistoricProcessInstanceEntityManagerImpl.java:71)
at org.activiti.engine.impl.persistence.entity.ExecutionEntityManagerImpl.deleteProcessInstanceCascade(ExecutionEntityManagerImpl.java:412)
at org.activiti.engine.impl.persistence.entity.ExecutionEntityManagerImpl.deleteProcessInstanceCascade(ExecutionEntityManagerImpl.java:384)
at org.activiti.engine.impl.persistence.entity.ExecutionEntityManagerImpl.deleteProcessInstanceExecutionEntity(ExecutionEntityManagerImpl.java:443)
at org.activiti.engine.impl.bpmn.behavior.BoundaryEventActivityBehavior.deleteChildExecutions(BoundaryEventActivityBehavior.java:152)
at org.activiti.engine.impl.bpmn.behavior.BoundaryEventActivityBehavior.deleteChildExecutions(BoundaryEventActivityBehavior.java:143)
at org.activiti.engine.impl.bpmn.behavior.BoundaryEventActivityBehavior.executeInterruptingBehavior(BoundaryEventActivityBehavior.java:88)
at org.activiti.engine.impl.bpmn.behavior.BoundaryEventActivityBehavior.trigger(BoundaryEventActivityBehavior.java:56)
at org.activiti.engine.impl.agenda.TriggerExecutionOperation.run(TriggerExecutionOperation.java:38)
at org.activiti.engine.impl.interceptor.CommandInvoker.executeOperation(CommandInvoker.java:73)
at org.activiti.engine.impl.interceptor.CommandInvoker.executeOperations(CommandInvoker.java:57)
at org.activiti.engine.impl.interceptor.CommandInvoker.execute(CommandInvoker.java:42)
at org.activiti.engine.impl.interceptor.TransactionContextInterceptor.execute(TransactionContextInterceptor.java:48)
at org.activiti.engine.impl.interceptor.CommandContextInterceptor.execute(CommandContextInterceptor.java:63)
at org.activiti.spring.SpringTransactionInterceptor$1.doInTransaction(SpringTransactionInterceptor.java:47)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:130)
at org.activiti.spring.SpringTransactionInterceptor.execute(SpringTransactionInterceptor.java:45)
at org.activiti.engine.impl.interceptor.LogInterceptor.execute(LogInterceptor.java:29)
at org.activiti.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:44)
at org.activiti.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:39)
at org.activiti.engine.impl.asyncexecutor.ExecuteAsyncRunnable.executeJob(ExecuteAsyncRunnable.java:97)
at org.activiti.engine.impl.asyncexecutor.ExecuteAsyncRunnable.run(ExecuteAsyncRunnable.java:75)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

On further investigating, we found out for workflows for which we are not capturing history this error occurs as the global configured history level is audit, HistoricProcessInstanceEntityManagerImpl passes entity as null and hence NullPointerException.

Any suggestion or workaround to solve this issue?

1 REPLY 1

bassam_al-saror
Star Collaborator
Star Collaborator

Can you have the code as a maven project somewhere on Github. It will be helpful if its possible to reproduce the issue you are facing. 

Getting started

Explore our Alfresco products with the links below. Use labels to filter content by product module.