Prince Abhijeet
Prince Abhijeet

Reputation: 21

How to deploy BPMN or DMN to Camunda Process Engine in Spring Boot + REST?

Assuming the Spring Boot app is connected to a database which has all the Camunda related tables created like dbo.ACT_HI_PROCINST, dbo.ACT_HI_TASKINST, dbo.ACT_RU_TASK, dbo.ACT_RU_EXECUTION, etc. There is a UI screen (Angular/React frontend) which accepts BPMN & DMN files to be deployed in Camunda database (could be any Relational Database). This (.bpmn/.dmn) should get deployed as the latest version of their file name.

Camunda Version: 7.13.0

User can select a file by browsing the file system from UI screen (assuming UI file browsing and selecting a valid .bpmn or .dmn is done). User has to send this selected file as part of request in REST call to Spring Boot app, and deploy the .bpmn/.dmn file in database.

Upvotes: 0

Views: 3132

Answers (1)

Prince Abhijeet
Prince Abhijeet

Reputation: 21

A .bpmn or .dmn could be deployed in many ways:

  • via Camunda Modeler
  • via Spring Boot App startup auto-deploy from /src/main/resources/bpmn/* by using @EnableProcessApplication annotation along with @SpringBootApplication
  • via Manual deployment by sending .bpmn/.dmn file from frontend UI via REST call to Spring Boot controller and using Camunda's RepositoryService.createDeployment()

application.yaml: Provide Camunda DB datasource configurations like url, username and password along with Camunda admin user credential like -

camunda.bpm.admin-user:
  id: admin
  password: admin
  
camunda:
  bpm:
    history-level: audit
    job-execution:
      core-pool-size: 3
      max-pool-size: 10
    jpa:
      enabled: true
      handle-transaction: true

server:
  port: 8091
      
spring:
  application:
    name: camunda-bpm-workflow-app
  datasource:
    url: jdbc:sqlserver://ABC250.abc.xyz:10010;databaseName=DevCamunda
    username: DevUser
    password: DevPass
    driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
    hikari:
      maximum-pool-size: 200
  jpa:
    hibernate:
      ddl-auto: create
    show-sql: false
    properties:
      hibernate:
        format_sql: true
        dialect: org.hibernate.dialect.SQLServerDialect
  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 10MB

pom.xml: camunda-bpm-spring-boot-starter camunda-bpm-spring-boot-starter-webapp camunda-bpm-spring-boot-starter-rest

Auto-deployment: @EnableProcessApplication: Spring Boot App startup auto-deploy from /src/main/resources/bpmn/*

  • Turn your Spring Boot app into a Camunda process application using @EnableProcessApplication annotation without extending any super-classes.
  • In the Spring Boot app, this annotation helps to link a resource to the process engine.
  • Disables the SpringProcessEngineConfiguration auto-deploy feature
  • Enables auto-deployment from /src/main/resources/META-INF/processes.xml
  • processes.xml - is an indicator for resource scanning. This could be left empty.
  • We can have .bpmn and .dmn files inside bmpn folder, example - /src/main/resources/bpmn/xyz.bmpn or /src/main/resources/bpmn/abc.dmn
  • On startup of Spring Boot app, all .bpmn and .dmn files from location /src/main/resources/bpmn/* will be auto-deployed if any changes were done in them

Manual deployment: By sending .bpmn/.dmn file from fronend UI via REST call to Spring Boot controller and using Camunda's RepositoryService.createDeployment(). After deployment is successful, new deployment ID can be found in database using SQL:

SELECT 
    ID_, 
    NAME_, 
    DEPLOY_TIME_, 
    SOURCE_, 
    TENANT_ID_ 
FROM 
    dbo.ACT_RE_DEPLOYMENT 
ORDER BY 
    DEPLOY_TIME_ DESC

Main Class:

import org.camunda.bpm.spring.boot.starter.annotation.EnableProcessApplication;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableProcessApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }
}

REST Controller endpoint: A Camunda BPMN or DMN file to be deployed in database will be consumed by the rest endpoint as MediaType.MULTIPART_FORM_DATA_VALUE.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.abc.workflow.dto.CamundaDeployResponse;
import com.abc.workflow.service.CamundaDeployService;
import lombok.extern.slf4j.Slf4j;

@RestController("/camunda")
public class CamundaDeployController {
    
    @Autowired 
    private CamundaDeployService camundaDeployService;
    
    @PostMapping(value = "/deploy", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public ResponseEntity<CamundaDeployResponse> deploy(@RequestParam("file") MultipartFile file) {
        return ResponseEntity.ok(camundaDeployService.deploy(file));
    }
}

Service Interface:

import org.springframework.web.multipart.MultipartFile;
import com.abc.workflow.dto.CamundaDeployResponse;

public interface CamundaDeployService {
    CamundaDeployResponse deploy(MultipartFile file);
}

Service Implementation Class: RepositoryService - Service providing access to the repository of process definitions and deployments.

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.camunda.bpm.engine.RepositoryService;
import org.camunda.bpm.engine.repository.DeploymentWithDefinitions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import com.abc.workflow.dto.CamundaDeployRequestDto;
import com.abc.workflow.dto.CamundaDeployResponse;
import com.abc.workflow.service.CamundaDeployService;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class CamundaDeployServiceImpl implements CamundaDeployService {

    @Autowired 
    private RepositoryService repositoryService;

    @Override
    public CamundaDeployResponse deploy(MultipartFile file) {
        CamundaDeployResponse camundaDeployResponse = new CamundaDeployResponse();
        String orgFileName = file.getOriginalFilename();
        log.info("Camunda file to be deployed [{}]", orgFileName);
        if(orgFileName.endsWith(".bpmn") || orgFileName.endsWith(".dmn")) {
            try {
                log.info("Camunda Deployment START : [{}]", orgFileName);
                DeploymentWithDefinitions d = null;
                d = repositoryService.createDeployment().addInputStream(orgFileName, file.getInputStream()).name(orgFileName).deployWithResult();
                camundaDeployResponse.setSuccessMessage("Camunda Deployment SUCCESS ["+orgFileName+"] : Deployment ID ["+d.getId()+"]");
                log.info("Camunda Deployment SUCCESS [{}] : Deployment ID [{}]", orgFileName, d.getId());
            } 
            catch (IOException e) {
                camundaDeployResponse.setErrorMessage("Camunda Deployment FAILED : "+e.getMessage());
                log.error("Camunda Deployment FAILED [{}]: {}", orgFileName, e.getMessage());
                e.printStackTrace();
            }
        }
        else {
            camundaDeployResponse.setErrorMessage("Not a valid Camunda file (BPMN/DMN)");
            log.error("Not a valid Camunda file (BPMN/DMN)");
        }
        return camundaDeployResponse;
    }
}

Upvotes: 1

Related Questions