├── .github └── workflows │ └── build.yml ├── .gitignore ├── HOW-TO-RUN.md ├── README.md ├── WIE-LAUFEN.md ├── license.md ├── microservice-linkerd-bonus ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── Dockerfile ├── bonus.yaml ├── docker-build.sh ├── docker-push-gcp.sh ├── fix-bonus-dockerhub.sh ├── fix-bonus-gcp.sh ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── ewolff │ │ │ └── microservice │ │ │ └── bonus │ │ │ ├── Bonus.java │ │ │ ├── BonusApp.java │ │ │ ├── BonusRepository.java │ │ │ ├── BonusService.java │ │ │ ├── Customer.java │ │ │ ├── poller │ │ │ ├── BonusPoller.java │ │ │ ├── OrderFeed.java │ │ │ └── OrderFeedEntry.java │ │ │ └── web │ │ │ ├── BonusController.java │ │ │ └── PollController.java │ └── resources │ │ ├── application.properties │ │ └── templates │ │ ├── bonus.html │ │ ├── bonuslist.html │ │ └── layout.html │ └── test │ ├── java │ └── com │ │ └── ewolff │ │ └── microservice │ │ └── bonus │ │ ├── BonusServiceTest.java │ │ ├── BonusTestApp.java │ │ ├── BonusWebIntegrationTest.java │ │ └── PollingTest.java │ └── resources │ ├── application-test.properties │ └── logback-spring.xml └── microservice-linkerd-demo ├── apache ├── 000-default.conf ├── Dockerfile └── index.html ├── docker-build.sh ├── docker-push-gcp.sh ├── enable-tracing.sh ├── failing-order-service.yaml ├── fault-injection.yaml ├── fix-microservices-dockerhub.sh ├── fix-microservices-gcp.sh ├── infrastructure.yaml ├── ingress-forward.sh ├── ingress-url.sh ├── load.sh ├── microservice-linkerd-invoicing ├── Dockerfile ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── ewolff │ │ │ └── microservice │ │ │ └── invoicing │ │ │ ├── Address.java │ │ │ ├── Customer.java │ │ │ ├── Invoice.java │ │ │ ├── InvoiceApp.java │ │ │ ├── InvoiceLine.java │ │ │ ├── InvoiceRepository.java │ │ │ ├── InvoiceService.java │ │ │ ├── Item.java │ │ │ ├── poller │ │ │ ├── InvoicePoller.java │ │ │ ├── OrderFeed.java │ │ │ └── OrderFeedEntry.java │ │ │ └── web │ │ │ ├── InvoiceController.java │ │ │ └── PollController.java │ └── resources │ │ ├── application.properties │ │ └── templates │ │ ├── invoice.html │ │ ├── invoicelist.html │ │ ├── layout.html │ │ └── success.html │ └── test │ ├── java │ └── com │ │ └── ewolff │ │ └── microservice │ │ └── invoicing │ │ ├── InvoiceTestApp.java │ │ ├── InvoiceWebIntegrationTest.java │ │ ├── InvoicingServiceTest.java │ │ └── PollingTest.java │ └── resources │ ├── application-test.properties │ └── logback-spring.xml ├── microservice-linkerd-order ├── Dockerfile ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── ewolff │ │ │ └── microservice │ │ │ └── order │ │ │ ├── OrderApp.java │ │ │ ├── OrderFeed.java │ │ │ ├── OrderFeedEntry.java │ │ │ ├── RandomlyFailingFilter.java │ │ │ ├── customer │ │ │ ├── Customer.java │ │ │ ├── CustomerFormatter.java │ │ │ ├── CustomerRepository.java │ │ │ └── CustomerTestDataGenerator.java │ │ │ ├── item │ │ │ ├── Item.java │ │ │ ├── ItemFormatter.java │ │ │ ├── ItemRepository.java │ │ │ └── ItemTestDataGenerator.java │ │ │ └── logic │ │ │ ├── Address.java │ │ │ ├── Order.java │ │ │ ├── OrderController.java │ │ │ ├── OrderLine.java │ │ │ ├── OrderRepository.java │ │ │ ├── OrderRestController.java │ │ │ ├── OrderService.java │ │ │ └── SpringRestDataConfig.java │ └── resources │ │ ├── application.properties │ │ ├── static │ │ └── monitor.html │ │ └── templates │ │ ├── layout.html │ │ ├── order-full.html │ │ ├── order.html │ │ ├── orderForm.html │ │ ├── orderlist.html │ │ └── success.html │ └── test │ ├── java │ └── com │ │ └── ewolff │ │ └── microservice │ │ └── order │ │ ├── CustomerTestDataGeneratorTest.java │ │ ├── FeedClientTest.java │ │ ├── ItemTestDataGeneratorTest.java │ │ ├── OrderTestApp.java │ │ ├── OrderTestDataGenerator.java │ │ ├── PactTest.java │ │ └── logic │ │ ├── OrderServiceTest.java │ │ └── OrderWebIntegrationTest.java │ └── resources │ ├── application-test.properties │ ├── logback-spring.xml │ └── pacts │ ├── Invoice-OrderProvider.json │ └── Shipping-OrderProvider.json ├── microservice-linkerd-shipping ├── Dockerfile ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── ewolff │ │ │ └── microservice │ │ │ └── shipping │ │ │ ├── Address.java │ │ │ ├── Customer.java │ │ │ ├── Item.java │ │ │ ├── Shipment.java │ │ │ ├── ShipmentLine.java │ │ │ ├── ShipmentRepository.java │ │ │ ├── ShipmentService.java │ │ │ ├── ShippingApp.java │ │ │ ├── poller │ │ │ ├── OrderFeed.java │ │ │ ├── OrderFeedEntry.java │ │ │ └── ShippingPoller.java │ │ │ └── web │ │ │ ├── PollController.java │ │ │ └── ShippingController.java │ └── resources │ │ ├── application.properties │ │ └── templates │ │ ├── layout.html │ │ ├── shipment.html │ │ ├── shipmentlist.html │ │ └── success.html │ └── test │ ├── java │ └── com │ │ └── ewolff │ │ └── microservice │ │ └── shipping │ │ ├── PollingTest.java │ │ ├── ShippingServiceTest.java │ │ ├── ShippingTestApp.java │ │ └── ShippingWebIntegrationTest.java │ └── resources │ ├── application-test.properties │ └── logback-spring.xml ├── microservices.yaml ├── monitoring-prometheus.sh ├── mvnw ├── mvnw.cmd ├── pom.xml ├── postgres ├── Dockerfile └── init-user-db.sh ├── retry.yaml ├── timeout.yaml ├── tracing.sh └── tracing.yaml /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build and Publish Docker Images 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Set up JDK 11 17 | uses: actions/setup-java@v1 18 | with: 19 | java-version: 11 20 | - name: Build bonus microservice with Maven 21 | run: cd microservice-linkerd-bonus && mvn -B package --file pom.xml 22 | - name: Create Docker images for bonus microservice 23 | run: cd microservice-linkerd-bonus && sh ./docker-build.sh 24 | - name: Log into registry 25 | run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin 26 | - name: Push image for bonus microservice 27 | run: | 28 | IMAGE_PREFIX=${{ secrets.DOCKER_USERNAME }} 29 | docker tag microservice-linkerd-bonus:1 $IMAGE_PREFIX/microservice-linkerd-bonus:1 30 | docker push $IMAGE_PREFIX/microservice-linkerd-bonus:1 31 | 32 | 33 | - name: Build other microservices with Maven 34 | run: cd microservice-linkerd-demo && mvn -B package --file pom.xml 35 | - name: Create Docker images for other microservicee 36 | run: cd microservice-linkerd-demo && sh ./docker-build.sh 37 | - name: Log into registry 38 | run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin 39 | - name: Push image for other microservices 40 | run: | 41 | IMAGE_PREFIX=${{ secrets.DOCKER_USERNAME }} 42 | docker tag microservice-linkerd-apache $IMAGE_PREFIX/microservice-linkerd-apache:latest 43 | docker push $IMAGE_PREFIX/microservice-linkerd-apache:latest 44 | docker tag microservice-linkerd-postgres $IMAGE_PREFIX/microservice-linkerd-postgres:latest 45 | docker push $IMAGE_PREFIX/microservice-linkerd-postgres:latest 46 | docker tag microservice-linkerd-shipping:1 $IMAGE_PREFIX/microservice-linkerd-shipping:1 47 | docker push $IMAGE_PREFIX/microservice-linkerd-shipping:1 48 | docker tag microservice-linkerd-invoicing:1 $IMAGE_PREFIX/microservice-linkerd-invoicing:1 49 | docker push $IMAGE_PREFIX/microservice-linkerd-invoicing:1 50 | docker tag microservice-linkerd-order:1 $IMAGE_PREFIX/microservice-linkerd-order:1 51 | docker push $IMAGE_PREFIX/microservice-linkerd-order:1 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .mvn 3 | .vagrant 4 | .springBeans 5 | .classpath 6 | .project 7 | .settings 8 | .idea 9 | *.iml 10 | target/ 11 | linkerd-*/ 12 | pom.xml.tag 13 | pom.xml.releaseBackup 14 | pom.xml.versionsBackup 15 | pom.xml.next 16 | release.properties 17 | dependency-reduced-pom.xml 18 | buildNumber.properties 19 | .mvn/timing.properties 20 | .code 21 | .vscode 22 | *~ 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Microservice Linkerd Sample 2 | =========================== 3 | 4 | [Deutsche Anleitung zum Starten des Beispiels](WIE-LAUFEN.md) 5 | 6 | This demo uses [Kubernetes](https://kubernetes.io/) as Docker 7 | environment. Kubernetes also support service discovery and load 8 | balancing. An Apache httpd as a reverse proxy routes the calls to the 9 | services. 10 | 11 | Also the demo uses [linkerd](https://linkerd.io/) for features like 12 | monitoring, fault injection, and circuit breaking. 13 | 14 | This project creates a complete micro service demo system in Docker 15 | containers. The services are implemented in Java using Spring Boot and 16 | Spring Cloud. 17 | 18 | 19 | It uses three microservices: 20 | - `Order` to accept orders. 21 | - `Shipping` to ship the orders. 22 | - `Invoicing` to ship invoices. 23 | 24 | How to run 25 | --------- 26 | 27 | See [How to run](HOW-TO-RUN.md). 28 | 29 | 30 | Remarks on the Code 31 | ------------------- 32 | 33 | The microservices are: 34 | - [microservice-linkerd-order](microservice-linkerd-demo/microservice-linkerd-order) to create the orders 35 | - [microserivce-linkerd-shipping](microservice-linkerd-demo/microservice-linkerd-shipping) for the shipping 36 | - [microservice-linkerd-invoicing](microservice-linkerd-demo/microservice-linkerd-invoicing) for the invoices 37 | 38 | The microservices have an Java main application in `src/test/java` to 39 | run them stand alone. microservice-demo-shipping and 40 | microservice-demo-invoicing both use a stub for the 41 | other order service for the tests. 42 | 43 | The data of an order is copied - including the data of the customer 44 | and the items. So if a customer or item changes in the order system 45 | this does not influence existing shipments and invoices. It would be 46 | odd if a change to a price would also change existing invoices. Also 47 | only the information needed for the shipment and the invoice are 48 | copied over to the other systems. 49 | 50 | The job to poll the order feed is run every 30 seconds. 51 | 52 | -------------------------------------------------------------------------------- /microservice-linkerd-bonus/.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | import java.net.*; 21 | import java.io.*; 22 | import java.nio.channels.*; 23 | import java.util.Properties; 24 | 25 | public class MavenWrapperDownloader { 26 | 27 | /** 28 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 29 | */ 30 | private static final String DEFAULT_DOWNLOAD_URL = 31 | "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; 32 | 33 | /** 34 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 35 | * use instead of the default one. 36 | */ 37 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 38 | ".mvn/wrapper/maven-wrapper.properties"; 39 | 40 | /** 41 | * Path where the maven-wrapper.jar will be saved to. 42 | */ 43 | private static final String MAVEN_WRAPPER_JAR_PATH = 44 | ".mvn/wrapper/maven-wrapper.jar"; 45 | 46 | /** 47 | * Name of the property which should be used to override the default download url for the wrapper. 48 | */ 49 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 50 | 51 | public static void main(String args[]) { 52 | System.out.println("- Downloader started"); 53 | File baseDirectory = new File(args[0]); 54 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 55 | 56 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 57 | // wrapperUrl parameter. 58 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 59 | String url = DEFAULT_DOWNLOAD_URL; 60 | if(mavenWrapperPropertyFile.exists()) { 61 | FileInputStream mavenWrapperPropertyFileInputStream = null; 62 | try { 63 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 64 | Properties mavenWrapperProperties = new Properties(); 65 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 66 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 67 | } catch (IOException e) { 68 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 69 | } finally { 70 | try { 71 | if(mavenWrapperPropertyFileInputStream != null) { 72 | mavenWrapperPropertyFileInputStream.close(); 73 | } 74 | } catch (IOException e) { 75 | // Ignore ... 76 | } 77 | } 78 | } 79 | System.out.println("- Downloading from: : " + url); 80 | 81 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 82 | if(!outputFile.getParentFile().exists()) { 83 | if(!outputFile.getParentFile().mkdirs()) { 84 | System.out.println( 85 | "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 86 | } 87 | } 88 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 89 | try { 90 | downloadFileFromURL(url, outputFile); 91 | System.out.println("Done"); 92 | System.exit(0); 93 | } catch (Throwable e) { 94 | System.out.println("- Error downloading"); 95 | e.printStackTrace(); 96 | System.exit(1); 97 | } 98 | } 99 | 100 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 101 | URL website = new URL(urlString); 102 | ReadableByteChannel rbc; 103 | rbc = Channels.newChannel(website.openStream()); 104 | FileOutputStream fos = new FileOutputStream(destination); 105 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 106 | fos.close(); 107 | rbc.close(); 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /microservice-linkerd-bonus/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ewolff/microservice-linkerd/39d80e6e95a6dd2d79e1227bff67a8b9caf1c475/microservice-linkerd-bonus/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /microservice-linkerd-bonus/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.5.4/apache-maven-3.5.4-bin.zip -------------------------------------------------------------------------------- /microservice-linkerd-bonus/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:11.0.2-jre-slim 2 | COPY target/microservice-linkerd-bonus-0.0.1-SNAPSHOT.jar . 3 | CMD /usr/bin/java -Xmx300m -Xms300m -XX:TieredStopAtLevel=1 -noverify -jar microservice-linkerd-bonus-0.0.1-SNAPSHOT.jar 4 | EXPOSE 8080 -------------------------------------------------------------------------------- /microservice-linkerd-bonus/bonus.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | creationTimestamp: null 5 | labels: 6 | app: bonus 7 | version: "1.0" 8 | name: bonus 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app: bonus 14 | strategy: {} 15 | template: 16 | metadata: 17 | creationTimestamp: null 18 | labels: 19 | app: bonus 20 | spec: 21 | containers: 22 | - name: bonus 23 | image: microservice-linkerd-bonus:1 24 | imagePullPolicy: Never 25 | ports: 26 | - containerPort: 8080 27 | resources: {} 28 | status: {} 29 | 30 | --- 31 | 32 | apiVersion: v1 33 | kind: Service 34 | metadata: 35 | creationTimestamp: null 36 | labels: 37 | app: bonus 38 | name: bonus 39 | spec: 40 | ports: 41 | - port: 8080 42 | protocol: TCP 43 | targetPort: 8080 44 | name: http 45 | selector: 46 | app: bonus 47 | type: NodePort 48 | status: 49 | loadBalancer: {} 50 | 51 | --- 52 | 53 | apiVersion: extensions/v1beta1 54 | kind: Ingress 55 | metadata: 56 | name: bonus 57 | annotations: 58 | kubernetes.io/ingress.class: "traefik" 59 | ingress.kubernetes.io/custom-request-headers: l5d-dst-override:bonus.default.svc.cluster.local:80 60 | spec: 61 | rules: 62 | - http: 63 | paths: 64 | - path: /bonus 65 | backend: 66 | serviceName: bonus 67 | servicePort: 8080 68 | -------------------------------------------------------------------------------- /microservice-linkerd-bonus/docker-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | docker build --tag=microservice-linkerd-bonus:1 . 3 | -------------------------------------------------------------------------------- /microservice-linkerd-bonus/docker-push-gcp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | docker tag microservice-linkerd-demo gcr.io/${PROJECT_ID}/microservice-linkerd-demo 3 | docker push gcr.io/${PROJECT_ID}/microservice-linkerd-demo 4 | -------------------------------------------------------------------------------- /microservice-linkerd-bonus/fix-bonus-dockerhub.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | sed "s,image: ,image: docker.io/ewolff/,g" bonus.yaml | sed "s,imagePullPolicy: Never,imagePullPolicy: IfNotPresent," > bonus-dockerhub.yaml 3 | -------------------------------------------------------------------------------- /microservice-linkerd-bonus/fix-bonus-gcp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | sed "s,image: ,image: gcr.io/$PROJECT_ID/,g" bonus.yaml | sed -i "" "s,imagePullPolicy: Never,imagePullPolicy: IfNotPresent," > bonus-gcp.yaml 3 | -------------------------------------------------------------------------------- /microservice-linkerd-bonus/pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.3.3.RELEASE 9 | 10 | 11 | 12 | 4.0.0 13 | com.ewolff 14 | microservice-linkerd-bonus 15 | 0.0.1-SNAPSHOT 16 | 17 | 18 | 11 19 | Hoxton.SR7 20 | 21 | 22 | 23 | 24 | 25 | org.springframework.cloud 26 | spring-cloud-dependencies 27 | ${spring-cloud.version} 28 | pom 29 | import 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-maven-plugin 39 | 40 | 41 | org.apache.maven.plugins 42 | maven-surefire-plugin 43 | 44 | -XX:TieredStopAtLevel=1 -noverify 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | org.webjars 54 | bootstrap 55 | 3.3.6 56 | 57 | 58 | 59 | org.springframework.boot 60 | spring-boot-starter-data-jpa 61 | 62 | 63 | 64 | org.springframework.boot 65 | spring-boot-starter-thymeleaf 66 | 67 | 68 | 69 | nz.net.ultraq.thymeleaf 70 | thymeleaf-layout-dialect 71 | 72 | 73 | 74 | org.springframework.boot 75 | spring-boot-starter-web 76 | 77 | 78 | 79 | org.springframework.boot 80 | spring-boot-starter-actuator 81 | 82 | 83 | 84 | org.springframework.boot 85 | spring-boot-starter-test 86 | test 87 | 88 | 89 | 90 | org.springframework.hateoas 91 | spring-hateoas 92 | 93 | 94 | 95 | javax.xml.bind 96 | jaxb-api 97 | 98 | 99 | 100 | com.jayway.jsonpath 101 | json-path 102 | runtime 103 | 104 | 105 | 106 | org.hsqldb 107 | hsqldb 108 | runtime 109 | 110 | 111 | 112 | org.postgresql 113 | postgresql 114 | runtime 115 | 116 | 117 | 118 | org.apache.httpcomponents 119 | httpclient 120 | 121 | 122 | 123 | commons-lang 124 | commons-lang 125 | 2.6 126 | 127 | 128 | 129 | org.springframework.cloud 130 | spring-cloud-starter-sleuth 131 | 132 | 133 | 134 | net.logstash.logback 135 | logstash-logback-encoder 136 | 4.11 137 | 138 | 139 | 140 | com.internetitem 141 | logback-elasticsearch-appender 142 | 1.6 143 | 144 | 145 | 146 | org.junit.jupiter 147 | junit-jupiter-api 148 | test 149 | 150 | 151 | 152 | org.junit.jupiter 153 | junit-jupiter-engine 154 | test 155 | 156 | 157 | 158 | au.com.dius 159 | pact-jvm-consumer-junit5 160 | 4.0.0-beta.2 161 | test 162 | 163 | 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /microservice-linkerd-bonus/src/main/java/com/ewolff/microservice/bonus/Bonus.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.bonus; 2 | 3 | import java.util.Date; 4 | 5 | import javax.persistence.Embedded; 6 | import javax.persistence.Entity; 7 | import javax.persistence.Id; 8 | 9 | import org.apache.commons.lang.builder.EqualsBuilder; 10 | import org.apache.commons.lang.builder.HashCodeBuilder; 11 | import org.apache.commons.lang.builder.ToStringBuilder; 12 | 13 | @Entity 14 | public class Bonus { 15 | 16 | @Id 17 | private long id; 18 | 19 | @Embedded 20 | private Customer customer; 21 | 22 | private Date updated; 23 | 24 | private double revenue; 25 | 26 | public Bonus() { 27 | super(); 28 | } 29 | 30 | public Bonus(long id, Customer customer, Date updated, double revenue) { 31 | super(); 32 | this.id = id; 33 | this.customer = customer; 34 | this.updated = updated; 35 | this.revenue = revenue; 36 | } 37 | 38 | public void setId(long id) { 39 | this.id = id; 40 | } 41 | 42 | public long getId() { 43 | return id; 44 | } 45 | 46 | public double getRevenue() { 47 | return revenue; 48 | } 49 | 50 | public void setRevenue(double revenue) { 51 | this.revenue = revenue; 52 | } 53 | 54 | public Date getUpdated() { 55 | return updated; 56 | } 57 | 58 | public void setUpdated(Date created) { 59 | this.updated = created; 60 | } 61 | 62 | public Customer getCustomer() { 63 | return customer; 64 | } 65 | 66 | public void setCustomer(Customer customerId) { 67 | this.customer = customerId; 68 | } 69 | 70 | public Bonus(Customer customer) { 71 | super(); 72 | this.customer = customer; 73 | } 74 | 75 | @Override 76 | public String toString() { 77 | return ToStringBuilder.reflectionToString(this); 78 | } 79 | 80 | @Override 81 | public int hashCode() { 82 | return HashCodeBuilder.reflectionHashCode(this); 83 | } 84 | 85 | @Override 86 | public boolean equals(Object obj) { 87 | return EqualsBuilder.reflectionEquals(this, obj); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /microservice-linkerd-bonus/src/main/java/com/ewolff/microservice/bonus/BonusApp.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.bonus; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.scheduling.annotation.EnableScheduling; 6 | 7 | @EnableScheduling 8 | @SpringBootApplication 9 | public class BonusApp { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(BonusApp.class, args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /microservice-linkerd-bonus/src/main/java/com/ewolff/microservice/bonus/BonusRepository.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.bonus; 2 | 3 | import java.util.Date; 4 | 5 | import org.springframework.data.jpa.repository.Query; 6 | import org.springframework.data.repository.PagingAndSortingRepository; 7 | 8 | public interface BonusRepository extends PagingAndSortingRepository { 9 | 10 | @Query("SELECT max(b.updated) FROM Bonus b") 11 | Date lastUpdate(); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /microservice-linkerd-bonus/src/main/java/com/ewolff/microservice/bonus/BonusService.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.bonus; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | import org.springframework.transaction.annotation.Transactional; 8 | 9 | @Service 10 | public class BonusService { 11 | 12 | private final Logger log = LoggerFactory.getLogger(BonusService.class); 13 | 14 | private BonusRepository bonusRepository; 15 | 16 | @Autowired 17 | public BonusService(BonusRepository bonusRepository) { 18 | super(); 19 | this.bonusRepository = bonusRepository; 20 | } 21 | 22 | @Transactional 23 | public void calculateBonus(Bonus bonus) { 24 | if (bonusRepository.existsById(bonus.getId())) { 25 | log.info("Bonus id {} already exists - ignored", bonus.getId()); 26 | } else { 27 | bonusRepository.save(bonus); 28 | } 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /microservice-linkerd-bonus/src/main/java/com/ewolff/microservice/bonus/Customer.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.bonus; 2 | 3 | import javax.persistence.Column; 4 | import javax.persistence.Embeddable; 5 | 6 | import org.apache.commons.lang.builder.EqualsBuilder; 7 | import org.apache.commons.lang.builder.HashCodeBuilder; 8 | import org.apache.commons.lang.builder.ToStringBuilder; 9 | 10 | @Embeddable 11 | public class Customer { 12 | 13 | @Column(nullable = false) 14 | private Long customerId; 15 | 16 | @Column(nullable = false) 17 | private String name; 18 | 19 | @Column(nullable = false) 20 | private String firstname; 21 | 22 | public Customer() { 23 | super(); 24 | customerId = 0l; 25 | } 26 | 27 | public Customer(long customerId, String firstname, String name) { 28 | super(); 29 | this.customerId = customerId; 30 | this.name = name; 31 | this.firstname = firstname; 32 | } 33 | 34 | public String getName() { 35 | return name; 36 | } 37 | 38 | public void setName(String name) { 39 | this.name = name; 40 | } 41 | 42 | public String getFirstname() { 43 | return firstname; 44 | } 45 | 46 | public void setFirstname(String firstname) { 47 | this.firstname = firstname; 48 | } 49 | 50 | public Long getCustomerId() { 51 | return customerId; 52 | } 53 | 54 | public void setCustomerId(Long id) { 55 | this.customerId = id; 56 | } 57 | 58 | @Override 59 | public String toString() { 60 | return ToStringBuilder.reflectionToString(this); 61 | } 62 | 63 | @Override 64 | public int hashCode() { 65 | return HashCodeBuilder.reflectionHashCode(this); 66 | 67 | } 68 | 69 | @Override 70 | public boolean equals(Object obj) { 71 | return EqualsBuilder.reflectionEquals(this, obj); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /microservice-linkerd-bonus/src/main/java/com/ewolff/microservice/bonus/poller/BonusPoller.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.bonus.poller; 2 | 3 | import java.util.Date; 4 | 5 | import org.apache.http.client.utils.DateUtils; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.beans.factory.annotation.Value; 10 | import org.springframework.http.HttpEntity; 11 | import org.springframework.http.HttpHeaders; 12 | import org.springframework.http.HttpMethod; 13 | import org.springframework.http.HttpStatus; 14 | import org.springframework.http.ResponseEntity; 15 | import org.springframework.scheduling.annotation.Scheduled; 16 | import org.springframework.stereotype.Component; 17 | import org.springframework.web.client.RestTemplate; 18 | 19 | import com.ewolff.microservice.bonus.Bonus; 20 | import com.ewolff.microservice.bonus.BonusRepository; 21 | import com.ewolff.microservice.bonus.BonusService; 22 | 23 | @Component 24 | public class BonusPoller { 25 | 26 | private final Logger log = LoggerFactory.getLogger(BonusPoller.class); 27 | 28 | private String url = ""; 29 | 30 | private RestTemplate restTemplate = new RestTemplate(); 31 | 32 | private Date lastModified = null; 33 | 34 | private BonusService bonusService; 35 | 36 | private boolean pollingActivated = true; 37 | 38 | @Autowired 39 | public BonusPoller(@Value("${order.url}") String url, @Value("${poller.actived:true}") boolean pollingActivated, 40 | BonusRepository bonusRepository, BonusService bonusService) { 41 | super(); 42 | this.url = url; 43 | this.bonusService = bonusService; 44 | this.pollingActivated = pollingActivated; 45 | } 46 | 47 | @Scheduled(fixedDelay = 30000) 48 | public void poll() { 49 | if (pollingActivated) { 50 | pollInternal(); 51 | } 52 | } 53 | 54 | public void pollInternal() { 55 | HttpHeaders requestHeaders = new HttpHeaders(); 56 | if (lastModified != null) { 57 | requestHeaders.set(HttpHeaders.IF_MODIFIED_SINCE, DateUtils.formatDate(lastModified)); 58 | } 59 | HttpEntity requestEntity = new HttpEntity(requestHeaders); 60 | ResponseEntity response = restTemplate.exchange(url, HttpMethod.GET, requestEntity, OrderFeed.class); 61 | 62 | if (response.getStatusCode() != HttpStatus.NOT_MODIFIED) { 63 | log.trace("data has been modified"); 64 | OrderFeed feed = response.getBody(); 65 | for (OrderFeedEntry entry : feed.getOrders()) { 66 | if ((lastModified == null) || (entry.getUpdated().after(lastModified))) { 67 | Bonus bonus = restTemplate 68 | .getForEntity(entry.getLink(), Bonus.class).getBody(); 69 | log.trace("saving bonus {}", bonus.getId()); 70 | bonusService.calculateBonus(bonus); 71 | } 72 | } 73 | if (response.getHeaders().getFirst("Last-Modified") != null) { 74 | lastModified = DateUtils.parseDate(response.getHeaders().getFirst(HttpHeaders.LAST_MODIFIED)); 75 | log.trace("Last-Modified header {}", lastModified); 76 | } 77 | } else { 78 | log.trace("no new data"); 79 | } 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /microservice-linkerd-bonus/src/main/java/com/ewolff/microservice/bonus/poller/OrderFeed.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.bonus.poller; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Date; 5 | import java.util.List; 6 | 7 | import org.apache.commons.lang.builder.EqualsBuilder; 8 | import org.apache.commons.lang.builder.ToStringBuilder; 9 | 10 | import net.logstash.logback.encoder.org.apache.commons.lang.builder.HashCodeBuilder; 11 | 12 | public class OrderFeed { 13 | 14 | private Date updated; 15 | 16 | private List orders; 17 | 18 | public OrderFeed() { 19 | super(); 20 | orders = new ArrayList(); 21 | } 22 | 23 | public Date getUpdated() { 24 | return updated; 25 | } 26 | 27 | public void setUpdated(Date updated) { 28 | this.updated = updated; 29 | } 30 | 31 | public List getOrders() { 32 | return orders; 33 | } 34 | 35 | public void setOrders(List orders) { 36 | this.orders = orders; 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | return ToStringBuilder.reflectionToString(this); 42 | } 43 | 44 | @Override 45 | public int hashCode() { 46 | return HashCodeBuilder.reflectionHashCode(this); 47 | } 48 | 49 | @Override 50 | public boolean equals(Object obj) { 51 | return EqualsBuilder.reflectionEquals(this, obj); 52 | } 53 | 54 | } -------------------------------------------------------------------------------- /microservice-linkerd-bonus/src/main/java/com/ewolff/microservice/bonus/poller/OrderFeedEntry.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.bonus.poller; 2 | 3 | import java.util.Date; 4 | 5 | import org.apache.commons.lang.builder.EqualsBuilder; 6 | import org.apache.commons.lang.builder.HashCodeBuilder; 7 | import org.apache.commons.lang.builder.ToStringBuilder; 8 | 9 | public class OrderFeedEntry { 10 | 11 | private long id; 12 | 13 | private String link; 14 | 15 | private Date updated; 16 | 17 | public long getId() { 18 | return id; 19 | } 20 | 21 | public void setId(long id) { 22 | this.id = id; 23 | } 24 | 25 | public String getLink() { 26 | return link; 27 | } 28 | 29 | public void setLink(String link) { 30 | this.link = link; 31 | } 32 | 33 | public Date getUpdated() { 34 | return updated; 35 | } 36 | 37 | public void setUpdated(Date updated) { 38 | this.updated = updated; 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return ToStringBuilder.reflectionToString(this); 44 | } 45 | 46 | @Override 47 | public int hashCode() { 48 | return HashCodeBuilder.reflectionHashCode(this); 49 | } 50 | 51 | @Override 52 | public boolean equals(Object obj) { 53 | return EqualsBuilder.reflectionEquals(this, obj); 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /microservice-linkerd-bonus/src/main/java/com/ewolff/microservice/bonus/web/BonusController.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.bonus.web; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.http.MediaType; 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.web.bind.annotation.PathVariable; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RequestMethod; 9 | import org.springframework.web.servlet.ModelAndView; 10 | 11 | import com.ewolff.microservice.bonus.BonusRepository; 12 | 13 | @Controller 14 | public class BonusController { 15 | 16 | private BonusRepository bonusRepository; 17 | 18 | @Autowired 19 | public BonusController(BonusRepository bonusRepository) { 20 | this.bonusRepository = bonusRepository; 21 | } 22 | 23 | @RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE) 24 | public ModelAndView bonus(@PathVariable("id") long id) { 25 | return new ModelAndView("bonus", "bonus", bonusRepository.findById(id).get()); 26 | } 27 | 28 | @RequestMapping("/") 29 | public ModelAndView bonusList() { 30 | return new ModelAndView("bonuslist", "bonuses", bonusRepository.findAll()); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /microservice-linkerd-bonus/src/main/java/com/ewolff/microservice/bonus/web/PollController.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.bonus.web; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RequestMethod; 7 | 8 | import com.ewolff.microservice.bonus.poller.BonusPoller; 9 | 10 | @Controller 11 | public class PollController { 12 | 13 | private BonusPoller poller; 14 | 15 | @Autowired 16 | public PollController(BonusPoller poller) { 17 | this.poller = poller; 18 | } 19 | 20 | @RequestMapping(value = "/poll", method = RequestMethod.POST) 21 | public String poll() { 22 | poller.poll(); 23 | return "redirect:/"; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /microservice-linkerd-bonus/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8080 2 | spring.application.name=bonus 3 | server.servlet.context-path=/bonus 4 | management.endpoints.web.exposure.include=* 5 | logging.level.org.springframework.boot.actuate.trace.WebRequestTraceFilter: TRACE 6 | logging.level.com.ewolff.microservice.bonus.poller: TRACE 7 | logging.level.org.springframework.http.converter.json: ERROR 8 | order.url=http://order:80/order/feed 9 | spring.jpa.hibernate.ddl-auto=update 10 | spring.datasource.url=jdbc:postgresql://postgres/dbbonus 11 | spring.datasource.username=dbuser 12 | spring.datasource.password=dbpass 13 | spring.datasource.driver-class-name=org.postgresql.Driver 14 | spring.sleuth.propagation-keys=x-request-id,x-ot-span-context -------------------------------------------------------------------------------- /microservice-linkerd-bonus/src/main/resources/templates/bonus.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Bonus 7 | 8 | 9 |

Bonus

10 |
11 | 12 |
13 |
14 | Customer 15 |
16 |
18 |
19 | 20 |
21 |
22 | Revenue 23 |
24 |
26 |
27 | 28 |
29 | 30 | -------------------------------------------------------------------------------- /microservice-linkerd-bonus/src/main/resources/templates/bonuslist.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Bonuses : View all 7 | 8 | 9 |

Bonuses : View all

10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 25 | 28 | 29 | 30 |
IDCustomer
No bonuses
1Firstname 27 | Name
31 |
32 |
33 | 35 |
36 |
37 |
38 | 39 | -------------------------------------------------------------------------------- /microservice-linkerd-bonus/src/main/resources/templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | Layout 7 | 9 | 11 | 12 | 13 | 14 |
15 | 23 |

Layout

24 |
Fake content
25 |
26 | 14 | 15 | 16 | 17 |

Order, Shipping, Invoicing

18 |
19 |
20 |
21 | Order 22 |
23 |
Create an order
24 |
25 |
26 |
27 | Shipping 28 |
29 |
Display shipping information
30 |
31 |
32 |
33 | Invoicing 34 |
35 |
Display invoices
36 |
37 |
38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/docker-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | docker build --tag=microservice-linkerd-apache apache 3 | docker build --tag=microservice-linkerd-postgres postgres 4 | docker build --tag=microservice-linkerd-shipping:1 microservice-linkerd-shipping 5 | docker build --tag=microservice-linkerd-invoicing:1 microservice-linkerd-invoicing 6 | docker build --tag=microservice-linkerd-order:1 microservice-linkerd-order 7 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/docker-push-gcp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | docker tag microservice-linkerd-apache gcr.io/${PROJECT_ID}/microservice-linkerd-apache 3 | docker push gcr.io/${PROJECT_ID}/microservice-linkerd-apache 4 | docker tag microservice-linkerd-postgres gcr.io/${PROJECT_ID}/microservice-linkerd-postgres 5 | docker push gcr.io/${PROJECT_ID}/microservice-linkerd-postgres 6 | docker tag microservice-linkerd-shipping:1 gcr.io/${PROJECT_ID}/microservice-linkerd-shipping:1 7 | docker push gcr.io/${PROJECT_ID}/microservice-linkerd-shipping:1 8 | docker tag microservice-linkerd-invoicing:1 gcr.io/${PROJECT_ID}/microservice-linkerd-invoicing:1 9 | docker push gcr.io/${PROJECT_ID}/microservice-linkerd-invoicing:1 10 | docker tag microservice-linkerd-order:1 gcr.io/${PROJECT_ID}/microservice-linkerd-order:1 11 | docker push gcr.io/${PROJECT_ID}/microservice-linkerd-order:1 12 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/enable-tracing.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | linkerd upgrade --addon-config tracing.yaml | kubectl apply -f - 3 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/failing-order-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | creationTimestamp: null 5 | labels: 6 | app: order 7 | version: "1.0" 8 | name: order 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app: order 14 | strategy: {} 15 | template: 16 | metadata: 17 | creationTimestamp: null 18 | labels: 19 | app: order 20 | spec: 21 | containers: 22 | - name: order 23 | image: microservice-linkerd-order:1 24 | imagePullPolicy: Never 25 | ports: 26 | - containerPort: 8080 27 | env: 28 | - name: FAILRANDOMLY 29 | value: "true" 30 | resources: {} 31 | status: {} -------------------------------------------------------------------------------- /microservice-linkerd-demo/fault-injection.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: error-injector 5 | data: 6 | nginx.conf: |- 7 | events {} 8 | http { 9 | server { 10 | listen 8080; 11 | location / { 12 | return 500; 13 | } 14 | } 15 | } 16 | 17 | --- 18 | 19 | apiVersion: apps/v1 20 | kind: Deployment 21 | metadata: 22 | name: error-injector 23 | labels: 24 | app: error-injector 25 | spec: 26 | selector: 27 | matchLabels: 28 | app: error-injector 29 | replicas: 1 30 | template: 31 | metadata: 32 | labels: 33 | app: error-injector 34 | spec: 35 | containers: 36 | - name: nginx 37 | image: nginx:alpine 38 | volumeMounts: 39 | - name: nginx-config 40 | mountPath: /etc/nginx/nginx.conf 41 | subPath: nginx.conf 42 | volumes: 43 | - name: nginx-config 44 | configMap: 45 | name: error-injector 46 | 47 | --- 48 | 49 | apiVersion: v1 50 | kind: Service 51 | metadata: 52 | name: error-injector 53 | spec: 54 | ports: 55 | - name: service 56 | port: 8080 57 | selector: 58 | app: error-injector 59 | 60 | --- 61 | 62 | apiVersion: split.smi-spec.io/v1alpha1 63 | kind: TrafficSplit 64 | metadata: 65 | name: error-split 66 | spec: 67 | service: order 68 | backends: 69 | - service: order 70 | weight: 500m 71 | - service: error-injector 72 | weight: 500m -------------------------------------------------------------------------------- /microservice-linkerd-demo/fix-microservices-dockerhub.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | sed "s,image: ,image: docker.io/ewolff/,g" microservices.yaml | sed "s,imagePullPolicy: Never,imagePullPolicy: IfNotPresent," > microservices-dockerhub.yaml 3 | sed "s,image: ,image: docker.io/ewolff/,g" infrastructure.yaml | sed "s,imagePullPolicy: Never,imagePullPolicy: IfNotPresent," > infrastructure-dockerhub.yaml 4 | sed "s,image: ,image: docker.io/ewolff/,g" failing-order-service.yaml | sed "s,imagePullPolicy: Never,imagePullPolicy: IfNotPresent," > failing-order-service-dockerhub.yaml 5 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/fix-microservices-gcp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | sed "s,image: ,image: gcr.io/$PROJECT_ID/,g" microservices.yaml | sed -i "" "s,imagePullPolicy: Never,imagePullPolicy: IfNotPresent," > microservices-gcp.yaml 3 | sed "s,image: ,image: gcr.io/$PROJECT_ID/,g" infrastructure.yaml | sed -i "" "s,imagePullPolicy: Never,imagePullPolicy: IfNotPresent," > infrastructure-gcp.yaml 4 | sed "s,image: ,image: gcr.io/$PROJECT_ID/,g" failing-order-service.yaml | sed -i "" "s,imagePullPolicy: Never,imagePullPolicy: IfNotPresent," > failing-order-service-gcp.yaml 5 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/infrastructure.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | creationTimestamp: null 5 | labels: 6 | app: apache 7 | version: "1.0" 8 | name: apache 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app: apache 14 | strategy: {} 15 | template: 16 | metadata: 17 | creationTimestamp: null 18 | labels: 19 | app: apache 20 | spec: 21 | containers: 22 | - name: apache 23 | image: microservice-linkerd-apache:latest 24 | imagePullPolicy: Never 25 | ports: 26 | - containerPort: 80 27 | resources: {} 28 | status: {} 29 | 30 | --- 31 | 32 | apiVersion: apps/v1 33 | kind: Deployment 34 | metadata: 35 | creationTimestamp: null 36 | labels: 37 | app: postgres 38 | version: "1.0" 39 | name: postgres 40 | annotations: 41 | sidecar.linkerd.io/inject: "false" 42 | spec: 43 | replicas: 1 44 | selector: 45 | matchLabels: 46 | app: postgres 47 | strategy: {} 48 | template: 49 | metadata: 50 | creationTimestamp: null 51 | labels: 52 | app: postgres 53 | spec: 54 | containers: 55 | - name: postgres 56 | image: microservice-linkerd-postgres:latest 57 | imagePullPolicy: Never 58 | ports: 59 | - containerPort: 5432 60 | env: 61 | - name: POSTGRES_USER 62 | value: "dbuser" 63 | - name: POSTGRES_PASSWORD 64 | value: "dbpass" 65 | resources: {} 66 | volumeMounts: 67 | - name: postgres 68 | mountPath: /var/lib/postgresql/data 69 | volumes: 70 | - name: postgres 71 | emptyDir: {} 72 | status: {} 73 | 74 | --- 75 | 76 | apiVersion: v1 77 | kind: Service 78 | metadata: 79 | labels: 80 | app: apache 81 | name: apache 82 | spec: 83 | ports: 84 | - port: 80 85 | protocol: TCP 86 | targetPort: 80 87 | name: http 88 | selector: 89 | app: apache 90 | type: NodePort 91 | 92 | --- 93 | 94 | apiVersion: v1 95 | kind: Service 96 | metadata: 97 | labels: 98 | app: postgres 99 | name: postgres 100 | spec: 101 | ports: 102 | - port: 5432 103 | protocol: TCP 104 | targetPort: 5432 105 | selector: 106 | app: postgres 107 | type: NodePort 108 | 109 | --- 110 | 111 | apiVersion: extensions/v1beta1 112 | kind: Ingress 113 | metadata: 114 | name: apache 115 | annotations: 116 | kubernetes.io/ingress.class: "traefik" 117 | ingress.kubernetes.io/custom-request-headers: l5d-dst-override:apache.default.svc.cluster.local:80 118 | spec: 119 | rules: 120 | - http: 121 | paths: 122 | - path: / 123 | backend: 124 | serviceName: apache 125 | servicePort: 80 -------------------------------------------------------------------------------- /microservice-linkerd-demo/ingress-forward.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo Open Ingress at http://localhost:31380/ 3 | kubectl port-forward deployment/traefik -n traefik 31380:8000 4 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/ingress-url.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | IP=$(kubectl get service traefik -n traefik -o jsonpath='{.status.loadBalancer.ingress[0].hostname}') 3 | PORT=$(kubectl get service traefik -n traefik -o jsonpath='{.spec.ports[?(@.name=="web")].port}') 4 | echo http://$IP:$PORT/ 5 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/load.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | for i in `seq 1 1000`; 3 | do 4 | curl -s -o /dev/null -I -w "%{http_code}" $1 5 | echo 6 | done 7 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-invoicing/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:11.0.2-jre-slim 2 | COPY target/microservice-linkerd-invoicing-0.0.1-SNAPSHOT.jar . 3 | CMD /usr/bin/java -Xmx300m -Xms300m -XX:TieredStopAtLevel=1 -noverify -jar microservice-linkerd-invoicing-0.0.1-SNAPSHOT.jar 4 | EXPOSE 8080 5 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-invoicing/pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | 6 | 7 | com.ewolff 8 | microservice-linkerd 9 | 0.0.1-SNAPSHOT 10 | 11 | 12 | microservice-linkerd-invoicing 13 | 14 | 15 | 16 | 17 | org.springframework.boot 18 | spring-boot-starter-data-jpa 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-thymeleaf 24 | 25 | 26 | 27 | nz.net.ultraq.thymeleaf 28 | thymeleaf-layout-dialect 29 | 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-web 34 | 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-actuator 39 | 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-starter-test 44 | test 45 | 46 | 47 | 48 | org.springframework.hateoas 49 | spring-hateoas 50 | 51 | 52 | 53 | com.jayway.jsonpath 54 | json-path 55 | runtime 56 | 57 | 58 | 59 | org.hsqldb 60 | hsqldb 61 | runtime 62 | 63 | 64 | 65 | org.postgresql 66 | postgresql 67 | runtime 68 | 69 | 70 | 71 | org.apache.httpcomponents 72 | httpclient 73 | 74 | 75 | 76 | javax.xml.bind 77 | jaxb-api 78 | 79 | 80 | 81 | commons-lang 82 | commons-lang 83 | 2.6 84 | 85 | 86 | 87 | org.webjars 88 | bootstrap 89 | 90 | 91 | 92 | org.springframework.cloud 93 | spring-cloud-starter-sleuth 94 | 95 | 96 | 97 | net.logstash.logback 98 | logstash-logback-encoder 99 | 4.11 100 | 101 | 102 | 103 | com.internetitem 104 | logback-elasticsearch-appender 105 | 1.6 106 | 107 | 108 | 109 | org.junit.jupiter 110 | junit-jupiter-api 111 | test 112 | 113 | 114 | 115 | org.junit.jupiter 116 | junit-jupiter-engine 117 | test 118 | 119 | 120 | 121 | au.com.dius 122 | pact-jvm-consumer-junit5 123 | 4.0.0-beta.2 124 | test 125 | 126 | 127 | 128 | javax.validation 129 | validation-api 130 | 131 | 132 | 133 | io.opentracing.brave 134 | brave-opentracing 135 | 136 | 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-invoicing/src/main/java/com/ewolff/microservice/invoicing/Address.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.invoicing; 2 | 3 | import javax.persistence.Embeddable; 4 | 5 | @Embeddable 6 | public class Address { 7 | 8 | private String street; 9 | private String zip; 10 | private String city; 11 | 12 | public Address() { 13 | super(); 14 | } 15 | 16 | public Address(String street, String zip, String city) { 17 | super(); 18 | this.street = street; 19 | this.zip = zip; 20 | this.city = city; 21 | } 22 | 23 | public String getStreet() { 24 | return street; 25 | } 26 | 27 | public void setStreet(String street) { 28 | this.street = street; 29 | } 30 | 31 | public String getZip() { 32 | return zip; 33 | } 34 | 35 | public void setZip(String zip) { 36 | this.zip = zip; 37 | } 38 | 39 | public String getCity() { 40 | return city; 41 | } 42 | 43 | public void setCity(String city) { 44 | this.city = city; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-invoicing/src/main/java/com/ewolff/microservice/invoicing/Customer.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.invoicing; 2 | 3 | import javax.persistence.Column; 4 | import javax.persistence.Embeddable; 5 | import javax.validation.constraints.Email; 6 | 7 | import org.apache.commons.lang.builder.EqualsBuilder; 8 | import org.apache.commons.lang.builder.HashCodeBuilder; 9 | import org.apache.commons.lang.builder.ToStringBuilder; 10 | 11 | @Embeddable 12 | public class Customer { 13 | 14 | @Column(nullable = false) 15 | private Long customerId; 16 | 17 | @Column(nullable = false) 18 | private String name; 19 | 20 | @Column(nullable = false) 21 | private String firstname; 22 | 23 | @Column(nullable = false) 24 | @Email 25 | private String email; 26 | 27 | public Customer() { 28 | super(); 29 | customerId = 0l; 30 | } 31 | 32 | public Customer(long customerId, String firstname, String name, String email) { 33 | super(); 34 | this.customerId = customerId; 35 | this.name = name; 36 | this.firstname = firstname; 37 | this.email = email; 38 | } 39 | 40 | public String getEmail() { 41 | return email; 42 | } 43 | 44 | public void setEmail(String email) { 45 | this.email = email; 46 | } 47 | 48 | public String getName() { 49 | return name; 50 | } 51 | 52 | public void setName(String name) { 53 | this.name = name; 54 | } 55 | 56 | public String getFirstname() { 57 | return firstname; 58 | } 59 | 60 | public void setFirstname(String firstname) { 61 | this.firstname = firstname; 62 | } 63 | 64 | public Long getCustomerId() { 65 | return customerId; 66 | } 67 | 68 | public void setCustomerId(Long id) { 69 | this.customerId = id; 70 | } 71 | 72 | @Override 73 | public String toString() { 74 | return ToStringBuilder.reflectionToString(this); 75 | } 76 | 77 | @Override 78 | public int hashCode() { 79 | return HashCodeBuilder.reflectionHashCode(this); 80 | 81 | } 82 | 83 | @Override 84 | public boolean equals(Object obj) { 85 | return EqualsBuilder.reflectionEquals(this, obj); 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-invoicing/src/main/java/com/ewolff/microservice/invoicing/Invoice.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.invoicing; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Date; 5 | import java.util.List; 6 | 7 | import javax.persistence.CascadeType; 8 | import javax.persistence.Embedded; 9 | import javax.persistence.Entity; 10 | import javax.persistence.Id; 11 | import javax.persistence.OneToMany; 12 | import javax.persistence.Transient; 13 | 14 | import org.apache.commons.lang.builder.EqualsBuilder; 15 | import org.apache.commons.lang.builder.HashCodeBuilder; 16 | import org.apache.commons.lang.builder.ToStringBuilder; 17 | 18 | @Entity 19 | public class Invoice { 20 | 21 | @Id 22 | private long id; 23 | 24 | @Embedded 25 | private Customer customer; 26 | 27 | private Date updated; 28 | 29 | @Embedded 30 | private Address billingAddress = new Address(); 31 | 32 | @OneToMany(cascade = CascadeType.ALL) 33 | private List invoiceLine; 34 | 35 | public Invoice() { 36 | super(); 37 | invoiceLine = new ArrayList(); 38 | } 39 | 40 | public Invoice(long id, Customer customer, Date updated, Address billingAddress, List invoiceLine) { 41 | super(); 42 | this.id = id; 43 | this.customer = customer; 44 | this.updated = updated; 45 | this.billingAddress = billingAddress; 46 | this.invoiceLine = invoiceLine; 47 | } 48 | 49 | public Address getBillingAddress() { 50 | return billingAddress; 51 | } 52 | 53 | public void setBillingAddress(Address billingAddress) { 54 | this.billingAddress = billingAddress; 55 | } 56 | 57 | public void setId(long id) { 58 | this.id = id; 59 | } 60 | 61 | public long getId() { 62 | return id; 63 | } 64 | 65 | public Date getUpdated() { 66 | return updated; 67 | } 68 | 69 | public void setUpdated(Date created) { 70 | this.updated = created; 71 | } 72 | 73 | public Customer getCustomer() { 74 | return customer; 75 | } 76 | 77 | public void setCustomer(Customer customer) { 78 | this.customer = customer; 79 | } 80 | 81 | public List getInvoiceLine() { 82 | return invoiceLine; 83 | } 84 | 85 | public void setInvoiceLine(List invoiceLine) { 86 | this.invoiceLine = invoiceLine; 87 | } 88 | 89 | @Transient 90 | public void setOrderLine(List orderLine) { 91 | this.invoiceLine = orderLine; 92 | } 93 | 94 | public void addLine(int count, Item item) { 95 | this.invoiceLine.add(new InvoiceLine(count, item)); 96 | } 97 | 98 | public int getNumberOfLines() { 99 | return invoiceLine.size(); 100 | } 101 | 102 | public double totalAmount() { 103 | return invoiceLine.stream().map((ol) -> ol.getCount() * ol.getItem().getPrice()).reduce(0.0, 104 | (d1, d2) -> d1 + d2); 105 | } 106 | 107 | @Override 108 | public String toString() { 109 | return ToStringBuilder.reflectionToString(this); 110 | } 111 | 112 | @Override 113 | public int hashCode() { 114 | return HashCodeBuilder.reflectionHashCode(this); 115 | } 116 | 117 | @Override 118 | public boolean equals(Object obj) { 119 | return EqualsBuilder.reflectionEquals(this, obj); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-invoicing/src/main/java/com/ewolff/microservice/invoicing/InvoiceApp.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.invoicing; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.scheduling.annotation.EnableScheduling; 6 | 7 | @EnableScheduling 8 | @SpringBootApplication 9 | public class InvoiceApp { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(InvoiceApp.class, args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-invoicing/src/main/java/com/ewolff/microservice/invoicing/InvoiceLine.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.invoicing; 2 | 3 | import javax.persistence.Column; 4 | import javax.persistence.Embedded; 5 | import javax.persistence.Entity; 6 | import javax.persistence.GeneratedValue; 7 | import javax.persistence.Id; 8 | 9 | import org.apache.commons.lang.builder.EqualsBuilder; 10 | import org.apache.commons.lang.builder.HashCodeBuilder; 11 | import org.apache.commons.lang.builder.ToStringBuilder; 12 | 13 | @Entity 14 | public class InvoiceLine { 15 | 16 | @Column(name = "F_COUNT") 17 | private int count; 18 | 19 | @Embedded 20 | private Item item; 21 | 22 | @Id 23 | @GeneratedValue 24 | private long id; 25 | 26 | public void setCount(int count) { 27 | this.count = count; 28 | } 29 | 30 | public void setItem(Item item) { 31 | this.item = item; 32 | } 33 | 34 | public InvoiceLine() { 35 | } 36 | 37 | public InvoiceLine(int count, Item item) { 38 | this.count = count; 39 | this.item = item; 40 | } 41 | 42 | public int getCount() { 43 | return count; 44 | } 45 | 46 | public Item getItem() { 47 | return item; 48 | } 49 | 50 | public double totalAmount() { 51 | return getCount() * getItem().getPrice(); 52 | } 53 | 54 | @Override 55 | public String toString() { 56 | return ToStringBuilder.reflectionToString(this); 57 | } 58 | 59 | @Override 60 | public int hashCode() { 61 | return HashCodeBuilder.reflectionHashCode(this); 62 | 63 | } 64 | 65 | @Override 66 | public boolean equals(Object obj) { 67 | return EqualsBuilder.reflectionEquals(this, obj); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-invoicing/src/main/java/com/ewolff/microservice/invoicing/InvoiceRepository.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.invoicing; 2 | 3 | import java.util.Date; 4 | 5 | import org.springframework.data.jpa.repository.Query; 6 | import org.springframework.data.repository.PagingAndSortingRepository; 7 | 8 | public interface InvoiceRepository extends PagingAndSortingRepository { 9 | 10 | @Query("SELECT max(i.updated) FROM Invoice i") 11 | Date lastUpdate(); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-invoicing/src/main/java/com/ewolff/microservice/invoicing/InvoiceService.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.invoicing; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | import org.springframework.transaction.annotation.Transactional; 8 | 9 | @Service 10 | public class InvoiceService { 11 | 12 | private final Logger log = LoggerFactory.getLogger(InvoiceService.class); 13 | 14 | private InvoiceRepository invoiceRepository; 15 | 16 | @Autowired 17 | public InvoiceService(InvoiceRepository invoiceRepository) { 18 | super(); 19 | this.invoiceRepository = invoiceRepository; 20 | } 21 | 22 | @Transactional 23 | public void generateInvoice(Invoice invoice) { 24 | if (invoiceRepository.existsById(invoice.getId())) { 25 | log.info("Invoice id {} already exists - ignored", invoice.getId()); 26 | } else { 27 | invoiceRepository.save(invoice); 28 | } 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-invoicing/src/main/java/com/ewolff/microservice/invoicing/Item.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.invoicing; 2 | 3 | import javax.persistence.Column; 4 | import javax.persistence.Embeddable; 5 | 6 | import org.apache.commons.lang.builder.EqualsBuilder; 7 | import org.apache.commons.lang.builder.HashCodeBuilder; 8 | import org.apache.commons.lang.builder.ToStringBuilder; 9 | 10 | @Embeddable 11 | public class Item { 12 | 13 | @Column(nullable = false) 14 | private Long itemId; 15 | 16 | @Column(nullable = false) 17 | private String name; 18 | 19 | @Column(nullable = false) 20 | private double price; 21 | 22 | public Item() { 23 | super(); 24 | itemId = 0l; 25 | } 26 | 27 | public Item(String name, double price) { 28 | super(); 29 | this.name = name; 30 | this.price = price; 31 | } 32 | 33 | public String getName() { 34 | return name; 35 | } 36 | 37 | public void setName(String name) { 38 | this.name = name; 39 | } 40 | 41 | public double getPrice() { 42 | return price; 43 | } 44 | 45 | public void setPrice(double price) { 46 | this.price = price; 47 | } 48 | 49 | public Long getItemId() { 50 | return itemId; 51 | } 52 | 53 | public void setItemId(Long id) { 54 | this.itemId = id; 55 | } 56 | 57 | @Override 58 | public String toString() { 59 | return ToStringBuilder.reflectionToString(this); 60 | } 61 | 62 | @Override 63 | public int hashCode() { 64 | return HashCodeBuilder.reflectionHashCode(this); 65 | 66 | } 67 | 68 | @Override 69 | public boolean equals(Object obj) { 70 | return EqualsBuilder.reflectionEquals(this, obj); 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-invoicing/src/main/java/com/ewolff/microservice/invoicing/poller/InvoicePoller.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.invoicing.poller; 2 | 3 | import java.util.Date; 4 | 5 | import org.apache.http.client.utils.DateUtils; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.beans.factory.annotation.Value; 10 | import org.springframework.http.HttpEntity; 11 | import org.springframework.http.HttpHeaders; 12 | import org.springframework.http.HttpMethod; 13 | import org.springframework.http.HttpStatus; 14 | import org.springframework.http.ResponseEntity; 15 | import org.springframework.scheduling.annotation.Scheduled; 16 | import org.springframework.stereotype.Component; 17 | import org.springframework.web.client.RestTemplate; 18 | 19 | import com.ewolff.microservice.invoicing.Invoice; 20 | import com.ewolff.microservice.invoicing.InvoiceService; 21 | 22 | @Component 23 | public class InvoicePoller { 24 | 25 | private final Logger log = LoggerFactory.getLogger(InvoicePoller.class); 26 | 27 | private String url = ""; 28 | 29 | private RestTemplate restTemplate = new RestTemplate(); 30 | 31 | private Date lastModified = null; 32 | 33 | private boolean pollingActivated; 34 | 35 | private InvoiceService invoiceService; 36 | 37 | @Autowired 38 | public InvoicePoller(@Value("${order.url}") String url, @Value("${poller.actived:true}") boolean pollingActivated, 39 | InvoiceService invoiceService) { 40 | super(); 41 | this.pollingActivated = pollingActivated; 42 | this.url = url; 43 | this.invoiceService = invoiceService; 44 | } 45 | 46 | @Scheduled(fixedDelay = 30000) 47 | public void poll() { 48 | if (pollingActivated) { 49 | pollInternal(); 50 | } 51 | } 52 | 53 | public void pollInternal() { 54 | HttpHeaders requestHeaders = new HttpHeaders(); 55 | requestHeaders.set(HttpHeaders.ACCEPT, "*/*"); 56 | if (lastModified != null) { 57 | requestHeaders.set(HttpHeaders.IF_MODIFIED_SINCE, DateUtils.formatDate(lastModified)); 58 | } 59 | HttpEntity requestEntity = new HttpEntity(requestHeaders); 60 | ResponseEntity response = restTemplate.exchange(url, HttpMethod.GET, requestEntity, OrderFeed.class); 61 | 62 | if (response.getStatusCode() != HttpStatus.NOT_MODIFIED) { 63 | log.trace("data has been modified"); 64 | OrderFeed feed = response.getBody(); 65 | for (OrderFeedEntry entry : feed.getOrders()) { 66 | if ((lastModified == null) || (entry.getUpdated().after(lastModified))) { 67 | Invoice invoice = restTemplate 68 | .getForEntity(entry.getLink(), Invoice.class).getBody(); 69 | log.trace("saving invoice {}", invoice.getId()); 70 | invoiceService.generateInvoice(invoice); 71 | } 72 | } 73 | if (response.getHeaders().getFirst(HttpHeaders.LAST_MODIFIED) != null) { 74 | lastModified = DateUtils.parseDate(response.getHeaders().getFirst(HttpHeaders.LAST_MODIFIED)); 75 | log.trace("Last-Modified header {}", lastModified); 76 | } 77 | } else { 78 | log.trace("no new data"); 79 | } 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-invoicing/src/main/java/com/ewolff/microservice/invoicing/poller/OrderFeed.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.invoicing.poller; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Date; 5 | import java.util.List; 6 | 7 | import org.apache.commons.lang.builder.EqualsBuilder; 8 | import org.apache.commons.lang.builder.ToStringBuilder; 9 | 10 | import net.logstash.logback.encoder.org.apache.commons.lang.builder.HashCodeBuilder; 11 | 12 | public class OrderFeed { 13 | 14 | private Date updated; 15 | 16 | private List orders; 17 | 18 | public OrderFeed() { 19 | super(); 20 | orders = new ArrayList(); 21 | } 22 | 23 | public Date getUpdated() { 24 | return updated; 25 | } 26 | 27 | public void setUpdated(Date updated) { 28 | this.updated = updated; 29 | } 30 | 31 | public List getOrders() { 32 | return orders; 33 | } 34 | 35 | public void setOrders(List orders) { 36 | this.orders = orders; 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | return ToStringBuilder.reflectionToString(this); 42 | } 43 | 44 | @Override 45 | public int hashCode() { 46 | return HashCodeBuilder.reflectionHashCode(this); 47 | } 48 | 49 | @Override 50 | public boolean equals(Object obj) { 51 | return EqualsBuilder.reflectionEquals(this, obj); 52 | } 53 | 54 | } -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-invoicing/src/main/java/com/ewolff/microservice/invoicing/poller/OrderFeedEntry.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.invoicing.poller; 2 | 3 | import java.util.Date; 4 | 5 | import org.apache.commons.lang.builder.EqualsBuilder; 6 | import org.apache.commons.lang.builder.HashCodeBuilder; 7 | import org.apache.commons.lang.builder.ToStringBuilder; 8 | 9 | public class OrderFeedEntry { 10 | 11 | private long id; 12 | 13 | private String link; 14 | 15 | private Date updated; 16 | 17 | public long getId() { 18 | return id; 19 | } 20 | 21 | public void setId(long id) { 22 | this.id = id; 23 | } 24 | 25 | public String getLink() { 26 | return link; 27 | } 28 | 29 | public void setLink(String link) { 30 | this.link = link; 31 | } 32 | 33 | public Date getUpdated() { 34 | return updated; 35 | } 36 | 37 | public void setUpdated(Date updated) { 38 | this.updated = updated; 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return ToStringBuilder.reflectionToString(this); 44 | } 45 | 46 | @Override 47 | public int hashCode() { 48 | return HashCodeBuilder.reflectionHashCode(this); 49 | } 50 | 51 | @Override 52 | public boolean equals(Object obj) { 53 | return EqualsBuilder.reflectionEquals(this, obj); 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-invoicing/src/main/java/com/ewolff/microservice/invoicing/web/InvoiceController.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.invoicing.web; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.http.MediaType; 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.web.bind.annotation.PathVariable; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RequestMethod; 9 | import org.springframework.web.servlet.ModelAndView; 10 | 11 | import com.ewolff.microservice.invoicing.InvoiceRepository; 12 | 13 | @Controller 14 | public class InvoiceController { 15 | 16 | private InvoiceRepository invoiceRepository; 17 | 18 | @Autowired 19 | public InvoiceController(InvoiceRepository invoiceRepository) { 20 | this.invoiceRepository = invoiceRepository; 21 | } 22 | 23 | @RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE) 24 | public ModelAndView invoice(@PathVariable("id") long id) { 25 | return new ModelAndView("invoice", "invoice", invoiceRepository.findById(id).get()); 26 | } 27 | 28 | @RequestMapping("/") 29 | public ModelAndView invoiceList() { 30 | return new ModelAndView("invoicelist", "invoices", invoiceRepository.findAll()); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-invoicing/src/main/java/com/ewolff/microservice/invoicing/web/PollController.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.invoicing.web; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RequestMethod; 7 | 8 | import com.ewolff.microservice.invoicing.poller.InvoicePoller; 9 | 10 | @Controller 11 | public class PollController { 12 | 13 | private InvoicePoller poller; 14 | 15 | @Autowired 16 | public PollController(InvoicePoller poller) { 17 | this.poller = poller; 18 | } 19 | 20 | @RequestMapping(value = "/poll", method = RequestMethod.POST) 21 | public String poll() { 22 | poller.poll(); 23 | return "success"; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-invoicing/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8080 2 | management.endpoints.web.exposure.include=* 3 | logging.level.org.springframework.boot.actuate.trace.WebRequestTraceFilter: TRACE 4 | spring.application.name=invoicing 5 | server.servlet.context-path=/invoicing 6 | logging.level.com.ewolff.microservice.invoicing.poller: TRACE 7 | logging.level.org.springframework.http.converter.json: ERROR 8 | order.url=http://order:80/order/feed 9 | spring.jpa.hibernate.ddl-auto=update 10 | spring.datasource.url=jdbc:postgresql://postgres/dbinvoicing 11 | spring.datasource.username=dbuser 12 | spring.datasource.password=dbpass 13 | spring.datasource.driver-class-name=org.postgresql.Driver 14 | spring.sleuth.propagation-keys=x-request-id,x-ot-span-context 15 | spring.sleuth.opentracing.enabled=true 16 | spring.zipkin.baseUrl=http://linkerd-collector.linkerd:55678 -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-invoicing/src/main/resources/templates/invoice.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Invoicing 7 | 8 | 9 |

Invoicing

10 |
11 | 12 |
13 |
14 |
15 | Customer 16 |
17 |
19 |
21 |
22 | 23 |
24 |

Billing Address

25 |
26 | 27 |
28 |
29 | Street 30 |
31 |
32 |
33 |
34 |
35 | Zip 36 |
37 |
38 |
39 |
40 |
41 | City 42 |
43 |
44 |
45 | 46 |
47 |

Invoice Lines

48 |
49 | 50 |
51 |
52 | Quantity 53 |
54 |
55 | Item 56 |
57 |
58 | Name 59 |
60 |
61 | Price 62 |
63 |
64 | Total Price 65 |
66 |
67 | 68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | 76 |
77 | 78 |
79 |

More Information

80 |
81 | 82 |
83 | 84 | 85 |
86 | 87 |
88 | 89 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-invoicing/src/main/resources/templates/invoicelist.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Invoicing : View all 7 | 8 | 9 |

Invoicing : View all

10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 29 | 30 | 31 | 32 |
IDCustomerTotal Amount
No invoices
1Firstname 28 | Name42.0
33 |
34 |
35 | 37 |
38 |
39 |
40 | 41 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-invoicing/src/main/resources/templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | Layout 7 | 9 | 11 | 12 | 13 | 14 | 22 |

Layout

23 |
Fake content
24 | 94 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-order/src/main/resources/templates/order.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Order 7 | 8 | 9 |

Order

10 |
11 | 12 |
13 |
Customer
14 |
16 |
17 | 18 |
19 |
Total price
20 |
21 |
22 | 23 |
24 |

Shipping Address

25 |
26 | 27 |
28 |
Street
29 |
30 |
31 |
32 |
Zip
33 |
34 |
35 |
36 |
City
37 |
38 |
39 | 40 | 41 |
42 |

Billing Address

43 |
44 | 45 |
46 |
Street
47 |
48 |
49 |
50 |
Zip
51 |
52 |
53 |
54 |
City
55 |
56 |
57 | 58 |
59 |

Order Lines

60 |
61 | 62 |
63 |
Quantity
64 |
Item
65 |
Price
66 | 67 |
68 | 69 |
70 |
71 |
72 |
73 |
74 | 75 |
76 |

More Information

77 |
78 | 79 |
80 | 81 | 82 | 83 |
84 | 85 |
86 | 87 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-order/src/main/resources/templates/orderForm.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Order : Add 7 | 8 | 9 |

Order : Add

10 |
11 |
12 |
13 | 19 |
20 |
21 | 26 |
27 |

Shipping Address

28 |
29 | 32 |
33 |
34 | 37 |
38 |
39 | 42 |
43 |

Billing Address

44 |
45 | 48 |
49 |
50 | 53 |
54 |
55 | 58 |
59 | 60 |
61 |
62 | 63 |
64 |
65 | 66 |
67 |
68 | 69 |
70 |
71 |
72 |
1
73 |
74 | 76 |
77 |
78 | 82 |
83 |
84 |
85 | 87 | 88 |
89 |
90 |
91 | 92 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-order/src/main/resources/templates/orderlist.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Order: View all 7 | 8 | 9 |

Order: View all

10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 27 | 30 | 31 | 34 | 35 | 36 |
IDCustomerTotal Price
No orders
1Firstname 29 | Name42.0
32 | 33 |
37 |
38 |
39 | Add Order 40 |
41 |
42 |
43 | 44 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-order/src/main/resources/templates/success.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Success 7 | 8 | 9 |

Success

10 |
11 | Action was successful! 12 |
13 | 14 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-order/src/test/java/com/ewolff/microservice/order/CustomerTestDataGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.order; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | 5 | import org.junit.jupiter.api.Test; 6 | import org.junit.jupiter.api.extension.ExtendWith; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; 10 | import org.springframework.test.context.ActiveProfiles; 11 | import org.springframework.test.context.junit.jupiter.SpringExtension; 12 | 13 | import com.ewolff.microservice.order.customer.CustomerRepository; 14 | import com.ewolff.microservice.order.customer.CustomerTestDataGenerator; 15 | 16 | @ExtendWith(SpringExtension.class) 17 | @SpringBootTest(classes = OrderApp.class, webEnvironment = WebEnvironment.DEFINED_PORT) 18 | @ActiveProfiles("test") 19 | public class CustomerTestDataGeneratorTest { 20 | 21 | @Autowired 22 | private CustomerRepository customerRepository; 23 | 24 | @Autowired 25 | private CustomerTestDataGenerator customerTestDataGenerator; 26 | 27 | @Test 28 | public void assureTestDataGeneratedOnce() { 29 | assertEquals(1, customerRepository.findByName("Wolff").size()); 30 | customerTestDataGenerator.generateTestData(); 31 | assertEquals(1, customerRepository.findByName("Wolff").size()); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-order/src/test/java/com/ewolff/microservice/order/FeedClientTest.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.order; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertNotNull; 5 | import static org.junit.Assert.assertTrue; 6 | 7 | import java.util.Date; 8 | 9 | import org.apache.http.client.utils.DateUtils; 10 | import org.junit.jupiter.api.Test; 11 | import org.junit.jupiter.api.extension.ExtendWith; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.boot.test.context.SpringBootTest; 14 | import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; 15 | import org.springframework.boot.web.server.LocalServerPort; 16 | import org.springframework.http.HttpEntity; 17 | import org.springframework.http.HttpHeaders; 18 | import org.springframework.http.HttpMethod; 19 | import org.springframework.http.HttpStatus; 20 | import org.springframework.http.ResponseEntity; 21 | import org.springframework.test.context.ActiveProfiles; 22 | import org.springframework.test.context.junit.jupiter.SpringExtension; 23 | import org.springframework.web.client.RestTemplate; 24 | 25 | import com.ewolff.microservice.order.customer.CustomerRepository; 26 | import com.ewolff.microservice.order.logic.Order; 27 | import com.ewolff.microservice.order.logic.OrderRepository; 28 | 29 | @ExtendWith(SpringExtension.class) 30 | @SpringBootTest(classes = OrderApp.class, webEnvironment = WebEnvironment.DEFINED_PORT) 31 | @ActiveProfiles("test") 32 | public class FeedClientTest { 33 | 34 | @LocalServerPort 35 | private long serverPort; 36 | 37 | @Autowired 38 | private OrderRepository orderRepository; 39 | 40 | @Autowired 41 | private CustomerRepository customerRepository; 42 | 43 | private RestTemplate restTemplate = new RestTemplate(); 44 | 45 | @Test 46 | public void feedReturnsBasicInformation() { 47 | OrderFeed feed = retrieveFeed(); 48 | assertNotNull(feed.getUpdated()); 49 | } 50 | 51 | @Test 52 | public void requestWithLastModifiedReturns304() { 53 | ResponseEntity response = restTemplate.exchange(feedUrl(), HttpMethod.GET, new HttpEntity(null), 54 | OrderFeed.class); 55 | 56 | Date lastModified = DateUtils.parseDate(response.getHeaders().getFirst("Last-Modified")); 57 | 58 | HttpHeaders requestHeaders = new HttpHeaders(); 59 | requestHeaders.set("If-Modified-Since", DateUtils.formatDate(lastModified)); 60 | HttpEntity requestEntity = new HttpEntity(requestHeaders); 61 | 62 | response = restTemplate.exchange(feedUrl(), HttpMethod.GET, requestEntity, OrderFeed.class); 63 | 64 | assertEquals(HttpStatus.NOT_MODIFIED, response.getStatusCode()); 65 | } 66 | 67 | @Test 68 | public void feedReturnsNewlyCreatedOrder() { 69 | Order order = new Order(); 70 | order.setCustomer(customerRepository.findAll().iterator().next()); 71 | orderRepository.save(order); 72 | OrderFeed feed = retrieveFeed(); 73 | boolean foundLinkToCreatedOrder = false; 74 | for (OrderFeedEntry entry : feed.getOrders()) { 75 | if (entry.getLink().contains(Long.toString(order.getId()))) { 76 | foundLinkToCreatedOrder = true; 77 | } 78 | } 79 | assertTrue(foundLinkToCreatedOrder); 80 | } 81 | 82 | private OrderFeed retrieveFeed() { 83 | return restTemplate.getForEntity(feedUrl(), OrderFeed.class).getBody(); 84 | } 85 | 86 | private String feedUrl() { 87 | return String.format("http://localhost:%d/order/feed", serverPort); 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-order/src/test/java/com/ewolff/microservice/order/ItemTestDataGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.order; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | 5 | import org.junit.jupiter.api.Test; 6 | import org.junit.jupiter.api.extension.ExtendWith; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; 10 | import org.springframework.test.context.ActiveProfiles; 11 | import org.springframework.test.context.junit.jupiter.SpringExtension; 12 | 13 | import com.ewolff.microservice.order.item.ItemRepository; 14 | import com.ewolff.microservice.order.item.ItemTestDataGenerator; 15 | 16 | @ExtendWith(SpringExtension.class) 17 | @SpringBootTest(classes = OrderApp.class, webEnvironment = WebEnvironment.DEFINED_PORT) 18 | @ActiveProfiles("test") 19 | public class ItemTestDataGeneratorTest { 20 | 21 | @Autowired 22 | private ItemRepository itemRepository; 23 | 24 | @Autowired 25 | private ItemTestDataGenerator itemTestDataGenerator; 26 | 27 | @Test 28 | public void assureTestDataGeneratedOnce() { 29 | assertEquals(1, itemRepository.findByName("iPod").size()); 30 | itemTestDataGenerator.generateTestData(); 31 | assertEquals(1, itemRepository.findByName("iPod").size()); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-order/src/test/java/com/ewolff/microservice/order/OrderTestApp.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.order; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class OrderTestApp { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication app = new SpringApplication(OrderTestApp.class); 11 | app.setAdditionalProfiles("test"); 12 | app.run(args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-order/src/test/java/com/ewolff/microservice/order/OrderTestDataGenerator.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.order; 2 | 3 | import javax.annotation.PostConstruct; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.annotation.DependsOn; 7 | import org.springframework.context.annotation.Profile; 8 | import org.springframework.stereotype.Component; 9 | 10 | import com.ewolff.microservice.order.customer.CustomerRepository; 11 | import com.ewolff.microservice.order.item.ItemRepository; 12 | import com.ewolff.microservice.order.logic.Address; 13 | import com.ewolff.microservice.order.logic.Order; 14 | import com.ewolff.microservice.order.logic.OrderRepository; 15 | 16 | @Component 17 | @Profile("test") 18 | @DependsOn({ "itemTestDataGenerator", "customerTestDataGenerator" }) 19 | public class OrderTestDataGenerator { 20 | 21 | private final OrderRepository orderRepository; 22 | private ItemRepository itemRepository; 23 | private CustomerRepository customerRepository; 24 | 25 | @Autowired 26 | public OrderTestDataGenerator(OrderRepository orderRepository, ItemRepository itemRepository, 27 | CustomerRepository customerRepository) { 28 | this.orderRepository = orderRepository; 29 | this.itemRepository = itemRepository; 30 | this.customerRepository = customerRepository; 31 | } 32 | 33 | @PostConstruct 34 | public void generateTestData() { 35 | Order order = new Order(customerRepository.findAll().iterator().next(),1); 36 | order.setShippingAddress(new Address("Ohlauer Str. 43", "10999", "Berlin")); 37 | order.setBillingAddress(new Address("Krischerstr. 100", "40789", "Monheim am Rhein")); 38 | order.setDeliveryService("Hermes"); 39 | order.addLine(42, itemRepository.findAll().iterator().next()); 40 | order=orderRepository.save(order); 41 | orderRepository.save(order); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-order/src/test/java/com/ewolff/microservice/order/PactTest.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.order; 2 | 3 | import org.junit.jupiter.api.BeforeEach; 4 | import org.junit.jupiter.api.TestTemplate; 5 | import org.junit.jupiter.api.extension.ExtendWith; 6 | import org.springframework.boot.test.context.SpringBootTest; 7 | import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; 8 | import org.springframework.test.context.ActiveProfiles; 9 | import org.springframework.test.context.junit.jupiter.SpringExtension; 10 | 11 | import au.com.dius.pact.provider.junit.Provider; 12 | import au.com.dius.pact.provider.junit.loader.PactFolder; 13 | import au.com.dius.pact.provider.junit5.HttpTestTarget; 14 | import au.com.dius.pact.provider.junit5.PactVerificationContext; 15 | import au.com.dius.pact.provider.junit5.PactVerificationInvocationContextProvider; 16 | 17 | @ExtendWith(SpringExtension.class) 18 | @SpringBootTest(classes = OrderApp.class, webEnvironment = WebEnvironment.DEFINED_PORT) 19 | @ActiveProfiles("test") 20 | @Provider("OrderProvider") 21 | @PactFolder("pacts") 22 | public class PactTest { 23 | 24 | @BeforeEach 25 | void setupTestTarget(PactVerificationContext context) { 26 | context.setTarget(new HttpTestTarget("localhost", 8080, "/")); 27 | } 28 | 29 | @TestTemplate 30 | @ExtendWith(PactVerificationInvocationContextProvider.class) 31 | void pactVerificationTestTemplate(PactVerificationContext context) { 32 | context.verifyInteraction(); 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-order/src/test/java/com/ewolff/microservice/order/logic/OrderServiceTest.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.order.logic; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import org.junit.jupiter.api.Test; 6 | import org.junit.jupiter.api.extension.ExtendWith; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; 10 | import org.springframework.test.context.ActiveProfiles; 11 | import org.springframework.test.context.junit.jupiter.SpringExtension; 12 | import org.springframework.transaction.annotation.Transactional; 13 | 14 | import com.ewolff.microservice.order.OrderApp; 15 | 16 | @ExtendWith(SpringExtension.class) 17 | @SpringBootTest(classes = OrderApp.class, webEnvironment = WebEnvironment.DEFINED_PORT) 18 | @ActiveProfiles("test") 19 | public class OrderServiceTest { 20 | 21 | @Autowired 22 | private OrderRepository orderRepository; 23 | 24 | @Test 25 | @Transactional 26 | public void lastCreatedIsUpdated() { 27 | Order order = new Order(); 28 | order = orderRepository.save(order); 29 | assertEquals(order.getUpdated(), orderRepository.lastUpdate()); 30 | order = new Order(); 31 | order = orderRepository.save(order); 32 | assertEquals(order.getUpdated(), orderRepository.lastUpdate()); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-order/src/test/java/com/ewolff/microservice/order/logic/OrderWebIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.order.logic; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertFalse; 5 | import static org.junit.Assert.assertTrue; 6 | 7 | import java.util.stream.StreamSupport; 8 | 9 | import org.junit.jupiter.api.BeforeAll; 10 | import org.junit.jupiter.api.Test; 11 | import org.junit.jupiter.api.TestInstance; 12 | import org.junit.jupiter.api.TestInstance.Lifecycle; 13 | import org.junit.jupiter.api.extension.ExtendWith; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.boot.test.context.SpringBootTest; 16 | import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; 17 | import org.springframework.boot.web.server.LocalServerPort; 18 | import org.springframework.http.ResponseEntity; 19 | import org.springframework.test.context.ActiveProfiles; 20 | import org.springframework.test.context.junit.jupiter.SpringExtension; 21 | import org.springframework.util.LinkedMultiValueMap; 22 | import org.springframework.util.MultiValueMap; 23 | import org.springframework.web.client.RestTemplate; 24 | 25 | import com.ewolff.microservice.order.OrderApp; 26 | import com.ewolff.microservice.order.customer.Customer; 27 | import com.ewolff.microservice.order.customer.CustomerRepository; 28 | import com.ewolff.microservice.order.item.Item; 29 | import com.ewolff.microservice.order.item.ItemRepository; 30 | 31 | @ExtendWith(SpringExtension.class) 32 | @SpringBootTest(classes = OrderApp.class, webEnvironment = WebEnvironment.DEFINED_PORT) 33 | @ActiveProfiles("test") 34 | @TestInstance(Lifecycle.PER_CLASS) 35 | public class OrderWebIntegrationTest { 36 | 37 | private RestTemplate restTemplate = new RestTemplate(); 38 | 39 | @LocalServerPort 40 | private long serverPort; 41 | 42 | @Autowired 43 | private ItemRepository itemRepository; 44 | 45 | @Autowired 46 | private CustomerRepository customerRepository; 47 | 48 | @Autowired 49 | private OrderRepository orderRepository; 50 | 51 | private Item item; 52 | 53 | private Customer customer; 54 | 55 | @BeforeAll 56 | public void setup() { 57 | item = itemRepository.findAll().iterator().next(); 58 | customer = new Customer("RZA", "GZA", "rza@wutang.com", "Chamber", "Shaolin"); 59 | customer = customerRepository.save(customer); 60 | } 61 | 62 | @Test 63 | public void IsTestOrderReturned() { 64 | ResponseEntity resultEntity = restTemplate.getForEntity(orderURL() + "/order/1", String.class); 65 | assertTrue(resultEntity.getStatusCode().is2xxSuccessful()); 66 | String order = resultEntity.getBody(); 67 | assertTrue(order.contains("Berlin")); 68 | } 69 | 70 | @Test 71 | public void IsOrderListReturned() { 72 | Order order = null; 73 | try { 74 | Iterable orders = orderRepository.findAll(); 75 | assertTrue(StreamSupport.stream(orders.spliterator(), false) 76 | .noneMatch(o -> ((o.getCustomer() != null) && (o.getCustomer().equals(customer))))); 77 | ResponseEntity resultEntity = restTemplate.getForEntity(orderURL(), String.class); 78 | assertTrue(resultEntity.getStatusCode().is2xxSuccessful()); 79 | String orderList = resultEntity.getBody(); 80 | assertFalse(orderList.contains("RZA")); 81 | order = new Order(customer); 82 | order.addLine(42, item); 83 | orderRepository.save(order); 84 | orderList = restTemplate.getForObject(orderURL(), String.class); 85 | assertTrue(orderList.contains("Eberhard")); 86 | } finally { 87 | if (order != null) { 88 | orderRepository.delete(order); 89 | } 90 | } 91 | } 92 | 93 | private String orderURL() { 94 | return "http://localhost:" + serverPort + "/order"; 95 | } 96 | 97 | @Test 98 | public void IsOrderFormDisplayed() { 99 | ResponseEntity resultEntity = restTemplate.getForEntity(orderURL() + "/form.html", String.class); 100 | assertTrue(resultEntity.getStatusCode().is2xxSuccessful()); 101 | assertTrue(resultEntity.getBody().contains(" map = new LinkedMultiValueMap(); 108 | map.add("submit", ""); 109 | map.add("customer", Long.toString(customer.getCustomerId())); 110 | map.add("orderLine[0].item", Long.toString(item.getItemId())); 111 | map.add("orderLine[0].count", "42"); 112 | restTemplate.postForLocation(orderURL()+"/", map, String.class); 113 | assertEquals(before + 1, orderRepository.count()); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-order/src/test/resources/application-test.properties: -------------------------------------------------------------------------------- 1 | spring.thymeleaf.cache=false 2 | spring.datasource.url=jdbc:hsqldb:mem:mymemdb 3 | spring.datasource.username=dbuser 4 | spring.datasource.password=dbpass 5 | spring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver 6 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-order/src/test/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-shipping/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:11.0.2-jre-slim 2 | COPY target/microservice-linkerd-shipping-0.0.1-SNAPSHOT.jar . 3 | CMD /usr/bin/java -Xmx300m -Xms300m -XX:TieredStopAtLevel=1 -noverify -jar microservice-linkerd-shipping-0.0.1-SNAPSHOT.jar 4 | EXPOSE 8080 -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-shipping/pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | 6 | 7 | com.ewolff 8 | microservice-linkerd 9 | 0.0.1-SNAPSHOT 10 | 11 | 12 | microservice-linkerd-shipping 13 | 14 | 15 | 16 | 17 | org.springframework.boot 18 | spring-boot-starter-data-jpa 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-thymeleaf 24 | 25 | 26 | 27 | nz.net.ultraq.thymeleaf 28 | thymeleaf-layout-dialect 29 | 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-web 34 | 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-actuator 39 | 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-starter-test 44 | test 45 | 46 | 47 | 48 | org.springframework.hateoas 49 | spring-hateoas 50 | 51 | 52 | 53 | javax.xml.bind 54 | jaxb-api 55 | 56 | 57 | 58 | com.jayway.jsonpath 59 | json-path 60 | runtime 61 | 62 | 63 | 64 | org.hsqldb 65 | hsqldb 66 | runtime 67 | 68 | 69 | 70 | org.postgresql 71 | postgresql 72 | runtime 73 | 74 | 75 | 76 | org.apache.httpcomponents 77 | httpclient 78 | 79 | 80 | 81 | commons-lang 82 | commons-lang 83 | 2.6 84 | 85 | 86 | 87 | org.webjars 88 | bootstrap 89 | 90 | 91 | 92 | org.springframework.cloud 93 | spring-cloud-starter-sleuth 94 | 95 | 96 | 97 | net.logstash.logback 98 | logstash-logback-encoder 99 | 4.11 100 | 101 | 102 | 103 | com.internetitem 104 | logback-elasticsearch-appender 105 | 1.6 106 | 107 | 108 | 109 | org.junit.jupiter 110 | junit-jupiter-api 111 | test 112 | 113 | 114 | 115 | org.junit.jupiter 116 | junit-jupiter-engine 117 | test 118 | 119 | 120 | 121 | au.com.dius 122 | pact-jvm-consumer-junit5 123 | 4.0.0-beta.2 124 | test 125 | 126 | 127 | 128 | io.opentracing.brave 129 | brave-opentracing 130 | 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-shipping/src/main/java/com/ewolff/microservice/shipping/Address.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.shipping; 2 | 3 | import javax.persistence.Embeddable; 4 | 5 | @Embeddable 6 | public class Address { 7 | 8 | private String street; 9 | private String zip; 10 | private String city; 11 | 12 | public Address() { 13 | super(); 14 | } 15 | 16 | public Address(String street, String zip, String city) { 17 | super(); 18 | this.street = street; 19 | this.zip = zip; 20 | this.city = city; 21 | } 22 | 23 | public String getStreet() { 24 | return street; 25 | } 26 | 27 | public void setStreet(String street) { 28 | this.street = street; 29 | } 30 | 31 | public String getZip() { 32 | return zip; 33 | } 34 | 35 | public void setZip(String zip) { 36 | this.zip = zip; 37 | } 38 | 39 | public String getCity() { 40 | return city; 41 | } 42 | 43 | public void setCity(String city) { 44 | this.city = city; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-shipping/src/main/java/com/ewolff/microservice/shipping/Customer.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.shipping; 2 | 3 | import javax.persistence.Column; 4 | import javax.persistence.Embeddable; 5 | 6 | import org.apache.commons.lang.builder.EqualsBuilder; 7 | import org.apache.commons.lang.builder.HashCodeBuilder; 8 | import org.apache.commons.lang.builder.ToStringBuilder; 9 | 10 | @Embeddable 11 | public class Customer { 12 | 13 | @Column(nullable = false) 14 | private Long customerId; 15 | 16 | @Column(nullable = false) 17 | private String name; 18 | 19 | @Column(nullable = false) 20 | private String firstname; 21 | 22 | public Customer() { 23 | super(); 24 | customerId = 0l; 25 | } 26 | 27 | public Customer(long customerId, String firstname, String name) { 28 | super(); 29 | this.customerId = customerId; 30 | this.name = name; 31 | this.firstname = firstname; 32 | } 33 | 34 | public String getName() { 35 | return name; 36 | } 37 | 38 | public void setName(String name) { 39 | this.name = name; 40 | } 41 | 42 | public String getFirstname() { 43 | return firstname; 44 | } 45 | 46 | public void setFirstname(String firstname) { 47 | this.firstname = firstname; 48 | } 49 | 50 | public Long getCustomerId() { 51 | return customerId; 52 | } 53 | 54 | public void setCustomerId(Long id) { 55 | this.customerId = id; 56 | } 57 | 58 | @Override 59 | public String toString() { 60 | return ToStringBuilder.reflectionToString(this); 61 | } 62 | 63 | @Override 64 | public int hashCode() { 65 | return HashCodeBuilder.reflectionHashCode(this); 66 | 67 | } 68 | 69 | @Override 70 | public boolean equals(Object obj) { 71 | return EqualsBuilder.reflectionEquals(this, obj); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-shipping/src/main/java/com/ewolff/microservice/shipping/Item.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.shipping; 2 | 3 | import javax.persistence.Embeddable; 4 | 5 | import org.apache.commons.lang.builder.EqualsBuilder; 6 | import org.apache.commons.lang.builder.HashCodeBuilder; 7 | import org.apache.commons.lang.builder.ToStringBuilder; 8 | 9 | @Embeddable 10 | public class Item { 11 | 12 | private Long itemId; 13 | 14 | private String name; 15 | 16 | public Item() { 17 | super(); 18 | itemId = 0l; 19 | } 20 | 21 | public Long getItemId() { 22 | return itemId; 23 | } 24 | 25 | public void setItemId(Long itemId) { 26 | this.itemId = itemId; 27 | } 28 | 29 | public String getName() { 30 | return name; 31 | } 32 | 33 | public void setName(String name) { 34 | this.name = name; 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return ToStringBuilder.reflectionToString(this); 40 | } 41 | 42 | @Override 43 | public int hashCode() { 44 | return HashCodeBuilder.reflectionHashCode(this); 45 | 46 | } 47 | 48 | @Override 49 | public boolean equals(Object obj) { 50 | return EqualsBuilder.reflectionEquals(this, obj); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-shipping/src/main/java/com/ewolff/microservice/shipping/Shipment.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.shipping; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Date; 5 | import java.util.List; 6 | 7 | import javax.persistence.CascadeType; 8 | import javax.persistence.Embedded; 9 | import javax.persistence.Entity; 10 | import javax.persistence.Id; 11 | import javax.persistence.OneToMany; 12 | import javax.persistence.Transient; 13 | 14 | import org.apache.commons.lang.builder.EqualsBuilder; 15 | import org.apache.commons.lang.builder.HashCodeBuilder; 16 | import org.apache.commons.lang.builder.ToStringBuilder; 17 | 18 | @Entity 19 | public class Shipment { 20 | 21 | @Id 22 | private long id; 23 | 24 | @Embedded 25 | private Customer customer; 26 | 27 | private Date updated; 28 | 29 | @Embedded 30 | private Address shippingAddress = new Address(); 31 | 32 | @OneToMany(cascade = CascadeType.ALL) 33 | private List shipmentLine; 34 | 35 | private String deliveryService; 36 | 37 | private int cost; 38 | 39 | public Shipment() { 40 | super(); 41 | shipmentLine = new ArrayList(); 42 | } 43 | 44 | public Shipment(long id, Customer customer, Date updated, Address shippingAddress, List shipmentLine, 45 | String deliveryService) { 46 | super(); 47 | this.id = id; 48 | this.customer = customer; 49 | this.updated = updated; 50 | this.shippingAddress = shippingAddress; 51 | this.shipmentLine = shipmentLine; 52 | this.deliveryService = deliveryService; 53 | } 54 | 55 | public Address getShippingAddress() { 56 | return shippingAddress; 57 | } 58 | 59 | public void setShippingAddress(Address shippingAddress) { 60 | this.shippingAddress = shippingAddress; 61 | } 62 | 63 | public String getDeliveryService() { 64 | return deliveryService; 65 | } 66 | 67 | public void setDeliveryService(String deliveryService) { 68 | this.deliveryService = deliveryService; 69 | } 70 | 71 | public void setId(long id) { 72 | this.id = id; 73 | } 74 | 75 | public long getId() { 76 | return id; 77 | } 78 | 79 | public Date getUpdated() { 80 | return updated; 81 | } 82 | 83 | public void setUpdated(Date created) { 84 | this.updated = created; 85 | } 86 | 87 | public Customer getCustomer() { 88 | return customer; 89 | } 90 | 91 | public void setCustomer(Customer customerId) { 92 | this.customer = customerId; 93 | } 94 | 95 | public List getShipmentLine() { 96 | return shipmentLine; 97 | } 98 | 99 | public Shipment(Customer customer) { 100 | super(); 101 | this.customer = customer; 102 | this.shipmentLine = new ArrayList(); 103 | } 104 | 105 | public void setShipmentLine(List shipmentLine) { 106 | this.shipmentLine = shipmentLine; 107 | } 108 | 109 | @Transient 110 | public void setOrderLine(List orderLine) { 111 | this.shipmentLine = orderLine; 112 | } 113 | 114 | public int getNumberOfLines() { 115 | return shipmentLine.size(); 116 | } 117 | 118 | @Override 119 | public String toString() { 120 | return ToStringBuilder.reflectionToString(this); 121 | } 122 | 123 | @Override 124 | public int hashCode() { 125 | return HashCodeBuilder.reflectionHashCode(this); 126 | } 127 | 128 | @Override 129 | public boolean equals(Object obj) { 130 | return EqualsBuilder.reflectionEquals(this, obj); 131 | } 132 | 133 | public void setCost(int cost) { 134 | this.cost = cost; 135 | } 136 | 137 | public int getCost() { 138 | return cost; 139 | } 140 | 141 | public void calculateShippingCost() { 142 | if (getDeliveryService().equalsIgnoreCase("DHL")) { 143 | setCost(1); 144 | } else if (getDeliveryService().equalsIgnoreCase("Hermes")) { 145 | setCost(2); 146 | } else { 147 | throw new IllegalArgumentException("Unknown Delivery Service!"); 148 | } 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-shipping/src/main/java/com/ewolff/microservice/shipping/ShipmentLine.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.shipping; 2 | 3 | import javax.persistence.Column; 4 | import javax.persistence.Embedded; 5 | import javax.persistence.Entity; 6 | import javax.persistence.GeneratedValue; 7 | import javax.persistence.Id; 8 | 9 | import org.apache.commons.lang.builder.EqualsBuilder; 10 | import org.apache.commons.lang.builder.HashCodeBuilder; 11 | import org.apache.commons.lang.builder.ToStringBuilder; 12 | 13 | @Entity 14 | public class ShipmentLine { 15 | 16 | @Column(name = "F_COUNT") 17 | private int count; 18 | 19 | @Embedded 20 | private Item item; 21 | 22 | @Id 23 | @GeneratedValue 24 | private long id; 25 | 26 | public void setCount(int count) { 27 | this.count = count; 28 | } 29 | 30 | public void setItem(Item item) { 31 | this.item = item; 32 | } 33 | 34 | public ShipmentLine() { 35 | } 36 | 37 | public ShipmentLine(int count, Item item) { 38 | this.count = count; 39 | this.item = item; 40 | } 41 | 42 | public int getCount() { 43 | return count; 44 | } 45 | 46 | public Item getItem() { 47 | return item; 48 | } 49 | 50 | @Override 51 | public String toString() { 52 | return ToStringBuilder.reflectionToString(this); 53 | } 54 | 55 | @Override 56 | public int hashCode() { 57 | return HashCodeBuilder.reflectionHashCode(this); 58 | 59 | } 60 | 61 | @Override 62 | public boolean equals(Object obj) { 63 | return EqualsBuilder.reflectionEquals(this, obj); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-shipping/src/main/java/com/ewolff/microservice/shipping/ShipmentRepository.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.shipping; 2 | 3 | import java.util.Date; 4 | 5 | import org.springframework.data.jpa.repository.Query; 6 | import org.springframework.data.repository.PagingAndSortingRepository; 7 | 8 | public interface ShipmentRepository extends PagingAndSortingRepository { 9 | 10 | @Query("SELECT max(s.updated) FROM Shipment s") 11 | Date lastUpdate(); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-shipping/src/main/java/com/ewolff/microservice/shipping/ShipmentService.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.shipping; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | import org.springframework.transaction.annotation.Transactional; 8 | 9 | @Service 10 | public class ShipmentService { 11 | 12 | private final Logger log = LoggerFactory.getLogger(ShipmentService.class); 13 | 14 | private ShipmentRepository shipmentRepository; 15 | 16 | @Autowired 17 | public ShipmentService(ShipmentRepository shipmentRepository) { 18 | super(); 19 | this.shipmentRepository = shipmentRepository; 20 | } 21 | 22 | @Transactional 23 | public void ship(Shipment shipment) { 24 | if (shipmentRepository.existsById(shipment.getId())) { 25 | log.info("Shipment id {} already exists - ignored", shipment.getId()); 26 | } else { 27 | shipment.calculateShippingCost(); 28 | shipmentRepository.save(shipment); 29 | } 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-shipping/src/main/java/com/ewolff/microservice/shipping/ShippingApp.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.shipping; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.scheduling.annotation.EnableScheduling; 6 | 7 | @EnableScheduling 8 | @SpringBootApplication 9 | public class ShippingApp { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(ShippingApp.class, args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-shipping/src/main/java/com/ewolff/microservice/shipping/poller/OrderFeed.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.shipping.poller; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Date; 5 | import java.util.List; 6 | 7 | import org.apache.commons.lang.builder.EqualsBuilder; 8 | import org.apache.commons.lang.builder.ToStringBuilder; 9 | 10 | import net.logstash.logback.encoder.org.apache.commons.lang.builder.HashCodeBuilder; 11 | 12 | public class OrderFeed { 13 | 14 | private Date updated; 15 | 16 | private List orders; 17 | 18 | public OrderFeed() { 19 | super(); 20 | orders = new ArrayList(); 21 | } 22 | 23 | public Date getUpdated() { 24 | return updated; 25 | } 26 | 27 | public void setUpdated(Date updated) { 28 | this.updated = updated; 29 | } 30 | 31 | public List getOrders() { 32 | return orders; 33 | } 34 | 35 | public void setOrders(List orders) { 36 | this.orders = orders; 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | return ToStringBuilder.reflectionToString(this); 42 | } 43 | 44 | @Override 45 | public int hashCode() { 46 | return HashCodeBuilder.reflectionHashCode(this); 47 | } 48 | 49 | @Override 50 | public boolean equals(Object obj) { 51 | return EqualsBuilder.reflectionEquals(this, obj); 52 | } 53 | 54 | } -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-shipping/src/main/java/com/ewolff/microservice/shipping/poller/OrderFeedEntry.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.shipping.poller; 2 | 3 | import java.util.Date; 4 | 5 | import org.apache.commons.lang.builder.EqualsBuilder; 6 | import org.apache.commons.lang.builder.HashCodeBuilder; 7 | import org.apache.commons.lang.builder.ToStringBuilder; 8 | 9 | public class OrderFeedEntry { 10 | 11 | private long id; 12 | 13 | private String link; 14 | 15 | private Date updated; 16 | 17 | public long getId() { 18 | return id; 19 | } 20 | 21 | public void setId(long id) { 22 | this.id = id; 23 | } 24 | 25 | public String getLink() { 26 | return link; 27 | } 28 | 29 | public void setLink(String link) { 30 | this.link = link; 31 | } 32 | 33 | public Date getUpdated() { 34 | return updated; 35 | } 36 | 37 | public void setUpdated(Date updated) { 38 | this.updated = updated; 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return ToStringBuilder.reflectionToString(this); 44 | } 45 | 46 | @Override 47 | public int hashCode() { 48 | return HashCodeBuilder.reflectionHashCode(this); 49 | } 50 | 51 | @Override 52 | public boolean equals(Object obj) { 53 | return EqualsBuilder.reflectionEquals(this, obj); 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-shipping/src/main/java/com/ewolff/microservice/shipping/poller/ShippingPoller.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.shipping.poller; 2 | 3 | import java.util.Date; 4 | 5 | import com.ewolff.microservice.shipping.Shipment; 6 | import com.ewolff.microservice.shipping.ShipmentService; 7 | 8 | import org.apache.http.client.utils.DateUtils; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.beans.factory.annotation.Value; 13 | import org.springframework.http.HttpEntity; 14 | import org.springframework.http.HttpHeaders; 15 | import org.springframework.http.HttpMethod; 16 | import org.springframework.http.HttpStatus; 17 | import org.springframework.http.ResponseEntity; 18 | import org.springframework.scheduling.annotation.Scheduled; 19 | import org.springframework.stereotype.Component; 20 | import org.springframework.web.client.RestTemplate; 21 | 22 | @Component 23 | public class ShippingPoller { 24 | 25 | private final Logger log = LoggerFactory.getLogger(ShippingPoller.class); 26 | 27 | private String url = ""; 28 | 29 | private RestTemplate restTemplate = new RestTemplate(); 30 | 31 | private Date lastModified = null; 32 | 33 | private ShipmentService shipmentService; 34 | 35 | private boolean pollingActivated = true; 36 | 37 | @Autowired 38 | public ShippingPoller(@Value("${order.url}") String url, @Value("${poller.actived:true}") boolean pollingActivated, 39 | ShipmentService shipmentService) { 40 | super(); 41 | this.url = url; 42 | this.shipmentService = shipmentService; 43 | this.pollingActivated = pollingActivated; 44 | } 45 | 46 | @Scheduled(fixedDelay = 30000) 47 | public void poll() { 48 | if (pollingActivated) { 49 | pollInternal(); 50 | } 51 | } 52 | 53 | public void pollInternal() { 54 | HttpHeaders requestHeaders = new HttpHeaders(); 55 | requestHeaders.set(HttpHeaders.ACCEPT, "*/*"); 56 | if (lastModified != null) { 57 | requestHeaders.set(HttpHeaders.IF_MODIFIED_SINCE, DateUtils.formatDate(lastModified)); 58 | } 59 | HttpEntity requestEntity = new HttpEntity(requestHeaders); 60 | ResponseEntity response = restTemplate.exchange(url, HttpMethod.GET, requestEntity, OrderFeed.class); 61 | 62 | if (response.getStatusCode() != HttpStatus.NOT_MODIFIED) { 63 | log.trace("data has been modified"); 64 | OrderFeed feed = response.getBody(); 65 | for (OrderFeedEntry entry : feed.getOrders()) { 66 | if ((lastModified == null) || (entry.getUpdated().after(lastModified))) { 67 | Shipment shipping = restTemplate 68 | .getForEntity(entry.getLink(), Shipment.class).getBody(); 69 | log.trace("saving shipping {}", shipping.getId()); 70 | shipmentService.ship(shipping); 71 | } 72 | } 73 | if (response.getHeaders().getFirst("Last-Modified") != null) { 74 | lastModified = DateUtils.parseDate(response.getHeaders().getFirst(HttpHeaders.LAST_MODIFIED)); 75 | log.trace("Last-Modified header {}", lastModified); 76 | } 77 | } else { 78 | log.trace("no new data"); 79 | } 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-shipping/src/main/java/com/ewolff/microservice/shipping/web/PollController.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.shipping.web; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RequestMethod; 7 | 8 | import com.ewolff.microservice.shipping.poller.ShippingPoller; 9 | 10 | @Controller 11 | public class PollController { 12 | 13 | private ShippingPoller poller; 14 | 15 | @Autowired 16 | public PollController(ShippingPoller poller) { 17 | this.poller = poller; 18 | } 19 | 20 | @RequestMapping(value = "/poll", method = RequestMethod.POST) 21 | public String poll() { 22 | poller.poll(); 23 | return "success"; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-shipping/src/main/java/com/ewolff/microservice/shipping/web/ShippingController.java: -------------------------------------------------------------------------------- 1 | package com.ewolff.microservice.shipping.web; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.http.MediaType; 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.web.bind.annotation.PathVariable; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RequestMethod; 9 | import org.springframework.web.servlet.ModelAndView; 10 | 11 | import com.ewolff.microservice.shipping.ShipmentRepository; 12 | 13 | @Controller 14 | public class ShippingController { 15 | 16 | private ShipmentRepository shipmentRepository; 17 | 18 | @Autowired 19 | public ShippingController(ShipmentRepository shipmentRepository) { 20 | this.shipmentRepository = shipmentRepository; 21 | } 22 | 23 | @RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE) 24 | public ModelAndView shipment(@PathVariable("id") long id) { 25 | return new ModelAndView("shipment", "shipment", shipmentRepository.findById(id).get()); 26 | } 27 | 28 | @RequestMapping("/") 29 | public ModelAndView shipmentList() { 30 | return new ModelAndView("shipmentlist", "shipments", shipmentRepository.findAll()); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-shipping/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8080 2 | spring.application.name=shipping 3 | server.servlet.context-path=/shipping 4 | management.endpoints.web.exposure.include=* 5 | logging.level.org.springframework.boot.actuate.trace.WebRequestTraceFilter: TRACE 6 | logging.level.com.ewolff.microservice.shipping.poller: TRACE 7 | logging.level.org.springframework.http.converter.json: ERROR 8 | order.url=http://order:80/order/feed 9 | spring.jpa.hibernate.ddl-auto=update 10 | spring.datasource.url=jdbc:postgresql://postgres/dbshipping 11 | spring.datasource.username=dbuser 12 | spring.datasource.password=dbpass 13 | spring.datasource.driver-class-name=org.postgresql.Driver 14 | spring.sleuth.propagation-keys=x-request-id,x-ot-span-context 15 | spring.sleuth.opentracing.enabled=true 16 | spring.zipkin.baseUrl=http://linkerd-collector.linkerd:55678 -------------------------------------------------------------------------------- /microservice-linkerd-demo/microservice-linkerd-shipping/src/main/resources/templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | Layout 7 | 9 | 11 | 12 | 13 | 14 | 22 |

Layout

23 |
Fake content
24 |