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?
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.
Ask for and offer help to other Alfresco Process Services and Activiti Users and members of the Alfresco team.
By using this site, you are agreeing to allow us to collect and use cookies as outlined in Alfresco’s Cookie Statement and Terms of Use (and you have a legitimate interest in Alfresco and our products, authorizing us to contact you in such methods). If you are not ok with these terms, please do not use this website.