├── .gitignore
├── barista
├── Dockerfile
├── src
│ └── main
│ │ ├── java
│ │ └── com
│ │ │ └── sebastian_daschner
│ │ │ └── barista
│ │ │ ├── boundary
│ │ │ ├── CoffeeBrews.java
│ │ │ ├── HealthResource.java
│ │ │ └── BrewsResource.java
│ │ │ └── JAXRSConfiguration.java
│ │ └── webapp
│ │ └── WEB-INF
│ │ └── beans.xml
├── deployment
│ ├── routing.yaml
│ └── barista.yaml
├── openliberty
│ └── server.xml
└── pom.xml
├── coffee-shop
├── Dockerfile
├── src
│ └── main
│ │ ├── java
│ │ └── com
│ │ │ └── sebastian_daschner
│ │ │ └── coffee_shop
│ │ │ ├── entity
│ │ │ ├── OrderStatus.java
│ │ │ ├── CoffeeType.java
│ │ │ └── CoffeeOrder.java
│ │ │ ├── JAXRSConfiguration.java
│ │ │ ├── boundary
│ │ │ ├── HealthResource.java
│ │ │ ├── CoffeeShop.java
│ │ │ └── OrdersResource.java
│ │ │ ├── CoffeeTypeDeserializer.java
│ │ │ └── control
│ │ │ ├── Orders.java
│ │ │ └── Barista.java
│ │ └── webapp
│ │ └── WEB-INF
│ │ └── beans.xml
├── openliberty
│ └── server.xml
├── deployment
│ ├── routing.yaml
│ └── coffee-shop.yaml
└── pom.xml
├── presentation
├── slide002
├── slide006
├── slide007
├── slide017
├── slide005
├── syntax.vim
├── slide016
├── slide009
├── slide010
├── slide004
├── slide012
├── slide011
├── slide013
├── slide008
├── slide014
├── slide015
└── slide001
└── README.adoc
/.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 |
--------------------------------------------------------------------------------
/barista/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM sdaschner/open-liberty:javaee8-tracing-jdk8-b3
2 |
3 | COPY openliberty/server.xml $CONFIG_DIR
4 |
5 | COPY target/barista.war $DEPLOYMENT_DIR
6 |
--------------------------------------------------------------------------------
/coffee-shop/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM sdaschner/open-liberty:javaee8-tracing-jdk8-b3
2 |
3 | COPY openliberty/server.xml $CONFIG_DIR
4 |
5 | COPY target/coffee-shop.war $DEPLOYMENT_DIR
6 |
--------------------------------------------------------------------------------
/coffee-shop/src/main/java/com/sebastian_daschner/coffee_shop/entity/OrderStatus.java:
--------------------------------------------------------------------------------
1 | package com.sebastian_daschner.coffee_shop.entity;
2 |
3 | public enum OrderStatus {
4 |
5 | PREPARING,
6 | FINISHED
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/presentation/slide002:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Sebastian Daschner
7 |
8 | • Lead Java Developer Advocate @ IBM
9 | • Conference speaker
10 | • JAX-RS, JSON-P, Config Expert Group member
11 | • Java Champion
12 | • JavaOne Rockstar speaker
13 |
--------------------------------------------------------------------------------
/barista/src/main/java/com/sebastian_daschner/barista/boundary/CoffeeBrews.java:
--------------------------------------------------------------------------------
1 | package com.sebastian_daschner.barista.boundary;
2 |
3 | public class CoffeeBrews {
4 |
5 | public void startBrew(String coffeeType) {
6 | // ...
7 |
8 | System.out.println("starting to brew: " + coffeeType);
9 | }
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/barista/src/main/java/com/sebastian_daschner/barista/JAXRSConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.sebastian_daschner.barista;
2 |
3 | import javax.ws.rs.ApplicationPath;
4 | import javax.ws.rs.core.Application;
5 |
6 | @ApplicationPath("resources")
7 | public class JAXRSConfiguration extends Application {
8 |
9 | // nothing to configure
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/barista/src/main/webapp/WEB-INF/beans.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/barista/src/main/java/com/sebastian_daschner/barista/boundary/HealthResource.java:
--------------------------------------------------------------------------------
1 | package com.sebastian_daschner.barista.boundary;
2 |
3 | import javax.ws.rs.GET;
4 | import javax.ws.rs.Path;
5 |
6 | @Path("health")
7 | public class HealthResource {
8 |
9 | @GET
10 | public String health() {
11 | return "OK";
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/coffee-shop/src/main/webapp/WEB-INF/beans.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/presentation/slide006:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | |
6 | | orderCoffee()
7 | |
8 | |
9 | ┌────v────────┐ ┌─────────────┐
10 | │ coffee-shop │ │ barista │
11 | └─────────────┘ └─────────────┘
12 |
--------------------------------------------------------------------------------
/presentation/slide007:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ^|
6 | || orderCoffee()
7 | ||
8 | ||
9 | ┌───|v────────┐ startCoffeeBrew() ┌─────────────┐
10 | │ coffee-shop │---------------------->│ barista │
11 | └─────────────┘<----------------------└─────────────┘
12 |
--------------------------------------------------------------------------------
/coffee-shop/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("resources")
7 | public class JAXRSConfiguration extends Application {
8 |
9 | // nothing to configure
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/presentation/slide017:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Thank You For Your Attention!
7 |
8 | • sebastian-daschner.com
9 | • @DaschnerS
10 | • Book: Architecting Modern Java EE Applications
11 |
12 | • kubernetes.io
13 | • istio.io
14 | • jakarta.ee
15 | • microprofile.io
16 |
--------------------------------------------------------------------------------
/coffee-shop/src/main/java/com/sebastian_daschner/coffee_shop/boundary/HealthResource.java:
--------------------------------------------------------------------------------
1 | package com.sebastian_daschner.coffee_shop.boundary;
2 |
3 | import javax.ws.rs.GET;
4 | import javax.ws.rs.Path;
5 |
6 | @Path("health")
7 | public class HealthResource {
8 |
9 | @GET
10 | public String health() {
11 | return "OK";
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/presentation/slide005:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Enterprise Coffee:
7 |
8 |
9 | ┌─────────────┐ ┌─────────────┐
10 | │ coffee-shop │ │ barista │
11 | └─────────────┘ └─────────────┘
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/README.adoc:
--------------------------------------------------------------------------------
1 | == Enterprise Coffee
2 |
3 | The example project of my _Cloud Native, Service-Meshed Java Enterprise With Istio_ and _Bulletproof Java Enterprise For The Hard Production Life_ presentations.
4 |
5 | Comprises two applications, _coffee-shop_ and _barista_, which are deployed to a Kubernetes and Istio cluster.
6 |
7 | Uses the Istio v1alpha3 networking API and requires Istio version ≥ `1.0`.
8 |
--------------------------------------------------------------------------------
/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 azul "i-craft-shop\|aft-shop\|t-shop\|maker-bot\|i\s"
8 | syn match green "orderCoffee()\|startCoffeeBrew()"
9 | syn keyword blue main
10 | syn keyword azul POD PO Pilot
11 | syn keyword red proxy
12 |
13 | hi def link red String
14 | hi def link blue Comment
15 | hi def link azul Function
16 | hi def link green Type
17 | hi def link purple Special
18 |
--------------------------------------------------------------------------------
/barista/deployment/routing.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.istio.io/v1alpha3
2 | kind: VirtualService
3 | metadata:
4 | name: barista
5 | spec:
6 | hosts:
7 | - barista
8 | http:
9 | - route:
10 | - destination:
11 | host: barista
12 | subset: v1
13 | ---
14 |
15 | apiVersion: networking.istio.io/v1alpha3
16 | kind: DestinationRule
17 | metadata:
18 | name: barista
19 | spec:
20 | host: barista
21 | subsets:
22 | - name: v1
23 | labels:
24 | version: v1
25 | ---
26 |
--------------------------------------------------------------------------------
/presentation/slide016:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Service Meshes: Key Takeaways
7 |
8 |
9 | • Transparently add technical cross-cutting concerns to microservices
10 | • Think “AOP for applications”
11 | • Routing, load-balancing, resiliency, telemetry, auth
12 | • Integrates well with Java Enterprise approach:
13 | • Business logic is a responsibility of the applications
14 | • Technical concerns are part of the environment
15 |
--------------------------------------------------------------------------------
/coffee-shop/src/main/java/com/sebastian_daschner/coffee_shop/entity/CoffeeType.java:
--------------------------------------------------------------------------------
1 | package com.sebastian_daschner.coffee_shop.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 |
--------------------------------------------------------------------------------
/coffee-shop/src/main/java/com/sebastian_daschner/coffee_shop/CoffeeTypeDeserializer.java:
--------------------------------------------------------------------------------
1 | package com.sebastian_daschner.coffee_shop;
2 |
3 | import com.sebastian_daschner.coffee_shop.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 |
--------------------------------------------------------------------------------
/presentation/slide009:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | |
8 | |
9 | ┌─────|───────┐ ┌─────────────┐
10 | │ cof | -shop │ │ barista │
11 | │┌────|──────┐│ │┌───────────┐│
12 | ││ PO v ││ ││ POD ││
13 | ││┌─────────┐││ ││┌─────────┐││
14 | │││ main │││ │││ main │││
15 | ││└─────────┘││ ││└─────────┘││
16 | │└───────────┘│ │└───────────┘│
17 | └─────────────┘ └─────────────┘
18 |
--------------------------------------------------------------------------------
/presentation/slide010:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | ^ |
8 | | |
9 | ┌───|─|───────┐ ┌─────────────┐
10 | │ c | | -shop │ │ barista │
11 | │┌──|─|──────┐│ │┌───────────┐│
12 | ││ | v ││ ││ POD ││
13 | ││┌─────────┐││ ││┌─────────┐││
14 | │││ main ----------------> main │││
15 | ││└─────────<---------------└─────────┘││
16 | │└───────────┘│ │└───────────┘│
17 | └─────────────┘ └─────────────┘
18 |
--------------------------------------------------------------------------------
/presentation/slide004:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Microservice Example:
7 |
8 |
9 | ______ __ _ ______ ________
10 | / ____/___ / /____ _________ _____(_)_______ / ____/___ / __/ __/__ ___
11 | / __/ / __ \/ __/ _ \/ ___/ __ \/ ___/ / ___/ _ \ / / / __ \/ /_/ /_/ _ \/ _ \
12 | / /___/ / / / /_/ __/ / / /_/ / / / (__ ) __/ / /___/ /_/ / __/ __/ __/ __/
13 | /_____/_/ /_/\__/\___/_/ / .___/_/ /_/____/\___/ \____/\____/_/ /_/ \___/\___/
14 | /_/
15 |
--------------------------------------------------------------------------------
/presentation/slide012:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | |
8 | |
9 | ┌─────|───────────┐ ┌─────────────────┐
10 | │ cof | -shop │ │ barista │
11 | │┌────|──────────┐│ │┌───────────────┐│
12 | ││ PO v ││ ││ POD ││
13 | ││┌─────┐ ┌────┐││ ││┌─────┐ ┌────┐││
14 | │││proxy│->│main│││ │││proxy│ │main│││
15 | ││└─────┘ └────┘││ ││└─────┘ └────┘││
16 | │└───────────────┘│ │└───────────────┘│
17 | └─────────────────┘ └─────────────────┘
18 |
--------------------------------------------------------------------------------
/presentation/slide011:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | In Service Mesh (Istio)
7 |
8 |
9 | ┌─────────────────┐ ┌─────────────────┐
10 | │ coffee-shop │ │ barista │
11 | │┌───────────────┐│ │┌───────────────┐│
12 | ││ POD ││ ││ POD ││
13 | ││┌─────┐ ┌────┐││ ││┌─────┐ ┌────┐││
14 | │││proxy│ │main│││ │││proxy│ │main│││
15 | ││└─────┘ └────┘││ ││└─────┘ └────┘││
16 | │└───────────────┘│ │└───────────────┘│
17 | └─────────────────┘ └─────────────────┘
18 |
--------------------------------------------------------------------------------
/presentation/slide013:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | |
8 | |
9 | ┌─────|───────────┐ ┌─────────────────┐
10 | │ cof | -shop │ │ barista │
11 | │┌────|──────────┐│ │┌───────────────┐│
12 | ││ PO v ││ ││ POD ││
13 | ││┌─────┐ ┌────┐││ ││┌─────┐ ┌────┐││
14 | │││proxy│->│main│││ │││proxy│->│main│││
15 | ││└─────┘<-└────┘││ ││└─────┘ └────┘││
16 | │└────|──────────┘│ │└──^────────────┘│
17 | └─────|───────────┘ └───|─────────────┘
18 | └---------------------------┘
19 |
--------------------------------------------------------------------------------
/presentation/slide008:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | In Container Orchestration (Kubernetes)
7 |
8 |
9 | ┌──────────────┐ ┌─────────────┐
10 | │ coffee-shop │ │ barista │
11 | │┌───────────┐ │ │┌───────────┐│
12 | ││ POD │┐│ ││ POD ││
13 | ││┌─────────┐│││ ││┌─────────┐││
14 | │││ main ││││ │││ main │││
15 | ││└─────────┘│││ ││└─────────┘││
16 | │└───────────┘││ │└───────────┘│
17 | │ └───────────┘│ └─────────────┘
18 | │ ... │
19 | └──────────────┘
20 |
--------------------------------------------------------------------------------
/presentation/slide014:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | ^ |
8 | | |
9 | ┌───|─|───────────┐ ┌─────────────────┐
10 | │ c | | -shop │ │ barista │
11 | │┌──|─|──────────┐│ │┌───────────────┐│
12 | ││ | v ││ ││ POD ││
13 | ││┌─────┐ ┌────┐││ ││┌─────┐ ┌────┐││
14 | │││proxy│->│main│││ │││proxy│->│main│││
15 | ││└─────┘<-└────┘││ ││└─────┘<-└────┘││
16 | │└──^─|──────────┘│ │└──^─|──────────┘│
17 | └───|─|───────────┘ └───|─|───────────┘
18 | | └---------------------------┘ |
19 | └-------------------------------┘
20 |
--------------------------------------------------------------------------------
/barista/openliberty/server.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | javaee-8.0
6 | mpMetrics-1.0
7 | mpOpenTracing-1.0
8 | usr:opentracingZipkin-0.30
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | admin
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/coffee-shop/openliberty/server.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | javaee-8.0
6 | mpMetrics-1.0
7 | mpOpenTracing-1.0
8 | usr:opentracingZipkin-0.30
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | admin
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/barista/src/main/java/com/sebastian_daschner/barista/boundary/BrewsResource.java:
--------------------------------------------------------------------------------
1 | package com.sebastian_daschner.barista.boundary;
2 |
3 | import javax.inject.Inject;
4 | import javax.json.JsonObject;
5 | import javax.ws.rs.*;
6 | import javax.ws.rs.core.MediaType;
7 | import javax.ws.rs.core.Response;
8 |
9 | @Path("brews")
10 | @Produces(MediaType.APPLICATION_JSON)
11 | @Consumes(MediaType.APPLICATION_JSON)
12 | public class BrewsResource {
13 |
14 | @Inject
15 | CoffeeBrews coffeeBrews;
16 |
17 | @POST
18 | public Response startCoffeeBrew(JsonObject jsonObject) {
19 | String coffeeType = jsonObject.getString("type", null);
20 |
21 | if (coffeeType == null)
22 | throw new BadRequestException();
23 |
24 | coffeeBrews.startBrew(coffeeType);
25 |
26 | return Response.accepted().build();
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/coffee-shop/deployment/routing.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.istio.io/v1alpha3
2 | kind: Gateway
3 | metadata:
4 | name: coffee-shop-gateway
5 | spec:
6 | selector:
7 | istio: ingressgateway
8 | servers:
9 | - port:
10 | number: 80
11 | name: http
12 | protocol: HTTP
13 | hosts:
14 | - "*"
15 | ---
16 |
17 | apiVersion: networking.istio.io/v1alpha3
18 | kind: VirtualService
19 | metadata:
20 | name: coffee-shop
21 | spec:
22 | hosts:
23 | - "*"
24 | gateways:
25 | - coffee-shop-gateway
26 | http:
27 | - route:
28 | - destination:
29 | host: coffee-shop
30 | port:
31 | number: 9080
32 | subset: v1
33 | ---
34 |
35 | apiVersion: networking.istio.io/v1alpha3
36 | kind: DestinationRule
37 | metadata:
38 | name: coffee-shop
39 | spec:
40 | host: coffee-shop
41 | subsets:
42 | - name: v1
43 | labels:
44 | version: v1
45 | ---
46 |
--------------------------------------------------------------------------------
/coffee-shop/src/main/java/com/sebastian_daschner/coffee_shop/boundary/CoffeeShop.java:
--------------------------------------------------------------------------------
1 | package com.sebastian_daschner.coffee_shop.boundary;
2 |
3 | import com.sebastian_daschner.coffee_shop.control.Barista;
4 | import com.sebastian_daschner.coffee_shop.control.Orders;
5 | import com.sebastian_daschner.coffee_shop.entity.CoffeeOrder;
6 |
7 | import javax.ejb.Stateless;
8 | import javax.inject.Inject;
9 | import java.util.List;
10 | import java.util.UUID;
11 |
12 | @Stateless
13 | public class CoffeeShop {
14 |
15 | @Inject
16 | Orders orders;
17 |
18 | @Inject
19 | Barista barista;
20 |
21 | public List getOrders() {
22 | return orders.retrieveAll();
23 | }
24 |
25 | public CoffeeOrder getOrder(UUID id) {
26 | return orders.retrieve(id);
27 | }
28 |
29 | public CoffeeOrder orderCoffee(CoffeeOrder order) {
30 |
31 | barista.startCoffeeBrew(order.getType());
32 |
33 | order.setId(UUID.randomUUID());
34 | orders.store(order.getId(), order);
35 | return order;
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/coffee-shop/src/main/java/com/sebastian_daschner/coffee_shop/control/Orders.java:
--------------------------------------------------------------------------------
1 | package com.sebastian_daschner.coffee_shop.control;
2 |
3 | import com.sebastian_daschner.coffee_shop.entity.CoffeeOrder;
4 |
5 | import javax.ejb.ConcurrencyManagement;
6 | import javax.ejb.ConcurrencyManagementType;
7 | import javax.ejb.Singleton;
8 | import java.util.List;
9 | import java.util.Map;
10 | import java.util.UUID;
11 | import java.util.concurrent.ConcurrentHashMap;
12 | import java.util.stream.Collectors;
13 |
14 | @Singleton
15 | @ConcurrencyManagement(ConcurrencyManagementType.BEAN)
16 | public class Orders {
17 |
18 | private final ConcurrentHashMap orders = new ConcurrentHashMap<>();
19 |
20 | public List retrieveAll() {
21 | return orders.entrySet().stream()
22 | .map(Map.Entry::getValue)
23 | .collect(Collectors.toList());
24 | }
25 |
26 | public CoffeeOrder retrieve(UUID id) {
27 | return orders.get(id);
28 | }
29 |
30 | public void store(UUID id, CoffeeOrder order) {
31 | orders.put(id, order);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/barista/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 | com.sebastian-daschner
5 | barista
6 | 1.0-SNAPSHOT
7 | war
8 |
9 |
10 |
11 | javax
12 | javaee-api
13 | 8.0
14 | provided
15 |
16 |
17 |
18 |
19 | barista
20 |
21 |
22 |
23 | 1.8
24 | 1.8
25 | false
26 | UTF-8
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/presentation/slide015:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ┌─────────────────┐ ┌─────────────────┐
7 | │ coffee-shop │ │ barista │
8 | │┌───────────────┐│ │┌───────────────┐│
9 | ││ POD ││ ││ POD ││
10 | ││┌─────┐ ┌────┐││ ││┌─────┐ ┌────┐││
11 | │││proxy│ │main│││ │││proxy│ │main│││
12 | ││└─────┘ └────┘││ ││└─────┘ └────┘││
13 | │└───^───────────┘│ │└───^───────────┘│
14 | └────|────────────┘ └────|────────────┘
15 | └----------------┐ ┌---------┘
16 | | |
17 | Configuration | |
18 | Routing Rules | |
19 | Policy checks | |
20 | Telemetry | |
21 | v v
22 | ┌─────────┐
23 | │ Pilot │
24 | └─────────┘
25 |
--------------------------------------------------------------------------------
/coffee-shop/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 | com.sebastian-daschner
5 | coffee-shop
6 | 1.0-SNAPSHOT
7 | war
8 |
9 |
10 |
11 | javax
12 | javaee-api
13 | 8.0
14 | provided
15 |
16 |
17 |
18 |
19 | coffee-shop
20 |
21 |
22 |
23 | 1.8
24 | 1.8
25 | false
26 | UTF-8
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/barista/deployment/barista.yaml:
--------------------------------------------------------------------------------
1 | kind: Service
2 | apiVersion: v1
3 | metadata:
4 | name: barista
5 | labels:
6 | app: barista
7 | spec:
8 | selector:
9 | app: barista
10 | ports:
11 | - port: 9080
12 | name: http
13 | ---
14 |
15 | kind: Deployment
16 | apiVersion: apps/v1beta1
17 | metadata:
18 | name: barista
19 | spec:
20 | replicas: 1
21 | template:
22 | metadata:
23 | labels:
24 | app: barista
25 | version: v1
26 | spec:
27 | containers:
28 | - name: barista
29 | image: docker.sebastian-daschner.com/barista:1
30 | imagePullPolicy: Always
31 | ports:
32 | - containerPort: 9080
33 | livenessProbe:
34 | exec:
35 | command:
36 | - /bin/bash
37 | - -c
38 | - curl -f localhost:9080/
39 | initialDelaySeconds: 40
40 | readinessProbe:
41 | exec:
42 | command:
43 | - /bin/bash
44 | - -c
45 | - curl -f localhost:9080/barista/resources/health
46 | initialDelaySeconds: 60
47 | imagePullSecrets:
48 | - name: regsecret
49 | restartPolicy: Always
50 | ---
51 |
--------------------------------------------------------------------------------
/coffee-shop/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: docker.sebastian-daschner.com/coffee-shop:service-mesh-build-1
30 | imagePullPolicy: Always
31 | ports:
32 | - containerPort: 9080
33 | livenessProbe:
34 | exec:
35 | command:
36 | - /bin/bash
37 | - -c
38 | - curl -f localhost:9080/
39 | initialDelaySeconds: 40
40 | readinessProbe:
41 | exec:
42 | command:
43 | - /bin/bash
44 | - -c
45 | - curl -f localhost:9080/coffee-shop/resources/health
46 | initialDelaySeconds: 60
47 | imagePullSecrets:
48 | - name: regsecret
49 | restartPolicy: Always
50 | ---
51 |
--------------------------------------------------------------------------------
/coffee-shop/src/main/java/com/sebastian_daschner/coffee_shop/entity/CoffeeOrder.java:
--------------------------------------------------------------------------------
1 | package com.sebastian_daschner.coffee_shop.entity;
2 |
3 | import com.sebastian_daschner.coffee_shop.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 OrderStatus status = OrderStatus.PREPARING;
20 |
21 | public UUID getId() {
22 | return id;
23 | }
24 |
25 | public void setId(UUID id) {
26 | this.id = id;
27 | }
28 |
29 | public CoffeeType getType() {
30 | return type;
31 | }
32 |
33 | public void setType(CoffeeType type) {
34 | this.type = type;
35 | }
36 |
37 | public OrderStatus getStatus() {
38 | return status;
39 | }
40 |
41 | public void setStatus(OrderStatus status) {
42 | this.status = status;
43 | }
44 |
45 | @Override
46 | public String toString() {
47 | return "CoffeeOrder{" +
48 | "id=" + id +
49 | ", type=" + type +
50 | ", status=" + status +
51 | '}';
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/presentation/slide001:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | _____ _ __ ___ __ __
5 | / ___/___ ______ __(_)_______ / |/ /__ _____/ /_ ___ ____/ /
6 | \__ \/ _ \/ ___/ | / / / ___/ _ \______/ /|_/ / _ \/ ___/ __ \/ _ \/ __ /
7 | ___/ / __/ / | |/ / / /__/ __/_____/ / / / __(__ ) / / / __/ /_/ /
8 | /____/\___/_/ |___/_/\___/\___/ /_/ /_/\___/____/_/ /_/\___/\__,_/
9 |
10 | ______ __ _ __
11 | / ____/___ / /____ _________ _____(_)_______ / /___ __ ______ _
12 | / __/ / __ \/ __/ _ \/ ___/ __ \/ ___/ / ___/ _ \ __ / / __ `/ | / / __ `/
13 | / /___/ / / / /_/ __/ / / /_/ / / / (__ ) __/ / /_/ / /_/ /| |/ / /_/ /
14 | /_____/_/ /_/\__/\___/_/ / .___/_/ /_/____/\___/ \____/\__,_/ |___/\__,_/
15 | /_/
16 | _ ___ __ __ ____ __ _
17 | | | / (_) /_/ /_ / _/____/ /_(_)___
18 | | | /| / / / __/ __ \ / // ___/ __/ / __ \
19 | | |/ |/ / / /_/ / / / _/ /(__ ) /_/ / /_/ /
20 | |__/|__/_/\__/_/ /_/ /___/____/\__/_/\____/
21 |
22 |
23 | Sebastian Daschner
24 |
--------------------------------------------------------------------------------
/coffee-shop/src/main/java/com/sebastian_daschner/coffee_shop/control/Barista.java:
--------------------------------------------------------------------------------
1 | package com.sebastian_daschner.coffee_shop.control;
2 |
3 | import com.sebastian_daschner.coffee_shop.entity.CoffeeType;
4 |
5 | import javax.annotation.PostConstruct;
6 | import javax.annotation.PreDestroy;
7 | import javax.enterprise.context.ApplicationScoped;
8 | import javax.json.Json;
9 | import javax.json.JsonObject;
10 | import javax.ws.rs.client.Client;
11 | import javax.ws.rs.client.ClientBuilder;
12 | import javax.ws.rs.client.Entity;
13 | import javax.ws.rs.client.WebTarget;
14 | import javax.ws.rs.core.Response;
15 |
16 | @ApplicationScoped
17 | public class Barista {
18 |
19 | private Client client;
20 | private WebTarget target;
21 |
22 | @PostConstruct
23 | private void initClient() {
24 | client = ClientBuilder.newClient();
25 | target = client.target("http://barista:9080/barista/resources/brews");
26 | }
27 |
28 | public void startCoffeeBrew(CoffeeType type) {
29 | JsonObject requestBody = createRequestBody(type);
30 | Response response = sendRequest(requestBody);
31 | validateResponse(response);
32 | }
33 |
34 | private JsonObject createRequestBody(CoffeeType type) {
35 | return Json.createObjectBuilder()
36 | .add("type", type.name().toLowerCase())
37 | .build();
38 | }
39 |
40 | private Response sendRequest(JsonObject requestBody) {
41 | try {
42 | return target.request().post(Entity.json(requestBody));
43 | } catch (Exception e) {
44 | throw new IllegalStateException("Could not start coffee brew, reason: " + e.getMessage(), e);
45 | }
46 | }
47 |
48 | private void validateResponse(Response response) {
49 | if (response.getStatusInfo().getFamily() != Response.Status.Family.SUCCESSFUL)
50 | throw new IllegalStateException("Could not start coffee brew, status: " + response.getStatus());
51 | }
52 |
53 | @PreDestroy
54 | private void closeClient() {
55 | client.close();
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/coffee-shop/src/main/java/com/sebastian_daschner/coffee_shop/boundary/OrdersResource.java:
--------------------------------------------------------------------------------
1 | package com.sebastian_daschner.coffee_shop.boundary;
2 |
3 | import com.sebastian_daschner.coffee_shop.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 | .host(request.getServerName())
65 | .port(-1)
66 | .path(OrdersResource.class)
67 | .path(OrdersResource.class, "getOrder")
68 | .build(order.getId());
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------