├── .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 | --------------------------------------------------------------------------------