├── .gitignore
├── .gitmodules
├── .travis.yml
├── activiti-integration
├── manifest-leader.yml
├── manifest-worker.yml
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── example
│ │ │ ├── DemoApplication.java
│ │ │ ├── LeaderChannels.java
│ │ │ ├── LeaderConfiguration.java
│ │ │ ├── ProcessRestController.java
│ │ │ ├── Profiles.java
│ │ │ ├── WorkerChannels.java
│ │ │ └── WorkerConfiguration.java
│ └── resources
│ │ ├── application-default.properties
│ │ ├── application-leader.properties
│ │ ├── application-worker.properties
│ │ ├── application.properties
│ │ └── processes
│ │ └── async.bpmn20.xml
│ └── test
│ └── java
│ └── com
│ └── example
│ └── DemoApplicationTests.java
├── activiti
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── example
│ │ │ ├── CheckForm.java
│ │ │ ├── Customer.java
│ │ │ ├── CustomerRepository.java
│ │ │ ├── DemoApplication.java
│ │ │ ├── SendConfirmationEmail.java
│ │ │ ├── SignupRestController.java
│ │ │ └── email
│ │ │ ├── EmailValidationService.java
│ │ │ ├── InvalidEmailException.java
│ │ │ ├── MashapeEmailValidationService.java
│ │ │ └── SimpleEmailValidationService.java
│ └── resources
│ │ ├── application.properties
│ │ └── processes
│ │ └── signup.bpmn20.xml
│ └── test
│ └── java
│ └── com
│ └── example
│ ├── EmailValidationServiceTest.java
│ └── SignupRestControllerTests.java
├── batch-and-integration
├── pom.xml
└── src
│ └── main
│ ├── java
│ ├── eda
│ │ ├── IntegrationApplication.java
│ │ └── IntegrationConfiguration.java
│ └── edabatch
│ │ ├── BatchChannels.java
│ │ ├── BatchConfiguration.java
│ │ ├── BatchIntegrationApplication.java
│ │ ├── Contact.java
│ │ ├── EtlFlowConfiguration.java
│ │ ├── FinishedFileFlowConfiguration.java
│ │ ├── InvalidFileFlowConfiguration.java
│ │ ├── JobExecutionListener.java
│ │ ├── Utils.java
│ │ └── email
│ │ ├── EmailValidationService.java
│ │ ├── InvalidEmailException.java
│ │ ├── MashapeEmailValidationService.java
│ │ └── SimpleEmailValidationService.java
│ └── resources
│ ├── application.properties
│ ├── data.csv
│ └── schema.sql
├── batch
├── in.csv
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── processing
│ │ ├── BatchApplication.java
│ │ ├── BatchConfiguration.java
│ │ ├── Person.java
│ │ ├── Step1Configuration.java
│ │ ├── Step2Configuration.java
│ │ ├── Step3Configuration.java
│ │ └── email
│ │ ├── EmailValidationService.java
│ │ ├── InvalidEmailException.java
│ │ ├── MashapeEmailValidationService.java
│ │ └── SimpleEmailValidationService.java
│ └── resources
│ ├── application.properties
│ └── schema.sql
├── dataflow
├── pom.xml
├── server-definitions
│ ├── manifest.yml
│ ├── pom.xml
│ └── src
│ │ └── main
│ │ ├── java
│ │ └── demo
│ │ │ └── DataFlowDefinitionsApplication.java
│ │ └── resources
│ │ └── static
│ │ └── dataflow-example-apps.properties
├── server
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ ├── java
│ │ │ └── dataflow
│ │ │ │ ├── DataFlowInitializer.java
│ │ │ │ └── DataFlowServer.java
│ │ └── resources
│ │ │ ├── application.properties
│ │ │ └── static
│ │ │ ├── app.properties
│ │ │ └── maven-rabbitmq-1.0.1.properties
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── DemoApplicationTests.java
├── shell
│ ├── pom.xml
│ └── src
│ │ └── main
│ │ ├── java
│ │ └── com
│ │ │ └── example
│ │ │ └── ShellApplication.java
│ │ └── resources
│ │ └── application.properties
├── stream-example
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ ├── java
│ │ │ └── stream
│ │ │ │ └── ProcessorStreamExample.java
│ │ └── resources
│ │ │ └── application.properties
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── Stream101ApplicationTests.java
└── task-example
│ ├── pom.xml
│ └── src
│ └── main
│ ├── java
│ └── task
│ │ ├── BatchTaskExample.java
│ │ └── BatchTaskProperties.java
│ └── resources
│ └── application.properties
├── integration-it
├── pom.xml
└── src
│ ├── integration-test
│ ├── java
│ │ └── integration
│ │ │ ├── ActivitiIT.java
│ │ │ ├── DataFlowIT.java
│ │ │ ├── RemotePartitioningIT.java
│ │ │ └── ShakyServiceIT.java
│ └── resources
│ │ └── application.properties
│ ├── main
│ └── java
│ │ └── demo
│ │ └── Main.java
│ └── test
│ └── java
│ └── demo
│ └── RemotePartitionIntegrationTest.java
├── pom.xml
├── remote-partitioning
├── ddl
│ ├── data-init.sql
│ └── schema-init.sql
├── manifest-leader.yml
├── manifest-worker.yml
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── partition
│ │ ├── IdRangePartitioner.java
│ │ ├── JobConfiguration.java
│ │ ├── LeaderChannels.java
│ │ ├── LeaderStepConfiguration.java
│ │ ├── PartitionApplication.java
│ │ ├── PartitionRestController.java
│ │ ├── Person.java
│ │ ├── Profiles.java
│ │ ├── WorkerChannels.java
│ │ ├── WorkerConfiguration.java
│ │ └── WorkerStepConfiguration.java
│ └── resources
│ ├── application-worker.properties
│ ├── application.properties
│ ├── data.sql
│ └── schema.sql
├── shaky-service-to-service-calls
├── pom.xml
├── shaky-client
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ ├── java
│ │ │ └── demo
│ │ │ │ ├── CircuitBreakerGreetingClient.java
│ │ │ │ ├── GreetingClient.java
│ │ │ │ ├── GreetingClientApplication.java
│ │ │ │ └── RetryableGreetingClient.java
│ │ └── resources
│ │ │ └── application.properties
│ │ └── test
│ │ ├── java
│ │ └── demo
│ │ │ ├── AbstractGreetingClientTest.java
│ │ │ ├── CircuitBreakerGreetingClientTest.java
│ │ │ └── RetryableGreetingClientTest.java
│ │ └── resources
│ │ └── application.properties
└── shaky-service
│ ├── pom.xml
│ └── src
│ ├── main
│ └── java
│ │ └── service
│ │ ├── GreetingApplication.java
│ │ └── GreetingServiceRestController.java
│ └── test
│ └── java
│ └── service
│ └── GreetingServiceRestControllerTest.java
├── stream
├── pom.xml
├── stream-consumer
│ ├── pom.xml
│ └── src
│ │ └── main
│ │ ├── java
│ │ └── stream
│ │ │ └── consumer
│ │ │ ├── ConsumerChannels.java
│ │ │ ├── integration
│ │ │ └── StreamConsumer.java
│ │ │ └── listeners
│ │ │ └── StreamConsumer.java
│ │ └── resources
│ │ └── application.properties
└── stream-producer
│ ├── pom.xml
│ └── src
│ └── main
│ ├── java
│ └── stream
│ │ └── producer
│ │ ├── ProducerChannels.java
│ │ ├── channels
│ │ └── StreamProducer.java
│ │ └── gateway
│ │ └── StreamProducer.java
│ └── resources
│ └── application.properties
└── task
├── pom.xml
└── src
└── main
└── java
└── task
└── HelloTask.java
/.gitignore:
--------------------------------------------------------------------------------
1 | #
2 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "build"]
2 | path = build
3 | url = git@github.com:cloud-native-java/build.git
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 |
3 | #sudo: required
4 |
5 | jdk:
6 | - oraclejdk8
7 |
8 | cache:
9 | directories:
10 | - $HOME/.m2/repository/
11 |
12 | script:
13 | - mvn -e -P integration-test verify deploy
14 |
15 |
16 |
--------------------------------------------------------------------------------
/activiti-integration/manifest-leader.yml:
--------------------------------------------------------------------------------
1 | ---
2 | applications:
3 | - name: activiti-leader
4 | instances: 1
5 | buildpack: https://github.com/cloudfoundry/java-buildpack.git
6 | host: activiti-leader-${random-word}
7 | path: target/activiti-integration.jar
8 | services:
9 | - activiti-mysql
10 | - activiti-rabbitmq
11 | env:
12 | DEBUG: "true"
13 | SERVER_PORT: 80
14 | SPRING_PROFILES_ACTIVE: leader, cloud
15 |
--------------------------------------------------------------------------------
/activiti-integration/manifest-worker.yml:
--------------------------------------------------------------------------------
1 | ---
2 | applications:
3 | - name: activiti-worker
4 | instances: 2
5 | host: activiti-worker-${random-word}
6 | buildpack: https://github.com/cloudfoundry/java-buildpack.git
7 | path: target/activiti-integration.jar
8 | services:
9 | - activiti-mysql
10 | - activiti-rabbitmq
11 | env:
12 | DEBUG: "true"
13 | SPRING_PROFILES_ACTIVE: worker, cloud
14 | SERVER_PORT: 80
--------------------------------------------------------------------------------
/activiti-integration/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | 5.19.0
8 |
9 |
10 | cnj
11 | integration
12 | 1.0.0-SNAPSHOT
13 |
14 | integration/activiti-integration
15 | activiti-integration
16 |
17 |
18 | org.codehaus.groovy
19 | groovy-all
20 |
21 |
25 |
26 | com.h2database
27 | h2
28 |
29 |
30 |
31 | org.activiti
32 | activiti-spring-boot-starter-rest-api
33 | ${activiti-spring-boot.version}
34 |
35 |
36 |
41 |
42 | org.springframework.boot
43 | spring-boot-starter-web
44 |
45 |
46 | org.springframework.boot
47 | spring-boot-starter-integration
48 |
49 |
50 | org.springframework.cloud
51 | spring-cloud-starter-stream-rabbit
52 |
53 |
54 | org.springframework.boot
55 | spring-boot-starter-test
56 | test
57 |
58 |
59 |
60 |
61 |
62 |
63 | org.springframework.boot
64 | spring-boot-maven-plugin
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/activiti-integration/src/main/java/com/example/DemoApplication.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import org.activiti.engine.IdentityService;
4 | import org.activiti.engine.identity.Group;
5 | import org.activiti.engine.identity.User;
6 | import org.springframework.beans.factory.InitializingBean;
7 | import org.springframework.boot.SpringApplication;
8 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
9 | import org.springframework.boot.autoconfigure.SpringBootApplication;
10 | import org.springframework.cloud.stream.annotation.EnableBinding;
11 | import org.springframework.context.annotation.Bean;
12 | import org.springframework.context.annotation.Configuration;
13 | import org.springframework.context.annotation.Profile;
14 |
15 | @SpringBootApplication
16 | @EnableAutoConfiguration
17 | public class DemoApplication {
18 |
19 | @Configuration
20 | @Profile(Profiles.LEADER)
21 | @EnableBinding(LeaderChannels.class)
22 | public static class Leader {
23 |
24 | @Bean
25 | InitializingBean init(IdentityService identityService) {
26 | return () -> {
27 |
28 | String usersGroup = "users";
29 | if (0 == identityService.createGroupQuery().groupId(usersGroup).count()) {
30 | Group group = identityService.newGroup(usersGroup);
31 | group.setName(usersGroup);
32 | group.setType("security-role");
33 | identityService.saveGroup(group);
34 | }
35 |
36 | String adminUser = "operator";
37 | if (0 == identityService.createUserQuery().userId(adminUser).count()) {
38 | User admin = identityService.newUser(adminUser);
39 | admin.setPassword(adminUser);
40 | identityService.saveUser(admin);
41 | }
42 | };
43 | }
44 | }
45 |
46 | @Configuration
47 | @Profile(Profiles.WORKER)
48 | @EnableBinding(WorkerChannels.class)
49 | public static class Worker {
50 | }
51 |
52 |
53 | public static void main(String[] args) {
54 | SpringApplication.run(DemoApplication.class, args);
55 | }
56 | }
57 |
58 |
59 |
--------------------------------------------------------------------------------
/activiti-integration/src/main/java/com/example/LeaderChannels.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import org.springframework.cloud.stream.annotation.Input;
4 | import org.springframework.cloud.stream.annotation.Output;
5 | import org.springframework.messaging.MessageChannel;
6 |
7 | public interface LeaderChannels {
8 |
9 | @Output
10 | MessageChannel leaderRequests();
11 |
12 | @Input
13 | MessageChannel leaderReplies();
14 | }
15 |
--------------------------------------------------------------------------------
/activiti-integration/src/main/java/com/example/LeaderConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import org.activiti.engine.ProcessEngine;
4 | import org.activiti.engine.impl.bpmn.behavior.ReceiveTaskActivityBehavior;
5 | import org.activiti.engine.impl.pvm.delegate.ActivityBehavior;
6 | import org.activiti.engine.impl.pvm.delegate.ActivityExecution;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Configuration;
9 | import org.springframework.context.annotation.Profile;
10 | import org.springframework.integration.dsl.IntegrationFlow;
11 | import org.springframework.integration.dsl.IntegrationFlows;
12 | import org.springframework.integration.support.MessageBuilder;
13 | import org.springframework.messaging.Message;
14 |
15 | @Configuration
16 | @Profile(Profiles.LEADER)
17 | class LeaderConfiguration {
18 |
19 | // <1>
20 | @Bean
21 | ActivityBehavior gateway(LeaderChannels channels) {
22 | return new ReceiveTaskActivityBehavior() {
23 |
24 | @Override
25 | public void execute(ActivityExecution execution) throws Exception {
26 |
27 | Message> executionMessage = MessageBuilder
28 | .withPayload(execution.getId())
29 | .build();
30 |
31 | channels.leaderRequests().send(executionMessage);
32 | }
33 | };
34 | }
35 |
36 | // <2>
37 | @Bean
38 | IntegrationFlow repliesFlow(LeaderChannels channels,
39 | ProcessEngine engine) {
40 | return IntegrationFlows
41 | .from(channels.leaderReplies())
42 | .handle(String.class, (executionId, map) -> {
43 | engine.getRuntimeService().signal(executionId);
44 | return null;
45 | })
46 | .get();
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/activiti-integration/src/main/java/com/example/ProcessRestController.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import org.activiti.engine.ProcessEngine;
4 | import org.activiti.engine.runtime.ProcessInstance;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.context.annotation.Profile;
7 | import org.springframework.web.bind.annotation.GetMapping;
8 | import org.springframework.web.bind.annotation.RestController;
9 |
10 | import java.util.Collections;
11 | import java.util.Map;
12 |
13 | @Profile(Profiles.LEADER)
14 | @RestController
15 | class ProcessRestController {
16 |
17 | private final ProcessEngine processEngine;
18 |
19 | @Autowired
20 | ProcessRestController(ProcessEngine processEngine) {
21 | this.processEngine = processEngine;
22 | }
23 |
24 | @GetMapping("/start")
25 | Map launch() {
26 | ProcessInstance pi = this.processEngine.getRuntimeService()
27 | .startProcessInstanceByKey("asyncProcess");
28 | return Collections.singletonMap("processInstanceId", pi .getProcessInstanceId());
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/activiti-integration/src/main/java/com/example/Profiles.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 |
4 | public class Profiles {
5 | public static final String LEADER = "leader";
6 | public static final String WORKER = "worker";
7 | }
8 |
--------------------------------------------------------------------------------
/activiti-integration/src/main/java/com/example/WorkerChannels.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 |
4 | import org.springframework.cloud.stream.annotation.Input;
5 | import org.springframework.cloud.stream.annotation.Output;
6 | import org.springframework.messaging.MessageChannel;
7 |
8 | public interface WorkerChannels {
9 |
10 | @Input
11 | MessageChannel workerRequests();
12 |
13 | @Output
14 | MessageChannel workerReplies();
15 | }
16 |
--------------------------------------------------------------------------------
/activiti-integration/src/main/java/com/example/WorkerConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import org.apache.commons.logging.Log;
4 | import org.apache.commons.logging.LogFactory;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.Configuration;
7 | import org.springframework.context.annotation.Profile;
8 | import org.springframework.integration.dsl.IntegrationFlow;
9 | import org.springframework.integration.dsl.IntegrationFlows;
10 | import org.springframework.integration.dsl.support.GenericHandler;
11 |
12 |
13 | @Configuration
14 | @Profile(Profiles.WORKER)
15 | class WorkerConfiguration {
16 |
17 | @Bean
18 | IntegrationFlow requestsFlow(WorkerChannels channels) {
19 |
20 | Log log = LogFactory.getLog(getClass());
21 |
22 | // <1>
23 | return IntegrationFlows
24 | .from(channels.workerRequests())
25 | .handle((GenericHandler) (executionId, headers) -> {
26 | // <2>
27 | headers
28 | .entrySet()
29 | .forEach(e -> log.info(e.getKey() + '=' + e.getValue()));
30 | log.info("sending executionId (" + executionId + ") to workerReplies.");
31 | return executionId;
32 | })
33 | .channel(channels.workerReplies()) // <3>
34 | .get();
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/activiti-integration/src/main/resources/application-default.properties:
--------------------------------------------------------------------------------
1 | ## MySQL DB
2 | #
3 | #spring.datasource.url=jdbc:mysql://localhost:3306/batch?useSSL=false
4 | #spring.datasource.password=batch
5 | #spring.datasource.username=batch
6 |
--------------------------------------------------------------------------------
/activiti-integration/src/main/resources/application-leader.properties:
--------------------------------------------------------------------------------
1 | server.port=8080
2 |
3 | # leader node channels
4 | spring.cloud.stream.bindings.leaderRequests.destination=${as}-requests
5 | spring.cloud.stream.bindings.leaderReplies.destination=${as}-replies
6 | spring.cloud.stream.bindings.leaderReplies.group=${as}-replies
7 | spring.cloud.stream.bindings.leaderReplies.durableSubscription=true
8 |
--------------------------------------------------------------------------------
/activiti-integration/src/main/resources/application-worker.properties:
--------------------------------------------------------------------------------
1 | server.port=0
2 |
3 | # worker node channels
4 | spring.cloud.stream.bindings.workerReplies.destination=${as}-replies
5 | spring.cloud.stream.bindings.workerRequests.destination=${as}-requests
6 | spring.cloud.stream.bindings.workerRequests.group=${as}-requests
7 | spring.cloud.stream.bindings.workerRequests.durableSubscription=true
8 |
--------------------------------------------------------------------------------
/activiti-integration/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 |
2 | # channel definitions
3 | as=activiti-signup
4 |
5 | spring.jpa.hibernate.ddl-auto=update
6 |
--------------------------------------------------------------------------------
/activiti-integration/src/main/resources/processes/async.bpmn20.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/activiti-integration/src/test/java/com/example/DemoApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.SpringApplicationConfiguration;
6 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
7 |
8 | @RunWith(SpringJUnit4ClassRunner.class)
9 | @SpringApplicationConfiguration(classes = DemoApplication.class)
10 | public class DemoApplicationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/activiti/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | 5.19.0
8 |
9 |
10 | cnj
11 | integration
12 | 1.0.0-SNAPSHOT
13 |
14 | integration/activiti
15 | activiti
16 |
17 |
18 | org.codehaus.groovy
19 | groovy-all
20 |
21 |
22 | com.h2database
23 | h2
24 |
25 |
26 | org.activiti
27 | activiti-spring-boot-starter-basic
28 | ${activiti-spring-boot.version}
29 |
30 |
35 |
36 |
37 | org.springframework.retry
38 | spring-retry
39 |
40 |
41 |
42 | org.springframework.boot
43 | spring-boot-starter-web
44 |
45 |
46 | org.springframework.boot
47 | spring-boot-starter-data-jpa
48 |
49 |
50 | org.springframework.boot
51 | spring-boot-starter-test
52 | test
53 |
54 |
55 |
56 |
57 |
58 | org.springframework.boot
59 | spring-boot-maven-plugin
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/activiti/src/main/java/com/example/CheckForm.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import com.example.email.EmailValidationService;
4 | import org.activiti.engine.RuntimeService;
5 | import org.activiti.engine.impl.pvm.delegate.ActivityExecution;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.stereotype.Service;
8 |
9 | import java.util.Collections;
10 | import java.util.Map;
11 |
12 | import static org.apache.commons.lang3.StringUtils.isEmpty;
13 |
14 | @Service
15 | class CheckForm {
16 |
17 | private final RuntimeService runtimeService; // <1>
18 | private final CustomerRepository customerRepository;
19 | private final EmailValidationService emailValidationService;
20 |
21 | @Autowired
22 | public CheckForm(EmailValidationService emailValidationService,
23 | RuntimeService runtimeService, CustomerRepository customerRepository) {
24 | this.runtimeService = runtimeService;
25 | this.customerRepository = customerRepository;
26 | this.emailValidationService = emailValidationService;
27 | }
28 |
29 | // <2>
30 | public void execute(ActivityExecution e) throws Exception {
31 | Long customerId = Long.parseLong(e.getVariable("customerId",
32 | String.class));
33 | Map vars = Collections.singletonMap("formOK",
34 | validated(this.customerRepository.findOne(customerId)));
35 | this.runtimeService.setVariables(e.getId(), vars); // <3>
36 | }
37 |
38 | private boolean validated(Customer customer) {
39 | return !isEmpty(customer.getFirstName())
40 | && !isEmpty(customer.getLastName())
41 | && this.emailValidationService
42 | .isEmailValid(customer.getEmail());
43 | }
44 |
45 | }
--------------------------------------------------------------------------------
/activiti/src/main/java/com/example/Customer.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import javax.persistence.Entity;
4 | import javax.persistence.GeneratedValue;
5 | import javax.persistence.Id;
6 |
7 | @Entity
8 | public class Customer {
9 |
10 | @Id
11 | @GeneratedValue
12 | private Long id;
13 | private String firstName, lastName;
14 | private String email;
15 |
16 | Customer() {
17 | }
18 |
19 | public void setFirstName(String firstName) {
20 | this.firstName = firstName;
21 | }
22 |
23 | public void setLastName(String lastName) {
24 | this.lastName = lastName;
25 | }
26 |
27 | public void setEmail(String email) {
28 | this.email = email;
29 | }
30 |
31 | public Long getId() {
32 |
33 | return id;
34 | }
35 |
36 | public String getFirstName() {
37 | return firstName;
38 | }
39 |
40 | public String getLastName() {
41 | return lastName;
42 | }
43 |
44 | public String getEmail() {
45 | return email;
46 | }
47 |
48 | public Customer(String firstName, String lastName, String email) {
49 | this.firstName = firstName;
50 | this.lastName = lastName;
51 | this.email = email;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/activiti/src/main/java/com/example/CustomerRepository.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import org.springframework.data.jpa.repository.JpaRepository;
4 |
5 | import java.util.Optional;
6 |
7 | public interface CustomerRepository extends JpaRepository {
8 |
9 | Optional findByEmail(String e);
10 | }
11 |
--------------------------------------------------------------------------------
/activiti/src/main/java/com/example/DemoApplication.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.retry.annotation.EnableRetry;
7 | import org.springframework.web.client.RestTemplate;
8 |
9 | @SpringBootApplication
10 | public class DemoApplication {
11 |
12 | @Bean
13 | RestTemplate restTemplate() {
14 | return new RestTemplate();
15 | }
16 |
17 | public static void main(String[] args) {
18 | SpringApplication.run(DemoApplication.class, args);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/activiti/src/main/java/com/example/SendConfirmationEmail.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import org.activiti.engine.impl.pvm.delegate.ActivityExecution;
4 | import org.apache.commons.logging.Log;
5 | import org.apache.commons.logging.LogFactory;
6 | import org.springframework.stereotype.Service;
7 |
8 | @Service
9 | class SendConfirmationEmail {
10 |
11 | private Log log = LogFactory.getLog(getClass());
12 |
13 | public void execute(ActivityExecution execution) throws Exception {
14 | this.log.info("in " + getClass().getName() + ", customerId = "
15 | + execution.getVariable("customerId"));
16 | // exercise to reader: send an email, perhaps
17 | // using Sendgrid?
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/activiti/src/main/java/com/example/SignupRestController.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import org.activiti.engine.RuntimeService;
4 | import org.activiti.engine.TaskService;
5 | import org.activiti.engine.task.TaskInfo;
6 | import org.apache.commons.logging.Log;
7 | import org.apache.commons.logging.LogFactory;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.http.ResponseEntity;
10 | import org.springframework.util.Assert;
11 | import org.springframework.web.bind.annotation.*;
12 |
13 | import java.util.Collections;
14 | import java.util.List;
15 | import java.util.stream.Collectors;
16 |
17 | @RestController
18 | @RequestMapping("/customers")
19 | class SignupRestController {
20 |
21 | public static final String CUSTOMER_ID_PV_KEY = "customerId";
22 |
23 | private final RuntimeService runtimeService;
24 | private final TaskService taskService;
25 | private final CustomerRepository customerRepository;
26 | private Log log = LogFactory.getLog(getClass());
27 |
28 | // <1>
29 | @Autowired
30 | public SignupRestController(RuntimeService runtimeService,
31 | TaskService taskService, CustomerRepository repository) {
32 | this.runtimeService = runtimeService;
33 | this.taskService = taskService;
34 | this.customerRepository = repository;
35 | }
36 |
37 | // <2>
38 | @PostMapping
39 | public ResponseEntity> startProcess(@RequestBody Customer customer) {
40 | Assert.notNull(customer);
41 | Customer save = this.customerRepository.save(new Customer(customer
42 | .getFirstName(), customer.getLastName(), customer.getEmail()));
43 |
44 | String processInstanceId = this.runtimeService
45 | .startProcessInstanceByKey(
46 | "signup",
47 | Collections.singletonMap(CUSTOMER_ID_PV_KEY,
48 | Long.toString(save.getId()))).getId();
49 | this.log.info("started sign-up. the processInstance ID is "
50 | + processInstanceId);
51 |
52 | return ResponseEntity.ok(save.getId());
53 | }
54 |
55 | // <3>
56 | @GetMapping("/{customerId}/signup/errors")
57 | public List readErrors(@PathVariable String customerId) {
58 | // @formatter:off
59 | return this.taskService
60 | .createTaskQuery()
61 | .active()
62 | .taskName("fix-errors")
63 | .includeProcessVariables()
64 | .processVariableValueEquals(CUSTOMER_ID_PV_KEY, customerId)
65 | .list()
66 | .stream()
67 | .map(TaskInfo::getId)
68 | .collect(Collectors.toList());
69 | // @formatter:on
70 | }
71 |
72 | // <4>
73 | @PostMapping("/{customerId}/signup/errors/{taskId}")
74 | public void fixErrors(@PathVariable String customerId,
75 | @PathVariable String taskId, @RequestBody Customer fixedCustomer) {
76 |
77 | Customer customer = this.customerRepository.findOne(Long
78 | .parseLong(customerId));
79 | customer.setEmail(fixedCustomer.getEmail());
80 | customer.setFirstName(fixedCustomer.getFirstName());
81 | customer.setLastName(fixedCustomer.getLastName());
82 | this.customerRepository.save(customer);
83 |
84 | this.taskService
85 | .createTaskQuery()
86 | .active()
87 | .taskId(taskId)
88 | .includeProcessVariables()
89 | .processVariableValueEquals(CUSTOMER_ID_PV_KEY, customerId)
90 | .list()
91 | .forEach(
92 | t -> {
93 | log.info("fixing customer# " + customerId
94 | + " for taskId " + taskId);
95 | taskService.complete(t.getId(),
96 | Collections.singletonMap("formOK", true));
97 | });
98 | }
99 |
100 | // <5>
101 | @PostMapping("/{customerId}/signup/confirmation")
102 | public void confirm(@PathVariable String customerId) {
103 | this.taskService
104 | .createTaskQuery()
105 | .active()
106 | .taskName("confirm-email")
107 | .includeProcessVariables()
108 | .processVariableValueEquals(CUSTOMER_ID_PV_KEY, customerId)
109 | .list().forEach(t -> {
110 | log.info(t.toString());
111 | taskService.complete(t.getId());
112 | });
113 | this.log.info("confirmed email receipt for " + customerId);
114 | }
115 | }
--------------------------------------------------------------------------------
/activiti/src/main/java/com/example/email/EmailValidationService.java:
--------------------------------------------------------------------------------
1 | package com.example.email;
2 |
3 | public interface EmailValidationService {
4 | boolean isEmailValid(String email);
5 | }
6 |
--------------------------------------------------------------------------------
/activiti/src/main/java/com/example/email/InvalidEmailException.java:
--------------------------------------------------------------------------------
1 | package com.example.email;
2 |
3 | public class InvalidEmailException extends Exception {
4 | public InvalidEmailException(String email) {
5 | super(String.format("the email %s isn't valid", email));
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/activiti/src/main/java/com/example/email/MashapeEmailValidationService.java:
--------------------------------------------------------------------------------
1 | package com.example.email;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.beans.factory.annotation.Value;
5 | import org.springframework.context.annotation.Profile;
6 | import org.springframework.core.ParameterizedTypeReference;
7 | import org.springframework.http.RequestEntity;
8 | import org.springframework.http.ResponseEntity;
9 | import org.springframework.stereotype.Service;
10 | import org.springframework.web.client.RestTemplate;
11 | import org.springframework.web.util.UriComponents;
12 | import org.springframework.web.util.UriComponentsBuilder;
13 |
14 | import java.util.Map;
15 |
16 | @Service
17 | @Profile("production")
18 | class MashapeEmailValidationService implements EmailValidationService {
19 |
20 | private final String mashapeKey;
21 | private final RestTemplate restTemplate;
22 | private final String uri;
23 |
24 | @Autowired
25 | public MashapeEmailValidationService(
26 | @Value("${mashape.key}") String key,
27 | @Value("${email-validator.uri}") String uri,
28 | RestTemplate restTemplate) {
29 | this.mashapeKey = key;
30 | this.uri = uri;
31 | this.restTemplate = restTemplate;
32 | }
33 |
34 | public boolean isEmailValid(String email) {
35 | UriComponents emailValidatedUri = UriComponentsBuilder.fromHttpUrl(uri)
36 | .buildAndExpand(email);
37 |
38 | RequestEntity requestEntity = RequestEntity
39 | .get(emailValidatedUri.toUri())
40 | .header("X-Mashape-Key", mashapeKey).build();
41 |
42 | ParameterizedTypeReference