├── LICENSE ├── README.md ├── amqp-to-webflux ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── README.adoc ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── springframework │ │ │ └── amqp │ │ │ └── webflux │ │ │ └── so49662157 │ │ │ └── AmqpToWebFluxApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── org │ └── springframework │ └── amqp │ └── webflux │ └── so49662157 │ └── AmqpToWebfluxApplicationTests.java ├── cloud-stream-kinesis-to-webflux ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── README.adoc ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── springframework │ │ │ └── cloud │ │ │ └── stream │ │ │ └── kinesis │ │ │ └── webflux │ │ │ └── so51669324 │ │ │ └── CloudStreamKinesisToWebfluxApplication.java │ └── resources │ │ └── application.yml │ └── test │ └── java │ └── org │ └── springframework │ └── cloud │ └── stream │ └── kinesis │ └── webflux │ └── so51669324 │ └── CloudStreamKinesisToWebfluxApplicationTests.java ├── graph-sample-all-components ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── springframework │ │ │ └── integration │ │ │ └── graphsample │ │ │ └── GraphSampleAllComponentsApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── org │ └── springframework │ └── integration │ └── graphsample │ └── GraphSampleAllComponentsApplicationTests.java ├── http-reply-and-process ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── springframework │ │ │ └── integration │ │ │ └── stackoverflow │ │ │ └── httpreplyandprocess │ │ │ └── HttpReplyAndProcessApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── org │ └── springframework │ └── integration │ └── stackoverflow │ └── httpreplyandprocess │ └── HttpReplyAndProcessApplicationTests.java ├── images └── IntegrationGraph.png ├── kinesis-binder-observation-demo ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── README.adoc ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── kinesisbinderobservationdemo │ │ │ └── KinesisBinderObservationDemoApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── example │ └── kinesisbinderobservationdemo │ ├── KinesisBinderObservationDemoApplicationTests.java │ └── LocalstackContainerTest.java ├── leader-election ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── README.adoc ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── springframework │ │ │ └── integration │ │ │ └── leaderelection │ │ │ └── LeaderElectionApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── org │ └── springframework │ └── integration │ └── leaderelection │ └── LeaderElectionApplicationTests.java ├── lock-on-oracle ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── springframework │ │ │ └── integration │ │ │ └── jdbc │ │ │ └── lock │ │ │ └── oracle │ │ │ └── LockOnOracleApplication.java │ └── resources │ │ └── application.properties │ └── test │ ├── java │ └── org │ │ └── springframework │ │ └── integration │ │ └── jdbc │ │ └── lock │ │ └── oracle │ │ └── LockOnOracleApplicationTests.java │ └── resources │ └── schema.sql ├── null-away-issue ├── .gitattributes ├── .gitignore ├── README.md ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ └── main │ └── java │ └── org │ └── springframework │ └── example │ └── nullawayissue │ ├── NullAwayIssueApplication.java │ └── package-info.java ├── observation-over-stream-rabbit-binder ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── stream │ │ │ └── rabbit │ │ │ └── binder │ │ │ └── observation │ │ │ └── ObservationOverStreamRabbitBinderApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── example │ └── stream │ └── rabbit │ └── binder │ └── observation │ └── ObservationOverStreamRabbitBinderApplicationTests.java ├── postgres-channel-observation ├── .gitignore ├── README.adoc ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── springframework │ │ │ └── integration │ │ │ └── postgreschannelobservation │ │ │ └── PostgresChannelObservationApplication.java │ └── resources │ │ ├── application.properties │ │ └── schema.sql │ └── test │ └── java │ └── org │ └── springframework │ └── integration │ └── postgreschannelobservation │ └── PostgresChannelObservationApplicationTests.java ├── so-65667450 ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── README.md ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── kotlin │ │ └── stackoverflow │ │ │ └── so65667450 │ │ │ └── So65667450Application.kt │ └── resources │ │ └── application.properties │ └── test │ └── kotlin │ └── stackoverflow │ └── so65667450 │ └── So65667450ApplicationTests.kt ├── so-79334692 ├── .gitattributes ├── .gitignore ├── README.md ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── springframework │ │ │ └── integration │ │ │ └── example │ │ │ └── so79334692 │ │ │ └── So79334692Application.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── org │ └── springframework │ └── integration │ └── example │ └── so79334692 │ └── So79334692ApplicationTests.java ├── so-79382434 ├── .gitattributes ├── .gitignore ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── springframework │ │ │ └── cloud │ │ │ └── stream │ │ │ └── example │ │ │ └── so79382434 │ │ │ └── So79382434Application.java │ └── resources │ │ └── application.yml │ └── test │ └── java │ └── org │ └── springframework │ └── cloud │ └── stream │ └── example │ └── so79382434 │ └── So79382434ApplicationTests.java ├── so57889424 ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── springframework │ │ │ └── kafka │ │ │ └── so57889424 │ │ │ └── So57889424Application.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── org │ └── springframework │ └── kafka │ └── so57889424 │ └── So57889424ApplicationTests.java ├── spring-amqp-observation ├── .gitignore ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── springframework │ │ │ └── amqp │ │ │ └── sample │ │ │ └── tracing │ │ │ └── SpringAmqpObservationApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── org │ └── springframework │ └── amqp │ └── sample │ └── tracing │ └── SpringAmqpObservationApplicationTests.java ├── spring-boot-reactor-kafka-tracing ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── springbootreactorkafkatracing │ │ │ └── SpringBootReactorKafkaTracingApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── example │ └── springbootreactorkafkatracing │ └── SpringBootReactorKafkaTracingApplicationTests.java ├── spring-cloud-stream-rabbit-dlq ├── .gitignore ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ └── test │ ├── java │ └── org │ │ └── springframework │ │ └── cloud │ │ └── stream │ │ └── rabbitdlq │ │ └── SpringCloudStreamRabbitDlqApplicationTests.java │ └── resources │ └── application.properties ├── spring-integration-enricher ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── springframework │ │ │ └── integration │ │ │ └── stackoverflow │ │ │ └── enricher │ │ │ └── SpringIntegrationEnricherApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── org │ └── springframework │ └── integration │ └── stackoverflow │ └── enricher │ └── SpringIntegrationEnricherApplicationTests.java ├── spring-integration-mqtt-share-demo ├── .gitignore ├── README.adoc ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── springframework │ │ │ └── cloud │ │ │ └── stream │ │ │ └── springintegrationmqttsharedemo │ │ │ └── SpringIntegrationMqttShareDemoApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── org │ └── springframework │ └── cloud │ └── stream │ └── springintegrationmqttsharedemo │ └── SpringIntegrationMqttShareDemoApplicationTests.java ├── spring-integration-performance ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── README.md ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── springframework │ │ │ └── integration │ │ │ └── performance │ │ │ └── SpringIntegrationPerformanceApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── org │ └── springframework │ └── integration │ └── performance │ └── SpringIntegrationPerformanceApplicationTests.java ├── spring-integration-reactor-kafka ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── spring │ │ │ └── integration │ │ │ └── reactor │ │ │ └── kafka │ │ │ └── SpringIntegrationReactorKafkaApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── example │ └── spring │ └── integration │ └── reactor │ └── kafka │ └── SpringIntegrationReactorKafkaApplicationTests.java ├── spring-integration-security-context-propagation ├── .gitignore ├── HELP.md ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── springframework │ │ │ └── integration │ │ │ └── security │ │ │ └── sample │ │ │ └── springintegrationsecuritycontextpropagation │ │ │ └── SpringIntegrationSecurityContextPropagationApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── org │ └── springframework │ └── integration │ └── security │ └── sample │ └── springintegrationsecuritycontextpropagation │ └── SpringIntegrationSecurityContextPropagationApplicationTests.java ├── spring-integration-websocket-reactive ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── README.adoc ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── springframework │ │ │ └── integration │ │ │ └── socket │ │ │ └── stackoverflow │ │ │ └── springintegrationwebsocketreactive │ │ │ └── SpringIntegrationWebsocketReactiveApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── org │ └── springframework │ └── integration │ └── socket │ └── stackoverflow │ └── springintegrationwebsocketreactive │ └── SpringIntegrationWebsocketReactiveApplicationTests.java ├── spring-integration-with-hystrix ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── README.adoc ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── springframework │ │ │ └── integration │ │ │ └── hystrix │ │ │ └── SpringIntegrationWithHystrixApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── org │ └── springframework │ └── integration │ └── hystrix │ └── SpringIntegrationWithHystrixApplicationTests.java ├── spring-kafka-retry-demo ├── .gitattributes ├── .gitignore ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── springframework │ │ │ └── kafka │ │ │ └── example │ │ │ └── retry │ │ │ └── SpringKafkaRetryDemoApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── org │ └── springframework │ └── kafka │ └── example │ └── retry │ └── SpringKafkaRetryDemoApplicationTests.java └── websocket-over-webflux ├── .gitignore ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── README.md ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── main ├── java │ └── org │ │ └── springframework │ │ └── webflux │ │ └── websocket │ │ └── webfluxwebsocketdemo │ │ └── WebFluxWebSocketDemoApplication.java └── resources │ └── application.properties └── test └── java └── org └── springframework └── webflux └── websocket └── webfluxwebsocketdemo └── WebFluxWebSocketDemoApplicationTests.java /README.md: -------------------------------------------------------------------------------- 1 | # Artem Bilan's Sendbox 2 | 3 | In this repository you can find various small projects for some Proof of Concepts, as Samples for mixed concerns or answers to StackOverflow questions. 4 | 5 | Mostly they are about: 6 | 7 | * [Spring Integration](https://projects.spring.io/spring-integration/) 8 | * [Spring AMQP](https://projects.spring.io/spring-amqp/) 9 | * [Spring Kafka](https://projects.spring.io/spring-kafka/) 10 | * [Project Reactor](https://projectreactor.io/) 11 | * [Spring Cloud](https://projects.spring.io/spring-cloud/) 12 | * [Spring Boot](https://projects.spring.io/spring-boot/) 13 | -------------------------------------------------------------------------------- /amqp-to-webflux/.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/ -------------------------------------------------------------------------------- /amqp-to-webflux/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/amqp-to-webflux/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /amqp-to-webflux/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip 2 | -------------------------------------------------------------------------------- /amqp-to-webflux/README.adoc: -------------------------------------------------------------------------------- 1 | == RabbitMQ Listener to SSE via WebFlux 2 | 3 | This sample demonstrate a simple bridging of message from the RabbitMQ queue to the Server Side Events subscribers via Project Reactor `UnicastProcessor` with `share` mode. 4 | 5 | -------------------------------------------------------------------------------- /amqp-to-webflux/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.amqp.webflux.so49662157 7 | amqp-to-webflux 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | amqp-to-webflux 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.0.0.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-amqp 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-webflux 35 | 36 | 37 | 38 | org.springframework.boot 39 | spring-boot-starter-test 40 | test 41 | 42 | 43 | io.projectreactor 44 | reactor-test 45 | test 46 | 47 | 48 | 49 | 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-maven-plugin 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /amqp-to-webflux/src/main/java/org/springframework/amqp/webflux/so49662157/AmqpToWebFluxApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.amqp.webflux.so49662157; 18 | 19 | import org.springframework.amqp.core.Queue; 20 | import org.springframework.amqp.rabbit.annotation.RabbitListener; 21 | import org.springframework.boot.SpringApplication; 22 | import org.springframework.boot.autoconfigure.SpringBootApplication; 23 | import org.springframework.context.annotation.Bean; 24 | import org.springframework.http.MediaType; 25 | import org.springframework.web.bind.annotation.GetMapping; 26 | import org.springframework.web.bind.annotation.RestController; 27 | 28 | import reactor.core.publisher.Flux; 29 | import reactor.core.publisher.UnicastProcessor; 30 | 31 | /** 32 | * @author Artem Bilan 33 | */ 34 | @SpringBootApplication 35 | @RestController 36 | public class AmqpToWebFluxApplication { 37 | 38 | private final UnicastProcessor sseFluxProcessor = UnicastProcessor.create(); 39 | 40 | private final Flux sseFlux = this.sseFluxProcessor.share(); 41 | 42 | @GetMapping(value = "/sseFromAmqp", produces = MediaType.TEXT_EVENT_STREAM_VALUE) 43 | public Flux getSeeFromAmqp() { 44 | return this.sseFlux; 45 | } 46 | 47 | @Bean 48 | public Queue queueForSee() { 49 | return new Queue("queueForSee"); 50 | } 51 | 52 | @RabbitListener(queues = "queueForSee") 53 | public void handleAmqpMessages(String message) { 54 | this.sseFluxProcessor.onNext(message); 55 | } 56 | 57 | public static void main(String[] args) { 58 | SpringApplication.run(AmqpToWebFluxApplication.class, args); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /amqp-to-webflux/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/amqp-to-webflux/src/main/resources/application.properties -------------------------------------------------------------------------------- /amqp-to-webflux/src/test/java/org/springframework/amqp/webflux/so49662157/AmqpToWebfluxApplicationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.amqp.webflux.so49662157; 18 | 19 | import org.junit.Test; 20 | import org.junit.runner.RunWith; 21 | 22 | import org.springframework.amqp.core.Queue; 23 | import org.springframework.amqp.rabbit.core.RabbitTemplate; 24 | import org.springframework.beans.factory.annotation.Autowired; 25 | import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; 26 | import org.springframework.boot.test.context.SpringBootTest; 27 | import org.springframework.test.context.junit4.SpringRunner; 28 | import org.springframework.test.web.reactive.server.WebTestClient; 29 | 30 | import reactor.core.publisher.Flux; 31 | import reactor.test.StepVerifier; 32 | 33 | @RunWith(SpringRunner.class) 34 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 35 | @AutoConfigureWebTestClient 36 | public class AmqpToWebfluxApplicationTests { 37 | 38 | @Autowired 39 | private WebTestClient webTestClient; 40 | 41 | @Autowired 42 | private RabbitTemplate rabbitTemplate; 43 | 44 | @Autowired 45 | private Queue queueForSee; 46 | 47 | @Test 48 | public void testSeeFromAmqp() { 49 | this.rabbitTemplate.convertAndSend(this.queueForSee.getName(), "foo"); 50 | this.rabbitTemplate.convertAndSend(this.queueForSee.getName(), "bar"); 51 | this.rabbitTemplate.convertAndSend(this.queueForSee.getName(), "baz"); 52 | 53 | Flux flux1 = 54 | this.webTestClient.get().uri("/sseFromAmqp") 55 | .exchange() 56 | .returnResult(String.class) 57 | .getResponseBody(); 58 | 59 | StepVerifier 60 | .create(flux1) 61 | .expectNext("foo", "bar", "baz") 62 | .thenCancel() 63 | .verify(); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /cloud-stream-kinesis-to-webflux/.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/ -------------------------------------------------------------------------------- /cloud-stream-kinesis-to-webflux/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/cloud-stream-kinesis-to-webflux/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /cloud-stream-kinesis-to-webflux/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip 2 | -------------------------------------------------------------------------------- /cloud-stream-kinesis-to-webflux/README.adoc: -------------------------------------------------------------------------------- 1 | == Reactive Spring Cloud Stream AWS Kinesis Binder to SSE via WebFlux 2 | 3 | This sample demonstrate a simple bridging of AWS Kinesis stream records to the Server Side Events subscribers. 4 | The `@StreamListener` sink side is based on the Spring Cloud Stream Reactive support streaming incoming message to the `Flux` argument which, in turn, is used as a source for the `@GetMapping` controller. 5 | 6 | -------------------------------------------------------------------------------- /cloud-stream-kinesis-to-webflux/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.cloud.stream.kinesis.webflux.so51669324 7 | cloud-stream-kinesis-to-webflux 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | cloud-stream-kinesis-to-webflux 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.0.4.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | Finchley.SR1 26 | 27 | 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-webflux 32 | 33 | 34 | org.springframework.cloud 35 | spring-cloud-stream-reactive 36 | 37 | 38 | org.springframework.cloud 39 | spring-cloud-stream-binder-kinesis 40 | 1.0.0.RC1 41 | 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-starter-test 46 | test 47 | 48 | 49 | io.projectreactor 50 | reactor-test 51 | test 52 | 53 | 54 | 55 | 56 | 57 | 58 | org.springframework.cloud 59 | spring-cloud-dependencies 60 | ${spring-cloud.version} 61 | pom 62 | import 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | org.springframework.boot 71 | spring-boot-maven-plugin 72 | 73 | 74 | 75 | 76 | 77 | 78 | spring-milestones 79 | Spring Milestones 80 | https://repo.spring.io/libs-milestone-local 81 | 82 | false 83 | 84 | 85 | 86 | spring-releases 87 | Spring Releases 88 | https://repo.spring.io/release 89 | 90 | false 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /cloud-stream-kinesis-to-webflux/src/main/java/org/springframework/cloud/stream/kinesis/webflux/so51669324/CloudStreamKinesisToWebfluxApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.cloud.stream.kinesis.webflux.so51669324; 18 | 19 | import java.nio.charset.StandardCharsets; 20 | import java.util.List; 21 | 22 | import org.springframework.boot.SpringApplication; 23 | import org.springframework.boot.autoconfigure.SpringBootApplication; 24 | import org.springframework.cloud.stream.annotation.EnableBinding; 25 | import org.springframework.cloud.stream.annotation.StreamListener; 26 | import org.springframework.cloud.stream.messaging.Sink; 27 | import org.springframework.http.MediaType; 28 | import org.springframework.web.bind.annotation.GetMapping; 29 | import org.springframework.web.bind.annotation.RestController; 30 | 31 | import com.amazonaws.services.kinesis.model.Record; 32 | import reactor.core.publisher.ConnectableFlux; 33 | import reactor.core.publisher.Flux; 34 | import reactor.core.publisher.UnicastProcessor; 35 | 36 | @SpringBootApplication 37 | @EnableBinding(Sink.class) 38 | @RestController 39 | public class CloudStreamKinesisToWebfluxApplication { 40 | 41 | private volatile Flux recordFlux; 42 | 43 | @GetMapping(value = "/sseFromKinesis", produces = MediaType.TEXT_EVENT_STREAM_VALUE) 44 | public Flux getSeeFromKinesis() { 45 | return this.recordFlux; 46 | } 47 | 48 | @StreamListener(Sink.INPUT) 49 | public void kinesisSink(Flux> recordFlux) { 50 | this.recordFlux = recordFlux 51 | .flatMap(Flux::fromIterable) 52 | .map(record -> new String(record.getData().array(), StandardCharsets.UTF_8)); 53 | } 54 | 55 | 56 | public static void main(String[] args) { 57 | SpringApplication.run(CloudStreamKinesisToWebfluxApplication.class, args); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /cloud-stream-kinesis-to-webflux/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | stream: 4 | bindings: 5 | input: 6 | destination: SSE_DATA 7 | group: kinesis-to-sse 8 | contentType: application/octet-stream 9 | consumer: 10 | headerMode: none 11 | kinesis: 12 | bindings: 13 | input: 14 | consumer: 15 | listenerMode: rawRecords 16 | 17 | cloud: 18 | aws: 19 | region: 20 | static: eu-west-1 21 | -------------------------------------------------------------------------------- /graph-sample-all-components/.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 | -------------------------------------------------------------------------------- /graph-sample-all-components/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/graph-sample-all-components/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /graph-sample-all-components/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar 3 | -------------------------------------------------------------------------------- /graph-sample-all-components/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.2.RELEASE 9 | 10 | 11 | org.springframework.integration 12 | graph-sample-all-components 13 | 0.0.1-SNAPSHOT 14 | graph-sample-all-components 15 | Demo project for Spring Integration Graph 16 | 17 | 18 | 1.8 19 | 5.3.0.BUILD-SNAPSHOT 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-integration 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-web 30 | 31 | 32 | org.springframework.integration 33 | spring-integration-http 34 | 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-test 39 | test 40 | 41 | 42 | org.junit.vintage 43 | junit-vintage-engine 44 | 45 | 46 | 47 | 48 | org.springframework.amqp 49 | spring-rabbit-test 50 | test 51 | 52 | 53 | 54 | 55 | 56 | 57 | org.springframework.boot 58 | spring-boot-maven-plugin 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | spring-snapshots 67 | Spring Snapshots 68 | https://repo.spring.io/libs-snapshot-local 69 | 70 | true 71 | 72 | 73 | false 74 | 75 | 76 | 77 | spring-milestones 78 | Spring Milestones 79 | https://repo.spring.io/libs-milestone-local 80 | 81 | false 82 | 83 | 84 | 85 | spring-releases 86 | Spring Releases 87 | https://repo.spring.io/release 88 | 89 | false 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /graph-sample-all-components/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=testApplication 2 | spring.jackson.serialization.indent-output=true 3 | -------------------------------------------------------------------------------- /graph-sample-all-components/src/test/java/org/springframework/integration/graphsample/GraphSampleAllComponentsApplicationTests.java: -------------------------------------------------------------------------------- 1 | package org.springframework.integration.graphsample; 2 | 3 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 4 | import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; 5 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; 6 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.handler; 7 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; 8 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 9 | 10 | import org.junit.jupiter.api.Test; 11 | 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 14 | import org.springframework.boot.test.context.SpringBootTest; 15 | import org.springframework.http.MediaType; 16 | import org.springframework.integration.http.management.IntegrationGraphController; 17 | import org.springframework.test.annotation.DirtiesContext; 18 | import org.springframework.test.web.servlet.MockMvc; 19 | 20 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) 21 | @AutoConfigureMockMvc 22 | @DirtiesContext 23 | class GraphSampleAllComponentsApplicationTests { 24 | 25 | @Test 26 | void testIntegrationGraphGet(@Autowired MockMvc mockMvc) throws Exception { 27 | mockMvc.perform(get("/integration") 28 | .accept(MediaType.APPLICATION_JSON)) 29 | .andExpect(status().isOk()) 30 | .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) 31 | .andExpect(handler().handlerType(IntegrationGraphController.class)) 32 | .andExpect(handler().methodName("getGraph")) 33 | .andExpect(jsonPath("$.contentDescriptor.name").value("testApplication")) 34 | .andExpect(jsonPath("$.links").exists()) 35 | .andDo(print()); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /http-reply-and-process/.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 | -------------------------------------------------------------------------------- /http-reply-and-process/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/http-reply-and-process/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /http-reply-and-process/.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 | -------------------------------------------------------------------------------- /http-reply-and-process/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.0.RC1 9 | 10 | 11 | org.springframework.integration.stackoverflow 12 | http-reply-and-process 13 | 0.0.1-SNAPSHOT 14 | http-reply-and-process 15 | Demo project for SO58134243 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-activemq 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-integration 29 | 30 | 31 | org.springframework.integration 32 | spring-integration-http 33 | 34 | 35 | org.springframework.integration 36 | spring-integration-jms 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-web 41 | 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 | 61 | 62 | 63 | 64 | org.springframework.boot 65 | spring-boot-maven-plugin 66 | 67 | 68 | 69 | 70 | 71 | 72 | spring-milestones 73 | Spring Milestones 74 | https://repo.spring.io/milestone 75 | 76 | 77 | 78 | 79 | spring-milestones 80 | Spring Milestones 81 | https://repo.spring.io/milestone 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /http-reply-and-process/src/main/java/org/springframework/integration/stackoverflow/httpreplyandprocess/HttpReplyAndProcessApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.integration.stackoverflow.httpreplyandprocess; 18 | 19 | import java.util.Collections; 20 | 21 | import javax.jms.ConnectionFactory; 22 | 23 | import org.springframework.boot.SpringApplication; 24 | import org.springframework.boot.autoconfigure.SpringBootApplication; 25 | import org.springframework.context.annotation.Bean; 26 | import org.springframework.http.HttpStatus; 27 | import org.springframework.integration.dsl.IntegrationFlow; 28 | import org.springframework.integration.dsl.IntegrationFlows; 29 | import org.springframework.integration.http.HttpHeaders; 30 | import org.springframework.integration.http.dsl.Http; 31 | import org.springframework.integration.jms.dsl.Jms; 32 | import org.springframework.jms.core.JmsTemplate; 33 | 34 | /** 35 | * @author Artem Bilan 36 | */ 37 | @SpringBootApplication 38 | public class HttpReplyAndProcessApplication { 39 | 40 | public static void main(String[] args) { 41 | SpringApplication.run(HttpReplyAndProcessApplication.class, args); 42 | } 43 | 44 | @Bean 45 | public IntegrationFlow replyAndProcessFlow(JmsTemplate jmsTemplate) { 46 | return IntegrationFlows.from(Http.inboundGateway("/replyAndProcess")) 47 | .publishSubscribeChannel(publishSubscribeSpec -> 48 | publishSubscribeSpec.subscribe(flow -> flow 49 | .transform((payload) -> "OK") 50 | .enrichHeaders(Collections.singletonMap(HttpHeaders.STATUS_CODE, HttpStatus.ACCEPTED)))) 51 | .transform(String::toUpperCase) 52 | .handle(Jms.outboundAdapter(jmsTemplate).destination("resultQueue")) 53 | .get(); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /http-reply-and-process/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /http-reply-and-process/src/test/java/org/springframework/integration/stackoverflow/httpreplyandprocess/HttpReplyAndProcessApplicationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.integration.stackoverflow.httpreplyandprocess; 18 | 19 | import static org.assertj.core.api.Assertions.assertThat; 20 | 21 | import javax.jms.JMSException; 22 | import javax.jms.Message; 23 | import javax.jms.TextMessage; 24 | 25 | import org.junit.jupiter.api.Test; 26 | 27 | import org.springframework.beans.factory.annotation.Autowired; 28 | import org.springframework.boot.test.context.SpringBootTest; 29 | import org.springframework.boot.test.web.client.TestRestTemplate; 30 | import org.springframework.integration.dsl.IntegrationFlow; 31 | import org.springframework.integration.dsl.context.IntegrationFlowContext; 32 | import org.springframework.integration.http.dsl.Http; 33 | import org.springframework.jms.core.JmsTemplate; 34 | import org.springframework.test.annotation.DirtiesContext; 35 | 36 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 37 | @DirtiesContext 38 | class HttpReplyAndProcessApplicationTests { 39 | 40 | @Autowired 41 | private TestRestTemplate testRestTemplate; 42 | 43 | @Autowired 44 | private IntegrationFlowContext integrationFlowContext; 45 | 46 | @Autowired 47 | private JmsTemplate jmsTemplate; 48 | 49 | @Test 50 | void testReplyAndProcess() throws JMSException { 51 | 52 | IntegrationFlow clientFlow = 53 | (flow) -> flow 54 | .handle( 55 | Http.outboundGateway(this.testRestTemplate.getRootUri() + "/replyAndProcess", 56 | this.testRestTemplate.getRestTemplate()) 57 | .expectedResponseType(String.class)); 58 | 59 | IntegrationFlowContext.IntegrationFlowRegistration registration = 60 | this.integrationFlowContext 61 | .registration(clientFlow).register(); 62 | 63 | String reply = registration.getMessagingTemplate().convertSendAndReceive("test", String.class); 64 | assertThat(reply).isEqualTo("OK"); 65 | 66 | Message result = this.jmsTemplate.receive("resultQueue"); 67 | 68 | assertThat(result).isNotNull(); 69 | 70 | String payload = ((TextMessage) result).getText(); 71 | assertThat(payload).isEqualTo("TEST"); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /images/IntegrationGraph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/images/IntegrationGraph.png -------------------------------------------------------------------------------- /kinesis-binder-observation-demo/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 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 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /kinesis-binder-observation-demo/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/kinesis-binder-observation-demo/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /kinesis-binder-observation-demo/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar 3 | -------------------------------------------------------------------------------- /kinesis-binder-observation-demo/README.adoc: -------------------------------------------------------------------------------- 1 | == Observation over Spring Cloud Stream AWS Kinesis Binder 2 | 3 | This sample demonstrates an observation and tracing propagation over Spring Cloud Stream destination. 4 | 5 | In this case the application is a WebFlux server to receive `GET` request on a `/test`. 6 | Such a request then handled by Spring Cloud Stream `Supplier` bound to the `my-event` AWS Kinesis stream. 7 | A `name` request param becomes a payload of a message sent to the binder. 8 | 9 | To enable observation we added: 10 | 11 | 1. A `io.micrometer:micrometer-tracing-bridge-brave` dependency to handle tracing via Brave library; 12 | 2. A configuration property `spring.integration.management.observation-patterns=httpSupplier-out-0` to enable observation on a `MessageChannel` tied to the `httpSupplier-out-0` binding; 13 | 3. A configuration property `spring.cloud.stream.kinesis.binder.headers=traceparent` to ensure that W3C tracing header is embedded into Kinesis record for propagation over Kinesis stream. 14 | 15 | The unit test with Localstack Testcontainers environment ensures that HTTP request produced to our application propagates a tracing data over Kinesis stream which we check with a `KinesisMessageDrivenChannelAdapter` subscribed on the mentioned `my-event` bound destination. 16 | This `KinesisMessageDrivenChannelAdapter` is configured to use the same Spring Cloud Stream API for embedded headers for protocol like AWS Kinesis which don't support headers abstraction in their events. 17 | -------------------------------------------------------------------------------- /kinesis-binder-observation-demo/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.0.1 9 | 10 | 11 | com.example 12 | kinesis-binder-observation-demo 13 | 0.0.1-SNAPSHOT 14 | kinesis-binder-observation-demo 15 | kinesis-binder-observation-demo 16 | 17 | 17 18 | 2022.0.1 19 | 20 | 21 | 22 | org.springframework.cloud 23 | spring-cloud-stream 24 | 25 | 26 | org.springframework.cloud 27 | spring-cloud-stream-binder-kinesis 28 | 3.0.0 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-test 33 | test 34 | 35 | 36 | org.testcontainers 37 | junit-jupiter 38 | 1.17.6 39 | test 40 | 41 | 42 | org.testcontainers 43 | localstack 44 | 1.17.6 45 | test 46 | 47 | 48 | 49 | 50 | 51 | org.springframework.cloud 52 | spring-cloud-dependencies 53 | ${spring-cloud.version} 54 | pom 55 | import 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | org.springframework.boot 64 | spring-boot-maven-plugin 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /kinesis-binder-observation-demo/src/main/java/com/example/kinesisbinderobservationdemo/KinesisBinderObservationDemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.kinesisbinderobservationdemo; 2 | 3 | import java.util.function.Consumer; 4 | 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.cloud.stream.binder.EmbeddedHeaderUtils; 8 | import org.springframework.cloud.stream.binder.MessageValues; 9 | import org.springframework.cloud.stream.binder.kinesis.properties.KinesisProducerProperties; 10 | import org.springframework.cloud.stream.binding.NewDestinationBindingCallback; 11 | import org.springframework.context.annotation.Bean; 12 | import org.springframework.integration.channel.DirectChannel; 13 | import org.springframework.integration.channel.QueueChannel; 14 | import org.springframework.integration.support.MessageBuilder; 15 | import org.springframework.messaging.Message; 16 | import org.springframework.messaging.MessageChannel; 17 | import org.springframework.messaging.support.ChannelInterceptor; 18 | 19 | @SpringBootApplication 20 | public class KinesisBinderObservationDemoApplication { 21 | 22 | public static void main(String[] args) { 23 | SpringApplication.run(KinesisBinderObservationDemoApplication.class, args); 24 | } 25 | 26 | @Bean 27 | public Consumer> kinesisConsumer(QueueChannel testBuffer) { 28 | return testBuffer::send; 29 | } 30 | 31 | @Bean 32 | public QueueChannel testBuffer() { 33 | return new QueueChannel(); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /kinesis-binder-observation-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.cloud.stream.bindings.kinesisConsumer-in-0.destination=my-event 2 | spring.cloud.stream.bindings.kinesisConsumer-in-0.group=my-group 3 | spring.cloud.stream.kinesis.binder.headers=X-B3-TraceId,my-name 4 | -------------------------------------------------------------------------------- /kinesis-binder-observation-demo/src/test/java/com/example/kinesisbinderobservationdemo/KinesisBinderObservationDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.kinesisbinderobservationdemo; 2 | 3 | import com.amazonaws.services.dynamodbv2.AmazonDynamoDBAsync; 4 | import com.amazonaws.services.kinesis.AmazonKinesisAsync; 5 | import org.junit.jupiter.api.Test; 6 | 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | import org.springframework.boot.test.context.TestConfiguration; 10 | import org.springframework.cloud.stream.function.StreamBridge; 11 | import org.springframework.context.annotation.Bean; 12 | import org.springframework.integration.channel.QueueChannel; 13 | import org.springframework.integration.support.MessageBuilder; 14 | import org.springframework.messaging.Message; 15 | import org.springframework.test.annotation.DirtiesContext; 16 | import org.springframework.test.context.DynamicPropertyRegistry; 17 | import org.springframework.test.context.DynamicPropertySource; 18 | 19 | import static org.assertj.core.api.Assertions.assertThat; 20 | 21 | @SpringBootTest 22 | @DirtiesContext 23 | class KinesisBinderObservationDemoApplicationTests { 24 | 25 | @Autowired 26 | StreamBridge streamBridge; 27 | 28 | @Autowired 29 | QueueChannel testBuffer; 30 | 31 | @Test 32 | void tracesArePropagateOverKinesis() { 33 | this.streamBridge.send("my-event", 34 | MessageBuilder.withPayload("test data") 35 | .setHeader("my-name", "Test Test") 36 | .setHeader("spring.cloud.function.definition", "myConsumer") 37 | .setHeader("X-B3-TraceId", "123") 38 | .build()); 39 | 40 | Message receive = this.testBuffer.receive(60_000); 41 | assertThat(receive).isNotNull(); 42 | assertThat(receive.getPayload()).isEqualTo("test data"); 43 | assertThat(receive.getHeaders()) 44 | .containsKeys("my-name", "X-B3-TraceId") 45 | .doesNotContainKey("spring.cloud.function.definition"); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /leader-election/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 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 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /leader-election/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/leader-election/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /leader-election/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar 3 | -------------------------------------------------------------------------------- /leader-election/README.adoc: -------------------------------------------------------------------------------- 1 | == Leader Election with Zookeeper 2 | 3 | This sample demonstrate a distributed leader election and role control via Zookeeper. 4 | 5 | A `SourcePollingChannelAdapter` in the application context is marked as not started from the beginning and supplied with a `myRole` role. 6 | This role is used as a leadership election key in the `LeaderInitiatorFactoryBean` for Zookeeper server. 7 | 8 | An embedded `TestingServer` from Curator Framework is started in a JUnit test class. 9 | The unit test method starts two application context and verifies the `applicationEvents.txt` file content. 10 | When both application context are active, we see events only from one of them since exactly this one is a leader. 11 | When we stop the first application, the second takes a leadership, starts its endpoint and emits events for its environment. 12 | So, in the end we start seeing those events in the end of `applicationEvents.txt` file. 13 | -------------------------------------------------------------------------------- /leader-election/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.0.1 9 | 10 | 11 | org.springframework.integration 12 | leader-election 13 | 0.0.1-SNAPSHOT 14 | leader-election 15 | leader-election 16 | 17 | 17 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-integration 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-test 28 | test 29 | 30 | 31 | org.springframework.integration 32 | spring-integration-zookeeper 33 | 34 | 35 | org.springframework.integration 36 | spring-integration-file 37 | 38 | 39 | org.springframework.integration 40 | spring-integration-test 41 | test 42 | 43 | 44 | org.apache.curator 45 | curator-test 46 | 5.4.0 47 | test 48 | 49 | 50 | 51 | 52 | 53 | 54 | org.springframework.boot 55 | spring-boot-maven-plugin 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /leader-election/src/main/java/org/springframework/integration/leaderelection/LeaderElectionApplication.java: -------------------------------------------------------------------------------- 1 | package org.springframework.integration.leaderelection; 2 | 3 | import java.io.File; 4 | 5 | import org.apache.curator.framework.CuratorFramework; 6 | 7 | import org.springframework.beans.factory.annotation.Value; 8 | import org.springframework.boot.SpringApplication; 9 | import org.springframework.boot.autoconfigure.SpringBootApplication; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.integration.dsl.IntegrationFlow; 12 | import org.springframework.integration.file.dsl.Files; 13 | import org.springframework.integration.file.support.FileExistsMode; 14 | import org.springframework.integration.zookeeper.config.LeaderInitiatorFactoryBean; 15 | 16 | @SpringBootApplication 17 | public class LeaderElectionApplication { 18 | 19 | public static void main(String[] args) { 20 | SpringApplication.run(LeaderElectionApplication.class, args); 21 | } 22 | 23 | @Bean 24 | LeaderInitiatorFactoryBean leaderInitiator(CuratorFramework client) { 25 | return new LeaderInitiatorFactoryBean() 26 | .setClient(client) 27 | .setPath("/someZkPath/") 28 | .setRole("myRole"); 29 | } 30 | 31 | @Bean 32 | IntegrationFlow someFlow(@Value("${spring.application.name}") String applicationName, 33 | @Value("${output.directory}") File destinationDirectory) { 34 | 35 | return IntegrationFlow 36 | .fromSupplier(() -> applicationName, 37 | e -> e.role("myRole") 38 | .autoStartup(false) 39 | .poller(poller -> poller.fixedDelay(100))) 40 | .handle(Files.outboundAdapter(destinationDirectory) 41 | .fileNameGenerator(m -> "applicationEvents.txt") 42 | .fileExistsMode(FileExistsMode.APPEND) 43 | .appendNewLine(true)) 44 | .get(); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /leader-election/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | logging.level.org.springframework.integration=debug 2 | -------------------------------------------------------------------------------- /leader-election/src/test/java/org/springframework/integration/leaderelection/LeaderElectionApplicationTests.java: -------------------------------------------------------------------------------- 1 | package org.springframework.integration.leaderelection; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.nio.file.Files; 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | import org.apache.curator.framework.CuratorFramework; 10 | import org.apache.curator.framework.CuratorFrameworkFactory; 11 | import org.apache.curator.retry.BoundedExponentialBackoffRetry; 12 | import org.apache.curator.test.TestingServer; 13 | import org.junit.jupiter.api.AfterAll; 14 | import org.junit.jupiter.api.BeforeAll; 15 | import org.junit.jupiter.api.Test; 16 | import org.junit.jupiter.api.io.TempDir; 17 | 18 | import org.springframework.boot.builder.SpringApplicationBuilder; 19 | import org.springframework.context.ConfigurableApplicationContext; 20 | import org.springframework.context.annotation.Bean; 21 | import org.springframework.context.annotation.Configuration; 22 | 23 | import static org.assertj.core.api.Assertions.assertThat; 24 | 25 | class LeaderElectionApplicationTests { 26 | 27 | @TempDir 28 | static File tmpDir; 29 | 30 | static TestingServer testingServer; 31 | 32 | @BeforeAll 33 | public static void setUpClass() throws Exception { 34 | testingServer = new TestingServer(true); 35 | } 36 | 37 | @AfterAll 38 | public static void tearDownClass() throws IOException { 39 | testingServer.stop(); 40 | } 41 | 42 | @Test 43 | void distributedLeaderElectionOverZk() throws Exception { 44 | ConfigurableApplicationContext applicationContext1 = 45 | new SpringApplicationBuilder() 46 | .sources(CuratorClientConfiguration.class, LeaderElectionApplication.class) 47 | .properties( 48 | Map.of("spring.application.name", "application #1", 49 | "output.directory", tmpDir.getAbsolutePath())) 50 | .run(); 51 | 52 | Thread.sleep(100); // Give the first application a chance to take a leadership 53 | 54 | ConfigurableApplicationContext applicationContext2 = 55 | new SpringApplicationBuilder() 56 | .sources(CuratorClientConfiguration.class, LeaderElectionApplication.class) 57 | .properties( 58 | Map.of("spring.application.name", "application #2", 59 | "output.directory", tmpDir.getAbsolutePath())) 60 | .run(); 61 | 62 | Thread.sleep(1000); // Give applications a chance to generate some events. 63 | 64 | File eventsFile = new File(tmpDir, "applicationEvents.txt"); 65 | 66 | List lines = Files.readAllLines(eventsFile.toPath()); 67 | 68 | assertThat(lines).containsOnly("application #1"); 69 | 70 | applicationContext1.close(); 71 | 72 | Thread.sleep(1000); // Give the second application a chance to obtain a leadership and generate some events. 73 | 74 | lines = Files.readAllLines(eventsFile.toPath()); 75 | 76 | assertThat(lines).containsOnly("application #1", "application #2"); 77 | 78 | applicationContext2.close(); 79 | } 80 | 81 | @Configuration 82 | public static class CuratorClientConfiguration { 83 | 84 | @Bean 85 | public CuratorFramework client() { 86 | CuratorFramework client = CuratorFrameworkFactory.newClient(testingServer.getConnectString(), 87 | new BoundedExponentialBackoffRetry(100, 1000, 3)); 88 | client.start(); 89 | return client; 90 | } 91 | 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /lock-on-oracle/.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 | -------------------------------------------------------------------------------- /lock-on-oracle/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/lock-on-oracle/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /lock-on-oracle/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar 3 | -------------------------------------------------------------------------------- /lock-on-oracle/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.2.RELEASE 9 | 10 | 11 | org.springframework.integration 12 | lock-on-oracle 13 | 0.0.1-SNAPSHOT 14 | lock-on-oracle 15 | Demo project for Spring Integration JDBC Lock 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-jdbc 25 | 26 | 27 | 28 | org.hsqldb 29 | hsqldb 30 | runtime 31 | 32 | 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 | 50 | 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-maven-plugin 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /lock-on-oracle/src/main/java/org/springframework/integration/jdbc/lock/oracle/LockOnOracleApplication.java: -------------------------------------------------------------------------------- 1 | package org.springframework.integration.jdbc.lock.oracle; 2 | 3 | import java.util.Date; 4 | import java.util.UUID; 5 | 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.SpringApplication; 8 | import org.springframework.boot.autoconfigure.SpringBootApplication; 9 | import org.springframework.dao.DuplicateKeyException; 10 | import org.springframework.jdbc.core.JdbcTemplate; 11 | import org.springframework.transaction.annotation.Isolation; 12 | import org.springframework.transaction.annotation.Transactional; 13 | 14 | @SpringBootApplication 15 | public class LockOnOracleApplication { 16 | 17 | public static void main(String[] args) { 18 | SpringApplication.run(LockOnOracleApplication.class, args); 19 | } 20 | 21 | private final String insertQuery = "INSERT INTO INT_LOCK (REGION, LOCK_KEY, CLIENT_ID, CREATED_DATE) VALUES (?, ?, ?, ?)"; 22 | 23 | private final String updateQuery = "UPDATE INT_LOCK SET CREATED_DATE=? WHERE REGION=? AND LOCK_KEY=? AND CLIENT_ID=?"; 24 | 25 | private final String region = "DEFAULT"; 26 | 27 | private final String id = UUID.randomUUID().toString(); 28 | 29 | @Autowired 30 | private JdbcTemplate jdbcTemplate; 31 | 32 | @Transactional(isolation = Isolation.SERIALIZABLE) 33 | public boolean acquire(String lock) { 34 | if (this.jdbcTemplate.update(this.updateQuery, new Date(), this.region, lock, this.id) > 0) { 35 | return true; 36 | } 37 | try { 38 | return this.jdbcTemplate.update(this.insertQuery, this.region, lock, this.id, new Date()) > 0; 39 | } 40 | catch (DuplicateKeyException e) { 41 | return false; 42 | } 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /lock-on-oracle/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | logging.level.org.springframework.jdbc.core=trace 2 | -------------------------------------------------------------------------------- /lock-on-oracle/src/test/java/org/springframework/integration/jdbc/lock/oracle/LockOnOracleApplicationTests.java: -------------------------------------------------------------------------------- 1 | package org.springframework.integration.jdbc.lock.oracle; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import java.util.Date; 6 | 7 | import org.junit.jupiter.api.BeforeAll; 8 | import org.junit.jupiter.api.BeforeEach; 9 | import org.junit.jupiter.api.Test; 10 | 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.boot.test.context.SpringBootTest; 13 | import org.springframework.dao.DuplicateKeyException; 14 | import org.springframework.jdbc.core.JdbcTemplate; 15 | import org.springframework.transaction.annotation.Isolation; 16 | import org.springframework.transaction.annotation.Transactional; 17 | 18 | @SpringBootTest 19 | class LockOnOracleApplicationTests { 20 | 21 | @Autowired 22 | JdbcTemplate jdbcTemplate; 23 | 24 | @Autowired 25 | LockOnOracleApplication lockOnOracleApplication; 26 | 27 | @BeforeEach 28 | void setup() { 29 | this.jdbcTemplate.update("TRUNCATE TABLE INT_LOCK"); 30 | } 31 | 32 | @Test 33 | void contextLoads() { 34 | assertThat(this.lockOnOracleApplication.acquire("foo")).isTrue(); 35 | assertThat(this.lockOnOracleApplication.acquire("foo")).isTrue(); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /lock-on-oracle/src/test/resources/schema.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE INT_LOCK ( 2 | LOCK_KEY CHAR(36) NOT NULL, 3 | REGION VARCHAR(100) NOT NULL, 4 | CLIENT_ID CHAR(36), 5 | CREATED_DATE TIMESTAMP NOT NULL, 6 | constraint INT_LOCK_PK primary key (LOCK_KEY, REGION) 7 | ); 8 | -------------------------------------------------------------------------------- /null-away-issue/.gitattributes: -------------------------------------------------------------------------------- 1 | /gradlew text eol=lf 2 | *.bat text eol=crlf 3 | *.jar binary 4 | -------------------------------------------------------------------------------- /null-away-issue/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /null-away-issue/README.md: -------------------------------------------------------------------------------- 1 | Just run `./gradlew check` and you'll see an error like: 2 | ``` 3 | C:\SpringIO\sandbox\null-away-issue\src\main\java\org\springframework\example\nullawayissue\NullAwayIssueApplication.java:14: error: [NullAway] Cannot pass parameter of type @Nullable String[], as formal parameter has type Object[], which has mismatched type parameter nullability 4 | if (!ObjectUtils.isEmpty(args)) { 5 | ^ 6 | (see http://t.uber.com/nullaway ) 7 | C:\SpringIO\sandbox\null-away-issue\src\main\java\org\springframework\example\nullawayissue\NullAwayIssueApplication.java:20: error: [NullAway] Cannot pass parameter of type @Nullable Object[], as formal parameter has type Object[], which has mismatched type parameter nullability 8 | if (!ObjectUtils.isEmpty(application.someArgs)) { 9 | ^ 10 | (see http://t.uber.com/nullaway ) 11 | 2 errors 12 | ``` 13 | 14 | Which is not expected by the `@NullMarked` in the `package-info.java` and `ObjectUtils.isEmpty()` contract. -------------------------------------------------------------------------------- /null-away-issue/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' version '3.5.0-SNAPSHOT' 4 | id 'io.spring.dependency-management' version '1.1.7' 5 | id 'net.ltgt.errorprone' version '3.1.0' 6 | } 7 | 8 | group = 'org.springframework.example' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(17) 14 | } 15 | } 16 | 17 | repositories { 18 | mavenCentral() 19 | maven { url 'https://repo.spring.io/milestone' } 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | ext { 24 | set('spring-framework.version', '7.0.0-SNAPSHOT') 25 | } 26 | 27 | dependencies { 28 | implementation 'org.springframework.boot:spring-boot-starter' 29 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 30 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 31 | 32 | errorprone 'com.uber.nullaway:nullaway:0.12.3' 33 | errorprone 'com.google.errorprone:error_prone_core:2.35.1' 34 | } 35 | 36 | tasks.named('test') { 37 | useJUnitPlatform() 38 | } 39 | 40 | 41 | tasks.withType(JavaCompile).configureEach { 42 | options.errorprone { 43 | disableAllChecks = true 44 | option('NullAway:OnlyNullMarked', 'true') 45 | option('NullAway:CustomContractAnnotations', 'org.springframework.lang.Contract') 46 | option('NullAway:JSpecifyMode', 'true') 47 | } 48 | } 49 | 50 | tasks.compileJava { 51 | // The check defaults to a warning, bump it up to an error for the main sources 52 | options.errorprone.error('NullAway') 53 | } -------------------------------------------------------------------------------- /null-away-issue/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/null-away-issue/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /null-away-issue/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /null-away-issue/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /null-away-issue/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { url 'https://repo.spring.io/milestone' } 4 | maven { url 'https://repo.spring.io/snapshot' } 5 | gradlePluginPortal() 6 | } 7 | } 8 | rootProject.name = 'null-away-issue' 9 | -------------------------------------------------------------------------------- /null-away-issue/src/main/java/org/springframework/example/nullawayissue/NullAwayIssueApplication.java: -------------------------------------------------------------------------------- 1 | package org.springframework.example.nullawayissue; 2 | 3 | import org.jspecify.annotations.Nullable; 4 | 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.util.ObjectUtils; 7 | 8 | @SpringBootApplication 9 | public class NullAwayIssueApplication { 10 | 11 | @Nullable Object @Nullable [] someArgs; 12 | 13 | public static void main(@Nullable String @Nullable [] args) { 14 | if (!ObjectUtils.isEmpty(args)) { 15 | System.out.println("All good"); 16 | } 17 | 18 | NullAwayIssueApplication application = new NullAwayIssueApplication(); 19 | application.someArgs = args; 20 | if (!ObjectUtils.isEmpty(application.someArgs)) { 21 | System.out.println("All good again"); 22 | } 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /null-away-issue/src/main/java/org/springframework/example/nullawayissue/package-info.java: -------------------------------------------------------------------------------- 1 | @org.jspecify.annotations.NullMarked 2 | package org.springframework.example.nullawayissue; 3 | -------------------------------------------------------------------------------- /observation-over-stream-rabbit-binder/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 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 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /observation-over-stream-rabbit-binder/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/observation-over-stream-rabbit-binder/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /observation-over-stream-rabbit-binder/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip 18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar 19 | -------------------------------------------------------------------------------- /observation-over-stream-rabbit-binder/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.0.3 9 | 10 | 11 | com.example 12 | observation-over-stream-rabbit-binder 13 | 0.0.1-SNAPSHOT 14 | observation-over-stream-rabbit-binder 15 | observation-over-stream-rabbit-binder 16 | 17 | 17 18 | 2022.0.1 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-actuator 24 | 25 | 26 | io.micrometer 27 | micrometer-tracing-bridge-brave 28 | 29 | 30 | io.zipkin.reporter2 31 | zipkin-reporter-brave 32 | 33 | 34 | org.springframework.cloud 35 | spring-cloud-stream-binder-rabbit 36 | 37 | 38 | 39 | 40 | 41 | org.springframework.cloud 42 | spring-cloud-dependencies 43 | ${spring-cloud.version} 44 | pom 45 | import 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-maven-plugin 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /observation-over-stream-rabbit-binder/src/main/java/com/example/stream/rabbit/binder/observation/ObservationOverStreamRabbitBinderApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.stream.rabbit.binder.observation; 2 | 3 | import java.util.function.Consumer; 4 | 5 | import io.micrometer.observation.Observation; 6 | import io.micrometer.observation.ObservationRegistry; 7 | import org.apache.commons.logging.Log; 8 | import org.apache.commons.logging.LogFactory; 9 | 10 | import org.springframework.boot.ApplicationRunner; 11 | import org.springframework.boot.SpringApplication; 12 | import org.springframework.boot.autoconfigure.SpringBootApplication; 13 | import org.springframework.cloud.stream.function.StreamBridge; 14 | import org.springframework.context.annotation.Bean; 15 | import org.springframework.messaging.Message; 16 | 17 | @SpringBootApplication 18 | public class ObservationOverStreamRabbitBinderApplication { 19 | 20 | private static final Log LOGGER = LogFactory.getLog(ObservationOverStreamRabbitBinderApplication.class); 21 | 22 | public static void main(String[] args) { 23 | SpringApplication.run(ObservationOverStreamRabbitBinderApplication.class, args); 24 | } 25 | 26 | @Bean 27 | ApplicationRunner myApplicationRunner(StreamBridge streamBridge, ObservationRegistry observationRegistry) { 28 | return args -> 29 | Observation.createNotStarted("my parent observation", observationRegistry) 30 | .observe(() -> { 31 | String data = "my data"; 32 | LOGGER.debug("Send data to RabbitMQ: " + data); 33 | streamBridge.send("myQueue", data); 34 | }); 35 | } 36 | 37 | @Bean 38 | public Consumer> myRabbitConsumer() { 39 | return message -> LOGGER.debug("Received message from RabbitMQ: " + message); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /observation-over-stream-rabbit-binder/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=my-application 2 | management.tracing.sampling.probability=1 3 | logging.pattern.level=%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}] 4 | logging.level.com.example.stream.rabbit.binder.observation=debug 5 | spring.cloud.stream.bindings.myRabbitConsumer-in-0.destination=myQueue 6 | -------------------------------------------------------------------------------- /observation-over-stream-rabbit-binder/src/test/java/com/example/stream/rabbit/binder/observation/ObservationOverStreamRabbitBinderApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.stream.rabbit.binder.observation; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | 7 | @SpringBootTest 8 | class ObservationOverStreamRabbitBinderApplicationTests { 9 | 10 | @Test 11 | void contextLoads() { 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /postgres-channel-observation/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /postgres-channel-observation/README.adoc: -------------------------------------------------------------------------------- 1 | = Tracing Over PostgreSQL Message Channel 2 | 3 | This sample demonstrates a `PostgresSubscribableChannel` and how an `Observation` is propagated from producer to consumer. 4 | 5 | To propagate an observation over this channel, there is enough to have it enabled on this channel and on its subscriber: 6 | 7 | [source,properties] 8 | ---- 9 | spring.integration.management.observation-patterns=postgresChannel,postgresHandler 10 | ---- 11 | 12 | It uses Spring Boot https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#features.testing.testcontainers.service-connections[Service Connections] in the test to start Testcontainers for PostgreSQL DB. 13 | The `TestSpanHandler` from the `io.micrometer:micrometer-tracing-integration-test` is used to verify the tracing in the application. 14 | And also the test checks for the common `traceId` in the `CapturedOutput`, which is logged by the `postgresHandler` `@ServiceActivator`. 15 | 16 | See https://docs.spring.io/spring-integration/reference/jdbc/message-store.html#postgresql-push[Spring Integration JDBC] module for more information. 17 | -------------------------------------------------------------------------------- /postgres-channel-observation/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' version '3.2.3' 4 | id 'io.spring.dependency-management' version '1.1.4' 5 | } 6 | 7 | group = 'org.springframework.integration' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | java { 11 | sourceCompatibility = '17' 12 | } 13 | 14 | repositories { 15 | mavenCentral() 16 | } 17 | 18 | dependencies { 19 | implementation 'org.springframework.boot:spring-boot-starter-actuator' 20 | implementation 'org.springframework.boot:spring-boot-starter-integration' 21 | implementation 'org.springframework.boot:spring-boot-starter-jdbc' 22 | implementation 'org.springframework.integration:spring-integration-jdbc' 23 | implementation 'io.micrometer:micrometer-tracing-bridge-brave' 24 | implementation 'org.postgresql:postgresql' 25 | 26 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 27 | testImplementation 'org.springframework.boot:spring-boot-testcontainers' 28 | testImplementation 'org.springframework.integration:spring-integration-test' 29 | testImplementation 'org.testcontainers:postgresql' 30 | testImplementation 'io.micrometer:micrometer-observation-test' 31 | testImplementation('io.micrometer:micrometer-tracing-integration-test') { 32 | exclude group: 'io.zipkin.reporter2' 33 | exclude group: 'io.opentelemetry' 34 | exclude group: 'com.wavefront' 35 | exclude group: 'io.micrometer', module: 'micrometer-tracing-bridge-otel' 36 | } 37 | } 38 | 39 | tasks.named('test') { 40 | useJUnitPlatform() 41 | } 42 | -------------------------------------------------------------------------------- /postgres-channel-observation/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/postgres-channel-observation/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /postgres-channel-observation/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2012-2024 the original author or authors. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | distributionBase=GRADLE_USER_HOME 18 | distributionPath=wrapper/dists 19 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip 20 | networkTimeout=10000 21 | validateDistributionUrl=true 22 | zipStoreBase=GRADLE_USER_HOME 23 | zipStorePath=wrapper/dists 24 | -------------------------------------------------------------------------------- /postgres-channel-observation/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /postgres-channel-observation/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'postgres-channel-observation' 2 | -------------------------------------------------------------------------------- /postgres-channel-observation/src/main/java/org/springframework/integration/postgreschannelobservation/PostgresChannelObservationApplication.java: -------------------------------------------------------------------------------- 1 | package org.springframework.integration.postgreschannelobservation; 2 | 3 | import java.sql.DriverManager; 4 | 5 | import javax.sql.DataSource; 6 | 7 | import org.apache.commons.logging.Log; 8 | import org.apache.commons.logging.LogFactory; 9 | import org.postgresql.jdbc.PgConnection; 10 | 11 | import org.springframework.boot.SpringApplication; 12 | import org.springframework.boot.autoconfigure.SpringBootApplication; 13 | import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; 14 | import org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetails; 15 | import org.springframework.context.annotation.Bean; 16 | import org.springframework.integration.annotation.EndpointId; 17 | import org.springframework.integration.annotation.ServiceActivator; 18 | import org.springframework.integration.dsl.IntegrationFlow; 19 | import org.springframework.integration.jdbc.channel.PostgresChannelMessageTableSubscriber; 20 | import org.springframework.integration.jdbc.channel.PostgresSubscribableChannel; 21 | import org.springframework.integration.jdbc.store.JdbcChannelMessageStore; 22 | import org.springframework.integration.jdbc.store.channel.PostgresChannelMessageStoreQueryProvider; 23 | import org.springframework.messaging.Message; 24 | import org.springframework.transaction.PlatformTransactionManager; 25 | 26 | @SpringBootApplication 27 | public class PostgresChannelObservationApplication { 28 | 29 | private static final Log LOG = LogFactory.getLog(PostgresChannelObservationApplication.class); 30 | 31 | public static void main(String[] args) { 32 | SpringApplication.run(PostgresChannelObservationApplication.class, args); 33 | } 34 | 35 | @Bean 36 | public JdbcChannelMessageStore messageStore(DataSource dataSource) { 37 | var messageStore = new JdbcChannelMessageStore(dataSource); 38 | messageStore.setChannelMessageStoreQueryProvider(new PostgresChannelMessageStoreQueryProvider()); 39 | return messageStore; 40 | } 41 | 42 | @Bean 43 | public PostgresChannelMessageTableSubscriber subscriber(JdbcConnectionDetails jdbcConnectionDetails) { 44 | return new PostgresChannelMessageTableSubscriber( 45 | () -> DriverManager.getConnection( 46 | jdbcConnectionDetails.getJdbcUrl(), 47 | jdbcConnectionDetails.getUsername(), 48 | jdbcConnectionDetails.getPassword()) 49 | .unwrap(PgConnection.class)); 50 | } 51 | 52 | @Bean 53 | public PostgresSubscribableChannel postgresChannel(PostgresChannelMessageTableSubscriber subscriber, 54 | JdbcChannelMessageStore messageStore, 55 | PlatformTransactionManager transactionManager) { 56 | 57 | var postgresSubscribableChannel = new PostgresSubscribableChannel(messageStore, "group-id", subscriber); 58 | postgresSubscribableChannel.setTransactionManager(transactionManager); 59 | return postgresSubscribableChannel; 60 | } 61 | 62 | @ServiceActivator(inputChannel = "postgresChannel") 63 | @EndpointId("postgresHandler") 64 | void handleEvent(Message message) { 65 | LOG.info("Event received: " + message); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /postgres-channel-observation/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=postgres-channel-observation 2 | management.tracing.sampling.probability=1 3 | logging.pattern.level=%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}] 4 | spring.integration.management.observation-patterns=postgresChannel,postgresHandler 5 | spring.integration.jdbc.initialize-schema=always 6 | spring.sql.init.mode=always -------------------------------------------------------------------------------- /postgres-channel-observation/src/main/resources/schema.sql: -------------------------------------------------------------------------------- 1 | CREATE FUNCTION INT_CHANNEL_MESSAGE_NOTIFY_FCT() 2 | RETURNS TRIGGER AS 3 | ' 4 | BEGIN 5 | PERFORM 6 | pg_notify(''int_channel_message_notify'', NEW.REGION || '' '' || NEW.GROUP_KEY); 7 | RETURN NEW; 8 | END; 9 | ' 10 | LANGUAGE PLPGSQL; 11 | 12 | CREATE TRIGGER INT_CHANNEL_MESSAGE_NOTIFY_TRG 13 | AFTER INSERT 14 | ON INT_CHANNEL_MESSAGE 15 | FOR EACH ROW 16 | EXECUTE PROCEDURE INT_CHANNEL_MESSAGE_NOTIFY_FCT(); -------------------------------------------------------------------------------- /postgres-channel-observation/src/test/java/org/springframework/integration/postgreschannelobservation/PostgresChannelObservationApplicationTests.java: -------------------------------------------------------------------------------- 1 | package org.springframework.integration.postgreschannelobservation; 2 | 3 | import brave.handler.SpanHandler; 4 | import brave.test.TestSpanHandler; 5 | import io.micrometer.observation.Observation; 6 | import io.micrometer.observation.ObservationRegistry; 7 | import io.micrometer.tracing.brave.bridge.BraveFinishedSpan; 8 | import io.micrometer.tracing.exporter.FinishedSpan; 9 | import io.micrometer.tracing.test.simple.SpansAssert; 10 | import org.junit.jupiter.api.Test; 11 | import org.junit.jupiter.api.extension.ExtendWith; 12 | import org.testcontainers.containers.PostgreSQLContainer; 13 | import org.testcontainers.junit.jupiter.Container; 14 | import org.testcontainers.junit.jupiter.Testcontainers; 15 | 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.boot.test.autoconfigure.actuate.observability.AutoConfigureObservability; 18 | import org.springframework.boot.test.context.SpringBootTest; 19 | import org.springframework.boot.test.context.TestConfiguration; 20 | import org.springframework.boot.test.system.CapturedOutput; 21 | import org.springframework.boot.test.system.OutputCaptureExtension; 22 | import org.springframework.boot.testcontainers.service.connection.ServiceConnection; 23 | import org.springframework.context.annotation.Bean; 24 | import org.springframework.messaging.MessageChannel; 25 | import org.springframework.messaging.support.GenericMessage; 26 | 27 | import static org.assertj.core.api.Assertions.assertThat; 28 | import static org.awaitility.Awaitility.await; 29 | 30 | @SpringBootTest 31 | @AutoConfigureObservability 32 | @ExtendWith(OutputCaptureExtension.class) 33 | class PostgresChannelObservationApplicationTests { 34 | 35 | static final TestSpanHandler SPANS = new TestSpanHandler(); 36 | 37 | @Autowired 38 | ObservationRegistry observationRegistry; 39 | 40 | @Autowired 41 | MessageChannel postgresChannel; 42 | 43 | @Test 44 | void observationIsPropagatedOverPostgresSubscribableChannel(CapturedOutput output) { 45 | Observation 46 | .createNotStarted("test-parent-observation", this.observationRegistry) 47 | .lowCardinalityKeyValue("service.name", PostgresChannelObservationApplicationTests.class.getName()) 48 | .observe(() -> postgresChannel.send(new GenericMessage<>("test data"))); 49 | 50 | await().untilAsserted(() -> assertThat(SPANS.spans()).hasSize(3)); 51 | SpansAssert.assertThat(SPANS.spans().stream().map(BraveFinishedSpan::fromBrave).toList()) 52 | .haveSameTraceId(); 53 | 54 | assertThat(output.getOut()) 55 | .contains(SPANS.spans().stream() 56 | .map(BraveFinishedSpan::fromBrave) 57 | .map(FinishedSpan::getTraceId) 58 | .findFirst() 59 | .get()); 60 | } 61 | 62 | @TestConfiguration(proxyBeanMethods = false) 63 | public static class MyTestConfiguration { 64 | 65 | @Bean 66 | @ServiceConnection(name = "postgres") 67 | public PostgreSQLContainer postgreSQLContainer() { 68 | return new PostgreSQLContainer<>("postgres:11"); 69 | } 70 | 71 | @Bean 72 | public SpanHandler testSpanHandler() { 73 | return SPANS; 74 | } 75 | 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /so-65667450/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 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 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /so-65667450/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/so-65667450/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /so-65667450/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /so-65667450/README.md: -------------------------------------------------------------------------------- 1 | # Spring WebFlux with Kafka and Websockets in Kotlin 2 | 3 | See StackOverflow thread https://stackoverflow.com/questions/65667450/spring-webflux-with-kafka-and-websockets 4 | -------------------------------------------------------------------------------- /so-65667450/src/main/kotlin/stackoverflow/so65667450/So65667450Application.kt: -------------------------------------------------------------------------------- 1 | package stackoverflow.so65667450 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication 4 | import org.springframework.boot.runApplication 5 | import org.springframework.context.annotation.Bean 6 | import org.springframework.kafka.annotation.KafkaListener 7 | import org.springframework.web.reactive.HandlerMapping 8 | import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping 9 | import org.springframework.web.reactive.socket.WebSocketHandler 10 | import reactor.core.publisher.Sinks 11 | 12 | 13 | @SpringBootApplication 14 | class So65667450Application { 15 | 16 | val sink = Sinks.many().multicast().onBackpressureBuffer() 17 | 18 | @KafkaListener(topics = ["mytopic"], groupId = "test-consumer-group") 19 | fun receiveData(message: String) { 20 | this.sink.tryEmitNext(message) 21 | } 22 | 23 | @Bean 24 | fun handlerMapping(): HandlerMapping { 25 | val map = mapOf("/fromKafka" to 26 | WebSocketHandler { session -> 27 | session.send(this.sink.asFlux().map(session::textMessage)) 28 | }) 29 | return SimpleUrlHandlerMapping(map, -1) 30 | } 31 | 32 | fun main(args: Array) { 33 | runApplication(*args) 34 | } 35 | 36 | } 37 | 38 | -------------------------------------------------------------------------------- /so-65667450/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /so-65667450/src/test/kotlin/stackoverflow/so65667450/So65667450ApplicationTests.kt: -------------------------------------------------------------------------------- 1 | package stackoverflow.so65667450 2 | 3 | import org.junit.jupiter.api.Test 4 | import org.springframework.beans.factory.annotation.Autowired 5 | import org.springframework.boot.test.context.SpringBootTest 6 | import org.springframework.boot.web.server.LocalServerPort 7 | import org.springframework.kafka.core.KafkaTemplate 8 | import org.springframework.kafka.test.context.EmbeddedKafka 9 | import org.springframework.web.reactive.socket.WebSocketMessage 10 | import org.springframework.web.reactive.socket.client.ReactorNettyWebSocketClient 11 | import reactor.core.publisher.Sinks 12 | import reactor.test.StepVerifier 13 | import java.net.URI 14 | 15 | 16 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 17 | @EmbeddedKafka(topics = ["mytopic"], bootstrapServersProperty = "spring.kafka.bootstrap-servers") 18 | class So65667450ApplicationTests { 19 | 20 | @Autowired 21 | lateinit var kafkaTemplate: KafkaTemplate<*, String> 22 | 23 | @LocalServerPort 24 | var port = 0 25 | 26 | val webSocketClient = ReactorNettyWebSocketClient() 27 | 28 | @Test 29 | fun contextLoads() { 30 | val testDataSink = Sinks.many().unicast().onBackpressureBuffer() 31 | val url = URI("ws://localhost:${port}/fromKafka") 32 | webSocketClient.execute(url) { session -> 33 | session.receive() 34 | .doOnNext(testDataSink::tryEmitNext) 35 | .then() 36 | }.subscribe() 37 | 38 | val stepVerifier = 39 | StepVerifier.create( 40 | testDataSink.asFlux() 41 | .map { it.payloadAsText } 42 | .doOnNext(::println)) 43 | .expectNext("TEST DATA") 44 | .thenCancel() 45 | .verifyLater() 46 | 47 | this.kafkaTemplate.send("mytopic", "TEST DATA") 48 | 49 | stepVerifier.verify() 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /so-79334692/.gitattributes: -------------------------------------------------------------------------------- 1 | /gradlew text eol=lf 2 | *.bat text eol=crlf 3 | *.jar binary 4 | -------------------------------------------------------------------------------- /so-79334692/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | !**/src/main/**/build/ 5 | !**/src/test/**/build/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | bin/ 16 | !**/src/main/**/bin/ 17 | !**/src/test/**/bin/ 18 | 19 | ### IntelliJ IDEA ### 20 | .idea 21 | *.iws 22 | *.iml 23 | *.ipr 24 | out/ 25 | !**/src/main/**/out/ 26 | !**/src/test/**/out/ 27 | 28 | ### NetBeans ### 29 | /nbproject/private/ 30 | /nbbuild/ 31 | /dist/ 32 | /nbdist/ 33 | /.nb-gradle/ 34 | 35 | ### VS Code ### 36 | .vscode/ 37 | -------------------------------------------------------------------------------- /so-79334692/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' version '3.4.1' 4 | id 'io.spring.dependency-management' version '1.1.7' 5 | } 6 | 7 | group = 'org.springframework.integration.example' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | java { 11 | toolchain { 12 | languageVersion = JavaLanguageVersion.of(17) 13 | } 14 | } 15 | 16 | repositories { 17 | mavenCentral() 18 | } 19 | 20 | dependencies { 21 | implementation 'org.springframework.boot:spring-boot-starter-integration' 22 | implementation 'org.springframework.boot:spring-boot-starter-jdbc' 23 | implementation 'org.springframework.integration:spring-integration-jdbc' 24 | implementation 'org.springframework.integration:spring-integration-sftp' 25 | 26 | runtimeOnly 'com.h2database:h2' 27 | 28 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 29 | testImplementation 'org.springframework.integration:spring-integration-test' 30 | 31 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 32 | } 33 | 34 | tasks.named('test') { 35 | useJUnitPlatform() 36 | } 37 | -------------------------------------------------------------------------------- /so-79334692/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/so-79334692/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /so-79334692/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /so-79334692/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /so-79334692/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'so-79334692' 2 | -------------------------------------------------------------------------------- /so-79334692/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=so-79334692 2 | 3 | spring.task.scheduling.pool.size=10 -------------------------------------------------------------------------------- /so-79382434/.gitattributes: -------------------------------------------------------------------------------- 1 | /gradlew text eol=lf 2 | *.bat text eol=crlf 3 | *.jar binary 4 | -------------------------------------------------------------------------------- /so-79382434/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /so-79382434/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' version '3.4.2' 4 | id 'io.spring.dependency-management' version '1.1.7' 5 | } 6 | 7 | group = 'org.springframework.cloud.stream.example' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | java { 11 | toolchain { 12 | languageVersion = JavaLanguageVersion.of(17) 13 | } 14 | } 15 | 16 | repositories { 17 | mavenCentral() 18 | } 19 | 20 | ext { 21 | set('springCloudVersion', "2024.0.0") 22 | } 23 | 24 | dependencies { 25 | implementation 'org.springframework.boot:spring-boot-starter-amqp' 26 | implementation 'org.springframework.cloud:spring-cloud-stream' 27 | implementation 'org.springframework.cloud:spring-cloud-stream-binder-rabbit' 28 | 29 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 30 | testImplementation 'org.springframework.amqp:spring-rabbit-test' 31 | testImplementation 'org.springframework.cloud:spring-cloud-stream-test-binder' 32 | 33 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 34 | } 35 | 36 | dependencyManagement { 37 | imports { 38 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" 39 | } 40 | } 41 | 42 | tasks.named('test') { 43 | useJUnitPlatform() 44 | } 45 | -------------------------------------------------------------------------------- /so-79382434/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/so-79382434/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /so-79382434/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /so-79382434/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /so-79382434/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'so-79382434' 2 | -------------------------------------------------------------------------------- /so-79382434/src/main/java/org/springframework/cloud/stream/example/so79382434/So79382434Application.java: -------------------------------------------------------------------------------- 1 | package org.springframework.cloud.stream.example.so79382434; 2 | 3 | import java.util.function.Consumer; 4 | 5 | import org.springframework.boot.ApplicationRunner; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.cloud.stream.function.StreamBridge; 9 | import org.springframework.context.annotation.Bean; 10 | 11 | @SpringBootApplication 12 | public class So79382434Application { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(So79382434Application.class, args); 16 | } 17 | 18 | @Bean 19 | ApplicationRunner init(StreamBridge streamBridge) { 20 | return args -> streamBridge.send("new-price-out", "100.00"); 21 | } 22 | 23 | @Bean 24 | Consumer newPrice() { 25 | return data -> System.out.println("New price is: " + data); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /so-79382434/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: so-79382434 4 | cloud: 5 | stream: 6 | bindings: 7 | new-price-out: 8 | destination: new-price 9 | newPrice-in-0: 10 | destination: new-price -------------------------------------------------------------------------------- /so-79382434/src/test/java/org/springframework/cloud/stream/example/so79382434/So79382434ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package org.springframework.cloud.stream.example.so79382434; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class So79382434ApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /so57889424/.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 | -------------------------------------------------------------------------------- /so57889424/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/so57889424/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /so57889424/.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 | -------------------------------------------------------------------------------- /so57889424/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.1.8.RELEASE 9 | 10 | 11 | org.springframework.kafka.so57889424 12 | so57889424 13 | 0.0.1-SNAPSHOT 14 | so57889424 15 | Demo project for Spring Kafka to reproduce so57889424 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter 25 | 26 | 27 | org.springframework.kafka 28 | spring-kafka 29 | 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-test 34 | test 35 | 36 | 37 | org.springframework.kafka 38 | spring-kafka-test 39 | test 40 | 41 | 42 | 43 | 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-maven-plugin 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /so57889424/src/main/java/org/springframework/kafka/so57889424/So57889424Application.java: -------------------------------------------------------------------------------- 1 | package org.springframework.kafka.so57889424; 2 | 3 | import java.util.concurrent.CountDownLatch; 4 | import java.util.concurrent.atomic.AtomicInteger; 5 | 6 | import javax.annotation.PostConstruct; 7 | 8 | import org.apache.kafka.clients.admin.NewTopic; 9 | import org.apache.kafka.clients.consumer.ConsumerRecord; 10 | 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.boot.SpringApplication; 13 | import org.springframework.boot.autoconfigure.SpringBootApplication; 14 | import org.springframework.context.annotation.Bean; 15 | import org.springframework.context.event.EventListener; 16 | import org.springframework.kafka.annotation.KafkaListener; 17 | import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; 18 | import org.springframework.kafka.event.ListenerContainerIdleEvent; 19 | import org.springframework.kafka.listener.ErrorHandler; 20 | import org.springframework.kafka.listener.SeekToCurrentErrorHandler; 21 | import org.springframework.retry.backoff.BackOffPolicy; 22 | import org.springframework.retry.backoff.ExponentialRandomBackOffPolicy; 23 | import org.springframework.retry.policy.SimpleRetryPolicy; 24 | import org.springframework.retry.support.RetryTemplate; 25 | 26 | @SpringBootApplication 27 | public class So57889424Application { 28 | 29 | public static void main(String[] args) { 30 | SpringApplication.run(So57889424Application.class, args); 31 | } 32 | 33 | public static final String SO57889424_TOPIC = "So57889424"; 34 | 35 | @Autowired 36 | private ConcurrentKafkaListenerContainerFactory concurrentKafkaListenerContainerFactory; 37 | 38 | @PostConstruct 39 | public void setup() { 40 | this.concurrentKafkaListenerContainerFactory.setStatefulRetry(true); 41 | RetryTemplate retryTemplate = new RetryTemplate(); 42 | retryTemplate.setBackOffPolicy(new ExponentialRandomBackOffPolicy()); 43 | retryTemplate.setThrowLastExceptionOnExhausted(true); 44 | retryTemplate.setRetryPolicy(new SimpleRetryPolicy(3)); 45 | this.concurrentKafkaListenerContainerFactory.setRetryTemplate(retryTemplate); 46 | } 47 | 48 | @Bean 49 | public ErrorHandler seekToCurrentErrorHandler() { 50 | SeekToCurrentErrorHandler seekToCurrentErrorHandler = new SeekToCurrentErrorHandler(3); 51 | seekToCurrentErrorHandler.setCommitRecovered(true); 52 | return seekToCurrentErrorHandler; 53 | } 54 | 55 | @Bean 56 | public AtomicInteger processCount() { 57 | return new AtomicInteger(); 58 | } 59 | 60 | @KafkaListener(topics = SO57889424_TOPIC) 61 | public void process(ConsumerRecord record) { 62 | processCount().incrementAndGet(); 63 | throw new RuntimeException("force to retry for: " + record); 64 | } 65 | 66 | @Bean 67 | public CountDownLatch listenerIdleLatch() { 68 | return new CountDownLatch(1); 69 | } 70 | 71 | @EventListener 72 | public void containerIdleEvenListener(ListenerContainerIdleEvent event) { 73 | listenerIdleLatch().countDown(); 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /so57889424/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.kafka.listener.concurrency=4 2 | spring.kafka.consumer.group-id=so57889424 3 | spring.kafka.consumer.enable-auto-commit=false 4 | spring.kafka.consumer.auto-offset-reset=earliest 5 | spring.kafka.listener.idle-event-interval=5s 6 | spring.kafka.listener.ack-mode=manual_immediate 7 | -------------------------------------------------------------------------------- /so57889424/src/test/java/org/springframework/kafka/so57889424/So57889424ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package org.springframework.kafka.so57889424; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import java.util.concurrent.CountDownLatch; 6 | import java.util.concurrent.TimeUnit; 7 | import java.util.concurrent.atomic.AtomicInteger; 8 | 9 | import org.junit.BeforeClass; 10 | import org.junit.Test; 11 | import org.junit.runner.RunWith; 12 | 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.boot.test.context.SpringBootTest; 15 | import org.springframework.kafka.core.KafkaTemplate; 16 | import org.springframework.kafka.test.EmbeddedKafkaBroker; 17 | import org.springframework.kafka.test.context.EmbeddedKafka; 18 | import org.springframework.test.annotation.DirtiesContext; 19 | import org.springframework.test.context.junit4.SpringRunner; 20 | 21 | @RunWith(SpringRunner.class) 22 | @SpringBootTest 23 | @EmbeddedKafka(topics = So57889424Application.SO57889424_TOPIC, partitions = 32, controlledShutdown = true) 24 | @DirtiesContext 25 | public class So57889424ApplicationTests { 26 | 27 | static { 28 | System.setProperty(EmbeddedKafkaBroker.BROKER_LIST_PROPERTY, "spring.kafka.bootstrap-servers"); 29 | } 30 | 31 | @Autowired 32 | private KafkaTemplate kafkaTemplate; 33 | 34 | @Autowired 35 | private CountDownLatch listenerIdleLatch; 36 | 37 | @Autowired 38 | private AtomicInteger processCount; 39 | 40 | @Test 41 | public void testSo57889424() throws InterruptedException { 42 | for (int i = 0; i < 60; i++) { 43 | this.kafkaTemplate.send(So57889424Application.SO57889424_TOPIC, "test" + i); 44 | } 45 | 46 | this.kafkaTemplate.flush(); 47 | 48 | assertThat(this.listenerIdleLatch.await(60, TimeUnit.SECONDS)).isTrue(); 49 | 50 | assertThat(this.processCount.get()).isEqualTo(60 * 3); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /spring-amqp-observation/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /spring-amqp-observation/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' version '3.1.1' 4 | id 'io.spring.dependency-management' version '1.1.0' 5 | } 6 | 7 | group = 'org.springframework.amqp.sample.tracing' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | java { 11 | sourceCompatibility = '17' 12 | } 13 | 14 | repositories { 15 | mavenCentral() 16 | } 17 | 18 | dependencies { 19 | implementation 'org.springframework.boot:spring-boot-starter-actuator' 20 | implementation 'org.springframework.boot:spring-boot-starter-amqp' 21 | implementation 'org.springframework.boot:spring-boot-starter-web' 22 | implementation 'io.micrometer:micrometer-tracing-bridge-brave' 23 | implementation 'io.zipkin.reporter2:zipkin-reporter-brave' 24 | 25 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 26 | testImplementation 'org.springframework.amqp:spring-rabbit-test' 27 | } 28 | 29 | tasks.named('test') { 30 | useJUnitPlatform() 31 | } -------------------------------------------------------------------------------- /spring-amqp-observation/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/spring-amqp-observation/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /spring-amqp-observation/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip 4 | networkTimeout=10000 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /spring-amqp-observation/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /spring-amqp-observation/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'spring-amqp-observation' 2 | -------------------------------------------------------------------------------- /spring-amqp-observation/src/main/java/org/springframework/amqp/sample/tracing/SpringAmqpObservationApplication.java: -------------------------------------------------------------------------------- 1 | package org.springframework.amqp.sample.tracing; 2 | 3 | import io.micrometer.observation.Observation; 4 | import io.micrometer.observation.ObservationRegistry; 5 | import org.apache.commons.logging.Log; 6 | import org.apache.commons.logging.LogFactory; 7 | 8 | import org.springframework.amqp.rabbit.annotation.RabbitListener; 9 | import org.springframework.amqp.rabbit.config.ContainerCustomizer; 10 | import org.springframework.amqp.rabbit.core.RabbitTemplate; 11 | import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; 12 | import org.springframework.boot.ApplicationRunner; 13 | import org.springframework.boot.SpringApplication; 14 | import org.springframework.boot.autoconfigure.SpringBootApplication; 15 | import org.springframework.boot.autoconfigure.amqp.RabbitTemplateCustomizer; 16 | import org.springframework.context.annotation.Bean; 17 | 18 | @SpringBootApplication 19 | public class SpringAmqpObservationApplication { 20 | 21 | private static final Log LOGGER = LogFactory.getLog(SpringAmqpObservationApplication.class); 22 | 23 | public static void main(String[] args) { 24 | SpringApplication.run(SpringAmqpObservationApplication.class, args); 25 | } 26 | 27 | @Bean 28 | ContainerCustomizer simpleMessageListenerContainerContainerCustomizer() { 29 | return simpleMessageListenerContainer -> simpleMessageListenerContainer.setObservationEnabled(true); 30 | } 31 | 32 | @Bean 33 | RabbitTemplateCustomizer rabbitTemplateCustomizer() { 34 | return rabbitTemplate -> rabbitTemplate.setObservationEnabled(true); 35 | } 36 | 37 | @Bean 38 | ApplicationRunner applicationRunner(RabbitTemplate rabbitTemplate, ObservationRegistry observationRegistry) { 39 | return args -> 40 | Observation 41 | .createNotStarted("amqp-test-observation", observationRegistry) 42 | .lowCardinalityKeyValue("service.name", SpringAmqpObservationApplication.class.getName()) 43 | .observe(() -> { 44 | String data = "test data"; 45 | LOGGER.warn("Produced data: " + data); 46 | rabbitTemplate.convertAndSend("testQueue", data); 47 | }); 48 | } 49 | 50 | @RabbitListener(queues = "testQueue") 51 | void handleAmqp(String data) { 52 | LOGGER.warn("Received data: " + data); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /spring-amqp-observation/src/test/java/org/springframework/amqp/sample/tracing/SpringAmqpObservationApplicationTests.java: -------------------------------------------------------------------------------- 1 | package org.springframework.amqp.sample.tracing; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | 7 | @SpringBootTest 8 | class SpringAmqpObservationApplicationTests { 9 | 10 | @Test 11 | void contextLoads() { 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /spring-boot-reactor-kafka-tracing/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 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 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /spring-boot-reactor-kafka-tracing/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/spring-boot-reactor-kafka-tracing/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /spring-boot-reactor-kafka-tracing/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.5/apache-maven-3.9.5-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar 3 | -------------------------------------------------------------------------------- /spring-boot-reactor-kafka-tracing/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.1.5 9 | 10 | 11 | com.example 12 | spring-boot-reactor-kafka-tracing 13 | 0.0.1-SNAPSHOT 14 | spring-boot-reactor-kafka-tracing 15 | spring-boot-reactor-kafka-tracing 16 | 17 | 17 18 | 19 | 20 | 21 | io.projectreactor.kafka 22 | reactor-kafka 23 | 1.3.22-SNAPSHOT 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-actuator 28 | 29 | 30 | io.micrometer 31 | micrometer-tracing-bridge-brave 32 | 33 | 34 | io.zipkin.reporter2 35 | zipkin-reporter-brave 36 | 37 | 38 | org.springframework 39 | spring-web 40 | 41 | 42 | org.springframework.kafka 43 | spring-kafka 44 | 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-test 49 | test 50 | 51 | 52 | org.springframework.kafka 53 | spring-kafka-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 | 74 | spring-snapshots 75 | Spring Snapshots 76 | https://repo.spring.io/snapshot 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /spring-boot-reactor-kafka-tracing/src/main/java/com/example/springbootreactorkafkatracing/SpringBootReactorKafkaTracingApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.springbootreactorkafkatracing; 2 | 3 | import java.util.Collections; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | import io.micrometer.observation.ObservationRegistry; 8 | import org.apache.kafka.clients.consumer.ConsumerConfig; 9 | import org.apache.kafka.clients.producer.ProducerConfig; 10 | import reactor.kafka.receiver.KafkaReceiver; 11 | import reactor.kafka.receiver.ReceiverOptions; 12 | import reactor.kafka.sender.KafkaSender; 13 | import reactor.kafka.sender.SenderOptions; 14 | 15 | import org.springframework.boot.SpringApplication; 16 | import org.springframework.boot.autoconfigure.SpringBootApplication; 17 | import org.springframework.boot.autoconfigure.kafka.KafkaProperties; 18 | import org.springframework.context.annotation.Bean; 19 | import org.springframework.util.StringUtils; 20 | 21 | @SpringBootApplication 22 | public class SpringBootReactorKafkaTracingApplication { 23 | 24 | public static final String MY_TOPIC = "test-topic"; 25 | 26 | public static void main(String[] args) { 27 | SpringApplication.run(SpringBootReactorKafkaTracingApplication.class, args); 28 | } 29 | 30 | @Bean 31 | KafkaSender kafkaSender(KafkaProperties kafkaProperties, ObservationRegistry observationRegistry) { 32 | Map producerProperties = kafkaProperties.buildProducerProperties(); 33 | producerProperties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, 34 | StringUtils.collectionToCommaDelimitedString(kafkaProperties.getBootstrapServers())); 35 | SenderOptions senderOptions = SenderOptions.create(producerProperties); 36 | return KafkaSender.create(senderOptions.withObservation(observationRegistry)); 37 | } 38 | 39 | @Bean 40 | KafkaReceiver kafkaReceiver(KafkaProperties kafkaProperties) { 41 | Map consumerProperties = kafkaProperties.buildConsumerProperties(); 42 | consumerProperties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, 43 | StringUtils.collectionToCommaDelimitedString(kafkaProperties.getBootstrapServers())); 44 | ReceiverOptions receiverOptions = ReceiverOptions.create(consumerProperties); 45 | return KafkaReceiver.create(receiverOptions.subscription(List.of(MY_TOPIC))); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /spring-boot-reactor-kafka-tracing/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=reactor-kafka-tracing 2 | management.tracing.sampling.probability=1 3 | logging.pattern.level=%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}] 4 | spring.kafka.consumer.auto-offset-reset=earliest 5 | spring.kafka.consumer.group-id=reactor-kafka-group 6 | logging.level.root=warn -------------------------------------------------------------------------------- /spring-cloud-stream-rabbit-dlq/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /spring-cloud-stream-rabbit-dlq/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' version '3.2.5' 4 | id 'io.spring.dependency-management' version '1.1.4' 5 | } 6 | 7 | group = 'org.springframework.cloud.stream' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | java { 11 | sourceCompatibility = '17' 12 | } 13 | 14 | repositories { 15 | mavenLocal() 16 | mavenCentral() 17 | maven { url 'https://repo.spring.io/snapshot' } 18 | } 19 | 20 | ext { 21 | set('springCloudVersion', "2024.0.0-SNAPSHOT") 22 | } 23 | 24 | dependencies { 25 | implementation 'org.springframework.boot:spring-boot-starter-amqp' 26 | implementation 'org.springframework.cloud:spring-cloud-stream' 27 | implementation 'org.springframework.amqp:spring-amqp:3.2.0-SNAPSHOT' 28 | implementation 'org.springframework.amqp:spring-rabbit:3.2.0-SNAPSHOT' 29 | implementation 'org.springframework.integration:spring-integration-amqp:6.4.0-SNAPSHOT' 30 | implementation 'org.springframework.cloud:spring-cloud-stream-binder-rabbit' 31 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 32 | testImplementation 'org.springframework.boot:spring-boot-testcontainers' 33 | testImplementation 'org.springframework.amqp:spring-rabbit-test' 34 | testImplementation 'org.testcontainers:junit-jupiter' 35 | testImplementation 'org.testcontainers:rabbitmq' 36 | } 37 | 38 | dependencyManagement { 39 | imports { 40 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" 41 | } 42 | } 43 | 44 | tasks.named('test') { 45 | useJUnitPlatform() 46 | } 47 | -------------------------------------------------------------------------------- /spring-cloud-stream-rabbit-dlq/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/spring-cloud-stream-rabbit-dlq/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /spring-cloud-stream-rabbit-dlq/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /spring-cloud-stream-rabbit-dlq/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 1>&2 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 48 | echo. 1>&2 49 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 50 | echo location of your Java installation. 1>&2 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 1>&2 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 62 | echo. 1>&2 63 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 64 | echo location of your Java installation. 1>&2 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /spring-cloud-stream-rabbit-dlq/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'spring-cloud-stream-rabbit-dlq' 2 | -------------------------------------------------------------------------------- /spring-cloud-stream-rabbit-dlq/src/test/java/org/springframework/cloud/stream/rabbitdlq/SpringCloudStreamRabbitDlqApplicationTests.java: -------------------------------------------------------------------------------- 1 | package org.springframework.cloud.stream.rabbitdlq; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import java.util.concurrent.CountDownLatch; 6 | import java.util.concurrent.TimeUnit; 7 | import java.util.function.Consumer; 8 | 9 | import org.junit.jupiter.api.Test; 10 | import org.testcontainers.containers.RabbitMQContainer; 11 | import org.testcontainers.utility.DockerImageName; 12 | 13 | import org.springframework.amqp.AmqpRejectAndDontRequeueException; 14 | import org.springframework.amqp.ImmediateAcknowledgeAmqpException; 15 | import org.springframework.amqp.rabbit.core.RabbitTemplate; 16 | import org.springframework.amqp.support.AmqpHeaders; 17 | import org.springframework.beans.factory.annotation.Autowired; 18 | import org.springframework.boot.autoconfigure.SpringBootApplication; 19 | import org.springframework.boot.test.context.SpringBootTest; 20 | import org.springframework.boot.testcontainers.service.connection.ServiceConnection; 21 | import org.springframework.context.annotation.Bean; 22 | import org.springframework.messaging.Message; 23 | 24 | import static org.assertj.core.api.Assertions.assertThat; 25 | 26 | @SpringBootTest 27 | class SpringCloudStreamRabbitDlqApplicationTests { 28 | 29 | @Test 30 | void contextLoads(@Autowired RabbitTemplate rabbitTemplate, @Autowired CountDownLatch dlqRetryExhausted) 31 | throws InterruptedException { 32 | 33 | rabbitTemplate.convertAndSend("myDestination.consumerGroup", "test data"); 34 | 35 | assertThat(dlqRetryExhausted.await(10, TimeUnit.SECONDS)).isTrue(); 36 | } 37 | 38 | @SpringBootApplication 39 | public static class TestSpringCloudStreamRabbitDlqApplication { 40 | 41 | @Bean 42 | @ServiceConnection 43 | RabbitMQContainer rabbitContainer() { 44 | return new RabbitMQContainer(DockerImageName.parse("rabbitmq:4")); 45 | } 46 | 47 | @Bean 48 | CountDownLatch dlqRetryExhausted() { 49 | return new CountDownLatch(1); 50 | } 51 | 52 | @Bean 53 | public Consumer> listener(CountDownLatch dlqRetryExhausted) { 54 | return message -> { 55 | Long retryCount = message.getHeaders().get(AmqpHeaders.RETRY_COUNT, Long.class); 56 | if (retryCount != null && retryCount.equals(3L)) { 57 | dlqRetryExhausted.countDown(); 58 | // giving up - don't send to DLX 59 | throw new ImmediateAcknowledgeAmqpException("Failed after 4 attempts"); 60 | } 61 | throw new AmqpRejectAndDontRequeueException("failed"); 62 | }; 63 | } 64 | 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /spring-cloud-stream-rabbit-dlq/src/test/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=spring-cloud-stream-rabbit-dlq 2 | 3 | spring.cloud.stream.function.bindings.listener-in-0=input 4 | spring.cloud.stream.bindings.input.destination=myDestination 5 | spring.cloud.stream.bindings.input.group=consumerGroup 6 | #disable binder retries 7 | spring.cloud.stream.bindings.input.consumer.max-attempts=1 8 | #dlx/dlq setup 9 | spring.cloud.stream.rabbit.bindings.input.consumer.auto-bind-dlq=true 10 | spring.cloud.stream.rabbit.bindings.input.consumer.dlq-ttl=1000 11 | spring.cloud.stream.rabbit.bindings.input.consumer.dlq-dead-letter-exchange= 12 | #spring.cloud.stream.rabbit.bindings.input.consumer.republish-to-dlq=false -------------------------------------------------------------------------------- /spring-integration-enricher/.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 | -------------------------------------------------------------------------------- /spring-integration-enricher/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/spring-integration-enricher/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /spring-integration-enricher/.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 | -------------------------------------------------------------------------------- /spring-integration-enricher/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.0.RC1 9 | 10 | 11 | org.springframework.integration.stackoverflow 12 | spring-integration-enricher 13 | 0.0.1-SNAPSHOT 14 | spring-integration-enricher 15 | Demo project for SO58205432 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-integration 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-json 29 | 30 | 31 | org.springframework.integration 32 | spring-integration-http 33 | 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-starter-test 38 | test 39 | 40 | 41 | org.junit.vintage 42 | junit-vintage-engine 43 | 44 | 45 | 46 | 47 | org.springframework.integration 48 | spring-integration-test 49 | test 50 | 51 | 52 | 53 | 54 | 55 | 56 | org.springframework.boot 57 | spring-boot-maven-plugin 58 | 59 | 60 | 61 | 62 | 63 | 64 | spring-milestones 65 | Spring Milestones 66 | https://repo.spring.io/milestone 67 | 68 | 69 | 70 | 71 | spring-milestones 72 | Spring Milestones 73 | https://repo.spring.io/milestone 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /spring-integration-enricher/src/main/java/org/springframework/integration/stackoverflow/enricher/SpringIntegrationEnricherApplication.java: -------------------------------------------------------------------------------- 1 | package org.springframework.integration.stackoverflow.enricher; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import java.util.function.Function; 6 | import java.util.stream.Collectors; 7 | 8 | import org.springframework.boot.SpringApplication; 9 | import org.springframework.boot.autoconfigure.SpringBootApplication; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.http.HttpMethod; 12 | import org.springframework.integration.dsl.IntegrationFlow; 13 | import org.springframework.integration.dsl.IntegrationFlows; 14 | import org.springframework.integration.dsl.Transformers; 15 | import org.springframework.integration.http.dsl.Http; 16 | import org.springframework.web.client.RestTemplate; 17 | 18 | @SpringBootApplication 19 | public class SpringIntegrationEnricherApplication { 20 | 21 | public static void main(String[] args) { 22 | SpringApplication.run(SpringIntegrationEnricherApplication.class, args); 23 | } 24 | 25 | @Bean 26 | public IntegrationFlow jsonEnricherFlow(RestTemplate restTemplate) { 27 | return IntegrationFlows.from(Function.class) 28 | .transform(Transformers.fromJson(Map.class)) 29 | .enrich((enricher) -> enricher 30 | .>requestPayload((message) -> 31 | ((List) message.getPayload().get("attributeIds")) 32 | .stream() 33 | .map(Object::toString) 34 | .collect(Collectors.joining(","))) 35 | .requestSubFlow((subFlow) -> 36 | subFlow.handle( 37 | Http.outboundGateway("/attributes?id={ids}", restTemplate) 38 | .httpMethod(HttpMethod.GET) 39 | .expectedResponseType(Map.class) 40 | .uriVariable("ids", "payload"))) 41 | .propertyExpression("attributes", "payload.attributes")) 42 | ., Map>transform( 43 | (payload) -> { 44 | payload.remove("attributeIds"); 45 | return payload; 46 | }) 47 | .transform(Transformers.toJson()) 48 | .get(); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /spring-integration-enricher/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /spring-integration-enricher/src/test/java/org/springframework/integration/stackoverflow/enricher/SpringIntegrationEnricherApplicationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.integration.stackoverflow.enricher; 18 | 19 | import static org.assertj.core.api.Assertions.assertThat; 20 | import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; 21 | import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; 22 | import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; 23 | 24 | import java.util.function.Function; 25 | 26 | import org.junit.jupiter.api.Test; 27 | 28 | import org.springframework.beans.factory.annotation.Autowired; 29 | import org.springframework.boot.test.autoconfigure.web.client.AutoConfigureMockRestServiceServer; 30 | import org.springframework.boot.test.autoconfigure.web.client.AutoConfigureWebClient; 31 | import org.springframework.boot.test.context.SpringBootTest; 32 | import org.springframework.http.HttpMethod; 33 | import org.springframework.http.MediaType; 34 | import org.springframework.test.web.client.MockRestServiceServer; 35 | 36 | /** 37 | * @author Artem Bilan 38 | */ 39 | @SpringBootTest 40 | @AutoConfigureMockRestServiceServer 41 | @AutoConfigureWebClient(registerRestTemplate = true) 42 | class SpringIntegrationEnricherApplicationTests { 43 | 44 | @Autowired 45 | private MockRestServiceServer mockRestServiceServer; 46 | 47 | @Autowired 48 | private Function enricherGateway; 49 | 50 | @Test 51 | void testJsonEnrichWithHttp() { 52 | String request = 53 | "{" + 54 | "\"name\":\"House\"," + 55 | "\"attributeIds\": [1,3,5]" + 56 | "}"; 57 | 58 | String reply = 59 | "{\"attributes\": [" + 60 | "{\"id\": 1, \"value\":\"Waterproof\"}," + 61 | "{\"id\": 3, \"value\":\"SoundProof\"}," + 62 | "{\"id\": 5, \"value\":\"Concrete\"}" + 63 | "]}"; 64 | 65 | this.mockRestServiceServer.expect(requestTo("/attributes?id=1,3,5")).andExpect(method(HttpMethod.GET)) 66 | .andRespond(withSuccess(reply, MediaType.APPLICATION_JSON)); 67 | 68 | String resultJson = this.enricherGateway.apply(request); 69 | this.mockRestServiceServer.verify(); 70 | 71 | assertThat(resultJson).isEqualTo( 72 | "{" + 73 | "\"name\":\"House\"," + 74 | "\"attributes\":[" + 75 | "{\"id\":1,\"value\":\"Waterproof\"}," + 76 | "{\"id\":3,\"value\":\"SoundProof\"}," + 77 | "{\"id\":5,\"value\":\"Concrete\"}" + 78 | "]}" 79 | ); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /spring-integration-mqtt-share-demo/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /spring-integration-mqtt-share-demo/README.adoc: -------------------------------------------------------------------------------- 1 | == Spring Integration with MQTT Shared Subscriptions 2 | 3 | This sample demonstrates a simple functionality for shared subscription in MQTT protocol. 4 | The `Mqttv5PahoMessageDrivenChannelAdapter` subscribes to the `$share/group1/test`, and `Mqttv5PahoMessageHandler` produces to the `test` topic. 5 | The `SpringIntegrationMqttShareDemoApplicationTests` is based on the Testcontainers for the `eclipse-mosquitto` docker image. 6 | The `MockIntegrationContext` makes use of Integration mocks to verify the application logic. 7 | 8 | NOTE: The publisher and subscriber must use different client ids. 9 | The shared one, based on the `Mqttv5ClientManager`, for example, does not make it through consumption from the shared subscription. 10 | 11 | 12 | -------------------------------------------------------------------------------- /spring-integration-mqtt-share-demo/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' version '3.3.0' 4 | id 'io.spring.dependency-management' version '1.1.5' 5 | } 6 | 7 | group = 'org.springframework.integration.demo' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | java { 11 | toolchain { 12 | languageVersion = JavaLanguageVersion.of(17) 13 | } 14 | } 15 | 16 | repositories { 17 | mavenCentral() 18 | maven { url 'https://repo.spring.io/snapshot' } 19 | } 20 | 21 | ext { 22 | set('spring-integration.version', '6.3.1-SNAPSHOT') 23 | } 24 | 25 | dependencies { 26 | implementation 'org.springframework.boot:spring-boot-starter-integration' 27 | implementation 'org.springframework.integration:spring-integration-mqtt' 28 | implementation 'org.eclipse.paho:org.eclipse.paho.mqttv5.client:1.2.5' 29 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 30 | testImplementation 'org.springframework.integration:spring-integration-test' 31 | testImplementation 'org.testcontainers:junit-jupiter' 32 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 33 | } 34 | 35 | tasks.named('test') { 36 | useJUnitPlatform() 37 | } 38 | -------------------------------------------------------------------------------- /spring-integration-mqtt-share-demo/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/spring-integration-mqtt-share-demo/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /spring-integration-mqtt-share-demo/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /spring-integration-mqtt-share-demo/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 1>&2 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 48 | echo. 1>&2 49 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 50 | echo location of your Java installation. 1>&2 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 1>&2 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 62 | echo. 1>&2 63 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 64 | echo location of your Java installation. 1>&2 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /spring-integration-mqtt-share-demo/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'spring-integration-mqtt-share-demo' 2 | -------------------------------------------------------------------------------- /spring-integration-mqtt-share-demo/src/main/java/org/springframework/cloud/stream/springintegrationmqttsharedemo/SpringIntegrationMqttShareDemoApplication.java: -------------------------------------------------------------------------------- 1 | package org.springframework.cloud.stream.springintegrationmqttsharedemo; 2 | 3 | import org.eclipse.paho.mqttv5.client.IMqttAsyncClient; 4 | import org.eclipse.paho.mqttv5.client.MqttConnectionOptions; 5 | 6 | import org.springframework.beans.factory.annotation.Value; 7 | import org.springframework.boot.SpringApplication; 8 | import org.springframework.boot.autoconfigure.SpringBootApplication; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.integration.dsl.IntegrationFlow; 11 | import org.springframework.integration.mqtt.core.ClientManager; 12 | import org.springframework.integration.mqtt.core.Mqttv5ClientManager; 13 | import org.springframework.integration.mqtt.inbound.Mqttv5PahoMessageDrivenChannelAdapter; 14 | import org.springframework.messaging.converter.ByteArrayMessageConverter; 15 | import org.springframework.messaging.converter.StringMessageConverter; 16 | import org.springframework.validation.annotation.Validated; 17 | 18 | @SpringBootApplication 19 | public class SpringIntegrationMqttShareDemoApplication { 20 | 21 | public static void main(String[] args) { 22 | SpringApplication.run(SpringIntegrationMqttShareDemoApplication.class, args); 23 | } 24 | 25 | @Bean 26 | Mqttv5ClientManager mqttv5ClientManager(@Value("${mqtt.url}") String mqttUrl) { 27 | return new Mqttv5ClientManager(mqttUrl, "subscriber-for-shared-subscription"); 28 | } 29 | 30 | @Bean 31 | public IntegrationFlow mqttInFlow(Mqttv5ClientManager mqttv5ClientManager, @Value("${mqtt.url}") String mqttUrl) { 32 | return IntegrationFlow.from( 33 | new Mqttv5PahoMessageDrivenChannelAdapter( 34 | mqttv5ClientManager, "$share/group1/test")) 35 | .transform(String::new) 36 | .handle(m -> System.out.println("Received message: " + m.getPayload()), e -> e.id("dataHandler")) 37 | .get(); 38 | 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /spring-integration-mqtt-share-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=spring-integration-mqtt-share-demo 2 | logging.level.org.eclipse.paho.mqttv5.client=trace 3 | logging.level.root=warn 4 | -------------------------------------------------------------------------------- /spring-integration-performance/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 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 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /spring-integration-performance/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/spring-integration-performance/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /spring-integration-performance/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.2/apache-maven-3.8.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /spring-integration-performance/README.md: -------------------------------------------------------------------------------- 1 | # Spring Integration gateway parsing performance sample 2 | 3 | This simple Spring Boot application contains only Spring Integration dependency and provides only simple a `@MessagingGateway` interface to parse and expose as a bean. 4 | 5 | The goal of the sample to measure the mentioned parsing performance via currently provided `instanceSupplier` approach. 6 | It starts an `ApplicationContext` 100 times and shows a result of the `StopWatch` around. 7 | 8 | To compare with suggested gateway parser changes (back) to the reflection style instead of `instanceSupplier`, you need pull this [Spring Integration branch](https://github.com/spring-projects/spring-integration/tree/gateway_reflection) locally and perform `./gradlew publishToMavenLocal -x test` in Spring Integration project. 9 | Then on this sample side, in its `pom.xml`, uncomment the `spring-integration.version` property. 10 | Refresh project in the IDE to take fresh dependecies and run the sample again to see a difference in the SDOUT. 11 | You can also run it via Maven: `./mvn spring-boot:run`. 12 | 13 | On my machine it shows a performance degradation with reflection style as a half seconds. 14 | -------------------------------------------------------------------------------- /spring-integration-performance/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.5.5 9 | 10 | 11 | org.springframework.integration.performance 12 | spring-integration-performance 13 | 0.0.1-SNAPSHOT 14 | spring-integration-performance 15 | spring-integration-performance 16 | 17 | 11 18 | 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-integration 24 | 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-test 29 | test 30 | 31 | 32 | org.springframework.integration 33 | spring-integration-test 34 | test 35 | 36 | 37 | 38 | 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-maven-plugin 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /spring-integration-performance/src/main/java/org/springframework/integration/performance/SpringIntegrationPerformanceApplication.java: -------------------------------------------------------------------------------- 1 | package org.springframework.integration.performance; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.integration.annotation.MessagingGateway; 6 | import org.springframework.messaging.support.GenericMessage; 7 | import org.springframework.util.StopWatch; 8 | 9 | @SpringBootApplication 10 | public class SpringIntegrationPerformanceApplication { 11 | 12 | public static void main(String[] args) { 13 | StopWatch watch = new StopWatch(); 14 | watch.start(); 15 | for (int i = 0; i < 100; i++) { 16 | System.out.println("Execution #" + i + "..."); 17 | SpringApplication.run(SpringIntegrationPerformanceApplication.class, args).close(); 18 | } 19 | watch.stop(); 20 | System.out.println("PERFORMANCE: " + watch.getTotalTimeSeconds()); 21 | } 22 | 23 | @MessagingGateway(defaultRequestChannel = "testChannel") 24 | interface MyGateway { 25 | 26 | void testIt(Object payload); 27 | 28 | } 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /spring-integration-performance/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | logging.level.org.springframework=warn 2 | spring.main.banner-mode=off 3 | -------------------------------------------------------------------------------- /spring-integration-performance/src/test/java/org/springframework/integration/performance/SpringIntegrationPerformanceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package org.springframework.integration.performance; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | 7 | @SpringBootTest 8 | class SpringIntegrationPerformanceApplicationTests { 9 | 10 | @Test 11 | void contextLoads() { 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /spring-integration-reactor-kafka/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 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 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /spring-integration-reactor-kafka/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/spring-integration-reactor-kafka/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /spring-integration-reactor-kafka/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.3/apache-maven-3.8.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /spring-integration-reactor-kafka/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.6.2 9 | 10 | 11 | com.example 12 | spring-integration-reactor-kafka 13 | 0.0.1-SNAPSHOT 14 | spring-integration-reactor-kafka 15 | spring-integration-reactor-kafka 16 | 17 | 18 | 11 19 | 3.9.1 20 | 5.5.8-SNAPSHOT 21 | 22 | 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-integration 27 | 28 | 29 | org.springframework.kafka 30 | spring-kafka 31 | 32 | 33 | io.projectreactor.kafka 34 | reactor-kafka 35 | 36 | 37 | 38 | org.springframework.boot 39 | spring-boot-starter-test 40 | test 41 | 42 | 43 | 44 | org.springframework.kafka 45 | spring-kafka-test 46 | test 47 | 48 | 49 | org.apache.zookeeper 50 | zookeeper 51 | 52 | 53 | 54 | 55 | 56 | org.apache.kafka 57 | kafka-clients 58 | test 59 | test 60 | ${kafka.version} 61 | 62 | 63 | 64 | org.apache.kafka 65 | kafka_2.13 66 | test 67 | test 68 | ${kafka.version} 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | org.springframework.boot 78 | spring-boot-maven-plugin 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /spring-integration-reactor-kafka/src/main/java/com/example/spring/integration/reactor/kafka/SpringIntegrationReactorKafkaApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.spring.integration.reactor.kafka; 2 | 3 | import java.util.Collections; 4 | 5 | import org.apache.kafka.clients.consumer.ConsumerRecord; 6 | 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.SpringApplication; 9 | import org.springframework.boot.autoconfigure.SpringBootApplication; 10 | import org.springframework.boot.autoconfigure.kafka.KafkaProperties; 11 | import org.springframework.context.annotation.Bean; 12 | import org.springframework.context.annotation.Lazy; 13 | import org.springframework.integration.annotation.ServiceActivator; 14 | import org.springframework.integration.dsl.IntegrationFlow; 15 | import org.springframework.integration.dsl.IntegrationFlows; 16 | import org.springframework.integration.handler.LoggingHandler; 17 | import org.springframework.kafka.core.reactive.ReactiveKafkaConsumerTemplate; 18 | import org.springframework.kafka.core.reactive.ReactiveKafkaProducerTemplate; 19 | import org.springframework.messaging.support.GenericMessage; 20 | 21 | import reactor.core.publisher.Mono; 22 | import reactor.kafka.receiver.ReceiverOptions; 23 | import reactor.kafka.sender.SenderOptions; 24 | 25 | @SpringBootApplication 26 | public class SpringIntegrationReactorKafkaApplication { 27 | 28 | public static void main(String[] args) { 29 | SpringApplication.run(SpringIntegrationReactorKafkaApplication.class, args); 30 | } 31 | 32 | @Bean 33 | ReactiveKafkaProducerTemplate reactiveKafkaProducerTemplate(KafkaProperties kafkaProperties) { 34 | return new ReactiveKafkaProducerTemplate<>(SenderOptions.create(kafkaProperties.buildProducerProperties())); 35 | } 36 | 37 | @Autowired 38 | @Lazy 39 | ReactiveKafkaProducerTemplate reactiveKafkaProducerTemplate; 40 | 41 | @ServiceActivator(inputChannel = "kafkaProducerChannel", outputChannel = "nullChannel") 42 | Mono sendToKafkaReactively(String payload) { 43 | return this.reactiveKafkaProducerTemplate.send("testTopic", payload); 44 | } 45 | 46 | @Bean 47 | ReactiveKafkaConsumerTemplate reactiveKafkaConsumerTemplate(KafkaProperties kafkaProperties) { 48 | return new ReactiveKafkaConsumerTemplate<>( 49 | ReceiverOptions.create(kafkaProperties.buildConsumerProperties()) 50 | .subscription(Collections.singleton("testTopic"))); 51 | } 52 | 53 | @Bean 54 | IntegrationFlow kafkaConsumerFlow(ReactiveKafkaConsumerTemplate reactiveKafkaConsumerTemplate) { 55 | return IntegrationFlows.from(reactiveKafkaConsumerTemplate.receiveAutoAck().map(GenericMessage::new)) 56 | ., String>transform(ConsumerRecord::value) 57 | .log(LoggingHandler.Level.DEBUG, "com.example.spring.integration.reactor.kafka") 58 | .transform(String::toUpperCase) 59 | .channel(c -> c.queue("resultChannel")) 60 | .get(); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /spring-integration-reactor-kafka/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.kafka.consumer.group-id=my-test-group 2 | spring.kafka.consumer.auto-offset-reset=latest 3 | logging.level.root=warn 4 | logging.level.com.example.spring.integration.reactor.kafka=debug -------------------------------------------------------------------------------- /spring-integration-reactor-kafka/src/test/java/com/example/spring/integration/reactor/kafka/SpringIntegrationReactorKafkaApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.spring.integration.reactor.kafka; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import java.util.concurrent.ExecutionException; 6 | 7 | import org.junit.jupiter.api.Test; 8 | 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.boot.test.context.SpringBootTest; 11 | import org.springframework.kafka.core.KafkaTemplate; 12 | import org.springframework.kafka.support.SendResult; 13 | import org.springframework.kafka.test.context.EmbeddedKafka; 14 | import org.springframework.messaging.Message; 15 | import org.springframework.messaging.MessageChannel; 16 | import org.springframework.messaging.PollableChannel; 17 | import org.springframework.messaging.support.GenericMessage; 18 | import org.springframework.test.annotation.DirtiesContext; 19 | import org.springframework.util.concurrent.ListenableFuture; 20 | 21 | @SpringBootTest 22 | @DirtiesContext 23 | @EmbeddedKafka(topics = "testTopic", bootstrapServersProperty = "spring.kafka.bootstrap-servers") 24 | class SpringIntegrationReactorKafkaApplicationTests { 25 | 26 | @Autowired 27 | MessageChannel kafkaProducerChannel; 28 | 29 | @Autowired 30 | PollableChannel resultChannel; 31 | 32 | @Test 33 | void testSendAndReceiveOverReactorKafka() { 34 | for (int i = 0; i < 100; i++) { 35 | this.kafkaProducerChannel.send(new GenericMessage<>("test#" + i)); 36 | } 37 | 38 | for (int i = 0; i < 100; i++) { 39 | assertThat(this.resultChannel.receive(10000)) 40 | .isNotNull() 41 | .extracting(Message::getPayload) 42 | .isEqualTo("TEST#" + i); 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /spring-integration-security-context-propagation/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /spring-integration-security-context-propagation/HELP.md: -------------------------------------------------------------------------------- 1 | # How to propagate security context over Spring Integration channels 2 | 3 | This sample demonstrate a simple method security which is called from a scheduled thread via Spring Integration `PollingConsumer` with a message polled from `QueueChannel`. 4 | Before the message is sent we authorise principal. 5 | The `SecurityContextPropagationChannelInterceptor` added to the `myChannel` bean, propagates an `Authentication` from the current `SecurityContext` in the `preSend()` method via message header. 6 | When this channel is consumed in the scheduled thread, that header is extracted and set into `SecurityContext` of that thread. 7 | Without this interceptor the application fails with an `AuthenticationCredentialsNotFoundException`. 8 | 9 | -------------------------------------------------------------------------------- /spring-integration-security-context-propagation/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' version '3.1.3' 4 | id 'io.spring.dependency-management' version '1.1.3' 5 | } 6 | 7 | group = 'org.springframework.integration.security.sample' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | java { 11 | sourceCompatibility = '17' 12 | } 13 | 14 | repositories { 15 | mavenLocal() 16 | mavenCentral() 17 | } 18 | 19 | ext['spring-security.version'] = '6.2.0-SNAPSHOT' 20 | 21 | dependencies { 22 | implementation 'org.springframework.boot:spring-boot-starter-integration' 23 | implementation 'org.springframework.boot:spring-boot-starter-security' 24 | implementation 'org.springframework.security:spring-security-messaging' 25 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 26 | testImplementation 'org.springframework.integration:spring-integration-test' 27 | testImplementation 'org.springframework.security:spring-security-test' 28 | } 29 | 30 | tasks.named('test') { 31 | useJUnitPlatform() 32 | } 33 | -------------------------------------------------------------------------------- /spring-integration-security-context-propagation/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/spring-integration-security-context-propagation/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /spring-integration-security-context-propagation/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /spring-integration-security-context-propagation/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /spring-integration-security-context-propagation/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'spring-integration-security-context-propagation' 2 | -------------------------------------------------------------------------------- /spring-integration-security-context-propagation/src/main/java/org/springframework/integration/security/sample/springintegrationsecuritycontextpropagation/SpringIntegrationSecurityContextPropagationApplication.java: -------------------------------------------------------------------------------- 1 | package org.springframework.integration.security.sample.springintegrationsecuritycontextpropagation; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.context.ConfigurableApplicationContext; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.integration.annotation.MessagingGateway; 8 | import org.springframework.integration.annotation.ServiceActivator; 9 | import org.springframework.integration.channel.QueueChannel; 10 | import org.springframework.integration.dsl.MessageChannels; 11 | import org.springframework.security.access.prepost.PreAuthorize; 12 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 13 | import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; 14 | import org.springframework.security.core.Authentication; 15 | import org.springframework.security.core.context.SecurityContextHolder; 16 | import org.springframework.security.messaging.context.SecurityContextPropagationChannelInterceptor; 17 | 18 | @SpringBootApplication 19 | @EnableMethodSecurity 20 | public class SpringIntegrationSecurityContextPropagationApplication { 21 | 22 | public static void main(String[] args) { 23 | try (ConfigurableApplicationContext applicationContext = 24 | SpringApplication.run(SpringIntegrationSecurityContextPropagationApplication.class, args)) { 25 | 26 | MyGateway myGateway = applicationContext.getBean(MyGateway.class); 27 | 28 | Authentication authentication = 29 | UsernamePasswordAuthenticationToken.authenticated("user", "password", null); 30 | 31 | SecurityContextHolder.getContext().setAuthentication(authentication); 32 | 33 | String securedData = myGateway.callSecuredService("secured data"); 34 | 35 | System.out.println(securedData); 36 | } 37 | } 38 | 39 | @Bean 40 | QueueChannel myChannel() { 41 | return MessageChannels.queue() 42 | // .interceptor(new SecurityContextPropagationChannelInterceptor()) 43 | .getObject(); 44 | } 45 | 46 | @ServiceActivator(inputChannel = "myChannel") 47 | @PreAuthorize("isAuthenticated()") 48 | String securedService(String payload) { 49 | return "Handled '%s' by principal '%s' in thread '%s'" 50 | .formatted(payload, 51 | SecurityContextHolder.getContext().getAuthentication(), 52 | Thread.currentThread().getName()); 53 | } 54 | 55 | @MessagingGateway(defaultRequestChannel = "myChannel") 56 | interface MyGateway { 57 | 58 | String callSecuredService(String payload); 59 | 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /spring-integration-security-context-propagation/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.security.user.password=password 2 | -------------------------------------------------------------------------------- /spring-integration-security-context-propagation/src/test/java/org/springframework/integration/security/sample/springintegrationsecuritycontextpropagation/SpringIntegrationSecurityContextPropagationApplicationTests.java: -------------------------------------------------------------------------------- 1 | package org.springframework.integration.security.sample.springintegrationsecuritycontextpropagation; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class SpringIntegrationSecurityContextPropagationApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /spring-integration-websocket-reactive/.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/ -------------------------------------------------------------------------------- /spring-integration-websocket-reactive/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/spring-integration-websocket-reactive/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /spring-integration-websocket-reactive/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.4/apache-maven-3.5.4-bin.zip 2 | -------------------------------------------------------------------------------- /spring-integration-websocket-reactive/README.adoc: -------------------------------------------------------------------------------- 1 | == WebFlux Reactive WebSockets via Spring Integration 2 | 3 | This sample demonstrate a simple Reactive WebSocket messages processing using `IntegrationFlow` and Spring Integration Reactive support. 4 | The test-case shows how to test WebSockets interaction in Spring Boot applications. 5 | -------------------------------------------------------------------------------- /spring-integration-websocket-reactive/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.integration.socket.stackoverflow 7 | spring-integration-websocket-reactive 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | spring-integration-websocket-reactive 12 | Demo project for Spring Integration with Spring WebFlux WebSockets 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.0.5.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-integration 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-webflux 35 | 36 | 37 | 38 | org.springframework.boot 39 | spring-boot-starter-test 40 | test 41 | 42 | 43 | io.projectreactor 44 | reactor-test 45 | test 46 | 47 | 48 | 49 | 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-maven-plugin 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /spring-integration-websocket-reactive/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/spring-integration-websocket-reactive/src/main/resources/application.properties -------------------------------------------------------------------------------- /spring-integration-websocket-reactive/src/test/java/org/springframework/integration/socket/stackoverflow/springintegrationwebsocketreactive/SpringIntegrationWebsocketReactiveApplicationTests.java: -------------------------------------------------------------------------------- 1 | package org.springframework.integration.socket.stackoverflow.springintegrationwebsocketreactive; 2 | 3 | import java.net.URI; 4 | import java.net.URISyntaxException; 5 | import java.time.Duration; 6 | import java.util.List; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | import org.reactivestreams.Subscriber; 11 | 12 | import org.springframework.boot.test.context.SpringBootTest; 13 | import org.springframework.boot.web.server.LocalServerPort; 14 | import org.springframework.test.context.junit4.SpringRunner; 15 | import org.springframework.web.reactive.socket.WebSocketMessage; 16 | import org.springframework.web.reactive.socket.client.ReactorNettyWebSocketClient; 17 | import org.springframework.web.reactive.socket.client.WebSocketClient; 18 | 19 | import reactor.core.publisher.Flux; 20 | import reactor.core.publisher.ReplayProcessor; 21 | import reactor.test.StepVerifier; 22 | 23 | @RunWith(SpringRunner.class) 24 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 25 | public class SpringIntegrationWebsocketReactiveApplicationTests { 26 | 27 | @LocalServerPort 28 | private int port; 29 | 30 | @Test 31 | public void testReactiveWebsocketsWithIntegration() throws URISyntaxException { 32 | WebSocketClient client = new ReactorNettyWebSocketClient(); 33 | 34 | URI url = new URI("ws://localhost:" + this.port + "/integration"); 35 | 36 | Flux input = Flux.just("foo", "bar", "baz"); 37 | 38 | ReplayProcessor output = ReplayProcessor.create(); 39 | 40 | client.execute(url, 41 | session -> session 42 | .send(input.map(session::textMessage)) 43 | .thenMany(session.receive().take(3).map(WebSocketMessage::getPayloadAsText)) 44 | .subscribeWith(output) 45 | .then()) 46 | .block(Duration.ofMillis(10_000)); 47 | 48 | StepVerifier.create(output) 49 | .expectNext("FOO", "BAR", "BAZ") 50 | .verifyComplete(); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /spring-integration-with-hystrix/.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/ -------------------------------------------------------------------------------- /spring-integration-with-hystrix/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/spring-integration-with-hystrix/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /spring-integration-with-hystrix/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip 2 | -------------------------------------------------------------------------------- /spring-integration-with-hystrix/README.adoc: -------------------------------------------------------------------------------- 1 | == Hystrix Command with Service Activator 2 | 3 | This sample demonstrate how we can apply a Spring Cloud `@HystrixCommand` on the Spring Integration `@ServiceActivator`. 4 | 5 | NOTE: Since Netflix Hystrix proxying is based on the AspectJ, we can't apply `@HystrixCommand` on the `@MessagingGateway` interfaces. 6 | The JDK Proxy is not compatible with AspectJ and method annotations are not visible for the `AspectJAwareAdvisorAutoProxyCreator`. 7 | 8 | -------------------------------------------------------------------------------- /spring-integration-with-hystrix/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.integration.hystrix 7 | spring-integration-with-hystrix 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | spring-integration-with-hystrix 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 1.5.12.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | Edgware.SR3 26 | 27 | 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-integration 32 | 33 | 34 | org.springframework.cloud 35 | spring-cloud-starter-hystrix 36 | 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-test 41 | test 42 | 43 | 44 | 45 | 46 | 47 | 48 | org.springframework.cloud 49 | spring-cloud-dependencies 50 | ${spring-cloud.version} 51 | pom 52 | import 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | org.springframework.boot 61 | spring-boot-maven-plugin 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /spring-integration-with-hystrix/src/main/java/org/springframework/integration/hystrix/SpringIntegrationWithHystrixApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.integration.hystrix; 18 | 19 | import org.springframework.boot.SpringApplication; 20 | import org.springframework.cloud.client.SpringCloudApplication; 21 | import org.springframework.integration.annotation.ServiceActivator; 22 | 23 | import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; 24 | 25 | @SpringCloudApplication 26 | public class SpringIntegrationWithHystrixApplication { 27 | 28 | public static void main(String[] args) { 29 | SpringApplication.run(SpringIntegrationWithHystrixApplication.class, args); 30 | } 31 | 32 | @ServiceActivator(inputChannel = "serviceChannel") 33 | @HystrixCommand(fallbackMethod = "serviceFallback") 34 | public String myService(String payload) { 35 | throw new IllegalStateException("Service not available"); 36 | } 37 | 38 | public String serviceFallback(String payload) { 39 | return payload.toUpperCase(); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /spring-integration-with-hystrix/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /spring-integration-with-hystrix/src/test/java/org/springframework/integration/hystrix/SpringIntegrationWithHystrixApplicationTests.java: -------------------------------------------------------------------------------- 1 | package org.springframework.integration.hystrix; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.test.context.SpringBootTest; 10 | import org.springframework.integration.core.MessagingTemplate; 11 | import org.springframework.messaging.MessageChannel; 12 | import org.springframework.test.context.junit4.SpringRunner; 13 | 14 | @RunWith(SpringRunner.class) 15 | @SpringBootTest 16 | public class SpringIntegrationWithHystrixApplicationTests { 17 | 18 | @Autowired 19 | private MessageChannel serviceChannel; 20 | 21 | @Test 22 | public void testHystrixCommandWithSpringIntegration() { 23 | MessagingTemplate messagingTemplate = new MessagingTemplate(this.serviceChannel); 24 | assertThat(messagingTemplate.convertSendAndReceive("foo", String.class)).isEqualTo("FOO"); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /spring-kafka-retry-demo/.gitattributes: -------------------------------------------------------------------------------- 1 | /gradlew text eol=lf 2 | *.bat text eol=crlf 3 | *.jar binary 4 | -------------------------------------------------------------------------------- /spring-kafka-retry-demo/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /spring-kafka-retry-demo/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' version '3.4.2' 4 | id 'io.spring.dependency-management' version '1.1.7' 5 | } 6 | 7 | group = 'org.springframework.kafka.example' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | java { 11 | toolchain { 12 | languageVersion = JavaLanguageVersion.of(17) 13 | } 14 | } 15 | 16 | repositories { 17 | mavenCentral() 18 | } 19 | 20 | dependencies { 21 | implementation 'org.springframework.boot:spring-boot-starter' 22 | implementation 'org.springframework.kafka:spring-kafka' 23 | 24 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 25 | testImplementation 'org.springframework.kafka:spring-kafka-test' 26 | 27 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 28 | } 29 | 30 | tasks.named('test') { 31 | useJUnitPlatform() 32 | } 33 | -------------------------------------------------------------------------------- /spring-kafka-retry-demo/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/spring-kafka-retry-demo/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /spring-kafka-retry-demo/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /spring-kafka-retry-demo/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /spring-kafka-retry-demo/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'spring-kafka-retry-demo' 2 | -------------------------------------------------------------------------------- /spring-kafka-retry-demo/src/main/java/org/springframework/kafka/example/retry/SpringKafkaRetryDemoApplication.java: -------------------------------------------------------------------------------- 1 | package org.springframework.kafka.example.retry; 2 | 3 | import org.apache.kafka.clients.consumer.ConsumerRecord; 4 | 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.boot.task.SimpleAsyncTaskSchedulerBuilder; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.kafka.annotation.KafkaListener; 10 | import org.springframework.kafka.listener.ContainerPausingBackOffHandler; 11 | import org.springframework.kafka.listener.DefaultErrorHandler; 12 | import org.springframework.kafka.listener.ListenerContainerPauseService; 13 | import org.springframework.scheduling.TaskScheduler; 14 | import org.springframework.util.backoff.ExponentialBackOff; 15 | 16 | @SpringBootApplication 17 | public class SpringKafkaRetryDemoApplication { 18 | 19 | public static void main(String[] args) { 20 | SpringApplication.run(SpringKafkaRetryDemoApplication.class, args); 21 | } 22 | 23 | @Bean 24 | DefaultErrorHandler kafkaErrorHandler(SimpleAsyncTaskSchedulerBuilder simpleAsyncTaskSchedulerBuilder) { 25 | ExponentialBackOff backOff = new ExponentialBackOff(100, 2); 26 | backOff.setMaxInterval(6_000); 27 | backOff.setMaxElapsedTime(20_000); 28 | return new DefaultErrorHandler(null, backOff, 29 | new ContainerPausingBackOffHandler( 30 | new ListenerContainerPauseService(null, simpleAsyncTaskSchedulerBuilder.build()))); 31 | } 32 | 33 | @KafkaListener(topics = "${spring.kafka.template.default-topic}") 34 | void handleRecord(ConsumerRecord record) { 35 | System.out.println("Received record: " + record); 36 | throw new RuntimeException("intentional for retry"); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /spring-kafka-retry-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=spring-kafka-retry-demo 2 | 3 | spring.kafka.consumer.auto-offset-reset=earliest 4 | spring.kafka.consumer.group-id=demo-group 5 | spring.kafka.template.default-topic=retry-demo 6 | -------------------------------------------------------------------------------- /spring-kafka-retry-demo/src/test/java/org/springframework/kafka/example/retry/SpringKafkaRetryDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package org.springframework.kafka.example.retry; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.test.context.SpringBootTest; 7 | import org.springframework.kafka.core.KafkaTemplate; 8 | import org.springframework.kafka.test.context.EmbeddedKafka; 9 | import org.springframework.test.annotation.DirtiesContext; 10 | 11 | @SpringBootTest 12 | @DirtiesContext 13 | @EmbeddedKafka 14 | class SpringKafkaRetryDemoApplicationTests { 15 | 16 | @Autowired 17 | KafkaTemplate kafkaTemplate; 18 | 19 | @Test 20 | void recordRetried() throws InterruptedException { 21 | this.kafkaTemplate.sendDefault("test data"); 22 | 23 | Thread.sleep(60_000); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /websocket-over-webflux/.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 | 12 | ### IntelliJ IDEA ### 13 | .idea 14 | *.iws 15 | *.iml 16 | *.ipr 17 | 18 | ### NetBeans ### 19 | nbproject/private/ 20 | build/ 21 | nbbuild/ 22 | dist/ 23 | nbdist/ 24 | .nb-gradle/ -------------------------------------------------------------------------------- /websocket-over-webflux/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/websocket-over-webflux/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /websocket-over-webflux/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip 2 | -------------------------------------------------------------------------------- /websocket-over-webflux/README.md: -------------------------------------------------------------------------------- 1 | # websocket-over-webflux 2 | The Spring Boot application to demonstrate proxying WebSocket over WebFlux controller 3 | -------------------------------------------------------------------------------- /websocket-over-webflux/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.webflux.websocket 7 | websocket-over-webflux 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | websocket-over-webflux 12 | Demo project to demonstrate proxying WebSocket over WebFlux controller 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.1.0.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-webflux 31 | 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-test 36 | test 37 | 38 | 39 | 40 | io.projectreactor 41 | reactor-test 42 | test 43 | 44 | 45 | 46 | 47 | 48 | 49 | org.springframework.boot 50 | spring-boot-maven-plugin 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /websocket-over-webflux/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artembilan/sandbox/df95ea33d5189ac11b6d7f6149df9f803eff514b/websocket-over-webflux/src/main/resources/application.properties -------------------------------------------------------------------------------- /websocket-over-webflux/src/test/java/org/springframework/webflux/websocket/webfluxwebsocketdemo/WebFluxWebSocketDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.webflux.websocket.webfluxwebsocketdemo; 18 | 19 | import org.junit.Test; 20 | import org.junit.runner.RunWith; 21 | 22 | import org.springframework.beans.factory.annotation.Autowired; 23 | import org.springframework.boot.test.context.SpringBootTest; 24 | import org.springframework.test.context.junit4.SpringRunner; 25 | import org.springframework.test.web.reactive.server.WebTestClient; 26 | 27 | import reactor.core.publisher.Flux; 28 | import reactor.test.StepVerifier; 29 | 30 | /** 31 | * @author Artem Bilan 32 | * @author Christian Davatz 33 | */ 34 | @RunWith(SpringRunner.class) 35 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) 36 | public class WebFluxWebSocketDemoApplicationTests { 37 | 38 | @Autowired 39 | private WebTestClient webTestClient; 40 | 41 | @Test 42 | public void testWebSocketProxy() { 43 | Flux responseBody = 44 | this.webTestClient.get().uri("/stream") 45 | .exchange() 46 | .returnResult(String.class) 47 | .getResponseBody(); 48 | 49 | StepVerifier 50 | .create(responseBody) 51 | .expectNext("foo", "bar", "baz", "cux") 52 | .verifyComplete(); 53 | 54 | } 55 | 56 | } 57 | --------------------------------------------------------------------------------