├── 1.0 └── demo │ ├── .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 ├── 2.0 └── data │ ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── data │ │ │ └── DataApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── example │ └── data │ └── DataApplicationTests.java ├── 3.0 ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── http │ │ │ └── HttpApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── example │ └── http │ └── HttpApplicationTests.java ├── 4.0 ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── websockets │ │ │ └── WebsocketsApplication.java │ └── resources │ │ ├── application.properties │ │ └── static │ │ └── ws.html │ └── test │ └── java │ └── com │ └── example │ └── websockets │ └── WebsocketsApplicationTests.java ├── 5.0 ├── greeting-client │ ├── .mvn │ │ └── wrapper │ │ │ ├── MavenWrapperDownloader.java │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── greetingclient │ │ │ │ └── GreetingClientApplication.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── greetingclient │ │ └── GreetingClientApplicationTests.java └── greeting-service │ ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── greetingservice │ │ │ └── GreetingServiceApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── example │ └── greetingservice │ └── GreetingServiceApplicationTests.java ├── 6.0 ├── raw-rsocket-client │ ├── .mvn │ │ └── wrapper │ │ │ ├── MavenWrapperDownloader.java │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── HELP.md │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── rawrsocketclient │ │ │ │ └── RawRsocketClientApplication.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── rawrsocketclient │ │ └── RawRsocketClientApplicationTests.java ├── raw-rsocket-service │ ├── .mvn │ │ └── wrapper │ │ │ ├── MavenWrapperDownloader.java │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── HELP.md │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── rawrsocketservice │ │ │ │ └── RawRsocketServiceApplication.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── rawrsocketservice │ │ └── RawRsocketServiceApplicationTests.java ├── rsocket-client │ ├── .mvn │ │ └── wrapper │ │ │ ├── MavenWrapperDownloader.java │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── HELP.md │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── rsocketclient │ │ │ │ └── RsocketClientApplication.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── rsocketclient │ │ └── RsocketClientApplicationTests.java └── rsocket-service │ ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties │ ├── HELP.md │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── rsocketservice │ │ │ └── RsocketServiceApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── example │ └── rsocketservice │ └── RsocketServiceApplicationTests.java ├── 7.0 ├── secure-http-client │ ├── .mvn │ │ └── wrapper │ │ │ ├── MavenWrapperDownloader.java │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── http │ │ │ │ └── HttpApplication.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── http │ │ └── HttpApplicationTests.java ├── secure-http-service │ ├── .mvn │ │ └── wrapper │ │ │ ├── MavenWrapperDownloader.java │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── http │ │ │ │ └── HttpApplication.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── http │ │ └── HttpApplicationTests.java ├── secure-rsocket-client │ ├── .mvn │ │ └── wrapper │ │ │ ├── MavenWrapperDownloader.java │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── HELP.md │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── rsocketclient │ │ │ │ └── RsocketClientApplication.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── rsocketclient │ │ └── RsocketClientApplicationTests.java └── secure-rsocket-service │ ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties │ ├── HELP.md │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── rsocketservice │ │ │ └── RsocketServiceApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── example │ └── rsocketservice │ └── RsocketServiceApplicationTests.java ├── 8.0 ├── http │ ├── http-gateway │ │ ├── .mvn │ │ │ └── wrapper │ │ │ │ ├── MavenWrapperDownloader.java │ │ │ │ ├── maven-wrapper.jar │ │ │ │ └── maven-wrapper.properties │ │ ├── HELP.md │ │ ├── mvnw │ │ ├── mvnw.cmd │ │ ├── pom.xml │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── httpgateway │ │ │ │ │ └── HttpGatewayApplication.java │ │ │ └── resources │ │ │ │ └── application.properties │ │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── example │ │ │ └── httpgateway │ │ │ └── HttpGatewayApplicationTests.java │ └── reservation-service │ │ ├── .mvn │ │ └── wrapper │ │ │ ├── MavenWrapperDownloader.java │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ │ ├── HELP.md │ │ ├── mvnw │ │ ├── mvnw.cmd │ │ ├── pom.xml │ │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── reservationservice │ │ │ │ └── ReservationServiceApplication.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── reservationservice │ │ └── ReservationServiceApplicationTests.java ├── rsocket-gateway-deps.md └── rsocket │ ├── greetings-client │ ├── .mvn │ │ └── wrapper │ │ │ ├── MavenWrapperDownloader.java │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── HELP.md │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── greetingsclient │ │ │ │ └── GreetingsClientApplication.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── greetingsservice │ │ └── GreetingsServiceApplicationTests.java │ ├── greetings-service │ ├── .mvn │ │ └── wrapper │ │ │ ├── MavenWrapperDownloader.java │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── HELP.md │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── greetingsservice │ │ │ │ └── GreetingsServiceApplication.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── greetingsservice │ │ └── GreetingsServiceApplicationTests.java │ └── rsocket-gateway │ ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties │ ├── HELP.md │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── rsocketgateway │ │ │ └── RsocketGatewayApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── example │ └── rsocketgateway │ └── RsocketGatewayApplicationTests.java ├── 9.0 ├── 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 │ │ │ │ ├── Reservation.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 │ │ ├── ReservationPojoTest.java │ │ └── ReservationRepositoryTest.java │ └── resources │ └── contracts │ └── shouldReturnAllReservations.groovy └── reactive-spring.md /1.0/demo/.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import java.net.*; 17 | import java.io.*; 18 | import java.nio.channels.*; 19 | import java.util.Properties; 20 | 21 | public class MavenWrapperDownloader { 22 | 23 | private static final String WRAPPER_VERSION = "0.5.5"; 24 | /** 25 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 26 | */ 27 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 28 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 29 | 30 | /** 31 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 32 | * use instead of the default one. 33 | */ 34 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 35 | ".mvn/wrapper/maven-wrapper.properties"; 36 | 37 | /** 38 | * Path where the maven-wrapper.jar will be saved to. 39 | */ 40 | private static final String MAVEN_WRAPPER_JAR_PATH = 41 | ".mvn/wrapper/maven-wrapper.jar"; 42 | 43 | /** 44 | * Name of the property which should be used to override the default download url for the wrapper. 45 | */ 46 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 47 | 48 | public static void main(String args[]) { 49 | System.out.println("- Downloader started"); 50 | File baseDirectory = new File(args[0]); 51 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 52 | 53 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 54 | // wrapperUrl parameter. 55 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 56 | String url = DEFAULT_DOWNLOAD_URL; 57 | if(mavenWrapperPropertyFile.exists()) { 58 | FileInputStream mavenWrapperPropertyFileInputStream = null; 59 | try { 60 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 61 | Properties mavenWrapperProperties = new Properties(); 62 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 63 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 64 | } catch (IOException e) { 65 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 66 | } finally { 67 | try { 68 | if(mavenWrapperPropertyFileInputStream != null) { 69 | mavenWrapperPropertyFileInputStream.close(); 70 | } 71 | } catch (IOException e) { 72 | // Ignore ... 73 | } 74 | } 75 | } 76 | System.out.println("- Downloading from: " + url); 77 | 78 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 79 | if(!outputFile.getParentFile().exists()) { 80 | if(!outputFile.getParentFile().mkdirs()) { 81 | System.out.println( 82 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 83 | } 84 | } 85 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 86 | try { 87 | downloadFileFromURL(url, outputFile); 88 | System.out.println("Done"); 89 | System.exit(0); 90 | } catch (Throwable e) { 91 | System.out.println("- Error downloading"); 92 | e.printStackTrace(); 93 | System.exit(1); 94 | } 95 | } 96 | 97 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 98 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 99 | String username = System.getenv("MVNW_USERNAME"); 100 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 101 | Authenticator.setDefault(new Authenticator() { 102 | @Override 103 | protected PasswordAuthentication getPasswordAuthentication() { 104 | return new PasswordAuthentication(username, password); 105 | } 106 | }); 107 | } 108 | URL website = new URL(urlString); 109 | ReadableByteChannel rbc; 110 | rbc = Channels.newChannel(website.openStream()); 111 | FileOutputStream fos = new FileOutputStream(destination); 112 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 113 | fos.close(); 114 | rbc.close(); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /1.0/demo/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong/reactive-spring-livelessons-2e/f10c568102d0634a050639973ba99f632580392f/1.0/demo/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /1.0/demo/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar 3 | -------------------------------------------------------------------------------- /1.0/demo/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.2.RELEASE 9 | 10 | 11 | com.example 12 | demo 13 | 0.0.1-SNAPSHOT 14 | demo 15 | Demo project for Spring Boot 16 | 17 | 18 | 13 19 | Hoxton.RELEASE 20 | 21 | 22 | 23 | 24 | org.springframework.boot.experimental 25 | spring-boot-actuator-autoconfigure-r2dbc 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-actuator 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-data-mongodb-reactive 34 | 35 | 36 | org.springframework.boot.experimental 37 | spring-boot-starter-data-r2dbc 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-starter-rsocket 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-starter-webflux 46 | 47 | 48 | org.springframework.cloud 49 | spring-cloud-starter-gateway 50 | 51 | 52 | 53 | org.projectlombok 54 | lombok 55 | true 56 | 57 | 58 | org.springframework.boot 59 | spring-boot-starter-test 60 | test 61 | 62 | 63 | org.junit.vintage 64 | junit-vintage-engine 65 | 66 | 67 | 68 | 69 | org.springframework.boot.experimental 70 | spring-boot-test-autoconfigure-r2dbc 71 | test 72 | 73 | 74 | io.projectreactor 75 | reactor-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 | org.springframework.boot.experimental 91 | spring-boot-bom-r2dbc 92 | 0.1.0.M3 93 | pom 94 | import 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | org.springframework.boot 103 | spring-boot-maven-plugin 104 | 105 | 106 | 107 | 108 | 109 | 110 | spring-milestones 111 | Spring Milestones 112 | https://repo.spring.io/milestone 113 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /1.0/demo/src/main/java/com/example/demo/DemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class DemoApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(DemoApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /1.0/demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /1.0/demo/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 | -------------------------------------------------------------------------------- /2.0/data/.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import java.net.*; 17 | import java.io.*; 18 | import java.nio.channels.*; 19 | import java.util.Properties; 20 | 21 | public class MavenWrapperDownloader { 22 | 23 | private static final String WRAPPER_VERSION = "0.5.5"; 24 | /** 25 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 26 | */ 27 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 28 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 29 | 30 | /** 31 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 32 | * use instead of the default one. 33 | */ 34 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 35 | ".mvn/wrapper/maven-wrapper.properties"; 36 | 37 | /** 38 | * Path where the maven-wrapper.jar will be saved to. 39 | */ 40 | private static final String MAVEN_WRAPPER_JAR_PATH = 41 | ".mvn/wrapper/maven-wrapper.jar"; 42 | 43 | /** 44 | * Name of the property which should be used to override the default download url for the wrapper. 45 | */ 46 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 47 | 48 | public static void main(String args[]) { 49 | System.out.println("- Downloader started"); 50 | File baseDirectory = new File(args[0]); 51 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 52 | 53 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 54 | // wrapperUrl parameter. 55 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 56 | String url = DEFAULT_DOWNLOAD_URL; 57 | if(mavenWrapperPropertyFile.exists()) { 58 | FileInputStream mavenWrapperPropertyFileInputStream = null; 59 | try { 60 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 61 | Properties mavenWrapperProperties = new Properties(); 62 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 63 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 64 | } catch (IOException e) { 65 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 66 | } finally { 67 | try { 68 | if(mavenWrapperPropertyFileInputStream != null) { 69 | mavenWrapperPropertyFileInputStream.close(); 70 | } 71 | } catch (IOException e) { 72 | // Ignore ... 73 | } 74 | } 75 | } 76 | System.out.println("- Downloading from: " + url); 77 | 78 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 79 | if(!outputFile.getParentFile().exists()) { 80 | if(!outputFile.getParentFile().mkdirs()) { 81 | System.out.println( 82 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 83 | } 84 | } 85 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 86 | try { 87 | downloadFileFromURL(url, outputFile); 88 | System.out.println("Done"); 89 | System.exit(0); 90 | } catch (Throwable e) { 91 | System.out.println("- Error downloading"); 92 | e.printStackTrace(); 93 | System.exit(1); 94 | } 95 | } 96 | 97 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 98 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 99 | String username = System.getenv("MVNW_USERNAME"); 100 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 101 | Authenticator.setDefault(new Authenticator() { 102 | @Override 103 | protected PasswordAuthentication getPasswordAuthentication() { 104 | return new PasswordAuthentication(username, password); 105 | } 106 | }); 107 | } 108 | URL website = new URL(urlString); 109 | ReadableByteChannel rbc; 110 | rbc = Channels.newChannel(website.openStream()); 111 | FileOutputStream fos = new FileOutputStream(destination); 112 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 113 | fos.close(); 114 | rbc.close(); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /2.0/data/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong/reactive-spring-livelessons-2e/f10c568102d0634a050639973ba99f632580392f/2.0/data/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /2.0/data/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar 3 | -------------------------------------------------------------------------------- /2.0/data/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.2.RELEASE 9 | 10 | 11 | com.example 12 | data 13 | 0.0.1-SNAPSHOT 14 | data 15 | Demo project for Spring Boot 16 | 17 | 18 | 13 19 | 20 | 21 | 22 | 26 | 27 | 28 | io.r2dbc 29 | r2dbc-postgresql 30 | runtime 31 | 32 | 33 | org.springframework.boot.experimental 34 | spring-boot-starter-data-r2dbc 35 | 36 | 37 | 38 | org.springframework.boot 39 | spring-boot-starter-webflux 40 | 41 | 42 | 43 | org.projectlombok 44 | lombok 45 | true 46 | 47 | 48 | org.springframework.boot 49 | spring-boot-starter-test 50 | test 51 | 52 | 53 | org.junit.vintage 54 | junit-vintage-engine 55 | 56 | 57 | 58 | 59 | org.springframework.boot.experimental 60 | spring-boot-test-autoconfigure-r2dbc 61 | test 62 | 63 | 64 | io.projectreactor 65 | reactor-test 66 | test 67 | 68 | 69 | 70 | 71 | 72 | 73 | org.springframework.boot.experimental 74 | spring-boot-bom-r2dbc 75 | 0.1.0.M3 76 | pom 77 | import 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | org.springframework.boot 86 | spring-boot-maven-plugin 87 | 88 | 89 | 90 | 91 | 92 | 93 | spring-milestones 94 | Spring Milestones 95 | https://repo.spring.io/milestone 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /2.0/data/src/main/java/com/example/data/DataApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.data; 2 | 3 | import io.r2dbc.spi.ConnectionFactory; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | import lombok.RequiredArgsConstructor; 8 | import lombok.extern.log4j.Log4j2; 9 | import org.springframework.boot.SpringApplication; 10 | import org.springframework.boot.autoconfigure.SpringBootApplication; 11 | import org.springframework.boot.context.event.ApplicationReadyEvent; 12 | import org.springframework.context.annotation.Bean; 13 | import org.springframework.context.event.EventListener; 14 | import org.springframework.data.annotation.Id; 15 | import org.springframework.data.r2dbc.connectionfactory.R2dbcTransactionManager; 16 | import org.springframework.data.r2dbc.core.DatabaseClient; 17 | import org.springframework.data.r2dbc.repository.Query; 18 | import org.springframework.data.repository.reactive.ReactiveCrudRepository; 19 | import org.springframework.stereotype.Component; 20 | import org.springframework.stereotype.Service; 21 | import org.springframework.transaction.ReactiveTransactionManager; 22 | import org.springframework.transaction.annotation.EnableTransactionManagement; 23 | import org.springframework.transaction.annotation.Transactional; 24 | import org.springframework.transaction.reactive.TransactionalOperator; 25 | import org.springframework.util.Assert; 26 | import reactor.core.publisher.Flux; 27 | import reactor.util.context.Context; 28 | 29 | import java.util.UUID; 30 | 31 | @SpringBootApplication 32 | @EnableTransactionManagement 33 | public class DataApplication { 34 | 35 | @Bean 36 | TransactionalOperator transactionalOperator(ReactiveTransactionManager rtm) { 37 | return TransactionalOperator.create(rtm); 38 | } 39 | 40 | @Bean 41 | ReactiveTransactionManager r2dbcTransactionManager(ConnectionFactory cf) { 42 | return new R2dbcTransactionManager(cf); 43 | } 44 | 45 | public static void main(String[] args) { 46 | SpringApplication.run(DataApplication.class, args); 47 | } 48 | 49 | } 50 | 51 | @Service 52 | @Transactional 53 | @RequiredArgsConstructor 54 | class ReservationService { 55 | 56 | private final ReservationRepository reservationRepository; 57 | private final TransactionalOperator transactionalOperator; 58 | 59 | public Flux saveAll(String... names) { 60 | Flux reservations = Flux 61 | .fromArray(names) 62 | .map(name -> new Reservation(null, name)) 63 | .flatMap(this.reservationRepository::save) 64 | .doOnNext(this::assertValid); 65 | return reservations; 66 | } 67 | 68 | private void assertValid(Reservation r) { 69 | Assert.isTrue(r.getName() != null && r.getName().length() > 0 70 | && Character.isUpperCase(r.getName().charAt(0)), "the name must start with a capital letter"); 71 | } 72 | } 73 | 74 | @Component 75 | @RequiredArgsConstructor 76 | @Log4j2 77 | class SampleDataInitializer { 78 | 79 | private final ReservationRepository reservationRepository; 80 | private final ReservationService reservationService; 81 | private final DatabaseClient databaseClient; 82 | 83 | @EventListener(ApplicationReadyEvent.class) 84 | public void ready() { 85 | 86 | Flux reservations = reservationService 87 | .saveAll("Madhura", "josh", "Olga", "Marcin", "Ria", "Stéphane", "Violetta", "Dr. Syer"); 88 | 89 | this.reservationRepository 90 | .deleteAll() 91 | .thenMany(reservations) 92 | .thenMany(this.reservationRepository.findAll()) 93 | .subscribe(log::info); 94 | } 95 | } 96 | 97 | interface ReservationRepository extends ReactiveCrudRepository { 98 | 99 | // @Query("select * from reservation where name = $1 ") 100 | // Flux findByName(String name); 101 | } 102 | 103 | 104 | @Data 105 | @AllArgsConstructor 106 | @NoArgsConstructor 107 | class Reservation { 108 | 109 | @Id 110 | private Integer id; 111 | private String name; 112 | } -------------------------------------------------------------------------------- /2.0/data/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.r2dbc.url=r2dbc:postgres://localhost/orders 2 | spring.r2dbc.username=orders 3 | spring.r2dbc.password=orders 4 | -------------------------------------------------------------------------------- /2.0/data/src/test/java/com/example/data/DataApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.data; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class DataApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /3.0/.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import java.net.*; 17 | import java.io.*; 18 | import java.nio.channels.*; 19 | import java.util.Properties; 20 | 21 | public class MavenWrapperDownloader { 22 | 23 | private static final String WRAPPER_VERSION = "0.5.5"; 24 | /** 25 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 26 | */ 27 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 28 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 29 | 30 | /** 31 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 32 | * use instead of the default one. 33 | */ 34 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 35 | ".mvn/wrapper/maven-wrapper.properties"; 36 | 37 | /** 38 | * Path where the maven-wrapper.jar will be saved to. 39 | */ 40 | private static final String MAVEN_WRAPPER_JAR_PATH = 41 | ".mvn/wrapper/maven-wrapper.jar"; 42 | 43 | /** 44 | * Name of the property which should be used to override the default download url for the wrapper. 45 | */ 46 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 47 | 48 | public static void main(String args[]) { 49 | System.out.println("- Downloader started"); 50 | File baseDirectory = new File(args[0]); 51 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 52 | 53 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 54 | // wrapperUrl parameter. 55 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 56 | String url = DEFAULT_DOWNLOAD_URL; 57 | if(mavenWrapperPropertyFile.exists()) { 58 | FileInputStream mavenWrapperPropertyFileInputStream = null; 59 | try { 60 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 61 | Properties mavenWrapperProperties = new Properties(); 62 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 63 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 64 | } catch (IOException e) { 65 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 66 | } finally { 67 | try { 68 | if(mavenWrapperPropertyFileInputStream != null) { 69 | mavenWrapperPropertyFileInputStream.close(); 70 | } 71 | } catch (IOException e) { 72 | // Ignore ... 73 | } 74 | } 75 | } 76 | System.out.println("- Downloading from: " + url); 77 | 78 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 79 | if(!outputFile.getParentFile().exists()) { 80 | if(!outputFile.getParentFile().mkdirs()) { 81 | System.out.println( 82 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 83 | } 84 | } 85 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 86 | try { 87 | downloadFileFromURL(url, outputFile); 88 | System.out.println("Done"); 89 | System.exit(0); 90 | } catch (Throwable e) { 91 | System.out.println("- Error downloading"); 92 | e.printStackTrace(); 93 | System.exit(1); 94 | } 95 | } 96 | 97 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 98 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 99 | String username = System.getenv("MVNW_USERNAME"); 100 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 101 | Authenticator.setDefault(new Authenticator() { 102 | @Override 103 | protected PasswordAuthentication getPasswordAuthentication() { 104 | return new PasswordAuthentication(username, password); 105 | } 106 | }); 107 | } 108 | URL website = new URL(urlString); 109 | ReadableByteChannel rbc; 110 | rbc = Channels.newChannel(website.openStream()); 111 | FileOutputStream fos = new FileOutputStream(destination); 112 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 113 | fos.close(); 114 | rbc.close(); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /3.0/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong/reactive-spring-livelessons-2e/f10c568102d0634a050639973ba99f632580392f/3.0/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /3.0/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar 3 | -------------------------------------------------------------------------------- /3.0/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.2.RELEASE 9 | 10 | 11 | com.example 12 | http 13 | 0.0.1-SNAPSHOT 14 | http 15 | Demo project for Spring Boot 16 | 17 | 18 | 13 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-webflux 25 | 26 | 27 | org.projectlombok 28 | lombok 29 | true 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-test 34 | test 35 | 36 | 37 | org.junit.vintage 38 | junit-vintage-engine 39 | 40 | 41 | 42 | 43 | io.projectreactor 44 | reactor-test 45 | test 46 | 47 | 48 | 49 | 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-maven-plugin 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /3.0/src/main/java/com/example/http/HttpApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.http; 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.http.MediaType; 10 | import org.springframework.stereotype.Service; 11 | import org.springframework.web.reactive.function.server.*; 12 | import reactor.core.publisher.Flux; 13 | import reactor.core.publisher.Mono; 14 | import reactor.core.scheduler.Scheduler; 15 | import reactor.core.scheduler.Schedulers; 16 | 17 | import java.time.Duration; 18 | import java.time.Instant; 19 | import java.util.function.Supplier; 20 | import java.util.stream.Stream; 21 | 22 | import static org.springframework.web.reactive.function.server.RouterFunctions.route; 23 | import static org.springframework.web.reactive.function.server.ServerResponse.*; 24 | 25 | @SpringBootApplication 26 | public class HttpApplication { 27 | 28 | @Bean 29 | RouterFunction routes(GreetingService gs) { 30 | return route() 31 | .GET("/greeting/{name}", r -> ok().body(gs.greetOnce(new GreetingRequest(r.pathVariable("name"))), GreetingResponse.class)) 32 | .GET("/greetings/{name}", r -> ok().contentType(MediaType.TEXT_EVENT_STREAM).body(gs.greetMany(new GreetingRequest(r.pathVariable("name"))), GreetingResponse.class) 33 | ) 34 | .build(); 35 | } 36 | 37 | public static void main(String[] args) { 38 | SpringApplication.run(HttpApplication.class, args); 39 | } 40 | } 41 | 42 | /* 43 | @RestController 44 | @RequiredArgsConstructor 45 | class GreetingsRestController { 46 | 47 | private final GreetingService greetingService; 48 | 49 | @GetMapping("/greeting/{name}") 50 | Mono greet(@PathVariable String name) { 51 | return this.greetingService.greet(new GreetingRequest(name)); 52 | } 53 | } 54 | 55 | */ 56 | @Service 57 | class GreetingService { 58 | 59 | Flux greetMany(GreetingRequest request) { 60 | return Flux 61 | .fromStream(Stream.generate(() -> greet(request.getName()))) 62 | .delayElements(Duration.ofSeconds(1)) 63 | .subscribeOn(Schedulers.elastic()); 64 | } 65 | 66 | Mono greetOnce(GreetingRequest request) { 67 | return Mono.just(greet(request.getName())); 68 | } 69 | 70 | private GreetingResponse greet(String name) { 71 | return new GreetingResponse("Hello " + name + " @ " + Instant.now()); 72 | } 73 | } 74 | 75 | @Data 76 | @AllArgsConstructor 77 | @NoArgsConstructor 78 | class GreetingResponse { 79 | private String message; 80 | } 81 | 82 | @Data 83 | @AllArgsConstructor 84 | @NoArgsConstructor 85 | class GreetingRequest { 86 | private String name; 87 | } 88 | 89 | -------------------------------------------------------------------------------- /3.0/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /3.0/src/test/java/com/example/http/HttpApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.http; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class HttpApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /4.0/.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import java.net.*; 17 | import java.io.*; 18 | import java.nio.channels.*; 19 | import java.util.Properties; 20 | 21 | public class MavenWrapperDownloader { 22 | 23 | private static final String WRAPPER_VERSION = "0.5.5"; 24 | /** 25 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 26 | */ 27 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 28 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 29 | 30 | /** 31 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 32 | * use instead of the default one. 33 | */ 34 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 35 | ".mvn/wrapper/maven-wrapper.properties"; 36 | 37 | /** 38 | * Path where the maven-wrapper.jar will be saved to. 39 | */ 40 | private static final String MAVEN_WRAPPER_JAR_PATH = 41 | ".mvn/wrapper/maven-wrapper.jar"; 42 | 43 | /** 44 | * Name of the property which should be used to override the default download url for the wrapper. 45 | */ 46 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 47 | 48 | public static void main(String args[]) { 49 | System.out.println("- Downloader started"); 50 | File baseDirectory = new File(args[0]); 51 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 52 | 53 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 54 | // wrapperUrl parameter. 55 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 56 | String url = DEFAULT_DOWNLOAD_URL; 57 | if(mavenWrapperPropertyFile.exists()) { 58 | FileInputStream mavenWrapperPropertyFileInputStream = null; 59 | try { 60 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 61 | Properties mavenWrapperProperties = new Properties(); 62 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 63 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 64 | } catch (IOException e) { 65 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 66 | } finally { 67 | try { 68 | if(mavenWrapperPropertyFileInputStream != null) { 69 | mavenWrapperPropertyFileInputStream.close(); 70 | } 71 | } catch (IOException e) { 72 | // Ignore ... 73 | } 74 | } 75 | } 76 | System.out.println("- Downloading from: " + url); 77 | 78 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 79 | if(!outputFile.getParentFile().exists()) { 80 | if(!outputFile.getParentFile().mkdirs()) { 81 | System.out.println( 82 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 83 | } 84 | } 85 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 86 | try { 87 | downloadFileFromURL(url, outputFile); 88 | System.out.println("Done"); 89 | System.exit(0); 90 | } catch (Throwable e) { 91 | System.out.println("- Error downloading"); 92 | e.printStackTrace(); 93 | System.exit(1); 94 | } 95 | } 96 | 97 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 98 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 99 | String username = System.getenv("MVNW_USERNAME"); 100 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 101 | Authenticator.setDefault(new Authenticator() { 102 | @Override 103 | protected PasswordAuthentication getPasswordAuthentication() { 104 | return new PasswordAuthentication(username, password); 105 | } 106 | }); 107 | } 108 | URL website = new URL(urlString); 109 | ReadableByteChannel rbc; 110 | rbc = Channels.newChannel(website.openStream()); 111 | FileOutputStream fos = new FileOutputStream(destination); 112 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 113 | fos.close(); 114 | rbc.close(); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /4.0/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong/reactive-spring-livelessons-2e/f10c568102d0634a050639973ba99f632580392f/4.0/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /4.0/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar 3 | -------------------------------------------------------------------------------- /4.0/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.2.RELEASE 9 | 10 | 11 | com.example 12 | websockets 13 | 0.0.1-SNAPSHOT 14 | websockets 15 | Demo project for Spring Boot 16 | 17 | 18 | 13 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 | 43 | 44 | io.projectreactor 45 | reactor-test 46 | test 47 | 48 | 49 | 50 | 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-maven-plugin 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /4.0/src/main/java/com/example/websockets/WebsocketsApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.websockets; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.extern.log4j.Log4j2; 7 | import org.springframework.boot.SpringApplication; 8 | import org.springframework.boot.autoconfigure.SpringBootApplication; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | import org.springframework.stereotype.Service; 12 | import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping; 13 | import org.springframework.web.reactive.socket.WebSocketHandler; 14 | import org.springframework.web.reactive.socket.WebSocketMessage; 15 | import org.springframework.web.reactive.socket.WebSocketSession; 16 | import org.springframework.web.reactive.socket.server.support.WebSocketHandlerAdapter; 17 | import reactor.core.publisher.Flux; 18 | import reactor.core.publisher.Mono; 19 | 20 | import java.time.Duration; 21 | import java.time.Instant; 22 | import java.util.Map; 23 | import java.util.function.Supplier; 24 | import java.util.stream.Stream; 25 | 26 | @SpringBootApplication 27 | public class WebsocketsApplication { 28 | 29 | 30 | public static void main(String[] args) { 31 | SpringApplication.run(WebsocketsApplication.class, args); 32 | } 33 | 34 | } 35 | 36 | @Log4j2 37 | @Configuration 38 | class GreetingWebSocketConfiguration { 39 | 40 | @Bean 41 | SimpleUrlHandlerMapping simpleUrlHandlerMapping(WebSocketHandler wsh) { 42 | return new SimpleUrlHandlerMapping(Map.of("/ws/greetings", wsh), 10); 43 | } 44 | 45 | @Bean 46 | WebSocketHandler webSocketHandler(GreetingService greetingService) { 47 | return session -> { 48 | var receive = session 49 | .receive() 50 | .map(WebSocketMessage::getPayloadAsText) 51 | .map(GreetingRequest::new) 52 | .flatMap(greetingService::greet) 53 | .map(GreetingResponse::getMessage) 54 | .map(session::textMessage) 55 | .doOnEach(signal -> log.info(signal.getType())) 56 | .doFinally(signal -> log.info("finally: " + signal.toString())); 57 | return session.send(receive); 58 | }; 59 | } 60 | 61 | @Bean 62 | WebSocketHandlerAdapter webSocketHandlerAdapter() { 63 | return new WebSocketHandlerAdapter(); 64 | } 65 | 66 | } 67 | 68 | @Service 69 | class GreetingService { 70 | 71 | Flux greet(GreetingRequest request) { 72 | return Flux 73 | .fromStream(Stream.generate(() -> new GreetingResponse("Hello " + request.getName() + " @ " + Instant.now()))) 74 | .delayElements(Duration.ofSeconds(1)); 75 | } 76 | } 77 | 78 | @Data 79 | @AllArgsConstructor 80 | @NoArgsConstructor 81 | class GreetingRequest { 82 | private String name; 83 | } 84 | 85 | @Data 86 | @AllArgsConstructor 87 | @NoArgsConstructor 88 | class GreetingResponse { 89 | private String message; 90 | } 91 | -------------------------------------------------------------------------------- /4.0/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /4.0/src/main/resources/static/ws.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | 16 | -------------------------------------------------------------------------------- /4.0/src/test/java/com/example/websockets/WebsocketsApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.websockets; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class WebsocketsApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /5.0/greeting-client/.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import java.net.*; 17 | import java.io.*; 18 | import java.nio.channels.*; 19 | import java.util.Properties; 20 | 21 | public class MavenWrapperDownloader { 22 | 23 | private static final String WRAPPER_VERSION = "0.5.5"; 24 | /** 25 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 26 | */ 27 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 28 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 29 | 30 | /** 31 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 32 | * use instead of the default one. 33 | */ 34 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 35 | ".mvn/wrapper/maven-wrapper.properties"; 36 | 37 | /** 38 | * Path where the maven-wrapper.jar will be saved to. 39 | */ 40 | private static final String MAVEN_WRAPPER_JAR_PATH = 41 | ".mvn/wrapper/maven-wrapper.jar"; 42 | 43 | /** 44 | * Name of the property which should be used to override the default download url for the wrapper. 45 | */ 46 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 47 | 48 | public static void main(String args[]) { 49 | System.out.println("- Downloader started"); 50 | File baseDirectory = new File(args[0]); 51 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 52 | 53 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 54 | // wrapperUrl parameter. 55 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 56 | String url = DEFAULT_DOWNLOAD_URL; 57 | if(mavenWrapperPropertyFile.exists()) { 58 | FileInputStream mavenWrapperPropertyFileInputStream = null; 59 | try { 60 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 61 | Properties mavenWrapperProperties = new Properties(); 62 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 63 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 64 | } catch (IOException e) { 65 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 66 | } finally { 67 | try { 68 | if(mavenWrapperPropertyFileInputStream != null) { 69 | mavenWrapperPropertyFileInputStream.close(); 70 | } 71 | } catch (IOException e) { 72 | // Ignore ... 73 | } 74 | } 75 | } 76 | System.out.println("- Downloading from: " + url); 77 | 78 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 79 | if(!outputFile.getParentFile().exists()) { 80 | if(!outputFile.getParentFile().mkdirs()) { 81 | System.out.println( 82 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 83 | } 84 | } 85 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 86 | try { 87 | downloadFileFromURL(url, outputFile); 88 | System.out.println("Done"); 89 | System.exit(0); 90 | } catch (Throwable e) { 91 | System.out.println("- Error downloading"); 92 | e.printStackTrace(); 93 | System.exit(1); 94 | } 95 | } 96 | 97 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 98 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 99 | String username = System.getenv("MVNW_USERNAME"); 100 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 101 | Authenticator.setDefault(new Authenticator() { 102 | @Override 103 | protected PasswordAuthentication getPasswordAuthentication() { 104 | return new PasswordAuthentication(username, password); 105 | } 106 | }); 107 | } 108 | URL website = new URL(urlString); 109 | ReadableByteChannel rbc; 110 | rbc = Channels.newChannel(website.openStream()); 111 | FileOutputStream fos = new FileOutputStream(destination); 112 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 113 | fos.close(); 114 | rbc.close(); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /5.0/greeting-client/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong/reactive-spring-livelessons-2e/f10c568102d0634a050639973ba99f632580392f/5.0/greeting-client/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /5.0/greeting-client/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar 3 | -------------------------------------------------------------------------------- /5.0/greeting-client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.2.RELEASE 9 | 10 | 11 | com.example 12 | greeting-client 13 | 0.0.1-SNAPSHOT 14 | greeting-client 15 | Demo project for Spring Boot 16 | 17 | 18 | Hoxton.RELEASE 19 | 13 20 | 21 | 22 | 23 | 24 | org.springframework.cloud 25 | spring-cloud-starter-circuitbreaker-reactor-resilience4j 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-webflux 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 | org.junit.vintage 44 | junit-vintage-engine 45 | 46 | 47 | 48 | 49 | io.projectreactor 50 | reactor-test 51 | test 52 | 53 | 54 | 55 | 56 | 57 | 58 | org.springframework.boot 59 | spring-boot-maven-plugin 60 | 61 | 62 | 63 | 64 | 65 | 66 | org.springframework.cloud 67 | spring-cloud-dependencies 68 | ${spring-cloud.version} 69 | pom 70 | import 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /5.0/greeting-client/src/main/java/com/example/greetingclient/GreetingClientApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.greetingclient; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.extern.log4j.Log4j2; 7 | import org.springframework.boot.SpringApplication; 8 | import org.springframework.boot.autoconfigure.SpringBootApplication; 9 | import org.springframework.boot.context.event.ApplicationReadyEvent; 10 | import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreaker; 11 | import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreakerFactory; 12 | import org.springframework.context.annotation.Bean; 13 | import org.springframework.context.event.EventListener; 14 | import org.springframework.stereotype.Component; 15 | import org.springframework.web.reactive.function.client.*; 16 | import reactor.core.publisher.Flux; 17 | import reactor.core.publisher.Mono; 18 | 19 | import java.time.Duration; 20 | 21 | @SpringBootApplication 22 | public class GreetingClientApplication { 23 | 24 | public static void main(String[] args) { 25 | SpringApplication.run(GreetingClientApplication.class, args); 26 | } 27 | 28 | @Bean 29 | WebClient webClient(WebClient.Builder builder) { 30 | return builder 31 | .baseUrl("http://localhost:8080") 32 | // .filter( ExchangeFilterFunctions.basicAuthentication()) 33 | .build(); 34 | } 35 | 36 | } 37 | 38 | @Component 39 | @Log4j2 40 | //@RequiredArgsConstructor 41 | class Client { 42 | 43 | private final WebClient client; 44 | private final ReactiveCircuitBreaker reactiveCircuitBreaker; 45 | 46 | Client(WebClient client, ReactiveCircuitBreakerFactory cbf) { 47 | this.client = client; 48 | this.reactiveCircuitBreaker = cbf.create("greeting"); 49 | } 50 | 51 | @EventListener(ApplicationReadyEvent.class) 52 | public void ready() { 53 | 54 | 55 | // Flux host1 = null;//todo 56 | // Flux host2 = null;//todo 57 | // Flux host3 = null;//todo 58 | // 59 | // Flux first = Flux.first(host1, host2, host3); 60 | 61 | var name = "Spring Fans"; 62 | 63 | Mono http = this.client 64 | .get() 65 | .uri("/greeting/{name}", name) 66 | .retrieve() 67 | .bodyToMono(GreetingResponse.class) 68 | .timeout(Duration.ofSeconds(10)) 69 | .map(GreetingResponse::getMessage); 70 | 71 | this.reactiveCircuitBreaker 72 | .run(http, throwable -> Mono.just("EEEK!")) 73 | .subscribe(gr -> log.info("Mono: " + gr)); 74 | 75 | } 76 | } 77 | 78 | 79 | @Data 80 | @AllArgsConstructor 81 | @NoArgsConstructor 82 | class GreetingRequest { 83 | private String name; 84 | } 85 | 86 | @Data 87 | @AllArgsConstructor 88 | @NoArgsConstructor 89 | class GreetingResponse { 90 | private String message; 91 | } -------------------------------------------------------------------------------- /5.0/greeting-client/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=0 2 | -------------------------------------------------------------------------------- /5.0/greeting-client/src/test/java/com/example/greetingclient/GreetingClientApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.greetingclient; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class GreetingClientApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /5.0/greeting-service/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong/reactive-spring-livelessons-2e/f10c568102d0634a050639973ba99f632580392f/5.0/greeting-service/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /5.0/greeting-service/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar 3 | -------------------------------------------------------------------------------- /5.0/greeting-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.2.RELEASE 9 | 10 | 11 | com.example 12 | greeting-service 13 | 0.0.1-SNAPSHOT 14 | greeting-service 15 | Demo project for Spring Boot 16 | 17 | 18 | 13 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 | 43 | 44 | io.projectreactor 45 | reactor-test 46 | test 47 | 48 | 49 | 50 | 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-maven-plugin 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /5.0/greeting-service/src/main/java/com/example/greetingservice/GreetingServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.greetingservice; 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.http.MediaType; 10 | import org.springframework.stereotype.Service; 11 | import org.springframework.web.reactive.function.server.HandlerFunction; 12 | import org.springframework.web.reactive.function.server.RouterFunction; 13 | import org.springframework.web.reactive.function.server.ServerRequest; 14 | import org.springframework.web.reactive.function.server.ServerResponse; 15 | import reactor.core.publisher.Flux; 16 | import reactor.core.publisher.Mono; 17 | 18 | import java.time.Duration; 19 | import java.time.Instant; 20 | import java.util.function.Supplier; 21 | import java.util.stream.Stream; 22 | 23 | import static org.springframework.web.reactive.function.server.RouterFunctions.resourceLookupFunction; 24 | import static org.springframework.web.reactive.function.server.RouterFunctions.route; 25 | import static org.springframework.web.reactive.function.server.ServerResponse.*; 26 | 27 | @SpringBootApplication 28 | public class GreetingServiceApplication { 29 | 30 | public static void main(String[] args) { 31 | SpringApplication.run(GreetingServiceApplication.class, args); 32 | } 33 | 34 | @Bean 35 | RouterFunction routes(GreetingService greetingService) { 36 | return route() 37 | .GET("/greeting/{name}", serverRequest -> ok().body( 38 | greetingService.greetOnce(new GreetingRequest(serverRequest.pathVariable("name"))), GreetingResponse.class)) 39 | .GET("/greetings/{name}", serverRequest -> ok().contentType(MediaType.TEXT_EVENT_STREAM).body( 40 | greetingService.greetMany(new GreetingRequest(serverRequest.pathVariable("name"))), GreetingResponse.class)) 41 | .build(); 42 | } 43 | 44 | } 45 | 46 | @Data 47 | @AllArgsConstructor 48 | @NoArgsConstructor 49 | class GreetingRequest { 50 | private String name; 51 | } 52 | 53 | @Data 54 | @AllArgsConstructor 55 | @NoArgsConstructor 56 | class GreetingResponse { 57 | private String message; 58 | } 59 | 60 | @Service 61 | class GreetingService { 62 | 63 | Mono greetOnce(GreetingRequest request) { 64 | return Mono.just(greet(request.getName())); 65 | } 66 | 67 | Flux greetMany(GreetingRequest request) { 68 | return Flux 69 | .fromStream(Stream.generate(() -> greet(request.getName()))) 70 | .delayElements(Duration.ofSeconds(1)); 71 | } 72 | 73 | private GreetingResponse greet(String name) { 74 | return new GreetingResponse("Hello " + name + " @ " + Instant.now() + "!"); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /5.0/greeting-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /5.0/greeting-service/src/test/java/com/example/greetingservice/GreetingServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.greetingservice; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class GreetingServiceApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /6.0/raw-rsocket-client/.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import java.net.*; 18 | import java.io.*; 19 | import java.nio.channels.*; 20 | import java.util.Properties; 21 | 22 | public class MavenWrapperDownloader { 23 | 24 | private static final String WRAPPER_VERSION = "0.5.5"; 25 | /** 26 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 27 | */ 28 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 29 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 30 | 31 | /** 32 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 33 | * use instead of the default one. 34 | */ 35 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 36 | ".mvn/wrapper/maven-wrapper.properties"; 37 | 38 | /** 39 | * Path where the maven-wrapper.jar will be saved to. 40 | */ 41 | private static final String MAVEN_WRAPPER_JAR_PATH = 42 | ".mvn/wrapper/maven-wrapper.jar"; 43 | 44 | /** 45 | * Name of the property which should be used to override the default download url for the wrapper. 46 | */ 47 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 48 | 49 | public static void main(String args[]) { 50 | System.out.println("- Downloader started"); 51 | File baseDirectory = new File(args[0]); 52 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 53 | 54 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 55 | // wrapperUrl parameter. 56 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 57 | String url = DEFAULT_DOWNLOAD_URL; 58 | if (mavenWrapperPropertyFile.exists()) { 59 | FileInputStream mavenWrapperPropertyFileInputStream = null; 60 | try { 61 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 62 | Properties mavenWrapperProperties = new Properties(); 63 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 64 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 65 | } catch (IOException e) { 66 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 67 | } finally { 68 | try { 69 | if (mavenWrapperPropertyFileInputStream != null) { 70 | mavenWrapperPropertyFileInputStream.close(); 71 | } 72 | } catch (IOException e) { 73 | // Ignore ... 74 | } 75 | } 76 | } 77 | System.out.println("- Downloading from: " + url); 78 | 79 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 80 | if (!outputFile.getParentFile().exists()) { 81 | if (!outputFile.getParentFile().mkdirs()) { 82 | System.out.println( 83 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 84 | } 85 | } 86 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 87 | try { 88 | downloadFileFromURL(url, outputFile); 89 | System.out.println("Done"); 90 | System.exit(0); 91 | } catch (Throwable e) { 92 | System.out.println("- Error downloading"); 93 | e.printStackTrace(); 94 | System.exit(1); 95 | } 96 | } 97 | 98 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 99 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 100 | String username = System.getenv("MVNW_USERNAME"); 101 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 102 | Authenticator.setDefault(new Authenticator() { 103 | @Override 104 | protected PasswordAuthentication getPasswordAuthentication() { 105 | return new PasswordAuthentication(username, password); 106 | } 107 | }); 108 | } 109 | URL website = new URL(urlString); 110 | ReadableByteChannel rbc; 111 | rbc = Channels.newChannel(website.openStream()); 112 | FileOutputStream fos = new FileOutputStream(destination); 113 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 114 | fos.close(); 115 | rbc.close(); 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /6.0/raw-rsocket-client/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong/reactive-spring-livelessons-2e/f10c568102d0634a050639973ba99f632580392f/6.0/raw-rsocket-client/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /6.0/raw-rsocket-client/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar 3 | -------------------------------------------------------------------------------- /6.0/raw-rsocket-client/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 | * [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.2.2.RELEASE/maven-plugin/) 8 | 9 | -------------------------------------------------------------------------------- /6.0/raw-rsocket-client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.2.RELEASE 9 | 10 | 11 | com.example 12 | raw-rsocket-client 13 | 0.0.1-SNAPSHOT 14 | raw-rsocket-client 15 | Demo project for Spring Boot 16 | 17 | 18 | 13 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-rsocket 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 | 43 | 44 | io.projectreactor 45 | reactor-test 46 | test 47 | 48 | 49 | 50 | 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-maven-plugin 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /6.0/raw-rsocket-client/src/main/java/com/example/rawrsocketclient/RawRsocketClientApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.rawrsocketclient; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import io.rsocket.Payload; 5 | import io.rsocket.RSocketFactory; 6 | import io.rsocket.transport.netty.client.TcpClientTransport; 7 | import io.rsocket.util.DefaultPayload; 8 | import lombok.*; 9 | import lombok.extern.log4j.Log4j2; 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.ApplicationListener; 14 | import org.springframework.context.event.EventListener; 15 | import org.springframework.core.Ordered; 16 | import org.springframework.stereotype.Component; 17 | 18 | @SpringBootApplication 19 | public class RawRsocketClientApplication { 20 | 21 | @SneakyThrows 22 | public static void main(String[] args) { 23 | SpringApplication.run(RawRsocketClientApplication.class, args); 24 | System.in.read(); 25 | } 26 | 27 | } 28 | 29 | @Log4j2 30 | @RequiredArgsConstructor 31 | @Component 32 | class Consumer { 33 | 34 | private final JsonHelper jsonHelper; 35 | 36 | @EventListener(ApplicationReadyEvent.class) 37 | public void start() { 38 | 39 | log.info("consumer starting..."); 40 | 41 | var request = jsonHelper.write(new GreetingRequest("Livelessons")); 42 | 43 | RSocketFactory 44 | .connect() 45 | .transport(TcpClientTransport.create(7000)) 46 | .start() 47 | .flatMapMany(sender -> sender 48 | .requestStream(DefaultPayload.create(request)) 49 | .map(Payload::getDataUtf8) 50 | .map(json -> jsonHelper.read(json, GreetingResponse.class)) 51 | ) 52 | .subscribe(result -> log.info("processing new result " + result.toString())); 53 | } 54 | } 55 | 56 | @Data 57 | @AllArgsConstructor 58 | @NoArgsConstructor 59 | class GreetingRequest { 60 | private String name; 61 | } 62 | 63 | @Data 64 | @AllArgsConstructor 65 | @NoArgsConstructor 66 | class GreetingResponse { 67 | private String message; 68 | } 69 | 70 | @Component 71 | @RequiredArgsConstructor 72 | class JsonHelper { 73 | 74 | private final ObjectMapper objectMapper; 75 | 76 | @SneakyThrows 77 | T read(String json, Class clzz) { 78 | return this.objectMapper.readValue(json, clzz); 79 | } 80 | 81 | @SneakyThrows 82 | String write(Object o) { 83 | return this.objectMapper.writeValueAsString(o); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /6.0/raw-rsocket-client/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /6.0/raw-rsocket-client/src/test/java/com/example/rawrsocketclient/RawRsocketClientApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.rawrsocketclient; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class RawRsocketClientApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /6.0/raw-rsocket-service/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong/reactive-spring-livelessons-2e/f10c568102d0634a050639973ba99f632580392f/6.0/raw-rsocket-service/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /6.0/raw-rsocket-service/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar 3 | -------------------------------------------------------------------------------- /6.0/raw-rsocket-service/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 | * [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.2.2.RELEASE/maven-plugin/) 8 | 9 | -------------------------------------------------------------------------------- /6.0/raw-rsocket-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.2.RELEASE 9 | 10 | 11 | com.example 12 | raw-rsocket-service 13 | 0.0.1-SNAPSHOT 14 | raw-rsocket-service 15 | Demo project for Spring Boot 16 | 17 | 18 | 13 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-rsocket 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 | org.junit.vintage 43 | junit-vintage-engine 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 | -------------------------------------------------------------------------------- /6.0/raw-rsocket-service/src/main/java/com/example/rawrsocketservice/RawRsocketServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.rawrsocketservice; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import io.rsocket.AbstractRSocket; 5 | import io.rsocket.Payload; 6 | import io.rsocket.RSocketFactory; 7 | import io.rsocket.SocketAcceptor; 8 | import io.rsocket.transport.netty.server.TcpServerTransport; 9 | import io.rsocket.util.DefaultPayload; 10 | import lombok.*; 11 | import lombok.extern.log4j.Log4j2; 12 | import org.springframework.boot.SpringApplication; 13 | import org.springframework.boot.autoconfigure.SpringBootApplication; 14 | import org.springframework.boot.context.event.ApplicationReadyEvent; 15 | import org.springframework.context.ApplicationListener; 16 | import org.springframework.context.event.EventListener; 17 | import org.springframework.core.Ordered; 18 | import org.springframework.stereotype.Component; 19 | import reactor.core.publisher.Flux; 20 | import reactor.core.publisher.Mono; 21 | 22 | import java.time.Duration; 23 | import java.time.Instant; 24 | import java.util.stream.Stream; 25 | 26 | @SpringBootApplication 27 | public class RawRsocketServiceApplication { 28 | public static void main(String[] args) { 29 | SpringApplication.run(RawRsocketServiceApplication.class, args); 30 | } 31 | } 32 | 33 | @Data 34 | @AllArgsConstructor 35 | @NoArgsConstructor 36 | class GreetingRequest { 37 | private String name; 38 | } 39 | 40 | @Data 41 | @AllArgsConstructor 42 | @NoArgsConstructor 43 | class GreetingResponse { 44 | private String message; 45 | } 46 | 47 | @Component 48 | @RequiredArgsConstructor 49 | class JsonHelper { 50 | 51 | private final ObjectMapper objectMapper; 52 | 53 | @SneakyThrows 54 | T read(String json, Class clzz) { 55 | return this.objectMapper.readValue(json, clzz); 56 | } 57 | 58 | @SneakyThrows 59 | String write(Object o) { 60 | return this.objectMapper.writeValueAsString(o); 61 | } 62 | } 63 | 64 | @Log4j2 65 | @Component 66 | @RequiredArgsConstructor 67 | class Producer { 68 | 69 | private final JsonHelper jsonHelper; 70 | 71 | private Flux greet(GreetingRequest request) { 72 | return Flux 73 | .fromStream(Stream.generate( 74 | () -> new GreetingResponse("Hello " + request.getName() + " @ " + Instant.now().toString()))) 75 | .delayElements(Duration.ofSeconds(1)); 76 | } 77 | 78 | @EventListener(ApplicationReadyEvent.class) 79 | public void start() { 80 | log.info("producer starting..."); 81 | SocketAcceptor socketAcceptor = (connectionSetupPayload, sender) -> { 82 | 83 | AbstractRSocket abstractRSocket = new AbstractRSocket() { 84 | 85 | @Override 86 | public Flux requestStream(Payload payload) { 87 | String json = payload.getDataUtf8(); 88 | GreetingRequest greetingRequest = jsonHelper.read(json, GreetingRequest.class); 89 | return greet(greetingRequest) 90 | .map(jsonHelper::write) 91 | .map(DefaultPayload::create); 92 | } 93 | }; 94 | 95 | return Mono.just(abstractRSocket); 96 | }; 97 | 98 | TcpServerTransport transport = TcpServerTransport.create(7000); 99 | 100 | RSocketFactory 101 | .receive() 102 | .acceptor(socketAcceptor) 103 | .transport(transport) 104 | .start() 105 | .block(); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /6.0/raw-rsocket-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /6.0/raw-rsocket-service/src/test/java/com/example/rawrsocketservice/RawRsocketServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.rawrsocketservice; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class RawRsocketServiceApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /6.0/rsocket-client/.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import java.net.*; 18 | import java.io.*; 19 | import java.nio.channels.*; 20 | import java.util.Properties; 21 | 22 | public class MavenWrapperDownloader { 23 | 24 | private static final String WRAPPER_VERSION = "0.5.5"; 25 | /** 26 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 27 | */ 28 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 29 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 30 | 31 | /** 32 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 33 | * use instead of the default one. 34 | */ 35 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 36 | ".mvn/wrapper/maven-wrapper.properties"; 37 | 38 | /** 39 | * Path where the maven-wrapper.jar will be saved to. 40 | */ 41 | private static final String MAVEN_WRAPPER_JAR_PATH = 42 | ".mvn/wrapper/maven-wrapper.jar"; 43 | 44 | /** 45 | * Name of the property which should be used to override the default download url for the wrapper. 46 | */ 47 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 48 | 49 | public static void main(String args[]) { 50 | System.out.println("- Downloader started"); 51 | File baseDirectory = new File(args[0]); 52 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 53 | 54 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 55 | // wrapperUrl parameter. 56 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 57 | String url = DEFAULT_DOWNLOAD_URL; 58 | if (mavenWrapperPropertyFile.exists()) { 59 | FileInputStream mavenWrapperPropertyFileInputStream = null; 60 | try { 61 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 62 | Properties mavenWrapperProperties = new Properties(); 63 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 64 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 65 | } catch (IOException e) { 66 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 67 | } finally { 68 | try { 69 | if (mavenWrapperPropertyFileInputStream != null) { 70 | mavenWrapperPropertyFileInputStream.close(); 71 | } 72 | } catch (IOException e) { 73 | // Ignore ... 74 | } 75 | } 76 | } 77 | System.out.println("- Downloading from: " + url); 78 | 79 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 80 | if (!outputFile.getParentFile().exists()) { 81 | if (!outputFile.getParentFile().mkdirs()) { 82 | System.out.println( 83 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 84 | } 85 | } 86 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 87 | try { 88 | downloadFileFromURL(url, outputFile); 89 | System.out.println("Done"); 90 | System.exit(0); 91 | } catch (Throwable e) { 92 | System.out.println("- Error downloading"); 93 | e.printStackTrace(); 94 | System.exit(1); 95 | } 96 | } 97 | 98 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 99 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 100 | String username = System.getenv("MVNW_USERNAME"); 101 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 102 | Authenticator.setDefault(new Authenticator() { 103 | @Override 104 | protected PasswordAuthentication getPasswordAuthentication() { 105 | return new PasswordAuthentication(username, password); 106 | } 107 | }); 108 | } 109 | URL website = new URL(urlString); 110 | ReadableByteChannel rbc; 111 | rbc = Channels.newChannel(website.openStream()); 112 | FileOutputStream fos = new FileOutputStream(destination); 113 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 114 | fos.close(); 115 | rbc.close(); 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /6.0/rsocket-client/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong/reactive-spring-livelessons-2e/f10c568102d0634a050639973ba99f632580392f/6.0/rsocket-client/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /6.0/rsocket-client/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar 3 | -------------------------------------------------------------------------------- /6.0/rsocket-client/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 | * [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.2.2.RELEASE/maven-plugin/) 8 | 9 | -------------------------------------------------------------------------------- /6.0/rsocket-client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.2.RELEASE 9 | 10 | 11 | com.example 12 | rsocket-client 13 | 0.0.1-SNAPSHOT 14 | rsocket-client 15 | Demo project for Spring Boot 16 | 17 | 18 | 13 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-rsocket 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 | 43 | 44 | io.projectreactor 45 | reactor-test 46 | test 47 | 48 | 49 | 50 | 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-maven-plugin 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /6.0/rsocket-client/src/main/java/com/example/rsocketclient/RsocketClientApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.rsocketclient; 2 | 3 | import lombok.*; 4 | import lombok.extern.log4j.Log4j2; 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.event.EventListener; 10 | import org.springframework.messaging.rsocket.RSocketRequester; 11 | import org.springframework.stereotype.Component; 12 | 13 | @SpringBootApplication 14 | public class RsocketClientApplication { 15 | 16 | @Bean 17 | RSocketRequester rSocketRequester(RSocketRequester.Builder builder) { 18 | return builder.connectTcp("localhost", 7002).block(); 19 | } 20 | 21 | @SneakyThrows 22 | public static void main(String[] args) { 23 | SpringApplication.run(RsocketClientApplication.class, args); 24 | System.in.read(); 25 | } 26 | 27 | } 28 | 29 | @Component 30 | @Log4j2 31 | @RequiredArgsConstructor 32 | class Client { 33 | 34 | private final RSocketRequester rSocketRequester; 35 | 36 | @EventListener(ApplicationReadyEvent.class) 37 | public void ready() { 38 | this.rSocketRequester 39 | .route("greetings.10") 40 | .data(new GreetingRequest("Livelessons")) 41 | .retrieveFlux(GreetingResponse.class) 42 | .subscribe(log::info); 43 | } 44 | } 45 | 46 | @Data 47 | @AllArgsConstructor 48 | @NoArgsConstructor 49 | class GreetingRequest { 50 | private String name; 51 | } 52 | 53 | @Data 54 | @AllArgsConstructor 55 | @NoArgsConstructor 56 | class GreetingResponse { 57 | private String message; 58 | } -------------------------------------------------------------------------------- /6.0/rsocket-client/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /6.0/rsocket-client/src/test/java/com/example/rsocketclient/RsocketClientApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.rsocketclient; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class RsocketClientApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /6.0/rsocket-service/.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import java.net.*; 17 | import java.io.*; 18 | import java.nio.channels.*; 19 | import java.util.Properties; 20 | 21 | public class MavenWrapperDownloader { 22 | 23 | private static final String WRAPPER_VERSION = "0.5.5"; 24 | /** 25 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 26 | */ 27 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 28 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 29 | 30 | /** 31 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 32 | * use instead of the default one. 33 | */ 34 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 35 | ".mvn/wrapper/maven-wrapper.properties"; 36 | 37 | /** 38 | * Path where the maven-wrapper.jar will be saved to. 39 | */ 40 | private static final String MAVEN_WRAPPER_JAR_PATH = 41 | ".mvn/wrapper/maven-wrapper.jar"; 42 | 43 | /** 44 | * Name of the property which should be used to override the default download url for the wrapper. 45 | */ 46 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 47 | 48 | public static void main(String args[]) { 49 | System.out.println("- Downloader started"); 50 | File baseDirectory = new File(args[0]); 51 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 52 | 53 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 54 | // wrapperUrl parameter. 55 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 56 | String url = DEFAULT_DOWNLOAD_URL; 57 | if(mavenWrapperPropertyFile.exists()) { 58 | FileInputStream mavenWrapperPropertyFileInputStream = null; 59 | try { 60 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 61 | Properties mavenWrapperProperties = new Properties(); 62 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 63 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 64 | } catch (IOException e) { 65 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 66 | } finally { 67 | try { 68 | if(mavenWrapperPropertyFileInputStream != null) { 69 | mavenWrapperPropertyFileInputStream.close(); 70 | } 71 | } catch (IOException e) { 72 | // Ignore ... 73 | } 74 | } 75 | } 76 | System.out.println("- Downloading from: " + url); 77 | 78 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 79 | if(!outputFile.getParentFile().exists()) { 80 | if(!outputFile.getParentFile().mkdirs()) { 81 | System.out.println( 82 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 83 | } 84 | } 85 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 86 | try { 87 | downloadFileFromURL(url, outputFile); 88 | System.out.println("Done"); 89 | System.exit(0); 90 | } catch (Throwable e) { 91 | System.out.println("- Error downloading"); 92 | e.printStackTrace(); 93 | System.exit(1); 94 | } 95 | } 96 | 97 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 98 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 99 | String username = System.getenv("MVNW_USERNAME"); 100 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 101 | Authenticator.setDefault(new Authenticator() { 102 | @Override 103 | protected PasswordAuthentication getPasswordAuthentication() { 104 | return new PasswordAuthentication(username, password); 105 | } 106 | }); 107 | } 108 | URL website = new URL(urlString); 109 | ReadableByteChannel rbc; 110 | rbc = Channels.newChannel(website.openStream()); 111 | FileOutputStream fos = new FileOutputStream(destination); 112 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 113 | fos.close(); 114 | rbc.close(); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /6.0/rsocket-service/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong/reactive-spring-livelessons-2e/f10c568102d0634a050639973ba99f632580392f/6.0/rsocket-service/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /6.0/rsocket-service/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar 3 | -------------------------------------------------------------------------------- /6.0/rsocket-service/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 | * [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.2.2.RELEASE/maven-plugin/) 8 | 9 | -------------------------------------------------------------------------------- /6.0/rsocket-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.2.RELEASE 9 | 10 | 11 | com.example 12 | rsocket-service 13 | 0.0.1-SNAPSHOT 14 | rsocket-service 15 | Demo project for Spring Boot 16 | 17 | 18 | 13 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-rsocket 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 | 43 | 44 | io.projectreactor 45 | reactor-test 46 | test 47 | 48 | 49 | 50 | 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-maven-plugin 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /6.0/rsocket-service/src/main/java/com/example/rsocketservice/RsocketServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.rsocketservice; 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.messaging.handler.annotation.DestinationVariable; 9 | import org.springframework.messaging.handler.annotation.MessageMapping; 10 | import org.springframework.stereotype.Controller; 11 | import reactor.core.publisher.Flux; 12 | 13 | import java.time.Duration; 14 | import java.time.Instant; 15 | import java.util.stream.Stream; 16 | 17 | @SpringBootApplication 18 | public class RsocketServiceApplication { 19 | 20 | public static void main(String[] args) { 21 | SpringApplication.run(RsocketServiceApplication.class, args); 22 | } 23 | 24 | } 25 | 26 | @Controller 27 | class GreetingService { 28 | 29 | @MessageMapping("greetings.{timeInSeconds}") 30 | Flux greet(GreetingRequest request, @DestinationVariable int timeInSeconds) { 31 | if (timeInSeconds == 0 ) { 32 | timeInSeconds = 1 ; 33 | } 34 | return Flux 35 | .fromStream(Stream.generate(() -> new GreetingResponse("Hello " + request.getName() + " @ " + Instant.now() + "!"))) 36 | .delayElements(Duration.ofSeconds(timeInSeconds)); 37 | } 38 | } 39 | 40 | @Data 41 | @AllArgsConstructor 42 | @NoArgsConstructor 43 | class GreetingRequest { 44 | private String name; 45 | } 46 | 47 | @Data 48 | @AllArgsConstructor 49 | @NoArgsConstructor 50 | class GreetingResponse { 51 | private String message; 52 | } -------------------------------------------------------------------------------- /6.0/rsocket-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.rsocket.server.port=7002 2 | -------------------------------------------------------------------------------- /6.0/rsocket-service/src/test/java/com/example/rsocketservice/RsocketServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.rsocketservice; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class RsocketServiceApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /7.0/secure-http-client/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong/reactive-spring-livelessons-2e/f10c568102d0634a050639973ba99f632580392f/7.0/secure-http-client/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /7.0/secure-http-client/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar 3 | -------------------------------------------------------------------------------- /7.0/secure-http-client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.2.RELEASE 9 | 10 | 11 | com.example 12 | secure-http-client 13 | 0.0.1-SNAPSHOT 14 | secure-http-client 15 | Demo project for Spring Boot 16 | 17 | 18 | 13 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-security 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-webflux 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 | org.junit.vintage 42 | junit-vintage-engine 43 | 44 | 45 | 46 | 47 | io.projectreactor 48 | reactor-test 49 | test 50 | 51 | 52 | 53 | 54 | 55 | 56 | org.springframework.boot 57 | spring-boot-maven-plugin 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /7.0/secure-http-client/src/main/java/com/example/http/HttpApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.http; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.RequiredArgsConstructor; 7 | import lombok.extern.log4j.Log4j2; 8 | import org.springframework.boot.SpringApplication; 9 | import org.springframework.boot.autoconfigure.SpringBootApplication; 10 | import org.springframework.boot.context.event.ApplicationReadyEvent; 11 | import org.springframework.context.annotation.Bean; 12 | import org.springframework.context.event.EventListener; 13 | import org.springframework.stereotype.Component; 14 | import org.springframework.web.reactive.function.client.ExchangeFilterFunctions; 15 | import org.springframework.web.reactive.function.client.WebClient; 16 | 17 | import static org.springframework.web.reactive.function.server.RouterFunctions.route; 18 | 19 | @SpringBootApplication 20 | public class HttpApplication { 21 | 22 | @Bean 23 | WebClient webClient(WebClient.Builder builder) { 24 | return builder 25 | .filter(ExchangeFilterFunctions.basicAuthentication("user", "password")) 26 | .build(); 27 | } 28 | 29 | public static void main(String[] args) { 30 | SpringApplication.run(HttpApplication.class, args); 31 | } 32 | } 33 | 34 | @Component 35 | @Log4j2 36 | @RequiredArgsConstructor 37 | class Consumer { 38 | 39 | private final WebClient client; 40 | 41 | @EventListener(ApplicationReadyEvent.class) 42 | public void start() { 43 | this.client 44 | .get() 45 | .uri("http://localhost:8080/greetings") 46 | .retrieve() 47 | .bodyToFlux(GreetingResponse.class) 48 | .subscribe(log::info); 49 | } 50 | } 51 | 52 | @Data 53 | @AllArgsConstructor 54 | @NoArgsConstructor 55 | class GreetingResponse { 56 | private String message; 57 | } 58 | 59 | @Data 60 | @AllArgsConstructor 61 | @NoArgsConstructor 62 | class GreetingRequest { 63 | private String name; 64 | } 65 | 66 | -------------------------------------------------------------------------------- /7.0/secure-http-client/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=0 2 | -------------------------------------------------------------------------------- /7.0/secure-http-client/src/test/java/com/example/http/HttpApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.http; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class HttpApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /7.0/secure-http-service/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong/reactive-spring-livelessons-2e/f10c568102d0634a050639973ba99f632580392f/7.0/secure-http-service/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /7.0/secure-http-service/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar 3 | -------------------------------------------------------------------------------- /7.0/secure-http-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.2.RELEASE 9 | 10 | 11 | com.example 12 | secure-http-service 13 | 0.0.1-SNAPSHOT 14 | secure-http-service 15 | Demo project for Spring Boot 16 | 17 | 18 | 13 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-security 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-webflux 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 | org.junit.vintage 42 | junit-vintage-engine 43 | 44 | 45 | 46 | 47 | io.projectreactor 48 | reactor-test 49 | test 50 | 51 | 52 | 53 | 54 | 55 | 56 | org.springframework.boot 57 | spring-boot-maven-plugin 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /7.0/secure-http-service/src/main/java/com/example/http/HttpApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.http; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.extern.log4j.Log4j2; 7 | import org.springframework.boot.SpringApplication; 8 | import org.springframework.boot.autoconfigure.SpringBootApplication; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.http.MediaType; 11 | import org.springframework.security.config.Customizer; 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.core.userdetails.UserDetails; 16 | import org.springframework.security.web.server.SecurityWebFilterChain; 17 | import org.springframework.stereotype.Service; 18 | import org.springframework.web.reactive.function.server.*; 19 | import reactor.core.publisher.Flux; 20 | import reactor.core.publisher.Mono; 21 | import reactor.core.scheduler.Scheduler; 22 | import reactor.core.scheduler.Schedulers; 23 | 24 | import java.security.Principal; 25 | import java.time.Duration; 26 | import java.time.Instant; 27 | import java.util.function.Supplier; 28 | import java.util.stream.Stream; 29 | 30 | import static org.springframework.web.reactive.function.server.RouterFunctions.route; 31 | import static org.springframework.web.reactive.function.server.ServerResponse.*; 32 | 33 | @Log4j2 34 | @SpringBootApplication 35 | public class HttpApplication { 36 | 37 | @Bean 38 | MapReactiveUserDetailsService userDetails() { 39 | UserDetails user = User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build(); 40 | return new MapReactiveUserDetailsService(user); 41 | } 42 | 43 | @Bean 44 | SecurityWebFilterChain authorization(ServerHttpSecurity http) { 45 | return http 46 | .csrf(ServerHttpSecurity.CsrfSpec::disable) 47 | .authorizeExchange(x -> x.pathMatchers("/greeting*").authenticated()) 48 | .httpBasic(Customizer.withDefaults()) 49 | .build(); 50 | } 51 | 52 | 53 | @Bean 54 | RouterFunction routes(GreetingService gs) { 55 | return route() 56 | .GET("/greeting", request -> { 57 | 58 | Mono greetingResponseFlux = request 59 | .principal() 60 | .map(Principal::getName) 61 | .map(GreetingRequest::new) 62 | .flatMap(gs::greetOnce); 63 | return ServerResponse.ok().body(greetingResponseFlux, GreetingResponse.class); 64 | }) 65 | .GET("/greetings", request -> { 66 | Flux greetingResponseFlux = request 67 | .principal() 68 | .map(Principal::getName) 69 | .map(GreetingRequest::new) 70 | .flatMapMany(gs::greetMany); 71 | return ServerResponse 72 | .ok() 73 | .contentType(MediaType.TEXT_EVENT_STREAM) 74 | .body(greetingResponseFlux, GreetingResponse.class); 75 | }) 76 | .build(); 77 | } 78 | 79 | public static void main(String[] args) { 80 | SpringApplication.run(HttpApplication.class, args); 81 | } 82 | } 83 | 84 | 85 | @Service 86 | class GreetingService { 87 | 88 | Flux greetMany(GreetingRequest request) { 89 | return Flux 90 | .fromStream(Stream.generate(() -> greet(request.getName()))) 91 | .delayElements(Duration.ofSeconds(1)) 92 | .subscribeOn(Schedulers.elastic()); 93 | } 94 | 95 | Mono greetOnce(GreetingRequest request) { 96 | return Mono.just(greet(request.getName())); 97 | } 98 | 99 | private GreetingResponse greet(String name) { 100 | return new GreetingResponse("Hello " + name + " @ " + Instant.now()); 101 | } 102 | } 103 | 104 | @Data 105 | @AllArgsConstructor 106 | @NoArgsConstructor 107 | class GreetingResponse { 108 | private String message; 109 | } 110 | 111 | @Data 112 | @AllArgsConstructor 113 | @NoArgsConstructor 114 | class GreetingRequest { 115 | private String name; 116 | } 117 | 118 | -------------------------------------------------------------------------------- /7.0/secure-http-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /7.0/secure-http-service/src/test/java/com/example/http/HttpApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.http; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class HttpApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /7.0/secure-rsocket-client/.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import java.net.*; 18 | import java.io.*; 19 | import java.nio.channels.*; 20 | import java.util.Properties; 21 | 22 | public class MavenWrapperDownloader { 23 | 24 | private static final String WRAPPER_VERSION = "0.5.5"; 25 | /** 26 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 27 | */ 28 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 29 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 30 | 31 | /** 32 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 33 | * use instead of the default one. 34 | */ 35 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 36 | ".mvn/wrapper/maven-wrapper.properties"; 37 | 38 | /** 39 | * Path where the maven-wrapper.jar will be saved to. 40 | */ 41 | private static final String MAVEN_WRAPPER_JAR_PATH = 42 | ".mvn/wrapper/maven-wrapper.jar"; 43 | 44 | /** 45 | * Name of the property which should be used to override the default download url for the wrapper. 46 | */ 47 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 48 | 49 | public static void main(String args[]) { 50 | System.out.println("- Downloader started"); 51 | File baseDirectory = new File(args[0]); 52 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 53 | 54 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 55 | // wrapperUrl parameter. 56 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 57 | String url = DEFAULT_DOWNLOAD_URL; 58 | if (mavenWrapperPropertyFile.exists()) { 59 | FileInputStream mavenWrapperPropertyFileInputStream = null; 60 | try { 61 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 62 | Properties mavenWrapperProperties = new Properties(); 63 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 64 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 65 | } catch (IOException e) { 66 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 67 | } finally { 68 | try { 69 | if (mavenWrapperPropertyFileInputStream != null) { 70 | mavenWrapperPropertyFileInputStream.close(); 71 | } 72 | } catch (IOException e) { 73 | // Ignore ... 74 | } 75 | } 76 | } 77 | System.out.println("- Downloading from: " + url); 78 | 79 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 80 | if (!outputFile.getParentFile().exists()) { 81 | if (!outputFile.getParentFile().mkdirs()) { 82 | System.out.println( 83 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 84 | } 85 | } 86 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 87 | try { 88 | downloadFileFromURL(url, outputFile); 89 | System.out.println("Done"); 90 | System.exit(0); 91 | } catch (Throwable e) { 92 | System.out.println("- Error downloading"); 93 | e.printStackTrace(); 94 | System.exit(1); 95 | } 96 | } 97 | 98 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 99 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 100 | String username = System.getenv("MVNW_USERNAME"); 101 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 102 | Authenticator.setDefault(new Authenticator() { 103 | @Override 104 | protected PasswordAuthentication getPasswordAuthentication() { 105 | return new PasswordAuthentication(username, password); 106 | } 107 | }); 108 | } 109 | URL website = new URL(urlString); 110 | ReadableByteChannel rbc; 111 | rbc = Channels.newChannel(website.openStream()); 112 | FileOutputStream fos = new FileOutputStream(destination); 113 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 114 | fos.close(); 115 | rbc.close(); 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /7.0/secure-rsocket-client/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong/reactive-spring-livelessons-2e/f10c568102d0634a050639973ba99f632580392f/7.0/secure-rsocket-client/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /7.0/secure-rsocket-client/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar 3 | -------------------------------------------------------------------------------- /7.0/secure-rsocket-client/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 | * [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.2.2.RELEASE/maven-plugin/) 8 | 9 | -------------------------------------------------------------------------------- /7.0/secure-rsocket-client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.2.RELEASE 9 | 10 | 11 | com.example 12 | secure-rsocket-client 13 | 0.0.1-SNAPSHOT 14 | rsocket-client 15 | Demo project for Spring Boot 16 | 17 | 18 | Hoxton.RELEASE 19 | 20 | 13 21 | 22 | 23 | 24 | 25 | 26 | 27 | org.springframework.security 28 | spring-security-messaging 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-security 33 | 34 | 35 | org.springframework.security 36 | spring-security-rsocket 37 | 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-starter-rsocket 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 | org.junit.vintage 56 | junit-vintage-engine 57 | 58 | 59 | 60 | 61 | io.projectreactor 62 | reactor-test 63 | test 64 | 65 | 66 | 67 | 68 | 69 | 70 | org.springframework.boot 71 | spring-boot-maven-plugin 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /7.0/secure-rsocket-client/src/main/java/com/example/rsocketclient/RsocketClientApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.rsocketclient; 2 | 3 | import lombok.*; 4 | import lombok.extern.log4j.Log4j2; 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.boot.rsocket.messaging.RSocketStrategiesCustomizer; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.event.EventListener; 11 | import org.springframework.messaging.rsocket.RSocketRequester; 12 | import org.springframework.security.rsocket.metadata.BasicAuthenticationEncoder; 13 | import org.springframework.security.rsocket.metadata.UsernamePasswordMetadata; 14 | import org.springframework.stereotype.Component; 15 | 16 | import static org.springframework.security.rsocket.metadata.UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE; 17 | 18 | @SpringBootApplication 19 | public class RsocketClientApplication { 20 | 21 | @Bean 22 | RSocketStrategiesCustomizer rSocketStrategiesCustomizer() { 23 | return strategies -> strategies.encoder(new BasicAuthenticationEncoder()); 24 | } 25 | 26 | @Bean 27 | RSocketRequester rSocketRequester(RSocketRequester.Builder builder) { 28 | return builder.connectTcp("localhost", 7002).block(); 29 | } 30 | 31 | @SneakyThrows 32 | public static void main(String[] args) { 33 | SpringApplication.run(RsocketClientApplication.class, args); 34 | System.in.read(); 35 | } 36 | 37 | } 38 | 39 | @Component 40 | @Log4j2 41 | @RequiredArgsConstructor 42 | class Client { 43 | 44 | private final RSocketRequester rSocketRequester; 45 | 46 | @EventListener(ApplicationReadyEvent.class) 47 | public void ready() { 48 | var credentials = new UsernamePasswordMetadata("user", "password"); 49 | this.rSocketRequester 50 | .route("greetings.1") 51 | .metadata(credentials, BASIC_AUTHENTICATION_MIME_TYPE) 52 | .retrieveFlux(GreetingResponse.class) 53 | .subscribe(log::info); 54 | } 55 | } 56 | 57 | @Data 58 | @AllArgsConstructor 59 | @NoArgsConstructor 60 | class GreetingRequest { 61 | private String name; 62 | } 63 | 64 | @Data 65 | @AllArgsConstructor 66 | @NoArgsConstructor 67 | class GreetingResponse { 68 | private String message; 69 | } -------------------------------------------------------------------------------- /7.0/secure-rsocket-client/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /7.0/secure-rsocket-client/src/test/java/com/example/rsocketclient/RsocketClientApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.rsocketclient; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class RsocketClientApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /7.0/secure-rsocket-service/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong/reactive-spring-livelessons-2e/f10c568102d0634a050639973ba99f632580392f/7.0/secure-rsocket-service/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /7.0/secure-rsocket-service/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar 3 | -------------------------------------------------------------------------------- /7.0/secure-rsocket-service/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 | * [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.2.2.RELEASE/maven-plugin/) 8 | 9 | -------------------------------------------------------------------------------- /7.0/secure-rsocket-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.2.RELEASE 9 | 10 | 11 | com.example 12 | secure-rsocket-service 13 | 0.0.1-SNAPSHOT 14 | rsocket-service 15 | Demo project for Spring Boot 16 | 17 | 18 | 13 19 | 20 | 21 | 22 | 23 | org.springframework.security 24 | spring-security-messaging 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-security 29 | 30 | 31 | org.springframework.security 32 | spring-security-rsocket 33 | 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-starter-rsocket 38 | 39 | 40 | 41 | org.projectlombok 42 | lombok 43 | true 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-starter-test 48 | test 49 | 50 | 51 | org.junit.vintage 52 | junit-vintage-engine 53 | 54 | 55 | 56 | 57 | io.projectreactor 58 | reactor-test 59 | test 60 | 61 | 62 | 63 | 64 | 65 | 66 | org.springframework.boot 67 | spring-boot-maven-plugin 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /7.0/secure-rsocket-service/src/main/java/com/example/rsocketservice/RsocketServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.rsocketservice; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.extern.log4j.Log4j2; 7 | import org.springframework.boot.SpringApplication; 8 | import org.springframework.boot.autoconfigure.SpringBootApplication; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | import org.springframework.messaging.handler.annotation.DestinationVariable; 12 | import org.springframework.messaging.handler.annotation.MessageExceptionHandler; 13 | import org.springframework.messaging.handler.annotation.MessageMapping; 14 | import org.springframework.security.config.Customizer; 15 | import org.springframework.security.config.annotation.rsocket.EnableRSocketSecurity; 16 | import org.springframework.security.config.annotation.rsocket.RSocketSecurity; 17 | import org.springframework.security.core.annotation.AuthenticationPrincipal; 18 | import org.springframework.security.core.annotation.CurrentSecurityContext; 19 | import org.springframework.security.core.context.ReactiveSecurityContextHolder; 20 | import org.springframework.security.core.context.SecurityContext; 21 | import org.springframework.security.core.userdetails.MapReactiveUserDetailsService; 22 | import org.springframework.security.core.userdetails.User; 23 | import org.springframework.security.core.userdetails.UserDetails; 24 | import org.springframework.security.rsocket.core.PayloadSocketAcceptorInterceptor; 25 | import org.springframework.stereotype.Controller; 26 | import reactor.core.publisher.Flux; 27 | import reactor.core.publisher.Mono; 28 | 29 | import java.security.Principal; 30 | import java.time.Duration; 31 | import java.time.Instant; 32 | import java.util.stream.Stream; 33 | 34 | @SpringBootApplication 35 | public class RsocketServiceApplication { 36 | 37 | public static void main(String[] args) { 38 | SpringApplication.run(RsocketServiceApplication.class, args); 39 | } 40 | 41 | } 42 | 43 | @Log4j2 44 | @Controller 45 | class GreetingService { 46 | 47 | @MessageExceptionHandler(IllegalArgumentException.class) 48 | Mono onIllegalArgumentException(IllegalArgumentException iae) { 49 | log.error(iae); 50 | return Mono.just("OoOps!"); 51 | } 52 | 53 | @MessageMapping("greetings.{timeInSeconds}") 54 | Flux greet(@DestinationVariable int timeInSeconds) { 55 | 56 | return ReactiveSecurityContextHolder 57 | .getContext() 58 | .map(SecurityContext::getAuthentication) 59 | .map(au -> (User) au.getPrincipal()) 60 | .map(User::getUsername) 61 | .flatMapMany(str -> Flux 62 | .fromStream(Stream.generate(() -> new GreetingResponse("Hello " + str + " @ " + Instant.now() + "!"))) 63 | .delayElements(Duration.ofSeconds(timeInSeconds))); 64 | } 65 | } 66 | 67 | @Configuration 68 | @EnableRSocketSecurity 69 | class RSocketSecurityConfiguration { 70 | 71 | @Bean 72 | PayloadSocketAcceptorInterceptor rsocketInterceptor(RSocketSecurity rsocket) { 73 | return rsocket 74 | .authorizePayload(authorize -> 75 | authorize 76 | .route("greeting*").authenticated() 77 | .anyExchange().permitAll() 78 | ) 79 | .basicAuthentication(Customizer.withDefaults()) 80 | .build(); 81 | } 82 | 83 | @Bean 84 | MapReactiveUserDetailsService userDetailsService() { 85 | UserDetails user = User.withDefaultPasswordEncoder() 86 | .username("user") 87 | .password("password") 88 | .roles("USER") 89 | .build(); 90 | return new MapReactiveUserDetailsService(user); 91 | } 92 | 93 | } 94 | 95 | @Data 96 | @AllArgsConstructor 97 | @NoArgsConstructor 98 | class GreetingRequest { 99 | private String name; 100 | } 101 | 102 | @Data 103 | @AllArgsConstructor 104 | @NoArgsConstructor 105 | class GreetingResponse { 106 | private String message; 107 | } -------------------------------------------------------------------------------- /7.0/secure-rsocket-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.rsocket.server.port=7002 2 | -------------------------------------------------------------------------------- /7.0/secure-rsocket-service/src/test/java/com/example/rsocketservice/RsocketServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.rsocketservice; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class RsocketServiceApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /8.0/http/http-gateway/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong/reactive-spring-livelessons-2e/f10c568102d0634a050639973ba99f632580392f/8.0/http/http-gateway/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /8.0/http/http-gateway/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar 3 | -------------------------------------------------------------------------------- /8.0/http/http-gateway/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 | * [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.2.2.RELEASE/maven-plugin/) 8 | * [Spring Data Reactive Redis](https://docs.spring.io/spring-boot/docs/2.2.2.RELEASE/reference/htmlsingle/#boot-features-redis) 9 | * [Spring Security](https://docs.spring.io/spring-boot/docs/2.2.2.RELEASE/reference/htmlsingle/#boot-features-security) 10 | 11 | ### Guides 12 | The following guides illustrate how to use some features concretely: 13 | 14 | * [Using Spring Cloud Gateway](https://github.com/spring-cloud-samples/spring-cloud-gateway-sample) 15 | * [Messaging with Redis](https://spring.io/guides/gs/messaging-redis/) 16 | * [Securing a Web Application](https://spring.io/guides/gs/securing-web/) 17 | * [Spring Boot and OAuth2](https://spring.io/guides/tutorials/spring-boot-oauth2/) 18 | * [Authenticating a User with LDAP](https://spring.io/guides/gs/authenticating-ldap/) 19 | 20 | -------------------------------------------------------------------------------- /8.0/http/http-gateway/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.2.RELEASE 9 | 10 | 11 | com.example 12 | http-gateway 13 | 0.0.1-SNAPSHOT 14 | http-gateway 15 | Demo project for Spring Boot 16 | 17 | 18 | 13 19 | Hoxton.RELEASE 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-data-redis-reactive 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-security 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-webflux 34 | 35 | 36 | org.springframework.cloud 37 | spring-cloud-starter-gateway 38 | 39 | 40 | 41 | org.projectlombok 42 | lombok 43 | true 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-starter-test 48 | test 49 | 50 | 51 | org.junit.vintage 52 | junit-vintage-engine 53 | 54 | 55 | 56 | 57 | io.projectreactor 58 | reactor-test 59 | test 60 | 61 | 62 | org.springframework.security 63 | spring-security-test 64 | test 65 | 66 | 67 | 68 | 69 | 70 | 71 | org.springframework.cloud 72 | spring-cloud-dependencies 73 | ${spring-cloud.version} 74 | pom 75 | import 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | org.springframework.boot 84 | spring-boot-maven-plugin 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /8.0/http/http-gateway/src/main/java/com/example/httpgateway/HttpGatewayApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.httpgateway; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver; 6 | import org.springframework.cloud.gateway.filter.ratelimit.PrincipalNameKeyResolver; 7 | import org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter; 8 | import org.springframework.cloud.gateway.route.RouteLocator; 9 | import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.http.HttpHeaders; 12 | import org.springframework.security.config.Customizer; 13 | import org.springframework.security.config.web.server.ServerHttpSecurity; 14 | import org.springframework.security.core.userdetails.MapReactiveUserDetailsService; 15 | import org.springframework.security.core.userdetails.User; 16 | import org.springframework.security.web.server.SecurityWebFilterChain; 17 | import org.springframework.web.server.ServerWebExchange; 18 | import reactor.core.publisher.Mono; 19 | 20 | import java.security.Principal; 21 | import java.util.function.Predicate; 22 | 23 | @SpringBootApplication 24 | public class HttpGatewayApplication { 25 | 26 | @Bean 27 | RedisRateLimiter redisRateLimiter() { 28 | return new RedisRateLimiter(5, 7); 29 | } 30 | 31 | @Bean 32 | SecurityWebFilterChain authorization(ServerHttpSecurity http) { 33 | return http 34 | .csrf(ServerHttpSecurity.CsrfSpec::disable) 35 | .httpBasic(Customizer.withDefaults()) 36 | .authorizeExchange(x -> x.pathMatchers("/proxy").authenticated()) 37 | .build(); 38 | } 39 | 40 | @Bean 41 | MapReactiveUserDetailsService authentication() { 42 | return new MapReactiveUserDetailsService( 43 | User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build()); 44 | } 45 | 46 | @Bean 47 | RouteLocator gateway(RouteLocatorBuilder rlb) { 48 | return rlb 49 | .routes() 50 | .route(routeSpec -> routeSpec 51 | .host("*.spring.io").and().path("/proxy") 52 | .filters(filterSpec -> filterSpec 53 | .setPath("/reservations") 54 | .addResponseHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*") 55 | .requestRateLimiter(rl -> rl 56 | .setRateLimiter(redisRateLimiter()) 57 | ) 58 | ) 59 | .uri("http://localhost:8080/") 60 | ) 61 | .build(); 62 | } 63 | 64 | public static void main(String[] args) { 65 | SpringApplication.run(HttpGatewayApplication.class, args); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /8.0/http/http-gateway/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=9999 2 | -------------------------------------------------------------------------------- /8.0/http/http-gateway/src/test/java/com/example/httpgateway/HttpGatewayApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.httpgateway; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class HttpGatewayApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /8.0/http/reservation-service/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong/reactive-spring-livelessons-2e/f10c568102d0634a050639973ba99f632580392f/8.0/http/reservation-service/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /8.0/http/reservation-service/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar 3 | -------------------------------------------------------------------------------- /8.0/http/reservation-service/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 | * [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.2.2.RELEASE/maven-plugin/) 8 | * [Spring Data R2DBC [Experimental]](https://docs.spring.io/spring-data/r2dbc/docs/1.0.x/reference/html/#reference) 9 | 10 | ### Guides 11 | The following guides illustrate how to use some features concretely: 12 | 13 | * [R2DBC example](https://github.com/spring-projects-experimental/spring-boot-r2dbc/tree/master/spring-boot-example-h2) 14 | 15 | ### Additional Links 16 | These additional references should also help you: 17 | 18 | * [R2DBC Homepage](https://r2dbc.io) 19 | 20 | -------------------------------------------------------------------------------- /8.0/http/reservation-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.2.RELEASE 9 | 10 | 11 | com.example 12 | reservation-service 13 | 0.0.1-SNAPSHOT 14 | reservation-service 15 | Demo project for Spring Boot 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot.experimental 24 | spring-boot-starter-data-r2dbc 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-webflux 29 | 30 | 31 | 32 | io.r2dbc 33 | r2dbc-postgresql 34 | runtime 35 | 36 | 37 | org.postgresql 38 | postgresql 39 | runtime 40 | 41 | 42 | org.projectlombok 43 | lombok 44 | true 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-test 49 | test 50 | 51 | 52 | org.junit.vintage 53 | junit-vintage-engine 54 | 55 | 56 | 57 | 58 | org.springframework.boot.experimental 59 | spring-boot-test-autoconfigure-r2dbc 60 | test 61 | 62 | 63 | io.projectreactor 64 | reactor-test 65 | test 66 | 67 | 68 | 69 | 70 | 71 | 72 | org.springframework.boot.experimental 73 | spring-boot-bom-r2dbc 74 | 0.1.0.M3 75 | pom 76 | import 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | org.springframework.boot 85 | spring-boot-maven-plugin 86 | 87 | 88 | 89 | 90 | 91 | 92 | spring-milestones 93 | Spring Milestones 94 | https://repo.spring.io/milestone 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /8.0/http/reservation-service/src/main/java/com/example/reservationservice/ReservationServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.reservationservice; 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.context.event.EventListener; 10 | import org.springframework.data.annotation.Id; 11 | import org.springframework.data.repository.reactive.ReactiveCrudRepository; 12 | import org.springframework.web.reactive.function.server.HandlerFunction; 13 | import org.springframework.web.reactive.function.server.RouterFunction; 14 | import org.springframework.web.reactive.function.server.ServerRequest; 15 | import org.springframework.web.reactive.function.server.ServerResponse; 16 | import reactor.core.publisher.Mono; 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 ReservationServiceApplication { 23 | 24 | public static void main(String[] args) { 25 | SpringApplication.run(ReservationServiceApplication.class, args); 26 | } 27 | 28 | @Bean 29 | RouterFunction routes(ReservationRepository rr) { 30 | return route() 31 | .GET("/reservations", r -> ok().body(rr.findAll(), Reservation.class)) 32 | .build(); 33 | } 34 | } 35 | 36 | interface ReservationRepository extends ReactiveCrudRepository { 37 | } 38 | 39 | @Data 40 | @AllArgsConstructor 41 | @NoArgsConstructor 42 | class Reservation { 43 | @Id 44 | private Integer id; 45 | private String name; 46 | } 47 | 48 | -------------------------------------------------------------------------------- /8.0/http/reservation-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.r2dbc.url=r2dbc:postgres://localhost/orders 2 | spring.r2dbc.username=orders 3 | spring.r2dbc.password=orders 4 | -------------------------------------------------------------------------------- /8.0/http/reservation-service/src/test/java/com/example/reservationservice/ReservationServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.reservationservice; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ReservationServiceApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /8.0/rsocket-gateway-deps.md: -------------------------------------------------------------------------------- 1 | 2 | spring.rsocket.server.port=7002 3 | 4 | 5 | org.springframework.cloud 6 | spring-cloud-rsocket-dependencies 7 | 0.2.0.BUILD-SNAPSHOT 8 | pom 9 | import 10 | 11 | 12 | 13 | 14 | org.springframework.cloud 15 | spring-cloud-rsocket-broker 16 | 17 | 18 | 19 | 20 | org.springframework.cloud 21 | spring-cloud-rsocket-client 22 | 23 | 24 | spring.rsocket.server.port=8888 25 | server.port=8081 26 | spring.application.name=greetings-service 27 | spring.cloud.gateway.rsocket.client.service-name=greetings-service 28 | spring.cloud.gateway.rsocket.client.route-id=3 29 | spring.cloud.gateway.rsocket.client.broker.host=localhost 30 | spring.cloud.gateway.rsocket.client.broker.port=7002 31 | 32 | 33 | @Bean 34 | ApplicationListener> gatewayClient(BrokerClient client) { 35 | return event -> 36 | event 37 | .getPayload() 38 | .route("greetings") 39 | .metadata(client.forwarding("greetings-service")) 40 | .data(new GreetingRequest("World")) 41 | .retrieveFlux(GreetingResponse.class) 42 | .subscribe(gr -> log.info("gateway rsocket client: " + gr.getMessage())); 43 | } -------------------------------------------------------------------------------- /8.0/rsocket/greetings-client/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong/reactive-spring-livelessons-2e/f10c568102d0634a050639973ba99f632580392f/8.0/rsocket/greetings-client/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /8.0/rsocket/greetings-client/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar 3 | -------------------------------------------------------------------------------- /8.0/rsocket/greetings-client/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 | * [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.2.3.BUILD-SNAPSHOT/maven-plugin/) 8 | 9 | -------------------------------------------------------------------------------- /8.0/rsocket/greetings-client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.3.BUILD-SNAPSHOT 9 | 10 | 11 | com.example 12 | greetings-client 13 | 0.0.1-SNAPSHOT 14 | greetings-client 15 | Demo project for Spring Boot 16 | 17 | 18 | Hoxton.BUILD-SNAPSHOT 19 | 13 20 | 21 | 22 | 23 | 24 | import 25 | pom 26 | 0.2.0.BUILD-SNAPSHOT 27 | org.springframework.cloud 28 | spring-cloud-rsocket-dependencies 29 | 30 | 31 | org.springframework.cloud 32 | spring-cloud-dependencies 33 | ${spring-cloud.version} 34 | pom 35 | import 36 | 37 | 38 | 39 | 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-starter-actuator 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-starter-rsocket 48 | 49 | 50 | org.springframework.cloud 51 | spring-cloud-rsocket-client 52 | 53 | 54 | org.projectlombok 55 | lombok 56 | true 57 | 58 | 59 | org.springframework.boot 60 | spring-boot-starter-test 61 | test 62 | 63 | 64 | org.junit.vintage 65 | junit-vintage-engine 66 | 67 | 68 | 69 | 70 | io.projectreactor 71 | reactor-test 72 | test 73 | 74 | 75 | 76 | 77 | 78 | 79 | org.springframework.boot 80 | spring-boot-maven-plugin 81 | 82 | 83 | 84 | 85 | 86 | 87 | spring-milestones 88 | Spring Milestones 89 | https://repo.spring.io/milestone 90 | 91 | 92 | spring-snapshots 93 | Spring Snapshots 94 | https://repo.spring.io/snapshot 95 | 96 | true 97 | 98 | 99 | 100 | 101 | 102 | spring-milestones 103 | Spring Milestones 104 | https://repo.spring.io/milestone 105 | 106 | 107 | spring-snapshots 108 | Spring Snapshots 109 | https://repo.spring.io/snapshot 110 | 111 | true 112 | 113 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /8.0/rsocket/greetings-client/src/main/java/com/example/greetingsclient/GreetingsClientApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.greetingsclient; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.RequiredArgsConstructor; 7 | import lombok.extern.log4j.Log4j2; 8 | import org.springframework.boot.SpringApplication; 9 | import org.springframework.boot.autoconfigure.SpringBootApplication; 10 | import org.springframework.cloud.gateway.rsocket.client.BrokerClient; 11 | import org.springframework.context.PayloadApplicationEvent; 12 | import org.springframework.context.event.EventListener; 13 | import org.springframework.messaging.rsocket.RSocketRequester; 14 | import org.springframework.stereotype.Component; 15 | 16 | @SpringBootApplication 17 | public class GreetingsClientApplication { 18 | 19 | public static void main(String[] args) { 20 | SpringApplication.run(GreetingsClientApplication.class, args); 21 | } 22 | } 23 | 24 | @Data 25 | @AllArgsConstructor 26 | @NoArgsConstructor 27 | class GreetingResponse { 28 | private String message; 29 | } 30 | 31 | @Data 32 | @AllArgsConstructor 33 | @NoArgsConstructor 34 | class GreetingRequest { 35 | private String name; 36 | } 37 | 38 | @Log4j2 39 | @Component 40 | @RequiredArgsConstructor 41 | class RSocketGatewayClient { 42 | 43 | private final BrokerClient client; 44 | 45 | @EventListener 46 | public void gatewayRsocketClient(PayloadApplicationEvent event) { 47 | event 48 | .getPayload() 49 | .route("greetings.{time}", 2) 50 | .metadata(client.forwarding("greetings-service")) 51 | .data(new GreetingRequest("Livelessons")) 52 | .retrieveFlux(GreetingResponse.class) 53 | .subscribe(gr -> log.info(gr.toString())); 54 | } 55 | 56 | 57 | } 58 | 59 | 60 | -------------------------------------------------------------------------------- /8.0/rsocket/greetings-client/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.rsocket.server.port=6000 2 | spring.application.name=greetings-client 3 | # 4 | spring.cloud.gateway.rsocket.client.service-name=${spring.application.name} 5 | spring.cloud.gateway.rsocket.client.route-id=5 6 | spring.cloud.gateway.rsocket.client.broker.port=9999 7 | spring.cloud.gateway.rsocket.client.broker.host=localhost 8 | -------------------------------------------------------------------------------- /8.0/rsocket/greetings-client/src/test/java/com/example/greetingsservice/GreetingsServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.greetingsservice; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class GreetingsServiceApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /8.0/rsocket/greetings-service/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong/reactive-spring-livelessons-2e/f10c568102d0634a050639973ba99f632580392f/8.0/rsocket/greetings-service/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /8.0/rsocket/greetings-service/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar 3 | -------------------------------------------------------------------------------- /8.0/rsocket/greetings-service/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 | * [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.2.3.BUILD-SNAPSHOT/maven-plugin/) 8 | 9 | -------------------------------------------------------------------------------- /8.0/rsocket/greetings-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.3.BUILD-SNAPSHOT 9 | 10 | 11 | com.example 12 | greetings-service 13 | 0.0.1-SNAPSHOT 14 | greetings-service 15 | Demo project for Spring Boot 16 | 17 | 18 | Hoxton.BUILD-SNAPSHOT 19 | 13 20 | 21 | 22 | 23 | 24 | import 25 | pom 26 | 0.2.0.BUILD-SNAPSHOT 27 | org.springframework.cloud 28 | spring-cloud-rsocket-dependencies 29 | 30 | 31 | org.springframework.cloud 32 | spring-cloud-dependencies 33 | ${spring-cloud.version} 34 | pom 35 | import 36 | 37 | 38 | 39 | 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-starter-actuator 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-starter-rsocket 48 | 49 | 50 | org.springframework.cloud 51 | spring-cloud-rsocket-client 52 | 53 | 54 | org.projectlombok 55 | lombok 56 | true 57 | 58 | 59 | org.springframework.boot 60 | spring-boot-starter-test 61 | test 62 | 63 | 64 | org.junit.vintage 65 | junit-vintage-engine 66 | 67 | 68 | 69 | 70 | io.projectreactor 71 | reactor-test 72 | test 73 | 74 | 75 | 76 | 77 | 78 | 79 | org.springframework.boot 80 | spring-boot-maven-plugin 81 | 82 | 83 | 84 | 85 | 86 | 87 | spring-milestones 88 | Spring Milestones 89 | https://repo.spring.io/milestone 90 | 91 | 92 | spring-snapshots 93 | Spring Snapshots 94 | https://repo.spring.io/snapshot 95 | 96 | true 97 | 98 | 99 | 100 | 101 | 102 | spring-milestones 103 | Spring Milestones 104 | https://repo.spring.io/milestone 105 | 106 | 107 | spring-snapshots 108 | Spring Snapshots 109 | https://repo.spring.io/snapshot 110 | 111 | true 112 | 113 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /8.0/rsocket/greetings-service/src/main/java/com/example/greetingsservice/GreetingsServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.greetingsservice; 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.messaging.handler.annotation.DestinationVariable; 9 | import org.springframework.messaging.handler.annotation.MessageMapping; 10 | import org.springframework.stereotype.Controller; 11 | import reactor.core.publisher.Flux; 12 | 13 | import java.time.Duration; 14 | import java.time.Instant; 15 | import java.util.function.Supplier; 16 | import java.util.stream.Stream; 17 | 18 | @SpringBootApplication 19 | public class GreetingsServiceApplication { 20 | 21 | public static void main(String[] args) { 22 | SpringApplication.run(GreetingsServiceApplication.class, args); 23 | } 24 | } 25 | 26 | @Controller 27 | class GreetingsRSocketController { 28 | 29 | @MessageMapping("greetings.{timeInSeconds}") 30 | Flux greet(@DestinationVariable int timeInSeconds, GreetingRequest greetingRequest) { 31 | return Flux 32 | .fromStream(Stream.generate(() -> new GreetingResponse("Hello " + greetingRequest.getName() + " @ " + Instant.now() + "!"))) 33 | .delayElements(Duration.ofSeconds(timeInSeconds)); 34 | } 35 | } 36 | 37 | @Data 38 | @AllArgsConstructor 39 | @NoArgsConstructor 40 | class GreetingResponse { 41 | private String message; 42 | } 43 | 44 | @Data 45 | @AllArgsConstructor 46 | @NoArgsConstructor 47 | class GreetingRequest { 48 | private String name; 49 | } -------------------------------------------------------------------------------- /8.0/rsocket/greetings-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.rsocket.server.port=8000 2 | spring.application.name=greetings-service 3 | # 4 | spring.cloud.gateway.rsocket.client.service-name=${spring.application.name} 5 | spring.cloud.gateway.rsocket.client.route-id=2 6 | spring.cloud.gateway.rsocket.client.broker.port=9999 7 | spring.cloud.gateway.rsocket.client.broker.host=localhost 8 | -------------------------------------------------------------------------------- /8.0/rsocket/greetings-service/src/test/java/com/example/greetingsservice/GreetingsServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.greetingsservice; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class GreetingsServiceApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /8.0/rsocket/rsocket-gateway/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong/reactive-spring-livelessons-2e/f10c568102d0634a050639973ba99f632580392f/8.0/rsocket/rsocket-gateway/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /8.0/rsocket/rsocket-gateway/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar 3 | -------------------------------------------------------------------------------- /8.0/rsocket/rsocket-gateway/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 | * [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.2.2.RELEASE/maven-plugin/) 8 | * [Cloud Bootstrap](https://spring.io/projects/spring-cloud-commons) 9 | * [Spring Boot Actuator](https://docs.spring.io/spring-boot/docs/2.2.2.RELEASE/reference/htmlsingle/#production-ready) 10 | 11 | ### Guides 12 | The following guides illustrate how to use some features concretely: 13 | 14 | * [Building a RESTful Web Service with Spring Boot Actuator](https://spring.io/guides/gs/actuator-service/) 15 | 16 | -------------------------------------------------------------------------------- /8.0/rsocket/rsocket-gateway/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.2.RELEASE 9 | 10 | 11 | com.example 12 | rsocket-gateway 13 | 0.0.1-SNAPSHOT 14 | rsocket-gateway 15 | Demo project for Spring Boot 16 | 17 | 18 | 13 19 | Hoxton.RELEASE 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-actuator 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-rsocket 30 | 31 | 32 | org.springframework.cloud 33 | spring-cloud-starter 34 | 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-test 39 | test 40 | 41 | 42 | org.junit.vintage 43 | junit-vintage-engine 44 | 45 | 46 | 47 | 48 | io.projectreactor 49 | reactor-test 50 | test 51 | 52 | 53 | org.springframework.cloud 54 | spring-cloud-rsocket-broker 55 | 56 | 57 | 58 | 59 | 60 | 61 | import 62 | pom 63 | 0.2.0.BUILD-SNAPSHOT 64 | org.springframework.cloud 65 | spring-cloud-rsocket-dependencies 66 | 67 | 68 | org.springframework.cloud 69 | spring-cloud-dependencies 70 | ${spring-cloud.version} 71 | pom 72 | import 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | org.springframework.boot 81 | spring-boot-maven-plugin 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /8.0/rsocket/rsocket-gateway/src/main/java/com/example/rsocketgateway/RsocketGatewayApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.rsocketgateway; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class RsocketGatewayApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(RsocketGatewayApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /8.0/rsocket/rsocket-gateway/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.rsocket.server.port=9999 2 | -------------------------------------------------------------------------------- /8.0/rsocket/rsocket-gateway/src/test/java/com/example/rsocketgateway/RsocketGatewayApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.rsocketgateway; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class RsocketGatewayApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /9.0/consumer/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/** 5 | !**/src/test/** 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | 30 | ### VS Code ### 31 | .vscode/ 32 | -------------------------------------------------------------------------------- /9.0/consumer/.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import java.net.*; 17 | import java.io.*; 18 | import java.nio.channels.*; 19 | import java.util.Properties; 20 | 21 | public class MavenWrapperDownloader { 22 | 23 | private static final String WRAPPER_VERSION = "0.5.5"; 24 | /** 25 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 26 | */ 27 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 28 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 29 | 30 | /** 31 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 32 | * use instead of the default one. 33 | */ 34 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 35 | ".mvn/wrapper/maven-wrapper.properties"; 36 | 37 | /** 38 | * Path where the maven-wrapper.jar will be saved to. 39 | */ 40 | private static final String MAVEN_WRAPPER_JAR_PATH = 41 | ".mvn/wrapper/maven-wrapper.jar"; 42 | 43 | /** 44 | * Name of the property which should be used to override the default download url for the wrapper. 45 | */ 46 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 47 | 48 | public static void main(String args[]) { 49 | System.out.println("- Downloader started"); 50 | File baseDirectory = new File(args[0]); 51 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 52 | 53 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 54 | // wrapperUrl parameter. 55 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 56 | String url = DEFAULT_DOWNLOAD_URL; 57 | if(mavenWrapperPropertyFile.exists()) { 58 | FileInputStream mavenWrapperPropertyFileInputStream = null; 59 | try { 60 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 61 | Properties mavenWrapperProperties = new Properties(); 62 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 63 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 64 | } catch (IOException e) { 65 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 66 | } finally { 67 | try { 68 | if(mavenWrapperPropertyFileInputStream != null) { 69 | mavenWrapperPropertyFileInputStream.close(); 70 | } 71 | } catch (IOException e) { 72 | // Ignore ... 73 | } 74 | } 75 | } 76 | System.out.println("- Downloading from: " + url); 77 | 78 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 79 | if(!outputFile.getParentFile().exists()) { 80 | if(!outputFile.getParentFile().mkdirs()) { 81 | System.out.println( 82 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 83 | } 84 | } 85 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 86 | try { 87 | downloadFileFromURL(url, outputFile); 88 | System.out.println("Done"); 89 | System.exit(0); 90 | } catch (Throwable e) { 91 | System.out.println("- Error downloading"); 92 | e.printStackTrace(); 93 | System.exit(1); 94 | } 95 | } 96 | 97 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 98 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 99 | String username = System.getenv("MVNW_USERNAME"); 100 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 101 | Authenticator.setDefault(new Authenticator() { 102 | @Override 103 | protected PasswordAuthentication getPasswordAuthentication() { 104 | return new PasswordAuthentication(username, password); 105 | } 106 | }); 107 | } 108 | URL website = new URL(urlString); 109 | ReadableByteChannel rbc; 110 | rbc = Channels.newChannel(website.openStream()); 111 | FileOutputStream fos = new FileOutputStream(destination); 112 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 113 | fos.close(); 114 | rbc.close(); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /9.0/consumer/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong/reactive-spring-livelessons-2e/f10c568102d0634a050639973ba99f632580392f/9.0/consumer/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /9.0/consumer/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar 3 | -------------------------------------------------------------------------------- /9.0/consumer/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.2.RELEASE 9 | 10 | 11 | com.example 12 | consumer 13 | 0.0.1-SNAPSHOT 14 | consumer 15 | Demo project for Spring Boot 16 | 17 | 18 | 13 19 | Hoxton.RELEASE 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 | 38 | 39 | io.projectreactor 40 | reactor-test 41 | test 42 | 43 | 44 | org.springframework.cloud 45 | spring-cloud-starter-contract-stub-runner 46 | test 47 | 48 | 49 | 50 | 51 | 52 | 53 | org.springframework.cloud 54 | spring-cloud-dependencies 55 | ${spring-cloud.version} 56 | pom 57 | import 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | org.springframework.boot 66 | spring-boot-maven-plugin 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /9.0/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 webClient(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 | -------------------------------------------------------------------------------- /9.0/consumer/src/main/java/com/example/consumer/Reservation.java: -------------------------------------------------------------------------------- 1 | package com.example.consumer; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Data 8 | @AllArgsConstructor 9 | @NoArgsConstructor 10 | public class Reservation { 11 | private String id, name; 12 | } 13 | -------------------------------------------------------------------------------- /9.0/consumer/src/main/java/com/example/consumer/ReservationClient.java: -------------------------------------------------------------------------------- 1 | package com.example.consumer; 2 | 3 | import lombok.RequiredArgsConstructor; 4 | import org.springframework.stereotype.Component; 5 | import org.springframework.web.reactive.function.client.WebClient; 6 | import reactor.core.publisher.Flux; 7 | 8 | @Component 9 | @RequiredArgsConstructor 10 | public class ReservationClient { 11 | 12 | private final WebClient webClient; 13 | 14 | public Flux getAllReservations() { 15 | return this.webClient 16 | .get() 17 | .uri("http://localhost:8080/reservations") 18 | .retrieve() 19 | .bodyToFlux(Reservation.class); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /9.0/consumer/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /9.0/consumer/src/test/java/com/example/consumer/ConsumerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.consumer; 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.context.SpringBootTest; 7 | import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner; 8 | import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; 9 | import org.springframework.test.context.junit4.SpringRunner; 10 | import reactor.core.publisher.Flux; 11 | import reactor.test.StepVerifier; 12 | 13 | @SpringBootTest 14 | @RunWith(SpringRunner.class) 15 | @AutoConfigureStubRunner( 16 | ids = "com.example:producer:+:8080", 17 | stubsMode = StubRunnerProperties.StubsMode.LOCAL 18 | ) 19 | public class ConsumerApplicationTests { 20 | 21 | @Autowired 22 | private ReservationClient client; 23 | 24 | @Test 25 | public void contextLoads() { 26 | Flux reservations = this.client.getAllReservations(); 27 | StepVerifier 28 | .create(reservations) 29 | .expectNextMatches(reservation -> 30 | reservation.getId() != null && reservation.getName().equalsIgnoreCase("Jane")) 31 | .verifyComplete(); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /9.0/producer/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/** 5 | !**/src/test/** 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | 30 | ### VS Code ### 31 | .vscode/ 32 | -------------------------------------------------------------------------------- /9.0/producer/.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import java.net.*; 17 | import java.io.*; 18 | import java.nio.channels.*; 19 | import java.util.Properties; 20 | 21 | public class MavenWrapperDownloader { 22 | 23 | private static final String WRAPPER_VERSION = "0.5.5"; 24 | /** 25 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 26 | */ 27 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 28 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 29 | 30 | /** 31 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 32 | * use instead of the default one. 33 | */ 34 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 35 | ".mvn/wrapper/maven-wrapper.properties"; 36 | 37 | /** 38 | * Path where the maven-wrapper.jar will be saved to. 39 | */ 40 | private static final String MAVEN_WRAPPER_JAR_PATH = 41 | ".mvn/wrapper/maven-wrapper.jar"; 42 | 43 | /** 44 | * Name of the property which should be used to override the default download url for the wrapper. 45 | */ 46 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 47 | 48 | public static void main(String args[]) { 49 | System.out.println("- Downloader started"); 50 | File baseDirectory = new File(args[0]); 51 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 52 | 53 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 54 | // wrapperUrl parameter. 55 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 56 | String url = DEFAULT_DOWNLOAD_URL; 57 | if(mavenWrapperPropertyFile.exists()) { 58 | FileInputStream mavenWrapperPropertyFileInputStream = null; 59 | try { 60 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 61 | Properties mavenWrapperProperties = new Properties(); 62 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 63 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 64 | } catch (IOException e) { 65 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 66 | } finally { 67 | try { 68 | if(mavenWrapperPropertyFileInputStream != null) { 69 | mavenWrapperPropertyFileInputStream.close(); 70 | } 71 | } catch (IOException e) { 72 | // Ignore ... 73 | } 74 | } 75 | } 76 | System.out.println("- Downloading from: " + url); 77 | 78 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 79 | if(!outputFile.getParentFile().exists()) { 80 | if(!outputFile.getParentFile().mkdirs()) { 81 | System.out.println( 82 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 83 | } 84 | } 85 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 86 | try { 87 | downloadFileFromURL(url, outputFile); 88 | System.out.println("Done"); 89 | System.exit(0); 90 | } catch (Throwable e) { 91 | System.out.println("- Error downloading"); 92 | e.printStackTrace(); 93 | System.exit(1); 94 | } 95 | } 96 | 97 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 98 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 99 | String username = System.getenv("MVNW_USERNAME"); 100 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 101 | Authenticator.setDefault(new Authenticator() { 102 | @Override 103 | protected PasswordAuthentication getPasswordAuthentication() { 104 | return new PasswordAuthentication(username, password); 105 | } 106 | }); 107 | } 108 | URL website = new URL(urlString); 109 | ReadableByteChannel rbc; 110 | rbc = Channels.newChannel(website.openStream()); 111 | FileOutputStream fos = new FileOutputStream(destination); 112 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 113 | fos.close(); 114 | rbc.close(); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /9.0/producer/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshlong/reactive-spring-livelessons-2e/f10c568102d0634a050639973ba99f632580392f/9.0/producer/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /9.0/producer/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar 3 | -------------------------------------------------------------------------------- /9.0/producer/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.2.RELEASE 9 | 10 | 11 | com.example 12 | producer 13 | 0.0.1-SNAPSHOT 14 | producer 15 | Demo project for Spring Boot 16 | 17 | 18 | 13 19 | Hoxton.RELEASE 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-data-mongodb-reactive 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-webflux 30 | 31 | 32 | 33 | org.projectlombok 34 | lombok 35 | true 36 | 37 | 44 | 45 | org.springframework.boot 46 | spring-boot-starter-test 47 | test 48 | 54 | 55 | 56 | io.projectreactor 57 | reactor-test 58 | test 59 | 60 | 61 | org.springframework.cloud 62 | spring-cloud-starter-contract-verifier 63 | test 64 | 65 | 66 | 67 | 68 | 69 | 70 | org.springframework.cloud 71 | spring-cloud-dependencies 72 | ${spring-cloud.version} 73 | pom 74 | import 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | org.springframework.cloud 83 | spring-cloud-contract-maven-plugin 84 | 2.2.0.RELEASE 85 | true 86 | 87 | 88 | com.example.producer.BaseClass 89 | 90 | 91 | EXPLICIT 92 | 93 | 94 | 95 | org.springframework.boot 96 | spring-boot-maven-plugin 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /9.0/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 | -------------------------------------------------------------------------------- /9.0/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 | 8 | @Data 9 | @AllArgsConstructor 10 | @NoArgsConstructor 11 | public class Reservation { 12 | private String id; 13 | private String name; 14 | } 15 | -------------------------------------------------------------------------------- /9.0/producer/src/main/java/com/example/producer/ReservationHttpConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.example.producer; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.web.reactive.function.server.HandlerFunction; 7 | import org.springframework.web.reactive.function.server.RouterFunction; 8 | import org.springframework.web.reactive.function.server.ServerRequest; 9 | import org.springframework.web.reactive.function.server.ServerResponse; 10 | import reactor.core.publisher.Mono; 11 | 12 | import static org.springframework.web.reactive.function.server.RouterFunctions.route; 13 | import static org.springframework.web.reactive.function.server.ServerResponse.*; 14 | 15 | @Configuration 16 | class ReservationHttpConfiguration { 17 | 18 | @Bean 19 | RouterFunction routes(ReservationRepository rr) { 20 | return route() 21 | .GET("/reservations", r -> ok().body(rr.findAll(), Reservation.class)) 22 | .build(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /9.0/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 | -------------------------------------------------------------------------------- /9.0/producer/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /9.0/producer/src/test/java/com/example/producer/BaseClass.java: -------------------------------------------------------------------------------- 1 | package com.example.producer; 2 | 3 | import io.restassured.RestAssured; 4 | import org.junit.Before; 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.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 org.springframework.test.web.reactive.server.WebTestClient; 13 | import reactor.core.publisher.Flux; 14 | 15 | @SpringBootTest( 16 | webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 17 | properties = "server.port=0") 18 | @RunWith(SpringRunner.class) 19 | public class BaseClass { 20 | 21 | @MockBean 22 | private ReservationRepository reservationRepository; 23 | 24 | @LocalServerPort 25 | private int port; 26 | 27 | @Before 28 | public void before() { 29 | RestAssured.baseURI = "http://localhost:" + this.port; 30 | Mockito 31 | .when(this.reservationRepository.findAll()) 32 | .thenReturn(Flux.just(new Reservation("1", "Jane"))); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /9.0/producer/src/test/java/com/example/producer/ReservationEntityTest.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.data.mongodb.core.ReactiveMongoTemplate; 8 | import org.springframework.test.context.junit4.SpringRunner; 9 | import reactor.core.publisher.Mono; 10 | import reactor.test.StepVerifier; 11 | 12 | @RunWith(SpringRunner.class) 13 | @DataMongoTest 14 | public class ReservationEntityTest { 15 | 16 | @Autowired 17 | private ReactiveMongoTemplate reactiveMongoTemplate; 18 | 19 | @Test 20 | public void persist() { 21 | Reservation reservation = new Reservation(null, "Jane"); 22 | Mono savedRecord = this.reactiveMongoTemplate.save(reservation); 23 | StepVerifier 24 | .create(savedRecord) 25 | .expectNextMatches(res -> res.getId() != null && res.getName().equalsIgnoreCase("Jane")) 26 | .verifyComplete(); 27 | 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /9.0/producer/src/test/java/com/example/producer/ReservationHttpTest.java: -------------------------------------------------------------------------------- 1 | package com.example.producer; 2 | 3 | import org.junit.Before; 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.context.annotation.Bean; 11 | import org.springframework.context.annotation.Configuration; 12 | import org.springframework.context.annotation.Import; 13 | import org.springframework.http.MediaType; 14 | import org.springframework.test.context.junit4.SpringRunner; 15 | import org.springframework.test.web.reactive.server.WebTestClient; 16 | import reactor.core.publisher.Flux; 17 | 18 | @WebFluxTest 19 | @Import({ReservationHttpConfiguration.class}) 20 | @RunWith(SpringRunner.class) 21 | public class ReservationHttpTest { 22 | 23 | @MockBean 24 | private ReservationRepository reservationRepository; 25 | 26 | @Autowired 27 | private WebTestClient testClient; 28 | 29 | @Before 30 | public void before() { 31 | Mockito 32 | .when(this.reservationRepository.findAll()) 33 | .thenReturn(Flux.just(new Reservation("1", "Jane"))); 34 | } 35 | 36 | @Test 37 | public void getAllReservations() throws Exception { 38 | 39 | this.testClient 40 | .get() 41 | .uri("/reservations") 42 | .exchange() 43 | .expectStatus().isOk() 44 | .expectHeader().contentType(MediaType.APPLICATION_JSON) 45 | .expectBody().jsonPath("@.[0].name").isEqualTo("Jane"); 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /9.0/producer/src/test/java/com/example/producer/ReservationPojoTest.java: -------------------------------------------------------------------------------- 1 | package com.example.producer; 2 | 3 | import org.hamcrest.BaseMatcher; 4 | import org.hamcrest.Description; 5 | import org.hamcrest.Matcher; 6 | import org.hamcrest.Matchers; 7 | import org.junit.After; 8 | import org.junit.Assert; 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | 12 | public class ReservationPojoTest { 13 | 14 | 15 | 16 | @Test 17 | public void create() { 18 | Reservation reservation = new Reservation("1", "Jane"); 19 | Assert.assertEquals(reservation.getId(), "1"); 20 | Assert.assertEquals(reservation.getName(), "Jane"); 21 | Assert.assertNotNull(reservation.getId()); 22 | Assert.assertThat(reservation.getName(), Matchers.equalToIgnoringCase("Jane")); 23 | Assert.assertThat(reservation.getName(), new ValidNameMatcher()); 24 | } 25 | 26 | 27 | } 28 | 29 | class ValidNameMatcher extends BaseMatcher { 30 | 31 | @Override 32 | public boolean matches(Object o) { 33 | return o instanceof String && isValidName((String) o); 34 | } 35 | 36 | @Override 37 | public void describeTo(Description description) { 38 | description.appendText("the name must be non-empty and start with an uppercase letter"); 39 | } 40 | 41 | private boolean isValidName(String name) { 42 | return name != null && name.length() > 0 && Character.isUpperCase(name.charAt(0)); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /9.0/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.core.publisher.Mono; 10 | import reactor.test.StepVerifier; 11 | 12 | @RunWith(SpringRunner.class) 13 | @DataMongoTest 14 | public class ReservationRepositoryTest { 15 | 16 | @Autowired 17 | private ReservationRepository repository; 18 | 19 | @Test 20 | public void persist() throws Exception { 21 | 22 | Flux reservationFlux = this.repository.saveAll( 23 | Flux.just(new Reservation(null, "A"), 24 | new Reservation(null, "B"), 25 | new Reservation(null, "C"), 26 | new Reservation(null, "A"))); 27 | 28 | StepVerifier 29 | .create(this.repository.deleteAll()) 30 | .verifyComplete(); 31 | 32 | StepVerifier 33 | .create(reservationFlux) 34 | .expectNextCount(4) 35 | .verifyComplete(); 36 | 37 | StepVerifier 38 | .create(this.repository.findByName("A")) 39 | .expectNextCount(2) 40 | .verifyComplete(); 41 | 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /9.0/producer/src/test/resources/contracts/shouldReturnAllReservations.groovy: -------------------------------------------------------------------------------- 1 | import org.springframework.cloud.contract.spec.Contract 2 | import org.springframework.http.HttpStatus 3 | import org.springframework.http.MediaType 4 | 5 | Contract.make { 6 | description("should return all Reservations") 7 | request { 8 | method("GET") 9 | url("/reservations") 10 | } 11 | response { 12 | status(HttpStatus.OK.value()) 13 | headers { 14 | contentType(MediaType.APPLICATION_JSON_VALUE) 15 | } 16 | body([[id: "1", name: "Jane"]]) 17 | } 18 | } -------------------------------------------------------------------------------- /reactive-spring.md: -------------------------------------------------------------------------------- 1 | ## Basics 2 | * Motivations for Reactive Programming 3 | * Reactive Streams and Java 9 `Flow` 4 | * Project Reactor 5 | * The Spring Initializr 6 | 7 | ## Data 8 | * NoSQL with MongoDB 9 | * SQL with R2DBC 10 | * Transactions 11 | 12 | ## HTTP Services 13 | * Spring MVC-style HTTP Controllers 14 | * Functional Reactive-style Controllers 15 | * Server-Sent Events 16 | 17 | ## WebSockets 18 | * a simple never ending websocket example 19 | * JavaScript to talk to it 20 | 21 | ## HTTP Clients 22 | * The Reactive HTTP Client 23 | * Reactor Error Handling 24 | * Spring Cloud Circuit Breaker 25 | * Service Hedging 26 | 27 | ## RSocket 28 | * Motivations 29 | * Raw RSocket 30 | * RSocket in Spring 31 | 32 | ## Security 33 | * Motivations 34 | * HTTP 35 | * RSocket 36 | 37 | ## Gateway 38 | * Motivations 39 | * HTTP 40 | * RSocket 41 | 42 | ## Kotlin 43 | * Basics 44 | * Koroutines (see Spring Tips) 45 | 46 | ## Reactive Streams Redux 47 | * Akka Streams 48 | 49 | ## Testing 50 | * Motivations for Test-Driven Development 51 | * Basic Testing 52 | * Testing Data Tier 53 | * Testing the Web Tier 54 | * Testing a Client 55 | * Microservice Testing 56 | 57 | --------------------------------------------------------------------------------