├── react-tasklist ├── .nvmrc ├── src │ └── main │ │ ├── frontend │ │ ├── .eslintrc.json │ │ ├── jsconfig.json │ │ ├── postcss.config.js │ │ ├── src │ │ │ └── app │ │ │ │ ├── favicon.ico │ │ │ │ ├── components │ │ │ │ ├── forms │ │ │ │ │ └── some-form.js │ │ │ │ ├── react-form.js │ │ │ │ ├── camunda-form.js │ │ │ │ └── task.js │ │ │ │ ├── layout.js │ │ │ │ ├── globals.css │ │ │ │ └── page.js │ │ ├── next.config.js │ │ ├── .gitignore │ │ ├── tailwind.config.js │ │ ├── public │ │ │ ├── vercel.svg │ │ │ └── next.svg │ │ ├── package.json │ │ └── README.md │ │ ├── java │ │ └── com │ │ │ └── camunda │ │ │ └── consulting │ │ │ └── tasklist │ │ │ ├── model │ │ │ ├── TaskOverviewDto.java │ │ │ └── TaskDto.java │ │ │ ├── CamundaWebhookProperties.java │ │ │ ├── App.java │ │ │ ├── StartProcessController.java │ │ │ ├── configuration │ │ │ └── CamundaWebhookClientConfiguration.java │ │ │ └── TasklistController.java │ │ └── resources │ │ └── application.yaml ├── .gitignore └── README.md ├── event-processing ├── .gitignore ├── docs │ ├── img.png │ ├── img2.png │ ├── img3.png │ └── img4.png └── src │ ├── test │ ├── resources │ │ ├── application.yaml │ │ └── createEventRequest.json │ └── java │ │ └── com │ │ └── camunda │ │ └── consulting │ │ └── eventprocessing │ │ └── ProcessTest.java │ └── main │ ├── resources │ └── application.yaml │ └── java │ └── com │ └── camunda │ └── consulting │ └── eventprocessing │ ├── App.java │ ├── ExampleServiceCalls.java │ ├── EventRepository.java │ └── EventController.java ├── twitter-review-java-springboot ├── .gitignore ├── src │ └── main │ │ ├── java │ │ └── org │ │ │ └── camunda │ │ │ └── community │ │ │ └── examples │ │ │ └── twitter │ │ │ ├── business │ │ │ ├── TwitterService.java │ │ │ ├── DuplicateTweetException.java │ │ │ └── TwitterServiceImpl.java │ │ │ ├── TwitterExampleApplication.java │ │ │ ├── process │ │ │ ├── TwitterProcessVariables.java │ │ │ └── TwitterWorker.java │ │ │ └── rest │ │ │ └── ReviewTweetRestApi.java │ │ └── resources │ │ └── application.properties └── readme.md ├── synchronous-response-springboot ├── .gitignore ├── doc │ ├── overview.png │ └── messageEvent.png └── src │ ├── main │ ├── resources │ │ └── application.properties │ └── java │ │ └── org │ │ └── example │ │ └── camunda │ │ └── process │ │ └── solution │ │ ├── SyncResponseProcessApplication.java │ │ └── worker │ │ └── CalculateSomethingWorker.java │ └── test │ └── java │ └── org │ └── example │ └── camunda │ └── process │ └── solution │ └── AppTest.java ├── async-service-task ├── src │ ├── test │ │ ├── resources │ │ │ └── application.yaml │ │ └── java │ │ │ └── com │ │ │ └── camunda │ │ │ └── consulting │ │ │ └── AsyncJobWorkerTest.java │ └── main │ │ ├── resources │ │ └── application.yaml │ │ └── java │ │ └── com │ │ └── camunda │ │ └── consulting │ │ ├── ExampleApplication.java │ │ ├── AsyncServiceProperties.java │ │ └── ProcessController.java └── README.md ├── payment-example-process-application ├── src │ ├── main │ │ ├── resources │ │ │ ├── application.yaml │ │ │ └── static │ │ │ │ ├── index.html │ │ │ │ └── start-process.form │ │ └── java │ │ │ └── com │ │ │ └── camunda │ │ │ └── consulting │ │ │ └── web_shop_process_app │ │ │ ├── service │ │ │ ├── CreditCardExpiredException.java │ │ │ ├── CreditCardService.java │ │ │ └── CustomerService.java │ │ │ ├── PaymentProcessApplication.java │ │ │ ├── rest │ │ │ └── StartFormRestController.java │ │ │ └── worker │ │ │ ├── CustomerCreditHandler.java │ │ │ └── CreditCardHandler.java │ └── test │ │ └── java │ │ └── com │ │ └── camunda │ │ └── consulting │ │ └── web_shop_process_app │ │ └── test │ │ ├── ServiceTest.java │ │ └── WorkerTest.java ├── kube │ ├── doc-images │ │ ├── bp.png │ │ ├── identity-add-app.png │ │ ├── identity-add-m2m-app.png │ │ ├── identity-reveal-secret.png │ │ └── identity-add-permission.png │ └── manifests │ │ ├── secrets.yaml │ │ ├── service.yaml │ │ ├── ingress.yaml │ │ ├── deployment.yaml │ │ └── start-processes-job.yaml ├── complete-usertasks │ └── complete-user-tasks.sh └── start-processes │ └── start.sh ├── rollback-on-error-example ├── src │ └── main │ │ ├── resources │ │ └── application.yaml │ │ └── java │ │ └── com │ │ └── camunda │ │ └── consulting │ │ ├── DynamicJobHandler.java │ │ ├── FailJobException.java │ │ ├── ValidateDataHandler.java │ │ ├── SaveDataHandler.java │ │ ├── ProcessController.java │ │ ├── ExampleApplication.java │ │ ├── UserTaskController.java │ │ └── UserTask.java ├── docs │ └── rollback-process.png └── README.md ├── parallel-operations ├── src │ ├── main │ │ ├── resources │ │ │ ├── application.yaml │ │ │ └── META-INF │ │ │ │ └── processes.xml │ │ └── java │ │ │ └── com │ │ │ └── camunda │ │ │ └── consulting │ │ │ ├── StringService.java │ │ │ ├── ParallelOperationsApp.java │ │ │ └── ProcessController.java │ └── test │ │ └── java │ │ └── com │ │ └── camunda │ │ └── consulting │ │ └── ParallelOperationsAppTest.java └── README.md ├── powerapps-dataverse └── screenshots │ ├── bpmn1.png │ ├── appUser1.png │ ├── appUser2.png │ ├── postman1.png │ ├── postman2.png │ ├── postman3.png │ ├── clientSecret.png │ ├── connectors1.png │ ├── connectors2.png │ ├── environment1.png │ ├── prerequisite.png │ ├── securityRole1.png │ ├── securityRole2.png │ ├── appRegistration1.png │ └── appRegistration2.png ├── ProcessMetadataListener ├── src │ ├── main │ │ ├── resources │ │ │ └── META-INF │ │ │ │ └── spring │ │ │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports │ │ └── java │ │ │ └── com │ │ │ └── camunda │ │ │ └── consulting │ │ │ ├── ProcessMetadataResult.java │ │ │ └── MetadataWorker.java │ └── test │ │ ├── java │ │ └── com │ │ │ └── camunda │ │ │ └── consulting │ │ │ ├── TestApp.java │ │ │ └── MetadataWorkerTest.java │ │ └── resources │ │ └── test.bpmn └── README.md ├── element-template-generation ├── src │ ├── main │ │ ├── resources │ │ │ └── META-INF │ │ │ │ └── services │ │ │ │ └── io.camunda.connector.api.outbound.OutboundConnectorFunction │ │ └── java │ │ │ └── com │ │ │ └── camunda │ │ │ └── consulting │ │ │ ├── CarConnectorOutput.java │ │ │ ├── CarConnectorInput.java │ │ │ └── CarConnector.java │ └── test │ │ └── java │ │ └── com │ │ └── camunda │ │ └── consulting │ │ ├── ResultType.java │ │ ├── TestApp.java │ │ └── CarConnectorTest.java └── README.md ├── extended-connector-runtime ├── src │ ├── main │ │ ├── resources │ │ │ ├── META-INF │ │ │ │ └── services │ │ │ │ │ └── org.camunda.feel.context.CustomFunctionProvider │ │ │ └── application.yaml │ │ └── java │ │ │ └── com │ │ │ └── camunda │ │ │ └── consulting │ │ │ └── example │ │ │ ├── SchedulingService.java │ │ │ ├── App.java │ │ │ ├── CustomFeelFunctionProvider.java │ │ │ └── NextExecutionTimeslotFeelFunction.java │ └── test │ │ └── java │ │ └── com │ │ └── camunda │ │ └── consulting │ │ └── example │ │ └── AppTest.java └── README.md ├── timer-testing ├── README.md └── src │ └── main │ └── java │ └── com │ └── camunda │ └── consulting │ ├── ExampleApplication.java │ └── rest │ └── ExampleRestApi.java ├── task-micro-frontend ├── src │ ├── main │ │ ├── resources │ │ │ ├── static │ │ │ │ └── favicon.ico │ │ │ ├── application.yaml │ │ │ └── index.html │ │ └── java │ │ │ └── com │ │ │ └── camunda │ │ │ └── consulting │ │ │ ├── TaskDto.java │ │ │ ├── App.java │ │ │ ├── UpdateTaskDto.java │ │ │ ├── TaskController.java │ │ │ └── TaskService.java │ └── test │ │ └── java │ │ └── com │ │ └── camunda │ │ └── consulting │ │ └── AppTest.java └── README.md ├── large-multi-instance-example ├── documentation │ ├── bucket-process.png │ ├── letter-process.png │ ├── campaign-process.png │ ├── modeling-concept.png │ ├── large-campaign-process.png │ ├── operate-letter-process.png │ ├── multi-instance-configuration.png │ ├── operate-multi-instance-call-activity.png │ └── operate-processes-with-business-key.png └── src │ ├── main │ ├── resources │ │ ├── application.properties │ │ └── META-INF │ │ │ └── additional-spring-configuration-metadata.json │ └── java │ │ └── com │ │ └── camunda │ │ └── consulting │ │ ├── ExampleApplication.java │ │ ├── rest │ │ └── ExampleRestApi.java │ │ └── worker │ │ └── multi_instance │ │ └── SimpleMultiInstanceWorker.java │ └── test │ └── java │ └── com │ └── camunda │ └── consulting │ ├── SimpleMultiInstanceTest.java │ └── MultiInstanceTest.java ├── renovate.json ├── .gitignore ├── weatherinfo-pyzeebe-connectors ├── src │ ├── activities.py │ ├── form.form │ └── pyzeebeWorker.py └── README.md ├── camunda-client-plain-java ├── README.md └── src │ ├── main │ ├── resources │ │ ├── log4j2.xml │ │ ├── demoDecision.dmn │ │ └── exampleProcess.bpmn │ └── java │ │ └── io │ │ └── camunda │ │ └── example │ │ ├── process │ │ ├── ProcessDeployer.java │ │ ├── ProcessInstanceCreator.java │ │ ├── NonBlockingProcessInstanceCreator.java │ │ └── ProcessInstanceWithResultCreator.java │ │ ├── decision │ │ └── EvaluateDecisionCreator.java │ │ ├── cluster │ │ └── TopologyViewer.java │ │ ├── job │ │ └── JobWorkerCreator.java │ │ └── data │ │ └── HandleVariablesAsPojo.java │ └── test │ └── java │ └── io │ └── camunda │ └── example │ └── DocsConsistencyTest.java ├── secret-provider-as-credentials-provider ├── src │ ├── main │ │ ├── resources │ │ │ └── application.yaml │ │ └── java │ │ │ └── com │ │ │ └── camunda │ │ │ └── consulting │ │ │ ├── App.java │ │ │ ├── BearerTokenProvider.java │ │ │ ├── BearerTokenProviderRegistry.java │ │ │ ├── BearerTokenSecretProvider.java │ │ │ └── ZeebeBearerTokenProvider.java │ └── test │ │ └── java │ │ └── com │ │ └── camunda │ │ └── consulting │ │ ├── BearerTokenSecretProviderTest.java │ │ └── AppTest.java └── README.md ├── zeebe-client-plain-java ├── README.md └── src │ ├── main │ ├── resources │ │ ├── log4j2.xml │ │ └── demoDecision.dmn │ └── java │ │ └── io │ │ └── camunda │ │ └── zeebe │ │ └── example │ │ ├── process │ │ ├── ProcessDeployer.java │ │ ├── ProcessInstanceCreator.java │ │ ├── NonBlockingProcessInstanceCreator.java │ │ └── ProcessInstanceWithResultCreator.java │ │ ├── decision │ │ └── EvaluateDecisionCreator.java │ │ ├── cluster │ │ └── TopologyViewer.java │ │ └── job │ │ └── JobWorkerCreator.java │ └── test │ └── java │ └── io │ └── camunda │ └── zeebe │ └── example │ └── DocsConsistencyTest.java ├── README.md └── .github └── PULL_REQUEST_TEMPLATE.md /react-tasklist/.nvmrc: -------------------------------------------------------------------------------- 1 | 24 -------------------------------------------------------------------------------- /event-processing/.gitignore: -------------------------------------------------------------------------------- 1 | events.mv.db 2 | events.trace.db 3 | -------------------------------------------------------------------------------- /twitter-review-java-springboot/.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | *.iml 3 | target 4 | -------------------------------------------------------------------------------- /synchronous-response-springboot/.gitignore: -------------------------------------------------------------------------------- 1 | /.project 2 | /.settings/ 3 | /.classpath 4 | -------------------------------------------------------------------------------- /async-service-task/src/test/resources/application.yaml: -------------------------------------------------------------------------------- 1 | async-service: 2 | duration: PT5S -------------------------------------------------------------------------------- /react-tasklist/src/main/frontend/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /payment-example-process-application/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | camunda: 2 | client: 3 | mode: selfmanaged -------------------------------------------------------------------------------- /rollback-on-error-example/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | zeebe: 2 | client: 3 | security: 4 | plaintext: true -------------------------------------------------------------------------------- /event-processing/docs/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/event-processing/docs/img.png -------------------------------------------------------------------------------- /event-processing/docs/img2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/event-processing/docs/img2.png -------------------------------------------------------------------------------- /event-processing/docs/img3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/event-processing/docs/img3.png -------------------------------------------------------------------------------- /event-processing/docs/img4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/event-processing/docs/img4.png -------------------------------------------------------------------------------- /parallel-operations/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | camunda: 2 | bpm: 3 | admin-user: 4 | id: demo 5 | password: demo -------------------------------------------------------------------------------- /event-processing/src/test/resources/application.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: jdbc:h2:mem:test 4 | jpa: 5 | generate-ddl: true -------------------------------------------------------------------------------- /react-tasklist/src/main/frontend/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": { 4 | "@/*": ["./src/*"] 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /event-processing/src/test/resources/createEventRequest.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "123", 3 | "name": "random", 4 | "content": { 5 | "foo": "baz" 6 | } 7 | } -------------------------------------------------------------------------------- /powerapps-dataverse/screenshots/bpmn1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/powerapps-dataverse/screenshots/bpmn1.png -------------------------------------------------------------------------------- /ProcessMetadataListener/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | com.camunda.consulting.MetadataWorker -------------------------------------------------------------------------------- /async-service-task/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | zeebe: 2 | client: 3 | security: 4 | plaintext: true 5 | 6 | async-service: 7 | duration: PT1M -------------------------------------------------------------------------------- /element-template-generation/src/main/resources/META-INF/services/io.camunda.connector.api.outbound.OutboundConnectorFunction: -------------------------------------------------------------------------------- 1 | com.camunda.consulting.CarConnector -------------------------------------------------------------------------------- /extended-connector-runtime/src/main/resources/META-INF/services/org.camunda.feel.context.CustomFunctionProvider: -------------------------------------------------------------------------------- 1 | com.camunda.consulting.example.CustomFeelFunctionProvider -------------------------------------------------------------------------------- /powerapps-dataverse/screenshots/appUser1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/powerapps-dataverse/screenshots/appUser1.png -------------------------------------------------------------------------------- /powerapps-dataverse/screenshots/appUser2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/powerapps-dataverse/screenshots/appUser2.png -------------------------------------------------------------------------------- /powerapps-dataverse/screenshots/postman1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/powerapps-dataverse/screenshots/postman1.png -------------------------------------------------------------------------------- /powerapps-dataverse/screenshots/postman2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/powerapps-dataverse/screenshots/postman2.png -------------------------------------------------------------------------------- /powerapps-dataverse/screenshots/postman3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/powerapps-dataverse/screenshots/postman3.png -------------------------------------------------------------------------------- /react-tasklist/src/main/frontend/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | "@tailwindcss/postcss": {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /powerapps-dataverse/screenshots/clientSecret.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/powerapps-dataverse/screenshots/clientSecret.png -------------------------------------------------------------------------------- /powerapps-dataverse/screenshots/connectors1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/powerapps-dataverse/screenshots/connectors1.png -------------------------------------------------------------------------------- /powerapps-dataverse/screenshots/connectors2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/powerapps-dataverse/screenshots/connectors2.png -------------------------------------------------------------------------------- /powerapps-dataverse/screenshots/environment1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/powerapps-dataverse/screenshots/environment1.png -------------------------------------------------------------------------------- /powerapps-dataverse/screenshots/prerequisite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/powerapps-dataverse/screenshots/prerequisite.png -------------------------------------------------------------------------------- /synchronous-response-springboot/doc/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/synchronous-response-springboot/doc/overview.png -------------------------------------------------------------------------------- /element-template-generation/src/test/java/com/camunda/consulting/ResultType.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | public record ResultType(CarConnectorOutput car) {} 4 | -------------------------------------------------------------------------------- /powerapps-dataverse/screenshots/securityRole1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/powerapps-dataverse/screenshots/securityRole1.png -------------------------------------------------------------------------------- /powerapps-dataverse/screenshots/securityRole2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/powerapps-dataverse/screenshots/securityRole2.png -------------------------------------------------------------------------------- /rollback-on-error-example/docs/rollback-process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/rollback-on-error-example/docs/rollback-process.png -------------------------------------------------------------------------------- /powerapps-dataverse/screenshots/appRegistration1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/powerapps-dataverse/screenshots/appRegistration1.png -------------------------------------------------------------------------------- /powerapps-dataverse/screenshots/appRegistration2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/powerapps-dataverse/screenshots/appRegistration2.png -------------------------------------------------------------------------------- /react-tasklist/src/main/frontend/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/react-tasklist/src/main/frontend/src/app/favicon.ico -------------------------------------------------------------------------------- /synchronous-response-springboot/doc/messageEvent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/synchronous-response-springboot/doc/messageEvent.png -------------------------------------------------------------------------------- /timer-testing/README.md: -------------------------------------------------------------------------------- 1 | # Timer Testing 2 | 3 | This is an example on how timers can be tested in Zeebe. 4 | 5 | It contains a unit-test as well as a Spring-Boot Application 6 | -------------------------------------------------------------------------------- /payment-example-process-application/kube/doc-images/bp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/payment-example-process-application/kube/doc-images/bp.png -------------------------------------------------------------------------------- /task-micro-frontend/src/main/resources/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/task-micro-frontend/src/main/resources/static/favicon.ico -------------------------------------------------------------------------------- /large-multi-instance-example/documentation/bucket-process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/large-multi-instance-example/documentation/bucket-process.png -------------------------------------------------------------------------------- /large-multi-instance-example/documentation/letter-process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/large-multi-instance-example/documentation/letter-process.png -------------------------------------------------------------------------------- /event-processing/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: jdbc:h2:file:./events 4 | jpa: 5 | generate-ddl: true 6 | camunda: 7 | client: 8 | mode: selfmanaged -------------------------------------------------------------------------------- /large-multi-instance-example/documentation/campaign-process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/large-multi-instance-example/documentation/campaign-process.png -------------------------------------------------------------------------------- /large-multi-instance-example/documentation/modeling-concept.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/large-multi-instance-example/documentation/modeling-concept.png -------------------------------------------------------------------------------- /react-tasklist/src/main/java/com/camunda/consulting/tasklist/model/TaskOverviewDto.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.tasklist.model; 2 | 3 | public record TaskOverviewDto(String id, String name) {} 4 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended", 5 | ":automergeMinor", 6 | ":automergePatch" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /element-template-generation/src/main/java/com/camunda/consulting/CarConnectorOutput.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | public record CarConnectorOutput(String make, String model, String gearbox) {} 4 | -------------------------------------------------------------------------------- /large-multi-instance-example/documentation/large-campaign-process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/large-multi-instance-example/documentation/large-campaign-process.png -------------------------------------------------------------------------------- /large-multi-instance-example/documentation/operate-letter-process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/large-multi-instance-example/documentation/operate-letter-process.png -------------------------------------------------------------------------------- /synchronous-response-springboot/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | zeebe.client.cloud.region=bru-2 2 | zeebe.client.cloud.clusterId=XXX 3 | zeebe.client.cloud.clientId=XXX 4 | zeebe.client.cloud.clientSecret=XXX -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | /zeebe-client/target/ 3 | /zeebe-client/.flattened-pom.xml 4 | /zeebe-client/zeebe-samples.iml 5 | target 6 | **/.classpath 7 | **/.project 8 | **/.settings 9 | **/.factorypath 10 | .DS_Store -------------------------------------------------------------------------------- /payment-example-process-application/kube/doc-images/identity-add-app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/payment-example-process-application/kube/doc-images/identity-add-app.png -------------------------------------------------------------------------------- /large-multi-instance-example/documentation/multi-instance-configuration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/large-multi-instance-example/documentation/multi-instance-configuration.png -------------------------------------------------------------------------------- /payment-example-process-application/kube/doc-images/identity-add-m2m-app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/payment-example-process-application/kube/doc-images/identity-add-m2m-app.png -------------------------------------------------------------------------------- /large-multi-instance-example/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | camunda.client.zeebe.grpc-address=http://localhost:26500 2 | 3 | multi-instance-example.number-of-buckets=4 4 | multi-instance-example.number-of-elements=3 5 | -------------------------------------------------------------------------------- /payment-example-process-application/kube/doc-images/identity-reveal-secret.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/payment-example-process-application/kube/doc-images/identity-reveal-secret.png -------------------------------------------------------------------------------- /payment-example-process-application/kube/doc-images/identity-add-permission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/payment-example-process-application/kube/doc-images/identity-add-permission.png -------------------------------------------------------------------------------- /large-multi-instance-example/documentation/operate-multi-instance-call-activity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/large-multi-instance-example/documentation/operate-multi-instance-call-activity.png -------------------------------------------------------------------------------- /large-multi-instance-example/documentation/operate-processes-with-business-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-8-examples/HEAD/large-multi-instance-example/documentation/operate-processes-with-business-key.png -------------------------------------------------------------------------------- /task-micro-frontend/src/main/java/com/camunda/consulting/TaskDto.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import java.util.Map; 4 | 5 | public record TaskDto( 6 | Map variables, Map formSchema, String status) {} 7 | -------------------------------------------------------------------------------- /payment-example-process-application/kube/manifests/secrets.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: payment-example-process-application-secrets 5 | namespace: c8-payment-demo 6 | type: Opaque 7 | data: 8 | CAMUNDA_CLIENT_AUTH_CLIENTSECRET: CLIENT_SECRET_B64 -------------------------------------------------------------------------------- /task-micro-frontend/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | tasklist: 2 | client: 3 | profile: simple 4 | defaults: 5 | load-truncated-variables: true 6 | return-variables: true 7 | use-zeebe-user-tasks: true 8 | camunda: 9 | client: 10 | mode: self-managed -------------------------------------------------------------------------------- /weatherinfo-pyzeebe-connectors/src/activities.py: -------------------------------------------------------------------------------- 1 | sunnyActivities = { 2 | "Potsdam": "Park Sansouci", 3 | "Berlin": "East Side Gallary", 4 | "Munich": "English Garden"} 5 | rainActivities = { 6 | "Potsdam": "Barberini", 7 | "Berlin": "Museums Insel", 8 | "Munich": "Kunstareal"} -------------------------------------------------------------------------------- /rollback-on-error-example/src/main/java/com/camunda/consulting/DynamicJobHandler.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import io.camunda.zeebe.client.api.response.ActivatedJob; 4 | 5 | public interface DynamicJobHandler { 6 | String getJobTypeName(); 7 | 8 | Object handle(ActivatedJob job); 9 | } 10 | -------------------------------------------------------------------------------- /task-micro-frontend/src/test/java/com/camunda/consulting/AppTest.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | public class AppTest { 8 | 9 | @Test 10 | void shouldRun() {} 11 | } 12 | -------------------------------------------------------------------------------- /camunda-client-plain-java/README.md: -------------------------------------------------------------------------------- 1 | # Camunda Java Client Examples 2 | 3 | This Maven project contains a number of examples each performing a specific task using the Camunda Java client. 4 | 5 | For an overview and context have a look at 6 | the [documentation](https://docs.camunda.io/docs/apis-tools/java-client-examples/) 7 | -------------------------------------------------------------------------------- /twitter-review-java-springboot/src/main/java/org/camunda/community/examples/twitter/business/TwitterService.java: -------------------------------------------------------------------------------- 1 | package org.camunda.community.examples.twitter.business; 2 | 3 | /** Publish content on Twitter. */ 4 | public interface TwitterService { 5 | 6 | void tweet(String content) throws DuplicateTweetException; 7 | } 8 | -------------------------------------------------------------------------------- /extended-connector-runtime/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | camunda: 2 | connector: 3 | polling: 4 | enabled: false 5 | webhook: 6 | enabled: false 7 | client: 8 | mode: self-managed 9 | operate: 10 | client: 11 | enabled: false 12 | logging: 13 | level: 14 | io.camunda.connector: DEBUG -------------------------------------------------------------------------------- /react-tasklist/src/main/java/com/camunda/consulting/tasklist/model/TaskDto.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.tasklist.model; 2 | 3 | import com.fasterxml.jackson.databind.JsonNode; 4 | import java.util.Map; 5 | 6 | public record TaskDto(String id,String name,Map schema, Map data, String formKey) {} 7 | -------------------------------------------------------------------------------- /twitter-review-java-springboot/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | zeebe.client.cloud.clusterId=9eb7ef05-1814-4888-8dc6-a043246df15a 2 | zeebe.client.cloud.clientId=g00AS9IpG2qErRd14lI_AuP~2Ocbr5lO 3 | zeebe.client.cloud.clientSecret=r-qSZw8rX1tSQFM2A1krCsbh-uDmNPBMagVQQCA-kEJmGeDEWXQgv5kd6X5QBFqF 4 | zeebe.client.cloud.region=bru-2 5 | -------------------------------------------------------------------------------- /secret-provider-as-credentials-provider/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | camunda: 2 | client: 3 | mode: self-managed 4 | auth: 5 | client-id: zeebe 6 | client-secret: zecret 7 | connector: 8 | webhook: 9 | enabled: false 10 | polling: 11 | enabled: false 12 | operate: 13 | client: 14 | enabled: false -------------------------------------------------------------------------------- /payment-example-process-application/kube/manifests/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: payment-example-process-application 5 | namespace: c8-payment-demo 6 | spec: 7 | selector: 8 | app: payment-example-process-application 9 | ports: 10 | - protocol: TCP 11 | port: 8080 12 | targetPort: 8080 13 | -------------------------------------------------------------------------------- /payment-example-process-application/src/main/java/com/camunda/consulting/web_shop_process_app/service/CreditCardExpiredException.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.web_shop_process_app.service; 2 | 3 | public class CreditCardExpiredException extends RuntimeException { 4 | 5 | public CreditCardExpiredException(String message) { 6 | super(message); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /parallel-operations/src/main/java/com/camunda/consulting/StringService.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import org.apache.commons.lang3.RandomStringUtils; 4 | import org.springframework.stereotype.Service; 5 | 6 | @Service 7 | public class StringService { 8 | public String get() { 9 | return RandomStringUtils.randomAlphabetic(10); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ProcessMetadataListener/src/main/java/com/camunda/consulting/ProcessMetadataResult.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | public record ProcessMetadataResult(Camunda camunda) { 4 | public record Camunda( 5 | String processInstanceKey, 6 | String processDefinitionKey, 7 | String processDefinitionId, 8 | int version, 9 | String versionTag) {} 10 | } 11 | -------------------------------------------------------------------------------- /task-micro-frontend/src/main/java/com/camunda/consulting/App.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class App { 8 | public static void main(String[] args) { 9 | SpringApplication.run(App.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /react-tasklist/src/main/frontend/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: false, 4 | output: 'export', 5 | async rewrites() { 6 | return [ 7 | { 8 | source: '/api/:path*', 9 | destination: `http://localhost:8080/api/:path*`, 10 | }, 11 | ] 12 | }, 13 | } 14 | 15 | 16 | module.exports = nextConfig 17 | -------------------------------------------------------------------------------- /ProcessMetadataListener/src/test/java/com/camunda/consulting/TestApp.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class TestApp { 8 | public static void main(String[] args) { 9 | SpringApplication.run(TestApp.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /react-tasklist/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | tasklist: 2 | client: 3 | profile: simple 4 | camunda: 5 | webhook: 6 | url: http://localhost:8085/inbound 7 | authorization: 8 | username: demo 9 | password: demo 10 | client: 11 | mode: self-managed 12 | zeebe: 13 | enabled: true 14 | grpc-address: http://localhost:26500 15 | rest-address: http://localhost:8088 -------------------------------------------------------------------------------- /secret-provider-as-credentials-provider/src/main/java/com/camunda/consulting/App.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class App { 8 | public static void main(String[] args) { 9 | SpringApplication.run(App.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /element-template-generation/src/test/java/com/camunda/consulting/TestApp.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class TestApp { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(TestApp.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /react-tasklist/src/main/java/com/camunda/consulting/tasklist/CamundaWebhookProperties.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.tasklist; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | @ConfigurationProperties("camunda.webhook") 6 | public record CamundaWebhookProperties(String url, Authorization authorization) { 7 | public record Authorization(String username, String password) {} 8 | } 9 | -------------------------------------------------------------------------------- /secret-provider-as-credentials-provider/src/main/java/com/camunda/consulting/BearerTokenProvider.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | /** 4 | * This is the interface that describes the contract between the {@link BearerTokenProviderRegistry} 5 | * and each individual implementation. 6 | */ 7 | public interface BearerTokenProvider { 8 | String getServiceName(); 9 | 10 | String getBearerToken(); 11 | } 12 | -------------------------------------------------------------------------------- /event-processing/src/main/java/com/camunda/consulting/eventprocessing/App.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.eventprocessing; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class App { 8 | public static void main(String[] args) { 9 | SpringApplication.run(App.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /large-multi-instance-example/src/main/resources/META-INF/additional-spring-configuration-metadata.json: -------------------------------------------------------------------------------- 1 | {"properties": [ 2 | { 3 | "name": "multi-instance-example.number-of-buckets", 4 | "type": "java.lang.Integer", 5 | "description": "The number of buckets" 6 | }, 7 | { 8 | "name": "multi-instance-example.number-of-elements", 9 | "type": "java.lang.Integer", 10 | "description": "The numebr of elements per bucket" 11 | } 12 | ]} -------------------------------------------------------------------------------- /rollback-on-error-example/src/main/java/com/camunda/consulting/FailJobException.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import io.camunda.zeebe.gateway.protocol.GatewayOuterClass.FailJobRequest.Builder; 4 | 5 | public class FailJobException extends RuntimeException { 6 | private final Builder builder; 7 | 8 | public FailJobException(Builder builder) { 9 | super(builder.getErrorMessage()); 10 | this.builder = builder; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /twitter-review-java-springboot/src/main/java/org/camunda/community/examples/twitter/business/DuplicateTweetException.java: -------------------------------------------------------------------------------- 1 | package org.camunda.community.examples.twitter.business; 2 | 3 | public class DuplicateTweetException extends Exception { 4 | public DuplicateTweetException(String message) { 5 | super(message); 6 | } 7 | 8 | public DuplicateTweetException(String message, Throwable cause) { 9 | super(message, cause); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /zeebe-client-plain-java/README.md: -------------------------------------------------------------------------------- 1 | # Zeebe Java Client Examples 2 | 3 | This Maven project contains a number of examples each performing a specific task using the Zeebe 4 | Java client. 5 | 6 | For an overview and context have a look at 7 | the [Zeebe documentation](https://docs.camunda.io/docs/product-manuals/clients/java-client-examples/index) 8 | 9 | **Note:** If you are using an older version of Zeebe (< 8.0) some of the examples need to be adjusted. 10 | -------------------------------------------------------------------------------- /extended-connector-runtime/src/main/java/com/camunda/consulting/example/SchedulingService.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.example; 2 | 3 | import java.time.ZonedDateTime; 4 | import org.springframework.stereotype.Service; 5 | 6 | @Service 7 | public class SchedulingService { 8 | public ZonedDateTime schedule(ZonedDateTime scheduledExecution) { 9 | // you can call your scheduling system here 10 | return scheduledExecution.plusMinutes(10); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /react-tasklist/src/main/frontend/src/app/components/forms/some-form.js: -------------------------------------------------------------------------------- 1 | import {useEffect, useState} from "react"; 2 | 3 | export default function MyForm({data, setResult}) { 4 | const [myText, setMyText] = useState(data.myText || ""); 5 | const myTextChanged = (e) => setMyText(e.target.value); 6 | 7 | useEffect(() => { 8 | setResult({myText}) 9 | }, [myText]); 10 | 11 | return ( 12 | 13 | ); 14 | } -------------------------------------------------------------------------------- /react-tasklist/src/main/frontend/src/app/layout.js: -------------------------------------------------------------------------------- 1 | import { Inter } from 'next/font/google' 2 | import './globals.css' 3 | 4 | const inter = Inter({ subsets: ['latin'] }) 5 | 6 | export const metadata = { 7 | title: 'Tasklist App', 8 | description: 'Super nice Tasklist app', 9 | } 10 | 11 | export default function RootLayout({ children }) { 12 | return ( 13 | 14 | {children} 15 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /rollback-on-error-example/src/main/java/com/camunda/consulting/ValidateDataHandler.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import io.camunda.zeebe.client.api.response.ActivatedJob; 4 | import org.springframework.stereotype.Component; 5 | 6 | @Component 7 | public class ValidateDataHandler implements DynamicJobHandler { 8 | @Override 9 | public String getJobTypeName() { 10 | return "validateDataType"; 11 | } 12 | 13 | @Override 14 | public Object handle(ActivatedJob job) { 15 | return null; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /parallel-operations/src/main/resources/META-INF/processes.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | false 8 | true 9 | bpmn/camunda7 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /async-service-task/src/main/java/com/camunda/consulting/ExampleApplication.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import io.camunda.zeebe.spring.client.annotation.Deployment; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | @SpringBootApplication 8 | @Deployment(resources = "classpath*:*.bpmn") 9 | public class ExampleApplication { 10 | public static void main(String[] args) { 11 | SpringApplication.run(ExampleApplication.class, args); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /camunda-client-plain-java/src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /payment-example-process-application/kube/manifests/ingress.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: payment-ingress 5 | namespace: c8-payment-demo 6 | annotations: 7 | nginx.ingress.kubernetes.io/rewrite-target: / 8 | spec: 9 | rules: 10 | - host: your-host.dv 11 | http: 12 | paths: 13 | - path: / 14 | pathType: Prefix 15 | backend: 16 | service: 17 | name: payment-example-process-application 18 | port: 19 | number: 8080 20 | -------------------------------------------------------------------------------- /rollback-on-error-example/src/main/java/com/camunda/consulting/SaveDataHandler.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import io.camunda.zeebe.client.api.response.ActivatedJob; 4 | import org.springframework.stereotype.Component; 5 | 6 | @Component 7 | public class SaveDataHandler implements DynamicJobHandler { 8 | @Override 9 | public String getJobTypeName() { 10 | return "saveDataType"; 11 | } 12 | 13 | @Override 14 | public Object handle(ActivatedJob job) { 15 | throw new RuntimeException("An error happened"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /zeebe-client-plain-java/src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /react-tasklist/src/main/java/com/camunda/consulting/tasklist/App.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.tasklist; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 6 | 7 | @SpringBootApplication 8 | @EnableConfigurationProperties({CamundaWebhookProperties.class}) 9 | public class App { 10 | public static void main(String[] args) { 11 | SpringApplication.run(App.class, args); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /large-multi-instance-example/src/main/java/com/camunda/consulting/ExampleApplication.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import io.camunda.zeebe.spring.client.annotation.Deployment; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | @SpringBootApplication 8 | @Deployment(resources = "classpath*:**/*.bpmn") 9 | public class ExampleApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(ExampleApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /react-tasklist/src/main/frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /react-tasklist/src/main/frontend/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | './src/pages/**/*.{js,ts,jsx,tsx,mdx}', 5 | './src/components/**/*.{js,ts,jsx,tsx,mdx}', 6 | './src/app/**/*.{js,ts,jsx,tsx,mdx}', 7 | ], 8 | theme: { 9 | extend: { 10 | backgroundImage: { 11 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', 12 | 'gradient-conic': 13 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', 14 | }, 15 | }, 16 | }, 17 | plugins: [], 18 | } 19 | -------------------------------------------------------------------------------- /twitter-review-java-springboot/src/main/java/org/camunda/community/examples/twitter/TwitterExampleApplication.java: -------------------------------------------------------------------------------- 1 | package org.camunda.community.examples.twitter; 2 | 3 | import io.camunda.zeebe.spring.client.annotation.Deployment; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | @SpringBootApplication 8 | @Deployment(resources = "classpath*:*.bpmn") 9 | public class TwitterExampleApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(TwitterExampleApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /async-service-task/src/main/java/com/camunda/consulting/AsyncServiceProperties.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import java.time.Duration; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | @ConfigurationProperties("async-service") 8 | @Configuration 9 | public class AsyncServiceProperties { 10 | private Duration duration; 11 | 12 | public Duration getDuration() { 13 | return duration; 14 | } 15 | 16 | public void setDuration(Duration duration) { 17 | this.duration = duration; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /synchronous-response-springboot/src/main/java/org/example/camunda/process/solution/SyncResponseProcessApplication.java: -------------------------------------------------------------------------------- 1 | package org.example.camunda.process.solution; 2 | 3 | import io.camunda.zeebe.spring.client.annotation.Deployment; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | @SpringBootApplication 8 | @Deployment(resources = "classpath*:/models/*.*") 9 | public class SyncResponseProcessApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(SyncResponseProcessApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /payment-example-process-application/src/main/java/com/camunda/consulting/web_shop_process_app/PaymentProcessApplication.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.web_shop_process_app; 2 | 3 | import io.camunda.zeebe.spring.client.annotation.Deployment; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | @SpringBootApplication 8 | @Deployment(resources = {"payment_process.bpmn", "check-payment.form"}) 9 | public class PaymentProcessApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(PaymentProcessApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /react-tasklist/src/main/frontend/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extended-connector-runtime/src/main/java/com/camunda/consulting/example/App.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.example; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.context.ApplicationContext; 6 | 7 | @SpringBootApplication 8 | public class App { 9 | public static ApplicationContext applicationContext; 10 | 11 | public static void main(String[] args) { 12 | applicationContext = SpringApplication.run(App.class, args); 13 | } 14 | 15 | public static ApplicationContext getApplicationContext() { 16 | return applicationContext; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /react-tasklist/src/main/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@bpmn-io/form-js-viewer": "^1.6.0", 13 | "@tailwindcss/postcss": "^4.1.8", 14 | "next": "16.1.0", 15 | "react": "^19.0.0", 16 | "react-dom": "^19.0.0" 17 | }, 18 | "devDependencies": { 19 | "autoprefixer": "^10.0.1", 20 | "eslint": "^9.0.0", 21 | "eslint-config-next": "16.1.0", 22 | "postcss": "^8", 23 | "tailwindcss": "^4.0.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /parallel-operations/src/main/java/com/camunda/consulting/ParallelOperationsApp.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import io.camunda.zeebe.spring.client.annotation.Deployment; 4 | import org.camunda.bpm.spring.boot.starter.annotation.EnableProcessApplication; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | 8 | @SpringBootApplication 9 | @EnableProcessApplication 10 | @Deployment(resources = "classpath*:bpmn/camunda8/*.bpmn") 11 | public class ParallelOperationsApp { 12 | public static void main(String[] args) { 13 | SpringApplication.run(ParallelOperationsApp.class, args); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /react-tasklist/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | !**/src/main/**/target/ 4 | !**/src/test/**/target/ 5 | 6 | ### IntelliJ IDEA ### 7 | .idea/modules.xml 8 | .idea/jarRepositories.xml 9 | .idea/compiler.xml 10 | .idea/libraries/ 11 | *.iws 12 | *.iml 13 | *.ipr 14 | 15 | ### Eclipse ### 16 | .apt_generated 17 | .classpath 18 | .factorypath 19 | .project 20 | .settings 21 | .springBeans 22 | .sts4-cache 23 | 24 | ### NetBeans ### 25 | /nbproject/private/ 26 | /nbbuild/ 27 | /dist/ 28 | /nbdist/ 29 | /.nb-gradle/ 30 | build/ 31 | !**/src/main/**/build/ 32 | !**/src/test/**/build/ 33 | 34 | ### VS Code ### 35 | .vscode/ 36 | 37 | ### Mac OS ### 38 | .DS_Store 39 | 40 | node 41 | -------------------------------------------------------------------------------- /react-tasklist/src/main/frontend/src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --foreground-rgb: 0, 0, 0; 7 | --background-start-rgb: 214, 219, 220; 8 | --background-end-rgb: 255, 255, 255; 9 | } 10 | 11 | @media (prefers-color-scheme: dark) { 12 | :root { 13 | --foreground-rgb: 255, 255, 255; 14 | --background-start-rgb: 0, 0, 0; 15 | --background-end-rgb: 0, 0, 0; 16 | } 17 | } 18 | 19 | body { 20 | color: rgb(var(--foreground-rgb)); 21 | background: linear-gradient( 22 | to bottom, 23 | transparent, 24 | rgb(var(--background-end-rgb)) 25 | ) 26 | rgb(var(--background-start-rgb)); 27 | } 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![](https://img.shields.io/badge/Community%20Extension-An%20open%20source%20community%20maintained%20project-FF4700)](https://github.com/camunda-community-hub/community) 2 | 3 | # Camunda 8 Examples 4 | 5 | A collection of examples related to the usage of Camunda 8. 6 | 7 | ## How to use 8 | 9 | Check out the repo. Navigate to the project you are interested in. Each project should contain: 10 | 11 | * an introduction to the purpose 12 | * a brief description of the functionality 13 | * a guide on how to setup and test the example 14 | 15 | ## Report problems 16 | 17 | If problems occur, please file an issue containing: 18 | 19 | * which project should be used 20 | * what did not work out 21 | * which environment was used (java version, build tool, ...) 22 | -------------------------------------------------------------------------------- /weatherinfo-pyzeebe-connectors/src/form.form: -------------------------------------------------------------------------------- 1 | { 2 | "components": [ 3 | { 4 | "label": "City", 5 | "type": "textfield", 6 | "id": "Field_1r7q8ri", 7 | "key": "location", 8 | "validate": { 9 | "required": true 10 | } 11 | }, 12 | { 13 | "label": "email", 14 | "type": "textfield", 15 | "id": "Field_10n1zpm", 16 | "key": "email", 17 | "validate": { 18 | "required": true 19 | } 20 | } 21 | ], 22 | "schemaVersion": 4, 23 | "exporter": { 24 | "name": "Camunda Web Modeler", 25 | "version": "ed3e962" 26 | }, 27 | "type": "default", 28 | "id": "Formular_LocationAndEmail", 29 | "executionPlatform": "Camunda Cloud", 30 | "executionPlatformVersion": "1.3" 31 | } -------------------------------------------------------------------------------- /react-tasklist/README.md: -------------------------------------------------------------------------------- 1 | # React Tasklist 2 | 3 | ## Features 4 | 5 | * Uses Camunda Tasklist REST API to work with tasks 6 | * Uses a webhook to start a process instance 7 | * renders Camunda Forms using a dedicated component 8 | * renders other forms using react 9 | 10 | ## Prerequisites 11 | 12 | * run Camunda platform 13 | * ensure you have access to: 14 | * Tasklist REST API 15 | * Connectors inbound endpoint 16 | * Keycloak REST API 17 | * deploy _example.bpmn_ upfront (the application does not actually rely on a zeebe client, so no deployment) 18 | 19 | >For this, you may have to generate your own "Application" in Identity 20 | 21 | ## How to use 22 | 23 | * adjust the `application.yaml` to match your connection details 24 | * run it using `mvn spring-boot:run` -------------------------------------------------------------------------------- /react-tasklist/src/main/frontend/src/app/components/react-form.js: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import myForm from './forms/some-form'; 3 | 4 | const forms = { 5 | myForm 6 | } 7 | 8 | export default function ReactFormContainer({formKey,data,onComplete}) { 9 | const [result,setResult] = useState({}) 10 | const sanitizedFormKey = formKey.substring("react:".length) 11 | const ReactForm = forms[sanitizedFormKey] 12 | const submit = () => onComplete(result) 13 | return ( 14 | <> 15 | { ReactForm ? 16 | (<> 17 | 18 | 19 | ) : (

Form could not be found...

) 20 | } 21 | 22 | 23 | ) 24 | } -------------------------------------------------------------------------------- /twitter-review-java-springboot/readme.md: -------------------------------------------------------------------------------- 1 | # Camunda 8 Spring Boot Process Solution Example 2 | 3 | The self-contained process solution contains 4 | 5 | * The process model as BPMN (auto-deployed during startup) 6 | * Glue code for the service task 7 | * REST endpoint that then starts a process instance 8 | * Test case 9 | 10 | Requirements: 11 | 12 | * Camunda Platform 8 13 | * Java >= 17 14 | * Maven 15 | 16 | ## How to run 17 | 18 | * Download/clone the code in this folder. 19 | * Create a Camunda 8 SaaS cluster and add API client connection details in the file `application.properties`. Simply replace the existing sample values. 20 | * Run the application: 21 | 22 | ``` 23 | mvn package exec:java 24 | ``` 25 | 26 | ``` 27 | curl -i -X PUT http://localhost:8080/tweet 28 | ``` 29 | -------------------------------------------------------------------------------- /event-processing/src/main/java/com/camunda/consulting/eventprocessing/ExampleServiceCalls.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.eventprocessing; 2 | 3 | import io.camunda.zeebe.spring.client.annotation.JobWorker; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.stereotype.Component; 7 | 8 | @Component 9 | public class ExampleServiceCalls { 10 | private static final Logger LOG = LoggerFactory.getLogger(ExampleServiceCalls.class); 11 | 12 | @JobWorker 13 | public void service1() { 14 | LOG.info("Service 1 called"); 15 | } 16 | 17 | @JobWorker 18 | public void service2() { 19 | LOG.info("Service 2 called"); 20 | } 21 | 22 | @JobWorker 23 | public void service3() { 24 | LOG.info("Service 3 called"); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /payment-example-process-application/src/test/java/com/camunda/consulting/web_shop_process_app/test/ServiceTest.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.web_shop_process_app.test; 2 | 3 | import static org.assertj.core.api.Assertions.*; 4 | 5 | import com.camunda.consulting.web_shop_process_app.service.CustomerService; 6 | import org.junit.jupiter.api.Test; 7 | 8 | public class ServiceTest { 9 | 10 | @Test 11 | public void test_Customer_With_No_Credit_Number_Throws_Exception() { 12 | CustomerService customerService = new CustomerService(); 13 | 14 | try { 15 | customerService.getCustomerCredit("hallo"); 16 | fail("Exception expected"); 17 | } catch (Exception e) { 18 | assertThat(e).hasMessage("The customer ID doesn't end with a number"); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /synchronous-response-springboot/src/test/java/org/example/camunda/process/solution/AppTest.java: -------------------------------------------------------------------------------- 1 | package org.example.camunda.process.solution; 2 | 3 | import static org.assertj.core.api.Assertions.*; 4 | 5 | import io.camunda.process.test.api.CamundaSpringProcessTest; 6 | import org.example.camunda.process.solution.facade.ProcessController; 7 | import org.junit.jupiter.api.Test; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.test.context.SpringBootTest; 10 | 11 | @SpringBootTest 12 | @CamundaSpringProcessTest 13 | public class AppTest { 14 | 15 | @Autowired ProcessController processController; 16 | 17 | @Test 18 | void shouldWork() { 19 | String response = processController.startProcessInstance().block(); 20 | assertThat(response).isEqualTo("The response is - of course - 42"); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /async-service-task/src/main/java/com/camunda/consulting/ProcessController.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import io.camunda.zeebe.client.ZeebeClient; 4 | import io.camunda.zeebe.client.api.response.ProcessInstanceEvent; 5 | import org.springframework.web.bind.annotation.PostMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | @RestController 9 | public class ProcessController { 10 | private final ZeebeClient zeebeClient; 11 | 12 | public ProcessController(ZeebeClient zeebeClient) { 13 | this.zeebeClient = zeebeClient; 14 | } 15 | 16 | @PostMapping("/start") 17 | public ProcessInstanceEvent start() { 18 | return zeebeClient 19 | .newCreateInstanceCommand() 20 | .bpmnProcessId("AsyncServiceTaskProcess") 21 | .latestVersion() 22 | .send() 23 | .join(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /synchronous-response-springboot/src/main/java/org/example/camunda/process/solution/worker/CalculateSomethingWorker.java: -------------------------------------------------------------------------------- 1 | package org.example.camunda.process.solution.worker; 2 | 3 | import io.camunda.zeebe.spring.client.annotation.JobWorker; 4 | import java.util.Collections; 5 | import java.util.Map; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.stereotype.Component; 9 | 10 | @Component 11 | public class CalculateSomethingWorker { 12 | 13 | private static final Logger LOG = LoggerFactory.getLogger(CalculateSomethingWorker.class); 14 | 15 | @JobWorker 16 | public Map calculateSomething() { 17 | try { 18 | LOG.info("Calculating something ..."); 19 | Thread.sleep(5000); 20 | } catch (InterruptedException e) { 21 | LOG.error("Thread sleep got interrupted: {}", e.getMessage()); 22 | } 23 | return Collections.singletonMap("response", "The response is - of course - 42"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /extended-connector-runtime/src/main/java/com/camunda/consulting/example/CustomFeelFunctionProvider.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.example; 2 | 3 | import java.util.Collection; 4 | import java.util.List; 5 | import java.util.Optional; 6 | import org.camunda.feel.context.JavaFunction; 7 | import org.camunda.feel.context.JavaFunctionProvider; 8 | 9 | public class CustomFeelFunctionProvider extends JavaFunctionProvider { 10 | 11 | @Override 12 | public Optional resolveFunction(String functionName) { 13 | if (NextExecutionTimeslotFeelFunction.NAME.equals(functionName)) { 14 | return Optional.of( 15 | new JavaFunction( 16 | NextExecutionTimeslotFeelFunction.PARAMS, 17 | NextExecutionTimeslotFeelFunction.getInstance())); 18 | } 19 | return Optional.empty(); 20 | } 21 | 22 | @Override 23 | public Collection getFunctionNames() { 24 | return List.of(NextExecutionTimeslotFeelFunction.NAME); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /camunda-client-plain-java/src/main/java/io/camunda/example/process/ProcessDeployer.java: -------------------------------------------------------------------------------- 1 | package io.camunda.example.process; 2 | 3 | import io.camunda.client.CamundaClient; 4 | import io.camunda.client.api.response.DeploymentEvent; 5 | import io.camunda.example.ClientProvider; 6 | import io.camunda.example.ClientProvider.AuthMethod; 7 | 8 | /** 9 | * Example application that connects to a cluster on Camunda Cloud, or a locally deployed cluster. 10 | * 11 | *

It uses {@link ClientProvider} to create a client with the appropriate authentication method. 12 | */ 13 | public final class ProcessDeployer { 14 | 15 | public static void main(final String[] args) { 16 | try (final CamundaClient client = ClientProvider.createCamundaClient(AuthMethod.none)) { 17 | 18 | final DeploymentEvent deploymentEvent = 19 | client.newDeployResourceCommand().addResourceFromClasspath("demoProcess.bpmn").execute(); 20 | 21 | System.out.println("Deployment created with key: " + deploymentEvent.getKey()); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /element-template-generation/README.md: -------------------------------------------------------------------------------- 1 | # Element Template Generation 2 | 3 | >This example can be extended to demonstrate other element template generations 4 | 5 | ## Generating Dropdowns with Conditional Properties 6 | 7 | This example contains the `CarConnectorInput` that allows to configure a car. 8 | 9 | Based on the selected _make_, there are different other dropdowns shown for the _model_. Also, the _gearbox_ is a simple selection. 10 | 11 | ## Using the template 12 | 13 | Please upload the template to the Web Modeler and release it in your project to use it. 14 | 15 | As alternative, follow [this guide](https://docs.camunda.io/docs/next/components/modeler/desktop-modeler/element-templates/configuring-templates/) to install it to the Desktop Modeler to use it from there. 16 | 17 | ## Running the connector 18 | 19 | As the connector comes without any dependency, it can be added to any connector runtime as described [here](https://docs.camunda.io/docs/next/components/connectors/custom-built-connectors/connector-sdk/#runtime-environments). 20 | -------------------------------------------------------------------------------- /task-micro-frontend/README.md: -------------------------------------------------------------------------------- 1 | # User task micro frontend 2 | 3 | This is an example on how a user task micro frontend can be built. 4 | 5 | ## What is the purpose? 6 | 7 | To embed a Camunda task into your own tasklist, you might require a micro frontend for a composed web application. 8 | 9 | ## What does it cover? 10 | 11 | The current example covers: 12 | 13 | * backend integration between Tasklist/Camunda API and micro frontend backend 14 | * creation of plain html/js task view 15 | * handling of completed forms by making all components read-only 16 | * handling of submit buttons by removing all of them from the original form and only showing one 17 | 18 | ## How do I set it up? 19 | 20 | To start the application, configure the `application.yaml` so that: 21 | 22 | * the tasklist client is configured according to your tasklist api (base url and authentication) 23 | * task camunda client is configured according to your camunda api (addresses and authentication) 24 | 25 | Then, you can run the application with: 26 | 27 | ```shell 28 | mvn spring-boot:run 29 | ``` -------------------------------------------------------------------------------- /ProcessMetadataListener/README.md: -------------------------------------------------------------------------------- 1 | # Process metadata listener 2 | 3 | This example shows how a generic metadata listener for a process could look like. 4 | 5 | ## What does it do? 6 | 7 | The example contains a job worker for the type `metadata` that set a variable `camunda`: 8 | 9 | ```json 10 | { 11 | "processDefinitionId": "", 12 | "processDefinitionKey": "", 13 | "versionTag": "", 14 | "processInstanceKey": "", 15 | "version": 0 16 | } 17 | ``` 18 | 19 | ## Why do I need this? 20 | 21 | Camunda can currently not provide context information about the process instance from the feel context. This execution listener fills the gap. 22 | 23 | ## How can I make use of it? 24 | 25 | ### As part of the connector runtime 26 | 27 | You can build the project using maven: 28 | 29 | ```shell 30 | mvn clean package 31 | ``` 32 | 33 | Then, you can copy the resulting jar file to your connector runtime under `/opt/custom`. 34 | 35 | ### As part of your own project 36 | 37 | You can also copy/fork this project source code and use the worker in your own java project. 38 | -------------------------------------------------------------------------------- /rollback-on-error-example/src/main/java/com/camunda/consulting/ProcessController.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import io.camunda.zeebe.client.ZeebeClient; 4 | import io.camunda.zeebe.client.api.response.ProcessInstanceEvent; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.web.bind.annotation.PostMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | @RestController 11 | public class ProcessController { 12 | private final ZeebeClient zeebeClient; 13 | 14 | @Autowired 15 | public ProcessController(ZeebeClient zeebeClient) { 16 | this.zeebeClient = zeebeClient; 17 | } 18 | 19 | @PostMapping("/start") 20 | public ResponseEntity start() { 21 | return ResponseEntity.ok( 22 | zeebeClient 23 | .newCreateInstanceCommand() 24 | .bpmnProcessId("RollbackOnErrorProcess") 25 | .latestVersion() 26 | .send() 27 | .join()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | 4 | ## Additional context 5 | 6 | 7 | 8 | ## Types of changes 9 | 10 | - [ ] Bug fix (non-breaking change which fixes an existing open issue) 11 | - [ ] New example (non-breaking change which adds functionality to an extension) 12 | - [ ] Documentation update (changes made to an existing piece of documentation) 13 | 14 | ## Checklist: 15 | 16 | 17 | - [ ] My code is formatted by spotless 18 | - [ ] I have added at least one meaningful test to assert the behaviour of the example. 19 | - [ ] I have created documentation that informs about the purpose, the functionality and how to setup the example 20 | -------------------------------------------------------------------------------- /async-service-task/src/test/java/com/camunda/consulting/AsyncJobWorkerTest.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import static io.camunda.process.test.api.CamundaAssert.*; 4 | 5 | import io.camunda.process.test.api.CamundaSpringProcessTest; 6 | import io.camunda.zeebe.client.ZeebeClient; 7 | import io.camunda.zeebe.client.api.response.ProcessInstanceEvent; 8 | import java.time.Duration; 9 | import org.junit.jupiter.api.Test; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.boot.test.context.SpringBootTest; 12 | 13 | @CamundaSpringProcessTest 14 | @SpringBootTest 15 | public class AsyncJobWorkerTest { 16 | 17 | @Autowired ZeebeClient zeebeClient; 18 | 19 | @Test 20 | void shouldRun() { 21 | setAssertionTimeout(Duration.ofMinutes(2)); 22 | ProcessInstanceEvent process = 23 | zeebeClient 24 | .newCreateInstanceCommand() 25 | .bpmnProcessId("AsyncServiceTaskProcess") 26 | .latestVersion() 27 | .send() 28 | .join(); 29 | assertThat(process).isCompleted(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /task-micro-frontend/src/main/java/com/camunda/consulting/UpdateTaskDto.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import com.camunda.consulting.UpdateTaskDto.Data.AssignTaskDto; 4 | import com.camunda.consulting.UpdateTaskDto.Data.CompleteTaskDto; 5 | import com.fasterxml.jackson.annotation.JsonSubTypes; 6 | import com.fasterxml.jackson.annotation.JsonSubTypes.Type; 7 | import com.fasterxml.jackson.annotation.JsonTypeInfo; 8 | import com.fasterxml.jackson.annotation.JsonTypeInfo.As; 9 | import com.fasterxml.jackson.annotation.JsonTypeInfo.Id; 10 | import java.util.Map; 11 | 12 | public record UpdateTaskDto( 13 | @JsonTypeInfo(use = Id.NAME, property = "changeType", include = As.EXTERNAL_PROPERTY) 14 | @JsonSubTypes({ 15 | @Type(name = "complete", value = CompleteTaskDto.class), 16 | @Type(name = "assign", value = AssignTaskDto.class) 17 | }) 18 | Data data) { 19 | 20 | public sealed interface Data { 21 | record CompleteTaskDto(Map result) implements Data {} 22 | 23 | record AssignTaskDto(String assignee) implements Data {} 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /react-tasklist/src/main/frontend/src/app/page.js: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import dynamic from 'next/dynamic' 4 | import {useEffect, useState} from "react"; 5 | 6 | const Task = dynamic( 7 | () => import('./components/task'), 8 | {ssr: false} 9 | ) 10 | 11 | export default function Home() { 12 | const [tasks, setTasks] = useState(); 13 | const startProcess = () => fetch("/api/start-process", { 14 | method: "POST", 15 | body: JSON.stringify({foo: "bar"}), 16 | headers: {"Content-Type": "application/json"} 17 | }).then(r => r.status >= 200 && r.status < 400 ? alert("Process started") : alert(`Error while starting process: ${r.statusText}`)) 18 | 19 | useEffect(() => { 20 | fetch(`/api/tasks`).then(r => r.json()).then(json => { 21 | setTasks(json); 22 | }); 23 | }, []); 24 | const taskList = (tasks || []).map(task => ) 25 | return ( 26 |

27 | 28 |

Tasklist

29 | {taskList} 30 |
31 | ) 32 | } 33 | -------------------------------------------------------------------------------- /twitter-review-java-springboot/src/main/java/org/camunda/community/examples/twitter/process/TwitterProcessVariables.java: -------------------------------------------------------------------------------- 1 | package org.camunda.community.examples.twitter.process; 2 | 3 | public class TwitterProcessVariables { 4 | 5 | private String tweet; 6 | private String author; 7 | private String boss; 8 | private boolean approved; 9 | 10 | public String getTweet() { 11 | return tweet; 12 | } 13 | 14 | public TwitterProcessVariables setTweet(String tweet) { 15 | this.tweet = tweet; 16 | return this; 17 | } 18 | 19 | public String getAuthor() { 20 | return author; 21 | } 22 | 23 | public TwitterProcessVariables setAuthor(String author) { 24 | this.author = author; 25 | return this; 26 | } 27 | 28 | public String getBoss() { 29 | return boss; 30 | } 31 | 32 | public TwitterProcessVariables setBoss(String boss) { 33 | this.boss = boss; 34 | return this; 35 | } 36 | 37 | public boolean isApproved() { 38 | return approved; 39 | } 40 | 41 | public TwitterProcessVariables setApproved(boolean approved) { 42 | this.approved = approved; 43 | return this; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /parallel-operations/src/main/java/com/camunda/consulting/ProcessController.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import io.camunda.zeebe.client.ZeebeClient; 4 | import io.camunda.zeebe.client.api.response.ProcessInstanceEvent; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.PostMapping; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | @RestController 11 | @RequestMapping("/process") 12 | public class ProcessController { 13 | @Autowired ZeebeClient zeebeClient; 14 | 15 | @PostMapping 16 | public ProcessInstanceStartedResponse startProcessInstance() { 17 | ProcessInstanceEvent process = 18 | zeebeClient 19 | .newCreateInstanceCommand() 20 | .bpmnProcessId("MigratedProcessProcess") 21 | .latestVersion() 22 | .send() 23 | .join(); 24 | return new ProcessInstanceStartedResponse(process.getProcessInstanceKey()); 25 | } 26 | 27 | public record ProcessInstanceStartedResponse(Long processInstanceKey) {} 28 | } 29 | -------------------------------------------------------------------------------- /secret-provider-as-credentials-provider/src/main/java/com/camunda/consulting/BearerTokenProviderRegistry.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import java.util.Set; 4 | import org.springframework.stereotype.Component; 5 | 6 | /** 7 | * This component collects all instances of {@link BearerTokenProvider}. 8 | * 9 | *

In this example, only {@link ZeebeBearerTokenProvider} exists. 10 | * 11 | *

You can create your own beans of type {@link BearerTokenProvider} and they will be 12 | * automatically added here. 13 | */ 14 | @Component 15 | public class BearerTokenProviderRegistry { 16 | private final Set bearerTokenProviders; 17 | 18 | public BearerTokenProviderRegistry(Set bearerTokenProviders) { 19 | this.bearerTokenProviders = bearerTokenProviders; 20 | } 21 | 22 | public String getBearerTokenForService(String serviceName) { 23 | return bearerTokenProviders.stream() 24 | .filter(bearerTokenProvider -> bearerTokenProvider.getServiceName().equals(serviceName)) 25 | .findFirst() 26 | .map(BearerTokenProvider::getBearerToken) 27 | .orElse(null); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /payment-example-process-application/complete-usertasks/complete-user-tasks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Get the token" 4 | TOKEN=$(curl -s --location --request POST 'http://localhost:18080/auth/realms/camunda-platform/protocol/openid-connect/token' \ 5 | --header 'Content-Type: application/x-www-form-urlencoded' \ 6 | --data-urlencode 'client_id=payment-app' \ 7 | --data-urlencode "client_secret=$CLIENT_SECRET" \ 8 | --data-urlencode 'grant_type=client_credentials' | jq -r .access_token) 9 | 10 | echo "Get the task list" 11 | IDLIST=$(curl -s -X POST \ 12 | -H "Content-Type: application/json" \ 13 | -H "Authorization: Bearer $TOKEN" \ 14 | -d '{"state":"CREATED","sort":[{"field": "creationTime", "order": "ASC"}], "pageSize":200}' \ 15 | 'http://localhost:8082/v1/tasks/search' | jq -r '.[].id') 16 | 17 | echo -n "Number of tasks to complete: " 18 | printf '%s' "$IDLIST" | jq -Rsc 'split("\n") | map(select(length>0)) | length' 19 | 20 | echo "Complete the tasks" 21 | while ID= read -r item; do 22 | curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" -d '{"variables": {"errorResolved": false}}' "http://localhost:8088/v2/user-tasks/$item/completion"; 23 | done <<< "$IDLIST" 24 | -------------------------------------------------------------------------------- /react-tasklist/src/main/java/com/camunda/consulting/tasklist/StartProcessController.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.tasklist; 2 | 3 | import java.util.Map; 4 | import org.springframework.beans.factory.annotation.Qualifier; 5 | import org.springframework.http.ResponseEntity; 6 | import org.springframework.web.bind.annotation.PostMapping; 7 | import org.springframework.web.bind.annotation.RequestBody; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | import org.springframework.web.client.RestTemplate; 11 | 12 | @RestController 13 | @RequestMapping("/api") 14 | public class StartProcessController { 15 | private final RestTemplate camundaWebhookClient; 16 | 17 | public StartProcessController( 18 | @Qualifier("camundaWebhookClient") RestTemplate camundaWebhookClient) { 19 | this.camundaWebhookClient = camundaWebhookClient; 20 | } 21 | 22 | @PostMapping("/start-process") 23 | public ResponseEntity startProcess(@RequestBody Map body) { 24 | camundaWebhookClient.postForEntity("/startTheProcess", body, Void.class); 25 | return ResponseEntity.status(204).build(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /camunda-client-plain-java/src/main/java/io/camunda/example/process/ProcessInstanceCreator.java: -------------------------------------------------------------------------------- 1 | package io.camunda.example.process; 2 | 3 | import io.camunda.client.CamundaClient; 4 | import io.camunda.client.api.response.ProcessInstanceEvent; 5 | import io.camunda.example.ClientProvider; 6 | import io.camunda.example.ClientProvider.AuthMethod; 7 | 8 | /** 9 | * Example application that connects to a cluster on Camunda Cloud, or a locally deployed cluster. 10 | * 11 | *

It uses {@link ClientProvider} to create a client with the appropriate authentication method. 12 | */ 13 | public final class ProcessInstanceCreator { 14 | 15 | public static void main(final String[] args) { 16 | final String bpmnProcessId = "demoProcess"; 17 | 18 | try (final CamundaClient client = ClientProvider.createCamundaClient(AuthMethod.none)) { 19 | 20 | System.out.println("Creating process instance"); 21 | 22 | final ProcessInstanceEvent processInstanceEvent = 23 | client.newCreateInstanceCommand().bpmnProcessId(bpmnProcessId).latestVersion().execute(); 24 | 25 | System.out.println( 26 | "Process instance created with key: " + processInstanceEvent.getProcessInstanceKey()); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /secret-provider-as-credentials-provider/src/test/java/com/camunda/consulting/BearerTokenSecretProviderTest.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import static org.junit.jupiter.api.Assertions.*; 4 | 5 | import java.util.Collections; 6 | import org.junit.jupiter.api.Test; 7 | 8 | public class BearerTokenSecretProviderTest { 9 | @Test 10 | void shouldFindSecret() { 11 | BearerTokenSecretProvider provider = 12 | new BearerTokenSecretProvider( 13 | new BearerTokenProviderRegistry(Collections.singleton(new Peter()))); 14 | String secret = provider.getSecret("bearerToken(peter)"); 15 | assertEquals("hase", secret); 16 | } 17 | 18 | @Test 19 | void shouldNotFindSecret() { 20 | BearerTokenSecretProvider provider = 21 | new BearerTokenSecretProvider( 22 | new BearerTokenProviderRegistry(Collections.singleton(new Peter()))); 23 | String secret = provider.getSecret("bearerToken(hase)"); 24 | assertNull(secret); 25 | } 26 | 27 | static class Peter implements BearerTokenProvider { 28 | @Override 29 | public String getBearerToken() { 30 | return "hase"; 31 | } 32 | 33 | @Override 34 | public String getServiceName() { 35 | return "peter"; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /react-tasklist/src/main/frontend/src/app/components/camunda-form.js: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import {useEffect, useRef} from "react"; 4 | import {Form} from '@bpmn-io/form-js-viewer'; 5 | 6 | export default function CamundaFormContainer({schema, data, onComplete}) { 7 | const submit = () => form.current.submit() 8 | const formContainer = useRef(); 9 | const form = useRef(); 10 | const containsSubmit = schema && schema.components && schema.components.some(comp => comp.type === 'button' && comp.action === 'submit'); 11 | 12 | useEffect( () => { 13 | form.current = new Form({ 14 | container: formContainer.current 15 | }); 16 | 17 | form.current.importSchema(schema, data); 18 | form.current.on('submit', (event) => { 19 | onComplete(event.data); 20 | }); 21 | }, []); 22 | 23 | 24 | return ( 25 | <> 26 | 28 | 29 |

30 | {containsSubmit ? (<> 31 | ) : () 32 | } 33 | 34 | 35 | ) 36 | } -------------------------------------------------------------------------------- /weatherinfo-pyzeebe-connectors/README.md: -------------------------------------------------------------------------------- 1 | # Pyzeebe & Connectors Example 2 | 3 | This project contains 4 | * a process 5 | * receiving user input 6 | * calling openweathermap via the REST connector 7 | * calling a worker for looking up a suited activity for the given weather (via custom template) 8 | * sending an email to the user via the Send Grid Connector 9 | * a form for the user input 10 | * a worker written in Python, using the [pyzeebe](https://github.com/camunda-community-hub/pyzeebe) client 11 | * a custom template for the worker 12 | 13 | This example can be used most easily in [Camunda 8 SaaS](https://console.cloud.camunda.io) with the WebModeler and Connectors provided. 14 | 15 | Upload the process model to the web modeler and deploy it to your cluster. Process instances can be started from the Web Modeler. 16 | 17 | To run the project, you have to add your personal configuration: 18 | 1. Replace the Camunda SaaS credentials in `pyzeebeWorker.py` to match your cluster. 19 | 2. Add API keys for Openweathermap and Send Grid as secrets to your cluster. Read more about it in the [documentation](https://docs.camunda.io/docs/components/console/manage-clusters/manage-secrets/) 20 | * OWM_API_KEY holds the API key for Openweathermap 21 | * SEND_GRID_API_KEY holds the API key for Send Grid -------------------------------------------------------------------------------- /weatherinfo-pyzeebe-connectors/src/pyzeebeWorker.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from pyzeebe import ZeebeWorker, create_camunda_cloud_channel 3 | from activities import rainActivities, sunnyActivities 4 | 5 | # main function called by the program 6 | async def main(): 7 | # create a channel to Camunda 8 SaaS 8 | channel = create_camunda_cloud_channel( 9 | client_id= "u2Ss0Xzidrjt~FZExzBYvoB5loL50LnJ", 10 | client_secret="b.aQM5OF40HqpD1sf80h_gDfGmnUo1356Ua_2hKWwqnd405-J5xpp5scCFzNqx5u", 11 | cluster_id= "8f2a53cb-87a7-4992-a17b-940625fa3882", 12 | region="bru-2", 13 | ) # connect to your cloud instance 14 | 15 | # Create a worker object to register your workers 16 | worker = ZeebeWorker(channel) 17 | 18 | # Create a worker for task type "activity-lookup" 19 | @worker.task(task_type="activitiy-lookup") 20 | def lookup_activities(location, weather) -> dict: # parameters are matched to process variables 21 | print(f"The weather at {location} is {weather}") 22 | if weather == "Rain" or weather == "Snow": 23 | return {"activity": rainActivities[location]} 24 | return {"activity": sunnyActivities[location]} 25 | 26 | await worker.work() # start the workers 27 | 28 | 29 | asyncio.run(main()) -------------------------------------------------------------------------------- /payment-example-process-application/src/test/java/com/camunda/consulting/web_shop_process_app/test/WorkerTest.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.web_shop_process_app.test; 2 | 3 | import static org.assertj.core.api.Assertions.*; 4 | import static org.mockito.BDDMockito.*; 5 | 6 | import com.camunda.consulting.web_shop_process_app.service.CustomerService; 7 | import com.camunda.consulting.web_shop_process_app.worker.CustomerCreditHandler; 8 | import io.camunda.zeebe.client.api.response.ActivatedJob; 9 | import java.util.Map; 10 | import org.junit.jupiter.api.Test; 11 | import org.junit.jupiter.api.extension.ExtendWith; 12 | import org.mockito.Mock; 13 | import org.mockito.junit.jupiter.MockitoExtension; 14 | 15 | @ExtendWith(MockitoExtension.class) 16 | public class WorkerTest { 17 | 18 | @Mock(stubOnly = true) 19 | ActivatedJob mockedJob; 20 | 21 | @Test 22 | public void testCustomerCreditWorker() { 23 | given(mockedJob.getVariablesAsMap()) 24 | .willReturn(Map.of("customerId", "testCustomer40", "orderTotal", 75.0)); 25 | CustomerCreditHandler customerCreditHandler = new CustomerCreditHandler(new CustomerService()); 26 | 27 | Map variables = customerCreditHandler.handle(mockedJob); 28 | assertThat(variables).contains(entry("remainingAmount", 35.0)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /rollback-on-error-example/src/main/java/com/camunda/consulting/ExampleApplication.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import io.camunda.client.annotation.Deployment; 4 | import io.camunda.client.annotation.JobWorker; 5 | import io.camunda.client.annotation.Variable; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.boot.SpringApplication; 9 | import org.springframework.boot.autoconfigure.SpringBootApplication; 10 | 11 | @SpringBootApplication 12 | @Deployment(resources = "classpath*:*.bpmn") 13 | public class ExampleApplication { 14 | private static final Logger LOG = LoggerFactory.getLogger(ExampleApplication.class); 15 | 16 | public static void main(String[] args) { 17 | SpringApplication.run(ExampleApplication.class, args); 18 | } 19 | 20 | @JobWorker 21 | public void validateDataType(@Variable Boolean validationFails) { 22 | LOG.info("Validating data"); 23 | if (validationFails != null && validationFails) { 24 | throw new RuntimeException("Validation failed"); 25 | } 26 | } 27 | 28 | @JobWorker 29 | public void saveDataType(@Variable Boolean savingFails) { 30 | LOG.info("Saving data"); 31 | if (savingFails != null && savingFails) { 32 | throw new RuntimeException("Saving failed"); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /camunda-client-plain-java/src/main/java/io/camunda/example/decision/EvaluateDecisionCreator.java: -------------------------------------------------------------------------------- 1 | package io.camunda.example.decision; 2 | 3 | import io.camunda.client.CamundaClient; 4 | import io.camunda.client.api.response.EvaluateDecisionResponse; 5 | import io.camunda.example.ClientProvider; 6 | import io.camunda.example.ClientProvider.AuthMethod; 7 | 8 | /** 9 | * Example application that connects to a cluster on Camunda Cloud, or a locally deployed cluster. 10 | * 11 | *

It uses {@link ClientProvider} to create a client with the appropriate authentication method. 12 | */ 13 | public final class EvaluateDecisionCreator { 14 | 15 | public static void main(final String[] args) { 16 | final String decisionId = "demoDecision_jedi_or_sith"; 17 | 18 | try (final CamundaClient client = ClientProvider.createCamundaClient(AuthMethod.none)) { 19 | 20 | System.out.println("Evaluating decision"); 21 | 22 | final EvaluateDecisionResponse decisionEvaluation = 23 | client 24 | .newEvaluateDecisionCommand() 25 | .decisionId(decisionId) 26 | .variables("{\"lightsaberColor\": \"blue\"}") 27 | .execute(); 28 | 29 | System.out.println("Decision evaluation result: " + decisionEvaluation.getDecisionOutput()); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /large-multi-instance-example/src/test/java/com/camunda/consulting/SimpleMultiInstanceTest.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import static io.camunda.process.test.api.CamundaAssert.*; 4 | 5 | import io.camunda.process.test.api.CamundaSpringProcessTest; 6 | import io.camunda.zeebe.client.ZeebeClient; 7 | import io.camunda.zeebe.client.api.response.ProcessInstanceEvent; 8 | import java.util.List; 9 | import org.junit.jupiter.api.Test; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.boot.test.context.SpringBootTest; 14 | 15 | @SpringBootTest 16 | @CamundaSpringProcessTest 17 | public class SimpleMultiInstanceTest { 18 | 19 | private static final Logger LOG = LoggerFactory.getLogger(SimpleMultiInstanceTest.class); 20 | 21 | @Autowired ZeebeClient client; 22 | 23 | @Test 24 | public void runCallActivity() { 25 | LOG.info("Call activity"); 26 | ProcessInstanceEvent processInstance = 27 | client 28 | .newCreateInstanceCommand() 29 | .bpmnProcessId("MICallActivityProcess") 30 | .latestVersion() 31 | .send() 32 | .join(); 33 | 34 | assertThat(processInstance).hasVariable("resultList", List.of(65, 66, 67)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /payment-example-process-application/src/main/java/com/camunda/consulting/web_shop_process_app/rest/StartFormRestController.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.web_shop_process_app.rest; 2 | 3 | import io.camunda.zeebe.client.ZeebeClient; 4 | import java.util.Map; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.web.bind.annotation.PostMapping; 9 | import org.springframework.web.bind.annotation.RequestBody; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | @RestController 14 | @RequestMapping("/") 15 | public class StartFormRestController { 16 | private static final Logger LOG = LoggerFactory.getLogger(StartFormRestController.class); 17 | 18 | @Autowired private ZeebeClient zeebe; 19 | 20 | @PostMapping("/start") 21 | public void startProcessInstance(@RequestBody Map variables) { 22 | 23 | LOG.info("Starting process `paymentProcess` with variables: " + variables); 24 | 25 | zeebe 26 | .newCreateInstanceCommand() 27 | .bpmnProcessId("paymentProcess") 28 | .latestVersion() 29 | .variables(variables) 30 | .send() 31 | .join(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /react-tasklist/src/main/java/com/camunda/consulting/tasklist/configuration/CamundaWebhookClientConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.tasklist.configuration; 2 | 3 | import com.camunda.consulting.tasklist.CamundaWebhookProperties; 4 | import org.springframework.beans.factory.annotation.Qualifier; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.http.client.support.BasicAuthenticationInterceptor; 8 | import org.springframework.web.client.RestTemplate; 9 | import org.springframework.web.util.DefaultUriBuilderFactory; 10 | 11 | @Configuration 12 | public class CamundaWebhookClientConfiguration { 13 | @Bean 14 | @Qualifier("camundaWebhookClient") 15 | public RestTemplate camundaWebhookClient(CamundaWebhookProperties properties) { 16 | var camundaWebhookClient = new RestTemplate(); 17 | var uriTemplateHandler = new DefaultUriBuilderFactory(properties.url()); 18 | camundaWebhookClient 19 | .getInterceptors() 20 | .add( 21 | new BasicAuthenticationInterceptor( 22 | properties.authorization().username(), properties.authorization().password())); 23 | camundaWebhookClient.setUriTemplateHandler(uriTemplateHandler); 24 | return camundaWebhookClient; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /camunda-client-plain-java/src/main/java/io/camunda/example/cluster/TopologyViewer.java: -------------------------------------------------------------------------------- 1 | package io.camunda.example.cluster; 2 | 3 | import io.camunda.client.CamundaClient; 4 | import io.camunda.client.api.response.Topology; 5 | import io.camunda.example.ClientProvider; 6 | import io.camunda.example.ClientProvider.AuthMethod; 7 | 8 | /** 9 | * Example application that connects to a cluster on Camunda Cloud, or a locally deployed cluster. 10 | * 11 | *

It uses {@link ClientProvider} to create a client with the appropriate authentication method. 12 | */ 13 | public final class TopologyViewer { 14 | 15 | public static void main(final String[] args) { 16 | try (final CamundaClient client = ClientProvider.createCamundaClient(AuthMethod.none)) { 17 | final Topology topology = client.newTopologyRequest().execute(); 18 | 19 | System.out.println("Topology:"); 20 | topology 21 | .getBrokers() 22 | .forEach( 23 | b -> { 24 | System.out.println(" " + b.getAddress()); 25 | b.getPartitions() 26 | .forEach( 27 | p -> 28 | System.out.println( 29 | " " + p.getPartitionId() + " - " + p.getRole())); 30 | }); 31 | 32 | System.out.println("Done."); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /react-tasklist/src/main/frontend/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /twitter-review-java-springboot/src/main/java/org/camunda/community/examples/twitter/business/TwitterServiceImpl.java: -------------------------------------------------------------------------------- 1 | package org.camunda.community.examples.twitter.business; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | /** 6 | * Publish content on Twitter. It really goes live! Watch out http://twitter.com/#!/camunda_demo for 7 | * your postings. 8 | */ 9 | @Component 10 | public class TwitterServiceImpl implements TwitterService { 11 | 12 | // private Twitter twitter; 13 | 14 | public TwitterServiceImpl() { 15 | // AccessToken accessToken = new 16 | // AccessToken("220324559-jet1dkzhSOeDWdaclI48z5txJRFLCnLOK45qStvo", 17 | // "B28Ze8VDucBdiE38aVQqTxOyPc7eHunxBVv7XgGim4say"); 18 | // twitter = new TwitterFactory().getInstance(); 19 | // twitter.setOAuthConsumer("lRhS80iIXXQtm6LM03awjvrvk", 20 | // "gabtxwW8lnSL9yQUNdzAfgBOgIMSRqh7MegQs79GlKVWF36qLS"); 21 | // twitter.setOAuthAccessToken(accessToken); 22 | } 23 | 24 | @Override 25 | public void tweet(String content) throws DuplicateTweetException { 26 | System.out.println(" PRODUCTION TWEET: " + content); 27 | /*try { 28 | twitter.updateStatus(content); 29 | } catch (TwitterException e) { 30 | if (e.getErrorCode() == 187) { 31 | throw new DuplicateTweetException(); 32 | } else { 33 | throw new RuntimeException(e); 34 | } 35 | }*/ 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /react-tasklist/src/main/frontend/src/app/components/task.js: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import dynamic from 'next/dynamic' 4 | import {useEffect, useState} from "react"; 5 | 6 | const CamundaForm = dynamic( 7 | () => import('./camunda-form'), 8 | {ssr: false} 9 | ) 10 | const ReactForm = dynamic( 11 | () => import('./react-form'), 12 | {ssr: false} 13 | ) 14 | 15 | export default function Task({taskId}) { 16 | const [task, setTask] = useState(); 17 | const completeTask = (data) => { 18 | console.log(data); 19 | fetch(`/api/tasks/${taskId}/complete`, {method: "PATCH", body: JSON.stringify(data), headers: {"Content-Type":"application/json"}}).then(r => r.status >=200 && r.status<400 ? alert("Task completed"):alert(`Error while completing the task: ${r.statusText}`)) 20 | } 21 | useEffect(() => { 22 | fetch(`/api/tasks/${taskId}`).then(r => r.json()).then(json => { 23 | setTask(json); 24 | }); 25 | }, []); 26 | 27 | 28 | return ( 29 | <> 30 | {task ? ( 31 | <> 32 |

{task.name}

{ 33 | task.schema ? ( 34 | ) : ( 35 | )} 36 | 37 | ) : (

Loading...

)} 38 | 39 | ) 40 | } -------------------------------------------------------------------------------- /timer-testing/src/main/java/com/camunda/consulting/ExampleApplication.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import io.camunda.zeebe.spring.client.annotation.Deployment; 4 | import io.camunda.zeebe.spring.client.annotation.JobWorker; 5 | import io.camunda.zeebe.spring.client.annotation.Variable; 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.Random; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | import org.springframework.boot.SpringApplication; 12 | import org.springframework.boot.autoconfigure.SpringBootApplication; 13 | 14 | @SpringBootApplication 15 | @Deployment(resources = "classpath*:**/*.bpmn") 16 | public class ExampleApplication { 17 | private static final Logger LOG = LoggerFactory.getLogger(ExampleApplication.class); 18 | public static String progressOverride; 19 | 20 | public static void main(String[] args) { 21 | SpringApplication.run(ExampleApplication.class, args); 22 | } 23 | 24 | @JobWorker 25 | public void callKids(@Variable String message) { 26 | LOG.info("Message: '{}'", message); 27 | } 28 | 29 | @JobWorker 30 | public Map checkProgress(@Variable List options) { 31 | String progress = 32 | progressOverride != null 33 | ? progressOverride 34 | : options.get(new Random().nextInt(options.size())); 35 | return Map.of("progress", progress); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /timer-testing/src/main/java/com/camunda/consulting/rest/ExampleRestApi.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.rest; 2 | 3 | import io.camunda.zeebe.client.ZeebeClient; 4 | import io.camunda.zeebe.client.api.response.ProcessInstanceEvent; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.http.HttpStatus; 9 | import org.springframework.http.ResponseEntity; 10 | import org.springframework.web.bind.annotation.PostMapping; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | @RestController 14 | public class ExampleRestApi { 15 | 16 | private static final Logger LOG = LoggerFactory.getLogger(ExampleRestApi.class); 17 | 18 | private final ZeebeClient zeebeClient; 19 | 20 | @Autowired 21 | public ExampleRestApi(ZeebeClient zeebeClient) { 22 | this.zeebeClient = zeebeClient; 23 | } 24 | 25 | @PostMapping("/start-example") 26 | public ResponseEntity startExampleProcess() { 27 | ProcessInstanceEvent processInstanceEvent = 28 | zeebeClient 29 | .newCreateInstanceCommand() 30 | .bpmnProcessId("GetUpProcess") 31 | .latestVersion() 32 | .send() 33 | .join(); 34 | 35 | return ResponseEntity.status(HttpStatus.OK) 36 | .body("Started: " + processInstanceEvent.getProcessInstanceKey()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /twitter-review-java-springboot/src/main/java/org/camunda/community/examples/twitter/process/TwitterWorker.java: -------------------------------------------------------------------------------- 1 | package org.camunda.community.examples.twitter.process; 2 | 3 | import io.camunda.zeebe.spring.client.annotation.JobWorker; 4 | import io.camunda.zeebe.spring.client.annotation.VariablesAsType; 5 | import io.camunda.zeebe.spring.common.exception.ZeebeBpmnError; 6 | import java.util.Map; 7 | import org.camunda.community.examples.twitter.business.DuplicateTweetException; 8 | import org.camunda.community.examples.twitter.business.TwitterService; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.stereotype.Component; 11 | 12 | @Component 13 | public class TwitterWorker { 14 | 15 | @Autowired private TwitterService twitterService; 16 | 17 | @JobWorker(type = "publish-tweet") 18 | public void handleTweet(@VariablesAsType TwitterProcessVariables variables) throws Exception { 19 | try { 20 | twitterService.tweet(variables.getTweet()); 21 | } catch (DuplicateTweetException ex) { 22 | throw new ZeebeBpmnError( 23 | "duplicateMessage", "Could not post tweet, it is a duplicate.", Map.of()); 24 | } 25 | } 26 | 27 | @JobWorker(type = "send-rejection") 28 | public void sendRejection(@VariablesAsType TwitterProcessVariables variables) throws Exception { 29 | // same thing as above, do data transformation and delegate to real business code / service 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /large-multi-instance-example/src/main/java/com/camunda/consulting/rest/ExampleRestApi.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.rest; 2 | 3 | import io.camunda.zeebe.client.ZeebeClient; 4 | import io.camunda.zeebe.client.api.response.ProcessInstanceEvent; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.http.HttpStatus; 9 | import org.springframework.http.ResponseEntity; 10 | import org.springframework.web.bind.annotation.PostMapping; 11 | import org.springframework.web.bind.annotation.RequestBody; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | @RestController 15 | public class ExampleRestApi { 16 | 17 | private static final Logger LOG = LoggerFactory.getLogger(ExampleRestApi.class); 18 | 19 | @Autowired ZeebeClient client; 20 | 21 | @PostMapping("/start-example") 22 | public ResponseEntity startExampleProcess(@RequestBody String businessKey) { 23 | LOG.info("starting process with businessKey: {}", businessKey); 24 | ProcessInstanceEvent processInstanceEvent = 25 | client 26 | .newCreateInstanceCommand() 27 | .bpmnProcessId("campaignProcess") 28 | .latestVersion() 29 | .variables(businessKey) 30 | .send() 31 | .join(); 32 | 33 | return ResponseEntity.status(HttpStatus.OK) 34 | .body("Started: " + processInstanceEvent.getProcessInstanceKey()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /rollback-on-error-example/src/main/java/com/camunda/consulting/UserTaskController.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import com.fasterxml.jackson.databind.node.ObjectNode; 4 | import java.util.List; 5 | import org.apache.commons.lang3.exception.ExceptionUtils; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.PathVariable; 9 | import org.springframework.web.bind.annotation.PostMapping; 10 | import org.springframework.web.bind.annotation.RequestBody; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | @RestController 15 | @RequestMapping("/task") 16 | public class UserTaskController { 17 | private final UserTaskService service; 18 | 19 | public UserTaskController(UserTaskService service) { 20 | this.service = service; 21 | } 22 | 23 | @GetMapping 24 | public ResponseEntity> getTasks() { 25 | return ResponseEntity.ok(service.getUserTasks()); 26 | } 27 | 28 | @PostMapping("/{key}/complete") 29 | public ResponseEntity completeTask( 30 | @PathVariable("key") Long key, @RequestBody ObjectNode variables) { 31 | try { 32 | service.complete(key, variables); 33 | return ResponseEntity.ok().build(); 34 | } catch (Exception e) { 35 | return ResponseEntity.internalServerError().body(ExceptionUtils.getStackTrace(e)); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /zeebe-client-plain-java/src/main/java/io/camunda/zeebe/example/process/ProcessDeployer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under 3 | * one or more contributor license agreements. See the NOTICE file distributed 4 | * with this work for additional information regarding copyright ownership. 5 | * Licensed under the Zeebe Community License 1.1. You may not use this file 6 | * except in compliance with the Zeebe Community License 1.1. 7 | */ 8 | package io.camunda.zeebe.example.process; 9 | 10 | import io.camunda.zeebe.client.ZeebeClient; 11 | import io.camunda.zeebe.client.api.response.DeploymentEvent; 12 | import io.camunda.zeebe.example.ClientProvider; 13 | import io.camunda.zeebe.example.ClientProvider.AuthMethod; 14 | 15 | /** 16 | * Example application that connects to a cluster on Camunda Cloud, or a locally deployed cluster. 17 | * 18 | *

It uses {@link ClientProvider} to create a client with the appropriate authentication method. 19 | */ 20 | public final class ProcessDeployer { 21 | 22 | public static void main(final String[] args) { 23 | try (final ZeebeClient client = ClientProvider.createZeebeClient(AuthMethod.none)) { 24 | 25 | final DeploymentEvent deploymentEvent = 26 | client 27 | .newDeployResourceCommand() 28 | .addResourceFromClasspath("demoProcess.bpmn") 29 | .send() 30 | .join(); 31 | 32 | System.out.println("Deployment created with key: " + deploymentEvent.getKey()); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /react-tasklist/src/main/frontend/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | # or 14 | bun dev 15 | ``` 16 | 17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 18 | 19 | You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file. 20 | 21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 22 | 23 | ## Learn More 24 | 25 | To learn more about Next.js, take a look at the following resources: 26 | 27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 29 | 30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 31 | 32 | ## Deploy on Vercel 33 | 34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 35 | 36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 37 | -------------------------------------------------------------------------------- /large-multi-instance-example/src/test/java/com/camunda/consulting/MultiInstanceTest.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import static io.camunda.process.test.api.CamundaAssert.*; 4 | 5 | import io.camunda.process.test.api.CamundaSpringProcessTest; 6 | import io.camunda.zeebe.client.ZeebeClient; 7 | import io.camunda.zeebe.client.api.response.ProcessInstanceEvent; 8 | import java.util.Map; 9 | import org.junit.jupiter.api.Test; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.boot.test.context.SpringBootTest; 12 | 13 | @SpringBootTest 14 | @CamundaSpringProcessTest 15 | public class MultiInstanceTest { 16 | 17 | @Autowired ZeebeClient client; 18 | 19 | @Test 20 | public void testCampaignProcess() { 21 | runProcessAndTestCompleted("CampaignProcess", "2"); 22 | } 23 | 24 | @Test 25 | public void testLargeCampaignProcess() { 26 | runProcessAndTestCompleted("LargeCampaignProcess", "3"); 27 | } 28 | 29 | @Test 30 | public void testHugeCampaignWithFewElements() { 31 | runProcessAndTestCompleted("HugeCampaignProcess", "1"); 32 | } 33 | 34 | protected void runProcessAndTestCompleted(String processId, String campaignId) { 35 | ProcessInstanceEvent processInstance = 36 | client 37 | .newCreateInstanceCommand() 38 | .bpmnProcessId(processId) 39 | .latestVersion() 40 | .variables(Map.of("campaignId", campaignId)) 41 | .send() 42 | .join(); 43 | assertThat(processInstance).isCompleted(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /payment-example-process-application/src/main/java/com/camunda/consulting/web_shop_process_app/worker/CustomerCreditHandler.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.web_shop_process_app.worker; 2 | 3 | import com.camunda.consulting.web_shop_process_app.service.CustomerService; 4 | import io.camunda.zeebe.client.api.response.ActivatedJob; 5 | import io.camunda.zeebe.spring.client.annotation.JobWorker; 6 | import java.util.Map; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.stereotype.Component; 10 | 11 | @Component 12 | public class CustomerCreditHandler { 13 | 14 | private static final Logger LOG = LoggerFactory.getLogger(CustomerCreditHandler.class); 15 | 16 | private final CustomerService customerService; 17 | 18 | public CustomerCreditHandler(CustomerService customerService) { 19 | this.customerService = customerService; 20 | } 21 | 22 | @JobWorker(type = "customerCreditHandling") 23 | public Map handle(ActivatedJob job) { 24 | LOG.info("Handling customer credit for process instance {}", job.getProcessInstanceKey()); 25 | 26 | Map variables = job.getVariablesAsMap(); 27 | String customerId = (String) variables.get("customerId"); 28 | Double amount = Double.valueOf(variables.get("orderTotal").toString()); 29 | 30 | Double customerCredit = customerService.getCustomerCredit(customerId); 31 | Double remainingAmount = customerService.deductCredit(customerId, amount, customerCredit); 32 | 33 | return Map.of("customerCredit", customerCredit, "remainingAmount", remainingAmount); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /element-template-generation/src/test/java/com/camunda/consulting/CarConnectorTest.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import static org.assertj.core.api.Assertions.*; 4 | 5 | import io.camunda.process.test.api.CamundaSpringProcessTest; 6 | import io.camunda.zeebe.client.ZeebeClient; 7 | import io.camunda.zeebe.client.api.response.ProcessInstanceResult; 8 | import org.junit.jupiter.api.BeforeEach; 9 | import org.junit.jupiter.api.Test; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.boot.test.context.SpringBootTest; 12 | 13 | @CamundaSpringProcessTest 14 | @SpringBootTest( 15 | properties = { 16 | "camunda.connector.webhook.enabled=false", 17 | "camunda.connector.polling.enabled=false", 18 | "operate.client.enabled=false" 19 | }) 20 | public class CarConnectorTest { 21 | @Autowired ZeebeClient zeebeClient; 22 | 23 | @BeforeEach 24 | void setup() { 25 | zeebeClient.newDeployResourceCommand().addResourceFromClasspath("test.bpmn").send().join(); 26 | } 27 | 28 | @Test 29 | void shouldRun() { 30 | ProcessInstanceResult result = 31 | zeebeClient 32 | .newCreateInstanceCommand() 33 | .bpmnProcessId("test") 34 | .latestVersion() 35 | .withResult() 36 | .send() 37 | .join(); 38 | CarConnectorOutput output = result.getVariablesAsType(ResultType.class).car(); 39 | assertThat(output.make()).isEqualTo("Audi"); 40 | assertThat(output.model()).isEqualTo("A6"); 41 | assertThat(output.gearbox()).isEqualTo("Automatic"); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /task-micro-frontend/src/main/java/com/camunda/consulting/TaskController.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.core.io.ClassPathResource; 6 | import org.springframework.core.io.Resource; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.PatchMapping; 9 | import org.springframework.web.bind.annotation.PathVariable; 10 | import org.springframework.web.bind.annotation.RequestBody; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | @RestController 15 | @RequestMapping("/task") 16 | public class TaskController { 17 | private static final Logger LOG = LoggerFactory.getLogger(TaskController.class); 18 | private final TaskService taskService; 19 | 20 | public TaskController(TaskService taskService) { 21 | this.taskService = taskService; 22 | } 23 | 24 | @GetMapping(value = "/{id}", produces = "*/*") 25 | public Resource homePage(@PathVariable(name = "id") String id) { 26 | LOG.info("Loading task {}", id); 27 | return new ClassPathResource("index.html"); 28 | } 29 | 30 | @GetMapping(value = "/{id}", produces = "application/json") 31 | public TaskDto getTask(@PathVariable(name = "id") String id) { 32 | return taskService.getTask(id); 33 | } 34 | 35 | @PatchMapping(value = "/{id}") 36 | public void updateTask(@PathVariable(name = "id") String id, @RequestBody UpdateTaskDto request) { 37 | taskService.handleUpdate(id, request); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /large-multi-instance-example/src/main/java/com/camunda/consulting/worker/multi_instance/SimpleMultiInstanceWorker.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.worker.multi_instance; 2 | 3 | import io.camunda.zeebe.client.api.response.ActivatedJob; 4 | import io.camunda.zeebe.client.api.worker.JobClient; 5 | import io.camunda.zeebe.spring.client.annotation.JobWorker; 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | import org.springframework.stereotype.Component; 12 | 13 | @Component 14 | public class SimpleMultiInstanceWorker { 15 | 16 | private static final Logger LOG = LoggerFactory.getLogger(SimpleMultiInstanceWorker.class); 17 | 18 | @JobWorker 19 | public Map sequenceCreation(JobClient client, ActivatedJob job) { 20 | LOG.info("Create Sequence"); 21 | Map outputVars = new HashMap<>(); 22 | outputVars.put("sequence", List.of("A", "B", "C")); 23 | return outputVars; 24 | } 25 | 26 | @JobWorker 27 | public void resultLogging(JobClient client, ActivatedJob job) { 28 | Map inputVars = job.getVariablesAsMap(); 29 | LOG.info("All variables: {}", inputVars); 30 | } 31 | 32 | @JobWorker 33 | public Map elementCreation(JobClient client, ActivatedJob job) { 34 | Map inputVars = job.getVariablesAsMap(); 35 | LOG.info("Creating element: {}", inputVars); 36 | Map outputVars = new HashMap<>(); 37 | String element = (String) inputVars.get("element"); 38 | outputVars.put("result", (int) element.charAt(0)); 39 | return outputVars; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /extended-connector-runtime/README.md: -------------------------------------------------------------------------------- 1 | # Extended Connector Runtime 2 | 3 | As the connector runtime lies outside the engine, it can be adjusted. 4 | 5 | This example shows how a custom feel function can be introduced. 6 | 7 | This feel function can then be used on a connector runtime side feel expressions (for example result expression and error expression on outbound connectors). 8 | 9 | ## How this works 10 | 11 | As the connector runtime uses a standardized way to bootstrap the feel engine and this way includes using the SPI function provider, this can be used to extend the functions being used. 12 | 13 | The [SPI file](./src/main/resources/META-INF/services/org.camunda.feel.context.CustomFunctionProvider) points to the function provider that determines on how the function is loaded. 14 | 15 | The provider then resolves the function by its name. 16 | 17 | The function itself is instantiated and gets a static reference to a spring bean injected. This workaround is chosen as there is no way to access the SPI context from within spring. 18 | 19 | ## What kind of example is implemented here 20 | 21 | This example adds a function: 22 | 23 | ``` 24 | nextExecutionBackoff(backoff: days-time-duration): days-time-duration 25 | ``` 26 | 27 | This function then uses the `schedulingService` bean to determine the next timestamp where the execution could happen according to a defined schedule. 28 | 29 | ## How can I run it 30 | 31 | As the example comes as spring boot application containing the rest connector, you can configure the connection to camunda and start the application using 32 | 33 | ```bash 34 | mvn spring-boot:run 35 | ``` 36 | 37 | >Tip: Disable the default connectors coming with your Camunda 8 installation to test out this runtime. 38 | -------------------------------------------------------------------------------- /element-template-generation/src/main/java/com/camunda/consulting/CarConnectorInput.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import com.camunda.consulting.CarConnectorInput.Make.Audi; 4 | import com.camunda.consulting.CarConnectorInput.Make.Volkswagen; 5 | import com.fasterxml.jackson.annotation.JsonSubTypes; 6 | import com.fasterxml.jackson.annotation.JsonSubTypes.Type; 7 | import com.fasterxml.jackson.annotation.JsonTypeInfo; 8 | import com.fasterxml.jackson.annotation.JsonTypeInfo.Id; 9 | import io.camunda.connector.generator.java.annotation.TemplateSubType; 10 | import jakarta.validation.Valid; 11 | import jakarta.validation.constraints.NotNull; 12 | 13 | public record CarConnectorInput(@NotNull @Valid Make make, @NotNull Gearbox gearbox) { 14 | enum Gearbox { 15 | Manual, 16 | Automatic 17 | } 18 | 19 | @JsonTypeInfo(use = Id.NAME, property = "make") 20 | @JsonSubTypes({ 21 | @Type(value = Audi.class, name = "Audi_make"), 22 | @Type(value = Volkswagen.class, name = "Volkswagen_make") 23 | }) 24 | public sealed interface Make { 25 | @TemplateSubType(id = "Audi_make", label = "Audi") 26 | record Audi(@NotNull AudiModel audiModel) implements Make { 27 | enum AudiModel { 28 | A1, 29 | A3, 30 | A4, 31 | A5, 32 | A6, 33 | A7, 34 | A8 // no Q, because SUVs are s*** 35 | } 36 | } 37 | 38 | @TemplateSubType(id = "Volkswagen_make", label = "VW") 39 | record Volkswagen(@NotNull VolkswagenModel volkswagenModel) implements Make { 40 | enum VolkswagenModel { 41 | Polo, 42 | Golf, 43 | Golf_Variant, 44 | Jetta, 45 | Passat, 46 | Arteon, 47 | T7 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /zeebe-client-plain-java/src/main/java/io/camunda/zeebe/example/process/ProcessInstanceCreator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under 3 | * one or more contributor license agreements. See the NOTICE file distributed 4 | * with this work for additional information regarding copyright ownership. 5 | * Licensed under the Zeebe Community License 1.1. You may not use this file 6 | * except in compliance with the Zeebe Community License 1.1. 7 | */ 8 | package io.camunda.zeebe.example.process; 9 | 10 | import io.camunda.zeebe.client.ZeebeClient; 11 | import io.camunda.zeebe.client.api.response.ProcessInstanceEvent; 12 | import io.camunda.zeebe.example.ClientProvider; 13 | import io.camunda.zeebe.example.ClientProvider.AuthMethod; 14 | 15 | /** 16 | * Example application that connects to a cluster on Camunda Cloud, or a locally deployed cluster. 17 | * 18 | *

It uses {@link ClientProvider} to create a client with the appropriate authentication method. 19 | */ 20 | public final class ProcessInstanceCreator { 21 | 22 | public static void main(final String[] args) { 23 | final String bpmnProcessId = "demoProcess"; 24 | 25 | try (final ZeebeClient client = ClientProvider.createZeebeClient(AuthMethod.none)) { 26 | 27 | System.out.println("Creating process instance"); 28 | 29 | final ProcessInstanceEvent processInstanceEvent = 30 | client 31 | .newCreateInstanceCommand() 32 | .bpmnProcessId(bpmnProcessId) 33 | .latestVersion() 34 | .send() 35 | .join(); 36 | 37 | System.out.println( 38 | "Process instance created with key: " + processInstanceEvent.getProcessInstanceKey()); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /zeebe-client-plain-java/src/main/java/io/camunda/zeebe/example/decision/EvaluateDecisionCreator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under 3 | * one or more contributor license agreements. See the NOTICE file distributed 4 | * with this work for additional information regarding copyright ownership. 5 | * Licensed under the Zeebe Community License 1.1. You may not use this file 6 | * except in compliance with the Zeebe Community License 1.1. 7 | */ 8 | package io.camunda.zeebe.example.decision; 9 | 10 | import io.camunda.zeebe.client.ZeebeClient; 11 | import io.camunda.zeebe.client.api.response.EvaluateDecisionResponse; 12 | import io.camunda.zeebe.example.ClientProvider; 13 | import io.camunda.zeebe.example.ClientProvider.AuthMethod; 14 | 15 | /** 16 | * Example application that connects to a cluster on Camunda Cloud, or a locally deployed cluster. 17 | * 18 | *

It uses {@link ClientProvider} to create a client with the appropriate authentication method. 19 | */ 20 | public final class EvaluateDecisionCreator { 21 | 22 | public static void main(final String[] args) { 23 | final String decisionId = "demoDecision_jedi_or_sith"; 24 | 25 | try (final ZeebeClient client = ClientProvider.createZeebeClient(AuthMethod.none)) { 26 | 27 | System.out.println("Evaluating decision"); 28 | 29 | final EvaluateDecisionResponse decisionEvaluation = 30 | client 31 | .newEvaluateDecisionCommand() 32 | .decisionId(decisionId) 33 | .variables("{\"lightsaberColor\": \"blue\"}") 34 | .send() 35 | .join(); 36 | 37 | System.out.println("Decision evaluation result: " + decisionEvaluation.getDecisionOutput()); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /element-template-generation/src/main/java/com/camunda/consulting/CarConnector.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import com.camunda.consulting.CarConnectorInput.Make; 4 | import com.camunda.consulting.CarConnectorInput.Make.Audi; 5 | import com.camunda.consulting.CarConnectorInput.Make.Volkswagen; 6 | import io.camunda.connector.api.annotation.OutboundConnector; 7 | import io.camunda.connector.api.outbound.OutboundConnectorContext; 8 | import io.camunda.connector.api.outbound.OutboundConnectorFunction; 9 | import io.camunda.connector.generator.java.annotation.ElementTemplate; 10 | 11 | @OutboundConnector( 12 | name = "Car Connector", 13 | type = "com.camunda.consulting:carConnector:1", 14 | inputVariables = {"make", "gearbox"}) 15 | @ElementTemplate( 16 | id = "com.camunda.consulting:carConnector", 17 | name = "Car Connector", 18 | description = "A connector to get a car from a selection", 19 | documentationRef = "https://github.com/camunda-community-hub/camunda-8-examples", 20 | inputDataClass = CarConnectorInput.class, 21 | version = 1) 22 | public class CarConnector implements OutboundConnectorFunction { 23 | @Override 24 | public Object execute(OutboundConnectorContext outboundConnectorContext) throws Exception { 25 | var input = outboundConnectorContext.bindVariables(CarConnectorInput.class); 26 | Make make = input.make(); 27 | if (make instanceof Audi audi) { 28 | return new CarConnectorOutput("Audi", audi.audiModel().name(), input.gearbox().name()); 29 | } else if (make instanceof Volkswagen volkswagen) { 30 | return new CarConnectorOutput( 31 | "Volkswagen", volkswagen.volkswagenModel().name(), input.gearbox().name()); 32 | } 33 | throw new IllegalStateException("Unknown make type: " + make); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /payment-example-process-application/src/main/java/com/camunda/consulting/web_shop_process_app/service/CreditCardService.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.web_shop_process_app.service; 2 | 3 | import java.time.LocalDate; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.stereotype.Component; 7 | 8 | @Component 9 | public class CreditCardService { 10 | 11 | private static final Logger LOG = LoggerFactory.getLogger(CreditCardService.class); 12 | 13 | public void chargeAmount(String cardNumber, String cvc, String expiryDate, Double amount) { 14 | LOG.info( 15 | "charging card {} that expires on {} and has cvc {} with amount of {}", 16 | cardNumber, 17 | expiryDate, 18 | cvc, 19 | amount); 20 | if (validateExpiryDate(expiryDate) == false) { 21 | String message = "Expiry date " + expiryDate + " is invalid"; 22 | LOG.info("Error message: {}", message); 23 | throw new CreditCardExpiredException(message); 24 | } 25 | 26 | LOG.info("payment completed"); 27 | } 28 | 29 | boolean validateExpiryDate(String expiryDate) { 30 | if (expiryDate.length() != 5) { 31 | return false; 32 | } 33 | try { 34 | int month = Integer.valueOf(expiryDate.substring(0, 2)); 35 | int year = Integer.valueOf(expiryDate.substring(3, 5)) + 2000; 36 | LocalDate now = LocalDate.now(); 37 | if (month < 1 || month > 12 || year < now.getYear()) { 38 | return false; 39 | } 40 | if (year > now.getYear() || (year == now.getYear() && month >= now.getMonthValue())) { 41 | return true; 42 | } else { 43 | return false; 44 | } 45 | } catch (NumberFormatException | IndexOutOfBoundsException e) { 46 | return false; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /secret-provider-as-credentials-provider/src/main/java/com/camunda/consulting/BearerTokenSecretProvider.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import io.camunda.connector.api.secret.SecretProvider; 4 | import java.util.regex.Matcher; 5 | import java.util.regex.Pattern; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.stereotype.Component; 9 | 10 | /** 11 | * A secret provider that returns a token based on the configuration. 12 | * 13 | *

The format of the secret is {@code bearerToken(serviceName)}. 14 | * 15 | *

The {@code serviceName} is resolved using the {@link BearerTokenProviderRegistry}. 16 | */ 17 | @Component 18 | public class BearerTokenSecretProvider implements SecretProvider { 19 | private static final Logger LOG = LoggerFactory.getLogger(BearerTokenSecretProvider.class); 20 | private static final Pattern SECRET_PATTERN = Pattern.compile("bearerToken\\((.*)\\)"); 21 | private final BearerTokenProviderRegistry registry; 22 | 23 | public BearerTokenSecretProvider(BearerTokenProviderRegistry registry) { 24 | this.registry = registry; 25 | } 26 | 27 | @Override 28 | public String getSecret(String s) { 29 | Matcher matcher = SECRET_PATTERN.matcher(s); 30 | if (matcher.find()) { 31 | String serviceName = matcher.group(1); 32 | try { 33 | String bearerTokenForService = registry.getBearerTokenForService(serviceName); 34 | if (bearerTokenForService == null) { 35 | LOG.warn("Service '{}' not found, secret '{}' cannot be resolved", serviceName, s); 36 | } 37 | return bearerTokenForService; 38 | } catch (Exception e) { 39 | LOG.error("Error while resolving bearer token for service '{}'", serviceName, e); 40 | } 41 | } 42 | return null; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /zeebe-client-plain-java/src/main/java/io/camunda/zeebe/example/cluster/TopologyViewer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under 3 | * one or more contributor license agreements. See the NOTICE file distributed 4 | * with this work for additional information regarding copyright ownership. 5 | * Licensed under the Zeebe Community License 1.1. You may not use this file 6 | * except in compliance with the Zeebe Community License 1.1. 7 | */ 8 | package io.camunda.zeebe.example.cluster; 9 | 10 | import io.camunda.zeebe.client.ZeebeClient; 11 | import io.camunda.zeebe.client.api.response.Topology; 12 | import io.camunda.zeebe.example.ClientProvider; 13 | import io.camunda.zeebe.example.ClientProvider.AuthMethod; 14 | 15 | /** 16 | * Example application that connects to a cluster on Camunda Cloud, or a locally deployed cluster. 17 | * 18 | *

It uses {@link ClientProvider} to create a client with the appropriate authentication method. 19 | */ 20 | public final class TopologyViewer { 21 | 22 | public static void main(final String[] args) { 23 | try (final ZeebeClient client = ClientProvider.createZeebeClient(AuthMethod.none)) { 24 | final Topology topology = client.newTopologyRequest().send().join(); 25 | 26 | System.out.println("Topology:"); 27 | topology 28 | .getBrokers() 29 | .forEach( 30 | b -> { 31 | System.out.println(" " + b.getAddress()); 32 | b.getPartitions() 33 | .forEach( 34 | p -> 35 | System.out.println( 36 | " " + p.getPartitionId() + " - " + p.getRole())); 37 | }); 38 | 39 | System.out.println("Done."); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /payment-example-process-application/src/main/resources/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 13 | 14 | 15 | 16 | 17 |

18 |
19 | 20 | 24 | 25 | 26 | 29 | 30 | 31 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /secret-provider-as-credentials-provider/README.md: -------------------------------------------------------------------------------- 1 | # Secret Provider as Credentials Provider 2 | 3 | Currently, the Camunda Connectors offer various ways to apply credentials to a request. 4 | 5 | Especially OAuth requires extensive configuration. 6 | 7 | ## What is the example about? 8 | 9 | This example shows how a secret provider can be implemented that allows for fetching a token without configuring this in the connector itself. 10 | 11 | ## Why do I need this? 12 | 13 | >Especially OAuth requires extensive configuration. 14 | 15 | One main motivation here is to allow for abstraction of complex constructs like building a complex authentication. 16 | 17 | Further ideas could be to implement similar secret providers that allow for maintaining a registry of connection details. 18 | 19 | ## How does it work? 20 | 21 | ### Run the platform in identity mode 22 | 23 | The example is configured to run with a local docker-compose of camunda-platform. 24 | 25 | To start, you have to first run camunda in [docker-compose](https://docs.camunda.io/docs/self-managed/setup/deploy/local/docker-compose/#run-camunda-8-with-docker-compose). Please do *not* use the `-core` variant as we need Identity + Keycloak. 26 | 27 | Also, you need to set `ZEEBE_AUTHENTICATION_MODE=identity` in the `.env` file. 28 | 29 | ### Start the application 30 | 31 | After Camunda is running in docker-compose, you can start the application: 32 | 33 | ```shell 34 | mvn spring-boot:run 35 | ``` 36 | 37 | ### Run the test process 38 | 39 | To run the test process, deploy the process from `src/test/resources/test.bpmn` to your Camunda instance using the Camunda Modeler and run an instance. 40 | 41 | If you inspect the process instance in Operate, you should find the topology of the zeebe cluster as a variable. 42 | 43 | This is the response coming from the REST connector call that was used. 44 | -------------------------------------------------------------------------------- /ProcessMetadataListener/src/main/java/com/camunda/consulting/MetadataWorker.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import com.camunda.consulting.ProcessMetadataResult.Camunda; 4 | import io.camunda.client.CamundaClient; 5 | import io.camunda.client.annotation.JobWorker; 6 | import io.camunda.client.api.response.ActivatedJob; 7 | import io.camunda.client.exception.CamundaError; 8 | import java.time.Duration; 9 | import java.util.Map; 10 | import java.util.concurrent.ConcurrentHashMap; 11 | import org.springframework.stereotype.Component; 12 | 13 | @Component 14 | public class MetadataWorker { 15 | private final CamundaClient camundaClient; 16 | private final Map versionTagCache = new ConcurrentHashMap<>(); 17 | 18 | public MetadataWorker(CamundaClient camundaClient) { 19 | this.camundaClient = camundaClient; 20 | } 21 | 22 | @JobWorker 23 | public ProcessMetadataResult metadata(ActivatedJob job) { 24 | String versionTag = 25 | versionTagCache.computeIfAbsent(job.getProcessDefinitionKey(), this::getVersionTag); 26 | return new ProcessMetadataResult( 27 | new Camunda( 28 | String.valueOf(job.getProcessInstanceKey()), 29 | String.valueOf(job.getProcessDefinitionKey()), 30 | job.getBpmnProcessId(), 31 | job.getProcessDefinitionVersion(), 32 | versionTag)); 33 | } 34 | 35 | private String getVersionTag(Long processDefinitionKey) { 36 | try { 37 | return camundaClient 38 | .newProcessDefinitionGetRequest(processDefinitionKey) 39 | .execute() 40 | .getVersionTag(); 41 | } catch (Exception e) { 42 | throw CamundaError.jobError( 43 | "Could not get version tag for " + processDefinitionKey, 44 | null, 45 | null, 46 | Duration.ofSeconds(1)); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /parallel-operations/README.md: -------------------------------------------------------------------------------- 1 | # Parallel Operations 2 | 3 | This is an example that shows how Camunda 7 and 8 can run in parallel. 4 | 5 | Here, the embedded Camunda 7 engine setup is used to demonstrate interoperability between them. 6 | 7 | ## Important aspects 8 | 9 | Camunda 7 and 8 share the same "Delegates", the methods that are defined in `MyDelegates`. 10 | 11 | They can then be invoked from Camunda 7 as expression (`${myDelegates.sharedTask(someText).someOtherText()}` with result variable `someOtherText`) or from Camunda 8 as job worker (`sharedTask`). 12 | 13 | ## Requirements 14 | 15 | This example is built on the `camunda-bpm-spring-boot-starter` (plus webapp) and `spring-boot-starter-camunda`. 16 | 17 | ## Testing 18 | 19 | The example contains a test that performs a unit test for the processes. 20 | 21 | >Note: It is not easily possible to use the embedded zeebe engine as the versions of org.camunda.feel are not aligned between Camunda 7 and 8. 22 | 23 | ## Running the example 24 | 25 | ### Explanation 26 | 27 | By default, the `application.yaml` is configured to connect to a running camunda 8 instance. You can learn [here](https://docs.camunda.io/docs/self-managed/quickstart/developer-quickstart/docker-compose/) how to set it up. 28 | 29 | Camunda 7 will start with an in-memory h2 database. To adjust this, you need to configure the spring boot datasource. 30 | 31 | ### Steps 32 | 33 | Follow the docs to get Camunda 8 up and running. 34 | 35 | Now, go back to this directly and run this example: 36 | 37 | ```shell 38 | cd 39 | mvn spring-boot:run 40 | ``` 41 | 42 | Now, you can start process instances by sending: 43 | 44 | ```shell 45 | POST http://localhost:8080/process 46 | ``` 47 | 48 | You can then go to [Camunda 7 cockpit](http://localhost:8080/camunda) and [Camunda 8 Operate](http://localhost:8081) and inspect the run process instances. 49 | -------------------------------------------------------------------------------- /camunda-client-plain-java/src/main/java/io/camunda/example/process/NonBlockingProcessInstanceCreator.java: -------------------------------------------------------------------------------- 1 | package io.camunda.example.process; 2 | 3 | import io.camunda.client.CamundaClient; 4 | import io.camunda.client.api.CamundaFuture; 5 | import io.camunda.client.api.response.ProcessInstanceEvent; 6 | import io.camunda.example.ClientProvider; 7 | import io.camunda.example.ClientProvider.AuthMethod; 8 | 9 | /** 10 | * Example application that connects to a cluster on Camunda Cloud, or a locally deployed cluster. 11 | * 12 | *

It uses {@link ClientProvider} to create a client with the appropriate authentication method. 13 | */ 14 | public final class NonBlockingProcessInstanceCreator { 15 | public static void main(final String[] args) { 16 | final int numberOfInstances = 100_000; 17 | final String bpmnProcessId = "demoProcess"; 18 | 19 | try (final CamundaClient client = ClientProvider.createCamundaClient(AuthMethod.none)) { 20 | System.out.println("Creating " + numberOfInstances + " process instances"); 21 | 22 | final long startTime = System.currentTimeMillis(); 23 | 24 | long instancesCreating = 0; 25 | 26 | while (instancesCreating < numberOfInstances) { 27 | // this is non-blocking/async => returns a future 28 | final CamundaFuture future = 29 | client.newCreateInstanceCommand().bpmnProcessId(bpmnProcessId).latestVersion().send(); 30 | 31 | // could put the future somewhere and eventually wait for its completion 32 | 33 | instancesCreating++; 34 | } 35 | 36 | // creating one more instance; joining on this future ensures 37 | // that all the other create commands were handled 38 | client.newCreateInstanceCommand().bpmnProcessId(bpmnProcessId).latestVersion().execute(); 39 | 40 | System.out.println("Took: " + (System.currentTimeMillis() - startTime)); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /twitter-review-java-springboot/src/main/java/org/camunda/community/examples/twitter/rest/ReviewTweetRestApi.java: -------------------------------------------------------------------------------- 1 | package org.camunda.community.examples.twitter.rest; 2 | 3 | import io.camunda.zeebe.client.ZeebeClient; 4 | import io.camunda.zeebe.client.api.response.ProcessInstanceEvent; 5 | import org.camunda.community.examples.twitter.process.TwitterProcessVariables; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.http.HttpStatus; 8 | import org.springframework.http.ResponseEntity; 9 | import org.springframework.web.bind.annotation.PutMapping; 10 | import org.springframework.web.bind.annotation.RestController; 11 | import org.springframework.web.server.ServerWebExchange; 12 | 13 | @RestController 14 | public class ReviewTweetRestApi { 15 | 16 | @Autowired private ZeebeClient zeebeClient; 17 | 18 | @PutMapping("/tweet") 19 | public ResponseEntity startTweetReviewProcess(ServerWebExchange exchange) { 20 | // TODO: add data to the process instance from REST request 21 | String reference = startTweetReviewProcess("bernd", "Hello World", "Zeebot"); 22 | 23 | // And just return something for the sake of the example 24 | return ResponseEntity.status(HttpStatus.OK).body("Started process instance " + reference); 25 | } 26 | 27 | public String startTweetReviewProcess(String author, String tweet, String boss) { 28 | TwitterProcessVariables processVariables = 29 | new TwitterProcessVariables().setAuthor(author).setTweet(tweet).setBoss(boss); 30 | 31 | ProcessInstanceEvent processInstance = 32 | zeebeClient 33 | .newCreateInstanceCommand() 34 | .bpmnProcessId("TwitterDemoProcess") 35 | .latestVersion() 36 | .variables(processVariables) 37 | .send() 38 | .join(); // blocking call! 39 | 40 | return String.valueOf(processInstance.getProcessInstanceKey()); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /secret-provider-as-credentials-provider/src/main/java/com/camunda/consulting/ZeebeBearerTokenProvider.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import io.camunda.zeebe.client.CredentialsProvider; 4 | import io.camunda.zeebe.client.CredentialsProvider.CredentialsApplier; 5 | import java.io.IOException; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | import org.springframework.stereotype.Component; 9 | 10 | /** 11 | * This is an example implementation of {@link BearerTokenProvider}. 12 | * 13 | *

It uses the {@link CredentialsProvider} bean of the zeebe spring sdk to retrieve a token for 14 | * the zeebe api. 15 | */ 16 | @Component 17 | public class ZeebeBearerTokenProvider implements BearerTokenProvider { 18 | private final CredentialsProvider credentialsProvider; 19 | 20 | public ZeebeBearerTokenProvider(CredentialsProvider credentialsProvider) { 21 | this.credentialsProvider = credentialsProvider; 22 | } 23 | 24 | @Override 25 | public String getServiceName() { 26 | return "zeebe"; 27 | } 28 | 29 | @Override 30 | public String getBearerToken() { 31 | MapCredentialsApplier credentialsApplier = new MapCredentialsApplier(); 32 | try { 33 | credentialsProvider.applyCredentials(credentialsApplier); 34 | } catch (IOException e) { 35 | throw new RuntimeException("Error while applying zeebe credentials", e); 36 | } 37 | String authorization = credentialsApplier.getCredentials().get("Authorization"); 38 | return authorization.substring("Bearer ".length()); 39 | } 40 | 41 | private static class MapCredentialsApplier implements CredentialsApplier { 42 | private final Map credentials = new HashMap<>(); 43 | 44 | @Override 45 | public void put(String key, String value) { 46 | credentials.put(key, value); 47 | } 48 | 49 | public Map getCredentials() { 50 | return credentials; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /extended-connector-runtime/src/test/java/com/camunda/consulting/example/AppTest.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.example; 2 | 3 | import static org.assertj.core.api.Assertions.*; 4 | import static org.mockito.Mockito.*; 5 | 6 | import io.camunda.process.test.api.CamundaSpringProcessTest; 7 | import io.camunda.zeebe.client.ZeebeClient; 8 | import io.camunda.zeebe.client.api.response.ProcessInstanceResult; 9 | import java.time.Duration; 10 | import org.junit.jupiter.api.BeforeEach; 11 | import org.junit.jupiter.api.Test; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.boot.test.context.SpringBootTest; 14 | import org.testcontainers.containers.GenericContainer; 15 | import org.testcontainers.junit.jupiter.Container; 16 | import org.testcontainers.junit.jupiter.Testcontainers; 17 | 18 | @SpringBootTest 19 | @CamundaSpringProcessTest 20 | @Testcontainers 21 | public class AppTest { 22 | @Autowired ZeebeClient zeebeClient; 23 | 24 | @Container 25 | private final GenericContainer httpbin = 26 | new GenericContainer<>("kennethreitz/httpbin").withExposedPorts(80); 27 | 28 | @BeforeEach 29 | public void setup() { 30 | zeebeClient.newDeployResourceCommand().addResourceFromClasspath("test.bpmn").send().join(); 31 | } 32 | 33 | @Test 34 | void shouldExecute() { 35 | Integer mappedPort = httpbin.getMappedPort(80); 36 | Duration nextExecutionBackoff = Duration.ofMinutes(20); 37 | ProcessInstanceResult result = 38 | zeebeClient 39 | .newCreateInstanceCommand() 40 | .bpmnProcessId("test") 41 | .latestVersion() 42 | .variable("host", "http://localhost:" + mappedPort) 43 | .withResult() 44 | .send() 45 | .join(); 46 | assertThat(result).isNotNull(); 47 | assertThat(Duration.parse((CharSequence) result.getVariable("nextExecutionBackoff"))) 48 | .isEqualTo(nextExecutionBackoff); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /rollback-on-error-example/src/main/java/com/camunda/consulting/UserTask.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import com.fasterxml.jackson.databind.node.ObjectNode; 4 | import java.util.List; 5 | 6 | public class UserTask { 7 | private long key; 8 | private long originalKey; 9 | private ObjectNode variables; 10 | private String taskName; 11 | private String elementId; 12 | private long elementInstanceKey; 13 | private List rollbackTaskTypes; 14 | private long processInstanceKey; 15 | 16 | public long getOriginalKey() { 17 | return originalKey; 18 | } 19 | 20 | public void setOriginalKey(long originalKey) { 21 | this.originalKey = originalKey; 22 | } 23 | 24 | public long getProcessInstanceKey() { 25 | return processInstanceKey; 26 | } 27 | 28 | public void setProcessInstanceKey(long processInstanceKey) { 29 | this.processInstanceKey = processInstanceKey; 30 | } 31 | 32 | public List getRollbackTaskTypes() { 33 | return rollbackTaskTypes; 34 | } 35 | 36 | public void setRollbackTaskTypes(List rollbackTaskTypes) { 37 | this.rollbackTaskTypes = rollbackTaskTypes; 38 | } 39 | 40 | public long getKey() { 41 | return key; 42 | } 43 | 44 | public void setKey(long key) { 45 | this.key = key; 46 | } 47 | 48 | public ObjectNode getVariables() { 49 | return variables; 50 | } 51 | 52 | public void setVariables(ObjectNode variables) { 53 | this.variables = variables; 54 | } 55 | 56 | public String getTaskName() { 57 | return taskName; 58 | } 59 | 60 | public void setTaskName(String taskName) { 61 | this.taskName = taskName; 62 | } 63 | 64 | public String getElementId() { 65 | return elementId; 66 | } 67 | 68 | public void setElementId(String elementId) { 69 | this.elementId = elementId; 70 | } 71 | 72 | public long getElementInstanceKey() { 73 | return elementInstanceKey; 74 | } 75 | 76 | public void setElementInstanceKey(long elementInstanceKey) { 77 | this.elementInstanceKey = elementInstanceKey; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /payment-example-process-application/src/main/java/com/camunda/consulting/web_shop_process_app/service/CustomerService.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.web_shop_process_app.service; 2 | 3 | import java.util.regex.Matcher; 4 | import java.util.regex.Pattern; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.stereotype.Component; 8 | 9 | @Component 10 | public class CustomerService { 11 | 12 | private static final Logger LOG = LoggerFactory.getLogger(CustomerService.class); 13 | 14 | /** The customer credit are the last digits of the customer id */ 15 | private Pattern pattern = Pattern.compile("(.*?)(\\d*)"); 16 | 17 | /** 18 | * Deduct the credit for the given customer and the given amount 19 | * 20 | * @param customerId 21 | * @param amount 22 | * @param credit 23 | * @return the open order amount 24 | */ 25 | public Double deductCredit(String customerId, Double amount, Double credit) { 26 | // Double credit = getCustomerCredit(customerId); 27 | Double openAmount; 28 | Double deductedCredit; 29 | if (credit > amount) { 30 | deductedCredit = amount; 31 | openAmount = 0.0; 32 | } else { 33 | openAmount = amount - credit; 34 | deductedCredit = credit; 35 | } 36 | LOG.info("charged {} from the credit, open amount is {}", deductedCredit, openAmount); 37 | return openAmount; 38 | } 39 | 40 | /** 41 | * Get the current customer credit 42 | * 43 | * @param customerId 44 | * @return the current credit of the given customer 45 | */ 46 | public Double getCustomerCredit(String customerId) { 47 | Double credit = 0.0; 48 | Matcher matcher = pattern.matcher(customerId); 49 | 50 | if (matcher.matches() && matcher.group(2) != null && matcher.group(2).length() > 0) { 51 | credit = Double.valueOf(matcher.group(2)); 52 | } else { 53 | throw new RuntimeException("The customer ID doesn't end with a number"); 54 | } 55 | 56 | LOG.info("customer {} has credit of {}", customerId, credit); 57 | 58 | return credit; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /async-service-task/README.md: -------------------------------------------------------------------------------- 1 | # Async Service Task Example 2 | 3 | ## What is the use case? 4 | 5 | The implementation of a service task might be asynchronous. Usually, you would handle this using the Messaging Pattern (Send - Receive). 6 | 7 | But there might be cases when the requirement to the process is to hide this kind of implementation detail and instead represent the service call as one task. 8 | 9 | In this case, the implementation needs to be able to cover this kind of call by sending a request in an idempotent way and then waiting for the answer. 10 | 11 | ## How does it work? 12 | 13 | This implementation will check for a transactionId, create an transactionId on service task scope if missing and uses it to send a request to a service and then check for the answer. 14 | 15 | Then, it checks for the answer being present. 16 | 17 | If not, it defers the polling by failing the job while leaving the amount of retries untouched. 18 | 19 | ## What are the constraints of the implementation? 20 | 21 | The constraints of the implementation lie in the `AsyncService`. Here, the assumption is that creation of a transaction requires an ID. 22 | 23 | As soon as complete, the result can be fetched over and over until it is completed (which will remove the transaction from the `AsyncService`). 24 | 25 | ## How can I try it out? 26 | 27 | Configure the Camunda connection in the `application.yaml`. By default, it points to a plaintext local Camunda instance. 28 | 29 | Then, start the app by running 30 | 31 | ```shell 32 | mvn spring-boot:run 33 | ``` 34 | 35 | On starting up, the example process is deployed. 36 | 37 | After the app is up and running, a process instance can be started with a `POST` to `http://localhost:8080/start`. 38 | 39 | The process instance executes one service task that has an asynchronous implementation. In the logs, you should be able to see that the `AsyncService` is triggered from time to time, only creating a transaction on the first invocation. 40 | 41 | Then, the result is fetched. After the result has been fetched, the next poll will return it and the job is completed. 42 | -------------------------------------------------------------------------------- /camunda-client-plain-java/src/test/java/io/camunda/example/DocsConsistencyTest.java: -------------------------------------------------------------------------------- 1 | package io.camunda.example; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import io.camunda.example.cluster.TopologyViewer; 6 | import io.camunda.example.data.HandleVariablesAsPojo; 7 | import io.camunda.example.decision.EvaluateDecisionCreator; 8 | import io.camunda.example.job.JobWorkerCreator; 9 | import io.camunda.example.process.NonBlockingProcessInstanceCreator; 10 | import io.camunda.example.process.ProcessDeployer; 11 | import io.camunda.example.process.ProcessInstanceCreator; 12 | import java.util.stream.Stream; 13 | import org.junit.jupiter.params.ParameterizedTest; 14 | import org.junit.jupiter.params.provider.Arguments; 15 | import org.junit.jupiter.params.provider.MethodSource; 16 | 17 | public final class DocsConsistencyTest { 18 | 19 | static Stream data() { 20 | return Stream.of( 21 | Arguments.of(TopologyViewer.class, "io.camunda.example.cluster.TopologyViewer"), 22 | Arguments.of(JobWorkerCreator.class, "io.camunda.example.job.JobWorkerCreator"), 23 | Arguments.of( 24 | NonBlockingProcessInstanceCreator.class, 25 | "io.camunda.example.process.NonBlockingProcessInstanceCreator"), 26 | Arguments.of(ProcessDeployer.class, "io.camunda.example.process.ProcessDeployer"), 27 | Arguments.of( 28 | ProcessInstanceCreator.class, "io.camunda.example.process.ProcessInstanceCreator"), 29 | Arguments.of(HandleVariablesAsPojo.class, "io.camunda.example.data.HandleVariablesAsPojo"), 30 | Arguments.of( 31 | EvaluateDecisionCreator.class, "io.camunda.example.decision.EvaluateDecisionCreator")); 32 | } 33 | 34 | @ParameterizedTest 35 | @MethodSource("data") 36 | void todo(Class exampleClass, String expectedClassName) { 37 | assertThat(exampleClass.getName()) 38 | .withFailMessage( 39 | "This class's source code is referenced from the java-client-example docs. " 40 | + "Make sure to adapt them as well.") 41 | .isEqualTo(expectedClassName); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /payment-example-process-application/src/main/java/com/camunda/consulting/web_shop_process_app/worker/CreditCardHandler.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.web_shop_process_app.worker; 2 | 3 | import com.camunda.consulting.web_shop_process_app.service.CreditCardExpiredException; 4 | import com.camunda.consulting.web_shop_process_app.service.CreditCardService; 5 | import io.camunda.zeebe.client.api.response.ActivatedJob; 6 | import io.camunda.zeebe.client.api.worker.JobClient; 7 | import io.camunda.zeebe.spring.client.annotation.JobWorker; 8 | import java.util.Map; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | import org.springframework.stereotype.Component; 12 | 13 | @Component 14 | public class CreditCardHandler { 15 | 16 | private static final Logger LOG = LoggerFactory.getLogger(CreditCardHandler.class); 17 | 18 | private final CreditCardService creditCardService; 19 | 20 | public CreditCardHandler(CreditCardService creditCardService) { 21 | this.creditCardService = creditCardService; 22 | } 23 | 24 | @JobWorker(type = "creditCardCharging", autoComplete = false) 25 | public void handle(JobClient client, ActivatedJob job) { 26 | LOG.info("Handling credit card payment for process instance {}", job.getProcessInstanceKey()); 27 | Map variables = job.getVariablesAsMap(); 28 | String cardNumber = (String) variables.get("cardNumber"); 29 | String cvc = (String) variables.get("cvc"); 30 | String expiryDate = (String) variables.get("expiryDate"); 31 | Double amount = Double.valueOf(variables.get("openAmount").toString()); 32 | try { 33 | creditCardService.chargeAmount(cardNumber, cvc, expiryDate, amount); 34 | client.newCompleteCommand(job).send(); 35 | } catch (CreditCardExpiredException e) { 36 | LOG.info("Credit card payment failed: {}", e.getLocalizedMessage()); 37 | client 38 | .newThrowErrorCommand(job) 39 | .errorCode("creditCardError") 40 | .errorMessage(e.getLocalizedMessage()) 41 | .variables(Map.of("errorMessage", e.getLocalizedMessage())) 42 | .send(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /ProcessMetadataListener/src/test/java/com/camunda/consulting/MetadataWorkerTest.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import static org.assertj.core.api.Assertions.*; 4 | 5 | import com.camunda.consulting.ProcessMetadataResult.Camunda; 6 | import io.camunda.client.CamundaClient; 7 | import io.camunda.client.api.response.DeploymentEvent; 8 | import io.camunda.client.api.response.Process; 9 | import io.camunda.client.api.response.ProcessInstanceEvent; 10 | import io.camunda.process.test.api.CamundaAssert; 11 | import io.camunda.process.test.api.CamundaSpringProcessTest; 12 | import org.junit.jupiter.api.Test; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.boot.test.context.SpringBootTest; 15 | 16 | @SpringBootTest 17 | @CamundaSpringProcessTest 18 | public class MetadataWorkerTest { 19 | @Autowired CamundaClient camundaClient; 20 | 21 | @Test 22 | public void shouldSetProcessInstanceMetadata() { 23 | DeploymentEvent deploymentEvent = 24 | camundaClient.newDeployResourceCommand().addResourceFromClasspath("test.bpmn").execute(); 25 | assertThat(deploymentEvent.getProcesses()).hasSize(1); 26 | Process process = deploymentEvent.getProcesses().get(0); 27 | ProcessInstanceEvent processInstance = 28 | camundaClient 29 | .newCreateInstanceCommand() 30 | .processDefinitionKey(process.getProcessDefinitionKey()) 31 | .execute(); 32 | CamundaAssert.assertThat(processInstance) 33 | .isCompleted() 34 | .hasVariableSatisfies( 35 | "camunda", 36 | Camunda.class, 37 | camunda -> { 38 | assertThat(camunda.processDefinitionId()).isEqualTo(process.getBpmnProcessId()); 39 | assertThat(camunda.processDefinitionKey()) 40 | .isEqualTo(String.valueOf(process.getProcessDefinitionKey())); 41 | assertThat(camunda.processInstanceKey()) 42 | .isEqualTo(String.valueOf(processInstance.getProcessInstanceKey())); 43 | assertThat(camunda.version()).isEqualTo(process.getVersion()); 44 | }); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /extended-connector-runtime/src/main/java/com/camunda/consulting/example/NextExecutionTimeslotFeelFunction.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.example; 2 | 3 | import java.time.Duration; 4 | import java.time.ZonedDateTime; 5 | import java.time.temporal.ChronoUnit; 6 | import java.util.List; 7 | import java.util.function.Function; 8 | import org.camunda.feel.syntaxtree.Val; 9 | import org.camunda.feel.syntaxtree.ValDayTimeDuration; 10 | import org.springframework.stereotype.Component; 11 | 12 | @Component 13 | public class NextExecutionTimeslotFeelFunction implements Function, Val> { 14 | public static final List PARAMS = List.of("backoff"); 15 | public static final String NAME = "nextExecutionBackoff"; 16 | 17 | /** 18 | * This field is required to access a bean from outside the spring context as spi is used for the 19 | * function provider 20 | */ 21 | private static NextExecutionTimeslotFeelFunction instance; 22 | 23 | private final SchedulingService schedulingService; 24 | 25 | public NextExecutionTimeslotFeelFunction(SchedulingService schedulingService) { 26 | this.schedulingService = schedulingService; 27 | instance = this; 28 | } 29 | 30 | public static NextExecutionTimeslotFeelFunction getInstance() { 31 | return instance; 32 | } 33 | 34 | @Override 35 | public Val apply(List vals) { 36 | Val scheduledExecution = vals.get(0); 37 | if (scheduledExecution instanceof ValDayTimeDuration duration) { 38 | Duration value = duration.value(); 39 | return new ValDayTimeDuration(calculateNextExecution(value)); 40 | } else { 41 | throw new IllegalStateException( 42 | "Param 'scheduledExecution' expected to be of type 'date and time'"); 43 | } 44 | } 45 | 46 | private Duration calculateNextExecution(Duration duration) { 47 | // we use the same "now" for both transformations to prevent inconsistencies 48 | ZonedDateTime now = ZonedDateTime.now(); 49 | ZonedDateTime scheduledExecution = now.plus(duration); 50 | return Duration.between(now, schedulingService.schedule(scheduledExecution)) 51 | .truncatedTo(ChronoUnit.SECONDS); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /payment-example-process-application/kube/manifests/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: payment-example-process-application 5 | namespace: c8-payment-demo 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: payment-example-process-application 11 | template: 12 | metadata: 13 | labels: 14 | app: payment-example-process-application 15 | spec: 16 | containers: 17 | - name: payment-example-process-application 18 | image: ghcr.io/camunda-community-hub/camunda-8-examples/payment-example-process-application:8.7.0 19 | ports: 20 | - containerPort: 8080 21 | name: http 22 | env: 23 | - name: CAMUNDA_CLIENT_MODE 24 | value: "self-managed" 25 | - name: CAMUNDA_CLIENT_ZEEBE_GRPCADDRESS 26 | value: "http://camunda-zeebe-gateway.camunda.svc.cluster.local:26500" 27 | - name: CAMUNDA_CLIENT_ZEEBE_RESTADDRESS 28 | value: "http://camunda-zeebe-gateway.camunda.svc.cluster.local:8080" 29 | - name: CAMUNDA_CLIENT_AUTH_CLIENTID 30 | value: "payment-app" 31 | - name: CAMUNDA_CLIENT_AUTH_ISSUER 32 | value: http://camunda-keycloak.camunda.svc.cluster.local/auth/realms/camunda-platform/protocol/openid-connect/token 33 | - name: CAMUNDA_CLIENT_ZEEBE_AUDIENCE 34 | value: zeebe-api 35 | - name: CAMUNDA_CLIENT_AUTH_CLIENTSECRET 36 | valueFrom: 37 | secretKeyRef: 38 | name: payment-example-process-application-secrets 39 | key: CAMUNDA_CLIENT_AUTH_CLIENTSECRET 40 | resources: 41 | limits: 42 | memory: "768Mi" 43 | cpu: "500m" 44 | requests: 45 | memory: "768Mi" 46 | cpu: "500m" 47 | livenessProbe: 48 | httpGet: 49 | path: / 50 | port: 8080 51 | initialDelaySeconds: 30 52 | periodSeconds: 10 53 | readinessProbe: 54 | httpGet: 55 | path: / 56 | port: 8080 57 | initialDelaySeconds: 15 58 | periodSeconds: 5 -------------------------------------------------------------------------------- /camunda-client-plain-java/src/main/java/io/camunda/example/process/ProcessInstanceWithResultCreator.java: -------------------------------------------------------------------------------- 1 | package io.camunda.example.process; 2 | 3 | import io.camunda.client.CamundaClient; 4 | import io.camunda.client.api.response.ProcessInstanceResult; 5 | import io.camunda.example.ClientProvider; 6 | import io.camunda.example.ClientProvider.AuthMethod; 7 | import java.time.Duration; 8 | import java.util.Map; 9 | 10 | /** 11 | * Example application that connects to a cluster on Camunda Cloud, or a locally deployed cluster. 12 | * 13 | *

It uses {@link ClientProvider} to create a client with the appropriate authentication method. 14 | */ 15 | public class ProcessInstanceWithResultCreator { 16 | public static void main(final String[] args) { 17 | final String bpmnProcessId = "demoProcessSingleTask"; 18 | 19 | try (final CamundaClient client = ClientProvider.createCamundaClient(AuthMethod.none)) { 20 | 21 | openJobWorker(client); // open job workers so that task are executed and process is completed 22 | System.out.println("Creating process instance"); 23 | 24 | final ProcessInstanceResult processInstanceResult = 25 | client 26 | .newCreateInstanceCommand() 27 | .bpmnProcessId(bpmnProcessId) 28 | .latestVersion() 29 | .withResult() // to await the completion of process execution and return result 30 | .execute(); 31 | 32 | System.out.println( 33 | "Process instance created with key: " 34 | + processInstanceResult.getProcessInstanceKey() 35 | + " and completed with results: " 36 | + processInstanceResult.getVariables()); 37 | } 38 | } 39 | 40 | private static void openJobWorker(final CamundaClient client) { 41 | client 42 | .newWorker() 43 | .jobType("foo") 44 | .handler( 45 | (jobClient, job) -> 46 | jobClient 47 | .newCompleteCommand(job.getKey()) 48 | .variables(Map.of("job", job.getKey())) 49 | .send()) 50 | .timeout(Duration.ofSeconds(10)) 51 | .open(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /camunda-client-plain-java/src/main/resources/demoDecision.dmn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | lightsaberColor 8 | 9 | 10 | 11 | 12 | "Jedi","Sith" 13 | 14 | 15 | 16 | 17 | "blue" 18 | 19 | 20 | "Jedi" 21 | 22 | 23 | 24 | 25 | "green" 26 | 27 | 28 | "Jedi" 29 | 30 | 31 | 32 | 33 | "red" 34 | 35 | 36 | "Sith" 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /zeebe-client-plain-java/src/main/resources/demoDecision.dmn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | lightsaberColor 8 | 9 | 10 | 11 | 12 | "Jedi","Sith" 13 | 14 | 15 | 16 | 17 | "blue" 18 | 19 | 20 | "Jedi" 21 | 22 | 23 | 24 | 25 | "green" 26 | 27 | 28 | "Jedi" 29 | 30 | 31 | 32 | 33 | "red" 34 | 35 | 36 | "Sith" 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /camunda-client-plain-java/src/main/java/io/camunda/example/job/JobWorkerCreator.java: -------------------------------------------------------------------------------- 1 | package io.camunda.example.job; 2 | 3 | import io.camunda.client.CamundaClient; 4 | import io.camunda.client.api.response.ActivatedJob; 5 | import io.camunda.client.api.worker.JobClient; 6 | import io.camunda.client.api.worker.JobHandler; 7 | import io.camunda.client.api.worker.JobWorker; 8 | import io.camunda.example.ClientProvider; 9 | import io.camunda.example.ClientProvider.AuthMethod; 10 | import java.time.Duration; 11 | import java.util.Scanner; 12 | 13 | /** 14 | * Example application that connects to a cluster on Camunda Cloud, or a locally deployed cluster. 15 | * 16 | *

It uses {@link ClientProvider} to create a client with the appropriate authentication method. 17 | */ 18 | public final class JobWorkerCreator { 19 | public static void main(final String[] args) { 20 | final String jobType = "foo"; 21 | 22 | try (final CamundaClient client = ClientProvider.createCamundaClient(AuthMethod.none)) { 23 | 24 | System.out.println("Opening job worker."); 25 | 26 | try (final JobWorker workerRegistration = 27 | client 28 | .newWorker() 29 | .jobType(jobType) 30 | .handler(new ExampleJobHandler()) 31 | .timeout(Duration.ofSeconds(10)) 32 | .open()) { 33 | System.out.println("Job worker opened and receiving jobs."); 34 | 35 | // run until System.in receives exit command 36 | waitUntilSystemInput("exit"); 37 | } 38 | } 39 | } 40 | 41 | private static void waitUntilSystemInput(final String exitCode) { 42 | try (final Scanner scanner = new Scanner(System.in)) { 43 | while (scanner.hasNextLine()) { 44 | final String nextLine = scanner.nextLine(); 45 | if (nextLine.contains(exitCode)) { 46 | return; 47 | } 48 | } 49 | } 50 | } 51 | 52 | private static class ExampleJobHandler implements JobHandler { 53 | @Override 54 | public void handle(final JobClient client, final ActivatedJob job) { 55 | // here: business logic that is executed with every job 56 | System.out.println(job); 57 | client.newCompleteCommand(job.getKey()).execute(); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /event-processing/src/main/java/com/camunda/consulting/eventprocessing/EventRepository.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.eventprocessing; 2 | 3 | import com.camunda.consulting.eventprocessing.EventRepository.EventEntity; 4 | import jakarta.persistence.Entity; 5 | import jakarta.persistence.Id; 6 | import java.time.OffsetDateTime; 7 | import org.springframework.data.jpa.repository.JpaRepository; 8 | import org.springframework.stereotype.Repository; 9 | 10 | @Repository 11 | public interface EventRepository extends JpaRepository { 12 | 13 | @Entity(name = "EVENT") 14 | class EventEntity { 15 | @Id private String id; 16 | private String name; 17 | private String content; 18 | private State state; 19 | private OffsetDateTime createdAt; 20 | private OffsetDateTime publishingAt; 21 | private OffsetDateTime publishedAt; 22 | 23 | public String getId() { 24 | return id; 25 | } 26 | 27 | public void setId(String id) { 28 | this.id = id; 29 | } 30 | 31 | public String getName() { 32 | return name; 33 | } 34 | 35 | public void setName(String name) { 36 | this.name = name; 37 | } 38 | 39 | public String getContent() { 40 | return content; 41 | } 42 | 43 | public void setContent(String content) { 44 | this.content = content; 45 | } 46 | 47 | public State getState() { 48 | return state; 49 | } 50 | 51 | public void setState(State state) { 52 | this.state = state; 53 | } 54 | 55 | public OffsetDateTime getCreatedAt() { 56 | return createdAt; 57 | } 58 | 59 | public void setCreatedAt(OffsetDateTime createdAt) { 60 | this.createdAt = createdAt; 61 | } 62 | 63 | public OffsetDateTime getPublishingAt() { 64 | return publishingAt; 65 | } 66 | 67 | public void setPublishingAt(OffsetDateTime publishingAt) { 68 | this.publishingAt = publishingAt; 69 | } 70 | 71 | public OffsetDateTime getPublishedAt() { 72 | return publishedAt; 73 | } 74 | 75 | public void setPublishedAt(OffsetDateTime publishedAt) { 76 | this.publishedAt = publishedAt; 77 | } 78 | 79 | public enum State { 80 | CREATED, 81 | PUBLISHING, 82 | PUBLISHED 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /ProcessMetadataListener/src/test/resources/test.bpmn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Flow_0pobca5 11 | 12 | 13 | Flow_0pobca5 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 | -------------------------------------------------------------------------------- /event-processing/src/test/java/com/camunda/consulting/eventprocessing/ProcessTest.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.eventprocessing; 2 | 3 | import static org.assertj.core.api.Assertions.*; 4 | 5 | import com.camunda.consulting.eventprocessing.EventController.CreateEventRequest; 6 | import com.camunda.consulting.eventprocessing.EventController.CreateEventResponse; 7 | import com.camunda.consulting.eventprocessing.EventService.Event.State.StateName; 8 | import com.fasterxml.jackson.databind.ObjectMapper; 9 | import io.camunda.process.test.api.CamundaSpringProcessTest; 10 | import io.camunda.zeebe.client.ZeebeClient; 11 | import java.io.IOException; 12 | import java.io.InputStream; 13 | import org.awaitility.Awaitility; 14 | import org.junit.jupiter.api.BeforeEach; 15 | import org.junit.jupiter.api.Test; 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.boot.test.context.SpringBootTest; 18 | 19 | @SpringBootTest 20 | @CamundaSpringProcessTest 21 | public class ProcessTest { 22 | @Autowired ZeebeClient zeebeClient; 23 | 24 | @Autowired EventService eventService; 25 | 26 | @Autowired EventController eventController; 27 | 28 | private static CreateEventRequest loadCreateEventRequest() { 29 | try (InputStream stream = 30 | ProcessTest.class.getClassLoader().getResourceAsStream("createEventRequest.json")) { 31 | 32 | return new ObjectMapper().readValue(stream, CreateEventRequest.class); 33 | } catch (IOException e) { 34 | throw new RuntimeException("Error while loading unsaved event", e); 35 | } 36 | } 37 | 38 | @BeforeEach 39 | void deployProcess() { 40 | zeebeClient 41 | .newDeployResourceCommand() 42 | .addResourceFromClasspath("eventHandler.bpmn") 43 | .send() 44 | .join(); 45 | } 46 | 47 | @Test 48 | void shouldPublishEvent() { 49 | // when 50 | CreateEventResponse event = eventController.createEvent(loadCreateEventRequest()).getBody(); 51 | // then 52 | Awaitility.await() 53 | .untilAsserted( 54 | () -> 55 | assertThat(eventService.getEvent(event.id())) 56 | .isPresent() 57 | .get() 58 | .matches(e -> e.state().name().equals(StateName.PUBLISHED))); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /secret-provider-as-credentials-provider/src/test/java/com/camunda/consulting/AppTest.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import static com.github.tomakehurst.wiremock.client.WireMock.*; 4 | import static io.camunda.process.test.api.CamundaAssert.*; 5 | import static org.mockito.Mockito.*; 6 | 7 | import io.camunda.process.test.api.CamundaSpringProcessTest; 8 | import io.camunda.zeebe.client.CredentialsProvider; 9 | import io.camunda.zeebe.client.CredentialsProvider.CredentialsApplier; 10 | import io.camunda.zeebe.client.ZeebeClient; 11 | import io.camunda.zeebe.client.api.response.ProcessInstanceEvent; 12 | import java.io.IOException; 13 | import org.junit.jupiter.api.Test; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.beans.factory.annotation.Value; 16 | import org.springframework.boot.test.context.SpringBootTest; 17 | import org.springframework.test.context.bean.override.mockito.MockitoBean; 18 | import org.wiremock.spring.EnableWireMock; 19 | 20 | @CamundaSpringProcessTest 21 | @SpringBootTest 22 | @EnableWireMock 23 | public class AppTest { 24 | @Autowired ZeebeClient zeebeClient; 25 | @MockitoBean CredentialsProvider credentialsProvider; 26 | 27 | @Value("${wiremock.server.baseUrl}") 28 | private String wireMockUrl; 29 | 30 | @Test 31 | void shouldRunProcessInstance() throws IOException { 32 | doAnswer( 33 | inv -> { 34 | CredentialsApplier applier = inv.getArgument(0); 35 | applier.put("Authorization", "Bearer xyz"); 36 | return null; 37 | }) 38 | .when(credentialsProvider) 39 | .applyCredentials(any()); 40 | stubFor( 41 | get("/v2/topology").withHeader("Authorization", equalTo("Bearer xyz")).willReturn(ok("x"))); 42 | zeebeClient.newDeployResourceCommand().addResourceFromClasspath("test.bpmn").send().join(); 43 | ProcessInstanceEvent processInstanceEvent = 44 | zeebeClient 45 | .newCreateInstanceCommand() 46 | .bpmnProcessId("ZeebeTopologyFetcherProcess") 47 | .latestVersion() 48 | .variable("zeebeTopologyUrl", wireMockUrl + "/v2/topology") 49 | .send() 50 | .join(); 51 | assertThat(processInstanceEvent).isCompleted().hasVariable("topology", "x"); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /zeebe-client-plain-java/src/main/java/io/camunda/zeebe/example/process/NonBlockingProcessInstanceCreator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under 3 | * one or more contributor license agreements. See the NOTICE file distributed 4 | * with this work for additional information regarding copyright ownership. 5 | * Licensed under the Zeebe Community License 1.1. You may not use this file 6 | * except in compliance with the Zeebe Community License 1.1. 7 | */ 8 | package io.camunda.zeebe.example.process; 9 | 10 | import io.camunda.zeebe.client.ZeebeClient; 11 | import io.camunda.zeebe.client.api.ZeebeFuture; 12 | import io.camunda.zeebe.client.api.response.ProcessInstanceEvent; 13 | import io.camunda.zeebe.example.ClientProvider; 14 | import io.camunda.zeebe.example.ClientProvider.AuthMethod; 15 | 16 | /** 17 | * Example application that connects to a cluster on Camunda Cloud, or a locally deployed cluster. 18 | * 19 | *

It uses {@link ClientProvider} to create a client with the appropriate authentication method. 20 | */ 21 | public final class NonBlockingProcessInstanceCreator { 22 | public static void main(final String[] args) { 23 | final int numberOfInstances = 100_000; 24 | final String bpmnProcessId = "demoProcess"; 25 | 26 | try (final ZeebeClient client = ClientProvider.createZeebeClient(AuthMethod.none)) { 27 | System.out.println("Creating " + numberOfInstances + " process instances"); 28 | 29 | final long startTime = System.currentTimeMillis(); 30 | 31 | long instancesCreating = 0; 32 | 33 | while (instancesCreating < numberOfInstances) { 34 | // this is non-blocking/async => returns a future 35 | final ZeebeFuture future = 36 | client.newCreateInstanceCommand().bpmnProcessId(bpmnProcessId).latestVersion().send(); 37 | 38 | // could put the future somewhere and eventually wait for its completion 39 | 40 | instancesCreating++; 41 | } 42 | 43 | // creating one more instance; joining on this future ensures 44 | // that all the other create commands were handled 45 | client.newCreateInstanceCommand().bpmnProcessId(bpmnProcessId).latestVersion().send().join(); 46 | 47 | System.out.println("Took: " + (System.currentTimeMillis() - startTime)); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /payment-example-process-application/src/main/resources/static/start-process.form: -------------------------------------------------------------------------------- 1 | { 2 | "components": [ 3 | { 4 | "text": "### Start a new payment process", 5 | "label": "Text view", 6 | "type": "text", 7 | "layout": { 8 | "row": "Row_1as2tgk", 9 | "columns": null 10 | }, 11 | "id": "Field_1piit3t" 12 | }, 13 | { 14 | "label": "Customer ID", 15 | "type": "textfield", 16 | "layout": { 17 | "row": "Row_0ynhlko", 18 | "columns": null 19 | }, 20 | "id": "Field_0h7xpgp", 21 | "key": "customerId", 22 | "description": "the last digits are taken as customer credit (e.g. \"customer30\" has a credit of 30)", 23 | "validate": { 24 | "required": true 25 | } 26 | }, 27 | { 28 | "label": "Order total", 29 | "type": "number", 30 | "layout": { 31 | "row": "Row_0tdvqtj", 32 | "columns": null 33 | }, 34 | "id": "Field_0b8uf9s", 35 | "key": "orderTotal", 36 | "description": "Decimal number", 37 | "validate": { 38 | "required": true 39 | } 40 | }, 41 | { 42 | "label": "Credit card", 43 | "type": "textfield", 44 | "layout": { 45 | "row": "Row_0v7a42m", 46 | "columns": null 47 | }, 48 | "id": "Field_00pxbba", 49 | "key": "cardNumber" 50 | }, 51 | { 52 | "label": "CVC", 53 | "type": "textfield", 54 | "layout": { 55 | "row": "Row_0pkraxb", 56 | "columns": 8 57 | }, 58 | "id": "Field_1g6ncvn", 59 | "key": "cvc" 60 | }, 61 | { 62 | "label": "Expiry date", 63 | "type": "textfield", 64 | "layout": { 65 | "row": "Row_0pkraxb", 66 | "columns": 8 67 | }, 68 | "id": "Field_1g2j73h", 69 | "key": "expiryDate", 70 | "description": "MM/YY (invalid payment if larger than 5 characters)" 71 | }, 72 | { 73 | "action": "submit", 74 | "label": "Start payment", 75 | "type": "button", 76 | "layout": { 77 | "row": "Row_0aq6f9y", 78 | "columns": null 79 | }, 80 | "id": "Field_1s5e8kx" 81 | } 82 | ], 83 | "type": "default", 84 | "id": "Form_1km08al", 85 | "executionPlatform": "Camunda Cloud", 86 | "executionPlatformVersion": "8.3.0", 87 | "exporter": { 88 | "name": "Camunda Modeler", 89 | "version": "5.17.0" 90 | }, 91 | "schemaVersion": 12 92 | } -------------------------------------------------------------------------------- /payment-example-process-application/kube/manifests/start-processes-job.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: start-processes 5 | spec: 6 | template: 7 | spec: 8 | containers: 9 | - name: start-processes 10 | image: curlimages/curl:8.13.0 11 | imagePullPolicy: IfNotPresent 12 | command: 13 | - /bin/sh 14 | - -c 15 | - | 16 | COUNTER=1 17 | # while [ $COUNTER -le 5 ]; do 18 | while [ 1 ]; do 19 | CUSTOMER_NUMBER=$(($RANDOM%1000)) 20 | ORDER_TOTAL=$(($RANDOM%1000)) 21 | CARD_NUMBER=$(awk -v paket1=$(($RANDOM%10000)) -v paket2=$(($RANDOM%10000)) \ 22 | -v paket3=$(($RANDOM%10000)) -v paket4=$(($RANDOM%10000)) \ 23 | 'BEGIN {printf "%04d %04d %04d %04d", paket1, paket2, paket3, paket4}') 24 | CVC=$(awk -v cvc=$(($RANDOM%1000)) 'BEGIN {printf "%03d", cvc}') 25 | MONTH=$(($RANDOM%12+1)) 26 | YEAR=$(($RANDOM%4+$(date +%y)-1)) 27 | EXPIRY_DATE=$(awk -v month="$MONTH" -v year="$YEAR" 'BEGIN {printf "%02d/%02d", month, year}') 28 | 29 | echo 'starting with customer' $CUSTOMER_NUMBER ' of order total ' $ORDER_TOTAL ' and payment data' \ 30 | $CARD_NUMBER $CVC $EXPIRY_DATE 31 | 32 | ## start payment process 33 | curl -s -L "payment-example-process-application.c8-payment-demo.svc.cluster.local:8080/start" \ 34 | -X "POST" -H "Content-Type: application/json" \ 35 | -d "{\"customerId\": \"cust$CUSTOMER_NUMBER\", \ 36 | \"orderTotal\": $ORDER_TOTAL, \ 37 | \"cardNumber\": \"$CARD_NUMBER\", \ 38 | \"cvc\": \"$CVC\", \ 39 | \"expiryDate\": \"$EXPIRY_DATE\"}" 40 | 41 | CURRENT_TIME_HOUR=$(date +%H) 42 | 43 | if [ $CURRENT_TIME_HOUR -eq 16 -o $CURRENT_TIME_HOUR -eq 9 ] 44 | then 45 | WAIT_TIME=$(awk -v wait_time="$(($RANDOM%20))" 'BEGIN {print wait_time/10}') 46 | echo 'Prime time! sleeping for' $WAIT_TIME 'seconds' 47 | else 48 | WAIT_TIME=$(awk -v wait_time="$(($RANDOM%100))" 'BEGIN {print wait_time/10}') 49 | echo 'sleeping for' $WAIT_TIME ' seconds' 50 | fi 51 | 52 | sleep $WAIT_TIME 53 | : 54 | echo $COUNTER '. process instance started' 55 | COUNTER=$(($COUNTER+1)) 56 | done 57 | restartPolicy: OnFailure 58 | -------------------------------------------------------------------------------- /payment-example-process-application/start-processes/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Function to generate a random time between 60 and 120 minutes 4 | generate_random_time() { 5 | min_minutes=60 6 | max_minutes=120 7 | wait_minutes=$((min_minutes + RANDOM % (max_minutes - min_minutes + 1))) 8 | echo $wait_minutes 9 | } 10 | 11 | if [[ -z $1 ]] || [[ -z $2 ]] || [[ -z $3 ]] 12 | then 13 | echo 'usage: start.sh url_of_process_application run_for_seconds [endless | once]' 14 | exit 1 15 | else 16 | PROCESS_APP_URL=$1 17 | RUN_SECONDS=$2 18 | RUN_FOREVER=$3 19 | fi 20 | 21 | if [ $RUN_FOREVER == "endless" ] 22 | then 23 | echo "run forever" 24 | elif [ $RUN_FOREVER == "once" ] 25 | then 26 | echo "run once" 27 | else 28 | echo "Invalid argument. Use 'endless' for an endless loop or 'once' to run the task once." 29 | exit 1 30 | fi 31 | 32 | echo 'run for' $RUN_SECONDS 'seconds' 33 | while [ $RUN_FOREVER == "endless" ] || [ $RUN_FOREVER == "once" ]; do 34 | while [[ $SECONDS -lt $RUN_SECONDS ]]; do 35 | CUSTOMER_NUMBER=$(($RANDOM%1000)) 36 | ORDER_TOTAL=$(($RANDOM%1000)) 37 | CARD_NUMBER=$(awk -v paket1=$(($RANDOM%10000)) -v paket2=$(($RANDOM%10000)) \ 38 | -v paket3=$(($RANDOM%10000)) -v paket4=$(($RANDOM%10000)) \ 39 | 'BEGIN {printf "%04d %04d %04d %04d", paket1, paket2, paket3, paket4}') 40 | CVC=$(awk -v cvc=$(($RANDOM%1000)) 'BEGIN {printf "%03d", cvc}') 41 | MONTH=$(($RANDOM%12+1)) 42 | YEAR=$(($RANDOM%4+$(date +%y)-1)) 43 | EXPIRY_DATE=$(awk -v month="$MONTH" -v year="$YEAR" 'BEGIN {printf "%02d/%02d", month, year}') 44 | 45 | echo $(date +"%Y-%m-%d %H:%M:%S") 'starting with customer' $CUSTOMER_NUMBER ' of order total ' $ORDER_TOTAL ' and payment data' \ 46 | $CARD_NUMBER $CVC $EXPIRY_DATE 47 | 48 | ## start payment process 49 | curl -L "$PROCESS_APP_URL" \ 50 | -X "POST" -H "Content-Type: application/json" \ 51 | -d "{\"customerId\": \"cust$CUSTOMER_NUMBER\", \ 52 | \"orderTotal\": $ORDER_TOTAL, \ 53 | \"cardNumber\": \"$CARD_NUMBER\", \ 54 | \"cvc\": \"$CVC\", \ 55 | \"expiryDate\": \"$EXPIRY_DATE\"}" 56 | 57 | WAIT_TIME=$(awk -v wait_time="$(($RANDOM%20))" 'BEGIN {print wait_time/10}') 58 | echo 'sleeping for' $WAIT_TIME ' seconds ...' 59 | sleep $WAIT_TIME 60 | : 61 | done 62 | 63 | if [ $RUN_FOREVER == "once" ] 64 | then 65 | exit 0 66 | fi 67 | 68 | wait_time_1=$(generate_random_time) 69 | echo "waiting for $wait_time_1 minutes ..." 70 | sleep $((wait_time_1 * 60)) 71 | : 72 | done 73 | -------------------------------------------------------------------------------- /zeebe-client-plain-java/src/main/java/io/camunda/zeebe/example/process/ProcessInstanceWithResultCreator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under 3 | * one or more contributor license agreements. See the NOTICE file distributed 4 | * with this work for additional information regarding copyright ownership. 5 | * Licensed under the Zeebe Community License 1.1. You may not use this file 6 | * except in compliance with the Zeebe Community License 1.1. 7 | */ 8 | package io.camunda.zeebe.example.process; 9 | 10 | import io.camunda.zeebe.client.ZeebeClient; 11 | import io.camunda.zeebe.client.api.response.ProcessInstanceResult; 12 | import io.camunda.zeebe.example.ClientProvider; 13 | import io.camunda.zeebe.example.ClientProvider.AuthMethod; 14 | import java.time.Duration; 15 | import java.util.Map; 16 | 17 | /** 18 | * Example application that connects to a cluster on Camunda Cloud, or a locally deployed cluster. 19 | * 20 | *

It uses {@link ClientProvider} to create a client with the appropriate authentication method. 21 | */ 22 | public class ProcessInstanceWithResultCreator { 23 | public static void main(final String[] args) { 24 | final String bpmnProcessId = "demoProcessSingleTask"; 25 | 26 | try (final ZeebeClient client = ClientProvider.createZeebeClient(AuthMethod.none)) { 27 | 28 | openJobWorker(client); // open job workers so that task are executed and process is completed 29 | System.out.println("Creating process instance"); 30 | 31 | final ProcessInstanceResult processInstanceResult = 32 | client 33 | .newCreateInstanceCommand() 34 | .bpmnProcessId(bpmnProcessId) 35 | .latestVersion() 36 | .withResult() // to await the completion of process execution and return result 37 | .send() 38 | .join(); 39 | 40 | System.out.println( 41 | "Process instance created with key: " 42 | + processInstanceResult.getProcessInstanceKey() 43 | + " and completed with results: " 44 | + processInstanceResult.getVariables()); 45 | } 46 | } 47 | 48 | private static void openJobWorker(final ZeebeClient client) { 49 | client 50 | .newWorker() 51 | .jobType("foo") 52 | .handler( 53 | (jobClient, job) -> 54 | jobClient 55 | .newCompleteCommand(job.getKey()) 56 | .variables(Map.of("job", job.getKey())) 57 | .send()) 58 | .timeout(Duration.ofSeconds(10)) 59 | .open(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /camunda-client-plain-java/src/main/resources/exampleProcess.bpmn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Flow_0g44tbo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | Flow_0xijhu9 14 | Flow_0g44tbo 15 | 16 | 17 | Flow_0xijhu9 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 | -------------------------------------------------------------------------------- /event-processing/src/main/java/com/camunda/consulting/eventprocessing/EventController.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.eventprocessing; 2 | 3 | import static com.camunda.consulting.eventprocessing.Mapper.*; 4 | 5 | import com.camunda.consulting.eventprocessing.EventService.Event; 6 | import com.fasterxml.jackson.databind.JsonNode; 7 | import com.fasterxml.jackson.databind.node.ObjectNode; 8 | import java.time.OffsetDateTime; 9 | import java.util.Optional; 10 | import org.springframework.data.domain.Pageable; 11 | import org.springframework.data.web.PagedModel; 12 | import org.springframework.http.ResponseEntity; 13 | import org.springframework.web.bind.annotation.GetMapping; 14 | import org.springframework.web.bind.annotation.PathVariable; 15 | import org.springframework.web.bind.annotation.PostMapping; 16 | import org.springframework.web.bind.annotation.RequestBody; 17 | import org.springframework.web.bind.annotation.RequestMapping; 18 | import org.springframework.web.bind.annotation.RestController; 19 | 20 | @RestController 21 | @RequestMapping("/events") 22 | public class EventController { 23 | private final EventService eventService; 24 | 25 | public EventController(EventService eventService) { 26 | this.eventService = eventService; 27 | } 28 | 29 | @PostMapping 30 | public ResponseEntity createEvent(@RequestBody CreateEventRequest request) { 31 | return ResponseEntity.ok(map(eventService.saveEvent(map(request)))); 32 | } 33 | 34 | @GetMapping 35 | public ResponseEntity> getEvents(Pageable pageable) { 36 | return ResponseEntity.ok(new PagedModel<>(eventService.getEvents(pageable).map(Mapper::map))); 37 | } 38 | 39 | @GetMapping("/{eventId}") 40 | public ResponseEntity getEvent(@PathVariable String eventId) { 41 | Optional event = eventService.getEvent(eventId); 42 | if (event.isPresent()) { 43 | GetEventResponse response = map(event.get()); 44 | return ResponseEntity.ok(response); 45 | } 46 | return ResponseEntity.notFound().build(); 47 | } 48 | 49 | public record CreateEventRequest(String id, String name, ObjectNode content) {} 50 | 51 | public record CreateEventResponse(String id) {} 52 | 53 | public record GetEventResponse(String id, String name, JsonNode content, State state) { 54 | public record State( 55 | StateName name, 56 | OffsetDateTime createdAt, 57 | OffsetDateTime publishingAt, 58 | OffsetDateTime publishedAt) { 59 | public enum StateName { 60 | CREATED, 61 | PUBLISHING, 62 | PUBLISHED 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /task-micro-frontend/src/main/java/com/camunda/consulting/TaskService.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import com.camunda.consulting.UpdateTaskDto.Data.AssignTaskDto; 4 | import com.camunda.consulting.UpdateTaskDto.Data.CompleteTaskDto; 5 | import com.fasterxml.jackson.core.JsonProcessingException; 6 | import com.fasterxml.jackson.core.type.TypeReference; 7 | import com.fasterxml.jackson.databind.ObjectMapper; 8 | import io.camunda.tasklist.CamundaTaskListClient; 9 | import io.camunda.tasklist.dto.Form; 10 | import io.camunda.tasklist.dto.Task; 11 | import io.camunda.tasklist.exception.TaskListException; 12 | import java.util.Map; 13 | import java.util.Map.Entry; 14 | import java.util.stream.Collectors; 15 | import org.springframework.stereotype.Service; 16 | 17 | @Service 18 | public class TaskService { 19 | private final CamundaTaskListClient camundaTaskListClient; 20 | private final ObjectMapper objectMapper = new ObjectMapper(); 21 | 22 | public TaskService(CamundaTaskListClient camundaTaskListClient) { 23 | this.camundaTaskListClient = camundaTaskListClient; 24 | } 25 | 26 | public TaskDto getTask(String id) { 27 | try { 28 | Task task = camundaTaskListClient.getTask(id); 29 | Form form = camundaTaskListClient.getForm(task.getFormId(), task.getProcessDefinitionKey()); 30 | return new TaskDto( 31 | task.getVariables().stream() 32 | .map(v -> Map.entry(v.getName(), v.getValue())) 33 | .collect(Collectors.toMap(Entry::getKey, Entry::getValue)), 34 | objectMapper.readValue(form.getSchema(), new TypeReference<>() {}), 35 | task.getTaskState().getRawValue()); 36 | } catch (TaskListException | JsonProcessingException e) { 37 | throw new RuntimeException("Error while fetching task", e); 38 | } 39 | } 40 | 41 | public void handleUpdate(String id, UpdateTaskDto content) { 42 | switch (content.data()) { 43 | case CompleteTaskDto complete -> completeTask(id, complete); 44 | 45 | case AssignTaskDto assignTaskDto -> assignTask(id, assignTaskDto); 46 | } 47 | } 48 | 49 | private void assignTask(String id, AssignTaskDto assignTaskDto) { 50 | try { 51 | camundaTaskListClient.claim(id, assignTaskDto.assignee()); 52 | } catch (TaskListException e) { 53 | throw new RuntimeException("Error while assigning task", e); 54 | } 55 | } 56 | 57 | private void completeTask(String id, CompleteTaskDto content) { 58 | try { 59 | camundaTaskListClient.completeTask(id, content.result()); 60 | } catch (TaskListException e) { 61 | throw new RuntimeException("Error while completing task", e); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /task-micro-frontend/src/main/resources/index.html: -------------------------------------------------------------------------------- 1 | 2 | Tasklist micro frontend 3 | 6 | 7 | 13 | 14 | 15 |

16 | 17 |
18 | 19 |
20 | 21 | 22 | 79 | -------------------------------------------------------------------------------- /rollback-on-error-example/README.md: -------------------------------------------------------------------------------- 1 | # Rollback on Error Example 2 | 3 | ## What is the use case? 4 | 5 | ![Rollback Process](./docs/rollback-process.png) 6 | 7 | After a user task, a validation can follow and possibly also saving data to a service. 8 | 9 | These 2 actions might be required to be run synchronous. 10 | 11 | While this was easy in Camunda Platform 7 (just leave out wait states), this is harder to achieve in an asynchronous environment. 12 | 13 | However, it is still possible. 14 | 15 | ## How does it work? 16 | 17 | The user task is activated by a job worker that is then transforming the user task, making it available to a service. 18 | 19 | This service offers the user task and allows its completion. 20 | 21 | On completion, the content of the header `rollbackOnError` is read and parsed to a list of strings, in this example `validateDataType, saveDataType` is parsed to 22 | 23 | ```json 24 | [ 25 | "validateDataType", 26 | "saveDataType" 27 | ] 28 | ``` 29 | 30 | The values of the array are the names of the process variables from which the next tasks read their job type from. 31 | 32 | These values are generated and saved as variables. 33 | 34 | Then, the job workers for the generated variable values are registered. Here, the job workers with the variable name as type are taken and dynamically re-registered. 35 | 36 | Each of them is wrapped, so that a failed task (either by an exception thrown or a fail command) is propagated and the rollback to the initial user task is performed. 37 | 38 | The result of the whole "transaction" is then returned from the method call `complete` (either as `void` or as thrown `RuntimeException`). 39 | 40 | ## How can I try it out? 41 | 42 | Configure the Camunda connection in the `application.yaml`. By default, it points to a plaintext local Camunda instance. 43 | 44 | Then, start the app by running 45 | 46 | ```shell 47 | mvn spring-boot:run 48 | ``` 49 | 50 | On starting up, the example process is deployed. 51 | 52 | After the app is up and running, a process instance can be started with a `POST` to `http://localhost:8080/start`. 53 | 54 | Then, you will be able to retrieve tasks with a `GET` to `http://localhost:8080/task`. 55 | 56 | To complete a task, you can `POST` to `http://localhost:8080/task/{key}/complete`. The body can contain 2 variables: 57 | 58 | ```json 59 | { 60 | "validationFails": true, 61 | "savingFails": true 62 | } 63 | ``` 64 | 65 | If `validationFails` is `true`, the validation task will fail. 66 | 67 | If `savingFails` is `true`, the saving task will fail. 68 | 69 | Both will result in the process instance being rolled back to the user task. 70 | 71 | If one the variables is null, it is not applied and the task succeeds. 72 | -------------------------------------------------------------------------------- /zeebe-client-plain-java/src/main/java/io/camunda/zeebe/example/job/JobWorkerCreator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under 3 | * one or more contributor license agreements. See the NOTICE file distributed 4 | * with this work for additional information regarding copyright ownership. 5 | * Licensed under the Zeebe Community License 1.1. You may not use this file 6 | * except in compliance with the Zeebe Community License 1.1. 7 | */ 8 | package io.camunda.zeebe.example.job; 9 | 10 | import io.camunda.zeebe.client.ZeebeClient; 11 | import io.camunda.zeebe.client.api.response.ActivatedJob; 12 | import io.camunda.zeebe.client.api.worker.JobClient; 13 | import io.camunda.zeebe.client.api.worker.JobHandler; 14 | import io.camunda.zeebe.client.api.worker.JobWorker; 15 | import io.camunda.zeebe.example.ClientProvider; 16 | import io.camunda.zeebe.example.ClientProvider.AuthMethod; 17 | import java.time.Duration; 18 | import java.util.Scanner; 19 | 20 | /** 21 | * Example application that connects to a cluster on Camunda Cloud, or a locally deployed cluster. 22 | * 23 | *

It uses {@link ClientProvider} to create a client with the appropriate authentication method. 24 | */ 25 | public final class JobWorkerCreator { 26 | public static void main(final String[] args) { 27 | final String jobType = "foo"; 28 | 29 | try (final ZeebeClient client = ClientProvider.createZeebeClient(AuthMethod.none)) { 30 | 31 | System.out.println("Opening job worker."); 32 | 33 | try (final JobWorker workerRegistration = 34 | client 35 | .newWorker() 36 | .jobType(jobType) 37 | .handler(new ExampleJobHandler()) 38 | .timeout(Duration.ofSeconds(10)) 39 | .open()) { 40 | System.out.println("Job worker opened and receiving jobs."); 41 | 42 | // run until System.in receives exit command 43 | waitUntilSystemInput("exit"); 44 | } 45 | } 46 | } 47 | 48 | private static void waitUntilSystemInput(final String exitCode) { 49 | try (final Scanner scanner = new Scanner(System.in)) { 50 | while (scanner.hasNextLine()) { 51 | final String nextLine = scanner.nextLine(); 52 | if (nextLine.contains(exitCode)) { 53 | return; 54 | } 55 | } 56 | } 57 | } 58 | 59 | private static class ExampleJobHandler implements JobHandler { 60 | @Override 61 | public void handle(final JobClient client, final ActivatedJob job) { 62 | // here: business logic that is executed with every job 63 | System.out.println(job); 64 | client.newCompleteCommand(job.getKey()).send().join(); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /camunda-client-plain-java/src/main/java/io/camunda/example/data/HandleVariablesAsPojo.java: -------------------------------------------------------------------------------- 1 | package io.camunda.example.data; 2 | 3 | import io.camunda.client.CamundaClient; 4 | import io.camunda.client.api.response.ActivatedJob; 5 | import io.camunda.client.api.worker.JobClient; 6 | import io.camunda.client.api.worker.JobHandler; 7 | import io.camunda.example.ClientProvider; 8 | import io.camunda.example.ClientProvider.AuthMethod; 9 | import java.util.Scanner; 10 | 11 | /** 12 | * Example application that connects to a cluster on Camunda Cloud, or a locally deployed cluster. 13 | * 14 | *

It uses {@link ClientProvider} to create a client with the appropriate authentication method. 15 | */ 16 | public final class HandleVariablesAsPojo { 17 | public static void main(final String[] args) { 18 | try (final CamundaClient client = ClientProvider.createCamundaClient(AuthMethod.none)) { 19 | final Order order = new Order(); 20 | order.setOrderId(31243); 21 | 22 | client 23 | .newCreateInstanceCommand() 24 | .bpmnProcessId("demoProcess") 25 | .latestVersion() 26 | .variables(order) 27 | .execute(); 28 | 29 | client.newWorker().jobType("foo").handler(new DemoJobHandler()).open(); 30 | 31 | // run until System.in receives exit command 32 | waitUntilSystemInput("exit"); 33 | } 34 | } 35 | 36 | private static void waitUntilSystemInput(final String exitCode) { 37 | try (final Scanner scanner = new Scanner(System.in)) { 38 | while (scanner.hasNextLine()) { 39 | final String nextLine = scanner.nextLine(); 40 | if (nextLine.contains(exitCode)) { 41 | return; 42 | } 43 | } 44 | } 45 | } 46 | 47 | public static class Order { 48 | private long orderId; 49 | private double totalPrice; 50 | 51 | public long getOrderId() { 52 | return orderId; 53 | } 54 | 55 | public void setOrderId(final long orderId) { 56 | this.orderId = orderId; 57 | } 58 | 59 | public double getTotalPrice() { 60 | return totalPrice; 61 | } 62 | 63 | public void setTotalPrice(final double totalPrice) { 64 | this.totalPrice = totalPrice; 65 | } 66 | } 67 | 68 | private static class DemoJobHandler implements JobHandler { 69 | @Override 70 | public void handle(final JobClient client, final ActivatedJob job) { 71 | // read the variables of the job 72 | final Order order = job.getVariablesAsType(Order.class); 73 | System.out.println("new job with orderId: " + order.getOrderId()); 74 | 75 | // update the variables and complete the job 76 | order.setTotalPrice(46.50); 77 | 78 | client.newCompleteCommand(job.getKey()).variables(order).send(); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /parallel-operations/src/test/java/com/camunda/consulting/ParallelOperationsAppTest.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting; 2 | 3 | import static org.assertj.core.api.Assertions.*; 4 | import static org.mockito.Mockito.*; 5 | 6 | import io.camunda.client.CamundaClient; 7 | import io.camunda.client.api.response.ProcessInstanceEvent; 8 | import io.camunda.process.test.api.CamundaAssert; 9 | import io.camunda.process.test.api.CamundaSpringProcessTest; 10 | import org.camunda.bpm.engine.HistoryService; 11 | import org.camunda.bpm.engine.RuntimeService; 12 | import org.camunda.bpm.engine.history.HistoricProcessInstance; 13 | import org.camunda.bpm.engine.history.HistoricVariableInstance; 14 | import org.junit.jupiter.api.Test; 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import org.springframework.boot.test.context.SpringBootTest; 17 | import org.springframework.test.context.bean.override.mockito.MockitoBean; 18 | 19 | @SpringBootTest 20 | @CamundaSpringProcessTest 21 | public class ParallelOperationsAppTest { 22 | @Autowired CamundaClient camundaClient; 23 | @Autowired RuntimeService runtimeService; 24 | @Autowired HistoryService historyService; 25 | @MockitoBean StringService stringService; 26 | 27 | @Test 28 | void shouldRun() { 29 | when(stringService.get()).thenReturn("test"); 30 | ProcessInstanceEvent migratedProcess = 31 | camundaClient 32 | .newCreateInstanceCommand() 33 | .bpmnProcessId("MigratedProcessProcess") 34 | .latestVersion() 35 | .send() 36 | .join(); 37 | CamundaAssert.assertThat(migratedProcess) 38 | .isCompleted() 39 | .hasVariable("someText", "test") 40 | .hasVariable("someOtherText", "testtest") 41 | .hasVariable("lastText", "testtesttest") 42 | .hasVariable("callbackId", "test"); 43 | HistoricProcessInstance test = 44 | historyService 45 | .createHistoricProcessInstanceQuery() 46 | .processInstanceBusinessKey("test") 47 | .singleResult(); 48 | assertThat(test).isNotNull(); 49 | assertThat(variableInstance(test.getId(), "someText").getValue()).isEqualTo("test"); 50 | assertThat(variableInstance(test.getId(), "someOtherText").getValue()).isEqualTo("testtest"); 51 | assertThat(variableInstance(test.getId(), "lastText").getValue()).isEqualTo("testtesttest"); 52 | assertThat(variableInstance(test.getId(), "callbackId").getValue()).isEqualTo("test"); 53 | } 54 | 55 | private HistoricVariableInstance variableInstance(String processInstanceId, String variableName) { 56 | return historyService 57 | .createHistoricVariableInstanceQuery() 58 | .processInstanceId(processInstanceId) 59 | .variableName(variableName) 60 | .singleResult(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /react-tasklist/src/main/java/com/camunda/consulting/tasklist/TasklistController.java: -------------------------------------------------------------------------------- 1 | package com.camunda.consulting.tasklist; 2 | 3 | import com.camunda.consulting.tasklist.model.TaskDto; 4 | import com.camunda.consulting.tasklist.model.TaskOverviewDto; 5 | import com.camunda.consulting.tasklist.service.TaskService; 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.http.HttpStatus; 13 | import org.springframework.http.ResponseEntity; 14 | import org.springframework.web.bind.annotation.GetMapping; 15 | import org.springframework.web.bind.annotation.PatchMapping; 16 | import org.springframework.web.bind.annotation.PathVariable; 17 | import org.springframework.web.bind.annotation.RequestBody; 18 | import org.springframework.web.bind.annotation.RequestMapping; 19 | import org.springframework.web.bind.annotation.RequestParam; 20 | import org.springframework.web.bind.annotation.RestController; 21 | import org.springframework.web.client.HttpServerErrorException; 22 | 23 | @RestController 24 | @RequestMapping("/api") 25 | public class TasklistController { 26 | private static final Logger LOG = LoggerFactory.getLogger(TasklistController.class); 27 | private final TaskService taskService; 28 | 29 | @Autowired 30 | public TasklistController(TaskService taskService) { 31 | this.taskService = taskService; 32 | } 33 | 34 | @GetMapping("/tasks/{id}") 35 | public ResponseEntity getTask(@PathVariable("id") String id) { 36 | try { 37 | return ResponseEntity.ok(taskService.getTask(id)); 38 | } catch (NullPointerException e) { 39 | return ResponseEntity.notFound().build(); 40 | } catch (Exception e) { 41 | LOG.error("Error while fetching task", e); 42 | throw new HttpServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage()); 43 | } 44 | } 45 | 46 | @GetMapping("/tasks") 47 | public ResponseEntity> getTasks(@RequestParam(value = "assignedOnly",required = false,defaultValue = "true")boolean assignedOnly) { 48 | 49 | return ResponseEntity.ok(taskService.getTasks(assignedOnly)); 50 | } 51 | 52 | @PatchMapping("/tasks/{id}/complete") 53 | public ResponseEntity completeTask( 54 | @PathVariable("id") String id, @RequestBody Map data) { 55 | try { 56 | taskService.completeTask(id, data); 57 | return ResponseEntity.ok().build(); 58 | } catch (NullPointerException e) { 59 | return ResponseEntity.notFound().build(); 60 | } catch (Exception e){ 61 | LOG.error("Error while fetching task", e); 62 | throw new HttpServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage()); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /zeebe-client-plain-java/src/test/java/io/camunda/zeebe/example/DocsConsistencyTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under 3 | * one or more contributor license agreements. See the NOTICE file distributed 4 | * with this work for additional information regarding copyright ownership. 5 | * Licensed under the Zeebe Community License 1.1. You may not use this file 6 | * except in compliance with the Zeebe Community License 1.1. 7 | */ 8 | package io.camunda.zeebe.example; 9 | 10 | import static org.assertj.core.api.Assertions.assertThat; 11 | 12 | import io.camunda.zeebe.example.cluster.TopologyViewer; 13 | import io.camunda.zeebe.example.data.HandleVariablesAsPojo; 14 | import io.camunda.zeebe.example.decision.EvaluateDecisionCreator; 15 | import io.camunda.zeebe.example.job.JobWorkerCreator; 16 | import io.camunda.zeebe.example.process.NonBlockingProcessInstanceCreator; 17 | import io.camunda.zeebe.example.process.ProcessDeployer; 18 | import io.camunda.zeebe.example.process.ProcessInstanceCreator; 19 | import java.util.Arrays; 20 | import java.util.Collection; 21 | import org.junit.Test; 22 | import org.junit.runner.RunWith; 23 | import org.junit.runners.Parameterized; 24 | import org.junit.runners.Parameterized.Parameter; 25 | import org.junit.runners.Parameterized.Parameters; 26 | 27 | @RunWith(Parameterized.class) 28 | public final class DocsConsistencyTest { 29 | @Parameter(0) 30 | public Class exampleClass; 31 | 32 | @Parameter(1) 33 | public String expectedClassName; 34 | 35 | @Parameters 36 | public static Collection data() { 37 | return Arrays.asList( 38 | new Object[][] { 39 | {TopologyViewer.class, "io.camunda.zeebe.example.cluster.TopologyViewer"}, 40 | {JobWorkerCreator.class, "io.camunda.zeebe.example.job.JobWorkerCreator"}, 41 | { 42 | NonBlockingProcessInstanceCreator.class, 43 | "io.camunda.zeebe.example.process.NonBlockingProcessInstanceCreator" 44 | }, 45 | {ProcessDeployer.class, "io.camunda.zeebe.example.process.ProcessDeployer"}, 46 | {ProcessInstanceCreator.class, "io.camunda.zeebe.example.process.ProcessInstanceCreator"}, 47 | {HandleVariablesAsPojo.class, "io.camunda.zeebe.example.data.HandleVariablesAsPojo"}, 48 | { 49 | EvaluateDecisionCreator.class, 50 | "io.camunda.zeebe.example.decision.EvaluateDecisionCreator" 51 | }, 52 | }); 53 | } 54 | 55 | @Test 56 | public void todo() { 57 | assertThat(exampleClass.getName()) 58 | .withFailMessage( 59 | "This class's source code is referenced from the java-client-example docs. " 60 | + "Make sure to adapt them as well.") 61 | .isEqualTo(expectedClassName); 62 | } 63 | } 64 | --------------------------------------------------------------------------------