Sequence flow path history?

For people who needs same thing in SpringBoot, I wanted to share my solution.

Create an execution listener to run everytime a process goes through a sequence flow.

import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.ExecutionListener;
import org.camunda.bpm.engine.delegate.Expression;
import org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity;

public class SequenceFlowHistoryListener implements ExecutionListener {

    @Override
    public void notify(DelegateExecution delegateExecution) throws Exception {
        try {
			// this method is called everytime a sequence flow is triggered
			
			log.info("Properties " + delegateExecution.getId() + "," + delegateExecution.getCurrentTransitionId() + "," + delegateExecution.getProcessInstanceId());
			
			// fire an historic event or do whatever you want
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

Then create a bpmn parser listener to set execution listener on each and every sequence flow in all process definitions.

import org.camunda.bpm.engine.impl.bpmn.listener.ClassDelegateExecutionListener;
import org.camunda.bpm.engine.impl.bpmn.parser.AbstractBpmnParseListener;
import org.camunda.bpm.engine.impl.bpmn.parser.BpmnParseListener;
import org.camunda.bpm.engine.impl.pvm.process.ScopeImpl;
import org.camunda.bpm.engine.impl.pvm.process.TransitionImpl;
import org.camunda.bpm.engine.impl.util.xml.Element;

public class CustomParseListener extends AbstractBpmnParseListener implements BpmnParseListener {

	@Override
	public void parseSequenceFlow(Element sequenceFlowElement, ScopeImpl scopeElement, TransitionImpl transition) {
		super.parseSequenceFlow(sequenceFlowElement, scopeElement, transition);
		try {
			ClassDelegateExecutionListener classDelegateExecutionListener = new ClassDelegateExecutionListener(SequenceFlowHistoryListener.class, null);
			transition.addListener("take", classDelegateExecutionListener);
		} catch (Exception e){
			e.printStackTrace();
		}
	}
}

Then wire parser listener to process engine configuration.

import org.camunda.bpm.engine.ProcessEngine;
import org.camunda.bpm.engine.impl.bpmn.parser.BpmnParseListener;
import org.camunda.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.camunda.bpm.engine.impl.cfg.ProcessEnginePlugin;
import org.camunda.bpm.spring.boot.starter.configuration.Ordering;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Order(Ordering.DEFAULT_ORDER -1)
public class MyCamundaProcessEnginePlugin implements ProcessEnginePlugin {

    @Override
    public void preInit(ProcessEngineConfigurationImpl processEngineConfiguration) {
        List<BpmnParseListener> postParseListeners = processEngineConfiguration.getCustomPostBPMNParseListeners();
        if (postParseListeners == null) {
            postParseListeners = new ArrayList<>();
            processEngineConfiguration.setCustomPostBPMNParseListeners(postParseListeners);
        }
        postParseListeners.add(new CustomParseListener());
    }

    @Override
    public void postInit(ProcessEngineConfigurationImpl processEngineConfiguration) {
        
    }

    @Override
    public void postProcessEngineBuild(ProcessEngine processEngine) {
        
    }
}