Bootstrap process engine in java class (Spring framework)

Hi Experts,

I am developing a camunda process application using spring framework. However, following examples provided by camunda learning pages, I can run the spring-based process application using AppliacationContext.xml (XML based configuration), whereas I need to use java class to configure my process application as we do in Spring-boot example.

I have tried using @configuration, @Component and many other annotations, but the BPM engine has not bootstrapped.

Anyone pls can guide me on this.

My XML configuation is below.

<!-- bind the process engine service as Spring Bean .. this is application managed process engine way-->
<!-- 	<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource"> -->
<!-- 	    <property name="driverClass" value="org.h2.Driver" /> -->
<!-- 	    <property name="url" value="jdbc:h2:mem:camunda;DB_CLOSE_DELAY=1000" /> -->
<!-- 	    <property name="username" value="sa" /> -->
<!-- 	    <property name="password" value="" /> -->
<!--    </bean> -->

<!--    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> -->
<!--     	<property name="dataSource" ref="dataSource" /> -->
<!--    </bean> -->
  
<!--    <bean id="processEngineConfiguration" class="org.camunda.bpm.engine.spring.SpringProcessEngineConfiguration">    -->
<!-- 	  <property name="dataSource" ref="dataSource" /> -->
<!--       <property name="transactionManager" ref="transactionManager" /> -->
<!--       <property name="databaseSchemaUpdate" value="true" /> -->
<!--       <property name="jobExecutorActivate" value="false" /> -->
<!--    </bean> -->
	
<!--    <bean id="processEngine" -->
<!-- 	      class="org.camunda.bpm.engine.spring.ProcessEngineFactoryBean"> -->
<!-- 	  <property name="processEngineConfiguration" ref="processEngineConfiguration" /> -->
<!--    </bean> -->
  
  <!-- bind the process engine service as Spring Bean .. this is shared process engine way-->
  <bean name="processEngineService" class="org.camunda.bpm.BpmPlatform" factory-method="getProcessEngineService" />
   <bean name="processEngine" factory-bean="processEngineService" factory-method="getDefaultProcessEngine" />
  
  

  <bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService"/>
  <bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService"/>
  <bean id="taskService" factory-bean="processEngine" factory-method="getTaskService"/>
  <bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService"/>
  <bean id="managementService" factory-bean="processEngine" factory-method="getManagementService"/>

  <!-- bootstrap the process application  commented as need to bootstrap from java classes-->
<!--   <bean id="processApplication" class="org.camunda.bpm.engine.spring.application.SpringServletProcessApplication" /> -->

  <context:annotation-config />

  <bean id="calculateInterestService" class="org.camunda.bpm.getstarted.loanapproval.CalculateInterestService" />

<context:component-scan base-package="org.camunda.bpm" />

</beans>

Java class to bootstrap the process engine.

/* Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.camunda.bpm.getstarted;

import static org.camunda.bpm.engine.variable.Variables.createVariables;
import static org.camunda.bpm.engine.variable.Variables.fileValue;

import java.io.InputStream;
import java.util.Arrays;
import java.util.Calendar;
import java.util.logging.Logger;

import org.camunda.bpm.BpmPlatform;
import org.camunda.bpm.application.PostDeploy;
import org.camunda.bpm.application.ProcessApplication;
import org.camunda.bpm.application.impl.ServletProcessApplication;
import org.camunda.bpm.engine.ProcessEngine;
import org.camunda.bpm.engine.RepositoryService;
import org.camunda.bpm.engine.authorization.Groups;
import org.camunda.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.camunda.bpm.engine.impl.util.ClockUtil;
import org.camunda.bpm.engine.impl.util.IoUtil;
import org.camunda.bpm.engine.repository.DeploymentBuilder;
import org.camunda.bpm.engine.repository.ProcessDefinition;
import org.camunda.bpm.engine.repository.ProcessDefinitionQuery;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.camunda.bpm.engine.spring.application.SpringProcessApplication;
import org.camunda.bpm.engine.task.Task;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

/**
 * Process Application exposing this application's resources the process engine.
 */
@Configuration
@Component
@EnableWebMvc
@ProcessApplication
public class MainProcessApplication extends SpringProcessApplication {

  private static final Logger LOGGER = Logger.getLogger(MainProcessApplication.class.getName());

  /**
   * In a @PostDeploy Hook you can interact with the process engine and access
   * the processes the application has deployed.
   */
  @PostDeploy
  public void startFirstProcess(ProcessEngine processEngine) {
	  System.out.println("Start first process -------------------------->"+processEngine.getName());
    createUsers(processEngine);
    
    //enable metric reporting
    ProcessEngineConfigurationImpl processEngineConfiguration = (ProcessEngineConfigurationImpl) processEngine.getProcessEngineConfiguration();
    processEngineConfiguration.setDbMetricsReporterActivate(true);
    processEngineConfiguration.getDbMetricsReporter().setReporterId("REPORTER");

    startProcessInstances(processEngine, "invoice", 1);
    startProcessInstances(processEngine, "invoice", null);

    //disable reporting
    processEngineConfiguration.setDbMetricsReporterActivate(false);
  }

  @Override
  public void createDeployment(String processArchiveName, DeploymentBuilder deploymentBuilder) {
    ProcessEngine processEngine = BpmPlatform.getProcessEngineService().getProcessEngine("default");

    // Hack: deploy the first version of the invoice process once before the process application
    //   is deployed the first time
    if (processEngine != null) {

      RepositoryService repositoryService = processEngine.getRepositoryService();

      if (!isProcessDeployed(repositoryService, "invoice")) {
        ClassLoader classLoader = getProcessApplicationClassloader();

        repositoryService.createDeployment(this.getReference())
          .addInputStream("invoice.v1.bpmn", classLoader.getResourceAsStream("invoice.v1.bpmn"))
          .addInputStream("invoiceBusinessDecisions.dmn", classLoader.getResourceAsStream("invoiceBusinessDecisions.dmn"))
          .addInputStream("review-invoice.cmmn", classLoader.getResourceAsStream("review-invoice.cmmn"))
          .deploy();
      }
    }
  }

  protected boolean isProcessDeployed(RepositoryService repositoryService, String key) {
    return repositoryService.createProcessDefinitionQuery().processDefinitionKey("invoice").count() > 0;
  }

  private void startProcessInstances(ProcessEngine processEngine, String processDefinitionKey, Integer version) {

    ProcessEngineConfigurationImpl processEngineConfiguration = (ProcessEngineConfigurationImpl) processEngine.getProcessEngineConfiguration();
    ProcessDefinitionQuery processDefinitionQuery = processEngine
      .getRepositoryService()
      .createProcessDefinitionQuery()
      .processDefinitionKey(processDefinitionKey);

    if (version != null) {
      processDefinitionQuery.processDefinitionVersion(version);
    }
    else {
      processDefinitionQuery.latestVersion();
    }

    ProcessDefinition processDefinition = processDefinitionQuery.singleResult();

    InputStream invoiceInputStream = MainProcessApplication.class.getClassLoader().getResourceAsStream("invoice.pdf");

    long numberOfRunningProcessInstances = processEngine.getRuntimeService().createProcessInstanceQuery().processDefinitionId(processDefinition.getId()).count();

    if (numberOfRunningProcessInstances == 0) { // start three process instances

      LOGGER.info("Start 3 instances of " + processDefinition.getName() + ", version " + processDefinition.getVersion());
      // process instance 1
      processEngine.getRuntimeService().startProcessInstanceById(processDefinition.getId(), createVariables()
          .putValue("creditor", "Great Pizza for Everyone Inc.")
          .putValue("amount", 30.00d)
          .putValue("invoiceCategory", "Travel Expenses")
          .putValue("invoiceNumber", "GPFE-23232323")
          .putValue("invoiceDocument", fileValue("invoice.pdf")
              .file(invoiceInputStream)
              .mimeType("application/pdf")
              .create()));

      IoUtil.closeSilently(invoiceInputStream);
      invoiceInputStream = MainProcessApplication.class.getClassLoader().getResourceAsStream("invoice.pdf");
      processEngineConfiguration.getDbMetricsReporter().reportNow();

      // process instance 2
      try {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DAY_OF_MONTH, -14);
        ClockUtil.setCurrentTime(calendar.getTime());

        ProcessInstance pi = processEngine.getRuntimeService().startProcessInstanceById(processDefinition.getId(), createVariables()
            .putValue("creditor", "Bobby's Office Supplies")
            .putValue("amount", 900.00d)
            .putValue("invoiceCategory", "Misc")
            .putValue("invoiceNumber", "BOS-43934")
            .putValue("invoiceDocument", fileValue("invoice.pdf")
                .file(invoiceInputStream)
                .mimeType("application/pdf")
                .create()));

        processEngineConfiguration.getDbMetricsReporter().reportNow();
        calendar.add(Calendar.DAY_OF_MONTH, 14);
        ClockUtil.setCurrentTime(calendar.getTime());

        processEngine.getIdentityService().setAuthentication("demo", Arrays.asList(Groups.CAMUNDA_ADMIN));
        Task task = processEngine.getTaskService().createTaskQuery().processInstanceId(pi.getId()).singleResult();
        processEngine.getTaskService().claim(task.getId(), "demo");
        processEngine.getTaskService().complete(task.getId(), createVariables().putValue("approved", true));
      }
      finally{
        processEngineConfiguration.getDbMetricsReporter().reportNow();
        ClockUtil.reset();
        processEngine.getIdentityService().clearAuthentication();
      }

      IoUtil.closeSilently(invoiceInputStream);
      invoiceInputStream = MainProcessApplication.class.getClassLoader().getResourceAsStream("invoice.pdf");

      // process instance 3
      try {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DAY_OF_MONTH, -5);
        ClockUtil.setCurrentTime(calendar.getTime());

        ProcessInstance pi = processEngine.getRuntimeService().startProcessInstanceById(processDefinition.getId(), createVariables()
            .putValue("creditor", "Papa Steve's all you can eat")
            .putValue("amount", 10.99d)
            .putValue("invoiceCategory", "Travel Expenses")
            .putValue("invoiceNumber", "PSACE-5342")
            .putValue("invoiceDocument", fileValue("invoice.pdf")
                .file(invoiceInputStream)
                .mimeType("application/pdf")
                .create()));

        processEngineConfiguration.getDbMetricsReporter().reportNow();
        calendar.add(Calendar.DAY_OF_MONTH, 5);
        ClockUtil.setCurrentTime(calendar.getTime());

        processEngine.getIdentityService().setAuthenticatedUserId("user2");
        Task task = processEngine.getTaskService().createTaskQuery().processInstanceId(pi.getId()).singleResult();
        processEngine.getTaskService().createComment(task.getId(), pi.getId(), "I cannot approve this invoice: the amount is missing.\n\n Could you please provide the amount?");
        processEngine.getTaskService().complete(task.getId(), createVariables().putValue("approved", false));
      }
      finally{
        processEngineConfiguration.getDbMetricsReporter().reportNow();
        ClockUtil.reset();
        processEngine.getIdentityService().clearAuthentication();
      }
    } else {
      LOGGER.info("No new instances of " + processDefinition.getName()
          + " version " + processDefinition.getVersion()
          + " started, there are " + numberOfRunningProcessInstances + " instances running");
    }
  }
  
  
  private void createUsers(ProcessEngine processEngine) {
	  System.out.println("Create users -------------------------->"+processEngine.toString());
    // create demo users
    new DemoDataGenerator().createUsers(processEngine);
  }
}

Hi,

Which camunda documentation are you following?

Best regards,
Yana

Hi Yana,

I am following https://docs.camunda.org/manual/latest/user-guide/process-applications/ link.

Another question I have asked is here.
ProcessApplication is not bootstrapped with annotation