├── barista
├── src
│ ├── test
│ │ ├── resources
│ │ │ ├── spring.properties
│ │ │ ├── application-contracts.yml
│ │ │ ├── contracts
│ │ │ │ ├── shouldSendError.groovy
│ │ │ │ └── shouldSendServing.groovy
│ │ │ └── application-integration.yml
│ │ └── java
│ │ │ └── io
│ │ │ └── spring
│ │ │ └── barcelona
│ │ │ └── coffee
│ │ │ └── barista
│ │ │ └── BaseTestClass.java
│ └── main
│ │ ├── resources
│ │ └── application.yml
│ │ └── java
│ │ └── io
│ │ └── spring
│ │ └── barcelona
│ │ └── coffee
│ │ └── barista
│ │ ├── coffee
│ │ ├── BrewingDevice.java
│ │ ├── Alternative.java
│ │ ├── Coffees.java
│ │ ├── Traditional.java
│ │ └── Coffee.java
│ │ ├── exceptions
│ │ └── CoffeeNotAvailableException.java
│ │ ├── orders
│ │ ├── Order.java
│ │ └── OrderEntry.java
│ │ ├── service
│ │ ├── Serving.java
│ │ ├── CoffeeService.java
│ │ ├── Beverage.java
│ │ └── KafkaHandler.java
│ │ └── BaristaApplication.java
├── .mvn
│ └── wrapper
│ │ ├── maven-wrapper.jar
│ │ └── maven-wrapper.properties
├── .gitignore
├── docker-compose.yml
├── pom.xml
├── mvnw.cmd
└── mvnw
├── waiter
├── .mvn
│ └── wrapper
│ │ ├── maven-wrapper.jar
│ │ └── maven-wrapper.properties
├── src
│ ├── main
│ │ ├── resources
│ │ │ └── application.yml
│ │ └── java
│ │ │ └── io
│ │ │ └── spring
│ │ │ └── barcelona
│ │ │ └── coffee
│ │ │ └── waiter
│ │ │ ├── coffee
│ │ │ ├── BrewingDevice.java
│ │ │ ├── Alternative.java
│ │ │ ├── Traditional.java
│ │ │ └── Coffee.java
│ │ │ ├── orders
│ │ │ ├── Order.java
│ │ │ └── OrderEntry.java
│ │ │ ├── service
│ │ │ ├── Serving.java
│ │ │ └── Beverage.java
│ │ │ ├── controller
│ │ │ └── OrderController.java
│ │ │ └── WaiterApplication.java
│ └── test
│ │ ├── resources
│ │ ├── application-contracts.yml
│ │ └── application-integration.yml
│ │ └── java
│ │ └── io
│ │ └── spring
│ │ └── barcelona
│ │ └── coffee
│ │ └── waiter
│ │ ├── TestApplication.java
│ │ ├── ContainersConfig.java
│ │ └── WaiterApplicationIntegrationTests.java
├── .gitignore
├── pom.xml
├── mvnw.cmd
└── mvnw
├── .idea
├── vcs.xml
├── jpa-buddy.xml
├── .gitignore
├── aws.xml
├── encodings.xml
├── libraries
│ ├── Maven__org_springframework_spring_tx_6_0_8_SNAPSHOT.xml
│ ├── Maven__org_springframework_spring_aop_6_0_8_SNAPSHOT.xml
│ ├── Maven__org_springframework_spring_jcl_6_0_8_SNAPSHOT.xml
│ ├── Maven__org_springframework_spring_web_6_0_8_SNAPSHOT.xml
│ ├── Maven__org_springframework_spring_core_6_0_8_SNAPSHOT.xml
│ ├── Maven__org_springframework_spring_test_6_0_8_SNAPSHOT.xml
│ ├── Maven__org_springframework_spring_beans_6_0_8_SNAPSHOT.xml
│ ├── Maven__org_springframework_spring_webmvc_6_0_8_SNAPSHOT.xml
│ ├── Maven__org_springframework_spring_context_6_0_8_SNAPSHOT.xml
│ ├── Maven__org_springframework_spring_messaging_6_0_8_SNAPSHOT.xml
│ └── Maven__org_springframework_spring_expression_6_0_8_SNAPSHOT.xml
├── compiler.xml
├── misc.xml
├── jarRepositories.xml
└── uiDesigner.xml
├── .gitignore
├── pom.xml
└── README.md
/barista/src/test/resources/spring.properties:
--------------------------------------------------------------------------------
1 | spring.test.context.failure.threshold = 10
--------------------------------------------------------------------------------
/barista/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OlgaMaciaszek/coffee/HEAD/barista/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/waiter/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OlgaMaciaszek/coffee/HEAD/waiter/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/barista/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | kafka:
3 | producer:
4 | value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/jpa-buddy.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/waiter/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8081
3 | spring:
4 | main:
5 | allow-circular-references: true
6 | kafka:
7 | producer:
8 | value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
9 |
--------------------------------------------------------------------------------
/barista/src/main/java/io/spring/barcelona/coffee/barista/coffee/BrewingDevice.java:
--------------------------------------------------------------------------------
1 | package io.spring.barcelona.coffee.barista.coffee;
2 |
3 | /**
4 | * @author Olga Maciaszek-Sharma
5 | */
6 | public enum BrewingDevice {
7 |
8 | V60, CHEMEX, AERO_PRESS;
9 | }
10 |
--------------------------------------------------------------------------------
/waiter/src/main/java/io/spring/barcelona/coffee/waiter/coffee/BrewingDevice.java:
--------------------------------------------------------------------------------
1 | package io.spring.barcelona.coffee.waiter.coffee;
2 |
3 | /**
4 | * @author Olga Maciaszek-Sharma
5 | */
6 | public enum BrewingDevice {
7 |
8 | V60, CHEMEX, AERO_PRESS;
9 | }
10 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 | # Datasource local storage ignored files
7 | /dataSources/
8 | /dataSources.local.xml
9 | # Zeppelin ignored files
10 | /ZeppelinRemoteNotebooks/
11 |
--------------------------------------------------------------------------------
/.idea/aws.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
--------------------------------------------------------------------------------
/waiter/src/test/resources/application-contracts.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | lifecycle:
3 | timeout-per-shutdown-phase: 1s
4 | kafka:
5 | consumer:
6 | properties:
7 | "key.serializer": "org.springframework.kafka.support.serializer.JsonSerializer"
8 | "key.deserializer": "org.springframework.kafka.support.serializer.JsonDeserializer"
9 | group-id: groupId
--------------------------------------------------------------------------------
/barista/src/test/resources/application-contracts.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | lifecycle:
3 | timeout-per-shutdown-phase: 1s
4 | kafka:
5 | consumer:
6 | properties:
7 | "key.serializer": "org.springframework.kafka.support.serializer.JsonSerializer"
8 | "key.deserializer": "org.springframework.kafka.support.serializer.JsonDeserializer"
9 | group-id: groupId
--------------------------------------------------------------------------------
/waiter/src/test/resources/application-integration.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | lifecycle:
3 | timeout-per-shutdown-phase: 1s
4 | kafka:
5 | consumer:
6 | properties:
7 | "key.serializer": "org.springframework.kafka.support.serializer.JsonSerializer"
8 | "key.deserializer": "org.springframework.kafka.support.serializer.JsonDeserializer"
9 | group-id: groupId
--------------------------------------------------------------------------------
/waiter/src/test/java/io/spring/barcelona/coffee/waiter/TestApplication.java:
--------------------------------------------------------------------------------
1 | package io.spring.barcelona.coffee.waiter;
2 |
3 | import org.springframework.boot.SpringApplication;
4 |
5 | public class TestApplication {
6 | public static void main(String[] args) {
7 | SpringApplication
8 | .from(WaiterApplication::main)
9 | .with(ContainersConfig.class)
10 | .run(args);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/barista/src/main/java/io/spring/barcelona/coffee/barista/exceptions/CoffeeNotAvailableException.java:
--------------------------------------------------------------------------------
1 | package io.spring.barcelona.coffee.barista.exceptions;
2 |
3 | /**
4 | * @author Olga Maciaszek-Sharma
5 | */
6 | public class CoffeeNotAvailableException extends RuntimeException {
7 |
8 | public CoffeeNotAvailableException(String coffeeName) {
9 | super("We currently do not have the following coffee in our menu: " + coffeeName);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/barista/src/test/resources/contracts/shouldSendError.groovy:
--------------------------------------------------------------------------------
1 | package contracts
2 |
3 | import org.springframework.cloud.contract.spec.Contract
4 |
5 | /**
6 | * @author Olga Maciaszek-Sharma
7 | */
8 |
9 | Contract.make {
10 | label("error")
11 | input {
12 | triggeredBy("triggerError()")
13 | }
14 | outputMessage {
15 | sentTo("errors")
16 | body([
17 | message: "We currently do not have the following coffee in our menu: expresso"
18 | ])
19 | }
20 | }
--------------------------------------------------------------------------------
/barista/src/test/resources/application-integration.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | lifecycle:
3 | timeout-per-shutdown-phase: 1s
4 | kafka:
5 | producer:
6 | value-serializer: io.spring.barcelona.coffee.barista.config.CustomSerializer
7 | consumer:
8 | properties:
9 | "key.serializer": "org.springframework.kafka.support.serializer.JsonSerializer"
10 | "key.deserializer": "org.springframework.kafka.support.serializer.JsonDeserializer"
11 | group-id: groupId
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**/target/
5 | !**/src/test/**/target/
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 | !**/src/main/**/build/
30 | !**/src/test/**/build/
31 |
32 | ### VS Code ###
33 | .vscode/
34 |
--------------------------------------------------------------------------------
/waiter/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**/target/
5 | !**/src/test/**/target/
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 | !**/src/main/**/build/
30 | !**/src/test/**/build/
31 |
32 | ### VS Code ###
33 | .vscode/
34 |
--------------------------------------------------------------------------------
/barista/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**/target/
5 | !**/src/test/**/target/
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 | !**/src/main/**/build/
30 | !**/src/test/**/build/
31 |
32 | ### VS Code ###
33 | .vscode/
34 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/barista/src/main/java/io/spring/barcelona/coffee/barista/orders/Order.java:
--------------------------------------------------------------------------------
1 | package io.spring.barcelona.coffee.barista.orders;
2 |
3 | import java.util.HashSet;
4 | import java.util.Set;
5 |
6 | /**
7 | * @author Olga Maciaszek-Sharma
8 | */
9 | public class Order {
10 |
11 | private Set entries = new HashSet<>();
12 |
13 | public void add(OrderEntry orderEntry) {
14 | entries.add(orderEntry);
15 | }
16 |
17 | public Set getEntries() {
18 | return entries;
19 | }
20 |
21 | @Override
22 | public String toString() {
23 | return "Order{" +
24 | "entries=" + entries +
25 | '}';
26 | }
27 | }
--------------------------------------------------------------------------------
/waiter/src/main/java/io/spring/barcelona/coffee/waiter/orders/Order.java:
--------------------------------------------------------------------------------
1 | package io.spring.barcelona.coffee.waiter.orders;
2 |
3 | import java.util.HashSet;
4 | import java.util.Set;
5 |
6 | /**
7 | * @author Olga Maciaszek-Sharma
8 | */
9 | public class Order {
10 |
11 | private Set entries = new HashSet<>();
12 |
13 | public void add(OrderEntry orderEntry) {
14 | entries.add(orderEntry);
15 | }
16 |
17 | public Set getEntries() {
18 | return entries;
19 | }
20 |
21 | @Override
22 | public String toString() {
23 | return "Order{" +
24 | "entries=" + entries +
25 | '}';
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/waiter/src/main/java/io/spring/barcelona/coffee/waiter/service/Serving.java:
--------------------------------------------------------------------------------
1 | package io.spring.barcelona.coffee.waiter.service;
2 |
3 | import java.util.HashSet;
4 | import java.util.Set;
5 |
6 | /**
7 | * @author Olga Maciaszek-Sharma
8 | */
9 | public class Serving {
10 |
11 | private final Set beverages = new HashSet<>();
12 |
13 | Serving() {
14 | }
15 |
16 | public void add(Beverage beverage) {
17 | beverages.add(beverage);
18 | }
19 |
20 | public Set getBeverages() {
21 | return beverages;
22 | }
23 |
24 | @Override
25 | public String toString() {
26 | return "Serving{" +
27 | "beverages=" + beverages +
28 | '}';
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/barista/src/main/java/io/spring/barcelona/coffee/barista/service/Serving.java:
--------------------------------------------------------------------------------
1 | package io.spring.barcelona.coffee.barista.service;
2 |
3 | import java.util.HashSet;
4 | import java.util.Set;
5 |
6 | /**
7 | * @author Olga Maciaszek-Sharma
8 | */
9 | public class Serving {
10 |
11 | private final Set beverages = new HashSet<>();
12 |
13 | Serving() {
14 | }
15 |
16 | public void add(Beverage beverage) {
17 | beverages.add(beverage);
18 | }
19 |
20 | public Set getBeverages() {
21 | return beverages;
22 | }
23 |
24 | @Override
25 | public String toString() {
26 | return "Serving{" +
27 | "beverages=" + beverages +
28 | '}';
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | io.spring.barcelona
8 | coffee
9 | pom
10 | 0.0.1-SNAPSHOT
11 |
12 | Coffee
13 | Spring Cloud Contract and Testcontainers sample repo
14 |
15 |
16 | barista
17 | waiter
18 |
19 |
20 |
--------------------------------------------------------------------------------
/waiter/src/test/java/io/spring/barcelona/coffee/waiter/ContainersConfig.java:
--------------------------------------------------------------------------------
1 | package io.spring.barcelona.coffee.waiter;
2 |
3 | import org.springframework.boot.test.context.TestConfiguration;
4 | import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
5 | import org.springframework.context.annotation.Bean;
6 | import org.testcontainers.containers.KafkaContainer;
7 | import org.testcontainers.utility.DockerImageName;
8 |
9 | @TestConfiguration(proxyBeanMethods = false)
10 | public class ContainersConfig {
11 |
12 | @Bean
13 | @ServiceConnection
14 | public KafkaContainer getKafka() {
15 |
16 | return new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka"));
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_springframework_spring_tx_6_0_8_SNAPSHOT.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_springframework_spring_aop_6_0_8_SNAPSHOT.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_springframework_spring_jcl_6_0_8_SNAPSHOT.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_springframework_spring_web_6_0_8_SNAPSHOT.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_springframework_spring_core_6_0_8_SNAPSHOT.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_springframework_spring_test_6_0_8_SNAPSHOT.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_springframework_spring_beans_6_0_8_SNAPSHOT.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/waiter/src/main/java/io/spring/barcelona/coffee/waiter/orders/OrderEntry.java:
--------------------------------------------------------------------------------
1 | package io.spring.barcelona.coffee.waiter.orders;
2 |
3 | /**
4 | * @author Olga Maciaszek-Sharma
5 | */
6 | public class OrderEntry {
7 |
8 | private final String beverageName;
9 | private final int count;
10 |
11 | public OrderEntry(String beverageName, int count) {
12 | this.beverageName = beverageName;
13 | this.count = count;
14 | }
15 |
16 | public String getBeverageName() {
17 | return beverageName;
18 | }
19 |
20 | public int getCount() {
21 | return count;
22 | }
23 |
24 | @Override
25 | public String toString() {
26 | return "OrderEntry{" +
27 | "beverageName='" + beverageName + '\'' +
28 | ", count=" + count +
29 | '}';
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_springframework_spring_webmvc_6_0_8_SNAPSHOT.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/barista/src/main/java/io/spring/barcelona/coffee/barista/coffee/Alternative.java:
--------------------------------------------------------------------------------
1 | package io.spring.barcelona.coffee.barista.coffee;
2 |
3 | /**
4 | * @author Olga Maciaszek-Sharma
5 | */
6 | public class Alternative extends Coffee {
7 |
8 | private BrewingDevice device;
9 |
10 | Alternative() {
11 | }
12 |
13 | Alternative(String name, int coffeeContent, BrewingDevice device) {
14 | super(name, coffeeContent);
15 | this.device = device;
16 | }
17 |
18 | public BrewingDevice getDevice() {
19 | return device;
20 | }
21 |
22 | @Override
23 | public String toString() {
24 | return "Alternative Coffee{" +
25 | "name='" + getName() + '\'' +
26 | ", coffeeContent=" + getCoffeeContent() +
27 | ", device=" + device +
28 | '}';
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/waiter/src/main/java/io/spring/barcelona/coffee/waiter/coffee/Alternative.java:
--------------------------------------------------------------------------------
1 | package io.spring.barcelona.coffee.waiter.coffee;
2 |
3 | /**
4 | * @author Olga Maciaszek-Sharma
5 | */
6 | public class Alternative extends Coffee {
7 |
8 | private BrewingDevice device;
9 |
10 | Alternative() {
11 | }
12 |
13 | Alternative(String name, int coffeeContent, BrewingDevice device) {
14 | super(name, coffeeContent);
15 | this.device = device;
16 | }
17 |
18 | public BrewingDevice getDevice() {
19 | return device;
20 | }
21 |
22 | @Override
23 | public String toString() {
24 | return "Alternative Coffee{" +
25 | "name='" + getName() + '\'' +
26 | ", coffeeContent=" + getCoffeeContent() +
27 | ", device=" + device +
28 | '}';
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_springframework_spring_context_6_0_8_SNAPSHOT.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/barista/src/main/java/io/spring/barcelona/coffee/barista/orders/OrderEntry.java:
--------------------------------------------------------------------------------
1 | package io.spring.barcelona.coffee.barista.orders;
2 |
3 | /**
4 | * @author Olga Maciaszek-Sharma
5 | */
6 | public class OrderEntry {
7 |
8 | private String beverageName;
9 | private int count;
10 |
11 | OrderEntry() {
12 | }
13 |
14 | public OrderEntry(String beverageName, int count) {
15 | this.beverageName = beverageName;
16 | this.count = count;
17 | }
18 |
19 | public String getBeverageName() {
20 | return beverageName;
21 | }
22 |
23 | public int getCount() {
24 | return count;
25 | }
26 |
27 | @Override
28 | public String toString() {
29 | return "OrderEntry{" +
30 | "beverageName='" + beverageName + '\'' +
31 | ", count=" + count +
32 | '}';
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_springframework_spring_messaging_6_0_8_SNAPSHOT.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/libraries/Maven__org_springframework_spring_expression_6_0_8_SNAPSHOT.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Coffee Demo App
2 |
3 | Both apps are producers and consumers at the same time, but for the purposes of the demo, producer side contract testing is set up for `barista` module and consumer-side contract testing is set up for `waiter` module.
4 |
5 | ## FLOW
6 |
7 | * Trigger new order via HTTP call in Waiter app (`@PostMapping("/order/{name}/{count}"`), eg. `http POST :8081/order/espresso/1`
8 | * `KafkaTemplate` is used to place a new `Order` on `orders` topic
9 | * The Barista app listens on `orders`; when a new order appears, it processes it into a `Serving` and sends it to `servings` topic; if the beverage name is not matched, a `CoffeeNotAvailableException` is thrown and sent to `errors` topic
10 | * The Waiter app listens on `servings` and `errors` and logs information based on messages received on these topics
--------------------------------------------------------------------------------
/barista/src/main/java/io/spring/barcelona/coffee/barista/service/CoffeeService.java:
--------------------------------------------------------------------------------
1 | package io.spring.barcelona.coffee.barista.service;
2 |
3 | import io.spring.barcelona.coffee.barista.coffee.Coffees;
4 | import io.spring.barcelona.coffee.barista.orders.Order;
5 | import org.springframework.stereotype.Service;
6 |
7 | import java.util.Locale;
8 | import java.util.stream.IntStream;
9 |
10 | /**
11 | * @author Olga Maciaszek-Sharma
12 | */
13 | @Service
14 | public class CoffeeService {
15 |
16 | public Serving prepareServing(Order order) {
17 | Serving serving = new Serving();
18 | order.getEntries().forEach(entry ->
19 | IntStream.range(0, entry.getCount())
20 | .forEach(i ->
21 | serving.add(Beverage.of(Coffees.forName(entry.getBeverageName()
22 | .toLowerCase(Locale.getDefault()))))));
23 | return serving;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/barista/src/test/resources/contracts/shouldSendServing.groovy:
--------------------------------------------------------------------------------
1 | package contracts
2 |
3 | import org.springframework.cloud.contract.spec.Contract
4 |
5 | /**
6 | * @author Olga Maciaszek-Sharma
7 | */
8 |
9 | Contract.make {
10 | label("serving")
11 | input {
12 | triggeredBy("triggerServing()")
13 | }
14 | outputMessage {
15 | sentTo("servings")
16 | body([beverages:
17 | [[uuid : $(anyUuid()),
18 | coffee: [
19 | name : "V60",
20 | coffeeContent: "500",
21 | device : "V60"
22 | ]],
23 | [uuid : $(anyUuid()),
24 | coffee: [
25 | name : "Latte",
26 | coffeeContent : "60",
27 | steamedMilkContent: "180",
28 | milkFoamContent : "5"
29 | ]]
30 | ]])
31 | headers {
32 | messagingContentType(applicationJson())
33 | header 'testKey1', 'testValue1'
34 | }
35 | }
36 |
37 | }
--------------------------------------------------------------------------------
/waiter/src/main/java/io/spring/barcelona/coffee/waiter/service/Beverage.java:
--------------------------------------------------------------------------------
1 | package io.spring.barcelona.coffee.waiter.service;
2 |
3 | import io.spring.barcelona.coffee.waiter.coffee.Coffee;
4 |
5 | import java.util.UUID;
6 |
7 | /**
8 | * @author Olga Maciaszek-Sharma
9 | */
10 | public class Beverage {
11 |
12 | private UUID uuid;
13 | private Coffee coffee;
14 |
15 | public static Beverage of(Coffee coffee) {
16 | return new Beverage(UUID.randomUUID(), coffee);
17 | }
18 |
19 | Beverage(UUID uuid, Coffee coffee) {
20 | this.uuid = uuid;
21 | this.coffee = coffee;
22 | }
23 |
24 | Beverage() {
25 | }
26 |
27 | public UUID getUuid() {
28 | return uuid;
29 | }
30 |
31 | public Coffee getCoffee() {
32 | return coffee;
33 | }
34 |
35 | @Override
36 | public String toString() {
37 | return "Beverage{" +
38 | "uuid=" + uuid +
39 | ", coffee=" + coffee +
40 | '}';
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/barista/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 | services:
3 | kafka:
4 | image: wurstmeister/kafka
5 | hostname: kafka
6 | ports:
7 | - '9092:9092'
8 | volumes:
9 | - /var/run/docker.sock:/var/run/docker.sock
10 | environment:
11 | KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
12 | KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
13 | KAFKA_LISTENERS: PLAINTEXT://:29092,PLAINTEXT_HOST://:9092
14 | KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:_{PORT_COMMAND}
15 | KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
16 | PORT_COMMAND: "docker ps | egrep 'kafka(-|_)1' | cut -d: -f 2 | cut -d- -f 1"
17 | depends_on:
18 | - zookeeper
19 |
20 | zookeeper:
21 | image: wurstmeister/zookeeper
22 | ports:
23 | - '2181:2181'
24 | environment:
25 | - KAFKA_ADVERTISED_HOST_NAME=zookeeper
26 |
--------------------------------------------------------------------------------
/barista/src/main/java/io/spring/barcelona/coffee/barista/service/Beverage.java:
--------------------------------------------------------------------------------
1 | package io.spring.barcelona.coffee.barista.service;
2 |
3 | import io.spring.barcelona.coffee.barista.coffee.Coffee;
4 |
5 | import java.util.UUID;
6 |
7 | /**
8 | * @author Olga Maciaszek-Sharma
9 | */
10 | public class Beverage {
11 |
12 | private UUID uuid;
13 | private Coffee coffee;
14 |
15 | public static Beverage of(Coffee coffee) {
16 | return new Beverage(UUID.randomUUID(), coffee);
17 | }
18 |
19 | Beverage(UUID uuid, Coffee coffee) {
20 | this.uuid = uuid;
21 | this.coffee = coffee;
22 | }
23 |
24 | Beverage() {
25 | }
26 |
27 | public UUID getUuid() {
28 | return uuid;
29 | }
30 |
31 | public Coffee getCoffee() {
32 | return coffee;
33 | }
34 |
35 | @Override
36 | public String toString() {
37 | return "Beverage{" +
38 | "uuid=" + uuid +
39 | ", coffee=" + coffee +
40 | '}';
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/barista/src/main/java/io/spring/barcelona/coffee/barista/coffee/Coffees.java:
--------------------------------------------------------------------------------
1 | package io.spring.barcelona.coffee.barista.coffee;
2 |
3 | import io.spring.barcelona.coffee.barista.exceptions.CoffeeNotAvailableException;
4 |
5 | import java.util.Map;
6 |
7 | import static io.spring.barcelona.coffee.barista.coffee.Coffee.*;
8 |
9 | /**
10 | * @author Olga Maciaszek-Sharma
11 | */
12 | public final class Coffees {
13 |
14 | private Coffees() {
15 | throw new IllegalStateException("Do not instantiate utility class");
16 | }
17 |
18 | private static final Map coffees = Map.of("espresso", espresso(),
19 | "cappuccino", cappuccino(),
20 | "latte", latte(),
21 | "v60", v60(),
22 | "aeropress", aeroPress());
23 |
24 | public static Coffee forName(String name) {
25 | if (!coffees.containsKey(name)) {
26 | throw new CoffeeNotAvailableException(name);
27 | }
28 | return coffees.get(name);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/barista/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | # Licensed to the Apache Software Foundation (ASF) under one
2 | # or more contributor license agreements. See the NOTICE file
3 | # distributed with this work for additional information
4 | # regarding copyright ownership. The ASF licenses this file
5 | # to you under the Apache License, Version 2.0 (the
6 | # "License"); you may not use this file except in compliance
7 | # with the License. You may obtain a copy of the License at
8 | #
9 | # https://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip
18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar
19 |
--------------------------------------------------------------------------------
/waiter/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | # Licensed to the Apache Software Foundation (ASF) under one
2 | # or more contributor license agreements. See the NOTICE file
3 | # distributed with this work for additional information
4 | # regarding copyright ownership. The ASF licenses this file
5 | # to you under the Apache License, Version 2.0 (the
6 | # "License"); you may not use this file except in compliance
7 | # with the License. You may obtain a copy of the License at
8 | #
9 | # https://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip
18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar
19 |
--------------------------------------------------------------------------------
/waiter/src/main/java/io/spring/barcelona/coffee/waiter/coffee/Traditional.java:
--------------------------------------------------------------------------------
1 | package io.spring.barcelona.coffee.waiter.coffee;
2 |
3 | /**
4 | * @author Olga Maciaszek-Sharma
5 | */
6 | public class Traditional extends Coffee {
7 |
8 |
9 | private int steamedMilkContent;
10 | private int milkFoamContent;
11 |
12 | Traditional() {
13 | }
14 |
15 | Traditional(String name, int coffeeContent, int steamedMilkContent, int milkFoamContent) {
16 | super(name, coffeeContent);
17 | this.steamedMilkContent = steamedMilkContent;
18 | this.milkFoamContent = milkFoamContent;
19 | }
20 |
21 | Traditional(String espresso, int coffeeContent) {
22 | super(espresso, coffeeContent);
23 | }
24 |
25 | public int getSteamedMilkContent() {
26 | return steamedMilkContent;
27 | }
28 |
29 | public int getMilkFoamContent() {
30 | return milkFoamContent;
31 | }
32 |
33 | @Override
34 | public String toString() {
35 | return "Traditional Coffee{" +
36 | "name='" + getName() + '\'' +
37 | ", coffeeContent=" + getCoffeeContent() +
38 | ", steamedMilkContent=" + steamedMilkContent +
39 | ", milkFoamContent=" + milkFoamContent +
40 | '}';
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/barista/src/main/java/io/spring/barcelona/coffee/barista/coffee/Traditional.java:
--------------------------------------------------------------------------------
1 | package io.spring.barcelona.coffee.barista.coffee;
2 |
3 | /**
4 | * @author Olga Maciaszek-Sharma
5 | */
6 | public class Traditional extends Coffee {
7 |
8 |
9 | private int steamedMilkContent;
10 | private int milkFoamContent;
11 |
12 | Traditional() {
13 | }
14 |
15 | Traditional(String name, int coffeeContent, int steamedMilkContent, int milkFoamContent) {
16 | super(name, coffeeContent);
17 | this.steamedMilkContent = steamedMilkContent;
18 | this.milkFoamContent = milkFoamContent;
19 | }
20 |
21 | Traditional(String espresso, int coffeeContent) {
22 | super(espresso, coffeeContent);
23 | }
24 |
25 | public int getSteamedMilkContent() {
26 | return steamedMilkContent;
27 | }
28 |
29 | public int getMilkFoamContent() {
30 | return milkFoamContent;
31 | }
32 |
33 | @Override
34 | public String toString() {
35 | return "Traditional Coffee{" +
36 | "name='" + getName() + '\'' +
37 | ", coffeeContent=" + getCoffeeContent() +
38 | ", steamedMilkContent=" + steamedMilkContent +
39 | ", milkFoamContent=" + milkFoamContent +
40 | '}';
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/waiter/src/main/java/io/spring/barcelona/coffee/waiter/coffee/Coffee.java:
--------------------------------------------------------------------------------
1 | package io.spring.barcelona.coffee.waiter.coffee;
2 |
3 | /**
4 | * @author Olga Maciaszek-Sharma
5 | */
6 | public class Coffee {
7 |
8 | private String name;
9 |
10 | private int coffeeContent;
11 |
12 | Coffee() {
13 | }
14 |
15 | public static Coffee espresso() {
16 | return new Traditional("Espresso", 30);
17 | }
18 |
19 | public static Coffee cappuccino() {
20 | return new Traditional("Cappuccino", 60, 60, 60);
21 | }
22 |
23 | public static Coffee latte() {
24 | return new Traditional("Latte", 60, 180, 5);
25 | }
26 |
27 | public static Coffee v60() {
28 | return new Alternative("V60", 500, BrewingDevice.V60);
29 | }
30 |
31 | public static Coffee aeroPress() {
32 | return new Alternative("AeroPress", 200, BrewingDevice.AERO_PRESS);
33 | }
34 |
35 |
36 | Coffee(String name, int coffeeContent) {
37 | this.name = name;
38 | this.coffeeContent = coffeeContent;
39 | }
40 |
41 | public String getName() {
42 | return name;
43 | }
44 |
45 | public int getCoffeeContent() {
46 | return coffeeContent;
47 | }
48 |
49 | @Override
50 | public String toString() {
51 | return "Coffee{" +
52 | "name='" + name + '\'' +
53 | ", coffeeContent=" + coffeeContent +
54 | '}';
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/barista/src/main/java/io/spring/barcelona/coffee/barista/coffee/Coffee.java:
--------------------------------------------------------------------------------
1 | package io.spring.barcelona.coffee.barista.coffee;
2 |
3 | /**
4 | * @author Olga Maciaszek-Sharma
5 | */
6 | public class Coffee {
7 |
8 | private String name;
9 |
10 | private int coffeeContent;
11 |
12 | Coffee() {
13 | }
14 |
15 | public static Coffee espresso() {
16 | return new Traditional("Espresso", 30);
17 | }
18 |
19 | public static Coffee cappuccino() {
20 | return new Traditional("Cappuccino", 60, 60, 60);
21 | }
22 |
23 | public static Coffee latte() {
24 | return new Traditional("Latte", 60, 180, 5);
25 | }
26 |
27 | public static Coffee v60() {
28 | return new Alternative("V60", 500, BrewingDevice.V60);
29 | }
30 |
31 | public static Coffee aeroPress() {
32 | return new Alternative("AeroPress", 200, BrewingDevice.AERO_PRESS);
33 | }
34 |
35 |
36 | Coffee(String name, int coffeeContent) {
37 | this.name = name;
38 | this.coffeeContent = coffeeContent;
39 | }
40 |
41 | public String getName() {
42 | return name;
43 | }
44 |
45 | public int getCoffeeContent() {
46 | return coffeeContent;
47 | }
48 |
49 | @Override
50 | public String toString() {
51 | return "Coffee{" +
52 | "name='" + name + '\'' +
53 | ", coffeeContent=" + coffeeContent +
54 | '}';
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/waiter/src/main/java/io/spring/barcelona/coffee/waiter/controller/OrderController.java:
--------------------------------------------------------------------------------
1 | package io.spring.barcelona.coffee.waiter.controller;
2 |
3 | import io.spring.barcelona.coffee.waiter.orders.Order;
4 | import io.spring.barcelona.coffee.waiter.orders.OrderEntry;
5 | import org.apache.juli.logging.Log;
6 | import org.apache.juli.logging.LogFactory;
7 |
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.http.HttpStatus;
10 | import org.springframework.http.ResponseEntity;
11 | import org.springframework.kafka.core.KafkaTemplate;
12 | import org.springframework.web.bind.annotation.GetMapping;
13 | import org.springframework.web.bind.annotation.PathVariable;
14 | import org.springframework.web.bind.annotation.RestController;
15 |
16 | /**
17 | * @author Olga Maciaszek-Sharma
18 | */
19 | @RestController
20 | public class OrderController {
21 |
22 | private static final Log LOG = LogFactory.getLog(OrderController.class);
23 |
24 | @Autowired
25 | private KafkaTemplate