├── .gitignore ├── LICENSE ├── README.md ├── crud ├── client │ ├── .gitignore │ ├── lombok.config │ ├── nbactions.xml │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── client │ │ │ │ └── ClientApplication.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── consumer │ │ └── ConsumerApplicationTests.java └── server │ ├── .gitignore │ ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── demo │ │ │ └── DemoApplication.java │ └── resources │ │ ├── application.properties │ │ ├── data.sql │ │ └── schema.sql │ └── test │ ├── java │ └── com │ │ └── example │ │ └── demo │ │ ├── IntegrationTests.java │ │ └── PostRepositoryTest.java │ └── resources │ └── junit-platform.properties ├── docs ├── GUIDE.md ├── _config.yml ├── crud.md ├── index.md ├── msg.png ├── rsocket.svg ├── run.png ├── spring.jpg └── springboot.png ├── integration ├── client-regular │ ├── .gitignore │ ├── nbactions.xml │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── demo │ │ │ └── DemoApplication.java │ │ └── resources │ │ └── application.properties ├── client │ ├── .gitignore │ ├── nbactions.xml │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── demo │ │ │ └── DemoApplication.java │ │ └── resources │ │ └── application.properties ├── server-regular │ ├── .gitignore │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── demo │ │ │ └── DemoApplication.java │ │ └── resources │ │ └── application.properties ├── server-vanilla │ ├── .gitignore │ ├── nbactions.xml │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── demo │ │ │ │ └── DemoApplication.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── demo │ │ └── DemoApplicationTests.java └── server │ ├── .gitignore │ ├── pom.xml │ └── src │ └── main │ ├── java │ └── com │ │ └── example │ │ └── demo │ │ └── DemoApplication.java │ └── resources │ └── application.properties ├── security ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── lombok.config ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── demo │ │ │ └── DemoApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── example │ └── demo │ └── DemoApplicationTests.java ├── server-requester ├── client │ ├── .gitignore │ ├── lombok.config │ ├── nbactions.xml │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── client │ │ │ └── ClientApplication.java │ │ └── resources │ │ └── application.properties └── server │ ├── .gitignore │ ├── lombok.config │ ├── nbactions.xml │ ├── pom.xml │ └── src │ └── main │ ├── java │ └── com │ │ └── example │ │ └── demo │ │ └── DemoApplication.java │ └── resources │ └── application.properties ├── tcp ├── client │ ├── .gitignore │ ├── lombok.config │ ├── nbactions.xml │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── client │ │ │ │ └── ClientApplication.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── consumer │ │ └── ConsumerApplicationTests.java └── server │ ├── .gitignore │ ├── nbactions.xml │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── server │ │ │ └── ServerApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── example │ └── producer │ └── ProducerApplicationTests.java ├── vanilla ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── demo │ │ │ ├── DemoApplication.java │ │ │ ├── FireAndForgetExample.java │ │ │ ├── RequestChannelExample.java │ │ │ ├── RequestResponseExample.java │ │ │ └── RequestStreamExample.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── example │ └── demo │ └── DemoApplicationTests.java └── websocket ├── client ├── .gitignore ├── lombok.config ├── nbactions.xml ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── client │ │ │ └── ClientApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── example │ └── consumer │ └── ConsumerApplicationTests.java └── server ├── .gitignore ├── nbactions.xml ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── example │ │ └── server │ │ ├── HelloController.java │ │ └── ServerApplication.java └── resources │ └── application.properties └── test └── java └── com └── example └── producer └── ProducerApplicationTests.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RSocket Sandbox 2 | 3 | Sample codes of RSocket Java and Spring RSocket integration. 4 | 5 | ## Docs 6 | 7 | [Using Rsocket with Spring Boot](./docs/GUIDE.md)([medium's link](https://medium.com/@hantsy/using-rsocket-with-spring-boot-cfc67924d06a)) 8 | 9 | [Building a CRUD application with RSocket and Spring](./docs/crud.md) 10 | 11 | ## Sample Codes 12 | 13 | * **vanilla** rsocket-java sample 14 | 15 | * **tcp** Spring Boot based application using TCP protocol between client and server 16 | 17 | * **websocket** Using WebSocket as transport protocol instead in a Webflux server. 18 | 19 | * **security** Spring Security RSocket integration. 20 | 21 | * **server-requester** Sending message to client via Server `RSocketRequster`. 22 | 23 | * **integration** Spring Integration RSocket inbound and outbound gateway. 24 | 25 | * **client** Sending messages to server via Spring Integration RSocket OutboundGateay. 26 | * **client-regular** Simple example using Spring Boot RSocket Starter aka `RSocketRequestor`. 27 | * **server-vanilla** Handling messages via Spring Integration RSocket InboundGateway. 28 | * **server** Similar with **server-vanilla**, but reuse Spring Boot RSocket Starter and declare the `ServerRSocketConnecter` bean through `ServerRSocketMessageHandler`. 29 | * **server-regular** Simple example using Spring Boot RSocket Starter aka `@Controller` and `@MessageMapping`. 30 | * **crud** Client and server CRUD interaction sample. 31 | * **client** Sending messages to server via `RSocketRequestor` and TCP protocol. 32 | * **server** Running on Netty/TCP(no web/http support) and handling request via TCP protocol. 33 | 34 | ## References 35 | 36 | * [Spring Framework Reference](https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/web-reactive.html#rsocket) 37 | * [Spring Secuirty Reference](https://docs.spring.io/spring-security/site/docs/current/reference/html/rsocket.html) 38 | * [Spring Boot Reference](https://docs.spring.io/spring-boot/docs/2.2.4.RELEASE/reference/htmlsingle/#boot-features-rsocket) 39 | * [Spring Integration Reference](https://docs.spring.io/spring-integration/reference/html/rsocket.html) 40 | * [RSocket Using Spring Boot](https://www.baeldung.com/spring-boot-rsocket) by Baeldung 41 | * [RSocket Messaging with Spring](https://www.youtube.com/watch?v=iSSrZoGtoSE) 42 | * [Reactive Architectures with RSocket and Spring Cloud Gateway](https://www.youtube.com/watch?v=PfbycN_eqhg) 43 | 44 | * [bclozel/spring-flights](https://github.com/bclozel/spring-flights) 45 | * [spring-projects/spring-security/tree/5.2.2.RELEASE/samples/boot/hellorsocket](https://github.com/spring-projects/spring-security/tree/5.2.2.RELEASE/samples/boot/hellorsocket) 46 | * [spencergibb/rsocket-routing-sample](https://github.com/spencergibb/rsocket-routing-sample) 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /crud/client/.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 | -------------------------------------------------------------------------------- /crud/client/lombok.config: -------------------------------------------------------------------------------- 1 | lombok.noArgsConstructor.extraPrivate=true 2 | -------------------------------------------------------------------------------- /crud/client/nbactions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | run 5 | 6 | jar 7 | 8 | 9 | spring-boot:run 10 | 11 | 12 | -noverify -XX:TieredStopAtLevel=1 13 | com.example.consumer.ConsumerApplication 14 | always 15 | 16 | 17 | 18 | debug 19 | 20 | jar 21 | 22 | 23 | spring-boot:run 24 | 25 | 26 | -Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address} -noverify -XX:TieredStopAtLevel=1 27 | com.example.consumer.ConsumerApplication 28 | always 29 | true 30 | 31 | 32 | 33 | profile 34 | 35 | jar 36 | 37 | 38 | process-classes 39 | org.codehaus.mojo:exec-maven-plugin:1.2.1:exec 40 | 41 | 42 | -classpath %classpath com.example.consumer.ConsumerApplication 43 | java 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /crud/client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.3.0.RELEASE 9 | 10 | 11 | com.example 12 | rsocket-sample-boot-crud-client 13 | 0.0.1-SNAPSHOT 14 | rsocket-sample-boot-crud-client 15 | Demo project for Spring Boot 16 | 17 | 18 | 11 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-webflux 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-rsocket 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 | 49 | 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-maven-plugin 54 | 55 | 56 | 57 | 58 | 59 | 60 | spring-milestones 61 | Spring Milestones 62 | https://repo.spring.io/milestone 63 | 64 | 65 | 66 | 67 | spring-milestones 68 | Spring Milestones 69 | https://repo.spring.io/milestone 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /crud/client/src/main/java/com/example/client/ClientApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.client; 2 | 3 | import lombok.*; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.messaging.rsocket.RSocketRequester; 9 | import org.springframework.util.MimeTypeUtils; 10 | import org.springframework.util.StringUtils; 11 | import org.springframework.web.bind.annotation.*; 12 | import reactor.core.publisher.Flux; 13 | import reactor.core.publisher.Mono; 14 | 15 | @SpringBootApplication 16 | public class ClientApplication { 17 | 18 | public static void main(String[] args) { 19 | SpringApplication.run(ClientApplication.class, args); 20 | } 21 | 22 | @Bean 23 | public RSocketRequester rSocketRequester(RSocketRequester.Builder b) { 24 | return b.dataMimeType(MimeTypeUtils.APPLICATION_JSON) 25 | .connectTcp("localhost", 7000) 26 | .block(); 27 | } 28 | 29 | } 30 | 31 | @Slf4j 32 | @RequiredArgsConstructor 33 | @RestController() 34 | @RequestMapping("/posts") 35 | class PostClientController { 36 | 37 | private final RSocketRequester requester; 38 | 39 | @GetMapping("") 40 | Flux all(@RequestParam(name = "title", required = false) String title) { 41 | if (StringUtils.hasText(title)) { 42 | return this.requester.route("posts.titleContains") 43 | .data(title).retrieveFlux(Post.class); 44 | } else { 45 | return this.requester.route("posts.findAll") 46 | .retrieveFlux(Post.class); 47 | } 48 | } 49 | 50 | @GetMapping("{id}") 51 | Mono findById(@PathVariable Integer id) { 52 | return this.requester.route("posts.findById." + id) 53 | .retrieveMono(Post.class); 54 | } 55 | 56 | @PostMapping("") 57 | Mono save(@RequestBody Post post) { 58 | return this.requester.route("posts.save") 59 | .data(post) 60 | .retrieveMono(Post.class); 61 | } 62 | 63 | @PutMapping("{id}") 64 | Mono update(@PathVariable Integer id, @RequestBody Post post) { 65 | return this.requester.route("posts.update."+ id) 66 | .data(post) 67 | .retrieveMono(Post.class); 68 | } 69 | 70 | @DeleteMapping("{id}") 71 | Mono delete(@PathVariable Integer id) { 72 | return this.requester.route("posts.deleteById."+ id).send(); 73 | } 74 | 75 | } 76 | 77 | @Data 78 | @ToString 79 | @Builder 80 | @NoArgsConstructor 81 | @AllArgsConstructor 82 | class Post { 83 | private Integer id; 84 | private String title; 85 | private String content; 86 | } 87 | -------------------------------------------------------------------------------- /crud/client/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /crud/client/src/test/java/com/example/consumer/ConsumerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.consumer; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ConsumerApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /crud/server/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /build/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ -------------------------------------------------------------------------------- /crud/server/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantsy/rsocket-sample/7349fd955764b163ac061b00d30d8a8646a0fcdd/crud/server/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /crud/server/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.5.4/apache-maven-3.5.4-bin.zip 2 | -------------------------------------------------------------------------------- /crud/server/mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Mingw, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | # TODO classpath? 118 | fi 119 | 120 | if [ -z "$JAVA_HOME" ]; then 121 | javaExecutable="`which javac`" 122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 123 | # readlink(1) is not available as standard on Solaris 10. 124 | readLink=`which readlink` 125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 126 | if $darwin ; then 127 | javaHome="`dirname \"$javaExecutable\"`" 128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 129 | else 130 | javaExecutable="`readlink -f \"$javaExecutable\"`" 131 | fi 132 | javaHome="`dirname \"$javaExecutable\"`" 133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 134 | JAVA_HOME="$javaHome" 135 | export JAVA_HOME 136 | fi 137 | fi 138 | fi 139 | 140 | if [ -z "$JAVACMD" ] ; then 141 | if [ -n "$JAVA_HOME" ] ; then 142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 143 | # IBM's JDK on AIX uses strange locations for the executables 144 | JAVACMD="$JAVA_HOME/jre/sh/java" 145 | else 146 | JAVACMD="$JAVA_HOME/bin/java" 147 | fi 148 | else 149 | JAVACMD="`which java`" 150 | fi 151 | fi 152 | 153 | if [ ! -x "$JAVACMD" ] ; then 154 | echo "Error: JAVA_HOME is not defined correctly." >&2 155 | echo " We cannot execute $JAVACMD" >&2 156 | exit 1 157 | fi 158 | 159 | if [ -z "$JAVA_HOME" ] ; then 160 | echo "Warning: JAVA_HOME environment variable is not set." 161 | fi 162 | 163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 164 | 165 | # traverses directory structure from process work directory to filesystem root 166 | # first directory with .mvn subdirectory is considered project base directory 167 | find_maven_basedir() { 168 | 169 | if [ -z "$1" ] 170 | then 171 | echo "Path not specified to find_maven_basedir" 172 | return 1 173 | fi 174 | 175 | basedir="$1" 176 | wdir="$1" 177 | while [ "$wdir" != '/' ] ; do 178 | if [ -d "$wdir"/.mvn ] ; then 179 | basedir=$wdir 180 | break 181 | fi 182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 183 | if [ -d "${wdir}" ]; then 184 | wdir=`cd "$wdir/.."; pwd` 185 | fi 186 | # end of workaround 187 | done 188 | echo "${basedir}" 189 | } 190 | 191 | # concatenates all lines of a file 192 | concat_lines() { 193 | if [ -f "$1" ]; then 194 | echo "$(tr -s '\n' ' ' < "$1")" 195 | fi 196 | } 197 | 198 | BASE_DIR=`find_maven_basedir "$(pwd)"` 199 | if [ -z "$BASE_DIR" ]; then 200 | exit 1; 201 | fi 202 | 203 | ########################################################################################## 204 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 205 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 206 | ########################################################################################## 207 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 208 | if [ "$MVNW_VERBOSE" = true ]; then 209 | echo "Found .mvn/wrapper/maven-wrapper.jar" 210 | fi 211 | else 212 | if [ "$MVNW_VERBOSE" = true ]; then 213 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 214 | fi 215 | jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" 216 | while IFS="=" read key value; do 217 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 218 | esac 219 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 220 | if [ "$MVNW_VERBOSE" = true ]; then 221 | echo "Downloading from: $jarUrl" 222 | fi 223 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 224 | 225 | if command -v wget > /dev/null; then 226 | if [ "$MVNW_VERBOSE" = true ]; then 227 | echo "Found wget ... using wget" 228 | fi 229 | wget "$jarUrl" -O "$wrapperJarPath" 230 | elif command -v curl > /dev/null; then 231 | if [ "$MVNW_VERBOSE" = true ]; then 232 | echo "Found curl ... using curl" 233 | fi 234 | curl -o "$wrapperJarPath" "$jarUrl" 235 | else 236 | if [ "$MVNW_VERBOSE" = true ]; then 237 | echo "Falling back to using Java to download" 238 | fi 239 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 240 | if [ -e "$javaClass" ]; then 241 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 242 | if [ "$MVNW_VERBOSE" = true ]; then 243 | echo " - Compiling MavenWrapperDownloader.java ..." 244 | fi 245 | # Compiling the Java class 246 | ("$JAVA_HOME/bin/javac" "$javaClass") 247 | fi 248 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 249 | # Running the downloader 250 | if [ "$MVNW_VERBOSE" = true ]; then 251 | echo " - Running MavenWrapperDownloader.java ..." 252 | fi 253 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 254 | fi 255 | fi 256 | fi 257 | fi 258 | ########################################################################################## 259 | # End of extension 260 | ########################################################################################## 261 | 262 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 263 | if [ "$MVNW_VERBOSE" = true ]; then 264 | echo $MAVEN_PROJECTBASEDIR 265 | fi 266 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 267 | 268 | # For Cygwin, switch paths to Windows format before running java 269 | if $cygwin; then 270 | [ -n "$M2_HOME" ] && 271 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 272 | [ -n "$JAVA_HOME" ] && 273 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 274 | [ -n "$CLASSPATH" ] && 275 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 276 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 277 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 278 | fi 279 | 280 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 281 | 282 | exec "$JAVACMD" \ 283 | $MAVEN_OPTS \ 284 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 285 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 286 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 287 | -------------------------------------------------------------------------------- /crud/server/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" 124 | FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( 125 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 126 | ) 127 | 128 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 129 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 130 | if exist %WRAPPER_JAR% ( 131 | echo Found %WRAPPER_JAR% 132 | ) else ( 133 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 134 | echo Downloading from: %DOWNLOAD_URL% 135 | powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" 136 | echo Finished downloading %WRAPPER_JAR% 137 | ) 138 | @REM End of extension 139 | 140 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 141 | if ERRORLEVEL 1 goto error 142 | goto end 143 | 144 | :error 145 | set ERROR_CODE=1 146 | 147 | :end 148 | @endlocal & set ERROR_CODE=%ERROR_CODE% 149 | 150 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 151 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 152 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 153 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 154 | :skipRcPost 155 | 156 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 157 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 158 | 159 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 160 | 161 | exit /B %ERROR_CODE% 162 | -------------------------------------------------------------------------------- /crud/server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.springframework.boot 8 | spring-boot-starter-parent 9 | 2.3.0.RELEASE 10 | 11 | 12 | com.example 13 | rsocket-sample-boot-crud-server 14 | 0.0.1-SNAPSHOT 15 | rsocket-sample-boot-crud-server 16 | Demo project for Spring Boot 17 | 18 | 19 | 11 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-rsocket 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-data-r2dbc 29 | 30 | 31 | io.r2dbc 32 | r2dbc-h2 33 | runtime 34 | 35 | 36 | org.projectlombok 37 | lombok 38 | true 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-starter-test 43 | test 44 | 45 | 46 | org.junit.vintage 47 | junit-vintage-engine 48 | 49 | 50 | 51 | 52 | io.projectreactor 53 | reactor-test 54 | test 55 | 56 | 57 | 58 | 59 | 60 | 61 | org.springframework.boot 62 | spring-boot-maven-plugin 63 | 64 | 65 | 66 | 67 | 68 | 69 | spring-snapshots 70 | Spring Snapshots 71 | https://repo.spring.io/snapshot 72 | 73 | true 74 | 75 | 76 | 77 | spring-milestones 78 | Spring Milestones 79 | https://repo.spring.io/milestone 80 | 81 | false 82 | 83 | 84 | 85 | 86 | 87 | 88 | spring-snapshots 89 | Spring Snapshots 90 | https://repo.spring.io/snapshot 91 | 92 | true 93 | 94 | 95 | 96 | spring-milestones 97 | Spring Milestones 98 | https://repo.spring.io/milestone 99 | 100 | false 101 | 102 | 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /crud/server/src/main/java/com/example/demo/DemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import io.r2dbc.spi.ConnectionFactory; 4 | import lombok.*; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.boot.ApplicationArguments; 7 | import org.springframework.boot.ApplicationRunner; 8 | import org.springframework.boot.SpringApplication; 9 | import org.springframework.boot.autoconfigure.SpringBootApplication; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.core.io.ClassPathResource; 12 | import org.springframework.data.annotation.Id; 13 | import org.springframework.data.r2dbc.connectionfactory.init.CompositeDatabasePopulator; 14 | import org.springframework.data.r2dbc.connectionfactory.init.ConnectionFactoryInitializer; 15 | import org.springframework.data.r2dbc.connectionfactory.init.ResourceDatabasePopulator; 16 | import org.springframework.data.r2dbc.repository.Query; 17 | import org.springframework.data.r2dbc.repository.R2dbcRepository; 18 | import org.springframework.data.relational.core.mapping.Column; 19 | import org.springframework.data.relational.core.mapping.Table; 20 | import org.springframework.messaging.handler.annotation.DestinationVariable; 21 | import org.springframework.messaging.handler.annotation.MessageMapping; 22 | import org.springframework.messaging.handler.annotation.Payload; 23 | import org.springframework.stereotype.Component; 24 | import org.springframework.stereotype.Controller; 25 | import reactor.core.publisher.Flux; 26 | import reactor.core.publisher.Mono; 27 | 28 | import java.util.List; 29 | 30 | @SpringBootApplication 31 | public class DemoApplication { 32 | 33 | public static void main(String[] args) { 34 | SpringApplication.run(DemoApplication.class, args); 35 | } 36 | 37 | @Bean 38 | public ConnectionFactoryInitializer initializer(ConnectionFactory connectionFactory) { 39 | 40 | ConnectionFactoryInitializer initializer = new ConnectionFactoryInitializer(); 41 | initializer.setConnectionFactory(connectionFactory); 42 | 43 | CompositeDatabasePopulator populator = new CompositeDatabasePopulator(); 44 | populator.addPopulators(new ResourceDatabasePopulator(new ClassPathResource("schema.sql"))); 45 | populator.addPopulators(new ResourceDatabasePopulator(new ClassPathResource("data.sql"))); 46 | initializer.setDatabasePopulator(populator); 47 | 48 | return initializer; 49 | } 50 | } 51 | 52 | @Component 53 | @Slf4j 54 | @RequiredArgsConstructor 55 | class DataInitializer implements ApplicationRunner { 56 | 57 | private final PostRepository posts; 58 | 59 | @Override 60 | public void run(ApplicationArguments args) throws Exception { 61 | log.info("start data initialization..."); 62 | this.posts 63 | .saveAll( 64 | List.of( 65 | Post.builder().title("Post one").content("The content of post one").build(), 66 | Post.builder().title("Post tow").content("The content of post tow").build() 67 | ) 68 | ) 69 | .log() 70 | .thenMany( 71 | this.posts.findAll() 72 | ) 73 | .subscribe( 74 | (data) -> log.info("post: " + data), 75 | (err) -> log.error("error: " + err), 76 | () -> log.info("initialization done...") 77 | ); 78 | } 79 | } 80 | 81 | @Controller 82 | @RequiredArgsConstructor 83 | class PostController { 84 | 85 | private final PostRepository posts; 86 | 87 | @MessageMapping("posts.findAll") 88 | public Flux all() { 89 | return this.posts.findAll(); 90 | } 91 | 92 | @MessageMapping("posts.titleContains") 93 | public Flux titleContains(@Payload String title) { 94 | return this.posts.findByTitleContains(title); 95 | } 96 | 97 | @MessageMapping("posts.findById.{id}") 98 | public Mono get(@DestinationVariable("id") Integer id) { 99 | return this.posts.findById(id); 100 | } 101 | 102 | @MessageMapping("posts.save") 103 | public Mono create(@Payload Post post) { 104 | return this.posts.save(post); 105 | } 106 | 107 | @MessageMapping("posts.update.{id}") 108 | public Mono update(@DestinationVariable("id") Integer id, @Payload Post post) { 109 | return this.posts.findById(id) 110 | .map(p -> { 111 | p.setTitle(post.getTitle()); 112 | p.setContent(post.getContent()); 113 | 114 | return p; 115 | }) 116 | .flatMap(p -> this.posts.save(p)); 117 | } 118 | 119 | @MessageMapping("posts.deleteById.{id}") 120 | public Mono delete(@DestinationVariable("id") Integer id) { 121 | return this.posts.deleteById(id); 122 | } 123 | 124 | } 125 | 126 | interface PostRepository extends R2dbcRepository { 127 | 128 | @Query("SELECT * FROM posts WHERE title like $1") 129 | Flux findByTitleContains(String name); 130 | 131 | } 132 | 133 | @Data 134 | @ToString 135 | @Builder 136 | @NoArgsConstructor 137 | @AllArgsConstructor 138 | @Table("posts") 139 | class Post { 140 | 141 | @Id 142 | @Column("id") 143 | private Integer id; 144 | 145 | @Column("title") 146 | private String title; 147 | 148 | @Column("content") 149 | private String content; 150 | 151 | } 152 | -------------------------------------------------------------------------------- /crud/server/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.rsocket.server.port=7000 2 | spring.rsocket.server.transport=tcp 3 | -------------------------------------------------------------------------------- /crud/server/src/main/resources/data.sql: -------------------------------------------------------------------------------- 1 | DELETE FROM posts; 2 | INSERT INTO posts (title, content) VALUES ('post one in data.sql', 'content of post one in data.sql'); -------------------------------------------------------------------------------- /crud/server/src/main/resources/schema.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE posts (id SERIAL PRIMARY KEY, title VARCHAR(255), content VARCHAR(255)); -------------------------------------------------------------------------------- /crud/server/src/test/java/com/example/demo/IntegrationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import org.junit.jupiter.api.BeforeAll; 4 | import org.junit.jupiter.api.Test; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.rsocket.context.LocalRSocketServerPort; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | import org.springframework.messaging.rsocket.RSocketRequester; 9 | import reactor.test.StepVerifier; 10 | 11 | import static org.junit.jupiter.api.Assertions.assertEquals; 12 | 13 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 14 | public class IntegrationTests { 15 | 16 | @LocalRSocketServerPort 17 | int port; 18 | 19 | RSocketRequester rSocketRequester; 20 | 21 | @Autowired 22 | RSocketRequester.Builder builder; 23 | 24 | @BeforeAll 25 | public void setup() { 26 | this.rSocketRequester = builder.connectTcp("localhost", port).block(); 27 | } 28 | 29 | @Test 30 | public void willLoadPosts() { 31 | this.rSocketRequester.route("posts.findAll") 32 | .retrieveFlux(Post.class) 33 | .as(StepVerifier::create) 34 | .expectNextCount(3) 35 | .verifyComplete(); 36 | } 37 | 38 | @Test 39 | public void testTitleContains() { 40 | this.rSocketRequester.route("posts.titleContains") 41 | .data("%data.sql") 42 | .retrieveFlux(Post.class) 43 | .take(1) 44 | .as(StepVerifier::create) 45 | .consumeNextWith(p -> assertEquals("post one in data.sql", p.getTitle())) 46 | .verifyComplete(); 47 | } 48 | 49 | } 50 | 51 | -------------------------------------------------------------------------------- /crud/server/src/test/java/com/example/demo/PostRepositoryTest.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | 4 | import org.junit.jupiter.api.Test; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.test.autoconfigure.data.r2dbc.DataR2dbcTest; 7 | import org.springframework.data.r2dbc.core.DatabaseClient; 8 | import reactor.test.StepVerifier; 9 | 10 | import java.time.Duration; 11 | 12 | import static org.junit.jupiter.api.Assertions.assertEquals; 13 | import static org.junit.jupiter.api.Assertions.assertNotNull; 14 | 15 | // see: https://github.com/spring-projects-experimental/spring-boot-r2dbc/issues/68 16 | @DataR2dbcTest 17 | public class PostRepositoryTest { 18 | 19 | @Autowired 20 | DatabaseClient client; 21 | 22 | @Autowired 23 | PostRepository posts; 24 | 25 | @Test 26 | public void testDatabaseClientExisted() { 27 | assertNotNull(client); 28 | } 29 | 30 | @Test 31 | public void testPostRepositoryExisted() { 32 | assertNotNull(posts); 33 | } 34 | 35 | @Test 36 | public void testInsertAndQuery() { 37 | this.client.insert() 38 | .into("posts") 39 | //.nullValue("id", Integer.class) 40 | .value("title", "mytesttitle") 41 | .value("content", "testcontent") 42 | .then().block(Duration.ofSeconds(5)); 43 | 44 | this.posts.findByTitleContains("%testtitle") 45 | .take(1) 46 | .as(StepVerifier::create) 47 | .consumeNextWith(p -> assertEquals("mytesttitle", p.getTitle())) 48 | .verifyComplete(); 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /crud/server/src/test/resources/junit-platform.properties: -------------------------------------------------------------------------------- 1 | junit.jupiter.testinstance.lifecycle.default = per_class 2 | -------------------------------------------------------------------------------- /docs/GUIDE.md: -------------------------------------------------------------------------------- 1 | # Using RSocket with Spring Boot 2 | 3 | [RSocket](https://rsocket.io) is a binary protocol for use on byte stream transports such as TCP, WebSockets, and Aeron. 4 | 5 | It enables the following symmetric interaction models via async message passing over a single connection: 6 | 7 | - request/response (stream of 1) 8 | - request/stream (finite stream of many) 9 | - fire-and-forget (no response) 10 | - channel (bi-directional streams) 11 | 12 | There are several implementations provided now, including Javascript, Java, Kotlin etc. In this post, we will explore the official Java implementation- [rsocket-java](https://github.com/rsocket/rsocket-java), and later we will have a look at the RSocket integration provided in the latest Spring framework (and Spring Boot). 13 | 14 | The following example is showing **request/response** usage with rsocket-java. 15 | 16 | First of all, create a RSocket server and run it on localhost:7000. 17 | 18 | ```java 19 | final AbstractRSocket responseHandler = new AbstractRSocket() { 20 | 21 | @Override 22 | public Mono requestResponse(Payload payload) { 23 | log.info("received request-response payload: {}", payload.getDataUtf8()); 24 | return Mono.just(DefaultPayload.create("received (" + payload.getDataUtf8() + ") at " + Instant.now())); 25 | } 26 | }; 27 | 28 | RSocketFactory.receive() 29 | .acceptor((setupPayload, reactiveSocket) -> Mono.just(responseHandler)) 30 | .transport(TcpServerTransport.create("localhost", PORT)) 31 | .start() 32 | .block(); 33 | ``` 34 | 35 | 36 | 37 | In the above codes: 38 | 39 | * The `receive()` means it will receive the request from client. 40 | * The `acceptor` defines how to process the request, it accept a `SocketAcceptor` class. It is the place we can embed our handler for processing the incoming request. `AbstractRSocket` is a convenient class which provides methods for all interactive models supported in RSocket. As an example, here we only need to handle the **request/response** model by overriding the `requestResponse` method. 41 | * The `transport` specifies the server information, including host, port, protocol, etc. Here we use TCP as protocol, and run it on localhost at port 7000. 42 | 43 | Next create a client to connect the existing server and send some data to it. 44 | 45 | ```java 46 | RSocketFactory.connect() 47 | .transport(TcpClientTransport.create("localhost", PORT)) 48 | .start() 49 | .flatMap(r -> r.requestResponse(DefaultPayload.create("Hello"))) 50 | .subscribe(r -> log.info("handled result:#" + r.getDataUtf8())); 51 | ``` 52 | 53 | 54 | 55 | In the above codes: 56 | 57 | * The `connect` indicates the current client will connect to server. 58 | * The `transport` provides the server info which it will connect to. 59 | * The `start` method returns a `RSocket`, it can be used to interact with server side. Here we send a `requestResponse` type request, it requires a response from server. 60 | * Finally, we can use `subcribe` to display the received response from server. 61 | 62 | Spring integrated RSocket into its messaging infrastructure, and it defines a `RSocketStrategies ` to allow you encode and decode the RSocket payload via Jackson, besides a `RSocketRequester` is used to interact with the server side. 63 | 64 | 65 | 66 | Using [Spring initializr](https://start.spring.io), you can generate a Spring Boot project skeleton in seconds. 67 | 68 | * Project type: Maven 69 | * Spring Boot:2.2.0.M5 70 | * Project Metadata: 71 | * artifact : server 72 | * Options/Java : 11 73 | * Dependencies: RSocket, Lombok 74 | 75 | The generated codes are archived into a zip file for downloading. Download and extract it into your favorite IDE. Open the *pom.xml* in your IDE editor, there are two dependencies added. 76 | 77 | ```xml 78 | 79 | org.springframework.boot 80 | spring-boot-starter-rsocket 81 | 82 | 83 | 84 | org.projectlombok 85 | lombok 86 | true 87 | 88 | ``` 89 | 90 | The `spring-boot-starter-rsocket` includes auto-configurations for RSocket integration. For the server side, it will create a Roscket server automatically from `RSocketProperties`. For example, we defines the server info in the *application.properties*. 91 | 92 | ```pro 93 | spring.rsocket.server.port=7000 94 | spring.rsocket.server.transport=tcp 95 | ``` 96 | 97 | Start the application in IDE or run `mvn spring-boot:run`, you will see the server is running at localhost:7000. 98 | 99 | ![run](./run.png) 100 | 101 | > You can also use Rsosket with Webflux , just add extra `spring-boot-starter-webflux` in the project dependencies. 102 | 103 | Create a messaging controller . 104 | 105 | ```java 106 | @Controller 107 | @Slf4j 108 | class GreetingServerController { 109 | 110 | @MessageMapping("hello") 111 | public Mono hello(Greeting p) { 112 | log.info("received: {} at {}", p, Instant.now()); 113 | return Mono.empty(); 114 | } 115 | 116 | } 117 | 118 | @Data 119 | class Greeting { 120 | String name; 121 | } 122 | ``` 123 | 124 | 125 | 126 | It accepts a `Greeting` payload, return an `Mono.empty`. Let's create a client application to shake hands with it. Similarly generate it via [Spring initializr](https://start.spring.io). 127 | 128 | * Project type: Maven 129 | * Spring Boot:2.2.0.M5 130 | * Project Metadata: 131 | * artifact : client 132 | * Options/Java : 11 133 | * Dependencies: RSocket, Reactive Web, Lombok 134 | 135 | An extra `spring-boot-starter-webflux` is added because this client is a reactive web application, and it will run at port 8080. 136 | 137 | Declare a `RSocketRequester` bean firstly. We use `RSocketRequester` to interact the RSocket at port 7000. 138 | 139 | ```java 140 | @Bean 141 | public RSocketRequester rSocketRequester(RSocketRequester.Builder b) { 142 | return b.connectTcp("localhost", 7000).block(); 143 | } 144 | ``` 145 | 146 | Create a `@RestController` to send a greeting message to the server side. 147 | 148 | ```java 149 | @RestController 150 | @RequiredArgsConstructor 151 | class GreetingController { 152 | 153 | private final RSocketRequester requester; 154 | 155 | @GetMapping 156 | Mono hello() { 157 | return this.requester.route("hello").data(new Greeting("Welcome to Rsocket")).send(); 158 | } 159 | 160 | } 161 | 162 | @Data 163 | @AllArgsConstructor 164 | class Greeting { 165 | String name; 166 | } 167 | 168 | ``` 169 | 170 | Start the client and server respectively. And try to access `http://localhost:8080` by `curl` . 171 | 172 | ```bash 173 | curl http://localhost:8080 174 | ``` 175 | 176 | In the output console of the server application, you can see the information like the following. 177 | 178 | ![msg](./msg.png) 179 | 180 | As you see, the sent message is received. 181 | 182 | Check the source codes from [Github](https://github.com/hantsy/rsocket-sample). 183 | 184 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman 2 | title: Spring RSocket by Examples 3 | description: Tips of using RSocket and Spring RSocket 4 | -------------------------------------------------------------------------------- /docs/crud.md: -------------------------------------------------------------------------------- 1 | # Building a CRUD application with RSocket and Spring 2 | 3 | In [the last post](https://medium.com/@hantsy/using-rsocket-with-spring-boot-cfc67924d06a), we explored the basic RSocket support in Spring and Spring Boot. In this post, we will create a CRUD application which is closer to the real world applications. 4 | 5 | We will create a *client* and *server* applications to demonstrate the interactions between RSocket client and server side. 6 | 7 | Firstly let's create the server application. 8 | 9 | You can simply generate a project template from [Spring initializr](https://start.spring.io), set the following properties. 10 | 11 | 12 | * Build: Maven 13 | * Java: 11 14 | * Spring Boot version: 2.3.0.M3(I preferred the new version for practicing new techniques) 15 | * Dependencies: RSocket, Spring Data R2dbc, H2 Database, Lombok 16 | 17 | > If you are new to Spring Data R2dbc, check the post [ Accessing RDBMS with Spring Data R2dbc](https://medium.com/@hantsy/reactive-accessing-rdbms-with-spring-data-r2dbc-d6e453f2837e). 18 | 19 | In the server application, we will use RSocket to serve a RSocket server via TCP protocol. 20 | 21 | Open the *src/main/resources/application.properties*, add the following properties. 22 | 23 | ```properties 24 | spring.rsocket.server.port=7000 25 | spring.rsocket.server.transport=tcp 26 | ``` 27 | 28 | Like what I have done in the former posts, firstly create a simple POJO. 29 | 30 | ```java 31 | @Data 32 | @ToString 33 | @Builder 34 | @NoArgsConstructor 35 | @AllArgsConstructor 36 | @Table("posts") 37 | class Post { 38 | 39 | @Id 40 | @Column("id") 41 | private Integer id; 42 | 43 | @Column("title") 44 | private String title; 45 | 46 | @Column("content") 47 | private String content; 48 | 49 | } 50 | ``` 51 | 52 | And create a simple Repository for `Post`. 53 | 54 | ```java 55 | 56 | interface PostRepository extends R2dbcRepository { 57 | } 58 | ``` 59 | 60 | Create a `Controller` class to handle the request messages. 61 | 62 | ```java 63 | @Controller 64 | @RequiredArgsConstructor 65 | class PostController { 66 | 67 | private final PostRepository posts; 68 | 69 | @MessageMapping("posts.findAll") 70 | public Flux all() { 71 | return this.posts.findAll(); 72 | } 73 | 74 | @MessageMapping("posts.findById.{id}") 75 | public Mono get(@DestinationVariable("id") Integer id) { 76 | return this.posts.findById(id); 77 | } 78 | 79 | @MessageMapping("posts.save") 80 | public Mono create(@Payload Post post) { 81 | return this.posts.save(post); 82 | } 83 | 84 | @MessageMapping("posts.update.{id}") 85 | public Mono update(@DestinationVariable("id") Integer id, @Payload Post post) { 86 | return this.posts.findById(id) 87 | .map(p -> { 88 | p.setTitle(post.getTitle()); 89 | p.setContent(post.getContent()); 90 | 91 | return p; 92 | }) 93 | .flatMap(p -> this.posts.save(p)); 94 | } 95 | 96 | @MessageMapping("posts.deleteById.{id}") 97 | public Mono delete(@DestinationVariable("id") Integer id) { 98 | return this.posts.deleteById(id); 99 | } 100 | 101 | } 102 | ``` 103 | 104 | Create a `schema.sql` and a `data.sql` to create tables and initialize the data. 105 | 106 | ```sql 107 | -- schema.sql 108 | CREATE TABLE posts (id SERIAL PRIMARY KEY, title VARCHAR(255), content VARCHAR(255)); 109 | ``` 110 | 111 | ```sql 112 | -- data.sql 113 | DELETE FROM posts; 114 | INSERT INTO posts (title, content) VALUES ('post one in data.sql', 'content of post one in data.sql'); 115 | ``` 116 | > Note: In the Spring 2.3.0.M3, Spring Data R2dbc is merged in the Spring Data release train. But unfortunately, the auto-configuration of `ConnectionFactoryInitializer` is NOT ported. 117 | 118 | To make sure the the `schema.sql` and `data.sql` are loaded and executed at the application startup, declare a `ConnectionFactoryInitializer` bean yourself. 119 | 120 | ```java 121 | @Bean 122 | public ConnectionFactoryInitializer initializer(ConnectionFactory connectionFactory) { 123 | 124 | ConnectionFactoryInitializer initializer = new ConnectionFactoryInitializer(); 125 | initializer.setConnectionFactory(connectionFactory); 126 | 127 | CompositeDatabasePopulator populator = new CompositeDatabasePopulator(); 128 | populator.addPopulators(new ResourceDatabasePopulator(new ClassPathResource("schema.sql"))); 129 | populator.addPopulators(new ResourceDatabasePopulator(new ClassPathResource("data.sql"))); 130 | initializer.setDatabasePopulator(populator); 131 | 132 | return initializer; 133 | } 134 | ``` 135 | 136 | Start the server application. 137 | 138 | ```bash 139 | mvn spring-boot:run 140 | ``` 141 | 142 | Now let's move to the client application. 143 | 144 | Similarly, generate a project template from [Spring Initializr](https://start.spring.io), in the *Dependencies* area, ensure you have chosen *WebFlux*, *RSocket*, *Lombok*. 145 | 146 | The client application is a generic Webflux application, but uses `RSocketRequester` to shake hands with the RSocket server. 147 | 148 | Declare a `RSocketRequester` bean to connect localhost:7000 via the TCP protocol. 149 | 150 | ```java 151 | @Bean 152 | public RSocketRequester rSocketRequester(RSocketRequester.Builder b) { 153 | return b.dataMimeType(MimeTypeUtils.APPLICATION_JSON) 154 | .connectTcp("localhost", 7000) 155 | .block(); 156 | } 157 | ``` 158 | 159 | Create a generic `RestController` and use the `RSocketRequester` bean to communicate with the RSocket server. 160 | 161 | ```java 162 | @Slf4j 163 | @RequiredArgsConstructor 164 | @RestController() 165 | @RequestMapping("/posts") 166 | class PostClientController { 167 | 168 | private final RSocketRequester requester; 169 | 170 | @GetMapping("") 171 | Flux all() { 172 | return this.requester.route("posts.findAll") 173 | .retrieveFlux(Post.class); 174 | } 175 | 176 | @GetMapping("{id}") 177 | Mono findById(@PathVariable Integer id) { 178 | return this.requester.route("posts.findById." + id) 179 | .retrieveMono(Post.class); 180 | } 181 | 182 | @PostMapping("") 183 | Mono save(@RequestBody Post post) { 184 | return this.requester.route("posts.save") 185 | .data(post) 186 | .retrieveMono(Post.class); 187 | } 188 | 189 | @PutMapping("{id}") 190 | Mono update(@PathVariable Integer id, @RequestBody Post post) { 191 | return this.requester.route("posts.update."+ id) 192 | .data(post) 193 | .retrieveMono(Post.class); 194 | } 195 | 196 | @DeleteMapping("{id}") 197 | Mono delete(@PathVariable Integer id) { 198 | return this.requester.route("posts.deleteById."+ id).send(); 199 | } 200 | 201 | } 202 | ``` 203 | 204 | Create a POJO `Post` to present the RSocket message payload that transferred between the client and server side. 205 | 206 | ```java 207 | @Data 208 | @ToString 209 | @Builder 210 | @NoArgsConstructor 211 | @AllArgsConstructor 212 | class Post { 213 | private Integer id; 214 | private String title; 215 | private String content; 216 | } 217 | ``` 218 | Start up the client application. 219 | 220 | Try to test the CRUD operations by curl. 221 | 222 | 223 | ```bash 224 | # curl http://localhost:8080/posts 225 | [{"id":1,"title":"post one in data.sql","content":"content of post one in data.sql"},{"id":2,"title":"Post one","content":"The content of post one"},{"id":3,"title":"Post tow","content":"The content of post tow"}] 226 | 227 | # curl http://localhost:8080/posts/1 228 | {"id":1,"title":"post one in data.sql","content":"content of post one in data.sql"} 229 | 230 | # curl http://localhost:8080/posts/3 231 | {"id":3,"title":"Post tow","content":"The content of post tow"} 232 | 233 | # curl http://localhost:8080/posts/2 234 | {"id":2,"title":"Post one","content":"The content of post one"} 235 | 236 | # curl http://localhost:8080/posts -d "{\"title\":\"my save title\", \"content\":\"my content of my post\"}" -H "Content-Type:application/json" -X POST 237 | {"id":4,"title":"my save title","content":"my content of my post"} 238 | 239 | # curl http://localhost:8080/posts 240 | [{"id":1,"title":"post one in data.sql","content":"content of post one in data.sql"},{"id":2,"title":"Post one","content":"The content of post one"},{"id":3,"title":"Post tow","content":"The content of post tow"},{"id":4,"title":"my save title","content":"update my content of my post"}] 241 | 242 | # curl http://localhost:8080/posts/4 -X DELETE 243 | 244 | # curl http://localhost:8080/posts 245 | [{"id":1,"title":"post one in data.sql","content":"content of post one in data.sql"},{"id":2,"title":"Post one","content":"The content of post one"},{"id":3,"title":"Post tow","content":"The content of post tow"}] 246 | ``` 247 | 248 | As a bonus, try to add a filter to find the posts by keyword. 249 | 250 | In the server application, create a new method in the `PostRepository`. 251 | 252 | ```java 253 | @Query("SELECT * FROM posts WHERE title like $1") 254 | Flux findByTitleContains(String name); 255 | ``` 256 | 257 | And in the `PostController` , create a new route to handle this request from client. 258 | 259 | ```java 260 | class PostController { 261 | //... 262 | @MessageMapping("posts.titleContains") 263 | public Flux titleContains(@Payload String title) { 264 | return this.posts.findByTitleContains(title); 265 | } 266 | //... 267 | } 268 | ``` 269 | 270 | In the client side, change the `PostClientController` 's `all` method to the following: 271 | 272 | ```java 273 | class PostClientController { 274 | //... 275 | Flux all(@RequestParam(name = "title", required = false) String title) { 276 | if (StringUtils.hasText(title)) { 277 | return this.requester.route("posts.titleContains") 278 | .data(title).retrieveFlux(Post.class); 279 | } else { 280 | return this.requester.route("posts.findAll") 281 | .retrieveFlux(Post.class); 282 | } 283 | } 284 | //... 285 | } 286 | ``` 287 | 288 | Now, try to add an extra `title` request parameter to access http://localhost:8080/posts. 289 | 290 | Get the [source codes](https://github.com/hantsy/rsocket-sample/tree/master/crud) from my Github. 291 | 292 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | * [Using Rsocket with Spring Boot](./GUIDE.md)([medium's link](https://medium.com/@hantsy/using-rsocket-with-spring-boot-cfc67924d06a)) 2 | * [Building a CRUD application with RSocket and Spring](./crud.md) -------------------------------------------------------------------------------- /docs/msg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantsy/rsocket-sample/7349fd955764b163ac061b00d30d8a8646a0fcdd/docs/msg.png -------------------------------------------------------------------------------- /docs/rsocket.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantsy/rsocket-sample/7349fd955764b163ac061b00d30d8a8646a0fcdd/docs/run.png -------------------------------------------------------------------------------- /docs/spring.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantsy/rsocket-sample/7349fd955764b163ac061b00d30d8a8646a0fcdd/docs/spring.jpg -------------------------------------------------------------------------------- /docs/springboot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantsy/rsocket-sample/7349fd955764b163ac061b00d30d8a8646a0fcdd/docs/springboot.png -------------------------------------------------------------------------------- /integration/client-regular/.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 | -------------------------------------------------------------------------------- /integration/client-regular/nbactions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | run 5 | 6 | jar 7 | 8 | 9 | spring-boot:run 10 | 11 | 12 | -noverify -XX:TieredStopAtLevel=1 13 | com.example.demo.ProducerApplication 14 | always 15 | 16 | 17 | 18 | debug 19 | 20 | jar 21 | 22 | 23 | spring-boot:run 24 | 25 | 26 | -Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address} -noverify -XX:TieredStopAtLevel=1 27 | com.example.demo.ProducerApplication 28 | always 29 | true 30 | 31 | 32 | 33 | profile 34 | 35 | jar 36 | 37 | 38 | process-classes 39 | org.codehaus.mojo:exec-maven-plugin:1.2.1:exec 40 | 41 | 42 | -classpath %classpath com.example.demo.ProducerApplication 43 | java 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /integration/client-regular/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.3.0.RELEASE 9 | 10 | 11 | com.example 12 | rsocket-sample-integration-client-regular 13 | 0.0.1-SNAPSHOT 14 | rsocket-sample-integration-client-regular 15 | Demo project for Spring Boot 16 | 17 | 18 | 11 19 | 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-webflux 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-rsocket 31 | 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-test 36 | test 37 | 38 | 39 | org.junit.vintage 40 | junit-vintage-engine 41 | 42 | 43 | 44 | 45 | org.springframework.integration 46 | spring-integration-test 47 | test 48 | 49 | 50 | io.projectreactor 51 | reactor-test 52 | test 53 | 54 | 55 | 56 | 57 | 58 | 59 | org.springframework.boot 60 | spring-boot-maven-plugin 61 | 62 | 63 | 64 | 65 | 66 | 67 | spring-milestones 68 | Spring Milestones 69 | https://repo.spring.io/milestone 70 | 71 | 72 | 73 | 74 | spring-milestones 75 | Spring Milestones 76 | https://repo.spring.io/milestone 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /integration/client-regular/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 | import org.springframework.http.MediaType; 6 | import org.springframework.messaging.rsocket.RSocketRequester; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | import reactor.core.publisher.Flux; 10 | import reactor.core.publisher.Mono; 11 | 12 | @SpringBootApplication 13 | public class DemoApplication { 14 | 15 | public static void main(String[] args) { 16 | SpringApplication.run(DemoApplication.class, args); 17 | } 18 | 19 | } 20 | 21 | @RestController 22 | class HelloController { 23 | Mono requesterMono; 24 | 25 | public HelloController(RSocketRequester.Builder builder) { 26 | this.requesterMono = builder.connectTcp("localhost", 7000); 27 | } 28 | 29 | @GetMapping(value = "hello", produces = MediaType.TEXT_EVENT_STREAM_VALUE) 30 | public Flux uppercase() { 31 | return requesterMono.flatMapMany( 32 | rSocketRequester -> rSocketRequester.route("/uppercase") 33 | .data(Flux.just("a", "b", "c", "d")) 34 | .retrieveFlux(String.class) 35 | ); 36 | } 37 | } -------------------------------------------------------------------------------- /integration/client-regular/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | logging.level.org.springframework.integration=DEBUG 2 | 3 | 4 | -------------------------------------------------------------------------------- /integration/client/.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 | -------------------------------------------------------------------------------- /integration/client/nbactions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | run 5 | 6 | jar 7 | 8 | 9 | spring-boot:run 10 | 11 | 12 | -noverify -XX:TieredStopAtLevel=1 13 | com.example.demo.ProducerApplication 14 | always 15 | 16 | 17 | 18 | debug 19 | 20 | jar 21 | 22 | 23 | spring-boot:run 24 | 25 | 26 | -Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address} -noverify -XX:TieredStopAtLevel=1 27 | com.example.demo.ProducerApplication 28 | always 29 | true 30 | 31 | 32 | 33 | profile 34 | 35 | jar 36 | 37 | 38 | process-classes 39 | org.codehaus.mojo:exec-maven-plugin:1.2.1:exec 40 | 41 | 42 | -classpath %classpath com.example.demo.ProducerApplication 43 | java 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /integration/client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.3.0.RELEASE 9 | 10 | 11 | com.example 12 | rsocket-sample-integration-client 13 | 0.0.1-SNAPSHOT 14 | rsocket-sample-integration-client 15 | Demo project for Spring Boot 16 | 17 | 18 | 11 19 | 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-webflux 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-integration 31 | 32 | 33 | 34 | org.springframework.integration 35 | spring-integration-rsocket 36 | 37 | 38 | 39 | org.projectlombok 40 | lombok 41 | true 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-starter-test 46 | test 47 | 48 | 49 | org.junit.vintage 50 | junit-vintage-engine 51 | 52 | 53 | 54 | 55 | org.springframework.integration 56 | spring-integration-test 57 | test 58 | 59 | 60 | io.projectreactor 61 | reactor-test 62 | test 63 | 64 | 65 | 66 | 67 | 68 | 69 | org.springframework.boot 70 | spring-boot-maven-plugin 71 | 72 | 73 | 74 | 75 | 76 | 77 | spring-milestones 78 | Spring Milestones 79 | https://repo.spring.io/milestone 80 | 81 | 82 | 83 | 84 | spring-milestones 85 | Spring Milestones 86 | https://repo.spring.io/milestone 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /integration/client/src/main/java/com/example/demo/DemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.beans.factory.annotation.Qualifier; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Lazy; 9 | import org.springframework.http.MediaType; 10 | import org.springframework.integration.config.EnableIntegration; 11 | import org.springframework.integration.dsl.IntegrationFlow; 12 | import org.springframework.integration.dsl.IntegrationFlows; 13 | import org.springframework.integration.rsocket.ClientRSocketConnector; 14 | import org.springframework.integration.rsocket.RSocketInteractionModel; 15 | import org.springframework.integration.rsocket.dsl.RSockets; 16 | import org.springframework.web.bind.annotation.GetMapping; 17 | import org.springframework.web.bind.annotation.RestController; 18 | import reactor.core.publisher.Flux; 19 | 20 | import java.util.function.Function; 21 | 22 | @SpringBootApplication 23 | @EnableIntegration 24 | public class DemoApplication { 25 | 26 | public static void main(String[] args) { 27 | SpringApplication.run(DemoApplication.class, args); 28 | } 29 | 30 | // see PR: https://github.com/spring-projects/spring-boot/pull/18834 31 | @Bean 32 | public ClientRSocketConnector clientRSocketConnector() { 33 | ClientRSocketConnector clientRSocketConnector = new ClientRSocketConnector("localhost", 7000); 34 | clientRSocketConnector.setAutoStartup(false); 35 | return clientRSocketConnector; 36 | } 37 | 38 | @Bean 39 | public IntegrationFlow rsocketUpperCaseRequestFlow(ClientRSocketConnector clientRSocketConnector) { 40 | return IntegrationFlows 41 | .from(Function.class) 42 | .handle(RSockets.outboundGateway("/uppercase") 43 | .interactionModel((message) -> RSocketInteractionModel.requestChannel) 44 | .expectedResponseType("T(java.lang.String)") 45 | .clientRSocketConnector(clientRSocketConnector)) 46 | .get(); 47 | } 48 | } 49 | 50 | @RestController 51 | class HelloController { 52 | 53 | @Autowired() 54 | @Lazy 55 | @Qualifier("rsocketUpperCaseRequestFlow.gateway") 56 | private Function, Flux> rsocketUpperCaseFlowFunction; 57 | 58 | @GetMapping(value = "hello", produces = MediaType.TEXT_EVENT_STREAM_VALUE) 59 | public Flux uppercase() { 60 | return rsocketUpperCaseFlowFunction.apply(Flux.just("a", "b", "c", "d")); 61 | } 62 | } -------------------------------------------------------------------------------- /integration/client/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | logging.level.org.springframework.integration=DEBUG 2 | 3 | # auto configure ClientRSocketConnector via tcp 4 | #spring.integration.rsocket.client.port=7000 5 | #spring.integration.rsocket.client.host=localhost 6 | 7 | # auto configure ClientRSocketConnector via websocket 8 | #spring.integration.rsocket.client.uri=ws://localhost:7000/rsocket 9 | -------------------------------------------------------------------------------- /integration/server-regular/.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 | -------------------------------------------------------------------------------- /integration/server-regular/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.3.0.RELEASE 9 | 10 | 11 | com.example 12 | rsocket-sample-integration-server-regular 13 | 0.0.1-SNAPSHOT 14 | rsocket-sample-integration-boot-server-regular 15 | Demo project for Spring Boot 16 | 17 | 18 | 11 19 | 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-rsocket 26 | 27 | 28 | 29 | org.projectlombok 30 | lombok 31 | true 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-test 36 | test 37 | 38 | 39 | org.junit.vintage 40 | junit-vintage-engine 41 | 42 | 43 | 44 | 45 | io.projectreactor 46 | reactor-test 47 | test 48 | 49 | 50 | 51 | 52 | 53 | 54 | org.springframework.boot 55 | spring-boot-maven-plugin 56 | 57 | 58 | 59 | 60 | 61 | 62 | spring-milestones 63 | Spring Milestones 64 | https://repo.spring.io/milestone 65 | 66 | 67 | 68 | 69 | spring-milestones 70 | Spring Milestones 71 | https://repo.spring.io/milestone 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /integration/server-regular/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 | import org.springframework.messaging.handler.annotation.MessageMapping; 6 | import org.springframework.stereotype.Controller; 7 | import reactor.core.publisher.Flux; 8 | 9 | @SpringBootApplication 10 | public class DemoApplication { 11 | 12 | public static void main(String[] args) { 13 | SpringApplication.run(DemoApplication.class, args); 14 | } 15 | 16 | } 17 | 18 | @Controller 19 | class UpperCaseHandler { 20 | 21 | @MessageMapping("/uppercase") 22 | public Flux uppercase(Flux input) { 23 | return input.map(String::toUpperCase); 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /integration/server-regular/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.rsocket.server.transport=tcp 2 | spring.rsocket.server.port=7000 3 | logging.level.org.springframework.messaging.rsocket=DEBUG 4 | 5 | -------------------------------------------------------------------------------- /integration/server-vanilla/.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 | -------------------------------------------------------------------------------- /integration/server-vanilla/nbactions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | run 5 | 6 | jar 7 | 8 | 9 | spring-boot:run 10 | 11 | 12 | -noverify -XX:TieredStopAtLevel=1 13 | com.example.demo.ProducerApplication 14 | always 15 | 16 | 17 | 18 | debug 19 | 20 | jar 21 | 22 | 23 | spring-boot:run 24 | 25 | 26 | -Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address} -noverify -XX:TieredStopAtLevel=1 27 | com.example.demo.ProducerApplication 28 | always 29 | true 30 | 31 | 32 | 33 | profile 34 | 35 | jar 36 | 37 | 38 | process-classes 39 | org.codehaus.mojo:exec-maven-plugin:1.2.1:exec 40 | 41 | 42 | -classpath %classpath com.example.demo.ProducerApplication 43 | java 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /integration/server-vanilla/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.3.0.RELEASE 9 | 10 | 11 | com.example 12 | rsocket-sample-integration-server-vanilla 13 | 0.0.1-SNAPSHOT 14 | rsocket-sample-integration-server-vanilla 15 | Demo project for Spring Boot 16 | 17 | 18 | 11 19 | 20 | 21 | 22 | 23 | 24 | org.springframework.integration 25 | spring-integration-rsocket 26 | 27 | 28 | 29 | org.junit.jupiter 30 | junit-jupiter-engine 31 | test 32 | 33 | 34 | org.springframework.integration 35 | spring-integration-test 36 | test 37 | 38 | 39 | io.projectreactor 40 | reactor-test 41 | test 42 | 43 | 44 | 45 | 46 | 47 | 48 | org.springframework.boot 49 | spring-boot-maven-plugin 50 | 51 | 52 | 53 | 54 | 55 | 56 | spring-milestones 57 | Spring Milestones 58 | https://repo.spring.io/milestone 59 | 60 | 61 | 62 | 63 | spring-milestones 64 | Spring Milestones 65 | https://repo.spring.io/milestone 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /integration/server-vanilla/src/main/java/com/example/demo/DemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import org.springframework.context.ConfigurableApplicationContext; 4 | import org.springframework.context.annotation.AnnotationConfigApplicationContext; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.core.ResolvableType; 8 | import org.springframework.integration.config.EnableIntegration; 9 | import org.springframework.integration.dsl.IntegrationFlow; 10 | import org.springframework.integration.dsl.IntegrationFlows; 11 | import org.springframework.integration.rsocket.RSocketInteractionModel; 12 | import org.springframework.integration.rsocket.ServerRSocketConnector; 13 | import org.springframework.integration.rsocket.dsl.RSockets; 14 | import reactor.core.publisher.Flux; 15 | 16 | import java.io.IOException; 17 | 18 | @Configuration 19 | @EnableIntegration 20 | public class DemoApplication { 21 | 22 | public static void main(String[] args) throws IOException { 23 | try (ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(DemoApplication.class)) { 24 | System.out.println("Press any key to exit."); 25 | System.in.read(); 26 | } finally { 27 | System.out.println("Exited."); 28 | } 29 | 30 | } 31 | 32 | @Bean 33 | public ServerRSocketConnector serverRSocketConnector() { 34 | return new ServerRSocketConnector("localhost", 7000); 35 | } 36 | 37 | @Bean 38 | public IntegrationFlow rsocketUpperCaseFlow(ServerRSocketConnector serverRSocketConnector) { 39 | return IntegrationFlows 40 | .from(RSockets.inboundGateway("/uppercase") 41 | .requestElementType(ResolvableType.forClass(String.class)) 42 | .interactionModels(RSocketInteractionModel.requestChannel) 43 | .rsocketConnector(serverRSocketConnector) 44 | ) 45 | ., Flux>transform((flux) -> flux.map(String::toUpperCase)) 46 | .get(); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /integration/server-vanilla/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | logging.level.org.springframework.integration=DEBUG 2 | 3 | -------------------------------------------------------------------------------- /integration/server-vanilla/src/test/java/com/example/demo/DemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | package com.example.demo; 5 | 6 | import org.junit.jupiter.api.AfterEach; 7 | import org.junit.jupiter.api.BeforeEach; 8 | import org.junit.jupiter.api.Test; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.beans.factory.annotation.Qualifier; 11 | import org.springframework.context.annotation.AnnotationConfigApplicationContext; 12 | import org.springframework.context.annotation.Bean; 13 | import org.springframework.context.annotation.Configuration; 14 | import org.springframework.integration.dsl.IntegrationFlow; 15 | import org.springframework.integration.dsl.IntegrationFlows; 16 | import org.springframework.integration.rsocket.ClientRSocketConnector; 17 | import org.springframework.integration.rsocket.RSocketInteractionModel; 18 | import org.springframework.integration.rsocket.ServerRSocketConnector; 19 | import org.springframework.integration.rsocket.dsl.RSockets; 20 | import org.springframework.test.annotation.DirtiesContext; 21 | import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; 22 | import reactor.core.publisher.Flux; 23 | import reactor.test.StepVerifier; 24 | 25 | import java.util.function.Function; 26 | 27 | @SpringJUnitConfig(classes = {DemoApplication.class, DemoApplicationTests.TestConfig.class}) 28 | @DirtiesContext 29 | public class DemoApplicationTests { 30 | 31 | @Autowired 32 | @Qualifier("rsocketUpperCaseRequestFlow.gateway") 33 | private Function, Flux> rsocketUpperCaseFlowFunction; 34 | 35 | @Test 36 | void testRsocketUpperCaseFlows() { 37 | Flux result = this.rsocketUpperCaseFlowFunction.apply(Flux.just("a\n", "b\n", "c\n")); 38 | 39 | StepVerifier.create(result) 40 | .expectNext("A", "B", "C") 41 | .verifyComplete(); 42 | } 43 | 44 | @Configuration 45 | public static class TestConfig { 46 | 47 | @Bean 48 | public ClientRSocketConnector clientRSocketConnector(ServerRSocketConnector serverRSocketConnector) { 49 | int port = serverRSocketConnector.getBoundPort().block(); 50 | ClientRSocketConnector clientRSocketConnector = new ClientRSocketConnector("localhost", port); 51 | clientRSocketConnector.setAutoStartup(false); 52 | return clientRSocketConnector; 53 | } 54 | 55 | @Bean 56 | public IntegrationFlow rsocketUpperCaseRequestFlow(ClientRSocketConnector clientRSocketConnector) { 57 | return IntegrationFlows 58 | .from(Function.class) 59 | .handle(RSockets.outboundGateway("/uppercase") 60 | .interactionModel((message) -> RSocketInteractionModel.requestChannel) 61 | .expectedResponseType("T(java.lang.String)") 62 | .clientRSocketConnector(clientRSocketConnector)) 63 | .get(); 64 | } 65 | 66 | } 67 | 68 | } -------------------------------------------------------------------------------- /integration/server/.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 | -------------------------------------------------------------------------------- /integration/server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.3.0.RELEASE 9 | 10 | 11 | com.example 12 | rsocket-sample-integration-server 13 | 0.0.1-SNAPSHOT 14 | rsocket-sample-integration-server 15 | Demo project for Spring Boot 16 | 17 | 18 | 11 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-rsocket 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-integration 30 | 31 | 32 | 33 | org.springframework.integration 34 | spring-integration-rsocket 35 | 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 | org.springframework.integration 50 | spring-integration-test 51 | test 52 | 53 | 54 | io.projectreactor 55 | reactor-test 56 | test 57 | 58 | 59 | 60 | 61 | 62 | 63 | org.springframework.boot 64 | spring-boot-maven-plugin 65 | 66 | 67 | 68 | 69 | 70 | 71 | spring-milestones 72 | Spring Milestones 73 | https://repo.spring.io/milestone 74 | 75 | 76 | 77 | 78 | spring-milestones 79 | Spring Milestones 80 | https://repo.spring.io/milestone 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /integration/server/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 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.core.ResolvableType; 7 | import org.springframework.integration.config.EnableIntegration; 8 | import org.springframework.integration.dsl.IntegrationFlow; 9 | import org.springframework.integration.dsl.IntegrationFlows; 10 | import org.springframework.integration.rsocket.RSocketInteractionModel; 11 | import org.springframework.integration.rsocket.ServerRSocketConnector; 12 | import org.springframework.integration.rsocket.ServerRSocketMessageHandler; 13 | import org.springframework.integration.rsocket.dsl.RSockets; 14 | import org.springframework.messaging.rsocket.RSocketStrategies; 15 | import reactor.core.publisher.Flux; 16 | 17 | import java.io.IOException; 18 | 19 | @SpringBootApplication 20 | @EnableIntegration 21 | public class DemoApplication { 22 | 23 | public static void main(String[] args) throws IOException { 24 | SpringApplication.run(DemoApplication.class, args); 25 | } 26 | 27 | // see PR: https://github.com/spring-projects/spring-boot/pull/18834 28 | @Bean 29 | ServerRSocketMessageHandler serverRSocketMessageHandler(RSocketStrategies rSocketStrategies) { 30 | var handler = new ServerRSocketMessageHandler(true); 31 | handler.setRSocketStrategies(rSocketStrategies); 32 | return handler; 33 | } 34 | 35 | @Bean 36 | public ServerRSocketConnector serverRSocketConnector(ServerRSocketMessageHandler serverRSocketMessageHandler) { 37 | return new ServerRSocketConnector(serverRSocketMessageHandler); 38 | } 39 | 40 | @Bean 41 | public IntegrationFlow rsocketUpperCaseFlow(ServerRSocketConnector serverRSocketConnector) { 42 | return IntegrationFlows 43 | .from(RSockets.inboundGateway("/uppercase") 44 | .requestElementType(ResolvableType.forClass(String.class)) 45 | .interactionModels(RSocketInteractionModel.requestChannel) 46 | .rsocketConnector(serverRSocketConnector) 47 | ) 48 | ., Flux>transform((flux) -> flux.map(String::toUpperCase)) 49 | .get(); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /integration/server/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.rsocket.server.port=7000 2 | spring.rsocket.server.transport=tcp 3 | 4 | logging.level.org.springframework.integration=DEBUG 5 | 6 | # auto configure spring integration rsocket server. 7 | spring.integration.rsocket.server.messageMappingEnabled=true 8 | -------------------------------------------------------------------------------- /security/.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 | -------------------------------------------------------------------------------- /security/.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | https://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | import java.io.File; 21 | import java.io.FileInputStream; 22 | import java.io.FileOutputStream; 23 | import java.io.IOException; 24 | import java.net.URL; 25 | import java.nio.channels.Channels; 26 | import java.nio.channels.ReadableByteChannel; 27 | import java.util.Properties; 28 | 29 | public class MavenWrapperDownloader { 30 | 31 | /** 32 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 33 | */ 34 | private static final String DEFAULT_DOWNLOAD_URL = 35 | "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; 36 | 37 | /** 38 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 39 | * use instead of the default one. 40 | */ 41 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 42 | ".mvn/wrapper/maven-wrapper.properties"; 43 | 44 | /** 45 | * Path where the maven-wrapper.jar will be saved to. 46 | */ 47 | private static final String MAVEN_WRAPPER_JAR_PATH = 48 | ".mvn/wrapper/maven-wrapper.jar"; 49 | 50 | /** 51 | * Name of the property which should be used to override the default download url for the wrapper. 52 | */ 53 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 54 | 55 | public static void main(String args[]) { 56 | System.out.println("- Downloader started"); 57 | File baseDirectory = new File(args[0]); 58 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 59 | 60 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 61 | // wrapperUrl parameter. 62 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 63 | String url = DEFAULT_DOWNLOAD_URL; 64 | if(mavenWrapperPropertyFile.exists()) { 65 | FileInputStream mavenWrapperPropertyFileInputStream = null; 66 | try { 67 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 68 | Properties mavenWrapperProperties = new Properties(); 69 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 70 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 71 | } catch (IOException e) { 72 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 73 | } finally { 74 | try { 75 | if(mavenWrapperPropertyFileInputStream != null) { 76 | mavenWrapperPropertyFileInputStream.close(); 77 | } 78 | } catch (IOException e) { 79 | // Ignore ... 80 | } 81 | } 82 | } 83 | System.out.println("- Downloading from: : " + url); 84 | 85 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 86 | if(!outputFile.getParentFile().exists()) { 87 | if(!outputFile.getParentFile().mkdirs()) { 88 | System.out.println( 89 | "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 90 | } 91 | } 92 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 93 | try { 94 | downloadFileFromURL(url, outputFile); 95 | System.out.println("Done"); 96 | System.exit(0); 97 | } catch (Throwable e) { 98 | System.out.println("- Error downloading"); 99 | e.printStackTrace(); 100 | System.exit(1); 101 | } 102 | } 103 | 104 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 105 | URL website = new URL(urlString); 106 | ReadableByteChannel rbc; 107 | rbc = Channels.newChannel(website.openStream()); 108 | FileOutputStream fos = new FileOutputStream(destination); 109 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 110 | fos.close(); 111 | rbc.close(); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /security/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantsy/rsocket-sample/7349fd955764b163ac061b00d30d8a8646a0fcdd/security/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /security/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /security/lombok.config: -------------------------------------------------------------------------------- 1 | lombok.noArgsConstructor.extraPrivate=true 2 | -------------------------------------------------------------------------------- /security/mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # https://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Mingw, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | # TODO classpath? 118 | fi 119 | 120 | if [ -z "$JAVA_HOME" ]; then 121 | javaExecutable="`which javac`" 122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 123 | # readlink(1) is not available as standard on Solaris 10. 124 | readLink=`which readlink` 125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 126 | if $darwin ; then 127 | javaHome="`dirname \"$javaExecutable\"`" 128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 129 | else 130 | javaExecutable="`readlink -f \"$javaExecutable\"`" 131 | fi 132 | javaHome="`dirname \"$javaExecutable\"`" 133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 134 | JAVA_HOME="$javaHome" 135 | export JAVA_HOME 136 | fi 137 | fi 138 | fi 139 | 140 | if [ -z "$JAVACMD" ] ; then 141 | if [ -n "$JAVA_HOME" ] ; then 142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 143 | # IBM's JDK on AIX uses strange locations for the executables 144 | JAVACMD="$JAVA_HOME/jre/sh/java" 145 | else 146 | JAVACMD="$JAVA_HOME/bin/java" 147 | fi 148 | else 149 | JAVACMD="`which java`" 150 | fi 151 | fi 152 | 153 | if [ ! -x "$JAVACMD" ] ; then 154 | echo "Error: JAVA_HOME is not defined correctly." >&2 155 | echo " We cannot execute $JAVACMD" >&2 156 | exit 1 157 | fi 158 | 159 | if [ -z "$JAVA_HOME" ] ; then 160 | echo "Warning: JAVA_HOME environment variable is not set." 161 | fi 162 | 163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 164 | 165 | # traverses directory structure from process work directory to filesystem root 166 | # first directory with .mvn subdirectory is considered project base directory 167 | find_maven_basedir() { 168 | 169 | if [ -z "$1" ] 170 | then 171 | echo "Path not specified to find_maven_basedir" 172 | return 1 173 | fi 174 | 175 | basedir="$1" 176 | wdir="$1" 177 | while [ "$wdir" != '/' ] ; do 178 | if [ -d "$wdir"/.mvn ] ; then 179 | basedir=$wdir 180 | break 181 | fi 182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 183 | if [ -d "${wdir}" ]; then 184 | wdir=`cd "$wdir/.."; pwd` 185 | fi 186 | # end of workaround 187 | done 188 | echo "${basedir}" 189 | } 190 | 191 | # concatenates all lines of a file 192 | concat_lines() { 193 | if [ -f "$1" ]; then 194 | echo "$(tr -s '\n' ' ' < "$1")" 195 | fi 196 | } 197 | 198 | BASE_DIR=`find_maven_basedir "$(pwd)"` 199 | if [ -z "$BASE_DIR" ]; then 200 | exit 1; 201 | fi 202 | 203 | ########################################################################################## 204 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 205 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 206 | ########################################################################################## 207 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 208 | if [ "$MVNW_VERBOSE" = true ]; then 209 | echo "Found .mvn/wrapper/maven-wrapper.jar" 210 | fi 211 | else 212 | if [ "$MVNW_VERBOSE" = true ]; then 213 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 214 | fi 215 | jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" 216 | while IFS="=" read key value; do 217 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 218 | esac 219 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 220 | if [ "$MVNW_VERBOSE" = true ]; then 221 | echo "Downloading from: $jarUrl" 222 | fi 223 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 224 | 225 | if command -v wget > /dev/null; then 226 | if [ "$MVNW_VERBOSE" = true ]; then 227 | echo "Found wget ... using wget" 228 | fi 229 | wget "$jarUrl" -O "$wrapperJarPath" 230 | elif command -v curl > /dev/null; then 231 | if [ "$MVNW_VERBOSE" = true ]; then 232 | echo "Found curl ... using curl" 233 | fi 234 | curl -o "$wrapperJarPath" "$jarUrl" 235 | else 236 | if [ "$MVNW_VERBOSE" = true ]; then 237 | echo "Falling back to using Java to download" 238 | fi 239 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 240 | if [ -e "$javaClass" ]; then 241 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 242 | if [ "$MVNW_VERBOSE" = true ]; then 243 | echo " - Compiling MavenWrapperDownloader.java ..." 244 | fi 245 | # Compiling the Java class 246 | ("$JAVA_HOME/bin/javac" "$javaClass") 247 | fi 248 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 249 | # Running the downloader 250 | if [ "$MVNW_VERBOSE" = true ]; then 251 | echo " - Running MavenWrapperDownloader.java ..." 252 | fi 253 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 254 | fi 255 | fi 256 | fi 257 | fi 258 | ########################################################################################## 259 | # End of extension 260 | ########################################################################################## 261 | 262 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 263 | if [ "$MVNW_VERBOSE" = true ]; then 264 | echo $MAVEN_PROJECTBASEDIR 265 | fi 266 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 267 | 268 | # For Cygwin, switch paths to Windows format before running java 269 | if $cygwin; then 270 | [ -n "$M2_HOME" ] && 271 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 272 | [ -n "$JAVA_HOME" ] && 273 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 274 | [ -n "$CLASSPATH" ] && 275 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 276 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 277 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 278 | fi 279 | 280 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 281 | 282 | exec "$JAVACMD" \ 283 | $MAVEN_OPTS \ 284 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 285 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 286 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 287 | -------------------------------------------------------------------------------- /security/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" 124 | FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( 125 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 126 | ) 127 | 128 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 129 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 130 | if exist %WRAPPER_JAR% ( 131 | echo Found %WRAPPER_JAR% 132 | ) else ( 133 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 134 | echo Downloading from: %DOWNLOAD_URL% 135 | powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" 136 | echo Finished downloading %WRAPPER_JAR% 137 | ) 138 | @REM End of extension 139 | 140 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 141 | if ERRORLEVEL 1 goto error 142 | goto end 143 | 144 | :error 145 | set ERROR_CODE=1 146 | 147 | :end 148 | @endlocal & set ERROR_CODE=%ERROR_CODE% 149 | 150 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 151 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 152 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 153 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 154 | :skipRcPost 155 | 156 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 157 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 158 | 159 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 160 | 161 | exit /B %ERROR_CODE% 162 | -------------------------------------------------------------------------------- /security/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.5.RELEASE 9 | 10 | 11 | com.example 12 | rsocket-sample-boot-security 13 | 0.0.1-SNAPSHOT 14 | rsocket-sample-boot-security 15 | Demo project for Spring Boot 16 | 17 | 18 | 11 19 | 20 | 21 | 22 | 23 | org.projectlombok 24 | lombok 25 | true 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-rsocket 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-security 34 | 35 | 36 | org.springframework.security 37 | spring-security-rsocket 38 | 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-starter-test 43 | test 44 | 45 | 46 | org.junit.vintage 47 | junit-vintage-engine 48 | 49 | 50 | 51 | 52 | org.springframework.security 53 | spring-security-test 54 | test 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 | -------------------------------------------------------------------------------- /security/src/main/java/com/example/demo/DemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 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.boot.rsocket.messaging.RSocketStrategiesCustomizer; 9 | import org.springframework.boot.rsocket.server.ServerRSocketFactoryProcessor; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.context.annotation.Configuration; 12 | import org.springframework.http.codec.json.Jackson2JsonDecoder; 13 | import org.springframework.http.codec.json.Jackson2JsonEncoder; 14 | import org.springframework.messaging.handler.annotation.MessageMapping; 15 | import org.springframework.security.config.Customizer; 16 | import org.springframework.security.config.annotation.rsocket.EnableRSocketSecurity; 17 | import org.springframework.security.config.annotation.rsocket.RSocketSecurity; 18 | import org.springframework.security.core.userdetails.MapReactiveUserDetailsService; 19 | import org.springframework.security.core.userdetails.User; 20 | import org.springframework.security.core.userdetails.UserDetails; 21 | import org.springframework.security.crypto.factory.PasswordEncoderFactories; 22 | import org.springframework.security.crypto.password.PasswordEncoder; 23 | import org.springframework.security.rsocket.core.PayloadSocketAcceptorInterceptor; 24 | import org.springframework.security.rsocket.core.SecuritySocketAcceptorInterceptor; 25 | import org.springframework.security.rsocket.metadata.BasicAuthenticationDecoder; 26 | import org.springframework.security.rsocket.metadata.BasicAuthenticationEncoder; 27 | import org.springframework.stereotype.Controller; 28 | import reactor.core.publisher.Mono; 29 | 30 | import java.time.Instant; 31 | 32 | @SpringBootApplication 33 | public class DemoApplication { 34 | 35 | public static void main(String[] args) { 36 | SpringApplication.run(DemoApplication.class, args); 37 | } 38 | 39 | } 40 | 41 | @Configuration 42 | @EnableRSocketSecurity 43 | class SecurityConfig { 44 | // @Bean 45 | // RSocketStrategiesCustomizer rSocketStrategiesCustomizer() { 46 | // return (b) -> b.decoder(new BasicAuthenticationDecoder(), new Jackson2JsonDecoder()) 47 | // .encoder(new BasicAuthenticationEncoder(), new Jackson2JsonEncoder()) 48 | // .build(); 49 | // } 50 | 51 | @Bean 52 | public PayloadSocketAcceptorInterceptor rsocketInterceptor(RSocketSecurity rsocket) { 53 | return rsocket 54 | .authorizePayload( 55 | authorize -> { 56 | authorize 57 | // must have ROLE_SETUP to make connection 58 | .setup().hasRole("SETUP") 59 | // must have ROLE_ADMIN for routes starting with "greet." 60 | .route("greet*").hasRole("ADMIN") 61 | // any other request must be authenticated for 62 | .anyRequest().authenticated(); 63 | } 64 | ) 65 | .basicAuthentication(Customizer.withDefaults()) 66 | .build(); 67 | } 68 | 69 | @Bean 70 | public MapReactiveUserDetailsService userDetailsService(PasswordEncoder passwordEncoder) { 71 | UserDetails adminUser = User.withUsername("admin") 72 | .passwordEncoder(passwordEncoder::encode) 73 | .password("password") 74 | .roles("ADMIN") 75 | .build(); 76 | UserDetails setupUser = User.withUsername("setup") 77 | .passwordEncoder(passwordEncoder::encode) 78 | .password("password") 79 | .roles("SETUP") 80 | .build(); 81 | 82 | return new MapReactiveUserDetailsService(adminUser, setupUser); 83 | } 84 | 85 | 86 | @Bean 87 | PasswordEncoder passwordEncoder() { 88 | return PasswordEncoderFactories.createDelegatingPasswordEncoder(); 89 | } 90 | 91 | // see: https://github.com/spring-projects/spring-security/issues/7497 92 | // and https://github.com/spring-projects/spring-security/blob/5.2.0.RELEASE/samples/boot/hellorsocket/src/main/java/sample/HelloRSocketSecurityConfig.java 93 | // @Bean 94 | // ServerRSocketFactoryProcessor springSecurityServerRSocketFactoryProcessor( 95 | // SecuritySocketAcceptorInterceptor interceptor) { 96 | // return builder -> builder.addSocketAcceptorPlugin(interceptor); 97 | // } 98 | 99 | } 100 | 101 | 102 | @Controller 103 | class GreetingController { 104 | 105 | @MessageMapping("greet") 106 | Mono greet(GreetingRequest request) { 107 | return Mono.just(new GreetingResponse("Hello " + request.getName() + " @ " + Instant.now())); 108 | } 109 | } 110 | 111 | @Data 112 | @AllArgsConstructor 113 | @NoArgsConstructor 114 | class GreetingRequest { 115 | private String name; 116 | 117 | public static GreetingRequest of(String name) { 118 | var greeting = new GreetingRequest(); 119 | greeting.setName(name); 120 | return greeting; 121 | } 122 | } 123 | 124 | @Data 125 | @NoArgsConstructor 126 | @AllArgsConstructor 127 | class GreetingResponse { 128 | private String message; 129 | } 130 | -------------------------------------------------------------------------------- /security/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.rsocket.server.port=7000 2 | spring.rsocket.server.transport=tcp 3 | -------------------------------------------------------------------------------- /security/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.beans.factory.annotation.Autowired; 5 | import org.springframework.boot.rsocket.context.LocalRSocketServerPort; 6 | import org.springframework.boot.rsocket.context.RSocketServerInitializedEvent; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | import org.springframework.boot.test.context.TestConfiguration; 9 | import org.springframework.context.ApplicationListener; 10 | import org.springframework.messaging.rsocket.RSocketRequester; 11 | import org.springframework.security.rsocket.metadata.BasicAuthenticationEncoder; 12 | import org.springframework.security.rsocket.metadata.UsernamePasswordMetadata; 13 | import org.springframework.test.context.TestPropertySource; 14 | import reactor.test.StepVerifier; 15 | 16 | import static org.assertj.core.api.Assertions.assertThat; 17 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 18 | import static org.springframework.security.rsocket.metadata.UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE; 19 | 20 | // see: https://github.com/rwinch/rsocket-security/blob/master/src/test/java/org/springframework/security/rsocket/itests/RSocketMessageHandlerITests.java 21 | // and https://github.com/spring-projects/spring-security/blob/5.2.0.RELEASE/samples/boot/hellorsocket/src/integration-test/java/sample/HelloRSocketApplicationITests.java 22 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 23 | @TestPropertySource(properties = "spring.rsocket.server.port=0") 24 | class DemoApplicationTests { 25 | 26 | 27 | @LocalRSocketServerPort 28 | int port; 29 | 30 | @Autowired 31 | RSocketRequester.Builder requester; 32 | 33 | @Test 34 | public void retrieveMonoWhenSecureThenDenied() throws Exception { 35 | RSocketRequester requester = this.requester 36 | .connectTcp("localhost", this.port) 37 | .block(); 38 | String data = "hantsy"; 39 | assertThatThrownBy( 40 | () -> requester.route("greet*") 41 | .data(GreetingRequest.of(data)) 42 | .retrieveMono(GreetingResponse.class) 43 | .block() 44 | ).isNotNull(); 45 | } 46 | 47 | 48 | @Test 49 | public void retrieveMonoWithSetupUserWithoutAdminThenDenied() throws Exception { 50 | UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("setup", "password"); 51 | 52 | RSocketRequester requester = this.requester 53 | .rsocketStrategies(builder -> builder.encoder(new BasicAuthenticationEncoder())) 54 | .setupMetadata(credentials, BASIC_AUTHENTICATION_MIME_TYPE) 55 | .connectTcp("localhost", this.port) 56 | .block(); 57 | String data = "hantsy"; 58 | assertThatThrownBy( 59 | () -> requester.route("greet") 60 | .data(GreetingRequest.of(data)) 61 | .retrieveMono(GreetingResponse.class) 62 | .block() 63 | ).isNotNull(); 64 | } 65 | 66 | 67 | @Test 68 | public void retrieveMonoWithSetupUserAndAdminUserThenOK() throws Exception { 69 | UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("setup", "password"); 70 | 71 | RSocketRequester requester = this.requester 72 | .rsocketStrategies(builder -> builder.encoder(new BasicAuthenticationEncoder())) 73 | .setupMetadata(credentials, BASIC_AUTHENTICATION_MIME_TYPE) 74 | .connectTcp("localhost", this.port) 75 | .block(); 76 | UsernamePasswordMetadata adminCredentials = new UsernamePasswordMetadata("admin", "password"); 77 | 78 | String data = "hantsy"; 79 | requester.route("greet") 80 | .metadata(adminCredentials, BASIC_AUTHENTICATION_MIME_TYPE) 81 | .data(GreetingRequest.of(data)) 82 | .retrieveMono(GreetingResponse.class) 83 | .as(StepVerifier::create) 84 | .consumeNextWith(c -> assertThat(c.getMessage()).contains("hantsy")) 85 | .verifyComplete(); 86 | } 87 | 88 | 89 | // FIXME: Waiting for @LocalRSocketServerPort 90 | // https://github.com/spring-projects/spring-boot/pull/18287 91 | // @Autowired 92 | // Config config; 93 | // 94 | // private int getPort() { 95 | // return this.config.port; 96 | // } 97 | // 98 | // @TestConfiguration 99 | // static class Config implements ApplicationListener { 100 | // private int port; 101 | // 102 | // @Override 103 | // public void onApplicationEvent(RSocketServerInitializedEvent event) { 104 | // this.port = event.getServer().address().getPort(); 105 | // } 106 | // } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /server-requester/client/.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 | -------------------------------------------------------------------------------- /server-requester/client/lombok.config: -------------------------------------------------------------------------------- 1 | lombok.noArgsConstructor.extraPrivate=true 2 | -------------------------------------------------------------------------------- /server-requester/client/nbactions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | run 5 | 6 | jar 7 | 8 | 9 | spring-boot:run 10 | 11 | 12 | -noverify -XX:TieredStopAtLevel=1 13 | com.example.consumer.ConsumerApplication 14 | always 15 | 16 | 17 | 18 | debug 19 | 20 | jar 21 | 22 | 23 | spring-boot:run 24 | 25 | 26 | -Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address} -noverify -XX:TieredStopAtLevel=1 27 | com.example.consumer.ConsumerApplication 28 | always 29 | true 30 | 31 | 32 | 33 | profile 34 | 35 | jar 36 | 37 | 38 | process-classes 39 | org.codehaus.mojo:exec-maven-plugin:1.2.1:exec 40 | 41 | 42 | -classpath %classpath com.example.consumer.ConsumerApplication 43 | java 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /server-requester/client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.5.RELEASE 9 | 10 | 11 | com.example 12 | rsocket-sample-boot-server-requeter-client 13 | 0.0.1-SNAPSHOT 14 | rsocket-sample-boot-server-requeter-client 15 | Demo project for Spring Boot 16 | 17 | 18 | 11 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-webflux 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-rsocket 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 | 49 | 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-maven-plugin 54 | 55 | 56 | 57 | 58 | 59 | 60 | spring-milestones 61 | Spring Milestones 62 | https://repo.spring.io/milestone 63 | 64 | 65 | 66 | 67 | spring-milestones 68 | Spring Milestones 69 | https://repo.spring.io/milestone 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /server-requester/client/src/main/java/com/example/client/ClientApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.client; 2 | 3 | import lombok.RequiredArgsConstructor; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.messaging.handler.annotation.MessageMapping; 9 | import org.springframework.messaging.rsocket.RSocketRequester; 10 | import org.springframework.messaging.rsocket.RSocketStrategies; 11 | import org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler; 12 | import org.springframework.util.MimeTypeUtils; 13 | import org.springframework.web.bind.annotation.GetMapping; 14 | import org.springframework.web.bind.annotation.RestController; 15 | import reactor.core.publisher.Mono; 16 | 17 | import java.time.Duration; 18 | import java.time.LocalDateTime; 19 | 20 | @SpringBootApplication 21 | public class ClientApplication { 22 | 23 | public static void main(String[] args) { 24 | SpringApplication.run(ClientApplication.class, args); 25 | } 26 | 27 | @Bean 28 | public RSocketRequester rSocketRequester(RSocketRequester.Builder b, RSocketStrategies rSocketStrategies) { 29 | return b.dataMimeType(MimeTypeUtils.APPLICATION_JSON) 30 | .rsocketFactory(RSocketMessageHandler.clientResponder(rSocketStrategies, new ClientHandler())) 31 | .setupRoute("connect") 32 | .setupData("user") 33 | .connectTcp("localhost", 7000) 34 | .block(); 35 | } 36 | 37 | } 38 | 39 | @Slf4j 40 | class ClientHandler { 41 | 42 | @MessageMapping("status") 43 | public Mono statusUpdate(String status) { 44 | log.info("Received (" + status + ") at " + LocalDateTime.now()); 45 | return Mono.just("confirmed").delayElement(Duration.ofSeconds(1)); 46 | } 47 | } 48 | 49 | @Slf4j 50 | @RestController() 51 | @RequiredArgsConstructor 52 | class GreetingController { 53 | 54 | private final RSocketRequester requester; 55 | 56 | @GetMapping("hello") 57 | Mono hello() { 58 | return this.requester.route("hello").data("Hello RSocket").retrieveMono(String.class); 59 | } 60 | 61 | } -------------------------------------------------------------------------------- /server-requester/client/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /server-requester/server/.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 | -------------------------------------------------------------------------------- /server-requester/server/lombok.config: -------------------------------------------------------------------------------- 1 | lombok.noArgsConstructor.extraPrivate=true 2 | -------------------------------------------------------------------------------- /server-requester/server/nbactions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | run 5 | 6 | jar 7 | 8 | 9 | spring-boot:run 10 | 11 | 12 | -noverify -XX:TieredStopAtLevel=1 13 | com.example.demo.ProducerApplication 14 | always 15 | 16 | 17 | 18 | debug 19 | 20 | jar 21 | 22 | 23 | spring-boot:run 24 | 25 | 26 | -Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address} -noverify -XX:TieredStopAtLevel=1 27 | com.example.demo.ProducerApplication 28 | always 29 | true 30 | 31 | 32 | 33 | profile 34 | 35 | jar 36 | 37 | 38 | process-classes 39 | org.codehaus.mojo:exec-maven-plugin:1.2.1:exec 40 | 41 | 42 | -classpath %classpath com.example.demo.ProducerApplication 43 | java 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /server-requester/server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.5.RELEASE 9 | 10 | 11 | com.example 12 | rsocket-sample-boot-server-requester-server 13 | 0.0.1-SNAPSHOT 14 | rsocket-sample-boot-server-requester-server 15 | Demo project for Spring Boot 16 | 17 | 18 | 11 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 | 61 | spring-milestones 62 | Spring Milestones 63 | https://repo.spring.io/milestone 64 | 65 | 66 | 67 | 68 | spring-milestones 69 | Spring Milestones 70 | https://repo.spring.io/milestone 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /server-requester/server/src/main/java/com/example/demo/DemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import lombok.Data; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.messaging.handler.annotation.MessageMapping; 8 | import org.springframework.messaging.handler.annotation.Payload; 9 | import org.springframework.messaging.rsocket.RSocketRequester; 10 | import org.springframework.messaging.rsocket.annotation.ConnectMapping; 11 | import org.springframework.stereotype.Controller; 12 | import reactor.core.publisher.Flux; 13 | import reactor.core.publisher.Mono; 14 | 15 | import java.time.Duration; 16 | import java.time.LocalDateTime; 17 | import java.util.HashMap; 18 | import java.util.List; 19 | import java.util.Map; 20 | import java.util.Random; 21 | 22 | @SpringBootApplication 23 | public class DemoApplication { 24 | 25 | public static void main(String[] args) { 26 | SpringApplication.run(DemoApplication.class, args); 27 | } 28 | 29 | } 30 | 31 | @Controller 32 | @Slf4j 33 | class GreetingController { 34 | private final Map REQESTER_MAP = new HashMap<>(); 35 | 36 | @ConnectMapping("connect") 37 | void setup(RSocketRequester requester, @Payload String user) { 38 | log.info("@ConnectMapping(connect), user:{}", user); 39 | requester.rsocket() 40 | .onClose() 41 | .doFinally( 42 | f -> REQESTER_MAP.remove(user, requester) 43 | ); 44 | REQESTER_MAP.put(user, requester); 45 | log.info("send status back to client..."); 46 | requester.route("status").data("user:" + user + " is connected!") 47 | .retrieveMono(String.class) 48 | .subscribe( 49 | data -> log.info("received data from the client: {}", data), 50 | error -> log.error("error: {}", error), 51 | () -> log.info("done") 52 | ); 53 | } 54 | 55 | @MessageMapping("hello") 56 | Mono ping(@Payload String message) { 57 | log.info("@MessageMapping(hello), payload : {}", message); 58 | return Mono.just("received (" + message + ") at " + LocalDateTime.now()); 59 | } 60 | } 61 | 62 | -------------------------------------------------------------------------------- /server-requester/server/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.rsocket.server.port=7000 2 | spring.rsocket.server.transport=tcp 3 | logging.level.com.example=DEBUG 4 | -------------------------------------------------------------------------------- /tcp/client/.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 | -------------------------------------------------------------------------------- /tcp/client/lombok.config: -------------------------------------------------------------------------------- 1 | lombok.noArgsConstructor.extraPrivate=true 2 | -------------------------------------------------------------------------------- /tcp/client/nbactions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | run 5 | 6 | jar 7 | 8 | 9 | spring-boot:run 10 | 11 | 12 | -noverify -XX:TieredStopAtLevel=1 13 | com.example.consumer.ConsumerApplication 14 | always 15 | 16 | 17 | 18 | debug 19 | 20 | jar 21 | 22 | 23 | spring-boot:run 24 | 25 | 26 | -Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address} -noverify -XX:TieredStopAtLevel=1 27 | com.example.consumer.ConsumerApplication 28 | always 29 | true 30 | 31 | 32 | 33 | profile 34 | 35 | jar 36 | 37 | 38 | process-classes 39 | org.codehaus.mojo:exec-maven-plugin:1.2.1:exec 40 | 41 | 42 | -classpath %classpath com.example.consumer.ConsumerApplication 43 | java 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /tcp/client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.5.RELEASE 9 | 10 | 11 | com.example 12 | rsocket-sample-boot-tcp-client 13 | 0.0.1-SNAPSHOT 14 | rsocket-sample-boot-tcp-client 15 | Demo project for Spring Boot 16 | 17 | 18 | 11 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-webflux 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-rsocket 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 | 49 | 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-maven-plugin 54 | 55 | 56 | 57 | 58 | 59 | 60 | spring-milestones 61 | Spring Milestones 62 | https://repo.spring.io/milestone 63 | 64 | 65 | 66 | 67 | spring-milestones 68 | Spring Milestones 69 | https://repo.spring.io/milestone 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /tcp/client/src/main/java/com/example/client/ClientApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.client; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.RequiredArgsConstructor; 6 | import lombok.extern.slf4j.Slf4j; 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.messaging.rsocket.RSocketRequester; 12 | import org.springframework.util.MimeTypeUtils; 13 | import org.springframework.web.bind.annotation.GetMapping; 14 | import org.springframework.web.bind.annotation.PathVariable; 15 | import org.springframework.web.bind.annotation.RestController; 16 | import reactor.core.publisher.Flux; 17 | import reactor.core.publisher.Mono; 18 | 19 | @SpringBootApplication 20 | public class ClientApplication { 21 | 22 | public static void main(String[] args) { 23 | SpringApplication.run(ClientApplication.class, args); 24 | } 25 | 26 | @Bean 27 | public RSocketRequester rSocketRequester(RSocketRequester.Builder b) { 28 | return b.dataMimeType(MimeTypeUtils.APPLICATION_JSON) 29 | .connectTcp("localhost", 7000).block(); 30 | } 31 | 32 | } 33 | 34 | @Slf4j 35 | @RestController() 36 | @RequiredArgsConstructor 37 | class GreetingController { 38 | 39 | private final RSocketRequester requester; 40 | 41 | @GetMapping("hello") 42 | Mono hello() { 43 | return this.requester.route("hello").data(new Greeting("Welcome to Rsocket")).send(); 44 | } 45 | 46 | @GetMapping("name/{name}") 47 | Mono greet(@PathVariable String name) { 48 | return this.requester.route("greet." + name) 49 | .data(new Greeting("Welcome to RSocket")) 50 | .retrieveMono(String.class) 51 | .doOnNext(msg -> log.info("recevied message::" + msg)); 52 | } 53 | 54 | @GetMapping(value = "stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) 55 | Flux greetStream() { 56 | return this.requester.route("greet-stream").data(new Greeting("Welcome to RSocket")) 57 | .retrieveFlux(String.class) 58 | .doOnNext(msg -> log.info("received messages::" + msg)); 59 | } 60 | 61 | @GetMapping(value = "channel", produces = MediaType.TEXT_EVENT_STREAM_VALUE) 62 | Flux greetChannel() { 63 | return this.requester.route("greet-channel") 64 | .data( 65 | Flux.range(0, 10) 66 | .map(i -> new Greeting("Welcome to RSocket #" + i)) 67 | ) 68 | .retrieveFlux(String.class) 69 | .doOnNext(msg -> log.info("received messages::" + msg)); 70 | } 71 | } 72 | 73 | @Data 74 | @AllArgsConstructor 75 | class Greeting { 76 | 77 | String message; 78 | } 79 | -------------------------------------------------------------------------------- /tcp/client/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tcp/client/src/test/java/com/example/consumer/ConsumerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.consumer; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ConsumerApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /tcp/server/.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 | -------------------------------------------------------------------------------- /tcp/server/nbactions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | run 5 | 6 | jar 7 | 8 | 9 | spring-boot:run 10 | 11 | 12 | -noverify -XX:TieredStopAtLevel=1 13 | com.example.producer.ProducerApplication 14 | always 15 | 16 | 17 | 18 | debug 19 | 20 | jar 21 | 22 | 23 | spring-boot:run 24 | 25 | 26 | -Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address} -noverify -XX:TieredStopAtLevel=1 27 | com.example.producer.ProducerApplication 28 | always 29 | true 30 | 31 | 32 | 33 | profile 34 | 35 | jar 36 | 37 | 38 | process-classes 39 | org.codehaus.mojo:exec-maven-plugin:1.2.1:exec 40 | 41 | 42 | -classpath %classpath com.example.producer.ProducerApplication 43 | java 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /tcp/server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.5.RELEASE 9 | 10 | 11 | com.example 12 | rsocket-sample-boot-tcp-server 13 | 0.0.1-SNAPSHOT 14 | rsocket-sample-boot-tcp-server 15 | Demo project for Spring Boot 16 | 17 | 18 | 11 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 | 45 | 46 | 47 | 48 | org.springframework.boot 49 | spring-boot-maven-plugin 50 | 51 | 52 | 53 | 54 | 55 | 56 | spring-milestones 57 | Spring Milestones 58 | https://repo.spring.io/milestone 59 | 60 | 61 | 62 | 63 | spring-milestones 64 | Spring Milestones 65 | https://repo.spring.io/milestone 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /tcp/server/src/main/java/com/example/server/ServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.server; 2 | 3 | import java.time.Duration; 4 | import java.time.Instant; 5 | 6 | import lombok.Data; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.reactivestreams.Publisher; 9 | import org.springframework.boot.SpringApplication; 10 | import org.springframework.boot.autoconfigure.SpringBootApplication; 11 | import org.springframework.messaging.handler.annotation.DestinationVariable; 12 | import org.springframework.messaging.handler.annotation.MessageMapping; 13 | import org.springframework.messaging.handler.annotation.Payload; 14 | import org.springframework.stereotype.Controller; 15 | import reactor.core.publisher.Flux; 16 | import reactor.core.publisher.Mono; 17 | 18 | @SpringBootApplication 19 | public class ServerApplication { 20 | 21 | public static void main(String[] args) { 22 | SpringApplication.run(ServerApplication.class, args); 23 | } 24 | 25 | } 26 | 27 | @Controller 28 | @Slf4j 29 | class GreetingServerController { 30 | 31 | @MessageMapping("hello") 32 | public Mono hello(Greeting p) { 33 | log.info("received: {} at {}", p, Instant.now()); 34 | return Mono.empty(); 35 | } 36 | 37 | @MessageMapping("greet.{name}") 38 | public Mono greet(@DestinationVariable String name, @Payload Greeting p) { 39 | log.info("received: {}, {} at {}", name, p, Instant.now()); 40 | return Mono.just("Hello " + name + ", " + p.getMessage() + " at " + Instant.now()); 41 | } 42 | 43 | @MessageMapping("greet-stream") 44 | public Flux greetStream(@Payload Greeting p) { 45 | log.info("received: {} at {}", p, Instant.now()); 46 | return Flux.interval(Duration.ofSeconds(1)) 47 | .map(i -> "greet-stream#(Hello #" + i + "," + p.getMessage() + ") at " + Instant.now()); 48 | } 49 | 50 | @MessageMapping("greet-channel") 51 | public Flux greetChannel(@Payload Flux p) { 52 | log.info("received: {} at {}", p, Instant.now()); 53 | return p.delayElements(Duration.ofSeconds(1)) 54 | .map(m -> "greet-channel#(" + m + ") at " + Instant.now()); 55 | } 56 | 57 | } 58 | 59 | @Data 60 | class Greeting { 61 | String message; 62 | } 63 | -------------------------------------------------------------------------------- /tcp/server/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.rsocket.server.port=7000 2 | spring.rsocket.server.transport=tcp 3 | -------------------------------------------------------------------------------- /tcp/server/src/test/java/com/example/producer/ProducerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.producer; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ProducerApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /vanilla/.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 | -------------------------------------------------------------------------------- /vanilla/.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | https://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | import java.io.File; 21 | import java.io.FileInputStream; 22 | import java.io.FileOutputStream; 23 | import java.io.IOException; 24 | import java.net.URL; 25 | import java.nio.channels.Channels; 26 | import java.nio.channels.ReadableByteChannel; 27 | import java.util.Properties; 28 | 29 | public class MavenWrapperDownloader { 30 | 31 | /** 32 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 33 | */ 34 | private static final String DEFAULT_DOWNLOAD_URL = 35 | "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; 36 | 37 | /** 38 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 39 | * use instead of the default one. 40 | */ 41 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 42 | ".mvn/wrapper/maven-wrapper.properties"; 43 | 44 | /** 45 | * Path where the maven-wrapper.jar will be saved to. 46 | */ 47 | private static final String MAVEN_WRAPPER_JAR_PATH = 48 | ".mvn/wrapper/maven-wrapper.jar"; 49 | 50 | /** 51 | * Name of the property which should be used to override the default download url for the wrapper. 52 | */ 53 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 54 | 55 | public static void main(String args[]) { 56 | System.out.println("- Downloader started"); 57 | File baseDirectory = new File(args[0]); 58 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 59 | 60 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 61 | // wrapperUrl parameter. 62 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 63 | String url = DEFAULT_DOWNLOAD_URL; 64 | if(mavenWrapperPropertyFile.exists()) { 65 | FileInputStream mavenWrapperPropertyFileInputStream = null; 66 | try { 67 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 68 | Properties mavenWrapperProperties = new Properties(); 69 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 70 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 71 | } catch (IOException e) { 72 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 73 | } finally { 74 | try { 75 | if(mavenWrapperPropertyFileInputStream != null) { 76 | mavenWrapperPropertyFileInputStream.close(); 77 | } 78 | } catch (IOException e) { 79 | // Ignore ... 80 | } 81 | } 82 | } 83 | System.out.println("- Downloading from: : " + url); 84 | 85 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 86 | if(!outputFile.getParentFile().exists()) { 87 | if(!outputFile.getParentFile().mkdirs()) { 88 | System.out.println( 89 | "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 90 | } 91 | } 92 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 93 | try { 94 | downloadFileFromURL(url, outputFile); 95 | System.out.println("Done"); 96 | System.exit(0); 97 | } catch (Throwable e) { 98 | System.out.println("- Error downloading"); 99 | e.printStackTrace(); 100 | System.exit(1); 101 | } 102 | } 103 | 104 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 105 | URL website = new URL(urlString); 106 | ReadableByteChannel rbc; 107 | rbc = Channels.newChannel(website.openStream()); 108 | FileOutputStream fos = new FileOutputStream(destination); 109 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 110 | fos.close(); 111 | rbc.close(); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /vanilla/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantsy/rsocket-sample/7349fd955764b163ac061b00d30d8a8646a0fcdd/vanilla/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /vanilla/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /vanilla/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" 124 | FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( 125 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 126 | ) 127 | 128 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 129 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 130 | if exist %WRAPPER_JAR% ( 131 | echo Found %WRAPPER_JAR% 132 | ) else ( 133 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 134 | echo Downloading from: %DOWNLOAD_URL% 135 | powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" 136 | echo Finished downloading %WRAPPER_JAR% 137 | ) 138 | @REM End of extension 139 | 140 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 141 | if ERRORLEVEL 1 goto error 142 | goto end 143 | 144 | :error 145 | set ERROR_CODE=1 146 | 147 | :end 148 | @endlocal & set ERROR_CODE=%ERROR_CODE% 149 | 150 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 151 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 152 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 153 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 154 | :skipRcPost 155 | 156 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 157 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 158 | 159 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 160 | 161 | exit /B %ERROR_CODE% 162 | -------------------------------------------------------------------------------- /vanilla/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.0.RELEASE 9 | 10 | 11 | com.example 12 | rsocket-sample-vanilla 13 | 0.0.1-SNAPSHOT 14 | rsocket-sample-vanilla 15 | Demo project for Spring Boot 16 | 17 | 18 | 11 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-webflux 25 | 26 | 27 | 28 | io.rsocket 29 | rsocket-core 30 | 31 | 32 | 33 | io.rsocket 34 | rsocket-transport-netty 35 | 36 | 37 | 38 | org.projectlombok 39 | lombok 40 | 41 | 42 | 43 | org.springframework.boot 44 | spring-boot-starter-test 45 | test 46 | 47 | 48 | org.junit.vintage 49 | junit-vintage-engine 50 | 51 | 52 | junit 53 | junit 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | org.springframework.boot 63 | spring-boot-maven-plugin 64 | 65 | 66 | 67 | 68 | 69 | 70 | spring-milestones 71 | Spring Milestones 72 | https://repo.spring.io/milestone 73 | 74 | 75 | 76 | 77 | spring-milestones 78 | Spring Milestones 79 | https://repo.spring.io/milestone 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /vanilla/src/main/java/com/example/demo/DemoApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this license header, choose License Headers in Project Properties. 3 | * To change this template file, choose Tools | Templates 4 | * and open the template in the editor. 5 | */ 6 | package com.example.demo; 7 | 8 | import static com.example.demo.DemoApplication.PORT; 9 | import io.rsocket.AbstractRSocket; 10 | import io.rsocket.Payload; 11 | import io.rsocket.RSocketFactory; 12 | import io.rsocket.transport.netty.client.TcpClientTransport; 13 | import io.rsocket.transport.netty.server.TcpServerTransport; 14 | import io.rsocket.util.DefaultPayload; 15 | import java.time.Instant; 16 | import lombok.extern.slf4j.Slf4j; 17 | import org.springframework.boot.SpringApplication; 18 | import org.springframework.boot.autoconfigure.SpringBootApplication; 19 | import org.springframework.boot.context.event.ApplicationReadyEvent; 20 | import org.springframework.context.event.EventListener; 21 | import org.springframework.core.annotation.Order; 22 | import org.springframework.stereotype.Component; 23 | import reactor.core.publisher.Mono; 24 | 25 | /** 26 | * 27 | * @author hantsy 28 | */ 29 | @SpringBootApplication 30 | @Slf4j 31 | public class DemoApplication { 32 | 33 | final static int PORT = 7000; 34 | 35 | public static void main(String[] args) { 36 | SpringApplication.run(DemoApplication.class, args); 37 | } 38 | } 39 | 40 | @Component 41 | @Order(0) 42 | @Slf4j 43 | class Producer { 44 | 45 | @EventListener(value = ApplicationReadyEvent.class) 46 | void init() { 47 | 48 | final AbstractRSocket responseHandler = new AbstractRSocket() { 49 | 50 | @Override 51 | public Mono requestResponse(Payload payload) { 52 | log.info("received request-response payload: {}", payload.getDataUtf8()); 53 | return Mono.just(DefaultPayload.create("received (" + payload.getDataUtf8() + ") at " + Instant.now())); 54 | } 55 | }; 56 | 57 | RSocketFactory.receive() 58 | .acceptor( 59 | (setupPayload, reactiveSocket) 60 | -> Mono.just(responseHandler) 61 | ) 62 | .transport(TcpServerTransport.create("localhost", PORT)) 63 | .start() 64 | .block(); 65 | } 66 | } 67 | 68 | @Component 69 | @Slf4j 70 | class Consumer { 71 | 72 | @EventListener(value = ApplicationReadyEvent.class) 73 | void init() { 74 | RSocketFactory.connect() 75 | .transport(TcpClientTransport.create("localhost", PORT)) 76 | .start() 77 | .flatMap(r -> r.requestResponse(DefaultPayload.create("Hello"))) 78 | .subscribe(r -> log.info("handled result:#" + r.getDataUtf8())); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /vanilla/src/main/java/com/example/demo/FireAndForgetExample.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import io.rsocket.AbstractRSocket; 4 | import io.rsocket.Payload; 5 | import io.rsocket.RSocket; 6 | import io.rsocket.RSocketFactory; 7 | import io.rsocket.transport.netty.client.TcpClientTransport; 8 | import io.rsocket.transport.netty.server.TcpServerTransport; 9 | import io.rsocket.util.DefaultPayload; 10 | import reactor.core.Disposable; 11 | import reactor.core.publisher.Mono; 12 | 13 | public class FireAndForgetExample { 14 | 15 | public static void main(String[] args) throws InterruptedException { 16 | final int port = 7000; 17 | 18 | final AbstractRSocket responseHandler = new AbstractRSocket() { 19 | @Override 20 | public Mono fireAndForget(Payload payload) { 21 | System.out.printf("received fire-forget payload: %s%n", payload.getDataUtf8()); 22 | return Mono.empty(); 23 | } 24 | }; 25 | 26 | Disposable server = RSocketFactory.receive() 27 | .acceptor( 28 | (setupPayload, reactiveSocket) 29 | -> Mono.just(responseHandler) 30 | ) 31 | .transport(TcpServerTransport.create("localhost", port)) 32 | .start() 33 | .subscribe(); 34 | 35 | System.out.printf("server is started on port:%d%n", port); 36 | 37 | RSocket socket 38 | = RSocketFactory.connect() 39 | .transport(TcpClientTransport.create("localhost", port)) 40 | .start() 41 | .block(); 42 | System.out.printf("client is connecting to port:%d%n", port); 43 | socket.fireAndForget(DefaultPayload.create("Hello")) 44 | .block(); 45 | 46 | Thread.sleep(2_000); 47 | socket.dispose(); 48 | server.dispose(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /vanilla/src/main/java/com/example/demo/RequestChannelExample.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import io.rsocket.AbstractRSocket; 4 | import io.rsocket.Payload; 5 | import io.rsocket.RSocket; 6 | import io.rsocket.RSocketFactory; 7 | import io.rsocket.transport.netty.client.TcpClientTransport; 8 | import io.rsocket.transport.netty.server.TcpServerTransport; 9 | import io.rsocket.util.DefaultPayload; 10 | import java.time.Duration; 11 | import java.time.Instant; 12 | import org.reactivestreams.Publisher; 13 | import reactor.core.Disposable; 14 | import reactor.core.publisher.Flux; 15 | import reactor.core.publisher.Mono; 16 | 17 | public class RequestChannelExample { 18 | 19 | public static void main(String[] args) throws InterruptedException { 20 | final int port = 7000; 21 | 22 | final AbstractRSocket responseHandler = new AbstractRSocket() { 23 | @Override 24 | public Flux requestChannel(Publisher payloads) { 25 | return Flux.from(payloads) 26 | .map(p->p.getDataUtf8()) 27 | .map(i -> DefaultPayload.create("received(" + i + ") at " + Instant.now())); 28 | } 29 | 30 | }; 31 | 32 | Disposable server = RSocketFactory.receive() 33 | .acceptor( 34 | (setupPayload, reactiveSocket) 35 | -> Mono.just(responseHandler) 36 | ) 37 | .transport(TcpServerTransport.create("localhost", port)) 38 | .start() 39 | .subscribe(); 40 | System.out.printf("server is started on port:%d%n", port); 41 | 42 | RSocket socket = RSocketFactory.connect() 43 | .transport(TcpClientTransport.create("localhost", port)) 44 | .start() 45 | .block(); 46 | System.out.printf("client is connecting to port:%d%n", port); 47 | socket.requestChannel( 48 | Flux.interval(Duration.ofSeconds(1)) 49 | .map(i -> DefaultPayload.create("message #" + i))) 50 | .map(p -> p.getDataUtf8()) 51 | .doOnNext(System.out::println) 52 | .take(10) 53 | .then() 54 | .doFinally(s -> socket.dispose()) 55 | .then().block(); 56 | 57 | server.dispose(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /vanilla/src/main/java/com/example/demo/RequestResponseExample.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import io.rsocket.AbstractRSocket; 4 | import io.rsocket.Payload; 5 | import io.rsocket.RSocket; 6 | import io.rsocket.RSocketFactory; 7 | import io.rsocket.transport.netty.client.TcpClientTransport; 8 | import io.rsocket.transport.netty.server.TcpServerTransport; 9 | import io.rsocket.util.DefaultPayload; 10 | import java.time.Instant; 11 | import reactor.core.Disposable; 12 | import reactor.core.publisher.Mono; 13 | 14 | public class RequestResponseExample { 15 | 16 | public static void main(String[] args) throws InterruptedException { 17 | final int port = 7000; 18 | 19 | final AbstractRSocket responseHandler = new AbstractRSocket() { 20 | 21 | @Override 22 | public Mono requestResponse(Payload payload) { 23 | 24 | System.out.printf("received request-response payload: %s%n", payload.getDataUtf8()); 25 | return Mono.just(DefaultPayload.create(payload.getDataUtf8() + " at "+ Instant.now())); 26 | } 27 | }; 28 | 29 | Disposable server = RSocketFactory.receive() 30 | .acceptor( 31 | (setupPayload, reactiveSocket) 32 | -> Mono.just(responseHandler) 33 | ) 34 | .transport(TcpServerTransport.create("localhost", port)) 35 | .start() 36 | .subscribe(); 37 | System.out.printf("server is started on port:%d%n", port); 38 | 39 | RSocket socket = RSocketFactory.connect() 40 | .transport(TcpClientTransport.create("localhost", port)) 41 | .start() 42 | .block(); 43 | System.out.printf("client is connecting to port:%d%n", port); 44 | socket.requestResponse(DefaultPayload.create("Hello")) 45 | .map(p -> p.getDataUtf8()) 46 | .doOnNext(System.out::println) 47 | .block(); 48 | 49 | socket.dispose(); 50 | server.dispose(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /vanilla/src/main/java/com/example/demo/RequestStreamExample.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import io.rsocket.AbstractRSocket; 4 | import io.rsocket.Payload; 5 | import io.rsocket.RSocket; 6 | import io.rsocket.RSocketFactory; 7 | import io.rsocket.transport.netty.client.TcpClientTransport; 8 | import io.rsocket.transport.netty.server.TcpServerTransport; 9 | import io.rsocket.util.DefaultPayload; 10 | import java.time.Duration; 11 | import java.time.Instant; 12 | import reactor.core.Disposable; 13 | import reactor.core.publisher.Flux; 14 | import reactor.core.publisher.Mono; 15 | 16 | public class RequestStreamExample { 17 | 18 | public static void main(String[] args) throws InterruptedException { 19 | final int port = 7000; 20 | 21 | final AbstractRSocket responseHandler = new AbstractRSocket() { 22 | @Override 23 | public Flux requestStream(Payload payload) { 24 | System.out.printf("received request-stream payload: %s%n", payload.getDataUtf8()); 25 | return Flux.interval(Duration.ofMillis(100)) 26 | .map(i -> DefaultPayload.create("message #" + i + " at " + Instant.now())); 27 | } 28 | 29 | }; 30 | 31 | Disposable server = RSocketFactory.receive() 32 | .acceptor( 33 | (setupPayload, reactiveSocket) 34 | -> Mono.just(responseHandler) 35 | ) 36 | .transport(TcpServerTransport.create("localhost", port)) 37 | .start() 38 | .subscribe(); 39 | System.out.printf("server is started on port:%d%n", port); 40 | 41 | RSocket socket = RSocketFactory.connect() 42 | .transport(TcpClientTransport.create("localhost", port)) 43 | .start() 44 | .block(); 45 | System.out.printf("client is connecting to port:%d%n", port); 46 | socket.requestStream(DefaultPayload.create("Hello")) 47 | .map(p -> p.getDataUtf8()) 48 | .doOnNext(System.out::println) 49 | .take(10) 50 | .then() 51 | .doFinally(s-> socket.dispose()) 52 | .then().block(); 53 | 54 | //Thread.sleep(5_000); 55 | //socket.dispose(); 56 | server.dispose(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /vanilla/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /vanilla/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 | -------------------------------------------------------------------------------- /websocket/client/.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 | -------------------------------------------------------------------------------- /websocket/client/lombok.config: -------------------------------------------------------------------------------- 1 | lombok.noArgsConstructor.extraPrivate=true 2 | -------------------------------------------------------------------------------- /websocket/client/nbactions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | run 5 | 6 | jar 7 | 8 | 9 | spring-boot:run 10 | 11 | 12 | -noverify -XX:TieredStopAtLevel=1 13 | com.example.consumer.ConsumerApplication 14 | always 15 | 16 | 17 | 18 | debug 19 | 20 | jar 21 | 22 | 23 | spring-boot:run 24 | 25 | 26 | -Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address} -noverify -XX:TieredStopAtLevel=1 27 | com.example.consumer.ConsumerApplication 28 | always 29 | true 30 | 31 | 32 | 33 | profile 34 | 35 | jar 36 | 37 | 38 | process-classes 39 | org.codehaus.mojo:exec-maven-plugin:1.2.1:exec 40 | 41 | 42 | -classpath %classpath com.example.consumer.ConsumerApplication 43 | java 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /websocket/client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.5.RELEASE 9 | 10 | 11 | com.example 12 | rsocket-sample-boot-ws-client 13 | 0.0.1-SNAPSHOT 14 | rsocket-sample-boot-ws-client 15 | Demo project for Spring Boot 16 | 17 | 18 | 11 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-webflux 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-rsocket 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 | 49 | 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-maven-plugin 54 | 55 | 56 | 57 | 58 | 59 | 60 | spring-milestones 61 | Spring Milestones 62 | https://repo.spring.io/milestone 63 | 64 | 65 | 66 | 67 | spring-milestones 68 | Spring Milestones 69 | https://repo.spring.io/milestone 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /websocket/client/src/main/java/com/example/client/ClientApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.client; 2 | 3 | import java.net.URI; 4 | import java.time.Duration; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Data; 7 | import lombok.RequiredArgsConstructor; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.boot.SpringApplication; 10 | import org.springframework.boot.autoconfigure.SpringBootApplication; 11 | import org.springframework.context.annotation.Bean; 12 | import org.springframework.http.MediaType; 13 | import org.springframework.messaging.rsocket.RSocketRequester; 14 | import org.springframework.util.MimeType; 15 | import org.springframework.util.MimeTypeUtils; 16 | import org.springframework.web.bind.annotation.GetMapping; 17 | import org.springframework.web.bind.annotation.PathVariable; 18 | import org.springframework.web.bind.annotation.RestController; 19 | import reactor.core.publisher.Flux; 20 | import reactor.core.publisher.Mono; 21 | 22 | @SpringBootApplication 23 | public class ClientApplication { 24 | 25 | public static void main(String[] args) { 26 | SpringApplication.run(ClientApplication.class, args); 27 | } 28 | 29 | @Bean 30 | public RSocketRequester rSocketRequester(RSocketRequester.Builder b) { 31 | return b.dataMimeType(MimeTypeUtils.APPLICATION_JSON) 32 | .connectWebSocket(URI.create("ws://localhost:8081/rsocket")).block(); 33 | } 34 | 35 | } 36 | 37 | @Slf4j 38 | @RestController() 39 | @RequiredArgsConstructor 40 | class GreetingController { 41 | 42 | private final RSocketRequester requester; 43 | 44 | @GetMapping("hello") 45 | Mono hello() { 46 | return this.requester.route("hello").data(new Greeting("Welcome to Rsocket")).send(); 47 | } 48 | 49 | @GetMapping("name/{name}") 50 | Mono greet(@PathVariable String name) { 51 | return this.requester.route("greet." + name).data(new Greeting("Welcome to Rsocket")).retrieveMono(String.class); 52 | } 53 | 54 | @GetMapping(value = "stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) 55 | Flux greetStream() { 56 | return this.requester.route("greet-stream").data(new Greeting("Welcome to Rsocket")) 57 | .retrieveFlux(String.class) 58 | .doOnNext(msg -> log.info("received messages::" + msg)); 59 | } 60 | 61 | @GetMapping(value = "channel", produces = MediaType.TEXT_EVENT_STREAM_VALUE) 62 | Flux greetChannel() { 63 | return this.requester.route("greet-channel") 64 | .data( 65 | Flux.range(0, 10) 66 | .map(i -> new Greeting("Welcome to Rsocket #" + i)) 67 | ) 68 | .retrieveFlux(String.class) 69 | .doOnNext(msg -> log.info("received messages::" + msg)); 70 | } 71 | } 72 | 73 | @Data 74 | @AllArgsConstructor 75 | class Greeting { 76 | 77 | String message; 78 | } 79 | -------------------------------------------------------------------------------- /websocket/client/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /websocket/client/src/test/java/com/example/consumer/ConsumerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.consumer; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ConsumerApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /websocket/server/.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 | -------------------------------------------------------------------------------- /websocket/server/nbactions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | run 5 | 6 | jar 7 | 8 | 9 | spring-boot:run 10 | 11 | 12 | -noverify -XX:TieredStopAtLevel=1 13 | com.example.producer.ProducerApplication 14 | always 15 | 16 | 17 | 18 | debug 19 | 20 | jar 21 | 22 | 23 | spring-boot:run 24 | 25 | 26 | -Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address} -noverify -XX:TieredStopAtLevel=1 27 | com.example.producer.ProducerApplication 28 | always 29 | true 30 | 31 | 32 | 33 | profile 34 | 35 | jar 36 | 37 | 38 | process-classes 39 | org.codehaus.mojo:exec-maven-plugin:1.2.1:exec 40 | 41 | 42 | -classpath %classpath com.example.producer.ProducerApplication 43 | java 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /websocket/server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.5.RELEASE 9 | 10 | 11 | com.example 12 | rsocket-sample-boot-ws-server 13 | 0.0.1-SNAPSHOT 14 | rsocket-sample-boot-ws-server 15 | Demo project for Spring Boot 16 | 17 | 18 | 11 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-webflux 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-rsocket 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 | 49 | 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-maven-plugin 54 | 55 | 56 | 57 | 58 | 59 | 60 | spring-milestones 61 | Spring Milestones 62 | https://repo.spring.io/milestone 63 | 64 | 65 | 66 | 67 | spring-milestones 68 | Spring Milestones 69 | https://repo.spring.io/milestone 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /websocket/server/src/main/java/com/example/server/HelloController.java: -------------------------------------------------------------------------------- 1 | package com.example.server; 2 | 3 | import org.springframework.web.bind.annotation.GetMapping; 4 | import org.springframework.web.bind.annotation.RestController; 5 | 6 | import java.time.Instant; 7 | 8 | @RestController 9 | public class HelloController { 10 | 11 | @GetMapping 12 | public String get() { 13 | return "server greeting at :" + Instant.now(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /websocket/server/src/main/java/com/example/server/ServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.server; 2 | 3 | import java.time.Duration; 4 | import java.time.Instant; 5 | import lombok.Data; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.reactivestreams.Publisher; 8 | import org.springframework.boot.SpringApplication; 9 | import org.springframework.boot.autoconfigure.SpringBootApplication; 10 | import org.springframework.messaging.handler.annotation.DestinationVariable; 11 | import org.springframework.messaging.handler.annotation.MessageMapping; 12 | import org.springframework.messaging.handler.annotation.Payload; 13 | import org.springframework.stereotype.Controller; 14 | import reactor.core.publisher.Flux; 15 | import reactor.core.publisher.Mono; 16 | 17 | @SpringBootApplication 18 | public class ServerApplication { 19 | 20 | public static void main(String[] args) { 21 | SpringApplication.run(ServerApplication.class, args); 22 | } 23 | 24 | } 25 | 26 | @Controller 27 | @Slf4j 28 | class GreetingServerController { 29 | 30 | @MessageMapping("hello") 31 | public Mono hello(Greeting p) { 32 | log.info("received: {} at {}", p, Instant.now()); 33 | return Mono.empty(); 34 | } 35 | 36 | @MessageMapping("greet.{name}") 37 | public Mono greet(@DestinationVariable String name, @Payload Greeting p) { 38 | log.info("received: {}, {} at {}", name, p, Instant.now()); 39 | return Mono.just("Hello " + name + ", " + p.getMessage() + " at " + Instant.now()); 40 | } 41 | 42 | @MessageMapping("greet-stream") 43 | public Flux greetStream(@Payload Greeting p) { 44 | log.info("received: {} at {}", p, Instant.now()); 45 | return Flux.interval(Duration.ofSeconds(1)) 46 | .map(i -> "greet-stream#(Hello #" + i + "," + p.getMessage() + ") at " + Instant.now()); 47 | } 48 | 49 | @MessageMapping("greet-channel") 50 | public Flux greetChannel(@Payload Flux p) { 51 | log.info("received: {} at {}", p, Instant.now()); 52 | return p.delayElements(Duration.ofSeconds(1)) 53 | .map(m -> "greet-channel#(" + m + ") at " + Instant.now()); 54 | } 55 | 56 | } 57 | 58 | @Data 59 | class Greeting { 60 | 61 | String message; 62 | } 63 | -------------------------------------------------------------------------------- /websocket/server/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # a mapping path is defined 2 | spring.rsocket.server.mapping-path=/rsocket 3 | # websocket is chosen as a transport 4 | spring.rsocket.server.transport=websocket 5 | server.port=8081 -------------------------------------------------------------------------------- /websocket/server/src/test/java/com/example/producer/ProducerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.producer; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ProducerApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | --------------------------------------------------------------------------------