├── .gitignore ├── LICENSE ├── README.md ├── bootstrap ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── HELP.md ├── README.md ├── bootcamp.iml ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── bootcamp │ │ │ └── BootcampApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── example │ └── bootcamp │ └── BootcampApplicationTests.java ├── build.sh ├── cloudfoundry ├── client │ ├── .gitignore │ ├── .mvn │ │ └── wrapper │ │ │ ├── MavenWrapperDownloader.java │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── cf │ │ │ │ └── CfApplication.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── cf │ │ └── CfApplicationTests.java └── demo │ ├── hi.groovy │ ├── hi.jar │ └── hi.jar.original ├── data ├── mongodb │ ├── .gitignore │ ├── .mvn │ │ └── wrapper │ │ │ ├── MavenWrapperDownloader.java │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── mongo │ │ │ │ └── MongoApplication.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── mongo │ │ └── MongoApplicationTests.java └── r2dbc │ ├── .gitignore │ ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── r2dbc │ │ │ └── R2dbcApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── example │ └── r2dbc │ └── R2dbcApplicationTests.java ├── gateways ├── client │ ├── .gitignore │ ├── .mvn │ │ └── wrapper │ │ │ ├── MavenWrapperDownloader.java │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── client │ │ │ │ └── ClientApplication.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── client │ │ └── ClientApplicationTests.java ├── eureka-service │ ├── .gitignore │ ├── .mvn │ │ └── wrapper │ │ │ ├── MavenWrapperDownloader.java │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── eurekaservice │ │ │ │ └── EurekaServiceApplication.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── eurekaservice │ │ └── EurekaServiceApplicationTests.java └── service │ ├── .gitignore │ ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── service │ │ │ └── ServiceApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── example │ └── service │ └── ServiceApplicationTests.java ├── kafka ├── kafka-consumer │ ├── .gitignore │ ├── .mvn │ │ └── wrapper │ │ │ ├── MavenWrapperDownloader.java │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── kafkaconsumer │ │ │ │ └── KafkaConsumerApplication.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── kafkaconsumer │ │ └── KafkaConsumerApplicationTests.java └── kafka-producer │ ├── .gitignore │ ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── kafkaproducer │ │ │ └── KafkaProducerApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── example │ └── kafkaproducer │ └── KafkaProducerApplicationTests.java ├── reactive-adapter ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── reactiveadapter │ │ │ └── ReactiveAdapterApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── example │ └── reactiveadapter │ └── ReactiveAdapterApplicationTests.java ├── reactor ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── demo │ │ │ └── DemoApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── example │ └── demo │ └── DemoApplicationTests.java ├── reliability ├── api │ ├── .gitignore │ ├── .mvn │ │ └── wrapper │ │ │ ├── MavenWrapperDownloader.java │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── api │ │ │ │ └── ApiApplication.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── api │ │ └── ApiApplicationTests.java └── client │ ├── .gitignore │ ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── client │ │ │ └── ClientApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── example │ └── client │ └── ClientApplicationTests.java ├── rsocket ├── client │ ├── .gitignore │ ├── .mvn │ │ └── wrapper │ │ │ ├── MavenWrapperDownloader.java │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── client │ │ │ ├── GreetingRequest.java │ │ │ ├── GreetingResponse.java │ │ │ ├── raw │ │ │ ├── ClientApplication.java │ │ │ └── GreetingClient.java │ │ │ └── spring │ │ │ ├── ClientApplication.java │ │ │ └── GreetingClient.java │ │ └── resources │ │ └── application.properties └── producer │ ├── .gitignore │ ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ └── main │ ├── java │ └── com │ │ └── example │ │ ├── GreetingService.java │ │ └── producer │ │ ├── GreetingRequest.java │ │ ├── GreetingResponse.java │ │ ├── raw │ │ └── RawRsocketApplication.java │ │ └── spring │ │ ├── GreetingRsocketService.java │ │ └── SpringRsocketApplication.java │ └── resources │ └── application.properties ├── testing ├── consumer │ ├── .gitignore │ ├── .mvn │ │ └── wrapper │ │ │ ├── MavenWrapperDownloader.java │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── consumer │ │ │ │ ├── ConsumerApplication.java │ │ │ │ └── ReservationClient.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── consumer │ │ └── ConsumerApplicationTests.java ├── producer │ ├── .gitignore │ ├── .mvn │ │ └── wrapper │ │ │ ├── MavenWrapperDownloader.java │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── producer │ │ │ │ ├── ProducerApplication.java │ │ │ │ ├── Reservation.java │ │ │ │ ├── ReservationHttpConfiguration.java │ │ │ │ └── ReservationRepository.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── producer │ │ │ ├── BaseClass.java │ │ │ ├── ReservationEntityTest.java │ │ │ ├── ReservationHttpTest.java │ │ │ ├── ReservationRepositoryTest.java │ │ │ └── ReservationTest.java │ │ └── resources │ │ ├── application.properties │ │ └── contracts │ │ └── shouldReturnAllReservations.groovy ├── run-stub-runner-boot.sh └── spring-cloud-contract-stub-runner-boot-2.1.1.RELEASE.jar └── web ├── .gitignore ├── .mvn └── wrapper │ ├── MavenWrapperDownloader.java │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── example │ │ └── web │ │ └── WebApplication.java └── resources │ ├── application.properties │ └── static │ ├── sse.html │ └── ws.html └── test └── java └── com └── example └── web └── WebApplicationTests.java /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | pom.xml.tag 3 | pom.xml.releaseBackup 4 | pom.xml.versionsBackup 5 | pom.xml.next 6 | release.properties 7 | dependency-reduced-pom.xml 8 | buildNumber.properties 9 | .mvn/timing.properties 10 | 11 | # Avoid ignoring Maven wrapper jar file (.jar files are usually ignored) 12 | !/.mvn/wrapper/maven-wrapper.jar 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A Bootiful Reactive Microservices Masterclass 2 | 3 | Useful to get everything built: `find . -iname pom.xml | xargs -I pom mvn -DskipTests=true -f pom install` 4 | 5 | 6 | * Motivations for Microservices (x) 7 | * Learning Organizations 8 | * Agility 9 | 10 | * Spring Boot "Bootcamp" (x) 11 | * Starters 12 | * Autoconfiguration 13 | 14 | * Introduction to the Reactive Streams & Reactor (x) 15 | * Cold & Hot Streams 16 | * Schedulers 17 | * the Reactor Context 18 | * Adapting non-reactive event sources to reactive APIs with a reactive adapter 19 | 20 | * Reactive Data Access (x) 21 | * Spring Data MongoDB 22 | * R2DBC 23 | 24 | * The Web Tier (x) 25 | * Spring Webflux-powered HTTP APIs 26 | * Websockets 27 | * the `WebClient` Reactive HTTP Client 28 | * Actuator 29 | 30 | * Testing (x) 31 | * Testing Reactive Pipelines 32 | * Testing Data Access 33 | * Testing Web Endpoints 34 | * Testing Microservices 35 | 36 | * Reliability Patterns (x) 37 | * The new Spring Cloud Circuit Breaker 38 | * `onErrorResume(...)` 39 | * `retry(...)` 40 | * `on*` 41 | 42 | * Edge Services (x) 43 | * API Gateway 44 | * API Adapters 45 | 46 | * RSocket (x) 47 | * Raw RSocket 48 | * Spring Message Mapping 49 | 50 | * Cloud Foundry (x) 51 | * `cf push` 52 | * The Reactive Java Client 53 | 54 | In order to use MongoDB you'll need a program like this: 55 | ``` 56 | data=$HOME/Desktop/mongodb-data 57 | mkdir -p $data 58 | mongod --replSet my-replica-set --dbpath $data & 59 | mongo --eval "rs.initiate()" 60 | ``` 61 | -------------------------------------------------------------------------------- /bootstrap/.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 | https://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.io.File; 21 | import java.io.FileInputStream; 22 | import java.io.FileOutputStream; 23 | import java.io.IOException; 24 | import java.net.URL; 25 | import java.nio.channels.Channels; 26 | import java.nio.channels.ReadableByteChannel; 27 | import java.util.Properties; 28 | 29 | public class MavenWrapperDownloader { 30 | 31 | /** 32 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 33 | */ 34 | private static final String DEFAULT_DOWNLOAD_URL = 35 | "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; 36 | 37 | /** 38 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 39 | * use instead of the default one. 40 | */ 41 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 42 | ".mvn/wrapper/maven-wrapper.properties"; 43 | 44 | /** 45 | * Path where the maven-wrapper.jar will be saved to. 46 | */ 47 | private static final String MAVEN_WRAPPER_JAR_PATH = 48 | ".mvn/wrapper/maven-wrapper.jar"; 49 | 50 | /** 51 | * Name of the property which should be used to override the default download url for the wrapper. 52 | */ 53 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 54 | 55 | public static void main(String args[]) { 56 | System.out.println("- Downloader started"); 57 | File baseDirectory = new File(args[0]); 58 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 59 | 60 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 61 | // wrapperUrl parameter. 62 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 63 | String url = DEFAULT_DOWNLOAD_URL; 64 | if(mavenWrapperPropertyFile.exists()) { 65 | FileInputStream mavenWrapperPropertyFileInputStream = null; 66 | try { 67 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 68 | Properties mavenWrapperProperties = new Properties(); 69 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 70 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 71 | } catch (IOException e) { 72 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 73 | } finally { 74 | try { 75 | if(mavenWrapperPropertyFileInputStream != null) { 76 | mavenWrapperPropertyFileInputStream.close(); 77 | } 78 | } catch (IOException e) { 79 | // Ignore ... 80 | } 81 | } 82 | } 83 | System.out.println("- Downloading from: : " + url); 84 | 85 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 86 | if(!outputFile.getParentFile().exists()) { 87 | if(!outputFile.getParentFile().mkdirs()) { 88 | System.out.println( 89 | "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 90 | } 91 | } 92 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 93 | try { 94 | downloadFileFromURL(url, outputFile); 95 | System.out.println("Done"); 96 | System.exit(0); 97 | } catch (Throwable e) { 98 | System.out.println("- Error downloading"); 99 | e.printStackTrace(); 100 | System.exit(1); 101 | } 102 | } 103 | 104 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 105 | URL website = new URL(urlString); 106 | ReadableByteChannel rbc; 107 | rbc = Channels.newChannel(website.openStream()); 108 | FileOutputStream fos = new FileOutputStream(destination); 109 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 110 | fos.close(); 111 | rbc.close(); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /bootstrap/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong-attic/bootiful-reactive-microservices-masterclass/080f7e0d79fbff17056eb20f29ad415ca30726d9/bootstrap/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /bootstrap/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /bootstrap/HELP.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | ### Reference Documentation 4 | For further reference, please consider the following sections: 5 | 6 | * [Official Apache Maven documentation](https://maven.apache.org/guides/index.html) 7 | 8 | ### Guides 9 | The following guides illustrate how to use some features concretely: 10 | 11 | * [Building a RESTful Web Service with Spring Boot Actuator](https://spring.io/guides/gs/actuator-service/) 12 | 13 | -------------------------------------------------------------------------------- /bootstrap/README.md: -------------------------------------------------------------------------------- 1 | ## Bootcamp 2 | 3 | This project requires Spring Boot 2.2.0.M3. It demonstrates how dependency injection, opinonated starters, autoconfiguration, the Spring Boot Devtools and configuration processor all congeal together to produce consistent applications. It also uses the `git-commit` plugin, so run `mvn clean package` before starting the application. It'll then show the details in `/actuator/info`. -------------------------------------------------------------------------------- /bootstrap/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.springframework.boot 8 | spring-boot-starter-parent 9 | 2.2.0.M3 10 | 11 | 12 | com.example 13 | bootcamp 14 | 0.0.1-SNAPSHOT 15 | bootcamp 16 | Demo project for Spring Boot 17 | 18 | 19 | 11 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-actuator 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-data-mongodb-reactive 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-webflux 34 | 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-devtools 39 | runtime 40 | true 41 | 42 | 43 | org.springframework.boot 44 | spring-boot-configuration-processor 45 | true 46 | 47 | 48 | org.projectlombok 49 | lombok 50 | true 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-starter-test 55 | test 56 | 57 | 58 | org.junit.vintage 59 | junit-vintage-engine 60 | 61 | 62 | junit 63 | junit 64 | 65 | 66 | 67 | 68 | io.projectreactor 69 | reactor-test 70 | test 71 | 72 | 73 | 74 | 75 | 76 | 77 | pl.project13.maven 78 | git-commit-id-plugin 79 | 80 | 81 | org.springframework.boot 82 | spring-boot-maven-plugin 83 | 84 | 85 | 86 | 87 | 88 | 89 | spring-snapshots 90 | Spring Snapshots 91 | https://repo.spring.io/snapshot 92 | 93 | true 94 | 95 | 96 | 97 | spring-milestones 98 | Spring Milestones 99 | https://repo.spring.io/milestone 100 | 101 | 102 | 103 | 104 | spring-snapshots 105 | Spring Snapshots 106 | https://repo.spring.io/snapshot 107 | 108 | true 109 | 110 | 111 | 112 | spring-milestones 113 | Spring Milestones 114 | https://repo.spring.io/milestone 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /bootstrap/src/main/java/com/example/bootcamp/BootcampApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.bootcamp; 2 | 3 | import lombok.extern.log4j.Log4j2; 4 | import org.springframework.beans.factory.InitializingBean; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.boot.context.event.ApplicationReadyEvent; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.context.event.EventListener; 11 | import org.springframework.web.bind.annotation.GetMapping; 12 | import org.springframework.web.bind.annotation.PathVariable; 13 | import org.springframework.web.bind.annotation.RestController; 14 | 15 | import javax.annotation.PostConstruct; 16 | import java.time.Instant; 17 | import java.util.function.Function; 18 | 19 | 20 | @SpringBootApplication 21 | public class BootcampApplication { 22 | 23 | 24 | public static void main(String[] args) { 25 | SpringApplication.run(BootcampApplication.class, args); 26 | } 27 | } 28 | 29 | 30 | @Configuration 31 | class WebConfig { 32 | 33 | @Bean 34 | MyInitializer myInitializer() { 35 | return new MyInitializer(); 36 | } 37 | 38 | @Bean 39 | GreetingsService greetingsService() { 40 | return new GreetingsService(); 41 | } 42 | 43 | 44 | } 45 | 46 | @Log4j2 47 | //@Component 48 | class MyInitializer { 49 | 50 | @EventListener 51 | public void onReady(ApplicationReadyEvent event) { 52 | log.info(getClass().getName() + '#' + "afterPropertiesSet"); 53 | } 54 | } 55 | 56 | //@Service 57 | class GreetingsService { 58 | 59 | String greet(String name) { 60 | return "Hello " + name + "@" + Instant.now() + "!"; 61 | } 62 | } 63 | 64 | @Log4j2 65 | @RestController 66 | class GreetingsRestController implements InitializingBean { 67 | 68 | private final GreetingsService greetingsService; 69 | 70 | GreetingsRestController(GreetingsService greetingsService) { 71 | log.info("initializing " + this.getClass().getName()); 72 | this.greetingsService = greetingsService; 73 | } 74 | 75 | @GetMapping("/hello/{name}") 76 | String greet(@PathVariable String name) { 77 | return this.greetingsService.greet(name); 78 | } 79 | 80 | @PostConstruct 81 | public void begin() { 82 | log.info("begin()"); 83 | } 84 | 85 | @Override 86 | public void afterPropertiesSet() throws Exception { 87 | log.info("afterPropertiesSet()"); 88 | } 89 | } 90 | 91 | -------------------------------------------------------------------------------- /bootstrap/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.main.lazy-initialization=true 2 | ## 3 | management.endpoints.web.exposure.include=* 4 | management.endpoint.health.show-details=always 5 | 6 | ## 7 | management.info.build.enabled=true -------------------------------------------------------------------------------- /bootstrap/src/test/java/com/example/bootcamp/BootcampApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.bootcamp; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class BootcampApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | find . -iname pom.xml | xargs -I pom mvn -DskipTests=true -f pom clean install 2 | -------------------------------------------------------------------------------- /cloudfoundry/client/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | /target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | 20 | ### NetBeans ### 21 | /nbproject/private/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ 26 | /build/ 27 | 28 | ### VS Code ### 29 | .vscode/ 30 | -------------------------------------------------------------------------------- /cloudfoundry/client/.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 | https://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.io.File; 21 | import java.io.FileInputStream; 22 | import java.io.FileOutputStream; 23 | import java.io.IOException; 24 | import java.net.URL; 25 | import java.nio.channels.Channels; 26 | import java.nio.channels.ReadableByteChannel; 27 | import java.util.Properties; 28 | 29 | public class MavenWrapperDownloader { 30 | 31 | /** 32 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 33 | */ 34 | private static final String DEFAULT_DOWNLOAD_URL = 35 | "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; 36 | 37 | /** 38 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 39 | * use instead of the default one. 40 | */ 41 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 42 | ".mvn/wrapper/maven-wrapper.properties"; 43 | 44 | /** 45 | * Path where the maven-wrapper.jar will be saved to. 46 | */ 47 | private static final String MAVEN_WRAPPER_JAR_PATH = 48 | ".mvn/wrapper/maven-wrapper.jar"; 49 | 50 | /** 51 | * Name of the property which should be used to override the default download url for the wrapper. 52 | */ 53 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 54 | 55 | public static void main(String args[]) { 56 | System.out.println("- Downloader started"); 57 | File baseDirectory = new File(args[0]); 58 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 59 | 60 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 61 | // wrapperUrl parameter. 62 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 63 | String url = DEFAULT_DOWNLOAD_URL; 64 | if(mavenWrapperPropertyFile.exists()) { 65 | FileInputStream mavenWrapperPropertyFileInputStream = null; 66 | try { 67 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 68 | Properties mavenWrapperProperties = new Properties(); 69 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 70 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 71 | } catch (IOException e) { 72 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 73 | } finally { 74 | try { 75 | if(mavenWrapperPropertyFileInputStream != null) { 76 | mavenWrapperPropertyFileInputStream.close(); 77 | } 78 | } catch (IOException e) { 79 | // Ignore ... 80 | } 81 | } 82 | } 83 | System.out.println("- Downloading from: : " + url); 84 | 85 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 86 | if(!outputFile.getParentFile().exists()) { 87 | if(!outputFile.getParentFile().mkdirs()) { 88 | System.out.println( 89 | "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 90 | } 91 | } 92 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 93 | try { 94 | downloadFileFromURL(url, outputFile); 95 | System.out.println("Done"); 96 | System.exit(0); 97 | } catch (Throwable e) { 98 | System.out.println("- Error downloading"); 99 | e.printStackTrace(); 100 | System.exit(1); 101 | } 102 | } 103 | 104 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 105 | URL website = new URL(urlString); 106 | ReadableByteChannel rbc; 107 | rbc = Channels.newChannel(website.openStream()); 108 | FileOutputStream fos = new FileOutputStream(destination); 109 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 110 | fos.close(); 111 | rbc.close(); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /cloudfoundry/client/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong-attic/bootiful-reactive-microservices-masterclass/080f7e0d79fbff17056eb20f29ad415ca30726d9/cloudfoundry/client/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /cloudfoundry/client/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /cloudfoundry/client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.springframework.boot 8 | spring-boot-starter-parent 9 | 2.2.0.M3 10 | 11 | 12 | com.example 13 | cf 14 | 0.0.1-SNAPSHOT 15 | cf 16 | Demo project for Spring Boot 17 | 18 | 19 | 1.8 20 | 3.15.0.RELEASE 21 | 22 | 23 | 24 | 25 | 26 | 27 | org.cloudfoundry 28 | cloudfoundry-client-reactor 29 | ${cloudfoundry-client.version} 30 | 31 | 32 | org.projectlombok 33 | lombok 34 | 35 | 36 | org.cloudfoundry 37 | cloudfoundry-operations 38 | ${cloudfoundry-client.version} 39 | 40 | 50 | 51 | org.springframework.boot 52 | spring-boot-starter-webflux 53 | 54 | 55 | org.springframework.boot 56 | spring-boot-starter 57 | 58 | 59 | 60 | org.springframework.boot 61 | spring-boot-starter-test 62 | test 63 | 64 | 65 | 66 | 67 | 68 | 69 | org.springframework.boot 70 | spring-boot-maven-plugin 71 | 72 | 73 | 74 | 75 | 76 | 77 | spring-snapshots 78 | Spring Snapshots 79 | https://repo.spring.io/snapshot 80 | 81 | true 82 | 83 | 84 | 85 | spring-milestones 86 | Spring Milestones 87 | https://repo.spring.io/milestone 88 | 89 | 90 | 91 | 92 | spring-snapshots 93 | Spring Snapshots 94 | https://repo.spring.io/snapshot 95 | 96 | true 97 | 98 | 99 | 100 | spring-milestones 101 | Spring Milestones 102 | https://repo.spring.io/milestone 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /cloudfoundry/client/src/main/java/com/example/cf/CfApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.cf; 2 | 3 | import lombok.RequiredArgsConstructor; 4 | import lombok.extern.log4j.Log4j2; 5 | import org.cloudfoundry.client.CloudFoundryClient; 6 | import org.cloudfoundry.client.v3.applications.ListApplicationsRequest; 7 | import org.cloudfoundry.doppler.DopplerClient; 8 | import org.cloudfoundry.operations.DefaultCloudFoundryOperations; 9 | import org.cloudfoundry.reactor.ConnectionContext; 10 | import org.cloudfoundry.reactor.DefaultConnectionContext; 11 | import org.cloudfoundry.reactor.TokenProvider; 12 | import org.cloudfoundry.reactor.client.ReactorCloudFoundryClient; 13 | import org.cloudfoundry.reactor.doppler.ReactorDopplerClient; 14 | import org.cloudfoundry.reactor.tokenprovider.PasswordGrantTokenProvider; 15 | import org.cloudfoundry.reactor.uaa.ReactorUaaClient; 16 | import org.cloudfoundry.uaa.UaaClient; 17 | import org.springframework.beans.factory.annotation.Value; 18 | import org.springframework.boot.SpringApplication; 19 | import org.springframework.boot.autoconfigure.SpringBootApplication; 20 | import org.springframework.boot.context.event.ApplicationReadyEvent; 21 | import org.springframework.context.annotation.Bean; 22 | import org.springframework.context.event.EventListener; 23 | import org.springframework.stereotype.Component; 24 | import reactor.core.publisher.Flux; 25 | 26 | @SpringBootApplication 27 | public class CfApplication { 28 | 29 | public static void main(String[] args) { 30 | SpringApplication.run(CfApplication.class, args); 31 | } 32 | 33 | @Bean 34 | DefaultCloudFoundryOperations cloudFoundryOperations(CloudFoundryClient cloudFoundryClient, 35 | DopplerClient dopplerClient, 36 | UaaClient uaaClient, 37 | @Value("${cf.org}") String organization, 38 | @Value("${cf.space}") String space) { 39 | return DefaultCloudFoundryOperations 40 | .builder() 41 | .cloudFoundryClient(cloudFoundryClient) 42 | .dopplerClient(dopplerClient) 43 | .uaaClient(uaaClient) 44 | .organization(organization) 45 | .space(space) 46 | .build(); 47 | } 48 | 49 | @Bean 50 | DefaultConnectionContext connectionContext(@Value("${cf.api}") String apiHost) { 51 | return DefaultConnectionContext 52 | .builder() 53 | .apiHost(apiHost.split("://")[1]) 54 | .build(); 55 | } 56 | 57 | @Bean 58 | PasswordGrantTokenProvider tokenProvider( 59 | @Value("${cf.user}") String username, 60 | @Value("${cf.password}") String password) { 61 | return PasswordGrantTokenProvider.builder() 62 | .password(password) 63 | .username(username) 64 | .build(); 65 | } 66 | 67 | @Bean 68 | ReactorCloudFoundryClient cloudFoundryClient(ConnectionContext connectionContext, TokenProvider tokenProvider) { 69 | return ReactorCloudFoundryClient 70 | .builder() 71 | .connectionContext(connectionContext) 72 | .tokenProvider(tokenProvider) 73 | .build(); 74 | } 75 | 76 | @Bean 77 | ReactorDopplerClient dopplerClient(ConnectionContext connectionContext, TokenProvider tokenProvider) { 78 | return ReactorDopplerClient 79 | .builder() 80 | .connectionContext(connectionContext) 81 | .tokenProvider(tokenProvider) 82 | .build(); 83 | } 84 | 85 | @Bean 86 | ReactorUaaClient uaaClient(ConnectionContext connectionContext, TokenProvider tokenProvider) { 87 | return ReactorUaaClient 88 | .builder() 89 | .connectionContext(connectionContext) 90 | .tokenProvider(tokenProvider) 91 | .build(); 92 | } 93 | } 94 | 95 | @Log4j2 96 | @Component 97 | @RequiredArgsConstructor 98 | class Demo { 99 | 100 | private final CloudFoundryClient cloudFoundryClient; 101 | 102 | @EventListener(ApplicationReadyEvent.class) 103 | public void go() throws Exception { 104 | this.cloudFoundryClient 105 | .applicationsV3() 106 | .list(ListApplicationsRequest.builder().build()) 107 | .flatMapMany(listApplicationsResponse -> Flux.fromIterable(listApplicationsResponse.getResources())) 108 | .subscribe(log::info); 109 | 110 | } 111 | } -------------------------------------------------------------------------------- /cloudfoundry/client/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /cloudfoundry/client/src/test/java/com/example/cf/CfApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.cf; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class CfApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /cloudfoundry/demo/hi.groovy: -------------------------------------------------------------------------------- 1 | @RestController 2 | class GreetingsRestController { 3 | 4 | @GetMapping("/hi/{name}") 5 | def greet (@PathVariable String name){ 6 | [ greeting : "Hello " + name + "!" ] 7 | } 8 | } 9 | 10 | -------------------------------------------------------------------------------- /cloudfoundry/demo/hi.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong-attic/bootiful-reactive-microservices-masterclass/080f7e0d79fbff17056eb20f29ad415ca30726d9/cloudfoundry/demo/hi.jar -------------------------------------------------------------------------------- /cloudfoundry/demo/hi.jar.original: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong-attic/bootiful-reactive-microservices-masterclass/080f7e0d79fbff17056eb20f29ad415ca30726d9/cloudfoundry/demo/hi.jar.original -------------------------------------------------------------------------------- /data/mongodb/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | /target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | 20 | ### NetBeans ### 21 | /nbproject/private/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ 26 | /build/ 27 | 28 | ### VS Code ### 29 | .vscode/ 30 | -------------------------------------------------------------------------------- /data/mongodb/.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 | https://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.io.File; 21 | import java.io.FileInputStream; 22 | import java.io.FileOutputStream; 23 | import java.io.IOException; 24 | import java.net.URL; 25 | import java.nio.channels.Channels; 26 | import java.nio.channels.ReadableByteChannel; 27 | import java.util.Properties; 28 | 29 | public class MavenWrapperDownloader { 30 | 31 | /** 32 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 33 | */ 34 | private static final String DEFAULT_DOWNLOAD_URL = 35 | "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; 36 | 37 | /** 38 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 39 | * use instead of the default one. 40 | */ 41 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 42 | ".mvn/wrapper/maven-wrapper.properties"; 43 | 44 | /** 45 | * Path where the maven-wrapper.jar will be saved to. 46 | */ 47 | private static final String MAVEN_WRAPPER_JAR_PATH = 48 | ".mvn/wrapper/maven-wrapper.jar"; 49 | 50 | /** 51 | * Name of the property which should be used to override the default download url for the wrapper. 52 | */ 53 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 54 | 55 | public static void main(String args[]) { 56 | System.out.println("- Downloader started"); 57 | File baseDirectory = new File(args[0]); 58 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 59 | 60 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 61 | // wrapperUrl parameter. 62 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 63 | String url = DEFAULT_DOWNLOAD_URL; 64 | if(mavenWrapperPropertyFile.exists()) { 65 | FileInputStream mavenWrapperPropertyFileInputStream = null; 66 | try { 67 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 68 | Properties mavenWrapperProperties = new Properties(); 69 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 70 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 71 | } catch (IOException e) { 72 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 73 | } finally { 74 | try { 75 | if(mavenWrapperPropertyFileInputStream != null) { 76 | mavenWrapperPropertyFileInputStream.close(); 77 | } 78 | } catch (IOException e) { 79 | // Ignore ... 80 | } 81 | } 82 | } 83 | System.out.println("- Downloading from: : " + url); 84 | 85 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 86 | if(!outputFile.getParentFile().exists()) { 87 | if(!outputFile.getParentFile().mkdirs()) { 88 | System.out.println( 89 | "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 90 | } 91 | } 92 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 93 | try { 94 | downloadFileFromURL(url, outputFile); 95 | System.out.println("Done"); 96 | System.exit(0); 97 | } catch (Throwable e) { 98 | System.out.println("- Error downloading"); 99 | e.printStackTrace(); 100 | System.exit(1); 101 | } 102 | } 103 | 104 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 105 | URL website = new URL(urlString); 106 | ReadableByteChannel rbc; 107 | rbc = Channels.newChannel(website.openStream()); 108 | FileOutputStream fos = new FileOutputStream(destination); 109 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 110 | fos.close(); 111 | rbc.close(); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /data/mongodb/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong-attic/bootiful-reactive-microservices-masterclass/080f7e0d79fbff17056eb20f29ad415ca30726d9/data/mongodb/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /data/mongodb/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /data/mongodb/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.springframework.boot 8 | spring-boot-starter-parent 9 | 2.2.0.M3 10 | 11 | 12 | com.example 13 | mongo 14 | 0.0.1-SNAPSHOT 15 | mongo 16 | Demo project for Spring Boot 17 | 18 | 19 | 11 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-data-mongodb-reactive 26 | 27 | 28 | 29 | org.projectlombok 30 | lombok 31 | true 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-test 36 | test 37 | 38 | 39 | org.junit.vintage 40 | junit-vintage-engine 41 | 42 | 43 | junit 44 | junit 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-maven-plugin 55 | 56 | 57 | 58 | 59 | 60 | 61 | spring-snapshots 62 | Spring Snapshots 63 | https://repo.spring.io/snapshot 64 | 65 | true 66 | 67 | 68 | 69 | spring-milestones 70 | Spring Milestones 71 | https://repo.spring.io/milestone 72 | 73 | 74 | 75 | 76 | spring-snapshots 77 | Spring Snapshots 78 | https://repo.spring.io/snapshot 79 | 80 | true 81 | 82 | 83 | 84 | spring-milestones 85 | Spring Milestones 86 | https://repo.spring.io/milestone 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /data/mongodb/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /data/mongodb/src/test/java/com/example/mongo/MongoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.mongo; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class MongoApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /data/r2dbc/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | /target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | 20 | ### NetBeans ### 21 | /nbproject/private/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ 26 | /build/ 27 | 28 | ### VS Code ### 29 | .vscode/ 30 | -------------------------------------------------------------------------------- /data/r2dbc/.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 | https://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.io.File; 21 | import java.io.FileInputStream; 22 | import java.io.FileOutputStream; 23 | import java.io.IOException; 24 | import java.net.URL; 25 | import java.nio.channels.Channels; 26 | import java.nio.channels.ReadableByteChannel; 27 | import java.util.Properties; 28 | 29 | public class MavenWrapperDownloader { 30 | 31 | /** 32 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 33 | */ 34 | private static final String DEFAULT_DOWNLOAD_URL = 35 | "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; 36 | 37 | /** 38 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 39 | * use instead of the default one. 40 | */ 41 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 42 | ".mvn/wrapper/maven-wrapper.properties"; 43 | 44 | /** 45 | * Path where the maven-wrapper.jar will be saved to. 46 | */ 47 | private static final String MAVEN_WRAPPER_JAR_PATH = 48 | ".mvn/wrapper/maven-wrapper.jar"; 49 | 50 | /** 51 | * Name of the property which should be used to override the default download url for the wrapper. 52 | */ 53 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 54 | 55 | public static void main(String args[]) { 56 | System.out.println("- Downloader started"); 57 | File baseDirectory = new File(args[0]); 58 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 59 | 60 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 61 | // wrapperUrl parameter. 62 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 63 | String url = DEFAULT_DOWNLOAD_URL; 64 | if(mavenWrapperPropertyFile.exists()) { 65 | FileInputStream mavenWrapperPropertyFileInputStream = null; 66 | try { 67 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 68 | Properties mavenWrapperProperties = new Properties(); 69 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 70 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 71 | } catch (IOException e) { 72 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 73 | } finally { 74 | try { 75 | if(mavenWrapperPropertyFileInputStream != null) { 76 | mavenWrapperPropertyFileInputStream.close(); 77 | } 78 | } catch (IOException e) { 79 | // Ignore ... 80 | } 81 | } 82 | } 83 | System.out.println("- Downloading from: : " + url); 84 | 85 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 86 | if(!outputFile.getParentFile().exists()) { 87 | if(!outputFile.getParentFile().mkdirs()) { 88 | System.out.println( 89 | "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 90 | } 91 | } 92 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 93 | try { 94 | downloadFileFromURL(url, outputFile); 95 | System.out.println("Done"); 96 | System.exit(0); 97 | } catch (Throwable e) { 98 | System.out.println("- Error downloading"); 99 | e.printStackTrace(); 100 | System.exit(1); 101 | } 102 | } 103 | 104 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 105 | URL website = new URL(urlString); 106 | ReadableByteChannel rbc; 107 | rbc = Channels.newChannel(website.openStream()); 108 | FileOutputStream fos = new FileOutputStream(destination); 109 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 110 | fos.close(); 111 | rbc.close(); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /data/r2dbc/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong-attic/bootiful-reactive-microservices-masterclass/080f7e0d79fbff17056eb20f29ad415ca30726d9/data/r2dbc/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /data/r2dbc/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /data/r2dbc/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.0.M3 9 | 10 | 11 | com.example 12 | r2dbc 13 | 0.0.1-SNAPSHOT 14 | r2dbc 15 | Demo project for Spring Boot 16 | 17 | 18 | 11 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | io.r2dbc 29 | r2dbc-pool 30 | 31 | 32 | org.springframework.boot.experimental 33 | spring-boot-starter-r2dbc 34 | 35 | 36 | org.springframework.boot.experimental 37 | spring-boot-starter-data-r2dbc 38 | 39 | 40 | io.r2dbc 41 | r2dbc-postgresql 42 | 43 | 44 | 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-webflux 49 | 50 | 51 | 52 | org.projectlombok 53 | lombok 54 | true 55 | 56 | 57 | org.springframework.boot 58 | spring-boot-starter-test 59 | test 60 | 61 | 62 | org.junit.vintage 63 | junit-vintage-engine 64 | 65 | 66 | junit 67 | junit 68 | 69 | 70 | 71 | 72 | io.projectreactor 73 | reactor-test 74 | test 75 | 76 | 77 | 78 | 79 | 80 | org.springframework.boot.experimental 81 | spring-boot-dependencies-r2dbc 82 | 0.1.0.M1 83 | pom 84 | import 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | org.springframework.boot 96 | spring-boot-maven-plugin 97 | 98 | 99 | 100 | 101 | 102 | 103 | spring-snapshots 104 | Spring Snapshots 105 | https://repo.spring.io/snapshot 106 | 107 | true 108 | 109 | 110 | 111 | spring-milestones 112 | Spring Milestones 113 | https://repo.spring.io/milestone 114 | 115 | 116 | 117 | 118 | spring-snapshots 119 | Spring Snapshots 120 | https://repo.spring.io/snapshot 121 | 122 | true 123 | 124 | 125 | 126 | spring-milestones 127 | Spring Milestones 128 | https://repo.spring.io/milestone 129 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /data/r2dbc/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.r2dbc.url=r2dbc:postgresql://orders:0rd3rz@localhost:5432/orders 2 | -------------------------------------------------------------------------------- /data/r2dbc/src/test/java/com/example/r2dbc/R2dbcApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.r2dbc; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class R2dbcApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /gateways/client/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | /target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | 20 | ### NetBeans ### 21 | /nbproject/private/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ 26 | /build/ 27 | 28 | ### VS Code ### 29 | .vscode/ 30 | -------------------------------------------------------------------------------- /gateways/client/.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 | https://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.io.File; 21 | import java.io.FileInputStream; 22 | import java.io.FileOutputStream; 23 | import java.io.IOException; 24 | import java.net.URL; 25 | import java.nio.channels.Channels; 26 | import java.nio.channels.ReadableByteChannel; 27 | import java.util.Properties; 28 | 29 | public class MavenWrapperDownloader { 30 | 31 | /** 32 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 33 | */ 34 | private static final String DEFAULT_DOWNLOAD_URL = 35 | "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; 36 | 37 | /** 38 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 39 | * use instead of the default one. 40 | */ 41 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 42 | ".mvn/wrapper/maven-wrapper.properties"; 43 | 44 | /** 45 | * Path where the maven-wrapper.jar will be saved to. 46 | */ 47 | private static final String MAVEN_WRAPPER_JAR_PATH = 48 | ".mvn/wrapper/maven-wrapper.jar"; 49 | 50 | /** 51 | * Name of the property which should be used to override the default download url for the wrapper. 52 | */ 53 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 54 | 55 | public static void main(String args[]) { 56 | System.out.println("- Downloader started"); 57 | File baseDirectory = new File(args[0]); 58 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 59 | 60 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 61 | // wrapperUrl parameter. 62 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 63 | String url = DEFAULT_DOWNLOAD_URL; 64 | if(mavenWrapperPropertyFile.exists()) { 65 | FileInputStream mavenWrapperPropertyFileInputStream = null; 66 | try { 67 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 68 | Properties mavenWrapperProperties = new Properties(); 69 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 70 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 71 | } catch (IOException e) { 72 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 73 | } finally { 74 | try { 75 | if(mavenWrapperPropertyFileInputStream != null) { 76 | mavenWrapperPropertyFileInputStream.close(); 77 | } 78 | } catch (IOException e) { 79 | // Ignore ... 80 | } 81 | } 82 | } 83 | System.out.println("- Downloading from: : " + url); 84 | 85 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 86 | if(!outputFile.getParentFile().exists()) { 87 | if(!outputFile.getParentFile().mkdirs()) { 88 | System.out.println( 89 | "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 90 | } 91 | } 92 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 93 | try { 94 | downloadFileFromURL(url, outputFile); 95 | System.out.println("Done"); 96 | System.exit(0); 97 | } catch (Throwable e) { 98 | System.out.println("- Error downloading"); 99 | e.printStackTrace(); 100 | System.exit(1); 101 | } 102 | } 103 | 104 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 105 | URL website = new URL(urlString); 106 | ReadableByteChannel rbc; 107 | rbc = Channels.newChannel(website.openStream()); 108 | FileOutputStream fos = new FileOutputStream(destination); 109 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 110 | fos.close(); 111 | rbc.close(); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /gateways/client/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong-attic/bootiful-reactive-microservices-masterclass/080f7e0d79fbff17056eb20f29ad415ca30726d9/gateways/client/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /gateways/client/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /gateways/client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.0.M3 9 | 10 | 11 | com.example 12 | client 13 | 0.0.1-SNAPSHOT 14 | client 15 | Demo project for Spring Boot 16 | 17 | 18 | 1.8 19 | Greenwich.BUILD-SNAPSHOT 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-security 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-data-redis-reactive 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-webflux 34 | 35 | 36 | org.springframework.cloud 37 | spring-cloud-starter-netflix-eureka-client 38 | 39 | 40 | org.springframework.cloud 41 | spring-cloud-starter-gateway 42 | 43 | 44 | 45 | org.projectlombok 46 | lombok 47 | true 48 | 49 | 50 | org.springframework.boot 51 | spring-boot-starter-test 52 | test 53 | 54 | 55 | io.projectreactor 56 | reactor-test 57 | test 58 | 59 | 60 | 61 | 62 | 63 | 64 | org.springframework.cloud 65 | spring-cloud-dependencies 66 | ${spring-cloud.version} 67 | pom 68 | import 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | org.springframework.boot 77 | spring-boot-maven-plugin 78 | 79 | 80 | 81 | 82 | 83 | 84 | spring-snapshots 85 | Spring Snapshots 86 | https://repo.spring.io/snapshot 87 | 88 | true 89 | 90 | 91 | 92 | spring-milestones 93 | Spring Milestones 94 | https://repo.spring.io/milestone 95 | 96 | 97 | 98 | 99 | spring-snapshots 100 | Spring Snapshots 101 | https://repo.spring.io/snapshot 102 | 103 | true 104 | 105 | 106 | 107 | spring-milestones 108 | Spring Milestones 109 | https://repo.spring.io/milestone 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /gateways/client/src/main/java/com/example/client/ClientApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.client; 2 | 3 | import lombok.extern.log4j.Log4j2; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.cloud.client.discovery.DiscoveryClient; 7 | import org.springframework.cloud.gateway.filter.ratelimit.PrincipalNameKeyResolver; 8 | import org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter; 9 | import org.springframework.cloud.gateway.route.RouteLocator; 10 | import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; 11 | import org.springframework.context.annotation.Bean; 12 | import org.springframework.security.config.web.server.ServerHttpSecurity; 13 | import org.springframework.security.core.userdetails.MapReactiveUserDetailsService; 14 | import org.springframework.security.core.userdetails.User; 15 | import org.springframework.security.web.server.SecurityWebFilterChain; 16 | import org.springframework.web.reactive.function.server.RouterFunction; 17 | import org.springframework.web.reactive.function.server.ServerResponse; 18 | 19 | import static org.springframework.web.reactive.function.server.RouterFunctions.route; 20 | 21 | @Log4j2 22 | @SpringBootApplication 23 | public class ClientApplication { 24 | 25 | public static void main(String[] args) { 26 | SpringApplication.run(ClientApplication.class, args); 27 | } 28 | 29 | @Bean 30 | RouterFunction routes(DiscoveryClient dc) { 31 | return route() 32 | .GET("/instances", s -> ServerResponse.ok().syncBody(dc.getInstances("greetings-service"))) 33 | .build(); 34 | } 35 | 36 | @Bean 37 | RedisRateLimiter redisRateLimiter() { 38 | return new RedisRateLimiter(5, 7); 39 | } 40 | 41 | @Bean 42 | MapReactiveUserDetailsService authentication() { 43 | return new MapReactiveUserDetailsService(User 44 | .withDefaultPasswordEncoder().username("jlong").password("pw").roles("USER").build()); 45 | } 46 | 47 | 48 | @Bean 49 | SecurityWebFilterChain authorization(ServerHttpSecurity httpSecurity) { 50 | httpSecurity.httpBasic(); 51 | httpSecurity.csrf().disable(); 52 | httpSecurity 53 | .authorizeExchange() 54 | .pathMatchers("/hi").authenticated() 55 | .anyExchange().permitAll(); 56 | return httpSecurity.build(); 57 | } 58 | 59 | @Bean 60 | RouteLocator gateway(RouteLocatorBuilder rlb) { 61 | return rlb 62 | .routes() 63 | .route(rs -> rs 64 | .path("/hi/*") 65 | .filters(fs -> fs 66 | .rewritePath("/hi/(?.*)", "/greetings/${name}") 67 | .requestRateLimiter(rlc -> rlc 68 | .setRateLimiter(redisRateLimiter()) 69 | .setKeyResolver(new PrincipalNameKeyResolver()) // default 70 | ) 71 | ) 72 | .uri("lb://greetings-service") 73 | ) 74 | .build(); 75 | } 76 | } 77 | 78 | -------------------------------------------------------------------------------- /gateways/client/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=greetings-client 2 | server.port=9090 3 | 4 | 5 | -------------------------------------------------------------------------------- /gateways/client/src/test/java/com/example/client/ClientApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.client; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class ClientApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /gateways/eureka-service/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | /target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | 20 | ### NetBeans ### 21 | /nbproject/private/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ 26 | /build/ 27 | 28 | ### VS Code ### 29 | .vscode/ 30 | -------------------------------------------------------------------------------- /gateways/eureka-service/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong-attic/bootiful-reactive-microservices-masterclass/080f7e0d79fbff17056eb20f29ad415ca30726d9/gateways/eureka-service/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /gateways/eureka-service/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /gateways/eureka-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.springframework.boot 8 | spring-boot-starter-parent 9 | 2.1.0.RELEASE 10 | 11 | 12 | com.example 13 | eureka-service 14 | 0.0.1-SNAPSHOT 15 | eureka-service 16 | Demo project for Spring Boot 17 | 18 | 19 | 1.8 20 | Greenwich.BUILD-SNAPSHOT 21 | 22 | 23 | 24 | 25 | 26 | javax.xml.bind 27 | jaxb-api 28 | 2.3.0 29 | 30 | 31 | com.sun.xml.bind 32 | jaxb-impl 33 | 2.3.0 34 | 35 | 36 | org.glassfish.jaxb 37 | jaxb-runtime 38 | 2.3.0 39 | 40 | 41 | javax.activation 42 | activation 43 | 1.1.1 44 | 45 | 46 | 47 | 48 | org.springframework.boot 49 | spring-boot-starter-web 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-starter-actuator 54 | 55 | 56 | org.springframework.cloud 57 | spring-cloud-starter-netflix-eureka-server 58 | 59 | 60 | 61 | org.projectlombok 62 | lombok 63 | true 64 | 65 | 66 | org.springframework.boot 67 | spring-boot-starter-test 68 | test 69 | 70 | 71 | 72 | 73 | 74 | 75 | org.springframework.cloud 76 | spring-cloud-dependencies 77 | ${spring-cloud.version} 78 | pom 79 | import 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | org.springframework.boot 88 | spring-boot-maven-plugin 89 | 90 | 91 | 92 | 93 | 94 | 95 | spring-snapshots 96 | Spring Snapshots 97 | https://repo.spring.io/snapshot 98 | 99 | true 100 | 101 | 102 | 103 | spring-milestones 104 | Spring Milestones 105 | https://repo.spring.io/milestone 106 | 107 | 108 | 109 | 110 | spring-snapshots 111 | Spring Snapshots 112 | https://repo.spring.io/snapshot 113 | 114 | true 115 | 116 | 117 | 118 | spring-milestones 119 | Spring Milestones 120 | https://repo.spring.io/milestone 121 | 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /gateways/eureka-service/src/main/java/com/example/eurekaservice/EurekaServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.eurekaservice; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; 6 | 7 | @EnableEurekaServer 8 | @SpringBootApplication 9 | public class EurekaServiceApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(EurekaServiceApplication.class, args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /gateways/eureka-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=eureka-service 2 | server.port=8761 3 | eureka.client.register-with-eureka=false 4 | eureka.client.fetch-registry=false -------------------------------------------------------------------------------- /gateways/eureka-service/src/test/java/com/example/eurekaservice/EurekaServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.eurekaservice; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class EurekaServiceApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /gateways/service/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | /target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | 20 | ### NetBeans ### 21 | /nbproject/private/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ 26 | /build/ 27 | 28 | ### VS Code ### 29 | .vscode/ 30 | -------------------------------------------------------------------------------- /gateways/service/.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 | https://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.io.File; 21 | import java.io.FileInputStream; 22 | import java.io.FileOutputStream; 23 | import java.io.IOException; 24 | import java.net.URL; 25 | import java.nio.channels.Channels; 26 | import java.nio.channels.ReadableByteChannel; 27 | import java.util.Properties; 28 | 29 | public class MavenWrapperDownloader { 30 | 31 | /** 32 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 33 | */ 34 | private static final String DEFAULT_DOWNLOAD_URL = 35 | "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; 36 | 37 | /** 38 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 39 | * use instead of the default one. 40 | */ 41 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 42 | ".mvn/wrapper/maven-wrapper.properties"; 43 | 44 | /** 45 | * Path where the maven-wrapper.jar will be saved to. 46 | */ 47 | private static final String MAVEN_WRAPPER_JAR_PATH = 48 | ".mvn/wrapper/maven-wrapper.jar"; 49 | 50 | /** 51 | * Name of the property which should be used to override the default download url for the wrapper. 52 | */ 53 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 54 | 55 | public static void main(String args[]) { 56 | System.out.println("- Downloader started"); 57 | File baseDirectory = new File(args[0]); 58 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 59 | 60 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 61 | // wrapperUrl parameter. 62 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 63 | String url = DEFAULT_DOWNLOAD_URL; 64 | if(mavenWrapperPropertyFile.exists()) { 65 | FileInputStream mavenWrapperPropertyFileInputStream = null; 66 | try { 67 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 68 | Properties mavenWrapperProperties = new Properties(); 69 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 70 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 71 | } catch (IOException e) { 72 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 73 | } finally { 74 | try { 75 | if(mavenWrapperPropertyFileInputStream != null) { 76 | mavenWrapperPropertyFileInputStream.close(); 77 | } 78 | } catch (IOException e) { 79 | // Ignore ... 80 | } 81 | } 82 | } 83 | System.out.println("- Downloading from: : " + url); 84 | 85 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 86 | if(!outputFile.getParentFile().exists()) { 87 | if(!outputFile.getParentFile().mkdirs()) { 88 | System.out.println( 89 | "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 90 | } 91 | } 92 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 93 | try { 94 | downloadFileFromURL(url, outputFile); 95 | System.out.println("Done"); 96 | System.exit(0); 97 | } catch (Throwable e) { 98 | System.out.println("- Error downloading"); 99 | e.printStackTrace(); 100 | System.exit(1); 101 | } 102 | } 103 | 104 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 105 | URL website = new URL(urlString); 106 | ReadableByteChannel rbc; 107 | rbc = Channels.newChannel(website.openStream()); 108 | FileOutputStream fos = new FileOutputStream(destination); 109 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 110 | fos.close(); 111 | rbc.close(); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /gateways/service/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong-attic/bootiful-reactive-microservices-masterclass/080f7e0d79fbff17056eb20f29ad415ca30726d9/gateways/service/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /gateways/service/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /gateways/service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.springframework.boot 8 | spring-boot-starter-parent 9 | 2.2.0.M3 10 | 11 | 12 | com.example 13 | service 14 | 0.0.1-SNAPSHOT 15 | service 16 | Demo project for Spring Boot 17 | 18 | 19 | 1.8 20 | Greenwich.BUILD-SNAPSHOT 21 | 22 | 23 | 24 | 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-webflux 29 | 30 | 31 | org.springframework.cloud 32 | spring-cloud-starter-netflix-eureka-client 33 | 34 | 35 | 36 | 37 | org.projectlombok 38 | lombok 39 | true 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-starter-test 44 | test 45 | 46 | 47 | io.projectreactor 48 | reactor-test 49 | test 50 | 51 | 52 | 53 | 54 | 55 | 56 | org.springframework.cloud 57 | spring-cloud-dependencies 58 | ${spring-cloud.version} 59 | pom 60 | import 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | org.springframework.boot 69 | spring-boot-maven-plugin 70 | 71 | 72 | 73 | 74 | 75 | 76 | spring-snapshots 77 | Spring Snapshots 78 | https://repo.spring.io/snapshot 79 | 80 | true 81 | 82 | 83 | 84 | spring-milestones 85 | Spring Milestones 86 | https://repo.spring.io/milestone 87 | 88 | 89 | 90 | 91 | spring-snapshots 92 | Spring Snapshots 93 | https://repo.spring.io/snapshot 94 | 95 | true 96 | 97 | 98 | 99 | spring-milestones 100 | Spring Milestones 101 | https://repo.spring.io/milestone 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /gateways/service/src/main/java/com/example/service/ServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.service; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.web.reactive.function.server.RouterFunction; 10 | import org.springframework.web.reactive.function.server.ServerResponse; 11 | 12 | import static org.springframework.web.reactive.function.server.RouterFunctions.route; 13 | import static org.springframework.web.reactive.function.server.ServerResponse.ok; 14 | 15 | @SpringBootApplication 16 | public class ServiceApplication { 17 | 18 | @Bean 19 | RouterFunction routes() { 20 | return route() 21 | .GET("/greetings/{n}", r -> ok().syncBody(new GreetingResponse("Hello " + r.pathVariable("n") + "!"))) 22 | .build(); 23 | } 24 | 25 | public static void main(String[] args) { 26 | SpringApplication.run(ServiceApplication.class, args); 27 | } 28 | 29 | } 30 | 31 | 32 | @Data 33 | @AllArgsConstructor 34 | @NoArgsConstructor 35 | class GreetingResponse { 36 | private String message; 37 | } -------------------------------------------------------------------------------- /gateways/service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=greetings-service 2 | -------------------------------------------------------------------------------- /gateways/service/src/test/java/com/example/service/ServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.service; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class ServiceApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /kafka/kafka-consumer/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | /target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | 20 | ### NetBeans ### 21 | /nbproject/private/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ 26 | /build/ 27 | 28 | ### VS Code ### 29 | .vscode/ 30 | -------------------------------------------------------------------------------- /kafka/kafka-consumer/.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 | https://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.io.File; 21 | import java.io.FileInputStream; 22 | import java.io.FileOutputStream; 23 | import java.io.IOException; 24 | import java.net.URL; 25 | import java.nio.channels.Channels; 26 | import java.nio.channels.ReadableByteChannel; 27 | import java.util.Properties; 28 | 29 | public class MavenWrapperDownloader { 30 | 31 | /** 32 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 33 | */ 34 | private static final String DEFAULT_DOWNLOAD_URL = 35 | "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; 36 | 37 | /** 38 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 39 | * use instead of the default one. 40 | */ 41 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 42 | ".mvn/wrapper/maven-wrapper.properties"; 43 | 44 | /** 45 | * Path where the maven-wrapper.jar will be saved to. 46 | */ 47 | private static final String MAVEN_WRAPPER_JAR_PATH = 48 | ".mvn/wrapper/maven-wrapper.jar"; 49 | 50 | /** 51 | * Name of the property which should be used to override the default download url for the wrapper. 52 | */ 53 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 54 | 55 | public static void main(String args[]) { 56 | System.out.println("- Downloader started"); 57 | File baseDirectory = new File(args[0]); 58 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 59 | 60 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 61 | // wrapperUrl parameter. 62 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 63 | String url = DEFAULT_DOWNLOAD_URL; 64 | if(mavenWrapperPropertyFile.exists()) { 65 | FileInputStream mavenWrapperPropertyFileInputStream = null; 66 | try { 67 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 68 | Properties mavenWrapperProperties = new Properties(); 69 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 70 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 71 | } catch (IOException e) { 72 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 73 | } finally { 74 | try { 75 | if(mavenWrapperPropertyFileInputStream != null) { 76 | mavenWrapperPropertyFileInputStream.close(); 77 | } 78 | } catch (IOException e) { 79 | // Ignore ... 80 | } 81 | } 82 | } 83 | System.out.println("- Downloading from: : " + url); 84 | 85 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 86 | if(!outputFile.getParentFile().exists()) { 87 | if(!outputFile.getParentFile().mkdirs()) { 88 | System.out.println( 89 | "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 90 | } 91 | } 92 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 93 | try { 94 | downloadFileFromURL(url, outputFile); 95 | System.out.println("Done"); 96 | System.exit(0); 97 | } catch (Throwable e) { 98 | System.out.println("- Error downloading"); 99 | e.printStackTrace(); 100 | System.exit(1); 101 | } 102 | } 103 | 104 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 105 | URL website = new URL(urlString); 106 | ReadableByteChannel rbc; 107 | rbc = Channels.newChannel(website.openStream()); 108 | FileOutputStream fos = new FileOutputStream(destination); 109 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 110 | fos.close(); 111 | rbc.close(); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /kafka/kafka-consumer/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong-attic/bootiful-reactive-microservices-masterclass/080f7e0d79fbff17056eb20f29ad415ca30726d9/kafka/kafka-consumer/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /kafka/kafka-consumer/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /kafka/kafka-consumer/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.0.M3 9 | 10 | 11 | com.example 12 | kafka-consumer 13 | 0.0.1-SNAPSHOT 14 | kafka-consumer 15 | Demo project for Spring Boot 16 | 17 | 18 | 11 19 | Hoxton.BUILD-SNAPSHOT 20 | 21 | 22 | 23 | 24 | org.projectlombok 25 | lombok 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-webflux 30 | 31 | 32 | org.springframework.cloud 33 | spring-cloud-stream 34 | 35 | 36 | org.springframework.cloud 37 | spring-cloud-stream-binder-kafka 38 | 39 | 40 | org.springframework.cloud 41 | spring-cloud-stream-reactive 42 | 43 | 44 | org.springframework.kafka 45 | spring-kafka 46 | 47 | 48 | 49 | org.springframework.boot 50 | spring-boot-starter-test 51 | test 52 | 53 | 54 | org.junit.vintage 55 | junit-vintage-engine 56 | 57 | 58 | junit 59 | junit 60 | 61 | 62 | 63 | 64 | io.projectreactor 65 | reactor-test 66 | test 67 | 68 | 69 | org.springframework.cloud 70 | spring-cloud-stream-test-support 71 | test 72 | 73 | 74 | org.springframework.kafka 75 | spring-kafka-test 76 | test 77 | 78 | 79 | 80 | 81 | 82 | 83 | org.springframework.cloud 84 | spring-cloud-dependencies 85 | ${spring-cloud.version} 86 | pom 87 | import 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | org.springframework.boot 96 | spring-boot-maven-plugin 97 | 98 | 99 | 100 | 101 | 102 | 103 | spring-snapshots 104 | Spring Snapshots 105 | https://repo.spring.io/snapshot 106 | 107 | true 108 | 109 | 110 | 111 | spring-milestones 112 | Spring Milestones 113 | https://repo.spring.io/milestone 114 | 115 | 116 | 117 | 118 | spring-snapshots 119 | Spring Snapshots 120 | https://repo.spring.io/snapshot 121 | 122 | true 123 | 124 | 125 | 126 | spring-milestones 127 | Spring Milestones 128 | https://repo.spring.io/milestone 129 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /kafka/kafka-consumer/src/main/java/com/example/kafkaconsumer/KafkaConsumerApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.kafkaconsumer; 2 | 3 | import lombok.extern.log4j.Log4j2; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.cloud.stream.annotation.EnableBinding; 7 | import org.springframework.cloud.stream.annotation.Input; 8 | import org.springframework.cloud.stream.annotation.StreamListener; 9 | import org.springframework.cloud.stream.messaging.Sink; 10 | import reactor.core.publisher.Flux; 11 | 12 | import java.util.Map; 13 | 14 | @Log4j2 15 | @EnableBinding(Sink.class) 16 | @SpringBootApplication 17 | public class KafkaConsumerApplication { 18 | 19 | 20 | 21 | @StreamListener 22 | public void processNewMessages(@Input(Sink.INPUT) Flux> greetings) { 23 | greetings.subscribe(greeting -> log.info("new message: " + greeting)); 24 | } 25 | 26 | public static void main(String[] args) { 27 | SpringApplication.run(KafkaConsumerApplication.class, args); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /kafka/kafka-consumer/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.cloud.stream.bindings.input.destination=greetings 2 | server.port=9090 3 | -------------------------------------------------------------------------------- /kafka/kafka-consumer/src/test/java/com/example/kafkaconsumer/KafkaConsumerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.kafkaconsumer; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class KafkaConsumerApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /kafka/kafka-producer/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | /target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | 20 | ### NetBeans ### 21 | /nbproject/private/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ 26 | /build/ 27 | 28 | ### VS Code ### 29 | .vscode/ 30 | -------------------------------------------------------------------------------- /kafka/kafka-producer/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong-attic/bootiful-reactive-microservices-masterclass/080f7e0d79fbff17056eb20f29ad415ca30726d9/kafka/kafka-producer/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /kafka/kafka-producer/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /kafka/kafka-producer/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.0.M3 9 | 10 | 11 | com.example 12 | kafka-producer 13 | 0.0.1-SNAPSHOT 14 | kafka-producer 15 | Demo project for Spring Boot 16 | 17 | 18 | 11 19 | Hoxton.BUILD-SNAPSHOT 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-webflux 26 | 27 | 28 | org.springframework.cloud 29 | spring-cloud-stream 30 | 31 | 32 | org.springframework.cloud 33 | spring-cloud-stream-binder-kafka 34 | 35 | 36 | org.springframework.cloud 37 | spring-cloud-stream-reactive 38 | 39 | 40 | org.springframework.kafka 41 | spring-kafka 42 | 43 | 44 | 45 | org.springframework.boot 46 | spring-boot-starter-test 47 | test 48 | 49 | 50 | org.junit.vintage 51 | junit-vintage-engine 52 | 53 | 54 | junit 55 | junit 56 | 57 | 58 | 59 | 60 | io.projectreactor 61 | reactor-test 62 | test 63 | 64 | 65 | org.springframework.cloud 66 | spring-cloud-stream-test-support 67 | test 68 | 69 | 70 | org.springframework.kafka 71 | spring-kafka-test 72 | test 73 | 74 | 75 | 76 | 77 | 78 | 79 | org.springframework.cloud 80 | spring-cloud-dependencies 81 | ${spring-cloud.version} 82 | pom 83 | import 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | org.springframework.boot 92 | spring-boot-maven-plugin 93 | 94 | 95 | 96 | 97 | 98 | 99 | spring-snapshots 100 | Spring Snapshots 101 | https://repo.spring.io/snapshot 102 | 103 | true 104 | 105 | 106 | 107 | spring-milestones 108 | Spring Milestones 109 | https://repo.spring.io/milestone 110 | 111 | 112 | 113 | 114 | spring-snapshots 115 | Spring Snapshots 116 | https://repo.spring.io/snapshot 117 | 118 | true 119 | 120 | 121 | 122 | spring-milestones 123 | Spring Milestones 124 | https://repo.spring.io/milestone 125 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /kafka/kafka-producer/src/main/java/com/example/kafkaproducer/KafkaProducerApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.kafkaproducer; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.stream.annotation.EnableBinding; 6 | import org.springframework.cloud.stream.messaging.Source; 7 | import org.springframework.messaging.Message; 8 | import org.springframework.messaging.MessageChannel; 9 | import org.springframework.messaging.support.MessageBuilder; 10 | import org.springframework.web.bind.annotation.PathVariable; 11 | import org.springframework.web.bind.annotation.PostMapping; 12 | import org.springframework.web.bind.annotation.RestController; 13 | import reactor.core.publisher.Mono; 14 | 15 | import java.util.Collections; 16 | import java.util.Map; 17 | 18 | @SpringBootApplication 19 | @EnableBinding(Source.class) 20 | public class KafkaProducerApplication { 21 | 22 | public static void main(String[] args) { 23 | SpringApplication.run(KafkaProducerApplication.class, args); 24 | } 25 | } 26 | 27 | @RestController 28 | class ProducerRestController { 29 | 30 | private final MessageChannel channel; 31 | 32 | ProducerRestController(Source producerBinding) { 33 | this.channel = producerBinding.output(); 34 | } 35 | 36 | @PostMapping("/publish/{name}") 37 | Mono publish(@PathVariable String name) { 38 | var greetingMsg = MessageBuilder.withPayload(Collections.singletonMap("greeting", "Hello " + name + "!")).build(); 39 | boolean send = this.channel.send(greetingMsg); 40 | return Mono.just(send); 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /kafka/kafka-producer/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.cloud.stream.bindings.output.destination=greetings 2 | 3 | -------------------------------------------------------------------------------- /kafka/kafka-producer/src/test/java/com/example/kafkaproducer/KafkaProducerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.kafkaproducer; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class KafkaProducerApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /reactive-adapter/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | /target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | 20 | ### NetBeans ### 21 | /nbproject/private/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ 26 | /build/ 27 | 28 | ### VS Code ### 29 | .vscode/ 30 | -------------------------------------------------------------------------------- /reactive-adapter/.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 | https://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.io.File; 21 | import java.io.FileInputStream; 22 | import java.io.FileOutputStream; 23 | import java.io.IOException; 24 | import java.net.URL; 25 | import java.nio.channels.Channels; 26 | import java.nio.channels.ReadableByteChannel; 27 | import java.util.Properties; 28 | 29 | public class MavenWrapperDownloader { 30 | 31 | /** 32 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 33 | */ 34 | private static final String DEFAULT_DOWNLOAD_URL = 35 | "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; 36 | 37 | /** 38 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 39 | * use instead of the default one. 40 | */ 41 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 42 | ".mvn/wrapper/maven-wrapper.properties"; 43 | 44 | /** 45 | * Path where the maven-wrapper.jar will be saved to. 46 | */ 47 | private static final String MAVEN_WRAPPER_JAR_PATH = 48 | ".mvn/wrapper/maven-wrapper.jar"; 49 | 50 | /** 51 | * Name of the property which should be used to override the default download url for the wrapper. 52 | */ 53 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 54 | 55 | public static void main(String args[]) { 56 | System.out.println("- Downloader started"); 57 | File baseDirectory = new File(args[0]); 58 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 59 | 60 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 61 | // wrapperUrl parameter. 62 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 63 | String url = DEFAULT_DOWNLOAD_URL; 64 | if(mavenWrapperPropertyFile.exists()) { 65 | FileInputStream mavenWrapperPropertyFileInputStream = null; 66 | try { 67 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 68 | Properties mavenWrapperProperties = new Properties(); 69 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 70 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 71 | } catch (IOException e) { 72 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 73 | } finally { 74 | try { 75 | if(mavenWrapperPropertyFileInputStream != null) { 76 | mavenWrapperPropertyFileInputStream.close(); 77 | } 78 | } catch (IOException e) { 79 | // Ignore ... 80 | } 81 | } 82 | } 83 | System.out.println("- Downloading from: : " + url); 84 | 85 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 86 | if(!outputFile.getParentFile().exists()) { 87 | if(!outputFile.getParentFile().mkdirs()) { 88 | System.out.println( 89 | "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 90 | } 91 | } 92 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 93 | try { 94 | downloadFileFromURL(url, outputFile); 95 | System.out.println("Done"); 96 | System.exit(0); 97 | } catch (Throwable e) { 98 | System.out.println("- Error downloading"); 99 | e.printStackTrace(); 100 | System.exit(1); 101 | } 102 | } 103 | 104 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 105 | URL website = new URL(urlString); 106 | ReadableByteChannel rbc; 107 | rbc = Channels.newChannel(website.openStream()); 108 | FileOutputStream fos = new FileOutputStream(destination); 109 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 110 | fos.close(); 111 | rbc.close(); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /reactive-adapter/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong-attic/bootiful-reactive-microservices-masterclass/080f7e0d79fbff17056eb20f29ad415ca30726d9/reactive-adapter/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /reactive-adapter/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /reactive-adapter/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.0.M3 9 | 10 | 11 | com.example 12 | reactive-adapter 13 | 0.0.1-SNAPSHOT 14 | reactive-adapter 15 | Demo project for Spring Boot 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.projectlombok 24 | lombok 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-webflux 29 | 30 | 31 | 32 | org.projectlombok 33 | lombok 34 | true 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-test 39 | test 40 | 41 | 42 | 43 | 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-maven-plugin 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | spring-snapshots 56 | Spring Snapshots 57 | https://repo.spring.io/snapshot 58 | 59 | true 60 | 61 | 62 | 63 | spring-milestones 64 | Spring Milestones 65 | https://repo.spring.io/milestone 66 | 67 | 68 | 69 | 70 | spring-snapshots 71 | Spring Snapshots 72 | https://repo.spring.io/snapshot 73 | 74 | true 75 | 76 | 77 | 78 | spring-milestones 79 | Spring Milestones 80 | https://repo.spring.io/milestone 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /reactive-adapter/src/main/java/com/example/reactiveadapter/ReactiveAdapterApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.reactiveadapter; 2 | 3 | import lombok.RequiredArgsConstructor; 4 | import lombok.extern.log4j.Log4j2; 5 | import org.reactivestreams.Publisher; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.context.ApplicationEvent; 9 | import org.springframework.context.ApplicationEventPublisher; 10 | import org.springframework.context.ApplicationListener; 11 | import org.springframework.http.MediaType; 12 | import org.springframework.stereotype.Component; 13 | import org.springframework.util.ReflectionUtils; 14 | import org.springframework.web.bind.annotation.GetMapping; 15 | import org.springframework.web.bind.annotation.PathVariable; 16 | import org.springframework.web.bind.annotation.PostMapping; 17 | import org.springframework.web.bind.annotation.RestController; 18 | import reactor.core.publisher.Flux; 19 | import reactor.core.publisher.FluxSink; 20 | import reactor.core.publisher.Mono; 21 | 22 | import java.time.Instant; 23 | import java.util.concurrent.LinkedBlockingQueue; 24 | import java.util.function.Consumer; 25 | 26 | @RestController 27 | @SpringBootApplication 28 | @Log4j2 29 | @RequiredArgsConstructor 30 | public class ReactiveAdapterApplication { 31 | 32 | public static void main(String[] args) { 33 | SpringApplication.run(ReactiveAdapterApplication.class, args); 34 | } 35 | 36 | private final ApplicationEventPublisher publisher; 37 | private final Bridger bridger; 38 | 39 | @PostMapping("/greet/{name}") 40 | Mono postGreeting(@PathVariable String name) { 41 | this.publisher.publishEvent(new GreetingsEvent("hello " + name + " @ " + Instant.now())); 42 | return Mono.empty(); 43 | } 44 | 45 | @GetMapping(produces = MediaType.TEXT_EVENT_STREAM_VALUE, value = "/sse/greetings") 46 | Publisher events() { 47 | return Flux.create(this.bridger); 48 | } 49 | 50 | 51 | } 52 | 53 | @Component 54 | class Bridger implements ApplicationListener, Consumer> { 55 | 56 | 57 | private final LinkedBlockingQueue queue = new LinkedBlockingQueue<>(); 58 | 59 | @Override 60 | public void onApplicationEvent(GreetingsEvent greetingsEvent) { 61 | this.queue.offer(greetingsEvent); 62 | } 63 | 64 | @Override 65 | public void accept(FluxSink sink) { 66 | 67 | try { 68 | GreetingsEvent event; 69 | while ((event = this.queue.take()) != null) { 70 | sink.next(event); 71 | } 72 | } 73 | catch (InterruptedException e) { 74 | ReflectionUtils.rethrowRuntimeException(e); 75 | } 76 | } 77 | 78 | } 79 | 80 | 81 | class GreetingsEvent extends ApplicationEvent { 82 | 83 | public GreetingsEvent(String greeting) { 84 | super(greeting); 85 | } 86 | } -------------------------------------------------------------------------------- /reactive-adapter/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /reactive-adapter/src/test/java/com/example/reactiveadapter/ReactiveAdapterApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.reactiveadapter; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class ReactiveAdapterApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /reactor/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | /target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | 20 | ### NetBeans ### 21 | /nbproject/private/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ 26 | /build/ 27 | 28 | ### VS Code ### 29 | .vscode/ 30 | -------------------------------------------------------------------------------- /reactor/.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 | https://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.io.File; 21 | import java.io.FileInputStream; 22 | import java.io.FileOutputStream; 23 | import java.io.IOException; 24 | import java.net.URL; 25 | import java.nio.channels.Channels; 26 | import java.nio.channels.ReadableByteChannel; 27 | import java.util.Properties; 28 | 29 | public class MavenWrapperDownloader { 30 | 31 | /** 32 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 33 | */ 34 | private static final String DEFAULT_DOWNLOAD_URL = 35 | "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; 36 | 37 | /** 38 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 39 | * use instead of the default one. 40 | */ 41 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 42 | ".mvn/wrapper/maven-wrapper.properties"; 43 | 44 | /** 45 | * Path where the maven-wrapper.jar will be saved to. 46 | */ 47 | private static final String MAVEN_WRAPPER_JAR_PATH = 48 | ".mvn/wrapper/maven-wrapper.jar"; 49 | 50 | /** 51 | * Name of the property which should be used to override the default download url for the wrapper. 52 | */ 53 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 54 | 55 | public static void main(String args[]) { 56 | System.out.println("- Downloader started"); 57 | File baseDirectory = new File(args[0]); 58 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 59 | 60 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 61 | // wrapperUrl parameter. 62 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 63 | String url = DEFAULT_DOWNLOAD_URL; 64 | if(mavenWrapperPropertyFile.exists()) { 65 | FileInputStream mavenWrapperPropertyFileInputStream = null; 66 | try { 67 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 68 | Properties mavenWrapperProperties = new Properties(); 69 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 70 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 71 | } catch (IOException e) { 72 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 73 | } finally { 74 | try { 75 | if(mavenWrapperPropertyFileInputStream != null) { 76 | mavenWrapperPropertyFileInputStream.close(); 77 | } 78 | } catch (IOException e) { 79 | // Ignore ... 80 | } 81 | } 82 | } 83 | System.out.println("- Downloading from: : " + url); 84 | 85 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 86 | if(!outputFile.getParentFile().exists()) { 87 | if(!outputFile.getParentFile().mkdirs()) { 88 | System.out.println( 89 | "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 90 | } 91 | } 92 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 93 | try { 94 | downloadFileFromURL(url, outputFile); 95 | System.out.println("Done"); 96 | System.exit(0); 97 | } catch (Throwable e) { 98 | System.out.println("- Error downloading"); 99 | e.printStackTrace(); 100 | System.exit(1); 101 | } 102 | } 103 | 104 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 105 | URL website = new URL(urlString); 106 | ReadableByteChannel rbc; 107 | rbc = Channels.newChannel(website.openStream()); 108 | FileOutputStream fos = new FileOutputStream(destination); 109 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 110 | fos.close(); 111 | rbc.close(); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /reactor/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong-attic/bootiful-reactive-microservices-masterclass/080f7e0d79fbff17056eb20f29ad415ca30726d9/reactor/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /reactor/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /reactor/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.0.M3 9 | 10 | 11 | com.example 12 | reactor 13 | 0.0.1-SNAPSHOT 14 | 15 | 16 | 17 | 11 18 | 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-webflux 24 | 25 | 26 | 27 | io.projectreactor.tools 28 | blockhound 29 | 1.0.0.M3 30 | 31 | 32 | 33 | io.projectreactor 34 | reactor-tools 35 | 1.0.0.M1 36 | 37 | 38 | 39 | org.projectlombok 40 | lombok 41 | true 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-starter-test 46 | test 47 | 48 | 49 | org.junit.vintage 50 | junit-vintage-engine 51 | 52 | 53 | junit 54 | junit 55 | 56 | 57 | 58 | 59 | io.projectreactor 60 | reactor-test 61 | test 62 | 63 | 64 | 65 | 66 | 67 | 68 | org.springframework.boot 69 | spring-boot-maven-plugin 70 | 71 | 72 | 73 | 74 | 75 | 76 | spring-snapshots 77 | Spring Snapshots 78 | https://repo.spring.io/snapshot 79 | 80 | true 81 | 82 | 83 | 84 | spring-milestones 85 | Spring Milestones 86 | https://repo.spring.io/milestone 87 | 88 | 89 | 90 | 91 | spring-snapshots 92 | Spring Snapshots 93 | https://repo.spring.io/snapshot 94 | 95 | true 96 | 97 | 98 | 99 | spring-milestones 100 | Spring Milestones 101 | https://repo.spring.io/milestone 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /reactor/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /reactor/src/test/java/com/example/demo/DemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class DemoApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /reliability/api/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | /target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | 20 | ### NetBeans ### 21 | /nbproject/private/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ 26 | /build/ 27 | 28 | ### VS Code ### 29 | .vscode/ 30 | -------------------------------------------------------------------------------- /reliability/api/.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 | https://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.io.File; 21 | import java.io.FileInputStream; 22 | import java.io.FileOutputStream; 23 | import java.io.IOException; 24 | import java.net.URL; 25 | import java.nio.channels.Channels; 26 | import java.nio.channels.ReadableByteChannel; 27 | import java.util.Properties; 28 | 29 | public class MavenWrapperDownloader { 30 | 31 | /** 32 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 33 | */ 34 | private static final String DEFAULT_DOWNLOAD_URL = 35 | "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; 36 | 37 | /** 38 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 39 | * use instead of the default one. 40 | */ 41 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 42 | ".mvn/wrapper/maven-wrapper.properties"; 43 | 44 | /** 45 | * Path where the maven-wrapper.jar will be saved to. 46 | */ 47 | private static final String MAVEN_WRAPPER_JAR_PATH = 48 | ".mvn/wrapper/maven-wrapper.jar"; 49 | 50 | /** 51 | * Name of the property which should be used to override the default download url for the wrapper. 52 | */ 53 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 54 | 55 | public static void main(String args[]) { 56 | System.out.println("- Downloader started"); 57 | File baseDirectory = new File(args[0]); 58 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 59 | 60 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 61 | // wrapperUrl parameter. 62 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 63 | String url = DEFAULT_DOWNLOAD_URL; 64 | if(mavenWrapperPropertyFile.exists()) { 65 | FileInputStream mavenWrapperPropertyFileInputStream = null; 66 | try { 67 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 68 | Properties mavenWrapperProperties = new Properties(); 69 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 70 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 71 | } catch (IOException e) { 72 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 73 | } finally { 74 | try { 75 | if(mavenWrapperPropertyFileInputStream != null) { 76 | mavenWrapperPropertyFileInputStream.close(); 77 | } 78 | } catch (IOException e) { 79 | // Ignore ... 80 | } 81 | } 82 | } 83 | System.out.println("- Downloading from: : " + url); 84 | 85 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 86 | if(!outputFile.getParentFile().exists()) { 87 | if(!outputFile.getParentFile().mkdirs()) { 88 | System.out.println( 89 | "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 90 | } 91 | } 92 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 93 | try { 94 | downloadFileFromURL(url, outputFile); 95 | System.out.println("Done"); 96 | System.exit(0); 97 | } catch (Throwable e) { 98 | System.out.println("- Error downloading"); 99 | e.printStackTrace(); 100 | System.exit(1); 101 | } 102 | } 103 | 104 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 105 | URL website = new URL(urlString); 106 | ReadableByteChannel rbc; 107 | rbc = Channels.newChannel(website.openStream()); 108 | FileOutputStream fos = new FileOutputStream(destination); 109 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 110 | fos.close(); 111 | rbc.close(); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /reliability/api/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong-attic/bootiful-reactive-microservices-masterclass/080f7e0d79fbff17056eb20f29ad415ca30726d9/reliability/api/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /reliability/api/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /reliability/api/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.1.5.RELEASE 9 | 10 | 11 | com.example 12 | api 13 | 0.0.1-SNAPSHOT 14 | api 15 | Demo project for Spring Boot 16 | 17 | 18 | 1.8 19 | Greenwich.SR1 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-webflux 26 | 27 | 28 | org.springframework.cloud 29 | spring-cloud-starter-netflix-eureka-client 30 | 31 | 32 | 33 | org.projectlombok 34 | lombok 35 | true 36 | 37 | 38 | org.springframework.boot 39 | spring-boot-starter-test 40 | test 41 | 42 | 43 | io.projectreactor 44 | reactor-test 45 | test 46 | 47 | 48 | 49 | 50 | 51 | 52 | org.springframework.cloud 53 | spring-cloud-dependencies 54 | ${spring-cloud.version} 55 | pom 56 | import 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | org.springframework.boot 65 | spring-boot-maven-plugin 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /reliability/api/src/main/java/com/example/api/ApiApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.api; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.extern.log4j.Log4j2; 7 | import org.springframework.beans.factory.annotation.Value; 8 | import org.springframework.boot.SpringApplication; 9 | import org.springframework.boot.autoconfigure.SpringBootApplication; 10 | import org.springframework.web.bind.annotation.GetMapping; 11 | import org.springframework.web.bind.annotation.PathVariable; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | @Log4j2 15 | @RestController 16 | @SpringBootApplication 17 | public class ApiApplication { 18 | 19 | 20 | ApiApplication(@Value("${server.port}") int port) { 21 | this.port = port; 22 | } 23 | 24 | public static void main(String[] args) { 25 | SpringApplication.run(ApiApplication.class, args); 26 | } 27 | 28 | private final int port; 29 | 30 | @GetMapping("/greetings/{name}") 31 | Greeting greeting(@PathVariable String name) { 32 | String msg = "Hello " + name + "!"; 33 | log.info("greeting: " + msg + " on port " + this.port); 34 | return new Greeting(msg); 35 | } 36 | } 37 | 38 | @Data 39 | @AllArgsConstructor 40 | @NoArgsConstructor 41 | class Greeting { 42 | private String name; 43 | } 44 | -------------------------------------------------------------------------------- /reliability/api/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=greetings-service 2 | server.port=8888 3 | -------------------------------------------------------------------------------- /reliability/api/src/test/java/com/example/api/ApiApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.api; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class ApiApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /reliability/client/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | /target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | 20 | ### NetBeans ### 21 | /nbproject/private/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ 26 | /build/ 27 | 28 | ### VS Code ### 29 | .vscode/ 30 | -------------------------------------------------------------------------------- /reliability/client/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong-attic/bootiful-reactive-microservices-masterclass/080f7e0d79fbff17056eb20f29ad415ca30726d9/reliability/client/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /reliability/client/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /reliability/client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.1.5.RELEASE 9 | 10 | 11 | com.example 12 | client 13 | 0.0.1-SNAPSHOT 14 | client 15 | Demo project for Spring Boot 16 | 17 | 18 | 11 19 | Greenwich.SR1 20 | 21 | 22 | 23 | 24 | org.springframework.cloud 25 | spring-cloud-starter-circuitbreaker-resilience4j 26 | 0.0.1.BUILD-SNAPSHOT 27 | 28 | 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-webflux 33 | 34 | 35 | org.springframework.cloud 36 | spring-cloud-starter-netflix-eureka-client 37 | 38 | 39 | 40 | org.projectlombok 41 | lombok 42 | true 43 | 44 | 45 | org.springframework.boot 46 | spring-boot-starter-test 47 | test 48 | 49 | 50 | io.projectreactor 51 | reactor-test 52 | test 53 | 54 | 55 | 56 | 57 | 58 | 59 | org.springframework.cloud 60 | spring-cloud-dependencies 61 | ${spring-cloud.version} 62 | pom 63 | import 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | org.springframework.boot 72 | spring-boot-maven-plugin 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /reliability/client/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=edge-service 2 | 3 | -------------------------------------------------------------------------------- /reliability/client/src/test/java/com/example/client/ClientApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.client; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class ClientApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /rsocket/client/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | /target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | 20 | ### NetBeans ### 21 | /nbproject/private/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ 26 | /build/ 27 | 28 | ### VS Code ### 29 | .vscode/ 30 | -------------------------------------------------------------------------------- /rsocket/client/.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 | https://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.io.File; 21 | import java.io.FileInputStream; 22 | import java.io.FileOutputStream; 23 | import java.io.IOException; 24 | import java.net.URL; 25 | import java.nio.channels.Channels; 26 | import java.nio.channels.ReadableByteChannel; 27 | import java.util.Properties; 28 | 29 | public class MavenWrapperDownloader { 30 | 31 | /** 32 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 33 | */ 34 | private static final String DEFAULT_DOWNLOAD_URL = 35 | "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; 36 | 37 | /** 38 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 39 | * use instead of the default one. 40 | */ 41 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 42 | ".mvn/wrapper/maven-wrapper.properties"; 43 | 44 | /** 45 | * Path where the maven-wrapper.jar will be saved to. 46 | */ 47 | private static final String MAVEN_WRAPPER_JAR_PATH = 48 | ".mvn/wrapper/maven-wrapper.jar"; 49 | 50 | /** 51 | * Name of the property which should be used to override the default download url for the wrapper. 52 | */ 53 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 54 | 55 | public static void main(String args[]) { 56 | System.out.println("- Downloader started"); 57 | File baseDirectory = new File(args[0]); 58 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 59 | 60 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 61 | // wrapperUrl parameter. 62 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 63 | String url = DEFAULT_DOWNLOAD_URL; 64 | if(mavenWrapperPropertyFile.exists()) { 65 | FileInputStream mavenWrapperPropertyFileInputStream = null; 66 | try { 67 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 68 | Properties mavenWrapperProperties = new Properties(); 69 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 70 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 71 | } catch (IOException e) { 72 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 73 | } finally { 74 | try { 75 | if(mavenWrapperPropertyFileInputStream != null) { 76 | mavenWrapperPropertyFileInputStream.close(); 77 | } 78 | } catch (IOException e) { 79 | // Ignore ... 80 | } 81 | } 82 | } 83 | System.out.println("- Downloading from: : " + url); 84 | 85 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 86 | if(!outputFile.getParentFile().exists()) { 87 | if(!outputFile.getParentFile().mkdirs()) { 88 | System.out.println( 89 | "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 90 | } 91 | } 92 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 93 | try { 94 | downloadFileFromURL(url, outputFile); 95 | System.out.println("Done"); 96 | System.exit(0); 97 | } catch (Throwable e) { 98 | System.out.println("- Error downloading"); 99 | e.printStackTrace(); 100 | System.exit(1); 101 | } 102 | } 103 | 104 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 105 | URL website = new URL(urlString); 106 | ReadableByteChannel rbc; 107 | rbc = Channels.newChannel(website.openStream()); 108 | FileOutputStream fos = new FileOutputStream(destination); 109 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 110 | fos.close(); 111 | rbc.close(); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /rsocket/client/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong-attic/bootiful-reactive-microservices-masterclass/080f7e0d79fbff17056eb20f29ad415ca30726d9/rsocket/client/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /rsocket/client/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /rsocket/client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.0.M3 9 | 10 | 11 | com.example 12 | client 13 | 0.0.1-SNAPSHOT 14 | client 15 | Demo project for Spring Boot 16 | 17 | 18 | 19 | com.example.client.spring.ClientApplication 20 | 21 | 1.8 22 | 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-rsocket 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-webflux 32 | 33 | 34 | org.projectlombok 35 | lombok 36 | true 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-test 41 | test 42 | 43 | 44 | 45 | 46 | 47 | 48 | org.springframework.boot 49 | spring-boot-maven-plugin 50 | 51 | 52 | 53 | 54 | 55 | 56 | spring-snapshots 57 | Spring Snapshots 58 | https://repo.spring.io/snapshot 59 | 60 | true 61 | 62 | 63 | 64 | spring-milestones 65 | Spring Milestones 66 | https://repo.spring.io/milestone 67 | 68 | 69 | 70 | 71 | spring-snapshots 72 | Spring Snapshots 73 | https://repo.spring.io/snapshot 74 | 75 | true 76 | 77 | 78 | 79 | spring-milestones 80 | Spring Milestones 81 | https://repo.spring.io/milestone 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /rsocket/client/src/main/java/com/example/client/GreetingRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.client; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Data 8 | @AllArgsConstructor 9 | @NoArgsConstructor 10 | public class GreetingRequest { 11 | private String name; 12 | } 13 | -------------------------------------------------------------------------------- /rsocket/client/src/main/java/com/example/client/GreetingResponse.java: -------------------------------------------------------------------------------- 1 | package com.example.client; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Data 8 | @NoArgsConstructor 9 | @AllArgsConstructor 10 | public class GreetingResponse { 11 | private String message; 12 | } 13 | -------------------------------------------------------------------------------- /rsocket/client/src/main/java/com/example/client/raw/ClientApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.client.raw; 2 | 3 | import com.example.client.GreetingResponse; 4 | import lombok.RequiredArgsConstructor; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.http.MediaType; 9 | import org.springframework.web.reactive.function.server.RouterFunction; 10 | import org.springframework.web.reactive.function.server.ServerResponse; 11 | 12 | import static org.springframework.web.reactive.function.server.RouterFunctions.route; 13 | import static org.springframework.web.reactive.function.server.ServerResponse.ok; 14 | 15 | @SpringBootApplication 16 | public class ClientApplication { 17 | 18 | public static void main(String[] args) { 19 | SpringApplication.run(ClientApplication.class, args); 20 | } 21 | 22 | @Bean 23 | RouterFunction routes(GreetingClient client) { 24 | return route() 25 | .GET("/greetings/{name}", serverRequest -> ok() 26 | .contentType(MediaType.TEXT_EVENT_STREAM) 27 | .body(client .greet(serverRequest.pathVariable("name")), GreetingResponse.class)) 28 | .build(); 29 | } 30 | 31 | } 32 | 33 | -------------------------------------------------------------------------------- /rsocket/client/src/main/java/com/example/client/raw/GreetingClient.java: -------------------------------------------------------------------------------- 1 | package com.example.client.raw; 2 | 3 | import com.example.client.GreetingResponse; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import io.rsocket.Payload; 6 | import io.rsocket.RSocketFactory; 7 | import io.rsocket.transport.netty.client.TcpClientTransport; 8 | import io.rsocket.util.DefaultPayload; 9 | import lombok.RequiredArgsConstructor; 10 | import lombok.SneakyThrows; 11 | import org.springframework.stereotype.Component; 12 | import reactor.core.publisher.Flux; 13 | 14 | @Component 15 | @RequiredArgsConstructor 16 | class GreetingClient { 17 | 18 | private final ObjectMapper objectMapper; 19 | 20 | Flux greet(String name) { 21 | return RSocketFactory 22 | .connect() 23 | .transport(TcpClientTransport.create(7000)) 24 | .start() 25 | .flatMapMany(rs -> rs.requestStream(DefaultPayload.create(name)) 26 | .map(Payload::getDataUtf8) 27 | .map(this::from) 28 | ); 29 | } 30 | 31 | @SneakyThrows 32 | private GreetingResponse from(String json) { 33 | return objectMapper.readValue(json, GreetingResponse.class); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /rsocket/client/src/main/java/com/example/client/spring/ClientApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.client.spring; 2 | 3 | import com.example.client.GreetingResponse; 4 | import io.rsocket.RSocket; 5 | import io.rsocket.RSocketFactory; 6 | import io.rsocket.frame.decoder.PayloadDecoder; 7 | import io.rsocket.transport.netty.client.TcpClientTransport; 8 | import org.springframework.boot.SpringApplication; 9 | import org.springframework.boot.autoconfigure.SpringBootApplication; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.http.MediaType; 12 | import org.springframework.messaging.rsocket.RSocketRequester; 13 | import org.springframework.messaging.rsocket.RSocketStrategies; 14 | import org.springframework.util.MimeTypeUtils; 15 | import org.springframework.web.reactive.function.server.RouterFunction; 16 | import org.springframework.web.reactive.function.server.ServerResponse; 17 | 18 | import static org.springframework.web.reactive.function.server.RouterFunctions.route; 19 | import static org.springframework.web.reactive.function.server.ServerResponse.ok; 20 | 21 | @SpringBootApplication 22 | public class ClientApplication { 23 | 24 | @Bean 25 | RSocket rSocket() { 26 | return 27 | RSocketFactory 28 | .connect() 29 | .frameDecoder(PayloadDecoder.ZERO_COPY) 30 | .dataMimeType(MimeTypeUtils.APPLICATION_JSON_VALUE) 31 | .transport(TcpClientTransport.create(7000)) 32 | .start() 33 | .block(); 34 | } 35 | 36 | @Bean 37 | RouterFunction routes(GreetingClient client) { 38 | return route() 39 | .GET("/greetings/{name}", serverRequest -> ok() 40 | .contentType(MediaType.TEXT_EVENT_STREAM) 41 | .body(client.greet(serverRequest.pathVariable("name")), GreetingResponse.class)) 42 | .build(); 43 | } 44 | 45 | @Bean 46 | RSocketRequester requester(RSocketStrategies strategies) { 47 | return RSocketRequester.create(rSocket(), MimeTypeUtils.APPLICATION_JSON, strategies); 48 | } 49 | 50 | public static void main(String[] args) { 51 | SpringApplication.run(ClientApplication.class, args); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /rsocket/client/src/main/java/com/example/client/spring/GreetingClient.java: -------------------------------------------------------------------------------- 1 | package com.example.client.spring; 2 | 3 | import com.example.client.GreetingRequest; 4 | import com.example.client.GreetingResponse; 5 | import lombok.RequiredArgsConstructor; 6 | import org.reactivestreams.Publisher; 7 | import org.springframework.messaging.rsocket.RSocketRequester; 8 | import org.springframework.stereotype.Component; 9 | 10 | @Component 11 | @RequiredArgsConstructor 12 | class GreetingClient { 13 | 14 | private final RSocketRequester requester; 15 | 16 | Publisher greet(String name) { 17 | return this.requester 18 | .route("greetings") 19 | .data(new GreetingRequest(name)) 20 | .retrieveFlux(GreetingResponse.class); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /rsocket/client/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong-attic/bootiful-reactive-microservices-masterclass/080f7e0d79fbff17056eb20f29ad415ca30726d9/rsocket/client/src/main/resources/application.properties -------------------------------------------------------------------------------- /rsocket/producer/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | /target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | 20 | ### NetBeans ### 21 | /nbproject/private/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ 26 | /build/ 27 | 28 | ### VS Code ### 29 | .vscode/ 30 | -------------------------------------------------------------------------------- /rsocket/producer/.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 | https://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.io.File; 21 | import java.io.FileInputStream; 22 | import java.io.FileOutputStream; 23 | import java.io.IOException; 24 | import java.net.URL; 25 | import java.nio.channels.Channels; 26 | import java.nio.channels.ReadableByteChannel; 27 | import java.util.Properties; 28 | 29 | public class MavenWrapperDownloader { 30 | 31 | /** 32 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 33 | */ 34 | private static final String DEFAULT_DOWNLOAD_URL = 35 | "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; 36 | 37 | /** 38 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 39 | * use instead of the default one. 40 | */ 41 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 42 | ".mvn/wrapper/maven-wrapper.properties"; 43 | 44 | /** 45 | * Path where the maven-wrapper.jar will be saved to. 46 | */ 47 | private static final String MAVEN_WRAPPER_JAR_PATH = 48 | ".mvn/wrapper/maven-wrapper.jar"; 49 | 50 | /** 51 | * Name of the property which should be used to override the default download url for the wrapper. 52 | */ 53 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 54 | 55 | public static void main(String args[]) { 56 | System.out.println("- Downloader started"); 57 | File baseDirectory = new File(args[0]); 58 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 59 | 60 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 61 | // wrapperUrl parameter. 62 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 63 | String url = DEFAULT_DOWNLOAD_URL; 64 | if(mavenWrapperPropertyFile.exists()) { 65 | FileInputStream mavenWrapperPropertyFileInputStream = null; 66 | try { 67 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 68 | Properties mavenWrapperProperties = new Properties(); 69 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 70 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 71 | } catch (IOException e) { 72 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 73 | } finally { 74 | try { 75 | if(mavenWrapperPropertyFileInputStream != null) { 76 | mavenWrapperPropertyFileInputStream.close(); 77 | } 78 | } catch (IOException e) { 79 | // Ignore ... 80 | } 81 | } 82 | } 83 | System.out.println("- Downloading from: : " + url); 84 | 85 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 86 | if(!outputFile.getParentFile().exists()) { 87 | if(!outputFile.getParentFile().mkdirs()) { 88 | System.out.println( 89 | "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 90 | } 91 | } 92 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 93 | try { 94 | downloadFileFromURL(url, outputFile); 95 | System.out.println("Done"); 96 | System.exit(0); 97 | } catch (Throwable e) { 98 | System.out.println("- Error downloading"); 99 | e.printStackTrace(); 100 | System.exit(1); 101 | } 102 | } 103 | 104 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 105 | URL website = new URL(urlString); 106 | ReadableByteChannel rbc; 107 | rbc = Channels.newChannel(website.openStream()); 108 | FileOutputStream fos = new FileOutputStream(destination); 109 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 110 | fos.close(); 111 | rbc.close(); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /rsocket/producer/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong-attic/bootiful-reactive-microservices-masterclass/080f7e0d79fbff17056eb20f29ad415ca30726d9/rsocket/producer/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /rsocket/producer/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /rsocket/producer/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.0.M3 9 | 10 | 11 | com.example 12 | producer 13 | 0.0.1-SNAPSHOT 14 | producer 15 | Demo project for Spring Boot 16 | 17 | 18 | 19 | com.example.producer.spring.SpringRsocketApplication 20 | 21 | 1.8 22 | 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-rsocket 28 | 29 | 30 | 31 | org.projectlombok 32 | lombok 33 | true 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-starter-test 38 | test 39 | 40 | 41 | 42 | 43 | 44 | 45 | org.springframework.boot 46 | spring-boot-maven-plugin 47 | 48 | 49 | 50 | 51 | 52 | 53 | spring-snapshots 54 | Spring Snapshots 55 | https://repo.spring.io/snapshot 56 | 57 | true 58 | 59 | 60 | 61 | spring-milestones 62 | Spring Milestones 63 | https://repo.spring.io/milestone 64 | 65 | 66 | 67 | 68 | spring-snapshots 69 | Spring Snapshots 70 | https://repo.spring.io/snapshot 71 | 72 | true 73 | 74 | 75 | 76 | spring-milestones 77 | Spring Milestones 78 | https://repo.spring.io/milestone 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /rsocket/producer/src/main/java/com/example/GreetingService.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import com.example.producer.GreetingRequest; 4 | import com.example.producer.GreetingResponse; 5 | import reactor.core.publisher.Flux; 6 | 7 | import java.time.Duration; 8 | import java.time.Instant; 9 | import java.util.stream.Stream; 10 | 11 | public class GreetingService { 12 | 13 | public Flux greetOverTime(GreetingRequest greetingRequest) { 14 | return Flux.fromStream(Stream 15 | .generate(() -> new GreetingResponse("Hello " + greetingRequest.getName() 16 | + " @ " + Instant.now() + " !"))) 17 | .delayElements(Duration.ofSeconds(1)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /rsocket/producer/src/main/java/com/example/producer/GreetingRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.producer; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | 8 | @Data 9 | @AllArgsConstructor 10 | @NoArgsConstructor 11 | public class GreetingRequest { 12 | private String name; 13 | } 14 | -------------------------------------------------------------------------------- /rsocket/producer/src/main/java/com/example/producer/GreetingResponse.java: -------------------------------------------------------------------------------- 1 | package com.example.producer; 2 | 3 | import lombok.*; 4 | 5 | @Data 6 | @NoArgsConstructor 7 | @AllArgsConstructor 8 | public class GreetingResponse { 9 | private String message; 10 | } 11 | -------------------------------------------------------------------------------- /rsocket/producer/src/main/java/com/example/producer/raw/RawRsocketApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.producer.raw; 2 | 3 | import com.example.GreetingService; 4 | import com.example.producer.GreetingRequest; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import io.rsocket.*; 7 | import io.rsocket.transport.netty.server.TcpServerTransport; 8 | import io.rsocket.util.DefaultPayload; 9 | import lombok.SneakyThrows; 10 | import org.springframework.boot.SpringApplication; 11 | import org.springframework.boot.autoconfigure.SpringBootApplication; 12 | import org.springframework.boot.context.event.ApplicationReadyEvent; 13 | import org.springframework.context.annotation.Bean; 14 | import org.springframework.context.event.EventListener; 15 | import reactor.core.publisher.Flux; 16 | import reactor.core.publisher.Mono; 17 | 18 | import java.io.IOException; 19 | 20 | @SpringBootApplication 21 | public class RawRsocketApplication { 22 | 23 | private final ObjectMapper objectMapper; 24 | 25 | @Bean 26 | GreetingService greetingService() { 27 | return new GreetingService(); 28 | } 29 | 30 | public RawRsocketApplication(ObjectMapper objectMapper) { 31 | this.objectMapper = objectMapper; 32 | } 33 | 34 | @EventListener(ApplicationReadyEvent.class) 35 | public void go() throws Exception { 36 | 37 | GreetingService greetingService = this.greetingService(); 38 | 39 | RSocketFactory 40 | .receive() 41 | .acceptor((setup, requestRsocket) -> { 42 | 43 | RSocket responseRsocket = new AbstractRSocket() { 44 | @Override 45 | public Flux requestStream(Payload payload) { 46 | return greetingService 47 | .greetOverTime(new GreetingRequest(payload.getDataUtf8())) 48 | .map(RawRsocketApplication.this::from) 49 | .map(DefaultPayload::create); 50 | } 51 | }; 52 | return Mono.just(responseRsocket); 53 | }) 54 | .transport(TcpServerTransport.create(7000)) 55 | .start() 56 | .subscribe(); 57 | 58 | } 59 | 60 | @SneakyThrows 61 | private String from(Object gr) { 62 | return objectMapper.writeValueAsString(gr); 63 | } 64 | 65 | public static void main(String[] args) throws IOException { 66 | SpringApplication.run(RawRsocketApplication.class); 67 | System.in.read(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /rsocket/producer/src/main/java/com/example/producer/spring/GreetingRsocketService.java: -------------------------------------------------------------------------------- 1 | package com.example.producer.spring; 2 | 3 | import com.example.GreetingService; 4 | import com.example.producer.GreetingRequest; 5 | import com.example.producer.GreetingResponse; 6 | import lombok.RequiredArgsConstructor; 7 | import org.springframework.messaging.handler.annotation.MessageMapping; 8 | import org.springframework.stereotype.Controller; 9 | import reactor.core.publisher.Flux; 10 | 11 | @Controller 12 | @RequiredArgsConstructor 13 | class GreetingRsocketService { 14 | 15 | private final GreetingService greetingService; 16 | 17 | @MessageMapping("greetings") 18 | Flux greet(GreetingRequest name) { 19 | return greetingService.greetOverTime(name); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /rsocket/producer/src/main/java/com/example/producer/spring/SpringRsocketApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.producer.spring; 2 | 3 | import com.example.GreetingService; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.context.annotation.Bean; 7 | 8 | @SpringBootApplication 9 | public class SpringRsocketApplication { 10 | 11 | @Bean 12 | GreetingService greetingService() { 13 | return new GreetingService(); 14 | } 15 | 16 | public static void main(String[] args) { 17 | SpringApplication.run(SpringRsocketApplication.class, args); 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /rsocket/producer/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.rsocket.server.port=7000 -------------------------------------------------------------------------------- /testing/consumer/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | /target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | 20 | ### NetBeans ### 21 | /nbproject/private/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ 26 | /build/ 27 | 28 | ### VS Code ### 29 | .vscode/ 30 | -------------------------------------------------------------------------------- /testing/consumer/.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 | https://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.io.File; 21 | import java.io.FileInputStream; 22 | import java.io.FileOutputStream; 23 | import java.io.IOException; 24 | import java.net.URL; 25 | import java.nio.channels.Channels; 26 | import java.nio.channels.ReadableByteChannel; 27 | import java.util.Properties; 28 | 29 | public class MavenWrapperDownloader { 30 | 31 | /** 32 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 33 | */ 34 | private static final String DEFAULT_DOWNLOAD_URL = 35 | "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; 36 | 37 | /** 38 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 39 | * use instead of the default one. 40 | */ 41 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 42 | ".mvn/wrapper/maven-wrapper.properties"; 43 | 44 | /** 45 | * Path where the maven-wrapper.jar will be saved to. 46 | */ 47 | private static final String MAVEN_WRAPPER_JAR_PATH = 48 | ".mvn/wrapper/maven-wrapper.jar"; 49 | 50 | /** 51 | * Name of the property which should be used to override the default download url for the wrapper. 52 | */ 53 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 54 | 55 | public static void main(String args[]) { 56 | System.out.println("- Downloader started"); 57 | File baseDirectory = new File(args[0]); 58 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 59 | 60 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 61 | // wrapperUrl parameter. 62 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 63 | String url = DEFAULT_DOWNLOAD_URL; 64 | if(mavenWrapperPropertyFile.exists()) { 65 | FileInputStream mavenWrapperPropertyFileInputStream = null; 66 | try { 67 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 68 | Properties mavenWrapperProperties = new Properties(); 69 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 70 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 71 | } catch (IOException e) { 72 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 73 | } finally { 74 | try { 75 | if(mavenWrapperPropertyFileInputStream != null) { 76 | mavenWrapperPropertyFileInputStream.close(); 77 | } 78 | } catch (IOException e) { 79 | // Ignore ... 80 | } 81 | } 82 | } 83 | System.out.println("- Downloading from: : " + url); 84 | 85 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 86 | if(!outputFile.getParentFile().exists()) { 87 | if(!outputFile.getParentFile().mkdirs()) { 88 | System.out.println( 89 | "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 90 | } 91 | } 92 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 93 | try { 94 | downloadFileFromURL(url, outputFile); 95 | System.out.println("Done"); 96 | System.exit(0); 97 | } catch (Throwable e) { 98 | System.out.println("- Error downloading"); 99 | e.printStackTrace(); 100 | System.exit(1); 101 | } 102 | } 103 | 104 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 105 | URL website = new URL(urlString); 106 | ReadableByteChannel rbc; 107 | rbc = Channels.newChannel(website.openStream()); 108 | FileOutputStream fos = new FileOutputStream(destination); 109 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 110 | fos.close(); 111 | rbc.close(); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /testing/consumer/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong-attic/bootiful-reactive-microservices-masterclass/080f7e0d79fbff17056eb20f29ad415ca30726d9/testing/consumer/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /testing/consumer/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /testing/consumer/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.0.M3 9 | 10 | 11 | com.example 12 | consumer 13 | 0.0.1-SNAPSHOT 14 | consumer 15 | Demo project for Spring Boot 16 | 17 | 18 | 11 19 | Hoxton.BUILD-SNAPSHOT 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-webflux 26 | 27 | 28 | 29 | org.projectlombok 30 | lombok 31 | true 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-test 36 | test 37 | 47 | 48 | 49 | io.projectreactor 50 | reactor-test 51 | test 52 | 53 | 54 | org.springframework.cloud 55 | spring-cloud-starter-contract-stub-runner 56 | test 57 | 58 | 59 | 60 | 61 | 62 | 63 | org.springframework.cloud 64 | spring-cloud-dependencies 65 | ${spring-cloud.version} 66 | pom 67 | import 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | org.springframework.boot 76 | spring-boot-maven-plugin 77 | 78 | 79 | 80 | 81 | 82 | 83 | spring-snapshots 84 | Spring Snapshots 85 | https://repo.spring.io/snapshot 86 | 87 | true 88 | 89 | 90 | 91 | spring-milestones 92 | Spring Milestones 93 | https://repo.spring.io/milestone 94 | 95 | 96 | 97 | 98 | spring-snapshots 99 | Spring Snapshots 100 | https://repo.spring.io/snapshot 101 | 102 | true 103 | 104 | 105 | 106 | spring-milestones 107 | Spring Milestones 108 | https://repo.spring.io/milestone 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /testing/consumer/src/main/java/com/example/consumer/ConsumerApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.consumer; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.web.reactive.function.client.WebClient; 7 | 8 | @SpringBootApplication 9 | public class ConsumerApplication { 10 | 11 | @Bean 12 | WebClient client(WebClient.Builder builder) { 13 | return builder.build(); 14 | } 15 | 16 | public static void main(String[] args) { 17 | SpringApplication.run(ConsumerApplication.class, args); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /testing/consumer/src/main/java/com/example/consumer/ReservationClient.java: -------------------------------------------------------------------------------- 1 | package com.example.consumer; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.RequiredArgsConstructor; 7 | import org.springframework.stereotype.Component; 8 | import org.springframework.web.reactive.function.client.WebClient; 9 | import reactor.core.publisher.Flux; 10 | 11 | @Component 12 | @RequiredArgsConstructor 13 | class ReservationClient { 14 | 15 | private final WebClient client; 16 | 17 | Flux getAllReservations() { 18 | return this.client 19 | .get() 20 | .uri("http://localhost:8080/reservations") 21 | .retrieve() 22 | .bodyToFlux(Reservation.class); 23 | } 24 | } 25 | 26 | @Data 27 | @AllArgsConstructor 28 | @NoArgsConstructor 29 | class Reservation { 30 | private String id, name; 31 | } -------------------------------------------------------------------------------- /testing/consumer/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /testing/consumer/src/test/java/com/example/consumer/ConsumerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.consumer; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner; 9 | import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; 10 | import org.springframework.test.context.junit4.SpringRunner; 11 | import reactor.test.StepVerifier; 12 | 13 | @RunWith(SpringRunner.class) 14 | @SpringBootTest 15 | @AutoConfigureStubRunner( 16 | ids = "com.example:producer:+:8080", 17 | stubsMode = StubRunnerProperties.StubsMode.LOCAL 18 | ) 19 | //@AutoConfigureWireMock(port = 8080) 20 | public class ConsumerApplicationTests { 21 | 22 | @Autowired 23 | private ReservationClient client; 24 | 25 | // private String buildJsonFor(String id, String name) { 26 | // return " {\"reservationName\":\"" + name + "\",\"id\":\"" + id + "\"}"; 27 | // } 28 | 29 | @Before 30 | public void before() { 31 | 32 | // 33 | // var json = "[" + buildJsonFor("1", "Jane") + "," + buildJsonFor("2", "John") + "]"; 34 | // stubFor(get( 35 | // urlEqualTo("/reservations")) 36 | // .willReturn(aResponse() 37 | // .withBody(json) 38 | // .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) 39 | // .withStatus(HttpStatus.OK.value()) 40 | // )); 41 | 42 | } 43 | 44 | @Test 45 | public void contextLoads() { 46 | 47 | var allReservations = this.client.getAllReservations(); 48 | StepVerifier 49 | .create(allReservations) 50 | .expectNext(new Reservation("1", "Jane")) 51 | .expectNext(new Reservation("2", "John")) 52 | .verifyComplete(); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /testing/producer/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | /target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | 20 | ### NetBeans ### 21 | /nbproject/private/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ 26 | /build/ 27 | 28 | ### VS Code ### 29 | .vscode/ 30 | -------------------------------------------------------------------------------- /testing/producer/.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 | https://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.io.File; 21 | import java.io.FileInputStream; 22 | import java.io.FileOutputStream; 23 | import java.io.IOException; 24 | import java.net.URL; 25 | import java.nio.channels.Channels; 26 | import java.nio.channels.ReadableByteChannel; 27 | import java.util.Properties; 28 | 29 | public class MavenWrapperDownloader { 30 | 31 | /** 32 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 33 | */ 34 | private static final String DEFAULT_DOWNLOAD_URL = 35 | "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; 36 | 37 | /** 38 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 39 | * use instead of the default one. 40 | */ 41 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 42 | ".mvn/wrapper/maven-wrapper.properties"; 43 | 44 | /** 45 | * Path where the maven-wrapper.jar will be saved to. 46 | */ 47 | private static final String MAVEN_WRAPPER_JAR_PATH = 48 | ".mvn/wrapper/maven-wrapper.jar"; 49 | 50 | /** 51 | * Name of the property which should be used to override the default download url for the wrapper. 52 | */ 53 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 54 | 55 | public static void main(String args[]) { 56 | System.out.println("- Downloader started"); 57 | File baseDirectory = new File(args[0]); 58 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 59 | 60 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 61 | // wrapperUrl parameter. 62 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 63 | String url = DEFAULT_DOWNLOAD_URL; 64 | if(mavenWrapperPropertyFile.exists()) { 65 | FileInputStream mavenWrapperPropertyFileInputStream = null; 66 | try { 67 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 68 | Properties mavenWrapperProperties = new Properties(); 69 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 70 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 71 | } catch (IOException e) { 72 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 73 | } finally { 74 | try { 75 | if(mavenWrapperPropertyFileInputStream != null) { 76 | mavenWrapperPropertyFileInputStream.close(); 77 | } 78 | } catch (IOException e) { 79 | // Ignore ... 80 | } 81 | } 82 | } 83 | System.out.println("- Downloading from: : " + url); 84 | 85 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 86 | if(!outputFile.getParentFile().exists()) { 87 | if(!outputFile.getParentFile().mkdirs()) { 88 | System.out.println( 89 | "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 90 | } 91 | } 92 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 93 | try { 94 | downloadFileFromURL(url, outputFile); 95 | System.out.println("Done"); 96 | System.exit(0); 97 | } catch (Throwable e) { 98 | System.out.println("- Error downloading"); 99 | e.printStackTrace(); 100 | System.exit(1); 101 | } 102 | } 103 | 104 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 105 | URL website = new URL(urlString); 106 | ReadableByteChannel rbc; 107 | rbc = Channels.newChannel(website.openStream()); 108 | FileOutputStream fos = new FileOutputStream(destination); 109 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 110 | fos.close(); 111 | rbc.close(); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /testing/producer/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong-attic/bootiful-reactive-microservices-masterclass/080f7e0d79fbff17056eb20f29ad415ca30726d9/testing/producer/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /testing/producer/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /testing/producer/src/main/java/com/example/producer/ProducerApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.producer; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ProducerApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ProducerApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /testing/producer/src/main/java/com/example/producer/Reservation.java: -------------------------------------------------------------------------------- 1 | package com.example.producer; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import org.springframework.data.annotation.Id; 7 | import org.springframework.data.mongodb.core.mapping.Document; 8 | 9 | @Document 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | @Data 13 | class Reservation { 14 | 15 | @Id 16 | private String id; 17 | 18 | private String name; 19 | } 20 | -------------------------------------------------------------------------------- /testing/producer/src/main/java/com/example/producer/ReservationHttpConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.example.producer; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.reactive.function.server.RouterFunction; 6 | import org.springframework.web.reactive.function.server.ServerResponse; 7 | 8 | import static org.springframework.web.reactive.function.server.RouterFunctions.route; 9 | import static org.springframework.web.reactive.function.server.ServerResponse.ok; 10 | 11 | @Configuration 12 | public class ReservationHttpConfiguration { 13 | 14 | @Bean 15 | RouterFunction routes(ReservationRepository reservationRepository) { 16 | return 17 | route() 18 | .GET("/reservations", request -> ok().body(reservationRepository.findAll(), Reservation.class)) 19 | .build(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /testing/producer/src/main/java/com/example/producer/ReservationRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.producer; 2 | 3 | import org.springframework.data.repository.reactive.ReactiveCrudRepository; 4 | import reactor.core.publisher.Flux; 5 | 6 | public interface ReservationRepository extends ReactiveCrudRepository { 7 | 8 | Flux findByName(String name); 9 | } 10 | -------------------------------------------------------------------------------- /testing/producer/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /testing/producer/src/test/java/com/example/producer/BaseClass.java: -------------------------------------------------------------------------------- 1 | package com.example.producer; 2 | 3 | 4 | import io.restassured.RestAssured; 5 | import org.junit.Before; 6 | import org.junit.runner.RunWith; 7 | import org.mockito.Mockito; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | import org.springframework.boot.test.mock.mockito.MockBean; 10 | import org.springframework.boot.web.server.LocalServerPort; 11 | import org.springframework.test.context.junit4.SpringRunner; 12 | import reactor.core.publisher.Flux; 13 | 14 | @SpringBootTest(classes = { 15 | ProducerApplication.class, 16 | ReservationHttpConfiguration.class}, 17 | webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 18 | properties = "server.port=0") 19 | @RunWith(SpringRunner.class) 20 | public class BaseClass { 21 | 22 | @MockBean 23 | private ReservationRepository repository; 24 | 25 | @LocalServerPort 26 | int port; 27 | 28 | @Before 29 | public void before() { 30 | Mockito.when(this.repository.findAll()).thenReturn(Flux.just(new Reservation("1", "Jane"), 31 | new Reservation("2", "John"))); 32 | RestAssured.baseURI = "http://localhost:" + this.port; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /testing/producer/src/test/java/com/example/producer/ReservationEntityTest.java: -------------------------------------------------------------------------------- 1 | package com.example.producer; 2 | 3 | 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest; 8 | import org.springframework.data.mongodb.core.ReactiveMongoTemplate; 9 | import org.springframework.test.context.junit4.SpringRunner; 10 | import reactor.core.publisher.Mono; 11 | import reactor.test.StepVerifier; 12 | 13 | @DataMongoTest 14 | @RunWith(SpringRunner.class) 15 | public class ReservationEntityTest { 16 | 17 | @Autowired 18 | private ReactiveMongoTemplate template; 19 | 20 | @Test 21 | public void persist() throws Exception { 22 | Reservation r = new Reservation(null, "Name"); 23 | Mono save = this.template.save(r); 24 | StepVerifier 25 | .create(save) 26 | .expectNextMatches(match -> match.getId() != null && match.getName().equalsIgnoreCase("name")) 27 | .verifyComplete(); 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /testing/producer/src/test/java/com/example/producer/ReservationHttpTest.java: -------------------------------------------------------------------------------- 1 | package com.example.producer; 2 | 3 | 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.mockito.Mockito; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; 9 | import org.springframework.boot.test.mock.mockito.MockBean; 10 | import org.springframework.http.MediaType; 11 | import org.springframework.test.context.junit4.SpringRunner; 12 | import org.springframework.test.web.reactive.server.WebTestClient; 13 | import reactor.core.publisher.Flux; 14 | 15 | 16 | @WebFluxTest(value = {ReservationHttpConfiguration.class}) 17 | @RunWith(SpringRunner.class) 18 | public class ReservationHttpTest { 19 | 20 | @MockBean 21 | private ReservationRepository repository; 22 | 23 | @Autowired 24 | private WebTestClient client; 25 | 26 | @Test 27 | public void getAllReservations() throws Exception { 28 | 29 | Mockito.when(this.repository.findAll()).thenReturn(Flux.just(new Reservation("1", "Jane"))); 30 | 31 | this.client 32 | .get() 33 | .uri("/reservations") 34 | .exchange() 35 | .expectStatus().isOk() 36 | .expectHeader().contentTypeCompatibleWith(MediaType.APPLICATION_JSON) 37 | .expectBody().jsonPath("@.[0].name").isEqualTo("Jane"); 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /testing/producer/src/test/java/com/example/producer/ReservationRepositoryTest.java: -------------------------------------------------------------------------------- 1 | package com.example.producer; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest; 7 | import org.springframework.test.context.junit4.SpringRunner; 8 | import reactor.core.publisher.Flux; 9 | import reactor.test.StepVerifier; 10 | 11 | @RunWith(SpringRunner.class) 12 | @DataMongoTest 13 | public class ReservationRepositoryTest { 14 | 15 | @Autowired 16 | private ReservationRepository repository; 17 | 18 | @Test 19 | public void query() throws Exception { 20 | 21 | Flux results = this.repository 22 | .deleteAll() 23 | .thenMany(Flux.just("A", "B").map(n -> new Reservation(null, n)).flatMap(r -> this.repository.save(r))) 24 | .thenMany(this.repository.findByName("B")); 25 | 26 | StepVerifier 27 | .create(results) 28 | .expectNextCount(1) 29 | .verifyComplete(); 30 | 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /testing/producer/src/test/java/com/example/producer/ReservationTest.java: -------------------------------------------------------------------------------- 1 | package com.example.producer; 2 | 3 | 4 | import org.assertj.core.api.Assertions; 5 | import org.hamcrest.BaseMatcher; 6 | import org.hamcrest.Description; 7 | import org.hamcrest.Matcher; 8 | import org.junit.Assert; 9 | import org.junit.Test; 10 | 11 | public class ReservationTest { 12 | 13 | private Matcher matcher = new BaseMatcher<>() { 14 | 15 | @Override 16 | public void describeTo(Description description) { 17 | description.appendText("the first letter of the name should be uppercase"); 18 | } 19 | 20 | @Override 21 | public boolean matches(Object item) { 22 | Assert.assertTrue(item instanceof String); 23 | String str = (String) item; 24 | return Character.isUpperCase(str.charAt(0)); 25 | } 26 | }; 27 | 28 | @Test 29 | public void create() throws Exception { 30 | Reservation re = new Reservation("1", "Name"); 31 | Assert.assertEquals(re.getName(), "Name"); 32 | Assert.assertThat(re.getName(), matcher); 33 | Assertions.assertThat(re.getName()).isNotEmpty(); 34 | Assertions.assertThat(re.getName()).isEqualToIgnoringCase("name"); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /testing/producer/src/test/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong-attic/bootiful-reactive-microservices-masterclass/080f7e0d79fbff17056eb20f29ad415ca30726d9/testing/producer/src/test/resources/application.properties -------------------------------------------------------------------------------- /testing/producer/src/test/resources/contracts/shouldReturnAllReservations.groovy: -------------------------------------------------------------------------------- 1 | import org.springframework.cloud.contract.spec.Contract 2 | import org.springframework.cloud.contract.spec.internal.HttpMethods 3 | import org.springframework.http.HttpStatus 4 | import org.springframework.http.MediaType 5 | 6 | Contract.make { 7 | 8 | description("should return all Reservations") 9 | 10 | request { 11 | url("/reservations") 12 | method(HttpMethods.HttpMethod.GET) 13 | } 14 | response { 15 | status(HttpStatus.OK.value()) 16 | body([[id: 1, name: "Jane"], [id: 2, name: "John"]]) 17 | headers { 18 | contentType(MediaType.APPLICATION_JSON_VALUE) 19 | } 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /testing/run-stub-runner-boot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | java -jar -Dserver.port=8090 spring-cloud-contract-stub-runner-boot-2.1.1.RELEASE.jar \ 3 | --stubrunner.workOffline=true \ 4 | --stubrunner.stubs-mode="local" \ 5 | --stubrunner.ids=com.example:producer:+:8080 \ 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /testing/spring-cloud-contract-stub-runner-boot-2.1.1.RELEASE.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong-attic/bootiful-reactive-microservices-masterclass/080f7e0d79fbff17056eb20f29ad415ca30726d9/testing/spring-cloud-contract-stub-runner-boot-2.1.1.RELEASE.jar -------------------------------------------------------------------------------- /web/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | /target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | 20 | ### NetBeans ### 21 | /nbproject/private/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ 26 | /build/ 27 | 28 | ### VS Code ### 29 | .vscode/ 30 | -------------------------------------------------------------------------------- /web/.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 | https://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.io.File; 21 | import java.io.FileInputStream; 22 | import java.io.FileOutputStream; 23 | import java.io.IOException; 24 | import java.net.URL; 25 | import java.nio.channels.Channels; 26 | import java.nio.channels.ReadableByteChannel; 27 | import java.util.Properties; 28 | 29 | public class MavenWrapperDownloader { 30 | 31 | /** 32 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 33 | */ 34 | private static final String DEFAULT_DOWNLOAD_URL = 35 | "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; 36 | 37 | /** 38 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 39 | * use instead of the default one. 40 | */ 41 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 42 | ".mvn/wrapper/maven-wrapper.properties"; 43 | 44 | /** 45 | * Path where the maven-wrapper.jar will be saved to. 46 | */ 47 | private static final String MAVEN_WRAPPER_JAR_PATH = 48 | ".mvn/wrapper/maven-wrapper.jar"; 49 | 50 | /** 51 | * Name of the property which should be used to override the default download url for the wrapper. 52 | */ 53 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 54 | 55 | public static void main(String args[]) { 56 | System.out.println("- Downloader started"); 57 | File baseDirectory = new File(args[0]); 58 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 59 | 60 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 61 | // wrapperUrl parameter. 62 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 63 | String url = DEFAULT_DOWNLOAD_URL; 64 | if(mavenWrapperPropertyFile.exists()) { 65 | FileInputStream mavenWrapperPropertyFileInputStream = null; 66 | try { 67 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 68 | Properties mavenWrapperProperties = new Properties(); 69 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 70 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 71 | } catch (IOException e) { 72 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 73 | } finally { 74 | try { 75 | if(mavenWrapperPropertyFileInputStream != null) { 76 | mavenWrapperPropertyFileInputStream.close(); 77 | } 78 | } catch (IOException e) { 79 | // Ignore ... 80 | } 81 | } 82 | } 83 | System.out.println("- Downloading from: : " + url); 84 | 85 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 86 | if(!outputFile.getParentFile().exists()) { 87 | if(!outputFile.getParentFile().mkdirs()) { 88 | System.out.println( 89 | "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 90 | } 91 | } 92 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 93 | try { 94 | downloadFileFromURL(url, outputFile); 95 | System.out.println("Done"); 96 | System.exit(0); 97 | } catch (Throwable e) { 98 | System.out.println("- Error downloading"); 99 | e.printStackTrace(); 100 | System.exit(1); 101 | } 102 | } 103 | 104 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 105 | URL website = new URL(urlString); 106 | ReadableByteChannel rbc; 107 | rbc = Channels.newChannel(website.openStream()); 108 | FileOutputStream fos = new FileOutputStream(destination); 109 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 110 | fos.close(); 111 | rbc.close(); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /web/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong-attic/bootiful-reactive-microservices-masterclass/080f7e0d79fbff17056eb20f29ad415ca30726d9/web/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /web/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /web/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.0.M3 9 | 10 | 11 | com.example 12 | web 13 | 0.0.1-SNAPSHOT 14 | web 15 | Demo project for Spring Boot 16 | 17 | 18 | 11 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-webflux 25 | 26 | 27 | 28 | org.projectlombok 29 | lombok 30 | true 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-test 35 | test 36 | 37 | 38 | org.junit.vintage 39 | junit-vintage-engine 40 | 41 | 42 | junit 43 | junit 44 | 45 | 46 | 47 | 48 | io.projectreactor 49 | reactor-test 50 | test 51 | 52 | 53 | 54 | 55 | 56 | 57 | org.springframework.boot 58 | spring-boot-maven-plugin 59 | 60 | 61 | 62 | 63 | 64 | 65 | spring-snapshots 66 | Spring Snapshots 67 | https://repo.spring.io/snapshot 68 | 69 | true 70 | 71 | 72 | 73 | spring-milestones 74 | Spring Milestones 75 | https://repo.spring.io/milestone 76 | 77 | 78 | 79 | 80 | spring-snapshots 81 | Spring Snapshots 82 | https://repo.spring.io/snapshot 83 | 84 | true 85 | 86 | 87 | 88 | spring-milestones 89 | Spring Milestones 90 | https://repo.spring.io/milestone 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /web/src/main/java/com/example/web/WebApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.web; 2 | 3 | import lombok.Data; 4 | import lombok.RequiredArgsConstructor; 5 | import lombok.extern.log4j.Log4j2; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.http.MediaType; 11 | import org.springframework.stereotype.Service; 12 | import org.springframework.web.bind.annotation.GetMapping; 13 | import org.springframework.web.bind.annotation.PathVariable; 14 | import org.springframework.web.bind.annotation.RestController; 15 | import org.springframework.web.reactive.function.server.*; 16 | import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping; 17 | import org.springframework.web.reactive.socket.WebSocketHandler; 18 | import org.springframework.web.reactive.socket.WebSocketMessage; 19 | import org.springframework.web.reactive.socket.server.support.WebSocketHandlerAdapter; 20 | import reactor.core.publisher.Flux; 21 | import reactor.core.publisher.Mono; 22 | 23 | import java.time.Instant; 24 | import java.util.Map; 25 | 26 | import static org.springframework.web.reactive.function.server.ServerResponse.ok; 27 | 28 | @SpringBootApplication 29 | public class WebApplication { 30 | 31 | public static void main(String[] args) { 32 | SpringApplication.run(WebApplication.class, args); 33 | } 34 | 35 | @Bean 36 | RouterFunction routes() { 37 | return RouterFunctions 38 | .route(RequestPredicates.GET("/greetings/{name}").and(request -> Math.random() > .5), this::handleGetGreetings); 39 | } 40 | 41 | 42 | private Mono handleGetGreetings(ServerRequest request) { 43 | return ok().syncBody(new Greeting(request.pathVariable("name"))); 44 | } 45 | } 46 | 47 | 48 | @RestController 49 | @RequiredArgsConstructor 50 | class GreetingsSseRestController { 51 | 52 | private final GreetingsService greetingsService; 53 | 54 | @GetMapping(value = "/greetings/sse/{name}", produces = MediaType.TEXT_EVENT_STREAM_VALUE) 55 | Flux greetingFlux(@PathVariable String name) { 56 | return this.greetingsService.greet(name); 57 | } 58 | } 59 | 60 | 61 | @Log4j2 62 | @Configuration 63 | class WebsocketConfig { 64 | 65 | @Bean 66 | WebSocketHandler webSocketHandler(GreetingsService gs) { 67 | return session -> { 68 | 69 | var map = session 70 | .receive() 71 | .map(WebSocketMessage::getPayloadAsText) 72 | .flatMap(gs::greet) 73 | .map(Greeting::getMessage) 74 | .map(session::textMessage) 75 | .doOnEach(signal -> log.info("onEach: " + signal.getType())) 76 | .doFinally(signal -> log.info("finally: " + signal.toString())); 77 | 78 | return session.send(map); 79 | }; 80 | } 81 | 82 | 83 | @Bean 84 | SimpleUrlHandlerMapping simpleUrlHandlerMapping(WebSocketHandler wsh) { 85 | return new SimpleUrlHandlerMapping() { 86 | { 87 | setUrlMap(Map.of("/ws/greetings", wsh)); 88 | setOrder(10); 89 | } 90 | }; 91 | } 92 | 93 | @Bean 94 | WebSocketHandlerAdapter webSocketHandlerAdapter() { 95 | return new WebSocketHandlerAdapter(); 96 | } 97 | } 98 | 99 | @Service 100 | class GreetingsService { 101 | 102 | Flux greet(String name) { 103 | 104 | return Mono 105 | .just("Josh") 106 | .flatMapMany(str -> { 107 | if (str.equalsIgnoreCase("josh")) { 108 | return Flux.just(new Greeting("Yo Josh")); 109 | } 110 | else { 111 | return Flux.just(new Greeting("Yo")); 112 | } 113 | }); 114 | 115 | // 116 | // if (name.equalsIgnoreCase("josh")) 117 | // return Flux.just(new Greeting("Yo Josh")); 118 | // 119 | // else return Flux.just(new Greeting("Yo")); 120 | // return Flux .fromStream(Stream.generate(() -> new Greeting("Hello " + name + " @ " + Instant.now()))).delayElements(Duration.ofSeconds(1)); 121 | } 122 | } 123 | 124 | /* 125 | @RestController 126 | class GreetingsRestController { 127 | 128 | @GetMapping("/greeting/{name}") 129 | Mono greeting(@PathVariable String name) { 130 | // ... 131 | return Mono.just(new Greeting("Hello " + name + "@" + Instant.now() + "!")); 132 | // ... 133 | } 134 | } 135 | */ 136 | 137 | @Data 138 | class Greeting { 139 | 140 | private String message; 141 | 142 | Greeting(String name) { 143 | this.message = "hello " + name + " @ " + Instant.now().toString(); 144 | } 145 | } 146 | 147 | 148 | -------------------------------------------------------------------------------- /web/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /web/src/main/resources/static/sse.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 13 | -------------------------------------------------------------------------------- /web/src/main/resources/static/ws.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 17 | 18 | -------------------------------------------------------------------------------- /web/src/test/java/com/example/web/WebApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.web; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class WebApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | --------------------------------------------------------------------------------