├── settings.gradle ├── camunda-webapp-webjar ├── .gitignore └── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── src ├── main │ ├── resources │ │ ├── loanApproval.png │ │ ├── META-INF │ │ │ └── services │ │ │ │ └── org.camunda.bpm.engine.rest.spi.ProcessEngineProvider │ │ └── loanApproval.bpmn │ └── java │ │ └── com │ │ └── github │ │ └── zapata │ │ └── camunda │ │ └── spring │ │ └── boot │ │ └── embedded │ │ ├── web │ │ ├── RestProcessApplication.java │ │ ├── JerseyResourceConfig.java │ │ ├── RestProcessEngineProvider.java │ │ └── CamundaWebAppInitializer.java │ │ ├── Application.java │ │ ├── service │ │ ├── CalculateInterestService.java │ │ └── Starter.java │ │ ├── config │ │ ├── MetricsConfiguration.java │ │ └── ProcessEngineSpringConfiguration.java │ │ └── resource │ │ └── SampleResource.java └── test │ └── java │ └── com │ └── github │ └── zapata │ └── camunda │ └── spring │ └── boot │ └── embedded │ ├── JerseyIntegrationTest.java │ ├── CamundaIntegrationTest.java │ ├── ActuatorIntegrationTest.java │ └── AbstractIntegrationTest.java ├── application.yml ├── README.md ├── gradlew.bat └── gradlew /settings.gradle: -------------------------------------------------------------------------------- 1 | include 'camunda-webapp-webjar' -------------------------------------------------------------------------------- /camunda-webapp-webjar/.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /bin/ 3 | /.classpath 4 | /.project 5 | /.settings/ 6 | /.gradle/ 7 | /src/main/webapp/ -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zapata/camunda-spring-boot-embedded/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/resources/loanApproval.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zapata/camunda-spring-boot-embedded/HEAD/src/main/resources/loanApproval.png -------------------------------------------------------------------------------- /src/main/resources/META-INF/services/org.camunda.bpm.engine.rest.spi.ProcessEngineProvider: -------------------------------------------------------------------------------- 1 | com.github.zapata.camunda.spring.boot.embedded.web.RestProcessEngineProvider -------------------------------------------------------------------------------- /application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 9080 3 | management: 4 | port: 9081 5 | spring: 6 | jackson: 7 | serialization: 8 | INDENT_OUTPUT: true 9 | ORDER_MAP_ENTRIES_BY_KEYS: true 10 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Mar 20 18:13:36 CET 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.3-bin.zip 7 | -------------------------------------------------------------------------------- /src/main/java/com/github/zapata/camunda/spring/boot/embedded/web/RestProcessApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.zapata.camunda.spring.boot.embedded.web; 2 | 3 | import org.camunda.bpm.application.ProcessApplication; 4 | import org.camunda.bpm.engine.spring.application.SpringServletProcessApplication; 5 | 6 | @ProcessApplication 7 | public class RestProcessApplication extends SpringServletProcessApplication { 8 | } -------------------------------------------------------------------------------- /src/main/java/com/github/zapata/camunda/spring/boot/embedded/Application.java: -------------------------------------------------------------------------------- 1 | package com.github.zapata.camunda.spring.boot.embedded; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | public static void main(String... args) { 9 | SpringApplication.run(Application.class, args); 10 | } 11 | } -------------------------------------------------------------------------------- /src/main/java/com/github/zapata/camunda/spring/boot/embedded/service/CalculateInterestService.java: -------------------------------------------------------------------------------- 1 | package com.github.zapata.camunda.spring.boot.embedded.service; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import com.codahale.metrics.annotation.Timed; 6 | 7 | @Component 8 | public class CalculateInterestService { 9 | 10 | @Timed 11 | public void compute() { 12 | System.out.println("Spring Bean invoked."); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/zapata/camunda/spring/boot/embedded/config/MetricsConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.github.zapata.camunda.spring.boot.embedded.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | 5 | import com.ryantenney.metrics.spring.config.annotation.EnableMetrics; 6 | import com.ryantenney.metrics.spring.config.annotation.MetricsConfigurerAdapter; 7 | 8 | @Configuration 9 | @EnableMetrics 10 | public class MetricsConfiguration extends MetricsConfigurerAdapter { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/github/zapata/camunda/spring/boot/embedded/web/JerseyResourceConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.zapata.camunda.spring.boot.embedded.web; 2 | 3 | import javax.ws.rs.ApplicationPath; 4 | 5 | import org.glassfish.jersey.server.ResourceConfig; 6 | import org.springframework.stereotype.Component; 7 | 8 | @Component 9 | @ApplicationPath("/api") 10 | public class JerseyResourceConfig extends ResourceConfig { 11 | 12 | public JerseyResourceConfig() { 13 | packages("com.github.zapata.camunda.spring.boot.embedded"); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/com/github/zapata/camunda/spring/boot/embedded/JerseyIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package com.github.zapata.camunda.spring.boot.embedded; 2 | 3 | import static org.hamcrest.Matchers.equalTo; 4 | 5 | import org.junit.Test; 6 | 7 | public class JerseyIntegrationTest extends AbstractIntegrationTest { 8 | 9 | @Test 10 | public void shouldGetHealthStatus() { 11 | noAuth().get("/api/sample").then().assertThat().statusCode(200) 12 | .body("status", equalTo("UP")).and() 13 | .body("description", equalTo("Jersey: Up and Running!")); 14 | } 15 | } -------------------------------------------------------------------------------- /src/main/java/com/github/zapata/camunda/spring/boot/embedded/service/Starter.java: -------------------------------------------------------------------------------- 1 | package com.github.zapata.camunda.spring.boot.embedded.service; 2 | 3 | import javax.annotation.PostConstruct; 4 | import javax.inject.Inject; 5 | 6 | import org.camunda.bpm.engine.RuntimeService; 7 | import org.springframework.stereotype.Component; 8 | 9 | @Component 10 | public class Starter { 11 | 12 | @Inject 13 | private RuntimeService runtimeService; 14 | 15 | @PostConstruct 16 | public void afterPropertiesSet() { 17 | runtimeService.startProcessInstanceByKey("loanApproval"); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/com/github/zapata/camunda/spring/boot/embedded/CamundaIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package com.github.zapata.camunda.spring.boot.embedded; 2 | 3 | import static org.hamcrest.Matchers.contains; 4 | 5 | import org.junit.Test; 6 | 7 | import com.jayway.restassured.http.ContentType; 8 | 9 | public class CamundaIntegrationTest extends AbstractIntegrationTest { 10 | 11 | @Test 12 | public void shouldGetEnginesUsingRestApi() { 13 | noAuth().get("/api/engine/engine").then().assertThat().statusCode(200) 14 | .body("name", contains("default")); 15 | } 16 | 17 | @Test 18 | public void shouldGetIndexHtmlPage() { 19 | noAuth().get("/").then().assertThat().statusCode(200) 20 | .contentType(ContentType.HTML); 21 | } 22 | } -------------------------------------------------------------------------------- /src/main/java/com/github/zapata/camunda/spring/boot/embedded/resource/SampleResource.java: -------------------------------------------------------------------------------- 1 | package com.github.zapata.camunda.spring.boot.embedded.resource; 2 | 3 | import javax.ws.rs.GET; 4 | import javax.ws.rs.Path; 5 | import javax.ws.rs.Produces; 6 | import javax.ws.rs.core.MediaType; 7 | 8 | import org.springframework.boot.actuate.health.Health; 9 | import org.springframework.boot.actuate.health.Status; 10 | import org.springframework.stereotype.Component; 11 | 12 | import com.codahale.metrics.annotation.Timed; 13 | 14 | @Component 15 | @Path("/sample") 16 | public class SampleResource { 17 | @GET 18 | @Produces(MediaType.APPLICATION_JSON) 19 | @Timed 20 | public Health health() { 21 | return Health.status(new Status("UP", "Jersey: Up and Running!")) 22 | .build(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/github/zapata/camunda/spring/boot/embedded/web/RestProcessEngineProvider.java: -------------------------------------------------------------------------------- 1 | package com.github.zapata.camunda.spring.boot.embedded.web; 2 | 3 | import java.util.Set; 4 | 5 | import org.camunda.bpm.engine.ProcessEngine; 6 | import org.camunda.bpm.engine.ProcessEngines; 7 | import org.camunda.bpm.engine.rest.spi.ProcessEngineProvider; 8 | 9 | public class RestProcessEngineProvider implements ProcessEngineProvider { 10 | 11 | @Override 12 | public ProcessEngine getDefaultProcessEngine() { 13 | return ProcessEngines.getDefaultProcessEngine(); 14 | } 15 | 16 | @Override 17 | public ProcessEngine getProcessEngine(String name) { 18 | return ProcessEngines.getProcessEngine(name); 19 | } 20 | 21 | @Override 22 | public Set getProcessEngineNames() { 23 | return ProcessEngines.getProcessEngines().keySet(); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /camunda-webapp-webjar/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { compile("org.camunda.bpm.webapp:camunda-webapp:$camundaVersion@war") } 2 | 3 | def generatedResourcesFolder = "src/main/webapp/resources" 4 | 5 | sourceSets { 6 | main { 7 | resources { srcDirs += generatedResourcesFolder } 8 | } 9 | } 10 | 11 | task generateWebappResources(type: Copy) { 12 | description 'Extract webapp files from camunda WAR.' 13 | from(zipTree(configurations.compile.singleFile)) { 14 | exclude 'META-INF/**' 15 | exclude 'WEB-INF/**' 16 | include '**' 17 | } 18 | 19 | from({ zipTree(configurations.compile.singleFile) }) { 20 | include 'WEB-INF/securityFilterRules.json' 21 | } 22 | 23 | into generatedResourcesFolder 24 | 25 | doLast { 26 | file(generatedResourcesFolder + '/WEB-INF/securityFilterRules.json').renameTo(file(generatedResourcesFolder + '/securityFilterRules.json')) 27 | file(generatedResourcesFolder + '/WEB-INF').deleteDir() 28 | } 29 | } 30 | 31 | processResources.dependsOn(generateWebappResources) 32 | 33 | clean { 34 | delete generatedResourcesFolder 35 | } 36 | 37 | jar { 38 | baseName = 'camunda-webapp-webjar' 39 | version = project.ext.camundaVersion 40 | } -------------------------------------------------------------------------------- /src/test/java/com/github/zapata/camunda/spring/boot/embedded/ActuatorIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package com.github.zapata.camunda.spring.boot.embedded; 2 | 3 | import static org.hamcrest.Matchers.equalTo; 4 | 5 | import org.junit.Test; 6 | 7 | import com.github.zapata.camunda.spring.boot.embedded.service.CalculateInterestService; 8 | 9 | public class ActuatorIntegrationTest extends AbstractIntegrationTest { 10 | @Test 11 | public void shouldGetHealthStatus() { 12 | noAuth().port(managementPort).get("/health").then().assertThat() 13 | .statusCode(200).body("status", equalTo("UP")); 14 | } 15 | 16 | @Test 17 | public void shouldGetThreadDump() { 18 | noAuth().port(managementPort).get("/dump").then().assertThat() 19 | .statusCode(200); 20 | } 21 | 22 | @Test 23 | public void shouldNotBeAbleToShutdown() { 24 | noAuth().port(managementPort).get("/shutdown").then().assertThat() 25 | .statusCode(405); 26 | } 27 | 28 | @Test 29 | public void shouldHaveDropwizardMetricsRegistered() { 30 | noAuth().port(managementPort) 31 | .get("/metrics/" + CalculateInterestService.class.getName() 32 | + ".compute.count").then().assertThat().statusCode(200) 33 | .body(equalTo("1")); 34 | } 35 | 36 | @Test 37 | public void shouldHaveJolokiaServlet() { 38 | noAuth().port(managementPort) 39 | .get("/jolokia/read/java.lang:type=Memory/HeapMemoryUsage") 40 | .then().assertThat().statusCode(200); 41 | } 42 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## What it is? 2 | 3 | A demo embedded application for a Camunda (rest + cockpit/tasklist) integrated with Spring Boot (Jersey2 + Undertow). 4 | 5 | ## How? 6 | 7 | # Spring Boot + Jersey 2 + Undertow: 8 | 9 | - Configure gradle correctly (include boot, and exclude tomcat) 10 | - Configure a `ResourceConfig` 11 | - Implement your resource: `SampleResource` 12 | 13 | # Camunda integration: 14 | 15 | - Include camunda dependencies. 16 | - Declare a SPI ProcessEngineProvider (see src/main/resources/META-INF/services) 17 | - Implement it: `RestProcessEngineProvider` 18 | - Configure the process engine: `ProcessEngineSpringConfiguration` 19 | - Implement your BPM / service class. 20 | 21 | # Camunda Rest + Cockpit integration: 22 | 23 | - Include webapp depedencies (note `classes` classifier): 24 | 25 | compile("org.camunda.bpm:camunda-engine-rest:$camundaVersion:classes") 26 | compile("org.camunda.bpm.webapp:camunda-webapp:$camundaVersion:classes") 27 | 28 | - Repackage the Javascript/Html files in a webjar-like manner: `camunda-webapp-webjar/build.gradle` 29 | 30 | - Register all the Camunda servlets: `CamundaWebAppInitializer` 31 | 32 | 33 | # Tests: 34 | 35 | - Use [REST-assured](https://code.google.com/p/rest-assured/) coz it rocks! 36 | 37 | # Production ready: 38 | 39 | - Add Spring boot actuator. 40 | - Configure Dropwizard metrics. 41 | - Expose JMX as HTTP with jolokia. 42 | 43 | ## What's next? 44 | 45 | - API documentation with swagger. 46 | - Multi project workflow architecture 47 | 48 | -------------------------------------------------------------------------------- /src/test/java/com/github/zapata/camunda/spring/boot/embedded/AbstractIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package com.github.zapata.camunda.spring.boot.embedded; 2 | 3 | import static com.jayway.restassured.RestAssured.with; 4 | 5 | import org.junit.Before; 6 | import org.junit.runner.RunWith; 7 | import org.springframework.beans.factory.annotation.Value; 8 | import org.springframework.boot.test.SpringApplicationConfiguration; 9 | import org.springframework.boot.test.WebIntegrationTest; 10 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 11 | 12 | import com.jayway.restassured.RestAssured; 13 | import com.jayway.restassured.http.ContentType; 14 | import com.jayway.restassured.specification.RequestSpecification; 15 | 16 | @RunWith(SpringJUnit4ClassRunner.class) 17 | @SpringApplicationConfiguration(classes = Application.class) 18 | @WebIntegrationTest(value = { "server.port=9000", "management.port=9001" }) 19 | public abstract class AbstractIntegrationTest { 20 | 21 | @Value("${management.port}") 22 | protected int managementPort; 23 | 24 | @Value("${server.port}") 25 | protected int serverPort; 26 | 27 | @Before 28 | public void initConnection() { 29 | RestAssured.baseURI = "http://localhost"; 30 | RestAssured.port = serverPort; 31 | 32 | RestAssured.requestContentType(ContentType.JSON); 33 | RestAssured.enableLoggingOfRequestAndResponseIfValidationFails(); 34 | } 35 | 36 | protected RequestSpecification auth(String userName) { 37 | return with().auth().preemptive().basic(userName, userName); 38 | } 39 | 40 | protected RequestSpecification noAuth() { 41 | return with().auth().none(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /src/main/resources/loanApproval.bpmn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SequenceFlow_1 6 | 7 | 8 | 9 | SequenceFlow_3 10 | 11 | 12 | SequenceFlow_1 13 | SequenceFlow_3 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/main/java/com/github/zapata/camunda/spring/boot/embedded/config/ProcessEngineSpringConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.github.zapata.camunda.spring.boot.embedded.config; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.inject.Inject; 6 | import javax.sql.DataSource; 7 | 8 | import org.camunda.bpm.engine.AuthorizationService; 9 | import org.camunda.bpm.engine.FormService; 10 | import org.camunda.bpm.engine.HistoryService; 11 | import org.camunda.bpm.engine.IdentityService; 12 | import org.camunda.bpm.engine.ManagementService; 13 | import org.camunda.bpm.engine.ProcessEngine; 14 | import org.camunda.bpm.engine.ProcessEngineConfiguration; 15 | import org.camunda.bpm.engine.RepositoryService; 16 | import org.camunda.bpm.engine.RuntimeService; 17 | import org.camunda.bpm.engine.TaskService; 18 | import org.camunda.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl; 19 | import org.camunda.bpm.engine.spring.ProcessEngineFactoryBean; 20 | import org.camunda.bpm.engine.spring.SpringProcessEngineConfiguration; 21 | import org.springframework.context.annotation.Bean; 22 | import org.springframework.context.annotation.Configuration; 23 | import org.springframework.core.io.support.ResourcePatternResolver; 24 | import org.springframework.transaction.PlatformTransactionManager; 25 | 26 | @Configuration 27 | public class ProcessEngineSpringConfiguration { 28 | 29 | @Inject 30 | private DataSource dataSource; 31 | 32 | @Inject 33 | private PlatformTransactionManager transactionManager; 34 | 35 | @Inject 36 | private ResourcePatternResolver resourceResolver; 37 | 38 | @Bean 39 | public ProcessEngineConfigurationImpl processEngineConfiguration() { 40 | SpringProcessEngineConfiguration config = new SpringProcessEngineConfiguration(); 41 | config.setDataSource(dataSource); 42 | config.setTransactionManager(transactionManager); 43 | config.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE); 44 | config.setJobExecutorActivate(false); 45 | try { 46 | config.setDeploymentResources(resourceResolver 47 | .getResources("classpath*:*.bpmn")); 48 | } catch (IOException e) { 49 | throw new RuntimeException(e); 50 | } 51 | 52 | return config; 53 | } 54 | 55 | @Bean(destroyMethod = "destroy") 56 | public ProcessEngineFactoryBean processEngineFactory() { 57 | ProcessEngineFactoryBean processEngineFactoryBean = new ProcessEngineFactoryBean(); 58 | processEngineFactoryBean 59 | .setProcessEngineConfiguration(processEngineConfiguration()); 60 | return processEngineFactoryBean; 61 | } 62 | 63 | public ProcessEngine processEngine() { 64 | try { 65 | return processEngineFactory().getObject(); 66 | } catch (Exception e) { 67 | throw new RuntimeException(e); 68 | } 69 | } 70 | 71 | @Bean 72 | public RuntimeService runtimeService() { 73 | return processEngine().getRuntimeService(); 74 | } 75 | 76 | @Bean 77 | public AuthorizationService authorizationService() { 78 | return processEngine().getAuthorizationService(); 79 | } 80 | 81 | @Bean 82 | public FormService formService() { 83 | return processEngine().getFormService(); 84 | } 85 | 86 | @Bean 87 | public HistoryService historyService() { 88 | return processEngine().getHistoryService(); 89 | } 90 | 91 | @Bean 92 | public IdentityService identityService() { 93 | return processEngine().getIdentityService(); 94 | } 95 | 96 | @Bean 97 | public ManagementService managementService() { 98 | return processEngine().getManagementService(); 99 | } 100 | 101 | @Bean 102 | public RepositoryService repositoryService() { 103 | return processEngine().getRepositoryService(); 104 | } 105 | 106 | @Bean 107 | public TaskService taskService() { 108 | return processEngine().getTaskService(); 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /src/main/java/com/github/zapata/camunda/spring/boot/embedded/web/CamundaWebAppInitializer.java: -------------------------------------------------------------------------------- 1 | package com.github.zapata.camunda.spring.boot.embedded.web; 2 | 3 | import java.util.EnumSet; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | import javax.servlet.DispatcherType; 8 | import javax.servlet.Filter; 9 | import javax.servlet.FilterRegistration; 10 | import javax.servlet.Servlet; 11 | import javax.servlet.ServletContext; 12 | import javax.servlet.ServletException; 13 | import javax.servlet.ServletRegistration; 14 | 15 | import org.camunda.bpm.admin.impl.web.AdminApplication; 16 | import org.camunda.bpm.admin.impl.web.bootstrap.AdminContainerBootstrap; 17 | import org.camunda.bpm.admin.impl.web.filter.plugin.AdminClientPluginsFilter; 18 | import org.camunda.bpm.cockpit.impl.web.CockpitApplication; 19 | import org.camunda.bpm.cockpit.impl.web.bootstrap.CockpitContainerBootstrap; 20 | import org.camunda.bpm.cockpit.impl.web.filter.plugin.CockpitClientPluginsFilter; 21 | import org.camunda.bpm.engine.rest.filter.CacheControlFilter; 22 | import org.camunda.bpm.webapp.impl.engine.EngineRestApplication; 23 | import org.camunda.bpm.webapp.impl.engine.ProcessEnginesFilter; 24 | import org.camunda.bpm.webapp.impl.security.auth.AuthenticationFilter; 25 | import org.camunda.bpm.webapp.impl.security.filter.SecurityFilter; 26 | import org.glassfish.jersey.servlet.ServletContainer; 27 | import org.glassfish.jersey.servlet.ServletProperties; 28 | import org.slf4j.Logger; 29 | import org.slf4j.LoggerFactory; 30 | import org.springframework.boot.context.embedded.ServletContextInitializer; 31 | import org.springframework.stereotype.Component; 32 | 33 | /** 34 | * Inspired by: 35 | * https://groups.google.com/forum/#!msg/camunda-bpm-users/BQHdcLIivzs 36 | * /iNVix8GkhYAJ (Christoph Berg) 37 | */ 38 | @Component 39 | public class CamundaWebAppInitializer implements ServletContextInitializer { 40 | public static final Logger LOGGER = LoggerFactory 41 | .getLogger(CamundaWebAppInitializer.class); 42 | 43 | private static final EnumSet DISPATCHER_TYPES = EnumSet 44 | .of(DispatcherType.REQUEST); 45 | 46 | private ServletContext servletContext; 47 | 48 | @Override 49 | public void onStartup(ServletContext servletContext) 50 | throws ServletException { 51 | this.servletContext = servletContext; 52 | 53 | servletContext.addListener(new CockpitContainerBootstrap()); 54 | servletContext.addListener(new AdminContainerBootstrap()); 55 | 56 | registerFilter("Authentication Filter", AuthenticationFilter.class, 57 | "/*"); 58 | 59 | HashMap securityFilterParameters = new HashMap<>(); 60 | securityFilterParameters.put("configFile", "/securityFilterRules.json"); 61 | registerFilter("Security Filter", SecurityFilter.class, 62 | securityFilterParameters, "/*"); 63 | 64 | registerFilter("Cockpit Client Plugins Filter", 65 | CockpitClientPluginsFilter.class, 66 | "/app/cockpit/cockpit-bootstrap.js", "/app/cockpit/cockpit.js"); 67 | 68 | registerFilter("Admin Client Plugins Filter", 69 | AdminClientPluginsFilter.class, 70 | "/app/admin/admin-bootstrap.js", "/app/admin/admin.js"); 71 | 72 | registerFilter("Engines Filter", ProcessEnginesFilter.class, "/app/*"); 73 | 74 | registerFilter("CacheControlFilter", CacheControlFilter.class, "/api/*"); 75 | 76 | HashMap cockpitApiParameters = new HashMap<>(); 77 | cockpitApiParameters.put(ServletProperties.JAXRS_APPLICATION_CLASS, 78 | CockpitApplication.class.getName()); 79 | registerServlet("Cockpit Api", ServletContainer.class, 80 | cockpitApiParameters, "/api/cockpit/*"); 81 | 82 | HashMap adminApiParameters = new HashMap<>(); 83 | adminApiParameters.put(ServletProperties.JAXRS_APPLICATION_CLASS, 84 | AdminApplication.class.getName()); 85 | registerServlet("Admin Api", ServletContainer.class, 86 | adminApiParameters, "/api/admin/*"); 87 | 88 | HashMap engineApiParameters = new HashMap<>(); 89 | engineApiParameters.put(ServletProperties.JAXRS_APPLICATION_CLASS, 90 | EngineRestApplication.class.getName()); 91 | registerServlet("Engine Api", ServletContainer.class, 92 | engineApiParameters, "/api/engine/*"); 93 | } 94 | 95 | private FilterRegistration registerFilter(final String filterName, 96 | final Class filterClass, 97 | final String... urlPatterns) { 98 | return registerFilter(filterName, filterClass, null, urlPatterns); 99 | } 100 | 101 | private FilterRegistration registerFilter(final String filterName, 102 | final Class filterClass, 103 | final Map initParameters, 104 | final String... urlPatterns) { 105 | FilterRegistration filterRegistration = servletContext 106 | .getFilterRegistration(filterName); 107 | 108 | if (filterRegistration == null) { 109 | filterRegistration = servletContext.addFilter(filterName, 110 | filterClass); 111 | filterRegistration.addMappingForUrlPatterns(DISPATCHER_TYPES, true, 112 | urlPatterns); 113 | 114 | if (initParameters != null) { 115 | filterRegistration.setInitParameters(initParameters); 116 | } 117 | 118 | LOGGER.debug("Filter {} for URL {} registered.", filterName, 119 | urlPatterns); 120 | } 121 | 122 | return filterRegistration; 123 | } 124 | 125 | private ServletRegistration registerServlet(final String servletName, 126 | final Class servletClass, 127 | final Map initParameters, 128 | final String... urlPatterns) { 129 | ServletRegistration servletRegistration = servletContext 130 | .getServletRegistration(servletName); 131 | 132 | if (servletRegistration == null) { 133 | servletRegistration = servletContext.addServlet(servletName, 134 | servletClass); 135 | servletRegistration.addMapping(urlPatterns); 136 | servletRegistration.setInitParameters(initParameters); 137 | 138 | LOGGER.debug("Servlet {} for URL {} registered.", servletName, 139 | urlPatterns); 140 | } 141 | 142 | return servletRegistration; 143 | } 144 | } 145 | --------------------------------------------------------------------------------