├── .gitignore
├── Dockerfile
├── README.adoc
├── deployment
└── coffee-shop.yaml
├── pom.xml
├── presentation
├── slide001
├── slide002
├── slide003
├── slide004
└── syntax.vim
└── src
├── main
├── java
│ └── com
│ │ └── sebastian_daschner
│ │ └── coffee_shop
│ │ ├── JAXRSConfiguration.java
│ │ ├── health
│ │ └── Health.java
│ │ ├── orders
│ │ ├── CoffeeTypeDeserializer.java
│ │ ├── boundary
│ │ │ ├── CoffeeShop.java
│ │ │ └── OrdersResource.java
│ │ ├── control
│ │ │ └── Orders.java
│ │ └── entity
│ │ │ ├── CoffeeOrder.java
│ │ │ ├── CoffeeType.java
│ │ │ └── OrderStatus.java
│ │ └── price
│ │ └── control
│ │ └── PriceCalculator.java
├── liberty
│ └── config
│ │ └── server.xml
├── resources
│ └── META-INF
│ │ └── microprofile-config.properties
└── webapp
│ └── WEB-INF
│ └── beans.xml
└── test
└── java
└── com
└── sebastian_daschner
└── coffee_shop
└── orders
├── CoffeeTypeDeserializerTest.java
└── boundary
├── CoffeeShopIT.java
└── CoffeeShopSystem.java
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | pom.xml.tag
3 | pom.xml.releaseBackup
4 | pom.xml.versionsBackup
5 | pom.xml.next
6 | release.properties
7 |
8 | *.iml
9 | .idea/
10 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM open-liberty:javaee8-java12
2 |
3 | COPY src/main/liberty/config/server.xml /config/
4 |
5 | COPY target/coffee-shop.war /config/dropins/
--------------------------------------------------------------------------------
/README.adoc:
--------------------------------------------------------------------------------
1 | = Enterprise Coffee
2 |
3 | The example project of my Jakarta EE Tech Talk _Best practices for modern Enterprise Java projects_.
4 |
5 | Comprises a _coffee-shop_ application, which can be deployed locally, or to a Kubernetes and Istio cluster.
6 |
--------------------------------------------------------------------------------
/deployment/coffee-shop.yaml:
--------------------------------------------------------------------------------
1 | kind: Service
2 | apiVersion: v1
3 | metadata:
4 | name: coffee-shop
5 | labels:
6 | app: coffee-shop
7 | spec:
8 | selector:
9 | app: coffee-shop
10 | ports:
11 | - port: 9080
12 | name: http
13 | ---
14 |
15 | kind: Deployment
16 | apiVersion: apps/v1beta1
17 | metadata:
18 | name: coffee-shop
19 | spec:
20 | replicas: 1
21 | template:
22 | metadata:
23 | labels:
24 | app: coffee-shop
25 | version: v1
26 | spec:
27 | containers:
28 | - name: coffee-shop
29 | image: sdaschner/coffee-shop:ee-best-practices-1
30 | imagePullPolicy: Always
31 | ports:
32 | - containerPort: 9080
33 | readinessProbe:
34 | exec:
35 | command:
36 | - /bin/sh
37 | - -c
38 | - curl -f localhost:9080/health
39 | initialDelaySeconds: 30
40 | restartPolicy: Always
41 | ---
42 |
43 | kind: Gateway
44 | apiVersion: networking.istio.io/v1alpha3
45 | metadata:
46 | name: coffee-shop-gateway
47 | spec:
48 | selector:
49 | istio: ingressgateway
50 | servers:
51 | - port:
52 | number: 80
53 | name: http
54 | protocol: HTTP
55 | hosts:
56 | - "*"
57 | ---
58 |
59 | kind: VirtualService
60 | apiVersion: networking.istio.io/v1alpha3
61 | metadata:
62 | name: coffee-shop
63 | spec:
64 | hosts:
65 | - "*"
66 | gateways:
67 | - coffee-shop-gateway
68 | http:
69 | - route:
70 | - destination:
71 | host: coffee-shop
72 | port:
73 | number: 9080
74 | subset: v1
75 | ---
76 |
77 | kind: DestinationRule
78 | apiVersion: networking.istio.io/v1alpha3
79 | metadata:
80 | name: coffee-shop
81 | spec:
82 | host: coffee-shop
83 | subsets:
84 | - name: v1
85 | labels:
86 | version: v1
87 | ---
88 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 | com.sebastian-daschner
5 | coffee-shop
6 | 1.0-SNAPSHOT
7 | war
8 |
9 |
10 |
11 | jakarta.platform
12 | jakarta.jakartaee-api
13 | 8.0.0
14 | provided
15 |
16 |
17 | org.eclipse.microprofile
18 | microprofile
19 | 3.0
20 | pom
21 | provided
22 |
23 |
24 |
25 |
26 | org.junit.jupiter
27 | junit-jupiter-api
28 | 5.4.2
29 | test
30 |
31 |
32 | org.junit.jupiter
33 | junit-jupiter-engine
34 | 5.4.2
35 | test
36 |
37 |
38 | org.junit.jupiter
39 | junit-jupiter-params
40 | 5.3.1
41 | test
42 |
43 |
44 | org.mockito
45 | mockito-core
46 | 2.27.0
47 | test
48 |
49 |
50 | org.assertj
51 | assertj-core
52 | 3.12.1
53 | test
54 |
55 |
56 |
57 |
58 | org.glassfish.jersey.core
59 | jersey-client
60 | 2.28
61 | test
62 |
63 |
64 | org.glassfish.jersey.inject
65 | jersey-hk2
66 | 2.28
67 | test
68 |
69 |
70 | org.glassfish.jersey.media
71 | jersey-media-json-jackson
72 | 2.28
73 | test
74 |
75 |
76 | org.glassfish.jersey.media
77 | jersey-media-json-processing
78 | 2.28
79 | test
80 |
81 |
82 |
83 |
84 | javax.xml.bind
85 | jaxb-api
86 | 2.3.1
87 | test
88 |
89 |
90 | javax.activation
91 | activation
92 | 1.1
93 | test
94 |
95 |
96 |
97 |
98 | coffee-shop
99 |
100 |
101 | io.openliberty.tools
102 | liberty-maven-plugin
103 | 3.2
104 |
105 |
106 | maven-war-plugin
107 | 3.2.2
108 |
109 |
110 | maven-surefire-plugin
111 | 2.22.2
112 |
113 |
114 | maven-failsafe-plugin
115 | 2.22.2
116 |
117 |
118 |
119 |
120 |
121 | 12
122 | 12
123 | UTF-8
124 |
125 |
126 |
127 |
--------------------------------------------------------------------------------
/presentation/slide001:
--------------------------------------------------------------------------------
1 |
2 | ___ _ _ _
3 | | _ ) ___ __| |_ _ __ _ _ __ _ __| |_(_)__ ___ ___
4 | | _ \/ -_|_-< _| | '_ \ '_/ _` / _| _| / _/ -_|_-<
5 | |___/\___/__/\__| | .__/_| \__,_\__|\__|_\__\___/__/
6 | |_|
7 | __ _
8 | / _|___ _ _ _ __ ___ __| |___ _ _ _ _
9 | | _/ _ \ '_| | ' \/ _ \/ _` / -_) '_| ' \
10 | |_| \___/_| |_|_|_\___/\__,_\___|_| |_||_|
11 |
12 | ___ _ _ _
13 | | __|_ _| |_ ___ _ _ _ __ _ _(_)___ ___ _ | |__ ___ ____ _
14 | | _|| ' \ _/ -_) '_| '_ \ '_| (_- -_) | || / _` \ V / _` |
15 | |___|_||_\__\___|_| | .__/_| |_/__/\___| \__/\__,_|\_/\__,_|
16 | |_|
17 | _ _
18 | _ __ _ _ ___ (_)___ __| |_ ___
19 | | '_ \ '_/ _ \| / -_) _| _(_-<
20 | | .__/_| \___// \___\__|\__/__/
21 | |_| |__/
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/presentation/slide002:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Sebastian Daschner
7 |
8 | • Lead Java Developer Advocate @ IBM
9 | • Conference speaker, trainer, book author
10 | • Jakarta EE Committer, JCP Expert Group member
11 | • Java Champion
12 | • Oracle Groundbreaker Ambassador (Alumni)
13 | • JavaOne Rockstar speaker
14 |
--------------------------------------------------------------------------------
/presentation/slide003:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Key takeaways
7 |
8 | • Use known technology & APIs
9 | • Focus on what solves business problems
10 | • Jakarta EE + MicroProfile = awesome
11 | • Especially interesting technology for existing investment in EE
12 | • Keep it simple & leverage build tools conventions
13 | • Keep turnaround times short
14 | • Invest in testing, automation, and CI/CD
15 |
16 |
17 |
--------------------------------------------------------------------------------
/presentation/slide004:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Thank you for your attention!
7 |
8 | • daschner.dev/ee-101
9 | • @DaschnerS
10 | • Book: Architecting Modern Java EE Applications
11 |
12 | • jakarta.ee
13 | • microprofile.io
14 | • openliberty.io
15 | • quarkus.io
16 |
--------------------------------------------------------------------------------
/presentation/syntax.vim:
--------------------------------------------------------------------------------
1 | " Vim syntax file for custom slides
2 |
3 | if exists("b:current_syntax")
4 | finish
5 | endif
6 |
7 | syn match purple "awesome"
8 |
9 | hi def link red String
10 | hi def link blue Comment
11 | hi def link azul Function
12 | hi def link green Type
13 | hi def link purple Special
14 |
--------------------------------------------------------------------------------
/src/main/java/com/sebastian_daschner/coffee_shop/JAXRSConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.sebastian_daschner.coffee_shop;
2 |
3 | import javax.ws.rs.ApplicationPath;
4 | import javax.ws.rs.core.Application;
5 |
6 | @ApplicationPath("/")
7 | public class JAXRSConfiguration extends Application {
8 |
9 | // nothing to configure
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/com/sebastian_daschner/coffee_shop/health/Health.java:
--------------------------------------------------------------------------------
1 | package com.sebastian_daschner.coffee_shop.health;
2 |
3 | import org.eclipse.microprofile.config.inject.ConfigProperty;
4 | import org.eclipse.microprofile.health.HealthCheck;
5 | import org.eclipse.microprofile.health.HealthCheckResponse;
6 | import org.eclipse.microprofile.health.Readiness;
7 |
8 | import javax.enterprise.context.ApplicationScoped;
9 | import javax.inject.Inject;
10 |
11 | @Readiness
12 | @ApplicationScoped
13 | public class Health implements HealthCheck {
14 |
15 | @Inject
16 | @ConfigProperty(name = "version")
17 | String version;
18 |
19 | @Override
20 | public HealthCheckResponse call() {
21 | return HealthCheckResponse.named("coffee-shop")
22 | .withData("version", version)
23 | .up()
24 | .build();
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/com/sebastian_daschner/coffee_shop/orders/CoffeeTypeDeserializer.java:
--------------------------------------------------------------------------------
1 | package com.sebastian_daschner.coffee_shop.orders;
2 |
3 | import com.sebastian_daschner.coffee_shop.orders.entity.CoffeeType;
4 |
5 | import javax.json.bind.adapter.JsonbAdapter;
6 |
7 | public class CoffeeTypeDeserializer implements JsonbAdapter {
8 |
9 | @Override
10 | public String adaptToJson(CoffeeType type) {
11 | return type.name();
12 | }
13 |
14 | @Override
15 | public CoffeeType adaptFromJson(String type) {
16 | return CoffeeType.fromString(type);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/sebastian_daschner/coffee_shop/orders/boundary/CoffeeShop.java:
--------------------------------------------------------------------------------
1 | package com.sebastian_daschner.coffee_shop.orders.boundary;
2 |
3 | import com.sebastian_daschner.coffee_shop.orders.control.Orders;
4 | import com.sebastian_daschner.coffee_shop.orders.entity.CoffeeOrder;
5 | import com.sebastian_daschner.coffee_shop.price.control.PriceCalculator;
6 | import org.eclipse.microprofile.metrics.annotation.Counted;
7 |
8 | import javax.enterprise.context.ApplicationScoped;
9 | import javax.inject.Inject;
10 | import java.util.List;
11 | import java.util.UUID;
12 |
13 | @ApplicationScoped
14 | public class CoffeeShop {
15 |
16 | @Inject
17 | Orders orders;
18 |
19 | @Inject
20 | PriceCalculator priceCalculator;
21 |
22 | public List getOrders() {
23 | return orders.retrieveAll();
24 | }
25 |
26 | public CoffeeOrder getOrder(UUID id) {
27 | return orders.retrieve(id);
28 | }
29 |
30 | @Counted(name = "coffees_total")
31 | public CoffeeOrder orderCoffee(CoffeeOrder order) {
32 | order.setId(UUID.randomUUID());
33 | order.setPrice(priceCalculator.calculatePrice(order));
34 |
35 | orders.store(order.getId(), order);
36 |
37 | return order;
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/com/sebastian_daschner/coffee_shop/orders/boundary/OrdersResource.java:
--------------------------------------------------------------------------------
1 | package com.sebastian_daschner.coffee_shop.orders.boundary;
2 |
3 | import com.sebastian_daschner.coffee_shop.orders.entity.CoffeeOrder;
4 |
5 | import javax.inject.Inject;
6 | import javax.json.Json;
7 | import javax.json.JsonArray;
8 | import javax.json.JsonObject;
9 | import javax.json.stream.JsonCollectors;
10 | import javax.servlet.http.HttpServletRequest;
11 | import javax.validation.Valid;
12 | import javax.validation.constraints.NotNull;
13 | import javax.ws.rs.*;
14 | import javax.ws.rs.core.Context;
15 | import javax.ws.rs.core.MediaType;
16 | import javax.ws.rs.core.Response;
17 | import javax.ws.rs.core.UriInfo;
18 | import java.net.URI;
19 | import java.util.UUID;
20 |
21 | @Path("orders")
22 | @Produces(MediaType.APPLICATION_JSON)
23 | @Consumes(MediaType.APPLICATION_JSON)
24 | public class OrdersResource {
25 |
26 | @Inject
27 | CoffeeShop coffeeShop;
28 |
29 | @Context
30 | UriInfo uriInfo;
31 |
32 | @Context
33 | HttpServletRequest request;
34 |
35 | @GET
36 | public JsonArray getOrders() {
37 | return coffeeShop.getOrders().stream()
38 | .map(this::buildOrder)
39 | .collect(JsonCollectors.toJsonArray());
40 | }
41 |
42 | private JsonObject buildOrder(CoffeeOrder order) {
43 | return Json.createObjectBuilder()
44 | .add("type", order.getType().name())
45 | .add("status", order.getStatus().name())
46 | .add("_self", buildUri(order).toString())
47 | .build();
48 | }
49 |
50 | @GET
51 | @Path("{id}")
52 | public CoffeeOrder getOrder(@PathParam("id") UUID id) {
53 | return coffeeShop.getOrder(id);
54 | }
55 |
56 | @POST
57 | public Response orderCoffee(@Valid @NotNull CoffeeOrder order) {
58 | final CoffeeOrder storedOrder = coffeeShop.orderCoffee(order);
59 | return Response.created(buildUri(storedOrder)).build();
60 | }
61 |
62 | private URI buildUri(CoffeeOrder order) {
63 | return uriInfo.getBaseUriBuilder()
64 | .path(OrdersResource.class)
65 | .path(OrdersResource.class, "getOrder")
66 | .build(order.getId());
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/src/main/java/com/sebastian_daschner/coffee_shop/orders/control/Orders.java:
--------------------------------------------------------------------------------
1 | package com.sebastian_daschner.coffee_shop.orders.control;
2 |
3 | import com.sebastian_daschner.coffee_shop.orders.entity.CoffeeOrder;
4 |
5 | import javax.enterprise.context.ApplicationScoped;
6 | import java.util.List;
7 | import java.util.Map;
8 | import java.util.UUID;
9 | import java.util.concurrent.ConcurrentHashMap;
10 | import java.util.stream.Collectors;
11 |
12 | @ApplicationScoped
13 | public class Orders {
14 |
15 | private final ConcurrentHashMap orders = new ConcurrentHashMap<>();
16 |
17 | public List retrieveAll() {
18 | return orders.entrySet().stream()
19 | .map(Map.Entry::getValue)
20 | .collect(Collectors.toList());
21 | }
22 |
23 | public CoffeeOrder retrieve(UUID id) {
24 | return orders.get(id);
25 | }
26 |
27 | public void store(UUID id, CoffeeOrder order) {
28 | orders.put(id, order);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/sebastian_daschner/coffee_shop/orders/entity/CoffeeOrder.java:
--------------------------------------------------------------------------------
1 | package com.sebastian_daschner.coffee_shop.orders.entity;
2 |
3 | import com.sebastian_daschner.coffee_shop.orders.CoffeeTypeDeserializer;
4 |
5 | import javax.json.bind.annotation.JsonbTransient;
6 | import javax.json.bind.annotation.JsonbTypeAdapter;
7 | import javax.validation.constraints.NotNull;
8 | import java.util.UUID;
9 |
10 | public class CoffeeOrder {
11 |
12 | @JsonbTransient
13 | private UUID id;
14 |
15 | @NotNull
16 | @JsonbTypeAdapter(CoffeeTypeDeserializer.class)
17 | private CoffeeType type;
18 |
19 | private double price;
20 |
21 | private OrderStatus status = OrderStatus.PREPARING;
22 |
23 | public UUID getId() {
24 | return id;
25 | }
26 |
27 | public void setId(UUID id) {
28 | this.id = id;
29 | }
30 |
31 | public CoffeeType getType() {
32 | return type;
33 | }
34 |
35 | public void setType(CoffeeType type) {
36 | this.type = type;
37 | }
38 |
39 | public double getPrice() {
40 | return price;
41 | }
42 |
43 | public void setPrice(double price) {
44 | this.price = price;
45 | }
46 |
47 | public OrderStatus getStatus() {
48 | return status;
49 | }
50 |
51 | public void setStatus(OrderStatus status) {
52 | this.status = status;
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/com/sebastian_daschner/coffee_shop/orders/entity/CoffeeType.java:
--------------------------------------------------------------------------------
1 | package com.sebastian_daschner.coffee_shop.orders.entity;
2 |
3 | import java.util.stream.Stream;
4 |
5 | public enum CoffeeType {
6 |
7 | ESPRESSO,
8 | LATTE,
9 | POUR_OVER;
10 |
11 | public static CoffeeType fromString(String string) {
12 | return Stream.of(CoffeeType.values())
13 | .filter(t -> t.name().equalsIgnoreCase(string))
14 | .findAny().orElse(null);
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/sebastian_daschner/coffee_shop/orders/entity/OrderStatus.java:
--------------------------------------------------------------------------------
1 | package com.sebastian_daschner.coffee_shop.orders.entity;
2 |
3 | public enum OrderStatus {
4 |
5 | PREPARING,
6 | FINISHED
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/java/com/sebastian_daschner/coffee_shop/price/control/PriceCalculator.java:
--------------------------------------------------------------------------------
1 | package com.sebastian_daschner.coffee_shop.price.control;
2 |
3 | import com.sebastian_daschner.coffee_shop.orders.entity.CoffeeOrder;
4 | import com.sebastian_daschner.coffee_shop.orders.entity.CoffeeType;
5 | import org.eclipse.microprofile.config.ConfigProvider;
6 |
7 | public class PriceCalculator {
8 |
9 | public double calculatePrice(CoffeeOrder order) {
10 | return getConfiguredPrice(order.getType());
11 | }
12 |
13 | private double getConfiguredPrice(CoffeeType type) {
14 | String key = "coffee.prices." + type.name().toLowerCase();
15 | return ConfigProvider.getConfig().getValue(key, double.class);
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/liberty/config/server.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | jaxrs-2.1
4 | cdi-2.0
5 | jsonb-1.0
6 | mpHealth-2.0
7 | mpConfig-1.3
8 | mpMetrics-2.0
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/microprofile-config.properties:
--------------------------------------------------------------------------------
1 | coffee.prices.espresso=1.5
2 | coffee.prices.pour_over=4.0
3 | coffee.prices.latte=3.0
4 |
5 | version=1.2.3
6 |
--------------------------------------------------------------------------------
/src/main/webapp/WEB-INF/beans.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/src/test/java/com/sebastian_daschner/coffee_shop/orders/CoffeeTypeDeserializerTest.java:
--------------------------------------------------------------------------------
1 | package com.sebastian_daschner.coffee_shop.orders;
2 |
3 | import com.sebastian_daschner.coffee_shop.orders.entity.CoffeeType;
4 | import org.junit.jupiter.api.BeforeEach;
5 | import org.junit.jupiter.params.ParameterizedTest;
6 | import org.junit.jupiter.params.provider.MethodSource;
7 |
8 | import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
9 |
10 | class CoffeeTypeDeserializerTest {
11 |
12 | private CoffeeTypeDeserializer deserializer;
13 |
14 | @BeforeEach
15 | void setUp() {
16 | deserializer = new CoffeeTypeDeserializer();
17 | }
18 |
19 | @ParameterizedTest
20 | @MethodSource("testData")
21 | void testDeserialize(String serializedType, CoffeeType expectedType) {
22 | assertThat(deserializer.adaptFromJson(serializedType)).isEqualTo(expectedType);
23 | }
24 |
25 | private static Object[][] testData() {
26 | return new Object[][]{
27 | new Object[]{"Espresso", CoffeeType.ESPRESSO},
28 | new Object[]{"ESPRESSO", CoffeeType.ESPRESSO},
29 | new Object[]{"espresso", CoffeeType.ESPRESSO},
30 | new Object[]{"Latte", CoffeeType.LATTE},
31 | new Object[]{"LAtte", CoffeeType.LATTE},
32 | new Object[]{"pour_over", CoffeeType.POUR_OVER}
33 | };
34 | }
35 |
36 | }
--------------------------------------------------------------------------------
/src/test/java/com/sebastian_daschner/coffee_shop/orders/boundary/CoffeeShopIT.java:
--------------------------------------------------------------------------------
1 | package com.sebastian_daschner.coffee_shop.orders.boundary;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import static org.assertj.core.api.Assertions.assertThat;
6 |
7 | class CoffeeShopIT {
8 |
9 | private CoffeeShopSystem coffeeShopSystem = new CoffeeShopSystem();
10 |
11 | @Test
12 | void testIsSystemRunning() {
13 | assertThat(coffeeShopSystem.isSystemUp()).isTrue();
14 | }
15 |
16 | @Test
17 | void testVersion() {
18 | assertThat(coffeeShopSystem.getAppVersion()).isEqualTo("1.2.3");
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/test/java/com/sebastian_daschner/coffee_shop/orders/boundary/CoffeeShopSystem.java:
--------------------------------------------------------------------------------
1 | package com.sebastian_daschner.coffee_shop.orders.boundary;
2 |
3 | import javax.json.JsonObject;
4 | import javax.ws.rs.client.Client;
5 | import javax.ws.rs.client.ClientBuilder;
6 | import javax.ws.rs.client.WebTarget;
7 | import javax.ws.rs.core.MediaType;
8 | import javax.ws.rs.core.UriBuilder;
9 | import java.net.URI;
10 | import java.util.concurrent.TimeUnit;
11 |
12 | class CoffeeShopSystem {
13 |
14 | private final Client client;
15 | private final WebTarget healthTarget;
16 |
17 | public CoffeeShopSystem() {
18 | client = ClientBuilder.newBuilder()
19 | .connectTimeout(5, TimeUnit.SECONDS)
20 | .readTimeout(5, TimeUnit.SECONDS)
21 | .build();
22 | healthTarget = client.target(buildHealthUri());
23 | }
24 |
25 | private URI buildHealthUri() {
26 | String host = System.getProperty("coffee-shop.test.host", "localhost");
27 | String port = System.getProperty("coffee-shop.test.port", "9080");
28 | return UriBuilder.fromUri("http://{host}:{port}/health/").build(host, port);
29 | }
30 |
31 | public boolean isSystemUp() {
32 | String status = healthTarget.request(MediaType.APPLICATION_JSON_TYPE)
33 | .get(JsonObject.class)
34 | .getString("status");
35 | return "UP".equalsIgnoreCase(status);
36 | }
37 |
38 | public String getAppVersion() {
39 | return healthTarget.request(MediaType.APPLICATION_JSON_TYPE)
40 | .get(JsonObject.class)
41 | .getJsonArray("checks")
42 | .getValuesAs(JsonObject.class)
43 | .stream()
44 | .filter(o -> o.getString("name").equalsIgnoreCase("coffee-shop"))
45 | .map(o -> o.getJsonObject("data").getString("version"))
46 | .findAny().orElse(null);
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------