├── .mvn ├── mvn.config ├── jvm.config └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── images ├── favicon.ico └── large-logo.png ├── nats-spring-samples ├── autoconfigure-sample │ ├── src │ │ └── main │ │ │ ├── resources │ │ │ └── application.properties │ │ │ └── java │ │ │ └── io │ │ │ └── nats │ │ │ └── spring │ │ │ ├── AutoconfigureSample.java │ │ │ └── Listener.java │ └── pom.xml ├── connect-error-sample │ ├── src │ │ └── main │ │ │ ├── resources │ │ │ └── application.properties │ │ │ └── java │ │ │ └── io │ │ │ └── nats │ │ │ └── spring │ │ │ ├── LoggingListener.java │ │ │ └── ConnectErrorSample.java │ └── pom.xml ├── source-sample │ ├── src │ │ └── main │ │ │ ├── resources │ │ │ └── application.properties │ │ │ └── java │ │ │ └── io │ │ │ └── nats │ │ │ └── spring │ │ │ ├── SourceSample.java │ │ │ └── TimedSource.java │ └── pom.xml ├── polling-sample │ ├── src │ │ └── main │ │ │ ├── resources │ │ │ └── application.properties │ │ │ └── java │ │ │ └── io │ │ │ └── nats │ │ │ └── spring │ │ │ └── PollingSample.java │ └── pom.xml ├── queue-sample │ ├── src │ │ └── main │ │ │ ├── resources │ │ │ └── application.yml │ │ │ └── java │ │ │ └── io │ │ │ └── nats │ │ │ └── spring │ │ │ ├── QueueSample.java │ │ │ └── QueueListener.java │ └── pom.xml ├── listener-sample │ ├── src │ │ └── main │ │ │ ├── resources │ │ │ └── application.properties │ │ │ └── java │ │ │ └── io │ │ │ └── nats │ │ │ └── spring │ │ │ ├── ListenerSample.java │ │ │ └── Listener.java │ └── pom.xml ├── processor-sample │ ├── src │ │ └── main │ │ │ ├── resources │ │ │ └── application.yml │ │ │ └── java │ │ │ └── io │ │ │ └── nats │ │ │ └── spring │ │ │ ├── ProcessorSample.java │ │ │ └── UpperCaseTransformer.java │ └── pom.xml ├── multi-connect-sample │ ├── src │ │ └── main │ │ │ ├── resources │ │ │ └── application.properties │ │ │ └── java │ │ │ └── io │ │ │ └── nats │ │ │ └── spring │ │ │ ├── MultiConnectSample.java │ │ │ └── MultiConnectTransformer.java │ └── pom.xml └── pom.xml ├── nats-spring ├── src │ ├── test │ │ ├── resources │ │ │ ├── cacerts │ │ │ ├── keystore.jks │ │ │ ├── tls.conf │ │ │ └── certs │ │ │ │ ├── server-cert.pem │ │ │ │ ├── ca.pem │ │ │ │ └── server-key.pem │ │ └── java │ │ │ └── io │ │ │ └── nats │ │ │ └── spring │ │ │ └── boot │ │ │ └── autoconfigure │ │ │ ├── AutoconfigureTests.java │ │ │ ├── PropertiesTests.java │ │ │ └── NatsTestServer.java │ └── main │ │ ├── resources │ │ └── META-INF │ │ │ ├── spring │ │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports │ │ │ ├── spring.factories │ │ │ └── spring-configuration-metadata.json │ │ └── java │ │ └── io │ │ └── nats │ │ └── spring │ │ └── boot │ │ └── autoconfigure │ │ ├── NatsProperties.java │ │ └── NatsAutoConfiguration.java └── pom.xml ├── nats-spring-cloud-stream-binder ├── src │ ├── main │ │ ├── resources │ │ │ └── META-INF │ │ │ │ └── spring.binders │ │ └── java │ │ │ └── io │ │ │ └── nats │ │ │ └── cloud │ │ │ └── stream │ │ │ └── binder │ │ │ ├── properties │ │ │ ├── NatsConsumerProperties.java │ │ │ ├── NatsProducerProperties.java │ │ │ ├── NatsBinderConfigurationProperties.java │ │ │ ├── NatsBindingProperties.java │ │ │ └── NatsExtendedBindingProperties.java │ │ │ ├── NatsProducerDestination.java │ │ │ ├── NatsConsumerDestination.java │ │ │ ├── NatsChannelProvisioner.java │ │ │ ├── NatsMessageHandler.java │ │ │ ├── NatsMessageSource.java │ │ │ ├── NatsMessageProducer.java │ │ │ ├── NatsChannelBinderConfiguration.java │ │ │ └── NatsChannelBinder.java │ └── test │ │ └── java │ │ └── io │ │ └── nats │ │ └── cloud │ │ └── stream │ │ └── binder │ │ ├── DestinationNameTests.java │ │ └── NatsBinderTestServer.java └── pom.xml ├── CODE-OF-CONDUCT.md ├── GOVERNANCE.md ├── demo ├── src │ └── main │ │ ├── resources │ │ └── application.properties │ │ └── java │ │ └── io │ │ └── nats │ │ └── demo │ │ ├── DemoApplication.java │ │ └── ReverseProcessor.java ├── README.md └── pom.xml ├── MAINTAINERS.md ├── settings.xml ├── .travis.yml ├── update-version.sh ├── .gitignore ├── .github └── workflows │ ├── build-merge.yml │ └── build-pr.yml ├── nats-spring-boot-starter └── pom.xml ├── project-management.md ├── mvnw.cmd ├── dependencies.md ├── LICENSE ├── mvnw └── pom.xml /.mvn/mvn.config: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nats-io/spring-nats/HEAD/images/favicon.ico -------------------------------------------------------------------------------- /images/large-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nats-io/spring-nats/HEAD/images/large-logo.png -------------------------------------------------------------------------------- /.mvn/jvm.config: -------------------------------------------------------------------------------- 1 | -Xmx1024m -XX:CICompilerCount=1 -XX:TieredStopAtLevel=1 -Djava.security.egd=file:/dev/./urandom -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nats-io/spring-nats/HEAD/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /nats-spring-samples/autoconfigure-sample/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | nats.spring.server=nats://localhost:4222 2 | -------------------------------------------------------------------------------- /nats-spring/src/test/resources/cacerts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nats-io/spring-nats/HEAD/nats-spring/src/test/resources/cacerts -------------------------------------------------------------------------------- /nats-spring-cloud-stream-binder/src/main/resources/META-INF/spring.binders: -------------------------------------------------------------------------------- 1 | nats:\ 2 | io.nats.cloud.stream.binder.NatsChannelBinderConfiguration -------------------------------------------------------------------------------- /nats-spring/src/test/resources/keystore.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nats-io/spring-nats/HEAD/nats-spring/src/test/resources/keystore.jks -------------------------------------------------------------------------------- /CODE-OF-CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Community Code of Conduct 2 | 3 | NATS follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). 4 | -------------------------------------------------------------------------------- /nats-spring/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | io.nats.spring.boot.autoconfigure.NatsAutoConfiguration 2 | -------------------------------------------------------------------------------- /GOVERNANCE.md: -------------------------------------------------------------------------------- 1 | # NATS Spring Support Governance 2 | 3 | NATS Spring Support is part of the NATS project and is subject to the [NATS Governance](https://github.com/nats-io/nats-general/blob/master/GOVERNANCE.md). 4 | -------------------------------------------------------------------------------- /nats-spring/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | # Auto Configure (deprecated with spring boot 2.7) 2 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 3 | io.nats.spring.boot.autoconfigure.NatsAutoConfiguration 4 | -------------------------------------------------------------------------------- /nats-spring-samples/connect-error-sample/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.cloud.stream.bindings.input-in-0.destination=dataIn 2 | spring.cloud.stream.bindings.input.in-0.binder=nats 3 | nats.spring.server=nats://localhost:4222 4 | -------------------------------------------------------------------------------- /nats-spring-samples/source-sample/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.cloud.stream.bindings.timedchannel.destination=dataOut 2 | spring.cloud.stream.bindings.timedchannel.binder=nats 3 | nats.spring.server=nats://localhost:4222 4 | -------------------------------------------------------------------------------- /nats-spring-samples/polling-sample/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.cloud.stream.bindings.input.destination=dataIn 2 | spring.cloud.stream.bindings.input.binder=nats 3 | spring.cloud.stream.pollable-source=nats 4 | nats.spring.server=nats://localhost:4222 5 | 6 | -------------------------------------------------------------------------------- /demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.cloud.stream.bindings.input.destination=dataIn 2 | spring.cloud.stream.bindings.input.binder=nats 3 | spring.cloud.stream.bindings.output.destination=dataOut 4 | spring.cloud.stream.bindings.output.binder=nats 5 | nats.spring.server=nats://localhost:4222 6 | -------------------------------------------------------------------------------- /nats-spring-samples/queue-sample/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | stream: 4 | bindings: 5 | input-in-0: 6 | destination: dataIn 7 | binder: nats 8 | group: one 9 | 10 | nats: 11 | spring: 12 | server: nats://localhost:4222 13 | -------------------------------------------------------------------------------- /MAINTAINERS.md: -------------------------------------------------------------------------------- 1 | # Maintainers 2 | 3 | Maintainership is on a per project basis. 4 | 5 | ### Maintainers 6 | 7 | - Derek Collison [@derekcollison](https://github.com/derekcollison) 8 | - Stephen Asbury [@sasbury](https://github.com/sasbury) 9 | - Colin Sullivan [@ColinSullivan1](https://github.com/ColinSullivan1) 10 | -------------------------------------------------------------------------------- /nats-spring/src/test/resources/tls.conf: -------------------------------------------------------------------------------- 1 | 2 | # Simple TLS config file 3 | 4 | port: 4443 5 | net: localhost 6 | 7 | tls { 8 | cert_file: "src/test/resources/certs/server-cert.pem" 9 | key_file: "src/test/resources/certs/server-key.pem" 10 | timeout: 2 11 | 12 | # Optional certificate authority for clients 13 | ca_file: "src/test/resources/certs/ca.pem" 14 | } 15 | -------------------------------------------------------------------------------- /nats-spring-samples/listener-sample/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.cloud.stream.bindings.input-in-0.destination=dataIn 2 | spring.cloud.stream.bindings.input-in-0.binder=nats1 3 | #nats.spring.server=nats://localhost:4222 4 | spring.cloud.stream.binders.nats1.type=nats 5 | spring.cloud.stream.binders.nats1.environment.nats.spring.cloud.stream.binder.server=nats://localhost:4222 6 | -------------------------------------------------------------------------------- /demo/src/main/java/io/nats/demo/DemoApplication.java: -------------------------------------------------------------------------------- 1 | package io.nats.demo; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class DemoApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(DemoApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /nats-spring-samples/processor-sample/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | stream: 4 | function: 5 | bindings: 6 | transform-in-0: input 7 | transform-out-0: output 8 | bindings: 9 | input: 10 | destination: dataIn 11 | binder: nats 12 | output: 13 | destination: dataOut 14 | binder: nats 15 | nats: 16 | spring: 17 | server: nats://localhost:4222 18 | -------------------------------------------------------------------------------- /demo/README.md: -------------------------------------------------------------------------------- 1 | # NATS Streaming Binder Example 2 | 3 | This is a simple example using the NATS Streaming binder. The example lives independently of the other samples, with 4 | only the SpringBoot parent pom. 5 | 6 | The example is similar to the processor examples from the nats-samples folder, but shows how to include the binder 7 | independently. 8 | 9 | To run: 10 | 11 | ```bash 12 | % cd demo 13 | % ../mvnw clean package 14 | % java -jar target/demo-0.0.1-SNAPSHOT.jar 15 | ``` 16 | -------------------------------------------------------------------------------- /settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | central 8 | ${env.OSSRH_USERNAME} 9 | ${env.OSSRH_PASSWORD} 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: jammy 2 | language: java 3 | sudo: required 4 | jdk: 5 | - openjdk17 6 | - openjdk18 7 | - openjdk19 8 | - openjdk20 9 | - openjdk21 10 | - openjdk22 11 | before_script: 12 | - wget "https://github.com/nats-io/nats-server/releases/download/$nats_server_version/nats-server-$nats_server_version-linux-amd64.zip" 13 | -O tmp.zip 14 | - unzip tmp.zip 15 | - mv nats-server-$nats_server_version-linux-amd64 nats-server 16 | install: mvn install -DskipTests -Dgpg.skip 17 | env: 18 | global: 19 | - nats_server_version=v2.0.2 20 | - nats_server_path=$TRAVIS_BUILD_DIR/nats-server/nats-server 21 | -------------------------------------------------------------------------------- /nats-spring-samples/multi-connect-sample/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.cloud.stream.function.bindings.transform-in-0=input 2 | spring.cloud.stream.function.bindings.transform-out-0=output 3 | spring.cloud.stream.bindings.input.destination=dataIn 4 | spring.cloud.stream.bindings.input.binder=nats1 5 | spring.cloud.stream.bindings.output.destination=dataOut 6 | spring.cloud.stream.bindings.output.binder=nats2 7 | #nats.spring.server=nats://localhost:4222 8 | spring.cloud.stream.binders.nats1.type=nats 9 | spring.cloud.stream.binders.nats1.environment.nats.spring.cloud.stream.binder.server=nats://localhost:4222 10 | spring.cloud.stream.binders.nats2.type=nats 11 | spring.cloud.stream.binders.nats2.environment.nats.spring.cloud.stream.binder.server=nats://localhost:4222 12 | -------------------------------------------------------------------------------- /nats-spring-cloud-stream-binder/src/main/java/io/nats/cloud/stream/binder/properties/NatsConsumerProperties.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.cloud.stream.binder.properties; 18 | 19 | public class NatsConsumerProperties { 20 | } 21 | -------------------------------------------------------------------------------- /nats-spring-cloud-stream-binder/src/main/java/io/nats/cloud/stream/binder/properties/NatsProducerProperties.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.cloud.stream.binder.properties; 18 | 19 | public class NatsProducerProperties { 20 | } 21 | -------------------------------------------------------------------------------- /update-version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #Execute this script from local checkout of spring cloud stream 4 | 5 | ./mvnw versions:update-parent -DparentVersion=[0.0.1,$2] -Pspring -DgenerateBackupPoms=false -DallowSnapshots=true 6 | ./mvnw versions:set -DnewVersion=$1 -DgenerateBackupPoms=false 7 | 8 | 9 | 10 | lines=$(find . -name 'pom.xml' | xargs egrep "SNAPSHOT|M[0-9]|RC[0-9]" | grep -v regex | wc -l) 11 | if [ $lines -eq 0 ]; then 12 | echo "No snapshots found" 13 | else 14 | echo "Snapshots found." 15 | fi 16 | 17 | lines=$(find . -name 'pom.xml' | xargs egrep "M[0-9]" | grep -v regex | wc -l) 18 | if [ $lines -eq 0 ]; then 19 | echo "No milestones found" 20 | else 21 | echo "Milestones found." 22 | fi 23 | 24 | lines=$(find . -name 'pom.xml' | xargs egrep "RC[0-9]" | grep -v regex | wc -l) 25 | if [ $lines -eq 0 ]; then 26 | echo "No release candidates found" 27 | else 28 | echo "Release candidates found." 29 | fi 30 | -------------------------------------------------------------------------------- /.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.9.3/apache-maven-3.9.3-bin.zip 18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar 19 | -------------------------------------------------------------------------------- /nats-spring-samples/queue-sample/src/main/java/io/nats/spring/QueueSample.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.spring; 18 | 19 | import org.springframework.boot.SpringApplication; 20 | import org.springframework.boot.autoconfigure.SpringBootApplication; 21 | 22 | @SpringBootApplication 23 | public class QueueSample { 24 | 25 | public static void main(String[] args) { 26 | SpringApplication.run(QueueSample.class, args); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /nats-spring-samples/source-sample/src/main/java/io/nats/spring/SourceSample.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.spring; 18 | 19 | import org.springframework.boot.SpringApplication; 20 | import org.springframework.boot.autoconfigure.SpringBootApplication; 21 | 22 | @SpringBootApplication 23 | public class SourceSample { 24 | 25 | public static void main(String[] args) { 26 | SpringApplication.run(SourceSample.class, args); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /nats-spring-samples/listener-sample/src/main/java/io/nats/spring/ListenerSample.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.spring; 18 | 19 | import org.springframework.boot.SpringApplication; 20 | import org.springframework.boot.autoconfigure.SpringBootApplication; 21 | 22 | @SpringBootApplication 23 | public class ListenerSample { 24 | 25 | public static void main(String[] args) { 26 | SpringApplication.run(ListenerSample.class, args); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /nats-spring-samples/multi-connect-sample/src/main/java/io/nats/spring/MultiConnectSample.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.spring; 18 | 19 | import org.springframework.boot.SpringApplication; 20 | import org.springframework.boot.autoconfigure.SpringBootApplication; 21 | 22 | @SpringBootApplication 23 | public class MultiConnectSample { 24 | public static void main(String[] args) { 25 | SpringApplication.run(MultiConnectSample.class, args); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /nats-spring-samples/processor-sample/src/main/java/io/nats/spring/ProcessorSample.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.spring; 18 | 19 | import org.springframework.boot.SpringApplication; 20 | import org.springframework.boot.autoconfigure.SpringBootApplication; 21 | 22 | @SpringBootApplication 23 | public class ProcessorSample { 24 | 25 | public static void main(String[] args) { 26 | SpringApplication.run(ProcessorSample.class, args); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /nats-spring-samples/autoconfigure-sample/src/main/java/io/nats/spring/AutoconfigureSample.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.spring; 18 | 19 | import org.springframework.boot.SpringApplication; 20 | import org.springframework.boot.autoconfigure.SpringBootApplication; 21 | 22 | @SpringBootApplication 23 | public class AutoconfigureSample { 24 | public static void main(String[] args) { 25 | SpringApplication.run(AutoconfigureSample.class, args); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # NATS stuff # 3 | ############## 4 | gnatsd.log 5 | *.csv 6 | 7 | # Compiled source # 8 | ################### 9 | *.com 10 | *.class 11 | *.dll 12 | *.exe 13 | *.o 14 | *.so 15 | /bin 16 | 17 | # Packages # 18 | ############ 19 | *.7z 20 | *.dmg 21 | *.gz 22 | *.iso 23 | *.rar 24 | *.tar 25 | *.zip 26 | 27 | # Logs and databases # 28 | ###################### 29 | *.log 30 | 31 | # OS generated files # 32 | ###################### 33 | .DS_Store* 34 | ehthumbs.db 35 | Icon? 36 | Thumbs.db 37 | 38 | # Editor Files # 39 | ################ 40 | *~ 41 | *.swp 42 | .sts4-cache/* 43 | 44 | # Gradle Files # 45 | ################ 46 | .gradle 47 | .m2 48 | 49 | # Build output directies 50 | /target 51 | */target 52 | */*/target 53 | /build 54 | */build 55 | 56 | # IntelliJ specific files/directories 57 | out 58 | .idea 59 | *.ipr 60 | *.iws 61 | *.iml 62 | atlassian-ide-plugin.xml 63 | 64 | # Eclipse specific files/directories 65 | .classpath 66 | .project 67 | .settings 68 | .metadata 69 | 70 | # NetBeans specific files/directories 71 | .nbattrs 72 | 73 | # VSCode 74 | .vscode/ 75 | 76 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 77 | hs_err_pid* 78 | /target/ 79 | -------------------------------------------------------------------------------- /nats-spring-cloud-stream-binder/src/main/java/io/nats/cloud/stream/binder/properties/NatsBinderConfigurationProperties.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.cloud.stream.binder.properties; 18 | 19 | import io.nats.spring.boot.autoconfigure.NatsConnectionProperties; 20 | import org.springframework.boot.context.properties.ConfigurationProperties; 21 | 22 | @ConfigurationProperties(prefix = "nats.spring.cloud.stream.binder") 23 | public class NatsBinderConfigurationProperties extends NatsConnectionProperties { 24 | public NatsBinderConfigurationProperties() { 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /nats-spring-samples/connect-error-sample/src/main/java/io/nats/spring/LoggingListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.spring; 18 | 19 | import org.apache.commons.logging.Log; 20 | import org.apache.commons.logging.LogFactory; 21 | import org.springframework.context.annotation.Bean; 22 | import org.springframework.stereotype.Component; 23 | 24 | import java.util.function.Consumer; 25 | 26 | @Component 27 | public class LoggingListener { 28 | private static final Log logger = LogFactory.getLog(LoggingListener.class); 29 | 30 | @Bean 31 | public Consumer input() { 32 | return message -> logger.info("received message " + message); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /nats-spring-samples/queue-sample/src/main/java/io/nats/spring/QueueListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.spring; 18 | 19 | import org.apache.commons.logging.Log; 20 | import org.apache.commons.logging.LogFactory; 21 | import org.springframework.context.annotation.Bean; 22 | import org.springframework.stereotype.Component; 23 | 24 | import java.util.function.Consumer; 25 | 26 | @Component 27 | public class QueueListener { 28 | private static final Log logger = LogFactory.getLog(QueueListener.class); 29 | 30 | @Bean 31 | public Consumer input() { 32 | return message -> logger.info("received message:- " + new String((byte[]) message)); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /nats-spring-samples/listener-sample/src/main/java/io/nats/spring/Listener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.spring; 18 | 19 | import org.apache.commons.logging.Log; 20 | import org.apache.commons.logging.LogFactory; 21 | import org.springframework.context.annotation.Bean; 22 | import org.springframework.stereotype.Component; 23 | 24 | import java.util.function.Consumer; 25 | 26 | @Component 27 | public class Listener { 28 | private static final Log logger = LogFactory.getLog(Listener.class); 29 | 30 | @Bean 31 | public Consumer input() { 32 | return message -> { 33 | logger.info("received message : " + new String((byte[]) message)); 34 | }; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /nats-spring-samples/source-sample/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | nats-spring-samples-source 7 | 0.6.3+3.5-SNAPSHOT 8 | jar 9 | source-sample 10 | A source using the nats binder 11 | 12 | 13 | io.nats.nats-spring-samples 14 | nats-spring-samples-parent 15 | 0.6.3+3.5-SNAPSHOT 16 | ../pom.xml 17 | 18 | 19 | 20 | ${basedir}/.. 21 | 22 | 23 | 24 | 25 | io.nats 26 | nats-spring-cloud-stream-binder 27 | 28 | 29 | 30 | 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-maven-plugin 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /demo/src/main/java/io/nats/demo/ReverseProcessor.java: -------------------------------------------------------------------------------- 1 | package io.nats.demo; 2 | 3 | import java.nio.charset.StandardCharsets; 4 | 5 | import org.springframework.cloud.stream.annotation.EnableBinding; 6 | import org.springframework.cloud.stream.annotation.StreamListener; 7 | import org.springframework.cloud.stream.messaging.Processor; 8 | import org.springframework.messaging.handler.annotation.SendTo; 9 | 10 | @EnableBinding(Processor.class) 11 | public class ReverseProcessor { 12 | @StreamListener(Processor.INPUT) 13 | @SendTo(Processor.OUTPUT) 14 | public Object transform(Object message) { 15 | if (message instanceof byte[]) { 16 | String value = new String((byte[]) message, StandardCharsets.UTF_8); 17 | StringBuilder reverse = new StringBuilder(); 18 | for (int i = value.length() - 1; i >= 0; i--) { 19 | reverse.append(value.charAt(i)); 20 | } 21 | message = reverse.toString().toUpperCase().getBytes(StandardCharsets.UTF_8); 22 | } else if (message instanceof String) { 23 | String value = (String) message; 24 | StringBuilder reverse = new StringBuilder(); 25 | for (int i = value.length() - 1; i >= 0; i--) { 26 | reverse.append(value.charAt(i)); 27 | } 28 | message = reverse.toString().toUpperCase().getBytes(StandardCharsets.UTF_8); 29 | } 30 | return message; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /nats-spring-samples/polling-sample/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | nats-spring-samples-polling 7 | 0.6.3+3.5-SNAPSHOT 8 | jar 9 | polling-sample 10 | A poller using the nats binder 11 | 12 | 13 | io.nats.nats-spring-samples 14 | nats-spring-samples-parent 15 | 0.6.3+3.5-SNAPSHOT 16 | ../pom.xml 17 | 18 | 19 | 20 | ${basedir}/.. 21 | 22 | 23 | 24 | 25 | io.nats 26 | nats-spring-cloud-stream-binder 27 | 28 | 29 | 30 | 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-maven-plugin 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /nats-spring-samples/queue-sample/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | nats-spring-samples-queue 7 | 0.6.3+3.5-SNAPSHOT 8 | jar 9 | queue-sample 10 | A queue listener using the nats binder 11 | 12 | 13 | io.nats.nats-spring-samples 14 | nats-spring-samples-parent 15 | 0.6.3+3.5-SNAPSHOT 16 | ../pom.xml 17 | 18 | 19 | 20 | ${basedir}/.. 21 | 22 | 23 | 24 | 25 | io.nats 26 | nats-spring-cloud-stream-binder 27 | 28 | 29 | 30 | 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-maven-plugin 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /nats-spring-samples/listener-sample/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | nats-spring-samples-listener 7 | 0.6.3+3.5-SNAPSHOT 8 | jar 9 | listener-sample 10 | A listener using the nats binder 11 | 12 | 13 | io.nats.nats-spring-samples 14 | nats-spring-samples-parent 15 | 0.6.3+3.5-SNAPSHOT 16 | ../pom.xml 17 | 18 | 19 | 20 | ${basedir}/.. 21 | 22 | 23 | 24 | 25 | io.nats 26 | nats-spring-cloud-stream-binder 27 | 28 | 29 | 30 | 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-maven-plugin 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /nats-spring-samples/multi-connect-sample/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | nats-spring-samples-multi-connect 7 | 0.6.3+3.5-SNAPSHOT 8 | jar 9 | multi-connect-sample 10 | A simple sample for the nats cloud stream binder 11 | 12 | 13 | io.nats.nats-spring-samples 14 | nats-spring-samples-parent 15 | 0.6.3+3.5-SNAPSHOT 16 | ../pom.xml 17 | 18 | 19 | 20 | ${basedir}/.. 21 | 22 | 23 | 24 | 25 | io.nats 26 | nats-spring-cloud-stream-binder 27 | 28 | 29 | 30 | 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-maven-plugin 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /nats-spring-samples/processor-sample/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | nats-spring-samples-processor 7 | 0.6.3+3.5-SNAPSHOT 8 | jar 9 | processor-sample 10 | A simple sample for the nats cloud stream binding with a processor 11 | 12 | 13 | io.nats.nats-spring-samples 14 | nats-spring-samples-parent 15 | 0.6.3+3.5-SNAPSHOT 16 | ../pom.xml 17 | 18 | 19 | 20 | ${basedir}/.. 21 | 22 | 23 | 24 | 25 | io.nats 26 | nats-spring-cloud-stream-binder 27 | 28 | 29 | 30 | 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-maven-plugin 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /nats-spring-samples/connect-error-sample/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | nats-spring-samples-connect-error 7 | 0.6.3+3.5-SNAPSHOT 8 | jar 9 | connect-error-sample 10 | A sample that sets up a custom connection and error listener for the NATS binder 11 | 12 | 13 | io.nats.nats-spring-samples 14 | nats-spring-samples-parent 15 | 0.6.3+3.5-SNAPSHOT 16 | ../pom.xml 17 | 18 | 19 | 20 | ${basedir}/.. 21 | 22 | 23 | 24 | 25 | io.nats 26 | nats-spring-cloud-stream-binder 27 | 28 | 29 | 30 | 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-maven-plugin 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /nats-spring/src/main/java/io/nats/spring/boot/autoconfigure/NatsProperties.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.spring.boot.autoconfigure; 18 | 19 | import io.nats.client.Options; 20 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 21 | import org.springframework.boot.context.properties.ConfigurationProperties; 22 | 23 | /** 24 | * NatsProperties extends NatsConnectionProperties, which provides all of the 25 | * attributes, setters and getters. A NatsProperties configuration is used 26 | * during autoconfigure to initialize the underlying NATs connection. 27 | */ 28 | @ConditionalOnClass({Options.class}) 29 | @ConfigurationProperties(prefix = "nats.spring") 30 | public class NatsProperties extends NatsConnectionProperties { 31 | 32 | /** 33 | * Default Constructor. 34 | */ 35 | public NatsProperties() { 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /nats-spring-samples/autoconfigure-sample/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | nats-spring-samples-autoconfigure 7 | 0.6.3+3.5-SNAPSHOT 8 | jar 9 | autoconfigure-sample 10 | A spring boot app that uses the autoconfigure NATS connection 11 | 12 | 13 | io.nats.nats-spring-samples 14 | nats-spring-samples-parent 15 | 0.6.3+3.5-SNAPSHOT 16 | ../pom.xml 17 | 18 | 19 | 20 | ${basedir}/.. 21 | 22 | 23 | 24 | 25 | io.nats 26 | nats-spring 27 | 0.6.3+3.5-SNAPSHOT 28 | 29 | 30 | 31 | 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-maven-plugin 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /nats-spring-cloud-stream-binder/src/main/java/io/nats/cloud/stream/binder/NatsProducerDestination.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.cloud.stream.binder; 18 | 19 | import org.springframework.cloud.stream.provisioning.ProducerDestination; 20 | 21 | /** 22 | * NATS uses subjects for sending and receiving. While partitions are not used 23 | * this class can generate a patition-based name for compatibility with the binder 24 | * API. 25 | */ 26 | public class NatsProducerDestination implements ProducerDestination { 27 | private String name; 28 | 29 | public NatsProducerDestination(String name) { 30 | this.name = name; 31 | } 32 | 33 | @Override 34 | public String getName() { 35 | return this.name; 36 | } 37 | 38 | @Override 39 | public String getNameForPartition(int partition) { 40 | return this.name + "-" + partition; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /nats-spring-samples/processor-sample/src/main/java/io/nats/spring/UpperCaseTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.spring; 18 | 19 | import java.nio.charset.StandardCharsets; 20 | import java.util.function.Function; 21 | 22 | import org.springframework.context.annotation.Bean; 23 | import org.springframework.stereotype.Component; 24 | 25 | @Component 26 | public class UpperCaseTransformer { 27 | 28 | @Bean 29 | public Function transform() { 30 | return message -> { 31 | if (message instanceof byte[]) { 32 | String value = new String((byte[]) message, StandardCharsets.UTF_8); 33 | message = value.toUpperCase().getBytes(StandardCharsets.UTF_8); 34 | } else if (message instanceof String) { 35 | message = ((String) message).toUpperCase(); 36 | } 37 | return message; 38 | }; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /nats-spring-samples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | io.nats.nats-spring-samples 7 | nats-spring-samples-parent 8 | 0.6.3+3.5-SNAPSHOT 9 | pom 10 | 11 | 12 | io.nats 13 | nats-spring-parent 14 | 0.6.3+3.5-SNAPSHOT 15 | ../pom.xml 16 | 17 | 18 | 19 | 4.2.1 20 | 21 | 22 | 23 | processor-sample 24 | listener-sample 25 | polling-sample 26 | source-sample 27 | queue-sample 28 | multi-connect-sample 29 | autoconfigure-sample 30 | connect-error-sample 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-maven-plugin 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /nats-spring-cloud-stream-binder/src/main/java/io/nats/cloud/stream/binder/properties/NatsBindingProperties.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.cloud.stream.binder.properties; 18 | 19 | import org.springframework.cloud.stream.binder.BinderSpecificPropertiesProvider; 20 | 21 | public class NatsBindingProperties implements BinderSpecificPropertiesProvider { 22 | 23 | private NatsConsumerProperties consumer = new NatsConsumerProperties(); 24 | private NatsProducerProperties producer = new NatsProducerProperties(); 25 | 26 | @Override 27 | public NatsConsumerProperties getConsumer() { 28 | return consumer; 29 | } 30 | 31 | public void setConsumer(NatsConsumerProperties consumer) { 32 | this.consumer = consumer; 33 | } 34 | 35 | @Override 36 | public NatsProducerProperties getProducer() { 37 | return producer; 38 | } 39 | 40 | public void setProducer(NatsProducerProperties producer) { 41 | this.producer = producer; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /.github/workflows/build-merge.yml: -------------------------------------------------------------------------------- 1 | name: Build Main 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | env: 13 | OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} 14 | OSSRH_PASSWORD: ${{ secrets.OSSRH_TOKEN }} 15 | MAVEN_GPG_PASSPHRASE: ${{ secrets.SIGNING_PASSWORD }} 16 | MAVEN_GPG_KEY: ${{ secrets.SIGNING_KEY }} 17 | GODEBUG: x509sha1=1 18 | steps: 19 | - name: Setup GO 20 | uses: actions/setup-go@v5 21 | with: 22 | go-version: '1.21.4' 23 | - name: Install Nats Server 24 | run: | 25 | cd $GITHUB_WORKSPACE 26 | git clone https://github.com/nats-io/nats-server.git 27 | cd nats-server 28 | go get 29 | go build main.go 30 | mkdir -p ~/.local/bin 31 | cp main ~/.local/bin/nats-server 32 | cd .. 33 | rm -rf nats-server 34 | nats-server -v 35 | - name: Check out code 36 | uses: actions/checkout@v4 37 | - name: Setup Maven Action 38 | uses: s4u/setup-maven-action@v1.18.0 39 | with: 40 | java-version: 17 41 | - name: Build and Install Parent Pom 42 | run: mvn --no-transfer-progress --settings ./settings.xml -N clean install 43 | - name: Build and Install Samples 44 | run: | 45 | cd nats-spring-samples 46 | mvn --no-transfer-progress --settings ../settings.xml -N clean install 47 | cd .. 48 | - name: Publish 49 | run: mvn --no-transfer-progress --settings ./settings.xml clean verify install deploy 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /.github/workflows/build-pr.yml: -------------------------------------------------------------------------------- 1 | name: Build Pull Request 2 | 3 | on: 4 | pull_request: 5 | types: [opened, synchronize, reopened] 6 | 7 | permissions: 8 | contents: read 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | env: 14 | OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} 15 | OSSRH_PASSWORD: ${{ secrets.OSSRH_TOKEN }} 16 | MAVEN_GPG_PASSPHRASE: ${{ secrets.SIGNING_PASSWORD }} 17 | MAVEN_GPG_KEY: ${{ secrets.SIGNING_KEY }} 18 | GODEBUG: x509sha1=1 19 | steps: 20 | - name: Setup GO 21 | uses: actions/setup-go@v5 22 | with: 23 | go-version: '1.21.4' 24 | - name: Install Nats Server 25 | run: | 26 | cd $GITHUB_WORKSPACE 27 | git clone https://github.com/nats-io/nats-server.git 28 | cd nats-server 29 | go build main.go 30 | mkdir -p ~/.local/bin 31 | cp main ~/.local/bin/nats-server 32 | cd .. 33 | rm -rf nats-server 34 | nats-server -v 35 | - name: Check out code 36 | uses: actions/checkout@v4 37 | - name: Setup Maven Action 38 | uses: s4u/setup-maven-action@v1.18.0 39 | with: 40 | java-version: 17 41 | - name: Build and Install Parent Pom 42 | run: mvn --no-transfer-progress --settings ./settings.xml -N clean install 43 | - name: Build and Install Samples 44 | run: | 45 | cd nats-spring-samples 46 | mvn --no-transfer-progress --settings ../settings.xml -N clean install 47 | cd .. 48 | - name: Compile and Test 49 | run: mvn --no-transfer-progress --settings ./settings.xml clean clean compile test 50 | -------------------------------------------------------------------------------- /nats-spring-cloud-stream-binder/src/main/java/io/nats/cloud/stream/binder/properties/NatsExtendedBindingProperties.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.cloud.stream.binder.properties; 18 | 19 | import org.springframework.boot.context.properties.ConfigurationProperties; 20 | import org.springframework.cloud.stream.binder.AbstractExtendedBindingProperties; 21 | import org.springframework.cloud.stream.binder.BinderSpecificPropertiesProvider; 22 | 23 | @ConfigurationProperties("nats.spring.cloud.stream") 24 | public class NatsExtendedBindingProperties 25 | extends AbstractExtendedBindingProperties { 26 | 27 | private static final String DEFAULTS_PREFIX = "nats.spring.cloud.stream.default"; 28 | 29 | @Override 30 | public String getDefaultsPrefix() { 31 | return DEFAULTS_PREFIX; 32 | } 33 | 34 | @Override 35 | public Class getExtendedPropertiesEntryClass() { 36 | return NatsBindingProperties.class; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /nats-spring-boot-starter/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | nats-spring-boot-starter 7 | NATS Starter for Spring 8 | 0.6.3+3.5-SNAPSHOT 9 | pom 10 | 11 | 12 | CNCF 13 | https://www.nats.io 14 | 15 | 16 | 17 | io.nats 18 | nats-spring-parent 19 | 0.6.3+3.5-SNAPSHOT 20 | ../pom.xml 21 | 22 | 23 | 24 | ${basedir}/.. 25 | 26 | 27 | 28 | 29 | io.nats 30 | jnats 31 | 2.21.1 32 | 33 | 34 | io.nats 35 | nats-spring 36 | 0.6.3+3.5-SNAPSHOT 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter 41 | ${spring-boot.version} 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-autoconfigure-processor 46 | true 47 | ${spring-boot.version} 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /nats-spring/src/test/resources/certs/server-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFQTCCAymgAwIBAgIJAO+k4G7bNTyoMA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD 3 | VQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzAR 4 | BgNVBAoTCkFwY2VyYSBJbmMxEDAOBgNVBAsTB25hdHMuaW8xEjAQBgNVBAMTCWxv 5 | Y2FsaG9zdDEcMBoGCSqGSIb3DQEJARYNZGVyZWtAbmF0cy5pbzAeFw0xNTExMDUy 6 | MzA2MzRaFw0xOTExMDQyMzA2MzRaMBQxEjAQBgNVBAMTCWxvY2FsaG9zdDCCAiIw 7 | DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALYBy3IEY3kqlf5h2vEtk9CB4Vnt 8 | AD+eaVc3Y9xuFHJ4k0ScsjwrYH3YcwQW0fDpOQCI0102YoQT7tPCBT+rC0w1mM82 9 | 0ZSKS/y2SIK9cM6LHWkUbQcWfeaL+uz2HB3jTEm8tmEEFTLBJFMbMpUsvjA5GLqG 10 | URswsNjYEl8M9wS1BETw2e+eCFa4wxq9oGHp/Dgh0vZglHzQL5osEpRct1aaQo6O 11 | jWzZc1Cgx4SxmMOoMWF8BQzlO7aikbZEJxk03TIFNph/azJt7mviMseW72mP+bX9 12 | sm/8bsINiYgJMM2HAyjIgFVMXX8AYfEFC4wozYloLqn0yy9TdjhyGbsUjg0yTd4l 13 | A9LkGKroBdY1drPSek5Nj9br27UGGGfU2ddAD5xYBIeeFY+3nqST868oIXB/m1P7 14 | 1p8tpkgujx/RqKr3nvOqBHizmoQaWZsPC3X/Jc4NvVHihpuNzN/u1D5mxGhxsx+R 15 | qnrIkhS0IqNrokggPZazugmHntd95HgTb3JpjY3RGEYXAQNr+mZGUCc+CVu0mhFX 16 | xAMZcfVp5nDg4hKHiaRv0KcaqBmnn8AB5w5FiTppzUbRP0zz7GkwrdulwR6c2Eb5 17 | 75+/022TbgCx8B9SH4zJRTj5mtrK56eFgTcnuXB+YnWaP7/7qmKIZzxrd3UDvnza 18 | bhnMiiIK7vL8qiOTAgMBAAGjHjAcMBoGA1UdEQQTMBGCCWxvY2FsaG9zdIcEfwAA 19 | ATANBgkqhkiG9w0BAQsFAAOCAgEAOrh8XfW6quwBAcCxHf6/uvu/iNq4yHCg2qH6 20 | VtWs/x38I2t3BRSNsLsJGieh6yLlZDzOus+XYui4uDE50XmcwaIsY0VcXnvdyZVZ 21 | w9+lMyfp00kRF1o3B6eVxq0pRE5VB0cai7XI7tyfpRwGzA+oNLF4vBvxAHm9Ony5 22 | Q57DC/HFzyUogdkMYciO/kd9oa4HosDEXwaE8UvZUL8OVl/dptMXLL/GGwzZsUAE 23 | 1sLAbgm044YChLUDzgBAtDTkB/HNkcPzSKwULuskhe7ndoaEQNXVZuP7quGiZ/W1 24 | 1lE59gnmnyG8ySFCL05jHrKLtFAJe88gQjgDK65ZJv4W/k7ocmT+HhCxWyQWcX6v 25 | abJ0EssqeSQuzRMuZebMJJ8s46d6RcYuMdIX3RDXq+1moJDFopE7lgNrlRhWgaky 26 | Og8f/u8s1j75tk1YaYcY9uBKjKk7f681R9wMumkd6IEmEvkUwHNFsctxi4fGI7h1 27 | PRdKL0DlhVmnpHlKs6Kvm2sJ3twSAGSrC4u0LuxACeR3XbiBfyhFV/291LSuw/y1 28 | JtWOW5koh0g1k9xtkiu3/ePVdG/CLp796IyRhdB1jP/vD7W5RLLG/VAlomfjsPsB 29 | AnwFYbVZ8KrmMKYUpTJOH31CRzFdOB6nWqXu5tk3nOtLKo1nIOuVtmp9XLz3VtHe 30 | NiZPnqA= 31 | -----END CERTIFICATE----- 32 | -------------------------------------------------------------------------------- /nats-spring-samples/autoconfigure-sample/src/main/java/io/nats/spring/Listener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.spring; 18 | 19 | import io.nats.client.Connection; 20 | import io.nats.client.Dispatcher; 21 | import org.apache.commons.logging.Log; 22 | import org.apache.commons.logging.LogFactory; 23 | import org.springframework.beans.factory.annotation.Autowired; 24 | import org.springframework.boot.CommandLineRunner; 25 | import org.springframework.stereotype.Component; 26 | 27 | @Component 28 | public class Listener implements CommandLineRunner { 29 | private static final Log logger = LogFactory.getLog(Listener.class); 30 | 31 | @Autowired 32 | Connection nc; 33 | 34 | private Dispatcher dispatcher; 35 | 36 | @Override 37 | public void run(String... args) { 38 | logger.info("starting autoconfigure listener with connection " + this.nc); 39 | 40 | this.dispatcher = this.nc.createDispatcher(m -> { 41 | logger.info("received message on " + m.getSubject() + " with reply to " + m.getReplyTo()); 42 | if (m.getReplyTo() != null) { 43 | nc.publish(m.getReplyTo(), m.getData()); 44 | } 45 | }); 46 | 47 | String subject = "dataIn"; 48 | 49 | if (args.length > 0) { 50 | subject = args[0]; 51 | } 52 | 53 | logger.info("subscribing to " + subject); 54 | this.dispatcher.subscribe(subject); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /nats-spring-samples/source-sample/src/main/java/io/nats/spring/TimedSource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.spring; 18 | 19 | import org.apache.commons.logging.Log; 20 | import org.apache.commons.logging.LogFactory; 21 | import org.springframework.beans.factory.annotation.Autowired; 22 | import org.springframework.cloud.stream.function.StreamBridge; 23 | import org.springframework.integration.support.MessageBuilder; 24 | import org.springframework.scheduling.annotation.EnableScheduling; 25 | import org.springframework.scheduling.annotation.Scheduled; 26 | import org.springframework.stereotype.Component; 27 | 28 | import java.nio.charset.StandardCharsets; 29 | import java.util.concurrent.atomic.AtomicLong; 30 | 31 | @Component 32 | @EnableScheduling 33 | public class TimedSource { 34 | private static final Log logger = LogFactory.getLog(TimedSource.class); 35 | private AtomicLong counter = new AtomicLong(0); 36 | 37 | @Autowired 38 | private StreamBridge streamBridge; 39 | 40 | @Scheduled(fixedRate = 2000) 41 | public void tick() { 42 | String msg = "message " + counter.incrementAndGet(); 43 | 44 | if (streamBridge == null) { 45 | logger.info("no output to send to - " + msg); 46 | return; 47 | } 48 | 49 | logger.info("sending - " + msg); 50 | streamBridge.send("timedchannel", MessageBuilder.withPayload(msg.getBytes(StandardCharsets.UTF_8)).build()); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /nats-spring-cloud-stream-binder/src/test/java/io/nats/cloud/stream/binder/DestinationNameTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.cloud.stream.binder; 18 | 19 | import org.junit.Test; 20 | import org.springframework.cloud.stream.provisioning.ProducerDestination; 21 | 22 | import static org.junit.Assert.assertEquals; 23 | 24 | public class DestinationNameTests { 25 | @Test 26 | public void testProducerNames() { 27 | String subject = "alpha"; 28 | NatsChannelProvisioner provisioner = new NatsChannelProvisioner(); 29 | ProducerDestination dest = provisioner.provisionProducerDestination(subject, null); 30 | 31 | assertEquals(subject, dest.getName()); 32 | assertEquals(subject + "-1", dest.getNameForPartition(1)); 33 | } 34 | 35 | @Test 36 | public void testConsumerNames() { 37 | String subject = "alpha"; 38 | String group = "beta"; 39 | NatsChannelProvisioner provisioner = new NatsChannelProvisioner(); 40 | NatsConsumerDestination dest = (NatsConsumerDestination) provisioner.provisionConsumerDestination(subject, group, null); 41 | 42 | assertEquals(subject, dest.getSubject()); 43 | assertEquals(group, dest.getQueueGroup()); 44 | 45 | dest = (NatsConsumerDestination) provisioner.provisionConsumerDestination(subject, null, null); 46 | 47 | assertEquals(subject, dest.getSubject()); 48 | assertEquals("", dest.getQueueGroup()); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /nats-spring-samples/multi-connect-sample/src/main/java/io/nats/spring/MultiConnectTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.spring; 18 | 19 | import org.slf4j.Logger; 20 | import org.slf4j.LoggerFactory; 21 | import org.springframework.context.annotation.Bean; 22 | import org.springframework.stereotype.Component; 23 | 24 | import java.nio.charset.StandardCharsets; 25 | import java.util.Objects; 26 | import java.util.function.Function; 27 | import java.util.stream.Collectors; 28 | import java.util.stream.IntStream; 29 | 30 | @Component 31 | public class MultiConnectTransformer { 32 | private static final Logger LOG = LoggerFactory.getLogger(MultiConnectTransformer.class); 33 | 34 | private static Object getMessage(String value) { 35 | String reverse = IntStream.iterate(value.length() - 1, i -> i >= 0, i -> i - 1) 36 | .mapToObj(i -> String.valueOf(value.charAt(i))).collect(Collectors.joining()); 37 | return reverse.getBytes(StandardCharsets.UTF_8); 38 | } 39 | 40 | @Bean 41 | public Function transform() { 42 | return message -> { 43 | String messageValue = null; 44 | if (message instanceof byte[]) { 45 | messageValue = new String((byte[]) message, StandardCharsets.UTF_8); 46 | } else if (message instanceof String value) { 47 | messageValue = value; 48 | } 49 | LOG.info("Message : {}", messageValue); 50 | return Objects.isNull(messageValue) ? null : getMessage(messageValue); 51 | }; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /nats-spring-cloud-stream-binder/src/main/java/io/nats/cloud/stream/binder/NatsConsumerDestination.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.cloud.stream.binder; 18 | 19 | import org.springframework.cloud.stream.provisioning.ConsumerDestination; 20 | 21 | /** 22 | * NatsConsumerDestinations use their name to determine the subject and queue group (if any) to listen to. 23 | */ 24 | public class NatsConsumerDestination implements ConsumerDestination { 25 | private String name; 26 | 27 | /** 28 | * Create a new consumer destination with the provided name. 29 | * 30 | * @param name compound name from the provisioner containing the subject and optional queue group 31 | */ 32 | public NatsConsumerDestination(String name) { 33 | this.name = name; 34 | } 35 | 36 | @Override 37 | public String getName() { 38 | return this.name; 39 | } 40 | 41 | /** 42 | * @return subject parsed from the name 43 | */ 44 | public String getSubject() { 45 | String[] parts = this.name.split("#"); 46 | 47 | if (parts.length > 2) { 48 | return parts[1]; 49 | } else { 50 | return parts[0]; 51 | } 52 | } 53 | 54 | /** 55 | * @return queue group parsed from the name, or an empty string if no queue should be used 56 | */ 57 | public String getQueueGroup() { 58 | String[] parts = this.name.split("#"); 59 | 60 | if (parts.length > 2) { 61 | return ""; 62 | } else if (parts.length == 2) { 63 | return parts[1]; 64 | } 65 | 66 | return ""; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /nats-spring-samples/connect-error-sample/src/main/java/io/nats/spring/ConnectErrorSample.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.spring; 18 | 19 | import io.nats.client.Connection; 20 | import io.nats.client.ConnectionListener; 21 | import io.nats.client.Consumer; 22 | import io.nats.client.ErrorListener; 23 | import org.springframework.boot.SpringApplication; 24 | import org.springframework.boot.autoconfigure.SpringBootApplication; 25 | import org.springframework.context.annotation.Bean; 26 | 27 | @SpringBootApplication 28 | public class ConnectErrorSample { 29 | 30 | public static void main(String[] args) { 31 | SpringApplication.run(ConnectErrorSample.class, args); 32 | } 33 | 34 | @Bean 35 | public ConnectionListener createConnectionListener() { 36 | return new ConnectionListener() { 37 | @Override 38 | public void connectionEvent(Connection conn, Events type) { 39 | System.out.println("## Custom status change " + type); 40 | } 41 | }; 42 | } 43 | 44 | @Bean 45 | public ErrorListener createErrorListener() { 46 | return new ErrorListener() { 47 | @Override 48 | public void slowConsumerDetected(Connection conn, Consumer consumer) { 49 | System.out.println("## slow consumer detected"); 50 | } 51 | 52 | @Override 53 | public void exceptionOccurred(Connection conn, Exception exp) { 54 | System.out.println("## exception occurred"); 55 | exp.printStackTrace(); 56 | } 57 | 58 | @Override 59 | public void errorOccurred(Connection conn, String error) { 60 | System.out.println("## error occurred " + error); 61 | } 62 | }; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /nats-spring-samples/polling-sample/src/main/java/io/nats/spring/PollingSample.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.spring; 18 | 19 | import org.apache.commons.logging.Log; 20 | import org.apache.commons.logging.LogFactory; 21 | import org.springframework.beans.factory.annotation.Qualifier; 22 | import org.springframework.boot.ApplicationRunner; 23 | import org.springframework.boot.SpringApplication; 24 | import org.springframework.boot.autoconfigure.SpringBootApplication; 25 | import org.springframework.cloud.stream.binder.PollableMessageSource; 26 | import org.springframework.context.annotation.Bean; 27 | import org.springframework.messaging.MessageChannel; 28 | 29 | import java.nio.charset.StandardCharsets; 30 | import java.util.concurrent.ExecutorService; 31 | import java.util.concurrent.Executors; 32 | 33 | @SpringBootApplication 34 | public class PollingSample { 35 | 36 | public static final ExecutorService exec = Executors.newSingleThreadExecutor(); 37 | private static final Log logger = LogFactory.getLog(PollingSample.class); 38 | 39 | public static void main(String[] args) { 40 | SpringApplication.run(PollingSample.class, args); 41 | } 42 | 43 | @Bean 44 | public ApplicationRunner runner(PollableMessageSource input, 45 | @Qualifier("errorChannel") MessageChannel output) { 46 | return args -> { 47 | exec.execute(() -> { 48 | while (true) { 49 | input.poll(message -> { 50 | byte[] bytes = (byte[]) message.getPayload(); 51 | String val = new String(bytes, StandardCharsets.UTF_8); 52 | logger.info("received message " + val); 53 | }); 54 | } 55 | }); 56 | }; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /nats-spring/src/test/resources/certs/ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIGjzCCBHegAwIBAgIJAKT2W9SKY7o4MA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD 3 | VQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzAR 4 | BgNVBAoTCkFwY2VyYSBJbmMxEDAOBgNVBAsTB25hdHMuaW8xEjAQBgNVBAMTCWxv 5 | Y2FsaG9zdDEcMBoGCSqGSIb3DQEJARYNZGVyZWtAbmF0cy5pbzAeFw0xNTExMDUy 6 | MzA2MTdaFw0xOTExMDQyMzA2MTdaMIGLMQswCQYDVQQGEwJVUzELMAkGA1UECBMC 7 | Q0ExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAoTCkFwY2VyYSBJbmMx 8 | EDAOBgNVBAsTB25hdHMuaW8xEjAQBgNVBAMTCWxvY2FsaG9zdDEcMBoGCSqGSIb3 9 | DQEJARYNZGVyZWtAbmF0cy5pbzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC 10 | ggIBAJOyBvFaREbmO/yaw8UD8u5vSk+Qrwdkfa0iHMo11nkcVtynHNKcgRUTkZBC 11 | xEZILVsuPa+WSUcUc0ej0TmuimrtOjXGn+LD0TrDVz6dd6lBufLXjo1fbUnKUjml 12 | TBYB2h7StDksrBPFnbEOVKN+qb1No4YxfvbJ6EK3xfnsm3dvamnetJugrmQ2EUlu 13 | glPNZDIShu9Fcsiq2hjw+dJ2Erl8kx2/PE8nOdcDG9I4wAM71pw9L1dHGmMOnTsq 14 | opLDVkMNjeIgMPxj5aIhvS8Tcnj16ZNi4h10587vld8fIdz+OgTDFMNi91PgZQmX 15 | 9puXraBGi5UEn0ly57IIY+aFkx74jPWgnVYz8w8G+W2GTFYQEVgHcPTJ4aIPjyRd 16 | m/cLelV34TMNCoTXmpIKVBkJY01t2awUYN0AcauhmD1L+ihY2lVk330lxQR11ZQ/ 17 | rjSRpG6jzb6diVK5wpNjsRRt5zJgZr6BMp0LYwJESGjt0sF0zZxixvHu8EctVle4 18 | zX6NHDic7mf4Wvo4rfnUyCGr7Y3OxB2vakq1fDZ1Di9OzpW/k8i/TE+mPRI5GTZt 19 | lR+c8mBxdV595EKHDxj0gY7PCM3Pe35p3oScWtfbpesTX6a7IL801ZwKKtN+4DOV 20 | mZhwiefztb/9IFPNXiuQnNh7mf7W2ob7SiGYct8iCLLjT64DAgMBAAGjgfMwgfAw 21 | HQYDVR0OBBYEFPDMEiYb7Np2STbm8j9qNj1aAvz2MIHABgNVHSMEgbgwgbWAFPDM 22 | EiYb7Np2STbm8j9qNj1aAvz2oYGRpIGOMIGLMQswCQYDVQQGEwJVUzELMAkGA1UE 23 | CBMCQ0ExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAoTCkFwY2VyYSBJ 24 | bmMxEDAOBgNVBAsTB25hdHMuaW8xEjAQBgNVBAMTCWxvY2FsaG9zdDEcMBoGCSqG 25 | SIb3DQEJARYNZGVyZWtAbmF0cy5pb4IJAKT2W9SKY7o4MAwGA1UdEwQFMAMBAf8w 26 | DQYJKoZIhvcNAQELBQADggIBAIkoO+svWiudydr4sQNv/XhDvH0GiWMjaI738fAB 27 | sGUKWXarXM9rsRtoQ78iwEBZmusEv0fmJ9hX275aZdduTJt4AnCBVptnSyMJS6K5 28 | RZF4ZQ3zqT3QOeWepLqszqRZHf+xNfl9JiXZc3pqNhoh1YXPubCgY+TY1XFSrL+u 29 | Wmbs3n56Cede5+dKwMpT9SfQ7nL1pwKihx16vlBGTjjvJ0RE5Tx+0VRcDgbtIF52 30 | pNlvjg9DL+UqP3S1WR0PcsUss/ygiC1NDegZr+I/04/wEG9Drwk1yPSshWsH90W0 31 | 7TmLDoWf5caAX62jOJtXbsA9JZ16RnIWy2iZYwg4YdE0rEeMbnDzrRucbyBahMX0 32 | mKc8C+rroW0TRTrqxYDQTE5gmAghCa9EixcwSTgMH/U6zsRbbY62m9WA5fKfu3n0 33 | z82+c36ijScHLgppTVosq+kkr/YE84ct56RMsg9esEKTxGxje812OSdHp/i2RzqW 34 | J59yo7KUn1nX7HsFvBVh9D8147J5BxtPztc0GtCQTXFT73nQapJjAd5J+AC5AB4t 35 | ShE+MRD+XIlPB/aMgtzz9Th8UCktVKoPOpFMC0SvFbbINWL/JO1QGhuZLMTKLjQN 36 | QBzjrETAOA9PICpI5hcPtTXz172X+I8/tIEFrZfew0Fdt/oAVcnb659zKiR8EuAq 37 | +Svp 38 | -----END CERTIFICATE----- 39 | -------------------------------------------------------------------------------- /nats-spring/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | nats-spring 7 | NATS Implementation for Spring 8 | 0.6.3+3.5-SNAPSHOT 9 | 10 | CNCF 11 | https://www.nats.io 12 | 13 | 14 | 15 | io.nats 16 | nats-spring-parent 17 | 0.6.3+3.5-SNAPSHOT 18 | ../pom.xml 19 | 20 | 21 | 22 | ${basedir}/.. 23 | 24 | 25 | 26 | 27 | io.nats 28 | jnats 29 | 2.21.1 30 | 31 | 32 | org.springframework.boot 33 | spring-boot 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-autoconfigure 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-configuration-processor 42 | ${spring-boot.version} 43 | true 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-autoconfigure-processor 48 | true 49 | ${spring-boot.version} 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-starter-test 54 | test 55 | ${spring-boot.version} 56 | 57 | 58 | junit 59 | junit 60 | test 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /nats-spring-cloud-stream-binder/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | nats-spring-cloud-stream-binder 7 | Spring Cloud Stream Binder for NATS 8 | 0.6.3+3.5-SNAPSHOT 9 | 10 | CNCF 11 | https://www.nats.io 12 | 13 | 14 | 15 | io.nats 16 | nats-spring-parent 17 | 0.6.3+3.5-SNAPSHOT 18 | ../pom.xml 19 | 20 | 21 | 22 | ${basedir}/.. 23 | 24 | 25 | 26 | 27 | io.nats 28 | jnats 29 | 2.21.1 30 | 31 | 32 | io.nats 33 | nats-spring 34 | 0.6.3+3.5-SNAPSHOT 35 | 36 | 37 | 38 | org.springframework.cloud 39 | spring-cloud-stream 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-configuration-processor 44 | true 45 | ${spring-boot.version} 46 | 47 | 48 | org.springframework.boot 49 | spring-boot-autoconfigure-processor 50 | true 51 | ${spring-boot.version} 52 | 53 | 54 | org.springframework.boot 55 | spring-boot-starter-test 56 | test 57 | ${spring-boot.version} 58 | 59 | 60 | junit 61 | junit 62 | test 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /project-management.md: -------------------------------------------------------------------------------- 1 | # Project Management 2 | 3 | This is just to note basic build processes. 4 | 5 | ### Version Format 6 | 7 | The version numbering is a combination of the normal semver plus the spring version, 8 | i.e. `1.2.3+3.1` 9 | 10 | ### GitHub Actions 11 | 12 | There are 2 GitHub actions: 13 | 14 | 1\. [Build Pull Request](.github/workflows/build-pr.yml) 15 | 16 | When a PR is submitted, this runs to compile and test the project. 17 | 18 | 2\. [Build Merge](.github/workflows/build-merge.yml) 19 | 20 | When a PR is merged, this runs to compile, test and publish the project. 21 | 22 | 23 | ### Version Management. 24 | 25 | The following pom.xml files all contain the version tag holding the version as shown in the format. 26 | Some may contain multiple tags due to dependencies. 27 | 28 | * [parent](pom.xml) 29 | * [demo](demo/pom.xml) 30 | * [nats-spring](nats-spring/pom.xml) 31 | * [nats-spring-boot-starter](nats-spring-boot-starter/pom.xml) 32 | * [nats-spring-cloud-stream-binder](nats-spring-cloud-stream-binder/pom.xml) 33 | * [nats-spring-samples parent](nats-spring-samples/pom.xml) 34 | * [nats-spring-samples autoconfigure](nats-spring-samples/autoconfigure-sample/pom.xml) 35 | * [nats-spring-samples connect-error](nats-spring-samples/connect-error-sample/pom.xml) 36 | * [nats-spring-samples listener-sample](nats-spring-samples/listener-sample/pom.xml) 37 | * [nats-spring-samples multi-connect](nats-spring-samples/multi-connect-sample/pom.xml) 38 | * [nats-spring-samples polling](nats-spring-samples/polling-sample/pom.xml) 39 | * [nats-spring-samples processor](nats-spring-samples/processor-sample/pom.xml) 40 | * [nats-spring-samples queue](nats-spring-samples/queue-sample/pom.xml) 41 | * [nats-spring-samples source](nats-spring-samples/source-sample/pom.xml) 42 | 43 | 44 | All `` tags in these files should match. 45 | 46 | i.e. `1.2.3+3.1` or `1.2.3+3.1-SNAPSHOT` 47 | 48 | When a PR is merged to main the project will be published either as a snapshot 49 | if the version contains `-SNAPSHOT`, otherwise a release will be published. 50 | 51 | ### Workflow 52 | 53 | When a version is in progress, all version tags should contain `-SNAPSHOT`, 54 | that way all merges to main will publish snapshots. 55 | 56 | When it's time to release, do the following: 57 | 58 | 1. Update all version tags to remove `-SNAPSHOT` 59 | 2. Push to a branch and make a PR. 60 | 3. Merge the PR. 61 | 62 | Once the release has been published, **IMMEDIATELY** ... 63 | 1. Update all version tags to increment the semver and add `-SNAPHOT` 64 | 2. Push a branch and make a PR. 65 | 3. Merge the PR. 66 | -------------------------------------------------------------------------------- /nats-spring-cloud-stream-binder/src/main/java/io/nats/cloud/stream/binder/NatsChannelProvisioner.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.cloud.stream.binder; 18 | 19 | import io.nats.client.NUID; 20 | import io.nats.cloud.stream.binder.properties.NatsConsumerProperties; 21 | import io.nats.cloud.stream.binder.properties.NatsProducerProperties; 22 | import org.springframework.cloud.stream.binder.ExtendedConsumerProperties; 23 | import org.springframework.cloud.stream.binder.ExtendedProducerProperties; 24 | import org.springframework.cloud.stream.provisioning.ConsumerDestination; 25 | import org.springframework.cloud.stream.provisioning.ProducerDestination; 26 | import org.springframework.cloud.stream.provisioning.ProvisioningException; 27 | import org.springframework.cloud.stream.provisioning.ProvisioningProvider; 28 | 29 | /** 30 | * Provisioners turn destination names into Destination objects. This is minimal for NATS where destination names are mapped to subjects. 31 | */ 32 | public class NatsChannelProvisioner implements ProvisioningProvider, ExtendedProducerProperties> { 33 | public NatsChannelProvisioner() { 34 | } 35 | 36 | @Override 37 | /** 38 | * @param subject for messages to go to 39 | * @param properties extended properties for the producer, unused 40 | * @return destination that will result in messages being sent to the provided subject 41 | */ 42 | public ProducerDestination provisionProducerDestination(String subject, ExtendedProducerProperties properties) 43 | throws ProvisioningException { 44 | return new NatsProducerDestination(subject); 45 | } 46 | 47 | @Override 48 | /** 49 | * @param subject to listen to messages on 50 | * @param group mapped to a queue group name in NATS 51 | * @param properties extended properties, unused 52 | * @return consumer desitation named based on the subject and group. 53 | */ 54 | public ConsumerDestination provisionConsumerDestination(String subject, String group, ExtendedConsumerProperties properties) 55 | throws ProvisioningException { 56 | String subscriptionName; 57 | 58 | if (group != null && group.length() > 0) { 59 | subscriptionName = subject + "#" + group; 60 | } else { 61 | subscriptionName = "anonymous#" + subject + "#" + NUID.nextGlobal(); 62 | } 63 | 64 | return new NatsConsumerDestination(subscriptionName); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /nats-spring-cloud-stream-binder/src/main/java/io/nats/cloud/stream/binder/NatsMessageHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.cloud.stream.binder; 18 | 19 | import io.nats.client.Connection; 20 | import org.apache.commons.logging.Log; 21 | import org.apache.commons.logging.LogFactory; 22 | import org.springframework.integration.handler.AbstractMessageHandler; 23 | import org.springframework.messaging.Message; 24 | import org.springframework.messaging.MessageHeaders; 25 | 26 | import java.nio.ByteBuffer; 27 | import java.nio.charset.StandardCharsets; 28 | 29 | /** 30 | * NatsMessageHandlers implement the standard message handling pattern. byte[], ByteBuffer and Strings are supported, where 31 | * Strings are treated as UTF8 bytes. 32 | */ 33 | public class NatsMessageHandler extends AbstractMessageHandler { 34 | private static final Log logger = LogFactory.getLog(NatsMessageHandler.class); 35 | 36 | private String subject; 37 | private Connection connection; 38 | 39 | /** 40 | * Create a handler with a specific, unchanging subject, and a NATS connection. 41 | * 42 | * @param subject where to send message to by default 43 | * @param nc NATS connection 44 | */ 45 | public NatsMessageHandler(String subject, Connection nc) { 46 | this.subject = subject; 47 | this.connection = nc; 48 | } 49 | 50 | @Override 51 | /** 52 | * Given a message, take the payload and publish it on the handlers subject. 53 | * If the message contains a MessageHeaders.REPLY_CHANNEL header, it is passed on to allow taking advantage of build-in request/reply handling 54 | * in Spring Integration / Spring Cloud Stream. 55 | */ 56 | protected void handleMessageInternal(Message message) { 57 | Object payload = message.getPayload(); 58 | byte[] bytes = null; 59 | 60 | if (payload instanceof byte[]) { 61 | bytes = (byte[]) payload; 62 | } else if (payload instanceof ByteBuffer) { 63 | ByteBuffer buf = ((ByteBuffer) payload); 64 | bytes = new byte[buf.remaining()]; 65 | buf.get(bytes); 66 | } else if (payload instanceof String) { 67 | bytes = ((String) payload).getBytes(StandardCharsets.UTF_8); 68 | } 69 | 70 | if (bytes == null) { 71 | logger.warn("NATS handler only supports byte array, byte buffer and string messages"); 72 | return; 73 | } 74 | 75 | if (this.connection != null) { 76 | final Object replyChannel = message.getHeaders().get(MessageHeaders.REPLY_CHANNEL); 77 | this.connection.publish(this.subject, replyChannel != null ? replyChannel.toString() : null, bytes); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /nats-spring/src/test/resources/certs/server-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIJKgIBAAKCAgEAtgHLcgRjeSqV/mHa8S2T0IHhWe0AP55pVzdj3G4UcniTRJyy 3 | PCtgfdhzBBbR8Ok5AIjTXTZihBPu08IFP6sLTDWYzzbRlIpL/LZIgr1wzosdaRRt 4 | BxZ95ov67PYcHeNMSby2YQQVMsEkUxsylSy+MDkYuoZRGzCw2NgSXwz3BLUERPDZ 5 | 754IVrjDGr2gYen8OCHS9mCUfNAvmiwSlFy3VppCjo6NbNlzUKDHhLGYw6gxYXwF 6 | DOU7tqKRtkQnGTTdMgU2mH9rMm3ua+Iyx5bvaY/5tf2yb/xuwg2JiAkwzYcDKMiA 7 | VUxdfwBh8QULjCjNiWguqfTLL1N2OHIZuxSODTJN3iUD0uQYqugF1jV2s9J6Tk2P 8 | 1uvbtQYYZ9TZ10APnFgEh54Vj7eepJPzryghcH+bU/vWny2mSC6PH9Goqvee86oE 9 | eLOahBpZmw8Ldf8lzg29UeKGm43M3+7UPmbEaHGzH5GqesiSFLQio2uiSCA9lrO6 10 | CYee133keBNvcmmNjdEYRhcBA2v6ZkZQJz4JW7SaEVfEAxlx9WnmcODiEoeJpG/Q 11 | pxqoGaefwAHnDkWJOmnNRtE/TPPsaTCt26XBHpzYRvnvn7/TbZNuALHwH1IfjMlF 12 | OPma2srnp4WBNye5cH5idZo/v/uqYohnPGt3dQO+fNpuGcyKIgru8vyqI5MCAwEA 13 | AQKCAgEAl6zBNUAxAW2a2AYGZgx8bTt/Z+hY16uUz8jqIG1f/tE6sOgApKHlZJp3 14 | pwW5aRGCnk5oDfrfeH///Fpo81kALj9QHAbr+uSRVIU3wjRLCOTn2oTaIxj8TJ+E 15 | ueqTHdko3x4zwn+bhtNsCRHWQnip+hfq4q5Ccu1Nwze1f56XUEXly+oHRGenPVX1 16 | yZgTSuWqecC+RPHRbH413T4zMY5efv5IzvI/K2G/doa2Hn+99fd5R2sJ7mguLhIm 17 | agU7rAbg+ulbSRSOadUw5pj3hlrjI06HY8GK7UYpqu+LGGHIWM7VtCv6vprII6lW 18 | 9Xsl12S9fG/ky1+j38mm8H0tsjj78t2L6ZDS2Fb9usbM5VhdQfQpTBTSfAEZPeus 19 | X2QTpTXnp5oHM7CzcQuGE25CruSHEJPy/Y0hTaunNBQ9VY6M/Pcq0sB0xAa0hN5H 20 | PqOae1/fNKR/7iwdptesNGguZoLnNd1yeVBdZ55SZw7+9hjIPAjn3iLNqfieSpXL 21 | 5lG+Z0JEUMW0f1MRmU9AsR2x4Dlpvulrn39Oc5vgc0JP+r7+MMpY5BpWS5WhTxqm 22 | tx1qh49yXFXIIEXqxjIIxQ3NO1del8QNDUGROnqlh5gFRADIcJpZMv8uAhSHEXm3 23 | +3PndJoCIfNv9gE8zNsB3r3PPgelG3wagy/eDe59PH0JvUmTWZkCggEBANxBkHAT 24 | LB5hkp3hAwmop62HgkG8k6Ht11q2qGgkO/EhfsgsZXTpI3LZZ3Nrf+5IZiwStloW 25 | iZwY/xocGL6tIFcuXHRqDDDPNRFUVxhSdcQd2mL7R6uin9eJ4ccQdaOXplQXOXFG 26 | G7wAIhfGR7JnyzS1+eKItdFYrU63BeavPLltE4GV4pFJIFXEXc3v87j/Ba9uIop1 27 | /zytEn37yzDxdptH0HYtCm4Ve17n0STwvf9Le7b3ZFbs/cj3akAoSOTy/bYKNZl4 28 | EtaT0T7AGr8qJIaAlUYtva30+sQ2ytXHOdjkKD38xTN2oXoHgAfn7wIinzM+rbGi 29 | d6FFIiARlp1g0O0CggEBANOLMJSvNeMxlM+8LJ0xo2J20Lk+1EGyb0+Ltp6jkrRW 30 | SPCvnNC7Ww6L6tRfCvatnb0qTvfR/HfM1oE2e2Q2QL+hZoZyxXEiZHd/ERyAj398 31 | uImSz8bkRPWzPZU0wqYO621MEdY+fPcQfZDMBlcA25cFlvuiCRoeRQ1DIREDKMMG 32 | Cnhbvv0f2J7e9rVAIqrTRtxKaRAIwU4YVIG2ymwWA+P/3/NFlYC344MGfoeum0NI 33 | qazULaAVKE99jV3sYC2twcrGgXel/OSGCX33WCVsQKIhIOGDib1KzyJHTBr+D8Tu 34 | rbO4fmyJtUpKC+XCIXto7ebbo0sVE2+7dp5ofBhCtn8CggEBALvBABkpnsA/OLZw 35 | qyA+rsET9IuI7uhoUN25OxGbYaWJggOtJMdmPZuXi8It7x32hXIoeV2OPLvd6wgc 36 | z1MrTZhDovhxtfadi4U8Ogo3sL//Grypq0y6EjuwA9CnTUCo81ZXfdX7h4TZMDbI 37 | BTIlnGlQfrUHCMZuKz4gcl1VIBSI0Mn0NPDYP0IdZEE6vK4EZppG7hbNw0e72Tmf 38 | vHP6QbrYmvFCL9PraAFc50HwHmZTuCAd/2DCIQyBLAeIz6qrIG9fgJVUb+qOkx5E 39 | sAgpKn2lepoaP8jcPi+o7XsSm1MyGsPMh2X5SGk3n4IdyfYuATuzwGjeL9A/mHlx 40 | xMxfTXkCggEAGYuTYEEQNtFD8Rn+ITVfT4KdjeEibJSJkIeEk/+YtaI9yKLMQwB8 41 | 7HLE9sRLZKJui+tSAecfn6/ir1PO7rkGdJ2e7dlqMlE+5Jc5j8GOkoyTFDngUVo7 42 | YZg1dZEbeEYQ8+/dr4t4N7WMFDIvCc6WtdP8+YIFq1vAZuuWUKGbCIHwPbyGgbaY 43 | yAaQsC6AgTRmOC/cJA2Kmk2h1tAl/YtjCONbPdtHRHXwSWA9Y1EYerWJl88/ezdS 44 | 2NaGfbMPojR7VGtIMxSeR1JQTx/RSyOZYnqxp8nkljE0diU58YCAkv1niG5dBepT 45 | NBdg/GvG80omgFxBic2PvUxb9KEVazCTLQKCAQEAwx3aNk2lMovLzuMRqj2O7rqs 46 | 4usiHDllR1S7vAySUqhBaL8l+y1lsulgCDExClt3SQpsaM5xep1sK5jN8REzKsE9 47 | xBgXkNRgy+/1VGa1Tx0DR6xLoAIYT7Ttm27kellAFLE1tEFsSdZP9ZcfwjYKQEuu 48 | Bsm4zf5duDb+hLraxK9ISqcc8ZUSlCLkj9GdhLwf+/8C81LXkS2ScR8Edumn8qe7 49 | IYqqWSYqKhaoqmx6sr8E0SIn6PKd7uXZnXTTxTf6AR1RNzFcStIL5lC06V6Savpa 50 | tSX2voU3DgUIDYrYUhDweukR8i+0nrkR8wRUUjxaAeegUIRHN5ffpk57lQNaNg== 51 | -----END RSA PRIVATE KEY----- 52 | -------------------------------------------------------------------------------- /demo/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.7.14 9 | 10 | 11 | io.nats 12 | demo 13 | 0.0.1-SNAPSHOT 14 | demo 15 | Demo project for Spring Boot 16 | 17 | 18 | 17 19 | 20 | 21 | 22 | 23 | io.nats 24 | nats-spring-cloud-stream-binder 25 | 0.6.3+3.5-SNAPSHOT 26 | 27 | 28 | io.nats 29 | nats-spring 30 | 0.6.3+3.5-SNAPSHOT 31 | 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-test 36 | test 37 | 38 | 39 | org.junit.vintage 40 | junit-vintage-engine 41 | 42 | 43 | junit 44 | junit 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-maven-plugin 55 | 56 | 57 | 58 | 59 | 60 | 61 | oss-sonatype 62 | oss-sonatype 63 | https://oss.sonatype.org/content/repositories/snapshots/ 64 | 65 | true 66 | 67 | 68 | 69 | spring-snapshots 70 | Spring Snapshots 71 | https://repo.spring.io/snapshot 72 | 73 | true 74 | 75 | 76 | 77 | spring-milestones 78 | Spring Milestones 79 | https://repo.spring.io/milestone 80 | 81 | 82 | 83 | 84 | spring-snapshots 85 | Spring Snapshots 86 | https://repo.spring.io/snapshot 87 | 88 | true 89 | 90 | 91 | 92 | spring-milestones 93 | Spring Milestones 94 | https://repo.spring.io/milestone 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /nats-spring-cloud-stream-binder/src/main/java/io/nats/cloud/stream/binder/NatsMessageSource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.cloud.stream.binder; 18 | 19 | import io.nats.client.Connection; 20 | import io.nats.client.Message; 21 | import io.nats.client.Subscription; 22 | import org.apache.commons.logging.Log; 23 | import org.apache.commons.logging.LogFactory; 24 | import org.springframework.context.Lifecycle; 25 | import org.springframework.integration.endpoint.AbstractMessageSource; 26 | import org.springframework.messaging.MessageHeaders; 27 | import org.springframework.messaging.support.GenericMessage; 28 | 29 | import java.time.Duration; 30 | import java.util.HashMap; 31 | import java.util.Map; 32 | 33 | /** 34 | * Message source for NATS connections, allowing synchronous polling. 35 | */ 36 | public class NatsMessageSource extends AbstractMessageSource implements Lifecycle { 37 | private static final Log logger = LogFactory.getLog(NatsMessageHandler.class); 38 | 39 | private NatsConsumerDestination destination; 40 | private Connection connection; 41 | private Subscription sub; 42 | 43 | /** 44 | * Create a message source. Once started, the source will have a subscription but no threads. 45 | * Calls to doReceive result in a nextMessage call at the NATS level. Currently nextMessage is 46 | * called with Duration.ZERO and will wait forever. 47 | * 48 | * @param destination where to subscribe 49 | * @param nc NATS connection 50 | */ 51 | public NatsMessageSource(NatsConsumerDestination destination, Connection nc) { 52 | this.destination = destination; 53 | this.connection = nc; 54 | } 55 | 56 | @Override 57 | protected Object doReceive() { 58 | if (this.sub == null) { 59 | return null; 60 | } 61 | 62 | try { 63 | Message m = this.sub.nextMessage(Duration.ZERO); 64 | 65 | if (m != null) { 66 | Map headers = new HashMap<>(); 67 | headers.put(NatsMessageProducer.SUBJECT, m.getSubject()); 68 | headers.put(MessageHeaders.REPLY_CHANNEL, m.getReplyTo()); 69 | GenericMessage gm = new GenericMessage(m.getData(), headers); 70 | return gm; 71 | } 72 | } catch (InterruptedException exp) { 73 | logger.info("wait for message interrupted"); 74 | } 75 | 76 | return null; 77 | } 78 | 79 | @Override 80 | public boolean isRunning() { 81 | return this.sub != null; 82 | } 83 | 84 | @Override 85 | public void start() { 86 | if (this.sub != null) { 87 | return; 88 | } 89 | 90 | String sub = this.destination.getSubject(); 91 | String queue = this.destination.getQueueGroup(); 92 | 93 | if (queue != null && queue.length() > 0) { 94 | this.sub = this.connection.subscribe(sub, queue); 95 | } else { 96 | this.sub = this.connection.subscribe(sub); 97 | } 98 | } 99 | 100 | @Override 101 | public void stop() { 102 | if (this.sub == null) { 103 | return; 104 | } 105 | 106 | this.sub.unsubscribe(); 107 | this.sub = null; 108 | } 109 | 110 | @Override 111 | public String getComponentType() { 112 | return "nats:message-source"; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /nats-spring/src/test/java/io/nats/spring/boot/autoconfigure/AutoconfigureTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.spring.boot.autoconfigure; 18 | 19 | import io.nats.client.Connection; 20 | import org.junit.Test; 21 | import org.springframework.boot.autoconfigure.AutoConfigurations; 22 | import org.springframework.boot.test.context.runner.ApplicationContextRunner; 23 | 24 | import java.io.IOException; 25 | import java.time.Duration; 26 | 27 | import static org.junit.Assert.assertEquals; 28 | import static org.junit.Assert.assertNotNull; 29 | import static org.junit.Assert.assertNull; 30 | import static org.junit.Assert.assertTrue; 31 | 32 | public class AutoconfigureTests { 33 | private final ApplicationContextRunner contextRunner = 34 | new ApplicationContextRunner().withConfiguration(AutoConfigurations.of(NatsAutoConfiguration.class)); 35 | 36 | @Test 37 | public void testDefaultConnection() throws IOException, InterruptedException { 38 | try (NatsTestServer ts = new NatsTestServer()) { 39 | this.contextRunner.withPropertyValues("nats.spring.server=" + ts.getURI(), 40 | "nats.spring.connectionTimeout=15s").run((context) -> { 41 | Connection conn = (Connection) context.getBean(Connection.class); 42 | assertNotNull(conn); 43 | assertTrue("Connected Status", Connection.Status.CONNECTED == conn.getStatus()); 44 | assertEquals(ts.getURI(), conn.getConnectedUrl()); 45 | assertEquals(Duration.ofSeconds(15), conn.getOptions().getConnectionTimeout()); 46 | }); 47 | } 48 | } 49 | 50 | @Test 51 | public void testSSLConnection() throws IOException, InterruptedException { 52 | try (NatsTestServer ts = new NatsTestServer("src/test/resources/tls.conf", false)) { 53 | this.contextRunner.withPropertyValues("nats.spring.server=" + ts.getURI(), 54 | "nats.spring.connectionTimeout=15s", 55 | "nats.spring.keystorepath=src/test/resources/keystore.jks", 56 | "nats.spring.keystorepassword=password", 57 | "nats.spring.truststorepath=src/test/resources/cacerts", 58 | "nats.spring.truststorepassword=password").run((context) -> { 59 | Connection conn = (Connection) context.getBean(Connection.class); 60 | assertNotNull(conn); 61 | assertTrue("Connected Status", Connection.Status.CONNECTED == conn.getStatus()); 62 | assertEquals(ts.getURI(), conn.getConnectedUrl()); 63 | assertEquals(Duration.ofSeconds(15), conn.getOptions().getConnectionTimeout()); 64 | }); 65 | } 66 | } 67 | 68 | @Test(expected = org.springframework.beans.factory.BeanNotOfRequiredTypeException.class) 69 | public void testNoParamNoConnection() throws IOException, InterruptedException { 70 | try (NatsTestServer ts = new NatsTestServer()) { 71 | this.contextRunner.run((context) -> { 72 | Object o = context.getBean(Connection.class); 73 | assertNull(o); 74 | }); 75 | } 76 | } 77 | 78 | @Test(expected = java.lang.IllegalStateException.class) 79 | public void testNoServer() throws IOException, InterruptedException { 80 | this.contextRunner.withPropertyValues("nats.spring.server=nodomain:3311").run((context) -> { 81 | Object o = context.getBean(Connection.class); 82 | assertNull(o); 83 | }); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /nats-spring-cloud-stream-binder/src/main/java/io/nats/cloud/stream/binder/NatsMessageProducer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.cloud.stream.binder; 18 | 19 | import io.nats.client.Connection; 20 | import io.nats.client.Dispatcher; 21 | import org.apache.commons.logging.Log; 22 | import org.apache.commons.logging.LogFactory; 23 | import org.springframework.context.Lifecycle; 24 | import org.springframework.integration.core.MessageProducer; 25 | import org.springframework.messaging.MessageChannel; 26 | import org.springframework.messaging.MessageHeaders; 27 | import org.springframework.messaging.support.GenericMessage; 28 | 29 | import java.util.HashMap; 30 | import java.util.Map; 31 | 32 | /** 33 | * MessageProducer for NATS connections. 34 | */ 35 | public class NatsMessageProducer implements MessageProducer, Lifecycle { 36 | private static final Log logger = LogFactory.getLog(NatsMessageProducer.class); 37 | 38 | /** 39 | * The NATS subject for incoming message is stored in the SUBJECT header. 40 | */ 41 | public static final String SUBJECT = "subject"; 42 | 43 | private NatsConsumerDestination destination; 44 | private Connection connection; 45 | private MessageChannel output; 46 | private Dispatcher dispatcher; 47 | 48 | /** 49 | * Create a message producer. Once started the producer will use a dispatcher, and the associated thread, to 50 | * listen for and handle incoming messages. 51 | * 52 | * @param destination where to subscribe 53 | * @param nc NATS connection 54 | */ 55 | public NatsMessageProducer(NatsConsumerDestination destination, Connection nc) { 56 | this.destination = destination; 57 | this.connection = nc; 58 | } 59 | 60 | @Override 61 | public MessageChannel getOutputChannel() { 62 | return this.output; 63 | } 64 | 65 | @Override 66 | public void setOutputChannel(MessageChannel outputChannel) { 67 | this.output = outputChannel; 68 | } 69 | 70 | @Override 71 | public boolean isRunning() { 72 | return this.dispatcher != null; 73 | } 74 | 75 | @Override 76 | public void start() { 77 | if (this.dispatcher != null) { 78 | return; 79 | } 80 | 81 | this.dispatcher = this.connection.createDispatcher((msg) -> { 82 | 83 | if (this.output == null) { 84 | logger.warn("skipping message, no output channel set for " + this.destination.getName()); 85 | return; 86 | } 87 | 88 | try { 89 | Map headers = new HashMap<>(); 90 | headers.put(SUBJECT, msg.getSubject()); 91 | headers.put(MessageHeaders.REPLY_CHANNEL, msg.getReplyTo()); 92 | GenericMessage m = new GenericMessage(msg.getData(), headers); 93 | this.output.send(m); 94 | } catch (Exception e) { 95 | logger.warn("exception sending message to output channel", e); 96 | } 97 | }); 98 | 99 | String sub = this.destination.getSubject(); 100 | String queue = this.destination.getQueueGroup(); 101 | 102 | if (queue != null && queue.length() > 0) { 103 | this.dispatcher.subscribe(sub, queue); 104 | } else { 105 | this.dispatcher.subscribe(sub); 106 | } 107 | } 108 | 109 | @Override 110 | public void stop() { 111 | if (this.dispatcher == null) { 112 | return; 113 | } 114 | 115 | this.connection.closeDispatcher(this.dispatcher); 116 | this.dispatcher = null; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /nats-spring/src/main/java/io/nats/spring/boot/autoconfigure/NatsAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.spring.boot.autoconfigure; 18 | 19 | import io.nats.client.Connection; 20 | import io.nats.client.ConnectionListener; 21 | import io.nats.client.Consumer; 22 | import io.nats.client.ErrorListener; 23 | import io.nats.client.Nats; 24 | import io.nats.client.Options; 25 | import org.apache.commons.logging.Log; 26 | import org.apache.commons.logging.LogFactory; 27 | import org.springframework.boot.autoconfigure.AutoConfiguration; 28 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 29 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 30 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 31 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 32 | import org.springframework.context.annotation.Bean; 33 | 34 | import java.io.IOException; 35 | import java.security.GeneralSecurityException; 36 | 37 | /** 38 | * NatsAutoConfiguration will create a NATS connection from an instance of NatsProperties. 39 | * A default connection and error handler is provided with basic logging. 40 | *

41 | * {@link EnableAutoConfiguration Auto-configuration} for NATS. 42 | */ 43 | @AutoConfiguration 44 | @ConditionalOnClass({Connection.class}) 45 | @EnableConfigurationProperties(NatsProperties.class) 46 | public class NatsAutoConfiguration { 47 | private static final Log logger = LogFactory.getLog(NatsAutoConfiguration.class); 48 | 49 | /** 50 | * @return NATS connection created with the provided properties. If no server URL is set the method will return null. 51 | * @throws IOException when a connection error occurs 52 | * @throws InterruptedException in the unusual case of a thread interruption during connect 53 | * @throws GeneralSecurityException if there is a problem authenticating the connection 54 | */ 55 | @Bean 56 | @ConditionalOnMissingBean 57 | public Connection natsConnection(NatsProperties properties, ConnectionListener connectionListener, ErrorListener errorListener) 58 | throws IOException, InterruptedException, GeneralSecurityException { 59 | Connection nc = null; 60 | String serverProp = (properties != null) ? properties.getServer() : null; 61 | 62 | if (serverProp == null || serverProp.length() == 0) { 63 | return null; 64 | } 65 | 66 | try { 67 | logger.info("autoconnecting to NATS with properties - " + properties); 68 | Options.Builder builder = properties.toOptionsBuilder(); 69 | 70 | builder = builder.connectionListener(connectionListener); 71 | 72 | builder = builder.errorListener(errorListener); 73 | 74 | nc = Nats.connect(builder.build()); 75 | } catch (Exception e) { 76 | logger.info("error connecting to nats", e); 77 | throw e; 78 | } 79 | return nc; 80 | } 81 | 82 | @Bean 83 | @ConditionalOnMissingBean 84 | public ConnectionListener defaultConnectionListener() { 85 | return new ConnectionListener() { 86 | public void connectionEvent(Connection conn, Events type) { 87 | logger.info("NATS connection status changed " + type); 88 | } 89 | }; 90 | } 91 | 92 | @Bean 93 | @ConditionalOnMissingBean 94 | public ErrorListener defaultErrorListener() { 95 | return new ErrorListener() { 96 | @Override 97 | public void slowConsumerDetected(Connection conn, Consumer consumer) { 98 | logger.info("NATS connection slow consumer detected"); 99 | } 100 | 101 | @Override 102 | public void exceptionOccurred(Connection conn, Exception exp) { 103 | logger.info("NATS connection exception occurred", exp); 104 | } 105 | 106 | @Override 107 | public void errorOccurred(Connection conn, String error) { 108 | logger.info("NATS connection error occurred " + error); 109 | } 110 | }; 111 | } 112 | 113 | 114 | } 115 | -------------------------------------------------------------------------------- /nats-spring-cloud-stream-binder/src/main/java/io/nats/cloud/stream/binder/NatsChannelBinderConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.cloud.stream.binder; 18 | 19 | import io.nats.client.ConnectionListener; 20 | import io.nats.client.ErrorListener; 21 | import io.nats.cloud.stream.binder.properties.NatsBinderConfigurationProperties; 22 | import io.nats.cloud.stream.binder.properties.NatsExtendedBindingProperties; 23 | import io.nats.spring.boot.autoconfigure.NatsAutoConfiguration; 24 | import io.nats.spring.boot.autoconfigure.NatsProperties; 25 | import org.springframework.beans.factory.annotation.Autowired; 26 | import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; 27 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 28 | import org.springframework.boot.context.properties.source.ConfigurationPropertyName; 29 | import org.springframework.cloud.stream.config.BindingHandlerAdvise.MappingsProvider; 30 | import org.springframework.context.annotation.Bean; 31 | import org.springframework.context.annotation.Configuration; 32 | import org.springframework.context.annotation.Import; 33 | 34 | import java.io.IOException; 35 | import java.util.Collections; 36 | 37 | @Configuration 38 | @Import({NatsAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class}) 39 | @EnableConfigurationProperties({NatsExtendedBindingProperties.class, NatsBinderConfigurationProperties.class}) 40 | /** 41 | * NatsChannelBinderConfiguration is used to parametrize a new NATS binder. This configuration provides custom error and connection listeners. 42 | */ 43 | public class NatsChannelBinderConfiguration { 44 | 45 | @Autowired(required = false) 46 | /** 47 | * A custom connection listener, otherwise a simple logging default is used. 48 | */ 49 | private ConnectionListener connectionListener; 50 | 51 | @Autowired(required = false) 52 | /** 53 | * A custom error listener, otherwise a simple logging default is used. 54 | */ 55 | private ErrorListener errorListener; 56 | 57 | @Autowired 58 | /** 59 | * The NatsProperties configured to define this binders NATS connections. These are configured globally. 60 | */ 61 | private NatsProperties natsProperties; 62 | 63 | @Autowired 64 | /** 65 | * Local configuration properties, with the same options as NatsProperties, but configured specifically for a binder. 66 | */ 67 | private NatsBinderConfigurationProperties natsBinderConfigurationProperties; 68 | 69 | @Autowired 70 | /** 71 | * Extended binding properties, unused currently. 72 | */ 73 | private NatsExtendedBindingProperties natsExtendedBindingProperties; 74 | 75 | /** 76 | * @return custom properties for this binding configuration 77 | */ 78 | public NatsBinderConfigurationProperties getNatsBinderConfigurationProperties() { 79 | return this.natsBinderConfigurationProperties; 80 | } 81 | 82 | /** 83 | * @param natsBinderConfigurationProperties custom properties for this configuration 84 | */ 85 | public void setNatsBinderConfigurationProperties(NatsBinderConfigurationProperties natsBinderConfigurationProperties) { 86 | this.natsBinderConfigurationProperties = natsBinderConfigurationProperties; 87 | } 88 | 89 | public NatsExtendedBindingProperties getNatsExtendedBindingProperties() { 90 | return this.natsExtendedBindingProperties; 91 | } 92 | 93 | public void setNatsExtendedBindingProperties(NatsExtendedBindingProperties natsExtendedBindingProperties) { 94 | this.natsExtendedBindingProperties = natsExtendedBindingProperties; 95 | } 96 | 97 | /** 98 | * @return global NATS connection properties associated with this binder configuration 99 | */ 100 | public NatsProperties getNatsProperties() { 101 | return this.natsProperties; 102 | } 103 | 104 | 105 | /** 106 | * @param natsProperties global NATS connection properties associated with this binder configuration 107 | */ 108 | public void setNatsProperties(NatsProperties natsProperties) { 109 | this.natsProperties = natsProperties; 110 | } 111 | 112 | @Bean 113 | /** 114 | * @return provisioner for NATS channels 115 | */ 116 | public NatsChannelProvisioner natsChannelProvisioner() { 117 | return new NatsChannelProvisioner(); 118 | } 119 | 120 | @Bean 121 | /** 122 | * @return binder, based on the channel provisioner, using the properties associated with this configuration 123 | */ 124 | public NatsChannelBinder natsBinder(NatsChannelProvisioner natsProvisioner) throws IOException, InterruptedException { 125 | NatsChannelBinder binder = new NatsChannelBinder(this.natsExtendedBindingProperties, 126 | this.natsBinderConfigurationProperties, 127 | this.natsProperties, natsProvisioner, 128 | this.connectionListener, 129 | this.errorListener); 130 | return binder.getConnection() != null ? binder : null; 131 | } 132 | 133 | @Bean 134 | /** 135 | * @return mapping between nats.spring.cloud.stream and nats.spring.cloud.stream 136 | */ 137 | public MappingsProvider natsExtendedPropertiesDefaultMappingsProvider() { 138 | return () -> Collections.singletonMap( 139 | ConfigurationPropertyName.of("nats.spring.cloud.stream"), 140 | ConfigurationPropertyName.of("nats.spring.cloud.stream")); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /nats-spring/src/main/resources/META-INF/spring-configuration-metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "groups": [ 3 | { 4 | "name": "nats.spring", 5 | "type": "io.nats.spring.boot.autoconfigure.NatsProperties", 6 | "sourceType": "io.nats.spring.boot.autoconfigure.NatsProperties" 7 | } 8 | ], 9 | "properties": [ 10 | { 11 | "name": "nats.spring.connection-name", 12 | "type": "java.lang.String", 13 | "description": "Connection name, shows up in thread names.", 14 | "sourceType": "io.nats.spring.boot.autoconfigure.NatsProperties" 15 | }, 16 | { 17 | "name": "nats.spring.connection-timeout", 18 | "type": "java.time.Duration", 19 | "description": "Timeout for the initial connection, if this time is passed, the connection will fail and no reconnect attempts are made.", 20 | "sourceType": "io.nats.spring.boot.autoconfigure.NatsProperties" 21 | }, 22 | { 23 | "name": "nats.spring.credentials", 24 | "type": "java.lang.String", 25 | "description": "User credentials file path, do not use with user\/password, or token, or NKey. Credentials are used by account enabled servers.", 26 | "sourceType": "io.nats.spring.boot.autoconfigure.NatsProperties" 27 | }, 28 | { 29 | "name": "nats.spring.inbox-prefix", 30 | "type": "java.lang.String", 31 | "description": "Prefix to use for inboxes, generally the default is used but custom prefixes can allow security controls.", 32 | "sourceType": "io.nats.spring.boot.autoconfigure.NatsProperties" 33 | }, 34 | { 35 | "name": "nats.spring.key-store-password", 36 | "type": "java.lang.Character[]", 37 | "description": "Password for the SSL keystore.", 38 | "sourceType": "io.nats.spring.boot.autoconfigure.NatsProperties" 39 | }, 40 | { 41 | "name": "nats.spring.key-store-path", 42 | "type": "java.lang.String", 43 | "description": "Path to the SSL keystore.", 44 | "sourceType": "io.nats.spring.boot.autoconfigure.NatsProperties" 45 | }, 46 | { 47 | "name": "nats.spring.key-store-provider", 48 | "type": "java.lang.String", 49 | "description": "Provider Algorithm for the the SSL key store, for verifying the server.", 50 | "sourceType": "io.nats.spring.boot.autoconfigure.NatsProperties" 51 | }, 52 | { 53 | "name": "nats.spring.key-store-type", 54 | "type": "java.lang.String", 55 | "description": "Type of SSL keystore, generally the default is used.", 56 | "sourceType": "io.nats.spring.boot.autoconfigure.NatsProperties" 57 | }, 58 | { 59 | "name": "nats.spring.max-reconnect", 60 | "type": "java.lang.Integer", 61 | "description": "Maximum reconnect attempts if a connection is lost, after the initial connection.", 62 | "sourceType": "io.nats.spring.boot.autoconfigure.NatsProperties" 63 | }, 64 | { 65 | "name": "nats.spring.nkey", 66 | "type": "java.lang.String", 67 | "description": "Private key (seed) for NKey authentication, do not use with user\/password, or token, or credentials.", 68 | "sourceType": "io.nats.spring.boot.autoconfigure.NatsProperties" 69 | }, 70 | { 71 | "name": "nats.spring.no-echo", 72 | "type": "java.lang.Boolean", 73 | "description": "Whether or not the server will send messages sent from this connection back to the connection.", 74 | "sourceType": "io.nats.spring.boot.autoconfigure.NatsProperties", 75 | "defaultValue": false 76 | }, 77 | { 78 | "name": "nats.spring.password", 79 | "type": "java.lang.String", 80 | "description": "Authentication password. Requires the username, but not the token, or credentials, or NKey.", 81 | "sourceType": "io.nats.spring.boot.autoconfigure.NatsProperties" 82 | }, 83 | { 84 | "name": "nats.spring.ping-interval", 85 | "type": "java.time.Duration", 86 | "description": "Time between pings to the server to check \"liveness\".", 87 | "sourceType": "io.nats.spring.boot.autoconfigure.NatsProperties" 88 | }, 89 | { 90 | "name": "nats.spring.reconnect-buffer-size", 91 | "type": "java.lang.Long", 92 | "description": "Size of the buffer, in bytes, used to hold outgoing messages during reconnect.", 93 | "sourceType": "io.nats.spring.boot.autoconfigure.NatsProperties" 94 | }, 95 | { 96 | "name": "nats.spring.reconnect-wait", 97 | "type": "java.time.Duration", 98 | "description": "Time to wait between reconnect attempts to the same server url.", 99 | "sourceType": "io.nats.spring.boot.autoconfigure.NatsProperties" 100 | }, 101 | { 102 | "name": "nats.spring.server", 103 | "type": "java.lang.String", 104 | "description": "URL for the nats server, can be a comma separated list.", 105 | "sourceType": "io.nats.spring.boot.autoconfigure.NatsProperties" 106 | }, 107 | { 108 | "name": "nats.spring.tls-protocol", 109 | "type": "java.lang.String", 110 | "description": "TLS Protocol version for the SSL Context Values: TLSv1.2, TLSv1.3", 111 | "sourceType": "io.nats.spring.boot.autoconfigure.NatsProperties" 112 | }, 113 | { 114 | "name": "nats.spring.token", 115 | "type": "java.lang.String", 116 | "description": "Authentication token, do not use with username\/password, or credentials, or NKey.", 117 | "sourceType": "io.nats.spring.boot.autoconfigure.NatsProperties" 118 | }, 119 | { 120 | "name": "nats.spring.trust-store-password", 121 | "type": "java.lang.Character[]", 122 | "description": "Password for the SSL trust store used to verify the server.", 123 | "sourceType": "io.nats.spring.boot.autoconfigure.NatsProperties" 124 | }, 125 | { 126 | "name": "nats.spring.trust-store-path", 127 | "type": "java.lang.String", 128 | "description": "Path the the SSL trust store, for verifying the server.", 129 | "sourceType": "io.nats.spring.boot.autoconfigure.NatsProperties" 130 | }, 131 | { 132 | "name": "nats.spring.trust-store-provider", 133 | "type": "java.lang.String", 134 | "description": "Provider Algorithm for the SSL trust store used to verify the server.", 135 | "sourceType": "io.nats.spring.boot.autoconfigure.NatsProperties" 136 | }, 137 | { 138 | "name": "nats.spring.trust-store-type", 139 | "type": "java.lang.String", 140 | "description": "Type of SSL trust store, generally the default is used.", 141 | "sourceType": "io.nats.spring.boot.autoconfigure.NatsProperties" 142 | }, 143 | { 144 | "name": "nats.spring.username", 145 | "type": "java.lang.String", 146 | "description": "Authentication user name. Requires the password, but not the token, or credentials, or NKey.", 147 | "sourceType": "io.nats.spring.boot.autoconfigure.NatsProperties" 148 | }, 149 | { 150 | "name": "nats.spring.utf8-support", 151 | "type": "java.lang.Boolean", 152 | "description": "Whether or not to treat subjects as UTF-8, the default is ASCII.", 153 | "sourceType": "io.nats.spring.boot.autoconfigure.NatsProperties", 154 | "defaultValue": false 155 | } 156 | ], 157 | "hints": [] 158 | } 159 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Apache Maven Wrapper startup batch script, version 3.2.0 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 28 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending 29 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 30 | @REM e.g. to debug Maven itself, use 31 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 32 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 33 | @REM ---------------------------------------------------------------------------- 34 | 35 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 36 | @echo off 37 | @REM set title of command window 38 | title %0 39 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 40 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 41 | 42 | @REM set %HOME% to equivalent of $HOME 43 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 44 | 45 | @REM Execute a user defined script before this one 46 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 47 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 48 | if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* 49 | if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* 50 | :skipRcPre 51 | 52 | @setlocal 53 | 54 | set ERROR_CODE=0 55 | 56 | @REM To isolate internal variables from possible post scripts, we use another setlocal 57 | @setlocal 58 | 59 | @REM ==== START VALIDATION ==== 60 | if not "%JAVA_HOME%" == "" goto OkJHome 61 | 62 | echo. 63 | echo Error: JAVA_HOME not found in your environment. >&2 64 | echo Please set the JAVA_HOME variable in your environment to match the >&2 65 | echo location of your Java installation. >&2 66 | echo. 67 | goto error 68 | 69 | :OkJHome 70 | if exist "%JAVA_HOME%\bin\java.exe" goto init 71 | 72 | echo. 73 | echo Error: JAVA_HOME is set to an invalid directory. >&2 74 | echo JAVA_HOME = "%JAVA_HOME%" >&2 75 | echo Please set the JAVA_HOME variable in your environment to match the >&2 76 | echo location of your Java installation. >&2 77 | echo. 78 | goto error 79 | 80 | @REM ==== END VALIDATION ==== 81 | 82 | :init 83 | 84 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 85 | @REM Fallback to current working directory if not found. 86 | 87 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 88 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 89 | 90 | set EXEC_DIR=%CD% 91 | set WDIR=%EXEC_DIR% 92 | :findBaseDir 93 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 94 | cd .. 95 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 96 | set WDIR=%CD% 97 | goto findBaseDir 98 | 99 | :baseDirFound 100 | set MAVEN_PROJECTBASEDIR=%WDIR% 101 | cd "%EXEC_DIR%" 102 | goto endDetectBaseDir 103 | 104 | :baseDirNotFound 105 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 106 | cd "%EXEC_DIR%" 107 | 108 | :endDetectBaseDir 109 | 110 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 111 | 112 | @setlocal EnableExtensions EnableDelayedExpansion 113 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 114 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 115 | 116 | :endReadAdditionalConfig 117 | 118 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" 123 | 124 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 125 | IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B 126 | ) 127 | 128 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 129 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 130 | if exist %WRAPPER_JAR% ( 131 | if "%MVNW_VERBOSE%" == "true" ( 132 | echo Found %WRAPPER_JAR% 133 | ) 134 | ) else ( 135 | if not "%MVNW_REPOURL%" == "" ( 136 | SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" 137 | ) 138 | if "%MVNW_VERBOSE%" == "true" ( 139 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 140 | echo Downloading from: %WRAPPER_URL% 141 | ) 142 | 143 | powershell -Command "&{"^ 144 | "$webclient = new-object System.Net.WebClient;"^ 145 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 146 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 147 | "}"^ 148 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ 149 | "}" 150 | if "%MVNW_VERBOSE%" == "true" ( 151 | echo Finished downloading %WRAPPER_JAR% 152 | ) 153 | ) 154 | @REM End of extension 155 | 156 | @REM If specified, validate the SHA-256 sum of the Maven wrapper jar file 157 | SET WRAPPER_SHA_256_SUM="" 158 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 159 | IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B 160 | ) 161 | IF NOT %WRAPPER_SHA_256_SUM%=="" ( 162 | powershell -Command "&{"^ 163 | "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ 164 | "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ 165 | " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ 166 | " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ 167 | " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ 168 | " exit 1;"^ 169 | "}"^ 170 | "}" 171 | if ERRORLEVEL 1 goto error 172 | ) 173 | 174 | @REM Provide a "standardized" way to retrieve the CLI args that will 175 | @REM work with both Windows and non-Windows executions. 176 | set MAVEN_CMD_LINE_ARGS=%* 177 | 178 | %MAVEN_JAVA_EXE% ^ 179 | %JVM_CONFIG_MAVEN_PROPS% ^ 180 | %MAVEN_OPTS% ^ 181 | %MAVEN_DEBUG_OPTS% ^ 182 | -classpath %WRAPPER_JAR% ^ 183 | "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ 184 | %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 185 | if ERRORLEVEL 1 goto error 186 | goto end 187 | 188 | :error 189 | set ERROR_CODE=1 190 | 191 | :end 192 | @endlocal & set ERROR_CODE=%ERROR_CODE% 193 | 194 | if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost 195 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 196 | if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" 197 | if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" 198 | :skipRcPost 199 | 200 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 201 | if "%MAVEN_BATCH_PAUSE%"=="on" pause 202 | 203 | if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% 204 | 205 | cmd /C exit /B %ERROR_CODE% 206 | -------------------------------------------------------------------------------- /nats-spring/src/test/java/io/nats/spring/boot/autoconfigure/PropertiesTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.spring.boot.autoconfigure; 18 | 19 | import io.nats.client.Options; 20 | import org.junit.Test; 21 | 22 | import java.net.URI; 23 | import java.time.Duration; 24 | 25 | import static org.junit.Assert.assertEquals; 26 | import static org.junit.Assert.assertFalse; 27 | import static org.junit.Assert.assertNotNull; 28 | import static org.junit.Assert.assertNull; 29 | import static org.junit.Assert.assertTrue; 30 | 31 | public class PropertiesTests { 32 | 33 | @Test 34 | public void testPropertySetters() throws Exception { 35 | String server = "nats://alphabet:4222"; 36 | String connectionName = "alpha"; 37 | Duration dura = Duration.ofSeconds(7); 38 | long size = 100; 39 | NatsConnectionProperties props = new NatsConnectionProperties(); 40 | 41 | props.setServer(server); 42 | props.setConnectionName(connectionName); 43 | props.setInboxPrefix(connectionName); 44 | props.setReconnectWait(dura); 45 | props.setConnectionTimeout(dura); 46 | props.setPingInterval(dura); 47 | props.setMaxReconnect((int) size); 48 | props.setReconnectBufferSize(size); 49 | 50 | Options options = props.toOptions(); 51 | URI[] servers = options.getServers().toArray(new URI[0]); 52 | assertEquals(1, servers.length); 53 | assertEquals(server, servers[0].toString()); 54 | assertEquals(connectionName, options.getConnectionName()); 55 | assertEquals(connectionName + ".", options.getInboxPrefix()); 56 | assertEquals(dura, options.getReconnectWait()); 57 | assertEquals(dura, options.getConnectionTimeout()); 58 | assertEquals(dura, options.getPingInterval()); 59 | assertEquals(size, options.getReconnectBufferSize()); 60 | assertEquals((int) size, options.getMaxReconnect()); 61 | assertFalse(options.isNoEcho()); 62 | assertFalse(options.supportUTF8Subjects()); 63 | assertNull(options.getUsername()); 64 | assertNull(options.getPassword()); 65 | 66 | props.setNoEcho(true); 67 | props.setUtf8Support(true); 68 | options = props.toOptions(); 69 | assertTrue(options.isNoEcho()); 70 | assertTrue(options.supportUTF8Subjects()); 71 | 72 | // Test authorization waterfall 73 | props.setUsername("user"); 74 | props.setPassword("pass"); 75 | options = props.toOptions(); 76 | assertEquals("user", options.getUsername()); 77 | assertEquals("pass", options.getPassword()); 78 | assertNull(options.getAuthHandler()); 79 | assertNull(options.getToken()); 80 | 81 | props.setToken("token"); 82 | options = props.toOptions(); 83 | assertEquals("token", options.getToken()); 84 | assertNull(options.getUsername()); 85 | assertNull(options.getPassword()); 86 | assertNull(options.getAuthHandler()); 87 | 88 | props.setCredentials("credentials"); 89 | options = props.toOptions(); 90 | assertNull(options.getToken()); 91 | assertNull(options.getUsername()); 92 | assertNull(options.getPassword()); 93 | assertNotNull(options.getAuthHandler()); 94 | assertEquals("FileAuthHandler", options.getAuthHandler().getClass().getSimpleName()); 95 | 96 | props.setNkey("nkey"); 97 | options = props.toOptions(); 98 | assertNull(options.getToken()); 99 | assertNull(options.getUsername()); 100 | assertNull(options.getPassword()); 101 | assertNotNull(options.getAuthHandler()); 102 | assertEquals("StringAuthHandler", options.getAuthHandler().getClass().getSimpleName()); 103 | 104 | props.setKeyStorePassword("password".toCharArray()); 105 | props.setKeyStorePath("src/test/resources/keystore.jks"); 106 | props.setKeyStoreType("SunX509"); 107 | props.setTrustStorePassword("password".toCharArray()); 108 | props.setTrustStorePath("src/test/resources/cacerts"); 109 | props.setTrustStoreType("SunX509"); 110 | options = props.toOptions(); 111 | assertNotNull(options.getSslContext()); 112 | } 113 | 114 | @Test 115 | public void testCommaListOfServers() throws Exception { 116 | String server1 = "nats://alphabet:4222"; 117 | String server2 = "nats://tebahpla:4222"; 118 | NatsConnectionProperties props = new NatsConnectionProperties(); 119 | 120 | props.setServer(server1 + "," + server2); 121 | 122 | Options options = props.toOptions(); 123 | URI[] servers = options.getServers().toArray(new URI[0]); 124 | assertEquals(2, servers.length); 125 | assertEquals(server1, servers[0].toString()); 126 | assertEquals(server2, servers[1].toString()); 127 | } 128 | 129 | @Test 130 | public void testFluentProperties() throws Exception { 131 | String server = "nats://alphabet:4222"; 132 | String connectionName = "alpha"; 133 | Duration dura = Duration.ofSeconds(7); 134 | long size = 100; 135 | NatsConnectionProperties props = new NatsConnectionProperties(); 136 | 137 | props = props.server(server); 138 | props = props.connectionName(connectionName); 139 | props = props.inboxPrefix(connectionName); 140 | props = props.reconnectWait(dura); 141 | props = props.connectionTimeout(dura); 142 | props = props.pingInterval(dura); 143 | props = props.maxReconnect((int) size); 144 | props = props.reconnectBufferSize(size); 145 | props = props.noEcho(true); 146 | props = props.utf8Support(true); 147 | 148 | Options options = props.toOptions(); 149 | URI[] servers = options.getServers().toArray(new URI[0]); 150 | assertEquals(1, servers.length); 151 | assertEquals(server, servers[0].toString()); 152 | assertEquals(connectionName, options.getConnectionName()); 153 | assertEquals(connectionName + ".", options.getInboxPrefix()); 154 | assertEquals(dura, options.getReconnectWait()); 155 | assertEquals(dura, options.getConnectionTimeout()); 156 | assertEquals(dura, options.getPingInterval()); 157 | assertEquals(size, options.getReconnectBufferSize()); 158 | assertEquals((int) size, options.getMaxReconnect()); 159 | assertTrue(options.isNoEcho()); 160 | assertTrue(options.supportUTF8Subjects()); 161 | assertNull(options.getUsername()); 162 | assertNull(options.getPassword()); 163 | 164 | // Test authorization waterfall 165 | props = props.username("user"); 166 | props = props.password("pass"); 167 | options = props.toOptions(); 168 | assertEquals("user", options.getUsername()); 169 | assertEquals("pass", options.getPassword()); 170 | assertNull(options.getAuthHandler()); 171 | assertNull(options.getToken()); 172 | 173 | props = props.token("token"); 174 | options = props.toOptions(); 175 | assertEquals("token", options.getToken()); 176 | assertNull(options.getUsername()); 177 | assertNull(options.getPassword()); 178 | assertNull(options.getAuthHandler()); 179 | 180 | props = props.credentials("credentials"); 181 | options = props.toOptions(); 182 | assertNull(options.getToken()); 183 | assertNull(options.getUsername()); 184 | assertNull(options.getPassword()); 185 | assertNotNull(options.getAuthHandler()); 186 | assertEquals("FileAuthHandler", options.getAuthHandler().getClass().getSimpleName()); 187 | 188 | props = props.nkey("nkey"); 189 | options = props.toOptions(); 190 | assertNull(options.getToken()); 191 | assertNull(options.getUsername()); 192 | assertNull(options.getPassword()); 193 | assertNotNull(options.getAuthHandler()); 194 | assertEquals("StringAuthHandler", options.getAuthHandler().getClass().getSimpleName()); 195 | 196 | props = props.keyStorePassword("password".toCharArray()); 197 | props = props.keyStorePath("src/test/resources/keystore.jks"); 198 | props = props.keyStoreType("SunX509"); 199 | props = props.trustStorePassword("password".toCharArray()); 200 | props = props.trustStorePath("src/test/resources/cacerts"); 201 | props = props.trustStoreType("SunX509"); 202 | options = props.toOptions(); 203 | assertNotNull(options.getSslContext()); 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /nats-spring-cloud-stream-binder/src/main/java/io/nats/cloud/stream/binder/NatsChannelBinder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-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 io.nats.cloud.stream.binder; 18 | 19 | import io.nats.client.Connection; 20 | import io.nats.client.ConnectionListener; 21 | import io.nats.client.Consumer; 22 | import io.nats.client.ErrorListener; 23 | import io.nats.client.Nats; 24 | import io.nats.client.Options; 25 | import io.nats.cloud.stream.binder.properties.NatsBinderConfigurationProperties; 26 | import io.nats.cloud.stream.binder.properties.NatsConsumerProperties; 27 | import io.nats.cloud.stream.binder.properties.NatsExtendedBindingProperties; 28 | import io.nats.cloud.stream.binder.properties.NatsProducerProperties; 29 | import io.nats.spring.boot.autoconfigure.NatsProperties; 30 | import org.apache.commons.logging.Log; 31 | import org.apache.commons.logging.LogFactory; 32 | import org.springframework.cloud.stream.binder.AbstractMessageChannelBinder; 33 | import org.springframework.cloud.stream.binder.BinderSpecificPropertiesProvider; 34 | import org.springframework.cloud.stream.binder.ExtendedConsumerProperties; 35 | import org.springframework.cloud.stream.binder.ExtendedProducerProperties; 36 | import org.springframework.cloud.stream.binder.ExtendedPropertiesBinder; 37 | import org.springframework.cloud.stream.provisioning.ConsumerDestination; 38 | import org.springframework.cloud.stream.provisioning.ProducerDestination; 39 | import org.springframework.integration.core.MessageProducer; 40 | import org.springframework.messaging.MessageChannel; 41 | import org.springframework.messaging.MessageHandler; 42 | 43 | /** 44 | * A NATS channel binder provides a NATS connection to the code attached to it. 45 | */ 46 | public class NatsChannelBinder extends 47 | AbstractMessageChannelBinder, ExtendedProducerProperties, NatsChannelProvisioner> 48 | implements ExtendedPropertiesBinder { 49 | private static final Log logger = LogFactory.getLog(NatsChannelBinder.class); 50 | private final NatsExtendedBindingProperties bindingProperties; 51 | private NatsBinderConfigurationProperties properties; 52 | private NatsProperties natsProperties; 53 | private Connection connection; 54 | 55 | /** 56 | * Create a binder with the specified properties. It is expected that either the NatsBinderConfigurationProperties will have a 57 | * server url set, or the NatsProperties will. They are preferred in that order, and only one server URL or server URL list is used. 58 | * The NatsProperties are considered global and a backup. If a connection or error listener is provided it is used, otherwise a default logging listener is assigned to avoid 59 | * silent errors. 60 | * 61 | * @param bindingProperties extended properties for future use 62 | * @param properties primary properties 63 | * @param natsProperties backup global properties 64 | * @param provisioningProvider provisioner for destination names 65 | * @param connectionListener custom connection listener 66 | * @param errorListener custom error listener 67 | */ 68 | public NatsChannelBinder(NatsExtendedBindingProperties bindingProperties, 69 | NatsBinderConfigurationProperties properties, 70 | NatsProperties natsProperties, 71 | NatsChannelProvisioner provisioningProvider, 72 | ConnectionListener connectionListener, 73 | ErrorListener errorListener) { 74 | super(null, provisioningProvider); // null for headers to embed 75 | this.bindingProperties = bindingProperties; 76 | this.properties = properties; 77 | this.natsProperties = natsProperties; 78 | 79 | try { 80 | Options.Builder builder = null; 81 | String bindingServer = (this.properties != null) ? this.properties.getServer() : null; 82 | String globalServer = (this.natsProperties != null) ? this.natsProperties.getServer() : null; 83 | 84 | // Use the binder properties first, if they don't have a server, try the global 85 | if (bindingServer != null && bindingServer.length() > 0) { 86 | logger.info("binder connecting to nats with named properties " + this.properties); 87 | builder = this.properties.toOptionsBuilder(); 88 | } else if (globalServer != null && globalServer.length() > 0) { 89 | logger.info("binder connecting to nats with global properties " + this.natsProperties); 90 | builder = this.natsProperties.toOptionsBuilder(); 91 | } else { 92 | this.connection = null; 93 | logger.info("unable to connect from binder to NATS no server properties where found"); 94 | return; 95 | } 96 | 97 | if (connectionListener != null) { 98 | builder = builder.connectionListener(connectionListener); 99 | } else { 100 | builder = builder.connectionListener(new ConnectionListener() { 101 | public void connectionEvent(Connection conn, Events type) { 102 | logger.info("NATS connection status changed " + type); 103 | } 104 | }); 105 | } 106 | 107 | if (errorListener != null) { 108 | builder = builder.errorListener(errorListener); 109 | } else { 110 | builder = builder.errorListener(new ErrorListener() { 111 | @Override 112 | public void slowConsumerDetected(Connection conn, Consumer consumer) { 113 | logger.info("NATS connection slow consumer detected"); 114 | } 115 | 116 | @Override 117 | public void exceptionOccurred(Connection conn, Exception exp) { 118 | logger.info("NATS connection exception occurred", exp); 119 | } 120 | 121 | @Override 122 | public void errorOccurred(Connection conn, String error) { 123 | logger.info("NATS connection error occurred " + error); 124 | } 125 | }); 126 | } 127 | 128 | this.connection = Nats.connect(builder.build()); 129 | } catch (Exception e) { 130 | logger.info("exception connecting binder to NATS", e); 131 | this.connection = null; 132 | } 133 | 134 | if (this.connection == null) { 135 | logger.info("unable to connect from binder to NATS"); 136 | } 137 | } 138 | 139 | /** 140 | * @return NATS connection 141 | */ 142 | public Connection getConnection() { 143 | return this.connection; 144 | } 145 | 146 | @Override 147 | protected MessageHandler createProducerMessageHandler(ProducerDestination destination, 148 | ExtendedProducerProperties producerProperties, MessageChannel errorChannel) { 149 | return new NatsMessageHandler(destination.getName(), this.connection); 150 | } 151 | 152 | @Override 153 | protected MessageProducer createConsumerEndpoint(ConsumerDestination destination, String group, 154 | ExtendedConsumerProperties properties) { 155 | return new NatsMessageProducer((NatsConsumerDestination) destination, this.connection); 156 | } 157 | 158 | @Override 159 | protected PolledConsumerResources createPolledConsumerResources(String name, String group, 160 | ConsumerDestination destination, ExtendedConsumerProperties consumerProperties) { 161 | return new PolledConsumerResources( 162 | new NatsMessageSource((NatsConsumerDestination) destination, this.connection), 163 | registerErrorInfrastructure(destination, group, consumerProperties, true)); 164 | } 165 | 166 | @Override 167 | public NatsConsumerProperties getExtendedConsumerProperties(String channelName) { 168 | return bindingProperties.getExtendedConsumerProperties(channelName); 169 | } 170 | 171 | @Override 172 | public NatsProducerProperties getExtendedProducerProperties(String channelName) { 173 | return bindingProperties.getExtendedProducerProperties(channelName); 174 | } 175 | 176 | @Override 177 | public String getDefaultsPrefix() { 178 | return bindingProperties.getDefaultsPrefix(); 179 | } 180 | 181 | @Override 182 | public Class getExtendedPropertiesEntryClass() { 183 | return bindingProperties.getExtendedPropertiesEntryClass(); 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /dependencies.md: -------------------------------------------------------------------------------- 1 | # External Dependencies 2 | 3 | This file lists the dependencies used in this repository. 4 | 5 | | Dependency | License | 6 | |------------------------------------------------------------------------|-----------------------------------------| 7 | | ch.qos.logback:logback-classic:jar:1.4.14 | EPL v1.0 and the LGPL 2.1 | 8 | | ch.qos.logback:logback-core:jar:1.4.14 | EPL v1.0 and the LGPL 2.1 | 9 | | com.fasterxml.jackson.core:jackson-annotations:jar:2.15.4 | Apache 2.0 License | 10 | | com.fasterxml.jackson.core:jackson-core:jar:2.15.4 | Apache 2.0 License | 11 | | com.fasterxml.jackson.core:jackson-databind:jar:2.15.4 | Apache 2.0 License | 12 | | com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.15.4 | Apache 2.0 License | 13 | | com.fasterxml:classmate:jar:1.5.1 | Apache 2.0 License | 14 | | com.jayway.jsonpath:json-path:jar:2.9.0 | Apache 2.0 License | 15 | | com.vaadin.external.google:android-json:jar:0.0.20131108.vaadin1 | Apache 2.0 License | 16 | | io.micrometer:micrometer-commons:jar:1.11.10 | Apache 2.0 License | 17 | | io.micrometer:micrometer-observation:jar:1.11.10 | Apache 2.0 License | 18 | | io.nats:jnats:jar:2.21.1 | Apache 2.0 License | 19 | | io.projectreactor:reactor-core:jar:3.5.15 | Apache 2.0 License | 20 | | jakarta.annotation:jakarta.annotation-api:jar:2.1.1 | BSD 3-Clause "New" or "Revised" License | 21 | | jakarta.validation:jakarta.validation-api:jar:3.0.2 | BSD 3-Clause "New" or "Revised" License | 22 | | jakarta.xml.bind:jakarta.xml.bind-api:jar:4.0.2 | BSD 3-Clause "New" or "Revised" License | 23 | | junit:junit:jar:4.13.2 | Eclipse Public License v2.0 | 24 | | net.bytebuddy:byte-buddy-agent:jar:1.14.12 | Apache 2.0 License | 25 | | net.bytebuddy:byte-buddy:jar:1.14.12 | Apache 2.0 License | 26 | | net.i2p.crypto:eddsa:jar:0.3.0:runtime | | 27 | | net.jodah:typetools:jar:0.6.2 | Apache 2.0 License | 28 | | net.minidev:accessors-smart:jar:2.4.11 | Apache 2.0 License | 29 | | net.minidev:json-smart:jar:2.4.11 | Apache 2.0 License | 30 | | org.apache.logging.log4j:log4j-api:jar:2.20.0 | Apache 2.0 License | 31 | | org.apache.logging.log4j:log4j-to-slf4j:jar:2.20.0 | Apache 2.0 License | 32 | | org.apache.tomcat.embed:tomcat-embed-el:jar:10.1.19 | Apache 2.0 License | 33 | | org.apiguardian:apiguardian-api:jar:1.1.2 | Apache 2.0 License | 34 | | org.assertj:assertj-core:jar:3.24.2 | Apache 2.0 License | 35 | | org.hamcrest:hamcrest-core:jar:2.2 | BSD 3-Clause "New" or "Revised" License | 36 | | org.hamcrest:hamcrest:jar:2.2 | BSD 3-Clause "New" or "Revised" License | 37 | | org.hibernate.validator:hibernate-validator:jar:8.0.1.Final | Apache 2.0 License | 38 | | org.jboss.logging:jboss-logging:jar:3.5.3.Final | Apache 2.0 License | 39 | | org.jetbrains.kotlin:kotlin-stdlib-common:jar:1.8.22 | Apache 2.0 License | 40 | | org.jetbrains.kotlin:kotlin-stdlib-jdk8:jar:1.8.22 | Apache 2.0 License | 41 | | org.jetbrains.kotlin:kotlin-stdlib:jar:1.8.22 | Apache 2.0 License | 42 | | org.jetbrains:annotations:jar:13.0 | Apache 2.0 License | 43 | | org.junit.jupiter:junit-jupiter-api:jar:5.9.3 | Eclipse Public License v2.0 | 44 | | org.junit.jupiter:junit-jupiter-engine:jar:5.9.3 | Eclipse Public License v2.0 | 45 | | org.junit.jupiter:junit-jupiter-params:jar:5.9.3 | Eclipse Public License v2.0 | 46 | | org.junit.jupiter:junit-jupiter:jar:5.9.3 | Eclipse Public License v2.0 | 47 | | org.junit.platform:junit-platform-commons:jar:1.9.3 | Eclipse Public License v2.0 | 48 | | org.junit.platform:junit-platform-engine:jar:1.9.3 | Eclipse Public License v2.0 | 49 | | org.mockito:mockito-core:jar:5.3.1 | MIT | 50 | | org.mockito:mockito-junit-jupiter:jar:5.3.1 | MIT | 51 | | org.objenesis:objenesis:jar:3.3 | Apache 2.0 License | 52 | | org.opentest4j:opentest4j:jar:1.2.0 | Apache 2.0 License | 53 | | org.ow2.asm:asm:jar:9.3 | BSD 3-Clause "New" or "Revised" License | 54 | | org.reactivestreams:reactive-streams:jar:1.0.4 | CC0 1.0 Universal | 55 | | org.skyscreamer:jsonassert:jar:1.5.1 | Apache 2.0 License | 56 | | org.slf4j:jul-to-slf4j:jar:2.0.12 | MIT | 57 | | org.slf4j:slf4j-api:jar:2.0.12 | MIT | 58 | | org.springframework.boot:spring-boot-autoconfigure-processor:jar:3.5.0 | Apache 2.0 License | 59 | | org.springframework.boot:spring-boot-autoconfigure:jar:3.5.0 | Apache 2.0 License | 60 | | org.springframework.boot:spring-boot-configuration-processor:jar:3.5.0 | Apache 2.0 License | 61 | | org.springframework.boot:spring-boot-starter-logging:jar:3.5.0 | Apache 2.0 License | 62 | | org.springframework.boot:spring-boot-starter-test:jar:3.5.0 | Apache 2.0 License | 63 | | org.springframework.boot:spring-boot-starter-validation:jar:3.5.0 | Apache 2.0 License | 64 | | org.springframework.boot:spring-boot-starter:jar:3.5.0 | Apache 2.0 License | 65 | | org.springframework.boot:spring-boot-test-autoconfigure:jar:3.5.0 | Apache 2.0 License | 66 | | org.springframework.boot:spring-boot-test:jar:3.5.0 | Apache 2.0 License | 67 | | org.springframework.boot:spring-boot:jar:3.5.0 | Apache 2.0 License | 68 | | org.springframework.cloud:spring-cloud-function-context:jar:4.2.1 | Apache 2.0 License | 69 | | org.springframework.cloud:spring-cloud-function-core:jar:4.2.1 | Apache 2.0 License | 70 | | org.springframework.cloud:spring-cloud-stream:jar:4.2.1 | Apache 2.0 License | 71 | | org.springframework.integration:spring-integration-core:jar:6.1.7 | Apache 2.0 License | 72 | | org.springframework.integration:spring-integration-jmx:jar:6.1.7 | Apache 2.0 License | 73 | | org.springframework.retry:spring-retry:jar:2.0.5 | Apache 2.0 License | 74 | | org.springframework:spring-aop:jar:6.0.18 | Apache 2.0 License | 75 | | org.springframework:spring-beans:jar:6.0.18 | Apache 2.0 License | 76 | | org.springframework:spring-context:jar:6.0.18 | Apache 2.0 License | 77 | | org.springframework:spring-core:jar:6.0.18 | Apache 2.0 License | 78 | | org.springframework:spring-expression:jar:6.0.18 | Apache 2.0 License | 79 | | org.springframework:spring-jcl:jar:6.0.18 | Apache 2.0 License | 80 | | org.springframework:spring-messaging:jar:6.0.18 | Apache 2.0 License | 81 | | org.springframework:spring-test:jar:6.0.18 | Apache 2.0 License | 82 | | org.springframework:spring-tx:jar:6.0.18 | Apache 2.0 License | 83 | | org.xmlunit:xmlunit-core:jar:2.9.1 | Apache 2.0 License | 84 | | org.yaml:snakeyaml:jar:1.33 | Apache 2.0 License | 85 | 86 | #### License Links 87 | 88 | [CC 1.0 Universal](https://creativecommons.org/publicdomain/zero/1.0/) 89 | 90 | [Eclipse Public License Version 2.0 ](http://www.eclipse.org/legal/epl-v20.html) 91 | 92 | [Apache 2.0 License](https://www.apache.org/licenses/LICENSE-2.0.html) 93 | 94 | [BSD Licenses](https://en.wikipedia.org/wiki/BSD_licenses) 95 | 96 | [MIT License](https://en.wikipedia.org/wiki/MIT_License) 97 | 98 | -------------------------------------------------------------------------------- /nats-spring/src/test/java/io/nats/spring/boot/autoconfigure/NatsTestServer.java: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2018 The NATS Authors 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at: 5 | // 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // 8 | // Unless required by applicable law or agreed to in writing, software 9 | // distributed under the License is distributed on an "AS IS" BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package io.nats.spring.boot.autoconfigure; 15 | 16 | import java.io.BufferedReader; 17 | import java.io.BufferedWriter; 18 | import java.io.File; 19 | import java.io.FileReader; 20 | import java.io.FileWriter; 21 | import java.io.IOException; 22 | import java.io.InputStreamReader; 23 | import java.util.ArrayList; 24 | import java.util.Arrays; 25 | import java.util.concurrent.atomic.AtomicInteger; 26 | import java.util.regex.Matcher; 27 | import java.util.regex.Pattern; 28 | 29 | /** 30 | * Class to run gnatds for tests. Highly based on the 1.0 client's NatsServer code. 31 | */ 32 | public class NatsTestServer implements AutoCloseable { 33 | 34 | private static final String NATS_SERVER = "nats-server"; 35 | 36 | // Use a new port each time, we increment and get so start at the normal port 37 | private static AtomicInteger portCounter = new AtomicInteger(5222); 38 | 39 | private int port; 40 | private boolean debug; 41 | private String configFilePath; 42 | private Process process; 43 | private String cmdLine; 44 | private String[] customArgs; 45 | private String[] configInserts; 46 | 47 | public NatsTestServer() { 48 | this(false); 49 | } 50 | 51 | public NatsTestServer(boolean debug) { 52 | this(NatsTestServer.nextPort(), debug); 53 | } 54 | 55 | public NatsTestServer(int port, boolean debug) { 56 | this.port = port; 57 | this.debug = debug; 58 | start(); 59 | } 60 | 61 | public NatsTestServer(String configFilePath, boolean debug) { 62 | this.configFilePath = configFilePath; 63 | this.debug = debug; 64 | this.port = nextPort(); 65 | start(); 66 | } 67 | 68 | public NatsTestServer(String configFilePath, String[] inserts, int port, boolean debug) { 69 | this.configFilePath = configFilePath; 70 | this.configInserts = inserts; 71 | this.debug = debug; 72 | this.port = port; 73 | start(); 74 | } 75 | 76 | public NatsTestServer(String configFilePath, int port, boolean debug) { 77 | this.configFilePath = configFilePath; 78 | this.debug = debug; 79 | this.port = port; 80 | start(); 81 | } 82 | 83 | public NatsTestServer(String[] customArgs, boolean debug) { 84 | this.port = NatsTestServer.nextPort(); 85 | this.debug = debug; 86 | this.customArgs = customArgs; 87 | start(); 88 | } 89 | 90 | public NatsTestServer(String[] customArgs, int port, boolean debug) { 91 | this.port = port; 92 | this.debug = debug; 93 | this.customArgs = customArgs; 94 | start(); 95 | } 96 | 97 | public static String generateNatsServerVersionString() { 98 | ArrayList cmd = new ArrayList(); 99 | 100 | String server_path = System.getenv("nats_server_path"); 101 | 102 | if (server_path == null) { 103 | server_path = NatsTestServer.NATS_SERVER; 104 | } 105 | 106 | cmd.add(server_path); 107 | cmd.add("--version"); 108 | 109 | try { 110 | ProcessBuilder pb = new ProcessBuilder(cmd); 111 | Process process = pb.start(); 112 | process.waitFor(); 113 | BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); 114 | ArrayList lines = new ArrayList(); 115 | String line = ""; 116 | while ((line = reader.readLine()) != null) { 117 | lines.add(line); 118 | } 119 | 120 | if (lines.size() > 0) { 121 | return lines.get(0); 122 | } 123 | 124 | return null; 125 | } catch (Exception exp) { 126 | return null; 127 | } 128 | } 129 | 130 | public static int nextPort() { 131 | return NatsTestServer.portCounter.incrementAndGet(); 132 | } 133 | 134 | public static int currentPort() { 135 | return NatsTestServer.portCounter.get(); 136 | } 137 | 138 | public static String getURIForPort(int port) { 139 | return "nats://localhost:" + port; 140 | } 141 | 142 | public void start() { 143 | ArrayList cmd = new ArrayList(); 144 | 145 | String server_path = System.getenv("nats_server_path"); 146 | 147 | if (server_path == null) { 148 | server_path = NatsTestServer.NATS_SERVER; 149 | } 150 | 151 | cmd.add(server_path); 152 | 153 | // Rewrite the port to a new one, so we don't reuse the same one over and over 154 | if (this.configFilePath != null) { 155 | Pattern pattern = Pattern.compile("port: (\\d+)"); 156 | Matcher matcher = pattern.matcher(""); 157 | BufferedReader read = null; 158 | File tmp = null; 159 | BufferedWriter write = null; 160 | String line; 161 | 162 | try { 163 | tmp = File.createTempFile("nats_java_test", ".conf"); 164 | write = new BufferedWriter(new FileWriter(tmp)); 165 | read = new BufferedReader(new FileReader(this.configFilePath)); 166 | 167 | while ((line = read.readLine()) != null) { 168 | matcher.reset(line); 169 | 170 | if (matcher.find()) { 171 | line = line.replace(matcher.group(1), String.valueOf(this.port)); 172 | } 173 | 174 | write.write(line); 175 | write.write("\n"); 176 | } 177 | 178 | if (configInserts != null) { 179 | for (String s : configInserts) { 180 | write.write(s); 181 | write.write("\n"); 182 | } 183 | } 184 | } catch (Exception exp) { 185 | System.out.println("%%% Error parsing config file for port."); 186 | return; 187 | } finally { 188 | if (read != null) { 189 | try { 190 | read.close(); 191 | } catch (Exception e) { 192 | throw new IllegalStateException("Failed to read config file"); 193 | } 194 | } 195 | if (write != null) { 196 | try { 197 | write.close(); 198 | } catch (Exception e) { 199 | throw new IllegalStateException("Failed to update config file"); 200 | } 201 | } 202 | } 203 | 204 | cmd.add("--config"); 205 | cmd.add(tmp.getAbsolutePath()); 206 | } else { 207 | cmd.add("--port"); 208 | cmd.add(String.valueOf(port)); 209 | } 210 | 211 | if (this.customArgs != null) { 212 | cmd.addAll(Arrays.asList(this.customArgs)); 213 | } 214 | 215 | if (debug) { 216 | cmd.add("-DV"); 217 | } 218 | 219 | this.cmdLine = String.join(" ", cmd); 220 | 221 | try { 222 | ProcessBuilder pb = new ProcessBuilder(cmd); 223 | 224 | if (debug) { 225 | System.out.println("%%% Starting [" + this.cmdLine + "] with redirected IO"); 226 | pb.inheritIO(); 227 | } else { 228 | String errFile = null; 229 | String osName = System.getProperty("os.name"); 230 | 231 | if (osName != null && osName.contains("Windows")) { 232 | // Windows uses the "nul" file. 233 | errFile = "nul"; 234 | } else { 235 | errFile = "/dev/null"; 236 | } 237 | 238 | pb.redirectError(new File(errFile)); 239 | } 240 | 241 | this.process = pb.start(); 242 | 243 | int tries = 10; 244 | // wait at least 1x and maybe 10 245 | do { 246 | try { 247 | Thread.sleep(100); 248 | } catch (Exception exp) { 249 | //Give the server time to get going 250 | } 251 | tries--; 252 | } while (!this.process.isAlive() && tries > 0); 253 | 254 | System.out.println("%%% Started [" + this.cmdLine + "]"); 255 | } catch (IOException ex) { 256 | System.out.println("%%% Failed to start [" + this.cmdLine + "] with message:"); 257 | System.out.println("\t" + ex.getMessage()); 258 | System.out.println("%%% Make sure that the nats-server is installed and in your PATH."); 259 | System.out.println("%%% See https://github.com/nats-io/nats-server for information on installation"); 260 | 261 | throw new IllegalStateException("Failed to run [" + this.cmdLine + "]"); 262 | } 263 | } 264 | 265 | public int getPort() { 266 | return this.port; 267 | } 268 | 269 | public String getURI() { 270 | return getURIForPort(this.port); 271 | } 272 | 273 | public void shutdown() { 274 | 275 | if (this.process == null) { 276 | return; 277 | } 278 | 279 | this.process.destroy(); 280 | 281 | System.out.println("%%% Shut down [" + this.cmdLine + "]"); 282 | 283 | this.process = null; 284 | } 285 | 286 | /** 287 | * Synonomous with shutdown. 288 | */ 289 | public void close() { 290 | shutdown(); 291 | } 292 | } 293 | -------------------------------------------------------------------------------- /nats-spring-cloud-stream-binder/src/test/java/io/nats/cloud/stream/binder/NatsBinderTestServer.java: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2018 The NATS Authors 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at: 5 | // 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // 8 | // Unless required by applicable law or agreed to in writing, software 9 | // distributed under the License is distributed on an "AS IS" BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package io.nats.cloud.stream.binder; 15 | 16 | import java.io.BufferedReader; 17 | import java.io.BufferedWriter; 18 | import java.io.File; 19 | import java.io.FileReader; 20 | import java.io.FileWriter; 21 | import java.io.IOException; 22 | import java.io.InputStreamReader; 23 | import java.util.ArrayList; 24 | import java.util.Arrays; 25 | import java.util.concurrent.atomic.AtomicInteger; 26 | import java.util.regex.Matcher; 27 | import java.util.regex.Pattern; 28 | 29 | /** 30 | * Class to run gnatds for tests. Highly based on the 1.0 client's NatsServer code. 31 | */ 32 | public class NatsBinderTestServer implements AutoCloseable { 33 | 34 | private static final String NATS_SERVER = "nats-server"; 35 | 36 | // Use a new port each time, we increment and get so start at the normal port 37 | private static AtomicInteger portCounter = new AtomicInteger(11223); 38 | 39 | private int port; 40 | private boolean debug; 41 | private String configFilePath; 42 | private Process process; 43 | private String cmdLine; 44 | private String[] customArgs; 45 | private String[] configInserts; 46 | 47 | public NatsBinderTestServer() { 48 | this(false); 49 | } 50 | 51 | public NatsBinderTestServer(boolean debug) { 52 | this(NatsBinderTestServer.nextPort(), debug); 53 | } 54 | 55 | public NatsBinderTestServer(int port, boolean debug) { 56 | this.port = port; 57 | this.debug = debug; 58 | start(); 59 | } 60 | 61 | public NatsBinderTestServer(String configFilePath, boolean debug) { 62 | this.configFilePath = configFilePath; 63 | this.debug = debug; 64 | this.port = nextPort(); 65 | start(); 66 | } 67 | 68 | public NatsBinderTestServer(String configFilePath, String[] inserts, int port, boolean debug) { 69 | this.configFilePath = configFilePath; 70 | this.configInserts = inserts; 71 | this.debug = debug; 72 | this.port = port; 73 | start(); 74 | } 75 | 76 | public NatsBinderTestServer(String configFilePath, int port, boolean debug) { 77 | this.configFilePath = configFilePath; 78 | this.debug = debug; 79 | this.port = port; 80 | start(); 81 | } 82 | 83 | public NatsBinderTestServer(String[] customArgs, boolean debug) { 84 | this.port = NatsBinderTestServer.nextPort(); 85 | this.debug = debug; 86 | this.customArgs = customArgs; 87 | start(); 88 | } 89 | 90 | public NatsBinderTestServer(String[] customArgs, int port, boolean debug) { 91 | this.port = NatsBinderTestServer.nextPort(); 92 | this.debug = debug; 93 | this.customArgs = customArgs; 94 | start(); 95 | } 96 | 97 | public static String generateNatsServerVersionString() { 98 | ArrayList cmd = new ArrayList(); 99 | 100 | String server_path = System.getenv("nats_server_path"); 101 | 102 | if (server_path == null) { 103 | server_path = NatsBinderTestServer.NATS_SERVER; 104 | } 105 | 106 | cmd.add(server_path); 107 | cmd.add("--version"); 108 | 109 | try { 110 | ProcessBuilder pb = new ProcessBuilder(cmd); 111 | Process process = pb.start(); 112 | process.waitFor(); 113 | BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); 114 | ArrayList lines = new ArrayList(); 115 | String line = ""; 116 | while ((line = reader.readLine()) != null) { 117 | lines.add(line); 118 | } 119 | 120 | if (lines.size() > 0) { 121 | return lines.get(0); 122 | } 123 | 124 | return null; 125 | } catch (Exception exp) { 126 | return null; 127 | } 128 | } 129 | 130 | public static int nextPort() { 131 | return NatsBinderTestServer.portCounter.incrementAndGet(); 132 | } 133 | 134 | public static int currentPort() { 135 | return NatsBinderTestServer.portCounter.get(); 136 | } 137 | 138 | public static String getURIForPort(int port) { 139 | return "nats://localhost:" + port; 140 | } 141 | 142 | public void start() { 143 | ArrayList cmd = new ArrayList(); 144 | 145 | String server_path = System.getenv("nats_server_path"); 146 | 147 | if (server_path == null) { 148 | server_path = NatsBinderTestServer.NATS_SERVER; 149 | } 150 | 151 | cmd.add(server_path); 152 | 153 | // Rewrite the port to a new one, so we don't reuse the same one over and over 154 | if (this.configFilePath != null) { 155 | Pattern pattern = Pattern.compile("port: (\\d+)"); 156 | Matcher matcher = pattern.matcher(""); 157 | BufferedReader read = null; 158 | File tmp = null; 159 | BufferedWriter write = null; 160 | String line; 161 | 162 | try { 163 | tmp = File.createTempFile("nats_java_test", ".conf"); 164 | write = new BufferedWriter(new FileWriter(tmp)); 165 | read = new BufferedReader(new FileReader(this.configFilePath)); 166 | 167 | while ((line = read.readLine()) != null) { 168 | matcher.reset(line); 169 | 170 | if (matcher.find()) { 171 | line = line.replace(matcher.group(1), String.valueOf(this.port)); 172 | } 173 | 174 | write.write(line); 175 | write.write("\n"); 176 | } 177 | 178 | if (configInserts != null) { 179 | for (String s : configInserts) { 180 | write.write(s); 181 | write.write("\n"); 182 | } 183 | } 184 | } catch (Exception exp) { 185 | System.out.println("%%% Error parsing config file for port."); 186 | return; 187 | } finally { 188 | if (read != null) { 189 | try { 190 | read.close(); 191 | } catch (Exception e) { 192 | throw new IllegalStateException("Failed to read config file"); 193 | } 194 | } 195 | if (write != null) { 196 | try { 197 | write.close(); 198 | } catch (Exception e) { 199 | throw new IllegalStateException("Failed to update config file"); 200 | } 201 | } 202 | } 203 | 204 | cmd.add("--config"); 205 | cmd.add(tmp.getAbsolutePath()); 206 | } else { 207 | cmd.add("--port"); 208 | cmd.add(String.valueOf(port)); 209 | } 210 | 211 | if (this.customArgs != null) { 212 | cmd.addAll(Arrays.asList(this.customArgs)); 213 | } 214 | 215 | if (debug) { 216 | cmd.add("-DV"); 217 | } 218 | 219 | this.cmdLine = String.join(" ", cmd); 220 | 221 | try { 222 | ProcessBuilder pb = new ProcessBuilder(cmd); 223 | 224 | if (debug) { 225 | System.out.println("%%% Starting [" + this.cmdLine + "] with redirected IO"); 226 | pb.inheritIO(); 227 | } else { 228 | String errFile = null; 229 | String osName = System.getProperty("os.name"); 230 | 231 | if (osName != null && osName.contains("Windows")) { 232 | // Windows uses the "nul" file. 233 | errFile = "nul"; 234 | } else { 235 | errFile = "/dev/null"; 236 | } 237 | 238 | pb.redirectError(new File(errFile)); 239 | } 240 | 241 | this.process = pb.start(); 242 | 243 | int tries = 10; 244 | // wait at least 1x and maybe 10 245 | do { 246 | try { 247 | Thread.sleep(100); 248 | } catch (Exception exp) { 249 | //Give the server time to get going 250 | } 251 | tries--; 252 | } while (!this.process.isAlive() && tries > 0); 253 | 254 | System.out.println("%%% Started [" + this.cmdLine + "]"); 255 | } catch (IOException ex) { 256 | System.out.println("%%% Failed to start [" + this.cmdLine + "] with message:"); 257 | System.out.println("\t" + ex.getMessage()); 258 | System.out.println("%%% Make sure that the nats-server is installed and in your PATH."); 259 | System.out.println("%%% See https://github.com/nats-io/nats-server for information on installation"); 260 | 261 | throw new IllegalStateException("Failed to run [" + this.cmdLine + "]"); 262 | } 263 | } 264 | 265 | public int getPort() { 266 | return this.port; 267 | } 268 | 269 | public String getURI() { 270 | return getURIForPort(this.port); 271 | } 272 | 273 | public void shutdown() { 274 | 275 | if (this.process == null) { 276 | return; 277 | } 278 | 279 | this.process.destroy(); 280 | 281 | System.out.println("%%% Shut down [" + this.cmdLine + "]"); 282 | 283 | this.process = null; 284 | } 285 | 286 | /** 287 | * Synonomous with shutdown. 288 | */ 289 | public void close() { 290 | shutdown(); 291 | } 292 | } 293 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | https://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | https://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # https://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Apache Maven Wrapper startup batch script, version 3.2.0 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | # e.g. to debug Maven itself, use 32 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | # ---------------------------------------------------------------------------- 35 | 36 | if [ -z "$MAVEN_SKIP_RC" ] ; then 37 | 38 | if [ -f /usr/local/etc/mavenrc ] ; then 39 | . /usr/local/etc/mavenrc 40 | fi 41 | 42 | if [ -f /etc/mavenrc ] ; then 43 | . /etc/mavenrc 44 | fi 45 | 46 | if [ -f "$HOME/.mavenrc" ] ; then 47 | . "$HOME/.mavenrc" 48 | fi 49 | 50 | fi 51 | 52 | # OS specific support. $var _must_ be set to either true or false. 53 | cygwin=false; 54 | darwin=false; 55 | mingw=false 56 | case "$(uname)" in 57 | CYGWIN*) cygwin=true ;; 58 | MINGW*) mingw=true;; 59 | Darwin*) darwin=true 60 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 61 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 62 | if [ -z "$JAVA_HOME" ]; then 63 | if [ -x "/usr/libexec/java_home" ]; then 64 | JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME 65 | else 66 | JAVA_HOME="/Library/Java/Home"; export JAVA_HOME 67 | fi 68 | fi 69 | ;; 70 | esac 71 | 72 | if [ -z "$JAVA_HOME" ] ; then 73 | if [ -r /etc/gentoo-release ] ; then 74 | JAVA_HOME=$(java-config --jre-home) 75 | fi 76 | fi 77 | 78 | # For Cygwin, ensure paths are in UNIX format before anything is touched 79 | if $cygwin ; then 80 | [ -n "$JAVA_HOME" ] && 81 | JAVA_HOME=$(cygpath --unix "$JAVA_HOME") 82 | [ -n "$CLASSPATH" ] && 83 | CLASSPATH=$(cygpath --path --unix "$CLASSPATH") 84 | fi 85 | 86 | # For Mingw, ensure paths are in UNIX format before anything is touched 87 | if $mingw ; then 88 | [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && 89 | JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" 90 | fi 91 | 92 | if [ -z "$JAVA_HOME" ]; then 93 | javaExecutable="$(which javac)" 94 | if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then 95 | # readlink(1) is not available as standard on Solaris 10. 96 | readLink=$(which readlink) 97 | if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then 98 | if $darwin ; then 99 | javaHome="$(dirname "\"$javaExecutable\"")" 100 | javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" 101 | else 102 | javaExecutable="$(readlink -f "\"$javaExecutable\"")" 103 | fi 104 | javaHome="$(dirname "\"$javaExecutable\"")" 105 | javaHome=$(expr "$javaHome" : '\(.*\)/bin') 106 | JAVA_HOME="$javaHome" 107 | export JAVA_HOME 108 | fi 109 | fi 110 | fi 111 | 112 | if [ -z "$JAVACMD" ] ; then 113 | if [ -n "$JAVA_HOME" ] ; then 114 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 115 | # IBM's JDK on AIX uses strange locations for the executables 116 | JAVACMD="$JAVA_HOME/jre/sh/java" 117 | else 118 | JAVACMD="$JAVA_HOME/bin/java" 119 | fi 120 | else 121 | JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" 122 | fi 123 | fi 124 | 125 | if [ ! -x "$JAVACMD" ] ; then 126 | echo "Error: JAVA_HOME is not defined correctly." >&2 127 | echo " We cannot execute $JAVACMD" >&2 128 | exit 1 129 | fi 130 | 131 | if [ -z "$JAVA_HOME" ] ; then 132 | echo "Warning: JAVA_HOME environment variable is not set." 133 | fi 134 | 135 | # traverses directory structure from process work directory to filesystem root 136 | # first directory with .mvn subdirectory is considered project base directory 137 | find_maven_basedir() { 138 | if [ -z "$1" ] 139 | then 140 | echo "Path not specified to find_maven_basedir" 141 | return 1 142 | fi 143 | 144 | basedir="$1" 145 | wdir="$1" 146 | while [ "$wdir" != '/' ] ; do 147 | if [ -d "$wdir"/.mvn ] ; then 148 | basedir=$wdir 149 | break 150 | fi 151 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 152 | if [ -d "${wdir}" ]; then 153 | wdir=$(cd "$wdir/.." || exit 1; pwd) 154 | fi 155 | # end of workaround 156 | done 157 | printf '%s' "$(cd "$basedir" || exit 1; pwd)" 158 | } 159 | 160 | # concatenates all lines of a file 161 | concat_lines() { 162 | if [ -f "$1" ]; then 163 | # Remove \r in case we run on Windows within Git Bash 164 | # and check out the repository with auto CRLF management 165 | # enabled. Otherwise, we may read lines that are delimited with 166 | # \r\n and produce $'-Xarg\r' rather than -Xarg due to word 167 | # splitting rules. 168 | tr -s '\r\n' ' ' < "$1" 169 | fi 170 | } 171 | 172 | log() { 173 | if [ "$MVNW_VERBOSE" = true ]; then 174 | printf '%s\n' "$1" 175 | fi 176 | } 177 | 178 | BASE_DIR=$(find_maven_basedir "$(dirname "$0")") 179 | if [ -z "$BASE_DIR" ]; then 180 | exit 1; 181 | fi 182 | 183 | MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR 184 | log "$MAVEN_PROJECTBASEDIR" 185 | 186 | ########################################################################################## 187 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 188 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 189 | ########################################################################################## 190 | wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" 191 | if [ -r "$wrapperJarPath" ]; then 192 | log "Found $wrapperJarPath" 193 | else 194 | log "Couldn't find $wrapperJarPath, downloading it ..." 195 | 196 | if [ -n "$MVNW_REPOURL" ]; then 197 | wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" 198 | else 199 | wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" 200 | fi 201 | while IFS="=" read -r key value; do 202 | # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) 203 | safeValue=$(echo "$value" | tr -d '\r') 204 | case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; 205 | esac 206 | done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" 207 | log "Downloading from: $wrapperUrl" 208 | 209 | if $cygwin; then 210 | wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") 211 | fi 212 | 213 | if command -v wget > /dev/null; then 214 | log "Found wget ... using wget" 215 | [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" 216 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 217 | wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" 218 | else 219 | wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" 220 | fi 221 | elif command -v curl > /dev/null; then 222 | log "Found curl ... using curl" 223 | [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" 224 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 225 | curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" 226 | else 227 | curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" 228 | fi 229 | else 230 | log "Falling back to using Java to download" 231 | javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" 232 | javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" 233 | # For Cygwin, switch paths to Windows format before running javac 234 | if $cygwin; then 235 | javaSource=$(cygpath --path --windows "$javaSource") 236 | javaClass=$(cygpath --path --windows "$javaClass") 237 | fi 238 | if [ -e "$javaSource" ]; then 239 | if [ ! -e "$javaClass" ]; then 240 | log " - Compiling MavenWrapperDownloader.java ..." 241 | ("$JAVA_HOME/bin/javac" "$javaSource") 242 | fi 243 | if [ -e "$javaClass" ]; then 244 | log " - Running MavenWrapperDownloader.java ..." 245 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" 246 | fi 247 | fi 248 | fi 249 | fi 250 | ########################################################################################## 251 | # End of extension 252 | ########################################################################################## 253 | 254 | # If specified, validate the SHA-256 sum of the Maven wrapper jar file 255 | wrapperSha256Sum="" 256 | while IFS="=" read -r key value; do 257 | case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; 258 | esac 259 | done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" 260 | if [ -n "$wrapperSha256Sum" ]; then 261 | wrapperSha256Result=false 262 | if command -v sha256sum > /dev/null; then 263 | if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then 264 | wrapperSha256Result=true 265 | fi 266 | elif command -v shasum > /dev/null; then 267 | if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then 268 | wrapperSha256Result=true 269 | fi 270 | else 271 | echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." 272 | echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." 273 | exit 1 274 | fi 275 | if [ $wrapperSha256Result = false ]; then 276 | echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 277 | echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 278 | echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 279 | exit 1 280 | fi 281 | fi 282 | 283 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 284 | 285 | # For Cygwin, switch paths to Windows format before running java 286 | if $cygwin; then 287 | [ -n "$JAVA_HOME" ] && 288 | JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") 289 | [ -n "$CLASSPATH" ] && 290 | CLASSPATH=$(cygpath --path --windows "$CLASSPATH") 291 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 292 | MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") 293 | fi 294 | 295 | # Provide a "standardized" way to retrieve the CLI args that will 296 | # work with both Windows and non-Windows executions. 297 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" 298 | export MAVEN_CMD_LINE_ARGS 299 | 300 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 301 | 302 | # shellcheck disable=SC2086 # safe args 303 | exec "$JAVACMD" \ 304 | $MAVEN_OPTS \ 305 | $MAVEN_DEBUG_OPTS \ 306 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 307 | "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 308 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 309 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | nats-spring-parent 7 | io.nats 8 | 0.6.3+3.5-SNAPSHOT 9 | pom 10 | 11 | 12 | org.springframework.cloud 13 | spring-cloud-build 14 | 3.1.8 15 | 16 | 17 | 18 | 19 | 3.5.0 20 | 4.2.1 21 | 4.13.2 22 | 17 23 | 17 24 | 17 25 | 26 | 0.6.0 27 | 28 | 29 | 30 | nats-spring 31 | nats-spring-boot-starter 32 | nats-spring-cloud-stream-binder 33 | nats-spring-samples 34 | 35 | 36 | 37 | 38 | central 39 | https://central.sonatype.com/repository/maven-snapshots 40 | 41 | 42 | central 43 | https://ossrh-staging-api.central.sonatype.com/service/local 44 | 45 | 46 | 47 | 48 | 49 | 50 | io.nats 51 | nats-spring-cloud-stream-binder 52 | ${project.version} 53 | 54 | 55 | 56 | org.springframework.boot 57 | spring-boot-dependencies 58 | ${spring-boot.version} 59 | pom 60 | import 61 | 62 | 63 | org.springframework.cloud 64 | spring-cloud-stream 65 | ${spring-cloud-stream.version} 66 | 67 | 68 | org.springframework.boot 69 | spring-boot 70 | ${spring-boot.version} 71 | 72 | 73 | org.springframework.boot 74 | spring-boot-autoconfigure 75 | ${spring-boot.version} 76 | 77 | 78 | org.springframework.boot 79 | spring-boot-configuration-processor 80 | true 81 | ${spring-boot.version} 82 | 83 | 84 | org.springframework.boot 85 | spring-boot-autoconfigure-processor 86 | true 87 | ${spring-boot.version} 88 | 89 | 90 | org.springframework.cloud 91 | spring-cloud-stream-binder-test 92 | ${spring-cloud-stream.version} 93 | test 94 | 95 | 96 | org.springframework.cloud 97 | spring-cloud-stream-test-support-internal 98 | ${spring-cloud-stream.version} 99 | test 100 | 101 | 102 | junit 103 | junit 104 | ${junit.version} 105 | test 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | org.apache.maven.plugins 125 | maven-antrun-plugin 126 | 1.7 127 | 128 | 129 | org.apache.maven.plugins 130 | maven-javadoc-plugin 131 | 132 | true 133 | 134 | 135 | 136 | org.apache.maven.plugins 137 | maven-surefire-plugin 138 | 139 | true 140 | 141 | 142 | 143 | 144 | 145 | 146 | org.apache.maven.plugins 147 | maven-compiler-plugin 148 | ${maven-compiler-plugin.version} 149 | 150 | ${java.version} 151 | ${java.version} 152 | -parameters 153 | true 154 | 155 | 156 | 157 | org.jacoco 158 | jacoco-maven-plugin 159 | 0.8.10 160 | 161 | 162 | 163 | prepare-agent 164 | 165 | 166 | 167 | 168 | report 169 | test 170 | 171 | report 172 | 173 | 174 | 175 | 176 | 177 | org.apache.maven.plugins 178 | maven-gpg-plugin 179 | 3.2.7 180 | 181 | 182 | sign-artifacts 183 | verify 184 | 185 | sign 186 | 187 | 188 | bc 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | org.sonatype.central 207 | central-publishing-maven-plugin 208 | 0.7.0 209 | true 210 | 211 | central 212 | true 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | spring 221 | 222 | 223 | spring-snapshots 224 | Spring Snapshots 225 | https://repo.spring.io/libs-snapshot-local 226 | 227 | true 228 | 229 | 230 | false 231 | 232 | 233 | 234 | spring-milestones 235 | Spring Milestones 236 | https://repo.spring.io/libs-milestone-local 237 | 238 | false 239 | 240 | 241 | 242 | spring-releases 243 | Spring Releases 244 | https://repo.spring.io/release 245 | 246 | false 247 | 248 | 249 | 250 | 251 | 252 | spring-snapshots 253 | Spring Snapshots 254 | https://repo.spring.io/libs-snapshot-local 255 | 256 | true 257 | 258 | 259 | false 260 | 261 | 262 | 263 | spring-milestones 264 | Spring Milestones 265 | https://repo.spring.io/libs-milestone-local 266 | 267 | false 268 | 269 | 270 | 271 | spring-releases 272 | Spring Releases 273 | https://repo.spring.io/libs-release-local 274 | 275 | false 276 | 277 | 278 | 279 | 280 | 281 | 282 | --------------------------------------------------------------------------------