├── .github ├── dependabot.yml ├── issue-template-checkStartSpringIO.md └── workflows │ ├── build-test.yml │ ├── checkStartSpringIO.yml │ ├── release.yml │ └── snapshot-release.yml ├── .gitignore ├── .gitmodules ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE ├── README.md ├── maven └── settings.xml ├── pom.xml ├── solace-spring-cloud-bom ├── README.md └── pom.xml ├── solace-spring-cloud-parent └── pom.xml ├── solace-spring-cloud-starters └── solace-spring-cloud-stream-starter │ ├── README.adoc │ ├── pom.xml │ └── solace-binder-5.x-migration-guide.adoc ├── solace-spring-cloud-stream-binder-opentelemetry ├── README.adoc ├── solace-spring-cloud-stream-binder-instrumentation-tests │ ├── pom.xml │ └── src │ │ └── test │ │ ├── java │ │ ├── com │ │ │ └── solace │ │ │ │ └── spring │ │ │ │ └── cloud │ │ │ │ └── stream │ │ │ │ └── binder │ │ │ │ └── instrumentation │ │ │ │ ├── springBootTests │ │ │ │ ├── SolaceBinderInstrumentationIT.java │ │ │ │ └── app │ │ │ │ │ ├── ConsumerConfig.java │ │ │ │ │ ├── DynamicDestinationProcessorConfig.java │ │ │ │ │ ├── ErrorHandlerConfig.java │ │ │ │ │ ├── MainApp.java │ │ │ │ │ ├── ManualAckConfig.java │ │ │ │ │ ├── ProcessorConfig.java │ │ │ │ │ └── SupplierConfig.java │ │ │ │ └── util │ │ │ │ ├── JaegerQueryUtil.java │ │ │ │ └── SempClientException.java │ │ └── io │ │ │ └── jaegertracing │ │ │ └── api_v3 │ │ │ ├── QueryServiceGrpc.java │ │ │ ├── QueryServiceOuterClass.java │ │ │ └── README.MD │ │ └── resources │ │ ├── application-bindingErrorHandler.yml │ │ ├── application-consumer.yml │ │ ├── application-dynamicDestinationProcessor.yml │ │ ├── application-globalErrorHandler.yml │ │ ├── application-manualAck.yml │ │ ├── application-processor.yml │ │ ├── application-supplier.yml │ │ └── otel-collector-config.yaml └── solace-spring-cloud-stream-binder-instrumentation │ ├── pom.xml │ └── src │ └── main │ └── java │ └── com │ └── solace │ └── spring │ └── cloud │ └── stream │ └── binder │ └── instrumentation │ ├── SolaceBinderConsumerInstrumentation.java │ └── SolaceBinderInstrumentationModule.java └── solace-spring-cloud-stream-binder ├── README.md ├── solace-spring-cloud-stream-binder-core ├── pom.xml └── src │ ├── main │ └── java │ │ └── com │ │ └── solace │ │ └── spring │ │ └── cloud │ │ └── stream │ │ └── binder │ │ ├── health │ │ ├── SolaceBinderHealthAccessor.java │ │ ├── base │ │ │ └── SolaceHealthIndicator.java │ │ ├── contributors │ │ │ ├── BindingHealthContributor.java │ │ │ ├── BindingsHealthContributor.java │ │ │ ├── FlowsHealthContributor.java │ │ │ └── SolaceBinderHealthContributor.java │ │ ├── handlers │ │ │ ├── SolaceFlowHealthEventHandler.java │ │ │ └── SolaceSessionEventHandler.java │ │ └── indicators │ │ │ ├── FlowHealthIndicator.java │ │ │ └── SessionHealthIndicator.java │ │ ├── inbound │ │ ├── BasicInboundXMLMessageListener.java │ │ ├── BatchCollector.java │ │ ├── InboundXMLMessageListener.java │ │ ├── JCSMPInboundChannelAdapter.java │ │ ├── JCSMPMessageSource.java │ │ ├── RetryableInboundXMLMessageListener.java │ │ └── acknowledge │ │ │ ├── JCSMPAcknowledgementCallback.java │ │ │ ├── JCSMPAcknowledgementCallbackFactory.java │ │ │ ├── JCSMPBatchAcknowledgementCallback.java │ │ │ ├── SolaceAckUtil.java │ │ │ └── TransactedJCSMPAcknowledgementCallback.java │ │ ├── messaging │ │ ├── HeaderMeta.java │ │ ├── SolaceBinderHeaderMeta.java │ │ ├── SolaceBinderHeaders.java │ │ ├── SolaceHeaderMeta.java │ │ └── SolaceHeaders.java │ │ ├── meter │ │ ├── SolaceMessageMeterBinder.java │ │ └── SolaceMeterAccessor.java │ │ ├── outbound │ │ └── JCSMPOutboundMessageHandler.java │ │ ├── properties │ │ ├── SmfMessageWriterProperties.java │ │ ├── SolaceBindingProperties.java │ │ ├── SolaceCommonProperties.java │ │ ├── SolaceConsumerProperties.java │ │ ├── SolaceExtendedBindingProperties.java │ │ ├── SolaceProducerProperties.java │ │ └── SolaceSessionHealthProperties.java │ │ ├── provisioning │ │ ├── EndpointProvider.java │ │ ├── ExpressionContextRoot.java │ │ ├── QueueNameDestinationEncoding.java │ │ ├── SolaceConsumerDestination.java │ │ ├── SolaceEndpointProvisioner.java │ │ ├── SolaceProducerDestination.java │ │ └── SolaceProvisioningUtil.java │ │ └── util │ │ ├── BatchProxyCorrelationKey.java │ │ ├── BatchWaitStrategy.java │ │ ├── ClosedChannelBindingException.java │ │ ├── CorrelationData.java │ │ ├── DestinationType.java │ │ ├── EndpointType.java │ │ ├── ErrorChannelSendingCorrelationKey.java │ │ ├── ErrorQueueInfrastructure.java │ │ ├── ErrorQueueRepublishCorrelationKey.java │ │ ├── FlowReceiverContainer.java │ │ ├── JCSMPSessionProducerManager.java │ │ ├── MessageContainer.java │ │ ├── SharedResourceManager.java │ │ ├── SmfMessageHeaderWriteCompatibility.java │ │ ├── SmfMessagePayloadWriteCompatibility.java │ │ ├── SolaceAcknowledgmentException.java │ │ ├── SolaceBatchAcknowledgementException.java │ │ ├── SolaceErrorMessageHandler.java │ │ ├── SolaceFlowEventHandler.java │ │ ├── SolaceMessageConversionException.java │ │ ├── SolaceMessageHeaderErrorMessageStrategy.java │ │ ├── StaticMessageHeaderMapAccessor.java │ │ ├── ToStringer.java │ │ ├── UnboundFlowReceiverContainerException.java │ │ └── XMLMessageMapper.java │ └── test │ ├── java │ └── com │ │ └── solace │ │ └── spring │ │ └── cloud │ │ └── stream │ │ └── binder │ │ ├── health │ │ ├── SolaceBinderHealthAccessorTest.java │ │ ├── base │ │ │ └── SolaceHealthIndicatorTest.java │ │ └── indicators │ │ │ ├── FlowHealthIndicatorTest.java │ │ │ └── SessionHealthIndicatorTest.java │ │ ├── inbound │ │ ├── BatchCollectorTest.java │ │ ├── InboundXMLMessageListenerTest.java │ │ └── acknowledge │ │ │ ├── JCSMPAcknowledgementCallbackFactoryIT.java │ │ │ └── SolaceAckUtilIT.java │ │ ├── messaging │ │ └── SolaceHeadersTest.java │ │ ├── meter │ │ ├── SolaceMessageMeterBinderTest.java │ │ └── SolaceMeterAccessorTest.java │ │ ├── outbound │ │ └── JCSMPOutboundMessageHandlerTest.java │ │ ├── properties │ │ ├── SmfMessageWriterPropertiesTest.java │ │ └── SolaceConsumerPropertiesTest.java │ │ ├── provisioning │ │ └── SolaceProvisioningUtilQueueNameTest.java │ │ ├── test │ │ ├── junit │ │ │ ├── extension │ │ │ │ └── pubsubplus │ │ │ │ │ └── provider │ │ │ │ │ └── PubSubPlusSpringProvider.java │ │ │ └── param │ │ │ │ └── provider │ │ │ │ └── SolaceSpringHeaderArgumentsProvider.java │ │ ├── spring │ │ │ ├── BatchedMessageCollector.java │ │ │ └── MessageGenerator.java │ │ └── util │ │ │ ├── RetryableAssertions.java │ │ │ ├── SerializableFoo.java │ │ │ └── ThrowingFunction.java │ │ └── util │ │ ├── BatchProxyCorrelationKeyTest.java │ │ ├── ErrorChannelSendingCorrelationKeyTest.java │ │ ├── ErrorQueueRepublishCorrelationKeyIT.java │ │ ├── FlowReceiverContainerIT.java │ │ ├── JmsCompatibilityIT.java │ │ ├── SolaceErrorMessageHandlerTest.java │ │ ├── StaticMessageHeaderMapAccessorTest.java │ │ └── XMLMessageMapperTest.java │ └── resources │ ├── META-INF │ └── services │ │ ├── com.solace.test.integration.junit.jupiter.extension.PubSubPlusExtension$ExternalProvider │ │ └── org.junit.jupiter.api.extension.Extension │ ├── junit-platform.properties │ └── logback.xml └── solace-spring-cloud-stream-binder ├── pom.xml └── src ├── main ├── java-templates │ └── com │ │ └── solace │ │ └── spring │ │ └── cloud │ │ └── stream │ │ └── binder │ │ └── config │ │ └── SolaceBinderClientInfoProvider.java ├── java │ └── com │ │ └── solace │ │ └── spring │ │ └── cloud │ │ └── stream │ │ └── binder │ │ ├── SolaceMessageChannelBinder.java │ │ └── config │ │ ├── ExtendedBindingHandlerMappingsProviderConfiguration.java │ │ ├── SolaceHealthIndicatorsConfiguration.java │ │ ├── SolaceMessageChannelBinderConfiguration.java │ │ ├── SolaceMeterConfiguration.java │ │ └── SolaceServiceAutoConfiguration.java └── resources │ └── META-INF │ ├── shared.beans │ ├── spring.binders │ └── spring │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports └── test ├── java └── com │ └── solace │ ├── it │ └── util │ │ └── semp │ │ ├── SempClientException.java │ │ ├── config │ │ └── BrokerConfiguratorBuilder.java │ │ └── monitor │ │ └── BrokerMonitorBuilder.java │ └── spring │ └── cloud │ └── stream │ └── binder │ ├── SolaceBinderBasicIT.java │ ├── SolaceBinderClientAckIT.java │ ├── SolaceBinderCustomErrorMessageHandlerIT.java │ ├── SolaceBinderDynamicMessagingIT.java │ ├── SolaceBinderHealthIT.java │ ├── SolaceBinderHealthIndicatorIT.java │ ├── SolaceBinderMessageConsistencyIT.java │ ├── SolaceBinderMeterIT.java │ ├── SolaceBinderNullPayloadIT.java │ ├── SolaceBinderProvisioningLifecycleIT.java │ ├── SolaceBinderSubscriptionsIT.java │ ├── config │ ├── SolaceBinderClientInfoProviderTest.java │ └── SolaceBinderConfigIT.java │ ├── health │ ├── handlers │ │ └── SolaceSessionEventHandlerTest.java │ └── indicators │ │ └── SolaceBinderHealthIndicatorTest.java │ ├── springBootTests │ ├── customizer │ │ ├── ProducerCustomizerIT.java │ │ └── SpringCloudStreamApp.java │ ├── multibinder │ │ ├── MultiBinderIT.java │ │ └── SpringCloudStreamApp.java │ └── oauth2 │ │ ├── MessagingServiceFreeTierBrokerTestContainerWithTlsAndOAuthSetup.java │ │ ├── MultiBinderOAuth2IT.java │ │ └── SpringCloudStreamOAuth2App.java │ └── test │ ├── junit │ ├── extension │ │ ├── SpringCloudStreamExtension.java │ │ └── pubsubplus │ │ │ └── provider │ │ │ └── PubSubPlusSpringProvider.java │ ├── launcher │ │ └── filter │ │ │ └── PostDiscoveryClassNameExclusionFilter.java │ └── param │ │ └── provider │ │ └── JCSMPMessageTypeArgumentsProvider.java │ ├── spring │ ├── BatchedMessageCollector.java │ ├── ConsumerInfrastructureUtil.java │ ├── MessageGenerator.java │ ├── MessageLayout.java │ ├── SpringCloudStreamContext.java │ └── configuration │ │ └── TestMeterRegistryConfiguration.java │ └── util │ ├── RetryableAssertions.java │ ├── SerializableFoo.java │ ├── SimpleJCSMPEventHandler.java │ ├── SolaceSpringCloudStreamAssertions.java │ ├── SolaceTestBinder.java │ ├── ThrowingFunction.java │ └── ThrowingSupplier.java └── resources ├── META-INF └── services │ ├── com.solace.test.integration.junit.jupiter.extension.PubSubPlusExtension$ExternalProvider │ ├── org.junit.jupiter.api.extension.Extension │ └── org.junit.platform.launcher.PostDiscoveryFilter ├── application-multibinder.yml ├── application-multibinderOAuth2.yml ├── application.properties ├── junit-platform.properties ├── logback.xml └── oauth2 ├── certs ├── README.txt ├── broker │ ├── solbroker.crt │ ├── solbroker.csr │ ├── solbroker.key │ └── solbroker.pem ├── client │ ├── client-keystore.jks │ ├── client-truststore.p12 │ ├── client.crt │ ├── client.csr │ ├── client.key │ ├── client.p12 │ └── client.pem ├── keycloak │ ├── keycloak.crt │ ├── keycloak.csr │ ├── keycloak.key │ └── keycloak.pem ├── keycloak_san.conf ├── rootCA │ ├── rootCA.crt │ ├── rootCA.der │ ├── rootCA.key │ ├── rootCA.pem │ └── rootCA.srl └── solbroker_san.conf ├── free-tier-broker-with-tls-and-oauth-docker-compose.yml ├── oauth ├── README ├── keycloak │ ├── solace-oauth-resource-server1-realm-export.json │ └── solace-oauth-resource-server2-realm-export.json ├── nginx.conf └── www │ └── index.html ├── solace.env └── solace_tls.env /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "maven" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | open-pull-requests-limit: 50 8 | allow: 9 | - dependency-name: "com.solace.*" 10 | - dependency-name: "com.solacesystems:*" 11 | - dependency-name: "org.springframework.*" 12 | - dependency-name: "io.opentelemetry.*" 13 | -------------------------------------------------------------------------------- /.github/issue-template-checkStartSpringIO.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Check start.spring.io 3 | --- 4 | 5 | ### Context 6 | [Failed Run](https://github.com/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}) 7 | Workflow name = `{{ env.GITHUB_WORKFLOW }}` 8 | Job - `{{ env.GITHUB_JOB }}` 9 | ### Error Info 10 | See Failed Run link above for more info, but the likely culprit is a new version of Spring Boot has been released and we need to open an issue over at [start.spring.io](https://github.com/spring-io/start.spring.io/issues) to have them re-enable Solace. -------------------------------------------------------------------------------- /.github/workflows/build-test.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build and test a Java project with Maven 2 | 3 | name: Test 4 | 5 | on: 6 | pull_request: 7 | push: 8 | workflow_dispatch: 9 | 10 | jobs: 11 | dupe_check: 12 | name: Check for Duplicate Workflow Run 13 | runs-on: ubuntu-latest 14 | outputs: 15 | should_skip: ${{ steps.skip_check.outputs.should_skip }} 16 | steps: 17 | - id: skip_check 18 | uses: fkirc/skip-duplicate-actions@v5.3.1 19 | with: 20 | concurrent_skipping: same_content_newer 21 | do_not_skip: '["pull_request", "workflow_dispatch", "schedule"]' 22 | 23 | build: 24 | name : Build & Test 25 | needs: 26 | - dupe_check 27 | if: needs.dupe_check.outputs.should_skip != 'true' 28 | runs-on: ubuntu-latest 29 | 30 | steps: 31 | - uses: actions/checkout@v4 32 | - name: Setup JDK 17 33 | uses: actions/setup-java@v4 34 | with: 35 | distribution: zulu 36 | java-version: 17 37 | cache: maven 38 | - name: Build and run Tests 39 | run: mvn clean verify 40 | - name: Upload Test Artifacts 41 | if: always() 42 | uses: actions/upload-artifact@v4 43 | with: 44 | name: Test Results 45 | path: | 46 | **/target/failsafe-reports/*.xml 47 | **/target/surefire-reports/*.xml 48 | - name: Publish Unit Test Results 49 | if: ${{ !cancelled() && (github.actor != 'dependabot[bot]' || (github.event_name == 'push' && !contains(github.ref, 'dependabot'))) }} 50 | uses: EnricoMi/publish-unit-test-result-action@v2 51 | continue-on-error: true 52 | with: 53 | fail_on: nothing 54 | junit_files: | 55 | **/target/failsafe-reports/*.xml 56 | !**/target/failsafe-reports/failsafe-summary.xml 57 | **/target/surefire-reports/*.xml 58 | -------------------------------------------------------------------------------- /.github/workflows/checkStartSpringIO.yml: -------------------------------------------------------------------------------- 1 | name: start.spring.io checker 2 | on: 3 | schedule: 4 | # Run at midnight every day 5 | - cron: "0 0 * * *" 6 | # Allows you to run this workflow manually from the Actions tab 7 | workflow_dispatch: 8 | 9 | jobs: 10 | # This workflow contains a single job called "build" 11 | build: 12 | # The type of runner that the job will run on 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | - name: Query start.spring.io 17 | id: checkStartSpringIO 18 | uses: fjogeleit/http-request-action@v1.11.1 19 | with: 20 | url: https://start.spring.io/pom.xml?dependencies=solace,cloud-stream 21 | # url: https://start.spring.io/pom.xml?bootVersion=3.0.0-SNAPSHOT&dependencies=solace,cloud-stream 22 | - name: Check Response 23 | run: | 24 | echo ${{ steps.checkStartSpringIO.outputs.response }} 25 | echo ${{ steps.checkStartSpringIO.outputs.headers }} 26 | - name: Create Issue Action 27 | uses: JasonEtco/create-an-issue@v2.9.1 28 | if: ${{ failure() }} # only run when this job is failed. 29 | env: 30 | GITHUB_JOB: ${{ github.job }} 31 | GITHUB_REPOSITORY: ${{ github.repository }} 32 | GITHUB_RUN_ID: ${{ github.run_id }} 33 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 34 | GITHUB_WORKFLOW: ${{ github.workflow }} 35 | with: 36 | filename: .github/issue-template-checkStartSpringIO.md 37 | update_existing: true 38 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release to Maven Central 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | release: 8 | runs-on: ubuntu-latest 9 | permissions: 10 | contents: write 11 | packages: write 12 | id-token: write 13 | 14 | steps: 15 | - name: Checkout repository 16 | uses: actions/checkout@v4 17 | 18 | - name: Set up JDK 17 19 | uses: actions/setup-java@v4 20 | with: 21 | java-version: '17' 22 | distribution: 'zulu' 23 | 24 | - name: Retrieve secrets from Vault 25 | id: secrets 26 | uses: hashicorp/vault-action@v3 27 | continue-on-error: true 28 | with: 29 | url: "${{ secrets.VAULT_ADDR }}" 30 | role: "cicd-workflows-secret-read-role" 31 | method: jwt 32 | path: jwt-github 33 | jwtGithubAudience: https://github.com/${{ github.repository_owner }} 34 | exportToken: true 35 | secrets: secret/data/tools/githubactions PACKAGES_ADMIN_USER | PACKAGES_ADMIN_USER ; 36 | secret/data/tools/githubactions PACKAGES_ADMIN_TOKEN | PACKAGES_ADMIN_TOKEN ; 37 | secret/data/tools/githubactions MAVEN_GPG_KEY_PASSPHRASE | MAVEN_GPG_KEY_PASSPHRASE ; 38 | secret/data/tools/githubactions MAVEN_GPG_KEY | MAVEN_GPG_KEY ; 39 | secret/data/tools/githubactions MAVEN_OSSRH_USER | MAVEN_OSSRH_USER ; 40 | secret/data/tools/githubactions MAVEN_OSSRH_PASS | MAVEN_OSSRH_PASS ; 41 | 42 | - name: Import GPG key 43 | uses: crazy-max/ghaction-import-gpg@cb9bde2e2525e640591a934b1fd28eef1dcaf5e5 #v6.2.0 44 | with: 45 | gpg_private_key: ${{ steps.secrets.outputs.MAVEN_GPG_KEY }} 46 | passphrase: ${{ steps.secrets.outputs.MAVEN_GPG_KEY_PASSPHRASE }} 47 | 48 | - name: Add SSH Key for write access for commits 49 | uses: kielabokkie/ssh-key-and-known-hosts-action@v1 50 | with: 51 | ssh-private-key: ${{ secrets.COMMIT_KEY }} 52 | ssh-host: github.com 53 | 54 | - name: Configure Git author 55 | run: | 56 | git config --local user.email "action@github.com" 57 | git config --local user.name "GitHub Action" 58 | 59 | - name: Deploy to Maven Central 60 | run: | 61 | mvn -DreleaseTarget=central \ 62 | -DstagingProgressTimeoutMinutes=360 \ 63 | -DstagingProgressPauseDurationSeconds=10 \ 64 | -P releaseCentral \ 65 | -s maven/settings.xml \ 66 | release:prepare release:perform -------------------------------------------------------------------------------- /.github/workflows/snapshot-release.yml: -------------------------------------------------------------------------------- 1 | name: Snapshot Release 2 | 3 | on: 4 | workflow_run: 5 | workflows: 6 | - Test 7 | branches: 8 | - master 9 | types: 10 | - completed 11 | 12 | jobs: 13 | publish: 14 | if: ${{ github.event.workflow_run.event == 'push' && github.event.workflow_run.conclusion == 'success' }} 15 | runs-on: ubuntu-latest 16 | permissions: 17 | contents: read 18 | packages: write 19 | steps: 20 | - uses: actions/checkout@v4 21 | with: 22 | ref: ${{ github.event.workflow_run.head_branch }} 23 | - uses: actions/setup-java@v4 24 | with: 25 | distribution: zulu 26 | java-version: 17 27 | - name: Publish package 28 | run: mvn --batch-mode deploy -DreleaseTarget=github 29 | env: 30 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Intellij configuration files 2 | .idea 3 | **/*.iml 4 | 5 | # Build files 6 | **/target 7 | **/.flattened-pom.xml 8 | 9 | # Release files 10 | release.properties -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "solace-integration-test-support"] 2 | path = solace-integration-test-support 3 | url = ../../SolaceDev/solace-integration-test-support.git 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## How to contribute to a Solace Project 2 | 3 | #### **Did you find a bug?** 4 | 5 | * **Ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/SolaceProducts/solace-spring-cloud/issues). 6 | 7 | * If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/SolaceProducts/solace-spring-cloud/issues/new). Be sure to include a **title and clear description**, as much relevant information as possible, and a **code sample** or an **executable test case** demonstrating the expected behavior that is not occurring. 8 | 9 | #### **Did you write a patch that fixes a bug?** 10 | 11 | * Open a new GitHub pull request with the patch. 12 | 13 | * Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable. 14 | 15 | #### **Do you intend to add a new feature or change an existing one?** 16 | 17 | * Open a GitHub [enhancement request issue](https://github.com/SolaceProducts/solace-spring-cloud/issues/new) and describe the new functionality. 18 | 19 | #### **Do you have questions about the source code?** 20 | 21 | * Ask any question about the code or how to use Solace PubSub+ in the [Solace community](https://solace.dev/community/). 22 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | This product includes software originally developed by Solace Inc. 2 | Copyright 2019 Solace Inc. -------------------------------------------------------------------------------- /maven/settings.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | github 7 | 8 | 9 | 10 | 11 | github 12 | 13 | 14 | central 15 | https://repo.maven.apache.org/maven2 16 | 17 | false 18 | 19 | 20 | 21 | github-solacedev 22 | https://maven.pkg.github.com/SolaceDev/* 23 | 24 | true 25 | always 26 | 27 | 28 | true 29 | always 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | github-solacedev 39 | ${env.PACKAGES_ADMIN_USER} 40 | ${env.PACKAGES_ADMIN_TOKEN} 41 | 42 | 43 | github 44 | ${env.GITHUB_ACTOR} 45 | ${env.GITHUB_TOKEN} 46 | 47 | 48 | ossrh 49 | ${env.MAVEN_OSSRH_USER} 50 | ${env.MAVEN_OSSRH_PASS} 51 | 52 | 53 | gpg.passphrase 54 | ${env.MAVEN_GPG_KEY_PASSPHRASE} 55 | 56 | 57 | -------------------------------------------------------------------------------- /solace-spring-cloud-bom/README.md: -------------------------------------------------------------------------------- 1 | # Solace Spring Cloud Bill of Materials (BOM) 2 | 3 | ## Contents 4 | 5 | * [Overview](#overview) 6 | * [Spring Boot Version Compatibility](#spring-cloud-version-compatibility) 7 | * [Including the BOM](#including-the-bom) 8 | 9 | ## Overview 10 | 11 | The Solace Spring Cloud Bill of Materials (BOM) is a POM file which defines the versions of Solace Spring Cloud projects that are compatible to a particular version of Spring Cloud. 12 | 13 | Note that since Spring Cloud depends on Spring Boot, the Solace Spring Boot BOM will be included by default by this BOM. 14 | 15 | ## Spring Cloud Version Compatibility 16 | 17 | Consult the table below to determine which version of the BOM you need to use: 18 | 19 | | Spring Cloud | Solace Spring Cloud BOM | Spring Boot | 20 | |--------------|----------------------------|-------------| 21 | | Hoxton.SR1 | 1.0.0 | 2.2.x | 22 | | Hoxton.SR6 | 1.1.0 | 2.3.x | 23 | | 2020.0.1 | 2.0.0, 2.1.0, 2.2.0, 2.2.1 | 2.4.x | 24 | | 2021.0.1 | 2.3.0, 2.3.1, 2.3.2 | 2.6.x | 25 | | 2021.0.4 | 2.4.0 | 2.7.x | 26 | | 2021.0.6 | 2.5.0 | 2.7.x | 27 | | 2022.0.2 | 3.0.0 | 3.0.x | 28 | | 2022.0.4 | 3.1.0, 3.2.0 | 3.1.x | 29 | | 2023.0.1 | 4.0.0, 4.1.0 | 3.2.x | 30 | | 2023.0.2 | 4.2.0 | 3.3.x | 31 | | 2023.0.3 | 4.3.0, 4.4.0, 4.5.0, 4.6.0 | 3.3.x | 32 | | 2024.0.0 | 4.7.0, 4.8.0 | 3.4.x | 33 | 34 | 35 | ## Including the BOM 36 | 37 | In addition to showing how to include the BOM, the following snippets also shows how to use "version-less" Solace dependencies (`spring-cloud-starter-stream-solace` in this case) when using the BOM. 38 | 39 | ### Using it with Maven 40 | ```xml 41 | 42 | 43 | 44 | com.solace.spring.cloud 45 | solace-spring-cloud-bom 46 | 4.8.0 47 | pom 48 | import 49 | 50 | 51 | 52 | 53 | 54 | 55 | com.solace.spring.cloud 56 | spring-cloud-starter-stream-solace 57 | 58 | 59 | ``` 60 | 61 | ### Using it with Gradle 62 | ```groovy 63 | dependencies { 64 | implementation(platform("com.solace.spring.cloud:solace-spring-cloud-bom:4.8.0")) 65 | implementation("com.solace.spring.cloud:spring-cloud-starter-stream-solace") 66 | } 67 | ``` 68 | -------------------------------------------------------------------------------- /solace-spring-cloud-bom/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | com.solace.spring.cloud 7 | solace-spring-cloud-build 8 | 4.8.1-SNAPSHOT 9 | ../pom.xml 10 | 11 | 12 | solace-spring-cloud-bom 13 | pom 14 | 4.8.1-SNAPSHOT 15 | 16 | Solace Spring Cloud BOM 17 | BOM for Solace Spring Cloud 18 | https://github.com/${repoName}/solace-spring-cloud/tree/${project.scm.tag}/solace-spring-cloud-bom 19 | 20 | 21 | 22 | 23 | 24 | com.solace.spring.boot 25 | solace-spring-boot-bom 26 | ${solace.spring.boot.bom.version} 27 | pom 28 | import 29 | 30 | 31 | 32 | com.solace.spring.cloud 33 | spring-cloud-starter-stream-solace 34 | ${solace.spring.cloud.stream-starter.version} 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | org.codehaus.mojo 43 | flatten-maven-plugin 44 | 45 | bom 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /solace-spring-cloud-starters/solace-spring-cloud-stream-starter/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | com.solace.spring.cloud 7 | solace-spring-cloud-parent 8 | 4.8.1-SNAPSHOT 9 | ../../solace-spring-cloud-parent/pom.xml 10 | 11 | 12 | spring-cloud-starter-stream-solace 13 | 5.8.1-SNAPSHOT 14 | jar 15 | 16 | 17 | Spring Cloud Starter Stream Solace 18 | Spring Cloud Starter Stream for the Solace Spring Cloud Stream Binder 19 | https://github.com/${repoName}/solace-spring-cloud/tree/${project.scm.tag}/solace-spring-cloud-starters/solace-spring-cloud-stream-starter 20 | 21 | 22 | ${basedir}/../.. 23 | 24 | 25 | 26 | 27 | com.solace.spring.cloud 28 | spring-cloud-stream-binder-solace 29 | ${project.version} 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder-opentelemetry/solace-spring-cloud-stream-binder-instrumentation-tests/src/test/java/com/solace/spring/cloud/stream/binder/instrumentation/springBootTests/app/ConsumerConfig.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.instrumentation.springBootTests.app; 2 | 3 | import java.util.function.Consumer; 4 | import java.util.function.Supplier; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Profile; 9 | import org.springframework.stereotype.Component; 10 | 11 | 12 | @Component 13 | @Profile("consumer") 14 | public class ConsumerConfig { 15 | 16 | private static final Logger log = LoggerFactory.getLogger(ConsumerConfig.class); 17 | 18 | @Bean 19 | public Consumer consumer1() { 20 | return message -> log.info("Received: {}", message); 21 | } 22 | 23 | @Bean 24 | public Supplier source1() { 25 | return () -> { 26 | String message = "Hello World!"; 27 | log.info("Emitting: {}", message); 28 | return message; 29 | }; 30 | } 31 | } -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder-opentelemetry/solace-spring-cloud-stream-binder-instrumentation-tests/src/test/java/com/solace/spring/cloud/stream/binder/instrumentation/springBootTests/app/DynamicDestinationProcessorConfig.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.instrumentation.springBootTests.app; 2 | 3 | import java.util.function.Consumer; 4 | import java.util.function.Supplier; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.cloud.stream.function.StreamBridge; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Profile; 10 | import org.springframework.stereotype.Component; 11 | 12 | @Component 13 | @Profile("dynamicDestinationProcessor") 14 | public class DynamicDestinationProcessorConfig { 15 | 16 | private static final Logger log = LoggerFactory.getLogger( 17 | DynamicDestinationProcessorConfig.class); 18 | 19 | @Bean 20 | public Consumer dynamicDestinationProcessor1(StreamBridge streamBridge) { 21 | return message -> { 22 | String topic = "solace/dynamicDestination/hello"; 23 | log.info("Received: {}", message); 24 | String output = message.toUpperCase(); 25 | log.info("Sending: {}", output); 26 | log.info("Setting dynamic target destination (using StreamBridge) to: {}", topic); 27 | streamBridge.send(topic, output); 28 | }; 29 | } 30 | 31 | @Bean 32 | public Supplier source1() { 33 | return () -> { 34 | String message = "Hello World!"; 35 | log.info("Emitting: {}", message); 36 | return message; 37 | }; 38 | } 39 | } -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder-opentelemetry/solace-spring-cloud-stream-binder-instrumentation-tests/src/test/java/com/solace/spring/cloud/stream/binder/instrumentation/springBootTests/app/ErrorHandlerConfig.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.instrumentation.springBootTests.app; 2 | 3 | import java.util.function.Consumer; 4 | import java.util.function.Supplier; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Profile; 9 | import org.springframework.messaging.support.ErrorMessage; 10 | import org.springframework.stereotype.Component; 11 | 12 | 13 | @Component 14 | @Profile({"bindingErrorHandler", "globalErrorHandler"}) 15 | public class ErrorHandlerConfig { 16 | 17 | private static final Logger log = LoggerFactory.getLogger(ErrorHandlerConfig.class); 18 | 19 | @Bean 20 | public Consumer consumer1() { 21 | return message -> { 22 | log.info("Received: {}", message); 23 | 24 | // throw exception 25 | throw new RuntimeException("Exception thrown"); 26 | }; 27 | } 28 | 29 | @Bean 30 | public Consumer customErrorHandler() { 31 | return message -> { 32 | // ErrorMessage received on a binder 33 | log.info("Received error message on custom error handler"); 34 | log.info("Original Message: " + message.getOriginalMessage()); 35 | }; 36 | } 37 | 38 | @Bean 39 | public Supplier source1() { 40 | return () -> { 41 | String message = "Hello World!"; 42 | log.info("Emitting: {}", message); 43 | return message; 44 | }; 45 | } 46 | } -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder-opentelemetry/solace-spring-cloud-stream-binder-instrumentation-tests/src/test/java/com/solace/spring/cloud/stream/binder/instrumentation/springBootTests/app/MainApp.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.instrumentation.springBootTests.app; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | 8 | @SpringBootApplication 9 | public class MainApp { 10 | 11 | private static final Logger log = LoggerFactory.getLogger(MainApp.class); 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(MainApp.class); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder-opentelemetry/solace-spring-cloud-stream-binder-instrumentation-tests/src/test/java/com/solace/spring/cloud/stream/binder/instrumentation/springBootTests/app/ManualAckConfig.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.instrumentation.springBootTests.app; 2 | 3 | import java.util.function.Consumer; 4 | import java.util.function.Supplier; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Profile; 9 | import org.springframework.integration.StaticMessageHeaderAccessor; 10 | import org.springframework.integration.acks.AckUtils; 11 | import org.springframework.integration.acks.AcknowledgmentCallback; 12 | import org.springframework.messaging.Message; 13 | import org.springframework.stereotype.Component; 14 | 15 | @Component 16 | @Profile("manualAck") 17 | public class ManualAckConfig { 18 | 19 | private static final Logger log = LoggerFactory.getLogger(ManualAckConfig.class); 20 | 21 | @Bean("manualAckFunction") 22 | @Profile("requeue") 23 | public Consumer> manualAckFunction1() { 24 | return message -> { 25 | log.info("Received: {}", message); 26 | 27 | // Disable Auto-Acknowledgement 28 | AcknowledgmentCallback ackCallback = StaticMessageHeaderAccessor.getAcknowledgmentCallback( 29 | message); 30 | ackCallback.noAutoAck(); 31 | 32 | log.info("Requeue: {}", message); 33 | 34 | //Message will be redelivered max 2 times as consumer has configured queueMaxMsgRedelivery: 2 35 | AckUtils.requeue(ackCallback); 36 | }; 37 | } 38 | 39 | @Bean("manualAckFunction") 40 | @Profile({"reject"}) 41 | public Consumer> manualAckFunction2() { 42 | return message -> { 43 | log.info("Received: {}", message); 44 | 45 | // Disable Auto-Acknowledgement 46 | AcknowledgmentCallback ackCallback = StaticMessageHeaderAccessor.getAcknowledgmentCallback( 47 | message); 48 | ackCallback.noAutoAck(); 49 | 50 | log.info("Reject: {}", message); 51 | 52 | //Message will not be redelivered. It will be moved to DMQ if one is configured. 53 | AckUtils.reject(ackCallback); 54 | }; 55 | } 56 | 57 | @Bean 58 | public Supplier source1() { 59 | return () -> { 60 | String message = "Hello World!"; 61 | log.info("Emitting: {}", message); 62 | return message; 63 | }; 64 | } 65 | } -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder-opentelemetry/solace-spring-cloud-stream-binder-instrumentation-tests/src/test/java/com/solace/spring/cloud/stream/binder/instrumentation/springBootTests/app/ProcessorConfig.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.instrumentation.springBootTests.app; 2 | 3 | import java.util.function.Function; 4 | import java.util.function.Supplier; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Profile; 9 | import org.springframework.stereotype.Component; 10 | 11 | @Component 12 | @Profile("processor") 13 | public class ProcessorConfig { 14 | 15 | private static final Logger log = LoggerFactory.getLogger(ProcessorConfig.class); 16 | 17 | @Bean 18 | public Function processor1() { 19 | return message -> { 20 | log.info("Received: {}", message); 21 | 22 | String output = message.toUpperCase(); 23 | log.info("Sending: {}", output); 24 | 25 | return output; 26 | }; 27 | } 28 | 29 | @Bean 30 | public Supplier source1() { 31 | return () -> { 32 | String message = "Hello World!"; 33 | log.info("Emitting: {}", message); 34 | return message; 35 | }; 36 | } 37 | } -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder-opentelemetry/solace-spring-cloud-stream-binder-instrumentation-tests/src/test/java/com/solace/spring/cloud/stream/binder/instrumentation/springBootTests/app/SupplierConfig.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.instrumentation.springBootTests.app; 2 | 3 | import java.util.function.Supplier; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Profile; 8 | import org.springframework.stereotype.Component; 9 | 10 | @Component 11 | @Profile("supplier") 12 | public class SupplierConfig { 13 | 14 | private static final Logger log = LoggerFactory.getLogger(SupplierConfig.class); 15 | 16 | @Bean 17 | public Supplier source1() { 18 | return () -> { 19 | String message = "Hello World!"; 20 | log.info("Emitting: {}", message); 21 | return message; 22 | }; 23 | } 24 | } -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder-opentelemetry/solace-spring-cloud-stream-binder-instrumentation-tests/src/test/java/io/jaegertracing/api_v3/README.MD: -------------------------------------------------------------------------------- 1 | The Jaeger Tracing Query Service client code in this package is auto generated from Jaeger API v3 proto files. 2 | 3 | Refer: https://github.com/jaegertracing/jaeger-idl/tree/main 4 | 5 | ``` 6 | git clone https://github.com/jaegertracing/jaeger-idl.git 7 | cd jaeger-idl 8 | make proto-all 9 | ``` -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder-opentelemetry/solace-spring-cloud-stream-binder-instrumentation-tests/src/test/resources/application-bindingErrorHandler.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | function: 4 | definition: consumer1;source1;customErrorHandler 5 | 6 | stream: 7 | poller: 8 | initialDelay: 2000 9 | fixed-delay: 300000 # 300 seconds 10 | 11 | bindings: 12 | source1-out-0: 13 | destination: solace/supply/errorHandlingTestQueue 14 | binder: local-solace 15 | 16 | consumer1-in-0: 17 | error-handler-definition: customErrorHandler #Binding error handler 18 | destination: errorHandlingTestQueue 19 | group: consumerGroup 20 | maxAttempts: 3 21 | binder: local-solace 22 | 23 | binders: 24 | local-solace: 25 | type: solace 26 | environment: 27 | solace: 28 | java: 29 | host: tcp://localhost:55555 30 | msgVpn: default 31 | clientUsername: default 32 | clientPassword: default 33 | 34 | solace: 35 | default: 36 | consumer: 37 | add-destination-as-subscription-to-queue: false 38 | provision-durable-queue: true 39 | provision-error-queue: false 40 | queue-name-expression: "destination" 41 | queueMaxMsgRedelivery: 2 42 | 43 | bindings: 44 | consumer1-in-0: 45 | consumer: 46 | queueAdditionalSubscriptions: solace/supply/errorHandlingTestQueue 47 | 48 | server: 49 | port: 0 -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder-opentelemetry/solace-spring-cloud-stream-binder-instrumentation-tests/src/test/resources/application-consumer.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | function: 4 | definition: consumer1;source1 5 | 6 | stream: 7 | poller: 8 | initialDelay: 2000 9 | fixed-delay: 300000 # 300 seconds 10 | 11 | bindings: 12 | source1-out-0: 13 | destination: solace/supply/consumerQueue 14 | binder: local-solace 15 | 16 | consumer1-in-0: 17 | destination: consumerQueue 18 | group: consumerGroup 19 | binder: local-solace 20 | 21 | binders: 22 | local-solace: 23 | type: solace 24 | environment: 25 | solace: 26 | java: 27 | host: tcp://localhost:55555 28 | msgVpn: default 29 | clientUsername: default 30 | clientPassword: default 31 | 32 | solace: 33 | default: 34 | consumer: 35 | add-destination-as-subscription-to-queue: false 36 | provision-durable-queue: true 37 | provision-error-queue: false 38 | queue-name-expression: "destination" 39 | queueMaxMsgRedelivery: 2 40 | 41 | bindings: 42 | consumer1-in-0: 43 | consumer: 44 | queueAdditionalSubscriptions: solace/supply/consumerQueue 45 | 46 | server: 47 | port: 0 -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder-opentelemetry/solace-spring-cloud-stream-binder-instrumentation-tests/src/test/resources/application-dynamicDestinationProcessor.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | function: 4 | definition: dynamicDestinationProcessor1;source1 5 | 6 | stream: 7 | poller: 8 | initialDelay: 2000 9 | fixed-delay: 300000 # 300 seconds 10 | 11 | bindings: 12 | source1-out-0: 13 | destination: solace/supply/dynamicDestQ 14 | binder: local-solace 15 | 16 | dynamicDestinationProcessor1-in-0: 17 | destination: dynamicDestQ 18 | group: dynamicDestinationProcessorGroup 19 | binder: local-solace 20 | dynamicDestinationProcessor1-out-0: 21 | destination: dummy # won't be used. 22 | binder: local-solace 23 | 24 | binders: 25 | local-solace: 26 | type: solace 27 | environment: 28 | solace: 29 | java: 30 | host: tcp://localhost:55555 31 | msgVpn: default 32 | clientUsername: default 33 | clientPassword: default 34 | 35 | solace: 36 | default: 37 | consumer: 38 | add-destination-as-subscription-to-queue: false 39 | provision-durable-queue: true 40 | provision-error-queue: false 41 | queue-name-expression: "destination" 42 | queueMaxMsgRedelivery: 2 43 | 44 | bindings: 45 | dynamicDestinationProcessor1-in-0: 46 | consumer: 47 | queueAdditionalSubscriptions: solace/supply/dynamicDestQ 48 | 49 | server: 50 | port: 0 -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder-opentelemetry/solace-spring-cloud-stream-binder-instrumentation-tests/src/test/resources/application-globalErrorHandler.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | function: 4 | definition: consumer1;source1;customErrorHandler 5 | 6 | stream: 7 | default: 8 | error-handler-definition: customErrorHandler #Global error handler 9 | 10 | poller: 11 | initialDelay: 2000 12 | fixed-delay: 300000 # 300 seconds 13 | 14 | bindings: 15 | source1-out-0: 16 | destination: solace/supply/errorHandlingTestQueue 17 | binder: local-solace 18 | 19 | consumer1-in-0: 20 | destination: errorHandlingTestQueue 21 | group: consumerGroup 22 | maxAttempts: 3 23 | binder: local-solace 24 | 25 | binders: 26 | local-solace: 27 | type: solace 28 | environment: 29 | solace: 30 | java: 31 | host: tcp://localhost:55555 32 | msgVpn: default 33 | clientUsername: default 34 | clientPassword: default 35 | 36 | solace: 37 | default: 38 | consumer: 39 | add-destination-as-subscription-to-queue: false 40 | provision-durable-queue: true 41 | provision-error-queue: false 42 | queue-name-expression: "destination" 43 | queueMaxMsgRedelivery: 2 44 | 45 | bindings: 46 | consumer1-in-0: 47 | consumer: 48 | queueAdditionalSubscriptions: solace/supply/errorHandlingTestQueue 49 | 50 | server: 51 | port: 0 -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder-opentelemetry/solace-spring-cloud-stream-binder-instrumentation-tests/src/test/resources/application-manualAck.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | function: 4 | definition: manualAckFunction;source1 5 | 6 | stream: 7 | poller: 8 | initialDelay: 2000 9 | fixed-delay: 300000 # 300 seconds 10 | 11 | bindings: 12 | source1-out-0: 13 | destination: solace/supply/manualAckQueue 14 | binder: local-solace 15 | 16 | manualAckFunction-in-0: 17 | destination: manualAckQueue 18 | group: manualAckGroup 19 | binder: local-solace 20 | 21 | binders: 22 | local-solace: 23 | type: solace 24 | environment: 25 | solace: 26 | java: 27 | host: tcp://localhost:55555 28 | msgVpn: default 29 | clientUsername: default 30 | clientPassword: default 31 | 32 | solace: 33 | default: 34 | consumer: 35 | add-destination-as-subscription-to-queue: false 36 | provision-durable-queue: true 37 | provision-error-queue: false 38 | queue-name-expression: "destination" 39 | queueMaxMsgRedelivery: 2 40 | 41 | bindings: 42 | manualAckFunction-in-0: 43 | consumer: 44 | queueAdditionalSubscriptions: solace/supply/manualAckQueue 45 | 46 | server: 47 | port: 0 -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder-opentelemetry/solace-spring-cloud-stream-binder-instrumentation-tests/src/test/resources/application-processor.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | function: 4 | definition: processor1;source1 5 | 6 | stream: 7 | poller: 8 | initialDelay: 2000 9 | fixed-delay: 300000 # 300 seconds 10 | 11 | bindings: 12 | source1-out-0: 13 | destination: solace/supply/processorQueue 14 | binder: local-solace 15 | 16 | processor1-in-0: 17 | destination: processorQueue 18 | group: processorGroup 19 | binder: local-solace 20 | processor1-out-0: 21 | destination: solace/processor/hello 22 | binder: local-solace 23 | 24 | binders: 25 | local-solace: 26 | type: solace 27 | environment: 28 | solace: 29 | java: 30 | host: tcp://localhost:55555 31 | msgVpn: default 32 | clientUsername: default 33 | clientPassword: default 34 | 35 | solace: 36 | default: 37 | consumer: 38 | add-destination-as-subscription-to-queue: false 39 | provision-durable-queue: true 40 | provision-error-queue: false 41 | queue-name-expression: "destination" 42 | queueMaxMsgRedelivery: 2 43 | 44 | bindings: 45 | processor1-in-0: 46 | consumer: 47 | queueAdditionalSubscriptions: solace/supply/processorQueue 48 | 49 | server: 50 | port: 0 -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder-opentelemetry/solace-spring-cloud-stream-binder-instrumentation-tests/src/test/resources/application-supplier.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | function: 4 | definition: source1 5 | 6 | stream: 7 | poller: 8 | initialDelay: 2000 9 | fixed-delay: 300000 # 300 seconds 10 | bindings: 11 | source1-out-0: 12 | destination: solace/supply/hello 13 | binder: local-solace 14 | 15 | binders: 16 | local-solace: 17 | type: solace 18 | environment: 19 | solace: 20 | java: 21 | host: tcp://localhost:55555 22 | msgVpn: default 23 | clientUsername: default 24 | clientPassword: default 25 | 26 | server: 27 | port: 0 -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder-opentelemetry/solace-spring-cloud-stream-binder-instrumentation-tests/src/test/resources/otel-collector-config.yaml: -------------------------------------------------------------------------------- 1 | extensions: 2 | health_check: 3 | endpoint: ":13133" # Default endpoint for OTEL collector health check 4 | 5 | processors: 6 | memory_limiter: 7 | check_interval: 1s 8 | limit_mib: 1000 9 | spike_limit_mib: 500 10 | 11 | batch: 12 | 13 | exporters: 14 | debug: 15 | verbosity: detailed 16 | 17 | otlp/jaeger: 18 | endpoint: jaeger-all-in-one:4317 19 | tls: 20 | insecure: true 21 | 22 | receivers: 23 | otlp: 24 | protocols: 25 | grpc: 26 | endpoint: 0.0.0.0:4317 27 | http: 28 | endpoint: 0.0.0.0:4318 29 | 30 | solace: 31 | broker: [solbroker:5672] 32 | max_unacknowledged: 500 33 | auth: 34 | sasl_plain: 35 | username: trace 36 | password: trace 37 | queue: queue://#telemetry-trace 38 | tls: 39 | insecure: true 40 | insecure_skip_verify: true 41 | 42 | 43 | service: 44 | extensions: [health_check] 45 | telemetry: 46 | logs: 47 | level: "debug" 48 | pipelines: 49 | traces: 50 | receivers: [solace, otlp] 51 | processors: [batch, memory_limiter] 52 | exporters: [otlp/jaeger, debug] 53 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder-opentelemetry/solace-spring-cloud-stream-binder-instrumentation/src/main/java/com/solace/spring/cloud/stream/binder/instrumentation/SolaceBinderInstrumentationModule.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.instrumentation; 2 | 3 | import com.google.auto.service.AutoService; 4 | import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; 5 | import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | @AutoService(InstrumentationModule.class) 10 | public final class SolaceBinderInstrumentationModule extends InstrumentationModule { 11 | 12 | public SolaceBinderInstrumentationModule() { 13 | super("spring-cloud-stream-binder-solace-instrumentation"); 14 | } 15 | 16 | @Override 17 | public int order() { 18 | return 1; 19 | } 20 | 21 | @Override 22 | public List typeInstrumentations() { 23 | return Arrays.asList(new SolaceBinderConsumerInstrumentation()); 24 | } 25 | 26 | @Override 27 | public List getAdditionalHelperClassNames() { 28 | return Arrays.asList( 29 | //Solace Binder Consumer Instrumentation Classes 30 | SolaceBinderConsumerInstrumentation.class.getName(), 31 | SolaceBinderConsumerInstrumentation.InboundXMLMessageListenerProcessMessageMethodAdvice.class.getName(), 32 | SolaceBinderConsumerInstrumentation.MessageProducerSupportSendMessageMethodAdvice.class.getName(), 33 | 34 | //Other required classes from JCSMP Instrumentation 35 | "com.solace.messaging.trace.propagation.SolaceJCSMPTextMapGetter", 36 | "com.solace.messaging.trace.propagation.SolaceJCSMPTextMapSetter", 37 | "com.solace.messaging.trace.propagation.VersionInfo", 38 | "com.solace.messaging.trace.propagation.internal.SpanAttributes", 39 | "com.solace.messaging.trace.propagation.internal.MessagingOperation", 40 | "com.solace.messaging.trace.propagation.internal.MessagingAttribute", 41 | "com.solace.messaging.trace.propagation.internal.SpanContextUtil", 42 | "com.solace.messaging.trace.propagation.internal.TraceStateUtil", 43 | "com.solace.messaging.trace.propagation.internal.VersionInfoImpl", 44 | "com.solace.messaging.trace.propagation.internal.ClassLoaderReflectionUtil" 45 | ); 46 | } 47 | } -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/README.md: -------------------------------------------------------------------------------- 1 | # Spring Cloud Stream Binder for Solace PubSub+ 2 | 3 | Please go to the starter [README.md](../solace-spring-cloud-starters/solace-spring-cloud-stream-starter) for documentation on how to use this project. 4 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/health/SolaceBinderHealthAccessor.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.health; 2 | 3 | import com.solace.spring.cloud.stream.binder.health.contributors.BindingHealthContributor; 4 | import com.solace.spring.cloud.stream.binder.health.contributors.FlowsHealthContributor; 5 | import com.solace.spring.cloud.stream.binder.health.contributors.SolaceBinderHealthContributor; 6 | import com.solace.spring.cloud.stream.binder.health.handlers.SolaceFlowHealthEventHandler; 7 | import com.solace.spring.cloud.stream.binder.health.indicators.FlowHealthIndicator; 8 | import com.solace.spring.cloud.stream.binder.util.FlowReceiverContainer; 9 | 10 | import java.util.Optional; 11 | 12 | /** 13 | *

Proxy class for the Solace binder to access health components. 14 | * Always use this instead of directly using health components in Solace binder code.

15 | *

Allows for the Solace binder to still function correctly without actuator on the classpath.

16 | */ 17 | public class SolaceBinderHealthAccessor { 18 | private final SolaceBinderHealthContributor solaceBinderHealthContributor; 19 | private static final String FLOW_ID_CONCURRENCY_IDX_PREFIX = "flow-"; 20 | 21 | public SolaceBinderHealthAccessor(SolaceBinderHealthContributor solaceBinderHealthContributor) { 22 | this.solaceBinderHealthContributor = solaceBinderHealthContributor; 23 | } 24 | 25 | public void addFlow(String bindingName, int concurrencyIdx, FlowReceiverContainer flowReceiverContainer) { 26 | FlowHealthIndicator flowHealthIndicator = new FlowHealthIndicator(); 27 | Optional.ofNullable(solaceBinderHealthContributor.getSolaceBindingsHealthContributor()) 28 | .map(b -> b.getContributor(bindingName)) 29 | .orElseGet(() -> { 30 | BindingHealthContributor newBindingHealth = new BindingHealthContributor(new FlowsHealthContributor()); 31 | solaceBinderHealthContributor.getSolaceBindingsHealthContributor() 32 | .addBindingContributor(bindingName, newBindingHealth); 33 | return newBindingHealth; 34 | }) 35 | .getFlowsHealthContributor() 36 | .addFlowContributor(createFlowIdFromConcurrencyIdx(concurrencyIdx), flowHealthIndicator); 37 | flowReceiverContainer.setEventHandler(new SolaceFlowHealthEventHandler( 38 | flowReceiverContainer.getXMLMessageMapper(), 39 | flowReceiverContainer.getId().toString(), 40 | flowHealthIndicator)); 41 | } 42 | 43 | public void removeFlow(String bindingName, int concurrencyIdx) { 44 | Optional.ofNullable(solaceBinderHealthContributor.getSolaceBindingsHealthContributor()) 45 | .map(b -> b.getContributor(bindingName)) 46 | .map(BindingHealthContributor::getFlowsHealthContributor) 47 | .ifPresent(b -> b.removeFlowContributor(createFlowIdFromConcurrencyIdx(concurrencyIdx))); 48 | } 49 | 50 | private String createFlowIdFromConcurrencyIdx(int concurrencyIdx) { 51 | return FLOW_ID_CONCURRENCY_IDX_PREFIX + concurrencyIdx; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/health/base/SolaceHealthIndicator.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.health.base; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.boot.actuate.health.Health; 7 | import org.springframework.boot.actuate.health.HealthIndicator; 8 | import org.springframework.boot.actuate.health.Status; 9 | import org.springframework.lang.Nullable; 10 | 11 | import java.lang.reflect.InvocationTargetException; 12 | import java.util.Optional; 13 | 14 | public class SolaceHealthIndicator implements HealthIndicator { 15 | private static final String STATUS_RECONNECTING = "RECONNECTING"; 16 | private static final String INFO = "info"; 17 | private static final String RESPONSE_CODE = "responseCode"; 18 | private volatile Health health; 19 | private static final Logger LOGGER = LoggerFactory.getLogger(SolaceHealthIndicator.class); 20 | 21 | private static void logDebugStatus(String status) { 22 | LOGGER.debug("Solace connection/flow status is {}", status); 23 | } 24 | protected void healthUp() { 25 | health = Health.up().build(); 26 | logDebugStatus(String.valueOf(Status.UP)); 27 | } 28 | protected void healthReconnecting(@Nullable T eventArgs) { 29 | health = addEventDetails(Health.status(STATUS_RECONNECTING), eventArgs).build(); 30 | logDebugStatus(STATUS_RECONNECTING); 31 | } 32 | 33 | protected void healthDown(@Nullable T eventArgs) { 34 | health = addEventDetails(Health.down(), eventArgs).build(); 35 | logDebugStatus(String.valueOf(Status.DOWN)); 36 | } 37 | 38 | public Health.Builder addEventDetails(Health.Builder builder, @Nullable T eventArgs) { 39 | if (eventArgs == null) { 40 | return builder; 41 | } 42 | 43 | try { 44 | Optional.ofNullable(eventArgs.getClass().getMethod("getException").invoke(eventArgs)) 45 | .ifPresent(ex -> builder.withException((Throwable) ex)); 46 | Optional.of(eventArgs.getClass().getMethod("getResponseCode").invoke(eventArgs)) 47 | .filter(c -> ((int) c) != 0) 48 | .ifPresent(c -> builder.withDetail(RESPONSE_CODE, c)); 49 | Optional.ofNullable(eventArgs.getClass().getMethod("getInfo").invoke(eventArgs)) 50 | .filter(t -> StringUtils.isNotBlank(String.valueOf(t))) 51 | .ifPresent(info -> builder.withDetail(INFO, info)); 52 | } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { 53 | throw new RuntimeException(e); 54 | } 55 | 56 | return builder; 57 | } 58 | 59 | @Override 60 | public Health health() { 61 | return health; 62 | } 63 | 64 | void setHealth(Health health) { 65 | this.health = health; 66 | } 67 | } -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/health/contributors/BindingHealthContributor.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.health.contributors; 2 | 3 | import org.springframework.boot.actuate.health.CompositeHealthContributor; 4 | import org.springframework.boot.actuate.health.HealthContributor; 5 | import org.springframework.boot.actuate.health.NamedContributor; 6 | 7 | import java.util.Collections; 8 | import java.util.Iterator; 9 | import java.util.Set; 10 | 11 | public class BindingHealthContributor implements CompositeHealthContributor { 12 | private final FlowsHealthContributor flowsHealthContributor; 13 | private static final String FLOWS = "flows"; 14 | 15 | public BindingHealthContributor(FlowsHealthContributor flowsHealthContributor) { 16 | this.flowsHealthContributor = flowsHealthContributor; 17 | } 18 | 19 | @Override 20 | public HealthContributor getContributor(String name) { 21 | return name.equals(FLOWS) ? flowsHealthContributor : null; 22 | } 23 | 24 | @Override 25 | public Iterator> iterator() { 26 | Set> contributors = Collections 27 | .singleton(NamedContributor.of(FLOWS, flowsHealthContributor)); 28 | return contributors.iterator(); 29 | } 30 | 31 | public FlowsHealthContributor getFlowsHealthContributor() { 32 | return flowsHealthContributor; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/health/contributors/BindingsHealthContributor.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.health.contributors; 2 | 3 | import org.springframework.boot.actuate.health.CompositeHealthContributor; 4 | import org.springframework.boot.actuate.health.HealthContributor; 5 | import org.springframework.boot.actuate.health.NamedContributor; 6 | 7 | import java.util.HashMap; 8 | import java.util.Iterator; 9 | import java.util.Map; 10 | 11 | public class BindingsHealthContributor implements CompositeHealthContributor { 12 | private final Map bindingHealthContributor = new HashMap<>(); 13 | 14 | public void addBindingContributor(String bindingName, BindingHealthContributor bindingHealthContributor) { 15 | this.bindingHealthContributor.put(bindingName, bindingHealthContributor); 16 | } 17 | 18 | public void removeBindingContributor(String bindingName) { 19 | bindingHealthContributor.remove(bindingName); 20 | } 21 | 22 | @Override 23 | public BindingHealthContributor getContributor(String bindingName) { 24 | return bindingHealthContributor.get(bindingName); 25 | } 26 | 27 | @Override 28 | public Iterator> iterator() { 29 | return bindingHealthContributor.entrySet() 30 | .stream() 31 | .map((entry) -> NamedContributor.of(entry.getKey(), (HealthContributor) entry.getValue())) 32 | .iterator(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/health/contributors/FlowsHealthContributor.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.health.contributors; 2 | 3 | import com.solace.spring.cloud.stream.binder.health.indicators.FlowHealthIndicator; 4 | import org.springframework.boot.actuate.health.CompositeHealthContributor; 5 | import org.springframework.boot.actuate.health.HealthContributor; 6 | import org.springframework.boot.actuate.health.NamedContributor; 7 | 8 | import java.util.HashMap; 9 | import java.util.Iterator; 10 | import java.util.Map; 11 | 12 | public class FlowsHealthContributor implements CompositeHealthContributor { 13 | private final Map flowHealthContributor = new HashMap<>(); 14 | 15 | public void addFlowContributor(String flowId, FlowHealthIndicator flowHealthIndicator) { 16 | flowHealthContributor.put(flowId, flowHealthIndicator); 17 | } 18 | 19 | public void removeFlowContributor(String flowId) { 20 | flowHealthContributor.remove(flowId); 21 | } 22 | 23 | @Override 24 | public FlowHealthIndicator getContributor(String flowId) { 25 | return flowHealthContributor.get(flowId); 26 | } 27 | 28 | @Override 29 | public Iterator> iterator() { 30 | return flowHealthContributor.entrySet() 31 | .stream() 32 | .map((entry) -> NamedContributor.of(entry.getKey(), (HealthContributor) entry.getValue())) 33 | .iterator(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/health/contributors/SolaceBinderHealthContributor.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.health.contributors; 2 | 3 | import com.solace.spring.cloud.stream.binder.health.indicators.SessionHealthIndicator; 4 | import org.springframework.boot.actuate.health.CompositeHealthContributor; 5 | import org.springframework.boot.actuate.health.HealthContributor; 6 | import org.springframework.boot.actuate.health.NamedContributor; 7 | 8 | import java.util.ArrayList; 9 | import java.util.Iterator; 10 | import java.util.List; 11 | 12 | public class SolaceBinderHealthContributor implements CompositeHealthContributor { 13 | private final SessionHealthIndicator sessionHealthIndicator; 14 | private final BindingsHealthContributor bindingsHealthContributor; 15 | private static final String CONNECTION = "connection"; 16 | private static final String BINDINGS = "bindings"; 17 | 18 | public SolaceBinderHealthContributor(SessionHealthIndicator sessionHealthIndicator, 19 | BindingsHealthContributor bindingsHealthContributor) { 20 | this.sessionHealthIndicator = sessionHealthIndicator; 21 | this.bindingsHealthContributor = bindingsHealthContributor; 22 | } 23 | 24 | @Override 25 | public HealthContributor getContributor(String name) { 26 | return switch (name) { 27 | case CONNECTION -> sessionHealthIndicator; 28 | case BINDINGS -> bindingsHealthContributor; 29 | default -> null; 30 | }; 31 | } 32 | 33 | public SessionHealthIndicator getSolaceSessionHealthIndicator() { 34 | return sessionHealthIndicator; 35 | } 36 | 37 | public BindingsHealthContributor getSolaceBindingsHealthContributor() { 38 | return bindingsHealthContributor; 39 | } 40 | 41 | @Override 42 | public Iterator> iterator() { 43 | List> contributors = new ArrayList<>(); 44 | contributors.add(NamedContributor.of(CONNECTION, sessionHealthIndicator)); 45 | contributors.add(NamedContributor.of(BINDINGS, bindingsHealthContributor)); 46 | return contributors.iterator(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/health/handlers/SolaceFlowHealthEventHandler.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.health.handlers; 2 | 3 | import com.solace.spring.cloud.stream.binder.health.indicators.FlowHealthIndicator; 4 | import com.solace.spring.cloud.stream.binder.util.SolaceFlowEventHandler; 5 | import com.solace.spring.cloud.stream.binder.util.XMLMessageMapper; 6 | import com.solacesystems.jcsmp.FlowEventArgs; 7 | 8 | public class SolaceFlowHealthEventHandler extends SolaceFlowEventHandler { 9 | private final FlowHealthIndicator flowHealthIndicator; 10 | 11 | public SolaceFlowHealthEventHandler(XMLMessageMapper xmlMessageMapper, 12 | String flowReceiverContainerId, 13 | FlowHealthIndicator flowHealthIndicator) { 14 | super(xmlMessageMapper, flowReceiverContainerId); 15 | this.flowHealthIndicator = flowHealthIndicator; 16 | } 17 | 18 | @Override 19 | public void handleEvent(Object source, FlowEventArgs flowEventArgs) { 20 | super.handleEvent(source, flowEventArgs); 21 | 22 | if (flowEventArgs.getEvent() != null) { 23 | switch (flowEventArgs.getEvent()) { 24 | case FLOW_DOWN: 25 | flowHealthIndicator.down(flowEventArgs); 26 | break; 27 | case FLOW_RECONNECTING: 28 | flowHealthIndicator.reconnecting(flowEventArgs); 29 | break; 30 | case FLOW_UP: 31 | case FLOW_RECONNECTED: 32 | flowHealthIndicator.up(); 33 | break; 34 | } 35 | } 36 | } 37 | 38 | /** 39 | * This method is used only on during event of binding to source 40 | */ 41 | public void setHealthStatusUp() { 42 | this.flowHealthIndicator.up(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/health/handlers/SolaceSessionEventHandler.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.health.handlers; 2 | 3 | import com.solace.spring.cloud.stream.binder.health.indicators.SessionHealthIndicator; 4 | import com.solacesystems.jcsmp.DefaultSolaceOAuth2SessionEventHandler; 5 | import com.solacesystems.jcsmp.JCSMPProperties; 6 | import com.solacesystems.jcsmp.SessionEventArgs; 7 | import com.solacesystems.jcsmp.SolaceSessionOAuth2TokenProvider; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.springframework.lang.Nullable; 11 | 12 | public class SolaceSessionEventHandler extends DefaultSolaceOAuth2SessionEventHandler { 13 | private final SessionHealthIndicator sessionHealthIndicator; 14 | private static final Logger LOGGER = LoggerFactory.getLogger(SolaceSessionEventHandler.class); 15 | 16 | public SolaceSessionEventHandler(JCSMPProperties jcsmpProperties, 17 | @Nullable SolaceSessionOAuth2TokenProvider solaceSessionOAuth2TokenProvider, 18 | SessionHealthIndicator sessionHealthIndicator) { 19 | super(jcsmpProperties, solaceSessionOAuth2TokenProvider); 20 | this.sessionHealthIndicator = sessionHealthIndicator; 21 | } 22 | 23 | @Override 24 | public void handleEvent(SessionEventArgs eventArgs) { 25 | LOGGER.debug("Received Solace JCSMP Session event [{}]", eventArgs); 26 | super.handleEvent(eventArgs); 27 | switch (eventArgs.getEvent()) { 28 | case RECONNECTED -> this.sessionHealthIndicator.up(); 29 | case DOWN_ERROR -> this.sessionHealthIndicator.down(eventArgs); 30 | case RECONNECTING -> this.sessionHealthIndicator.reconnecting(eventArgs); 31 | } 32 | } 33 | 34 | public void setSessionHealthUp() { 35 | this.sessionHealthIndicator.up(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/health/indicators/FlowHealthIndicator.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.health.indicators; 2 | 3 | import com.solace.spring.cloud.stream.binder.health.base.SolaceHealthIndicator; 4 | import com.solacesystems.jcsmp.FlowEventArgs; 5 | import org.springframework.lang.Nullable; 6 | 7 | public class FlowHealthIndicator extends SolaceHealthIndicator { 8 | public void up() { 9 | super.healthUp(); 10 | } 11 | 12 | public void reconnecting(@Nullable FlowEventArgs eventArgs) { 13 | super.healthReconnecting(eventArgs); 14 | } 15 | 16 | public void down(@Nullable FlowEventArgs eventArgs) { 17 | super.healthDown(eventArgs); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/health/indicators/SessionHealthIndicator.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.health.indicators; 2 | 3 | import com.solace.spring.cloud.stream.binder.health.base.SolaceHealthIndicator; 4 | import com.solace.spring.cloud.stream.binder.properties.SolaceSessionHealthProperties; 5 | import com.solacesystems.jcsmp.SessionEventArgs; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.lang.Nullable; 9 | 10 | import java.util.Optional; 11 | import java.util.concurrent.atomic.AtomicInteger; 12 | import java.util.concurrent.locks.ReentrantLock; 13 | 14 | public class SessionHealthIndicator extends SolaceHealthIndicator { 15 | private final AtomicInteger reconnectCount = new AtomicInteger(0); 16 | private final SolaceSessionHealthProperties solaceHealthSessionProperties; 17 | private final ReentrantLock writeLock = new ReentrantLock(); 18 | private static final Logger LOGGER = LoggerFactory.getLogger(SessionHealthIndicator.class); 19 | 20 | public SessionHealthIndicator(SolaceSessionHealthProperties solaceHealthSessionProperties) { 21 | this.solaceHealthSessionProperties = solaceHealthSessionProperties; 22 | } 23 | 24 | public void up() { 25 | writeLock.lock(); 26 | try { 27 | LOGGER.trace("Reset reconnect count"); 28 | this.reconnectCount.set(0); 29 | super.healthUp(); 30 | } finally { 31 | writeLock.unlock(); 32 | } 33 | } 34 | 35 | public void reconnecting(@Nullable SessionEventArgs eventArgs) { 36 | writeLock.lock(); 37 | try { 38 | long reconnectAttempt = this.reconnectCount.incrementAndGet(); 39 | if (Optional.of(this.solaceHealthSessionProperties.getReconnectAttemptsUntilDown()) 40 | .filter(maxReconnectAttempts -> maxReconnectAttempts > 0) 41 | .filter(maxReconnectAttempts -> reconnectAttempt > maxReconnectAttempts) 42 | .isPresent()) { 43 | LOGGER.debug("Solace connection reconnect attempt {} > {}, changing state to down", 44 | reconnectAttempt, solaceHealthSessionProperties.getReconnectAttemptsUntilDown()); 45 | this.down(eventArgs, false); 46 | return; 47 | } 48 | 49 | super.healthReconnecting(eventArgs); 50 | } finally { 51 | writeLock.unlock(); 52 | } 53 | } 54 | 55 | public void down(@Nullable SessionEventArgs eventArgs) { 56 | down(eventArgs, true); 57 | } 58 | 59 | public void down(@Nullable SessionEventArgs eventArgs, boolean resetReconnectCount) { 60 | writeLock.lock(); 61 | try { 62 | if (resetReconnectCount) { 63 | LOGGER.trace("Reset reconnect count"); 64 | this.reconnectCount.set(0); 65 | } 66 | super.healthDown(eventArgs); 67 | } finally { 68 | writeLock.unlock(); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/inbound/acknowledge/JCSMPAcknowledgementCallbackFactory.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.inbound.acknowledge; 2 | 3 | import com.solace.spring.cloud.stream.binder.util.ErrorQueueInfrastructure; 4 | import com.solace.spring.cloud.stream.binder.util.FlowReceiverContainer; 5 | import com.solace.spring.cloud.stream.binder.util.MessageContainer; 6 | import com.solacesystems.jcsmp.transaction.TransactedSession; 7 | import org.springframework.integration.acks.AcknowledgmentCallback; 8 | 9 | import java.util.List; 10 | 11 | public class JCSMPAcknowledgementCallbackFactory { 12 | private final FlowReceiverContainer flowReceiverContainer; 13 | private ErrorQueueInfrastructure errorQueueInfrastructure; 14 | 15 | public JCSMPAcknowledgementCallbackFactory(FlowReceiverContainer flowReceiverContainer) { 16 | this.flowReceiverContainer = flowReceiverContainer; 17 | } 18 | 19 | public void setErrorQueueInfrastructure(ErrorQueueInfrastructure errorQueueInfrastructure) { 20 | this.errorQueueInfrastructure = errorQueueInfrastructure; 21 | } 22 | 23 | public AcknowledgmentCallback createCallback(MessageContainer messageContainer) { 24 | return createJCSMPCallback(messageContainer); 25 | } 26 | 27 | public AcknowledgmentCallback createBatchCallback(List messageContainers) { 28 | return new JCSMPBatchAcknowledgementCallback(messageContainers.stream() 29 | .map(this::createJCSMPCallback).toList()); 30 | } 31 | 32 | public AcknowledgmentCallback createTransactedBatchCallback(List messageContainers, 33 | TransactedSession transactedSession) { 34 | return new TransactedJCSMPAcknowledgementCallback(transactedSession, errorQueueInfrastructure); 35 | } 36 | 37 | private JCSMPAcknowledgementCallback createJCSMPCallback(MessageContainer messageContainer) { 38 | return new JCSMPAcknowledgementCallback(messageContainer, flowReceiverContainer, 39 | errorQueueInfrastructure); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/inbound/acknowledge/SolaceAckUtil.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.inbound.acknowledge; 2 | 3 | import com.solace.spring.cloud.stream.binder.util.SolaceAcknowledgmentException; 4 | import org.springframework.integration.acks.AcknowledgmentCallback; 5 | 6 | /** 7 | * Utility methods for acting on Solace implementation of {@link AcknowledgmentCallback}. 8 | */ 9 | public class SolaceAckUtil { 10 | 11 | /** 12 | * Verify if the error queue is enabled for the related message consumer. Beneficial to a consumer 13 | * in client-ack mode. The application may simply want to verify if error queue is enabled without 14 | * actually moving the message to error queue. 15 | * 16 | * @param acknowledgmentCallback the AcknowledgmentCallback. 17 | * @return true if the error queue is enabled for the associated message consumer. 18 | */ 19 | public static boolean isErrorQueueEnabled(AcknowledgmentCallback acknowledgmentCallback) { 20 | if (acknowledgmentCallback instanceof JCSMPAcknowledgementCallback jcsmpAcknowledgementCallback) { 21 | return jcsmpAcknowledgementCallback.isErrorQueueEnabled(); 22 | } else if (acknowledgmentCallback instanceof JCSMPBatchAcknowledgementCallback batchAcknowledgementCallback) { 23 | return batchAcknowledgementCallback.isErrorQueueEnabled(); 24 | } 25 | 26 | return false; 27 | } 28 | 29 | /** 30 | * Send the related message to the error queue if enabled for associated message consumer. This 31 | * could be specially useful for a consumer in client-ack mode 32 | * 33 | * @param ackCallback the AcknowledgmentCallback. 34 | * @return return true if error queue is enabled for the associated message consumer and the 35 | * message is successfully published to the error queue. 36 | * @throws SolaceAcknowledgmentException failed to send message to error queue. 37 | */ 38 | public static boolean republishToErrorQueue(AcknowledgmentCallback ackCallback) { 39 | if (ackCallback.isAcknowledged()) { 40 | return false; 41 | } 42 | 43 | if (ackCallback instanceof JCSMPAcknowledgementCallback jcsmpAckCallback) { 44 | return jcsmpAckCallback.republishToErrorQueue(); 45 | } else if (ackCallback instanceof JCSMPBatchAcknowledgementCallback jcsmpBatchAckCallback) { 46 | return jcsmpBatchAckCallback.republishToErrorQueue(); 47 | } 48 | 49 | return false; 50 | } 51 | } -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/inbound/acknowledge/TransactedJCSMPAcknowledgementCallback.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.inbound.acknowledge; 2 | 3 | import com.solace.spring.cloud.stream.binder.util.ErrorQueueInfrastructure; 4 | import com.solace.spring.cloud.stream.binder.util.SolaceAcknowledgmentException; 5 | import com.solacesystems.jcsmp.JCSMPException; 6 | import com.solacesystems.jcsmp.transaction.RollbackException; 7 | import com.solacesystems.jcsmp.transaction.TransactedSession; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.springframework.integration.acks.AcknowledgmentCallback; 11 | 12 | class TransactedJCSMPAcknowledgementCallback implements AcknowledgmentCallback { 13 | private final TransactedSession transactedSession; 14 | private final ErrorQueueInfrastructure errorQueueInfrastructure; 15 | private final long creationThreadId = Thread.currentThread().getId(); 16 | private boolean acknowledged = false; 17 | private static final Logger LOGGER = LoggerFactory.getLogger(TransactedJCSMPAcknowledgementCallback.class); 18 | 19 | TransactedJCSMPAcknowledgementCallback(TransactedSession transactedSession, 20 | ErrorQueueInfrastructure errorQueueInfrastructure) { 21 | this.transactedSession = transactedSession; 22 | this.errorQueueInfrastructure = errorQueueInfrastructure; 23 | } 24 | 25 | @Override 26 | public void acknowledge(Status status) { 27 | if (acknowledged) { 28 | LOGGER.debug("transaction is already resolved"); 29 | return; 30 | } 31 | 32 | if (creationThreadId != Thread.currentThread().getId()) { 33 | throw new UnsupportedOperationException("Transactions must be resolved on the message handler's thread"); 34 | } 35 | 36 | try { 37 | switch (status) { 38 | case ACCEPT -> { 39 | try { 40 | transactedSession.commit(); 41 | } catch (JCSMPException e) { 42 | if (!(e instanceof RollbackException)) { 43 | try { 44 | LOGGER.debug("Rolling back transaction"); 45 | transactedSession.rollback(); 46 | } catch (JCSMPException e1) { 47 | e.addSuppressed(e1); 48 | } 49 | } 50 | 51 | throw e; 52 | } 53 | } 54 | case REJECT -> { 55 | if (!republishToErrorQueue()) { 56 | transactedSession.rollback(); 57 | } 58 | } 59 | case REQUEUE -> transactedSession.rollback(); 60 | } 61 | } catch (Exception e) { 62 | throw new SolaceAcknowledgmentException("Failed to resolve transaction", e); 63 | } 64 | 65 | acknowledged = true; 66 | } 67 | 68 | /** 69 | * Send the message to the error queue and acknowledge the message. 70 | * 71 | * @return {@code true} if successful, {@code false} if {@code errorQueueInfrastructure} is not 72 | * defined. 73 | */ 74 | private boolean republishToErrorQueue() { 75 | return false; //TODO 76 | } 77 | 78 | @Override 79 | public boolean isAcknowledged() { 80 | return acknowledged; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/messaging/HeaderMeta.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.messaging; 2 | 3 | public interface HeaderMeta { 4 | /** 5 | * The type of header. 6 | * @return header type 7 | */ 8 | Class getType(); 9 | 10 | /** 11 | * Whether applications can directly read the header's value. 12 | * @return is readable 13 | */ 14 | boolean isReadable(); 15 | 16 | /** 17 | * Whether applications can directly set the header's value. 18 | * @return is writable 19 | */ 20 | boolean isWritable(); 21 | 22 | /** 23 | * The scope of the header. 24 | * @return scope 25 | */ 26 | Scope getScope(); 27 | 28 | enum Scope { 29 | /** 30 | * The header is only present on a message within the given application. 31 | */ 32 | LOCAL, 33 | /** 34 | * The header is read/written from/to the wire message. 35 | */ 36 | WIRE 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/messaging/SolaceBinderHeaderMeta.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.messaging; 2 | 3 | import com.solace.spring.cloud.stream.binder.util.CorrelationData; 4 | 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.stream.Collectors; 8 | import java.util.stream.Stream; 9 | 10 | public class SolaceBinderHeaderMeta implements HeaderMeta { 11 | public static final Map> META = Stream.of(new Object[][] { 12 | {SolaceBinderHeaders.PARTITION_KEY, new SolaceBinderHeaderMeta<>(String.class, false, true, Scope.WIRE)}, 13 | {SolaceBinderHeaders.MESSAGE_VERSION, new SolaceBinderHeaderMeta<>(Integer.class, true, false, Scope.WIRE)}, 14 | {SolaceBinderHeaders.SERIALIZED_PAYLOAD, new SolaceBinderHeaderMeta<>(Boolean.class, false, false, Scope.WIRE)}, 15 | {SolaceBinderHeaders.SERIALIZED_HEADERS, new SolaceBinderHeaderMeta<>(String.class, false, false, Scope.WIRE)}, 16 | {SolaceBinderHeaders.SERIALIZED_HEADERS_ENCODING, new SolaceBinderHeaderMeta<>(String.class, false, false, Scope.WIRE)}, 17 | {SolaceBinderHeaders.CONFIRM_CORRELATION, new SolaceBinderHeaderMeta<>(CorrelationData.class, false, true, Scope.LOCAL)}, 18 | {SolaceBinderHeaders.NULL_PAYLOAD, new SolaceBinderHeaderMeta<>(Boolean.class, true, false, Scope.LOCAL)}, 19 | {SolaceBinderHeaders.BATCHED_HEADERS, new SolaceBinderHeaderMeta<>(List.class, true, true, Scope.LOCAL)}, 20 | {SolaceBinderHeaders.TARGET_DESTINATION_TYPE, new SolaceBinderHeaderMeta<>(String.class, false, true, Scope.LOCAL)} 21 | }).collect(Collectors.toMap(d -> (String) d[0], d -> (SolaceBinderHeaderMeta) d[1])); 22 | 23 | private final Class type; 24 | private final boolean readable; 25 | private final boolean writable; 26 | private final Scope scope; 27 | 28 | public SolaceBinderHeaderMeta(Class type, boolean readable, boolean writable, Scope scope) { 29 | this.type = type; 30 | this.readable = readable; 31 | this.writable = writable; 32 | this.scope = scope; 33 | } 34 | 35 | @Override 36 | public Class getType() { 37 | return type; 38 | } 39 | 40 | /** 41 | * The readable property is only used by tests and doesn't necessarily reflect whether a header can be read by an application or not 42 | */ 43 | @Override 44 | public boolean isReadable() { 45 | return readable; 46 | } 47 | 48 | /** 49 | * The writable property is only used by tests and doesn't necessarily reflect whether a header can be written by an application or not 50 | */ 51 | @Override 52 | public boolean isWritable() { 53 | return writable; 54 | } 55 | 56 | @Override 57 | public Scope getScope() { 58 | return scope; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/meter/SolaceMessageMeterBinder.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.meter; 2 | 3 | import com.solacesystems.jcsmp.XMLMessage; 4 | import io.micrometer.core.instrument.DistributionSummary; 5 | import io.micrometer.core.instrument.MeterRegistry; 6 | import io.micrometer.core.instrument.binder.BaseUnits; 7 | import io.micrometer.core.instrument.binder.MeterBinder; 8 | import org.springframework.lang.NonNull; 9 | 10 | public class SolaceMessageMeterBinder implements MeterBinder { 11 | MeterRegistry registry; 12 | 13 | public static final String METER_NAME_TOTAL_SIZE = "solace.message.size.total"; 14 | public static final String METER_NAME_PAYLOAD_SIZE = "solace.message.size.payload"; 15 | public static final String METER_DESCRIPTION_TOTAL_SIZE = "Total message size"; 16 | public static final String METER_DESCRIPTION_PAYLOAD_SIZE = "Message payload size"; 17 | public static final String TAG_NAME = "name"; 18 | 19 | @Override 20 | public void bindTo(@NonNull MeterRegistry registry) { 21 | this.registry = registry; 22 | } 23 | 24 | public void recordMessage(@NonNull String bindingName, @NonNull XMLMessage message) { 25 | long payloadSize = message.getAttachmentContentLength() + message.getContentLength(); 26 | registerSizeMeter(METER_NAME_TOTAL_SIZE, METER_DESCRIPTION_TOTAL_SIZE, bindingName) 27 | .record(payloadSize + message.getBinaryMetadataContentLength(0)); 28 | registerSizeMeter(METER_NAME_PAYLOAD_SIZE, METER_DESCRIPTION_PAYLOAD_SIZE, bindingName) 29 | .record(payloadSize); 30 | } 31 | 32 | private DistributionSummary registerSizeMeter(@NonNull String meterName, 33 | @NonNull String description, 34 | @NonNull String bindingName) { 35 | return DistributionSummary.builder(meterName) 36 | .description(description) 37 | .tag(TAG_NAME, bindingName) 38 | .baseUnit(BaseUnits.BYTES) 39 | .register(registry); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/meter/SolaceMeterAccessor.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.meter; 2 | 3 | import com.solacesystems.jcsmp.XMLMessage; 4 | 5 | /** 6 | *

Proxy class for the Solace binder to access meter components. 7 | * Always use this instead of directly using meter components in Solace binder code.

8 | *

Allows for the Solace binder to still function correctly without micrometer on the classpath.

9 | */ 10 | public class SolaceMeterAccessor { 11 | private final SolaceMessageMeterBinder solaceMessageMeterBinder; 12 | 13 | public SolaceMeterAccessor(SolaceMessageMeterBinder solaceMessageMeterBinder) { 14 | this.solaceMessageMeterBinder = solaceMessageMeterBinder; 15 | } 16 | 17 | public void recordMessage(String bindingName, XMLMessage message) { 18 | solaceMessageMeterBinder.recordMessage(bindingName, message); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/properties/SmfMessageWriterProperties.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.properties; 2 | 3 | import com.solace.spring.cloud.stream.binder.util.SmfMessageHeaderWriteCompatibility; 4 | import com.solace.spring.cloud.stream.binder.util.SmfMessagePayloadWriteCompatibility; 5 | 6 | import java.util.HashSet; 7 | import java.util.Set; 8 | 9 | public class SmfMessageWriterProperties { 10 | private Set headerExclusions; 11 | private SmfMessageHeaderWriteCompatibility headerTypeCompatibility; 12 | private SmfMessagePayloadWriteCompatibility payloadTypeCompatibility; 13 | private boolean nonSerializableHeaderConvertToString; 14 | 15 | public SmfMessageWriterProperties(SolaceProducerProperties solaceProducerProperties) { 16 | this.headerExclusions = new HashSet<>(solaceProducerProperties.getHeaderExclusions()); 17 | this.headerTypeCompatibility = solaceProducerProperties.getHeaderTypeCompatibility(); 18 | this.payloadTypeCompatibility = solaceProducerProperties.getPayloadTypeCompatibility(); 19 | this.nonSerializableHeaderConvertToString = solaceProducerProperties.isNonserializableHeaderConvertToString(); 20 | } 21 | 22 | public Set getHeaderExclusions() { 23 | return headerExclusions; 24 | } 25 | 26 | public void setHeaderExclusions(Set headerExclusions) { 27 | this.headerExclusions = headerExclusions; 28 | } 29 | 30 | public SmfMessageHeaderWriteCompatibility getHeaderTypeCompatibility() { 31 | return headerTypeCompatibility; 32 | } 33 | 34 | public void setHeaderTypeCompatibility(SmfMessageHeaderWriteCompatibility headerTypeCompatibility) { 35 | this.headerTypeCompatibility = headerTypeCompatibility; 36 | } 37 | 38 | public SmfMessagePayloadWriteCompatibility getPayloadTypeCompatibility() { 39 | return payloadTypeCompatibility; 40 | } 41 | 42 | public void setPayloadTypeCompatibility(SmfMessagePayloadWriteCompatibility payloadTypeCompatibility) { 43 | this.payloadTypeCompatibility = payloadTypeCompatibility; 44 | } 45 | 46 | public boolean isNonSerializableHeaderConvertToString() { 47 | return nonSerializableHeaderConvertToString; 48 | } 49 | 50 | public void setNonSerializableHeaderConvertToString(boolean nonSerializableHeaderConvertToString) { 51 | this.nonSerializableHeaderConvertToString = nonSerializableHeaderConvertToString; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/properties/SolaceBindingProperties.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.properties; 2 | 3 | import jakarta.validation.Valid; 4 | import org.springframework.boot.context.properties.NestedConfigurationProperty; 5 | import org.springframework.cloud.stream.binder.BinderSpecificPropertiesProvider; 6 | 7 | public class SolaceBindingProperties implements BinderSpecificPropertiesProvider { 8 | 9 | @NestedConfigurationProperty 10 | @Valid 11 | private SolaceConsumerProperties consumer = new SolaceConsumerProperties(); 12 | 13 | @NestedConfigurationProperty 14 | @Valid 15 | private SolaceProducerProperties producer = new SolaceProducerProperties(); 16 | 17 | @Override 18 | public SolaceConsumerProperties getConsumer() { 19 | return consumer; 20 | } 21 | 22 | public void setConsumer(SolaceConsumerProperties consumer) { 23 | this.consumer = consumer; 24 | } 25 | 26 | @Override 27 | public SolaceProducerProperties getProducer() { 28 | return producer; 29 | } 30 | 31 | public void setProducer(SolaceProducerProperties producer) { 32 | this.producer = producer; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/properties/SolaceExtendedBindingProperties.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.properties; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | import org.springframework.cloud.stream.binder.AbstractExtendedBindingProperties; 5 | import org.springframework.cloud.stream.binder.BinderSpecificPropertiesProvider; 6 | 7 | import java.util.Map; 8 | 9 | @ConfigurationProperties("spring.cloud.stream.solace") 10 | public class SolaceExtendedBindingProperties 11 | extends AbstractExtendedBindingProperties { 12 | 13 | protected static final String DEFAULTS_PREFIX = "spring.cloud.stream.solace.default"; 14 | 15 | @Override 16 | public String getDefaultsPrefix() { 17 | return DEFAULTS_PREFIX; 18 | } 19 | 20 | @Override 21 | public Map getBindings() { 22 | return super.doGetBindings(); 23 | } 24 | 25 | @Override 26 | public Class getExtendedPropertiesEntryClass() { 27 | return SolaceBindingProperties.class; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/properties/SolaceSessionHealthProperties.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.properties; 2 | 3 | import jakarta.validation.constraints.Min; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | import org.springframework.validation.annotation.Validated; 6 | 7 | @Validated 8 | @ConfigurationProperties("solace.health-check.connection") 9 | public class SolaceSessionHealthProperties { 10 | /** 11 | *

The number of session reconnect attempts until the health goes {@code DOWN}. This will happen regardless if 12 | * the underlying session is actually still reconnecting. Setting this to {@code 0} will disable this feature.

13 | *

This feature operates independently of the PubSub+ session reconnect feature. Meaning that if PubSub+ 14 | * session reconnect is configured to retry less than the value given to this property, then this feature 15 | * effectively does nothing.

16 | */ 17 | @Min(0) 18 | private long reconnectAttemptsUntilDown = 0; 19 | 20 | public long getReconnectAttemptsUntilDown() { 21 | return reconnectAttemptsUntilDown; 22 | } 23 | 24 | public void setReconnectAttemptsUntilDown(long reconnectAttemptsUntilDown) { 25 | this.reconnectAttemptsUntilDown = reconnectAttemptsUntilDown; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/provisioning/EndpointProvider.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.provisioning; 2 | 3 | import com.solace.spring.cloud.stream.binder.util.EndpointType; 4 | import com.solacesystems.jcsmp.Endpoint; 5 | import com.solacesystems.jcsmp.JCSMPException; 6 | import com.solacesystems.jcsmp.JCSMPFactory; 7 | import com.solacesystems.jcsmp.JCSMPSession; 8 | import com.solacesystems.jcsmp.Queue; 9 | import com.solacesystems.jcsmp.TopicEndpoint; 10 | 11 | public interface EndpointProvider { 12 | QueueProvider QUEUE_PROVIDER = new QueueProvider(); 13 | TopicEndpointProvider TOPIC_ENDPOINT_PROVIDER = new TopicEndpointProvider(); 14 | 15 | T createInstance(String name); 16 | T createTemporaryEndpoint(String name, JCSMPSession jcsmpSession) throws JCSMPException; 17 | 18 | static EndpointProvider from(EndpointType endpointType) { 19 | return switch (endpointType) { 20 | case QUEUE -> QUEUE_PROVIDER; 21 | case TOPIC_ENDPOINT -> TOPIC_ENDPOINT_PROVIDER; 22 | }; 23 | } 24 | 25 | class QueueProvider implements EndpointProvider { 26 | @Override 27 | public Queue createInstance(String name) { 28 | return JCSMPFactory.onlyInstance().createQueue(name); 29 | } 30 | 31 | @Override 32 | public Queue createTemporaryEndpoint(String name, JCSMPSession jcsmpSession) throws JCSMPException { 33 | return jcsmpSession.createTemporaryQueue(name); 34 | } 35 | } 36 | 37 | class TopicEndpointProvider implements EndpointProvider { 38 | @Override 39 | public TopicEndpoint createInstance(String name) { 40 | return JCSMPFactory.onlyInstance().createDurableTopicEndpointEx(name); 41 | } 42 | 43 | @Override 44 | public TopicEndpoint createTemporaryEndpoint(String name, JCSMPSession jcsmpSession) throws JCSMPException { 45 | return jcsmpSession.createNonDurableTopicEndpoint(name); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/provisioning/ExpressionContextRoot.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.provisioning; 2 | 3 | import com.solace.spring.cloud.stream.binder.properties.SolaceCommonProperties; 4 | import com.solace.spring.cloud.stream.binder.properties.SolaceConsumerProperties; 5 | import com.solace.spring.cloud.stream.binder.properties.SolaceProducerProperties; 6 | import org.springframework.cloud.stream.binder.ExtendedConsumerProperties; 7 | import org.springframework.cloud.stream.binder.ExtendedProducerProperties; 8 | 9 | /** 10 | * The context used to evaluate a queue name expression (SpEL) 11 | */ 12 | public class ExpressionContextRoot { 13 | 14 | private final String group; 15 | private final String destination; 16 | private final boolean isAnonymous; 17 | private final Properties properties; 18 | 19 | public ExpressionContextRoot(String physicalGroupName, String destination, boolean isAnonymous, ExtendedConsumerProperties extendedProperties) { 20 | this.group = physicalGroupName; 21 | this.destination = destination; 22 | this.isAnonymous = isAnonymous; 23 | this.properties = new Properties<>(extendedProperties); 24 | } 25 | 26 | public ExpressionContextRoot(String groupName, String destination, ExtendedProducerProperties extendedProperties) { 27 | this.group = groupName; 28 | this.destination = destination; 29 | this.isAnonymous = false; 30 | this.properties = new Properties<>(extendedProperties); 31 | } 32 | 33 | public String getGroup() { 34 | return group; 35 | } 36 | 37 | public String getDestination() { 38 | return destination; 39 | } 40 | 41 | public boolean isAnonymous() { 42 | return isAnonymous; 43 | } 44 | 45 | public Properties getProperties() { 46 | return properties; 47 | } 48 | 49 | private static class Properties { 50 | 51 | private final SolaceCommonProperties solace; 52 | private final T spring; 53 | 54 | public Properties(T extendedProperties) { 55 | if (extendedProperties instanceof ExtendedConsumerProperties) { 56 | this.solace = (SolaceCommonProperties) ((ExtendedConsumerProperties) extendedProperties).getExtension(); 57 | } else if (extendedProperties instanceof ExtendedProducerProperties) { 58 | this.solace = (SolaceCommonProperties) ((ExtendedProducerProperties) extendedProperties).getExtension(); 59 | } else { 60 | throw new IllegalArgumentException("Unsupported argument type"); 61 | } 62 | this.spring = extendedProperties; 63 | } 64 | 65 | public SolaceCommonProperties getSolace() { 66 | return solace; 67 | } 68 | 69 | public T getSpring() { 70 | return spring; 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/provisioning/QueueNameDestinationEncoding.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.provisioning; 2 | 3 | enum QueueNameDestinationEncoding { 4 | PLAIN("plain"); 5 | private final String label; 6 | 7 | QueueNameDestinationEncoding(String label) { 8 | this.label = label; 9 | } 10 | 11 | public String getLabel() { 12 | return label; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/provisioning/SolaceConsumerDestination.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.provisioning; 2 | 3 | import org.springframework.cloud.stream.provisioning.ConsumerDestination; 4 | 5 | import java.util.Set; 6 | import java.util.StringJoiner; 7 | 8 | public class SolaceConsumerDestination implements ConsumerDestination { 9 | private final String bindingDestinationName; 10 | private final String physicalGroupName; 11 | private final String endpointName; 12 | private final boolean isTemporary; 13 | private final String errorQueueName; 14 | private final Set additionalSubscriptions; 15 | 16 | SolaceConsumerDestination(String endpointName, String bindingDestinationName, String physicalGroupName, 17 | boolean isTemporary, String errorQueueName, Set additionalSubscriptions) { 18 | this.bindingDestinationName = bindingDestinationName; 19 | this.physicalGroupName = physicalGroupName; 20 | this.endpointName = endpointName; 21 | this.isTemporary = isTemporary; 22 | this.errorQueueName = errorQueueName; 23 | this.additionalSubscriptions = additionalSubscriptions; 24 | } 25 | 26 | @Override 27 | public String getName() { 28 | return endpointName; 29 | } 30 | 31 | public String getBindingDestinationName() { 32 | return bindingDestinationName; 33 | } 34 | 35 | public String getPhysicalGroupName() { 36 | return physicalGroupName; 37 | } 38 | 39 | public boolean isTemporary() { 40 | return isTemporary; 41 | } 42 | 43 | public String getErrorQueueName() { 44 | return errorQueueName; 45 | } 46 | 47 | public Set getAdditionalSubscriptions() { 48 | return additionalSubscriptions; 49 | } 50 | 51 | @Override 52 | public String toString() { 53 | return new StringJoiner(", ", SolaceConsumerDestination.class.getSimpleName() + "[", "]") 54 | .add("bindingDestinationName='" + bindingDestinationName + "'") 55 | .add("physicalGroupName='" + physicalGroupName + "'") 56 | .add("endpointName='" + endpointName + "'") 57 | .add("isTemporary=" + isTemporary) 58 | .add("errorQueueName='" + errorQueueName + "'") 59 | .toString(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/provisioning/SolaceProducerDestination.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.provisioning; 2 | 3 | import org.springframework.cloud.stream.provisioning.ProducerDestination; 4 | 5 | class SolaceProducerDestination implements ProducerDestination { 6 | private String destinationName; 7 | 8 | SolaceProducerDestination(String destinationName) { 9 | this.destinationName = destinationName; 10 | } 11 | 12 | @Override 13 | public String getName() { 14 | return destinationName; 15 | } 16 | 17 | @Override 18 | public String getNameForPartition(int partition) { 19 | return destinationName; 20 | } 21 | 22 | @Override 23 | public String toString() { 24 | final StringBuffer sb = new StringBuffer("SolaceProducerDestination{"); 25 | sb.append("destinationName='").append(destinationName).append('\''); 26 | sb.append('}'); 27 | return sb.toString(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/util/BatchProxyCorrelationKey.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.util; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | 5 | public class BatchProxyCorrelationKey { 6 | private final Object targetCorrelationKey; 7 | private final AtomicInteger numRemaining; 8 | private static final int RETURNED_KEY = -1; 9 | 10 | public BatchProxyCorrelationKey(Object targetCorrelationKey, int numRemaining) { 11 | this.targetCorrelationKey = targetCorrelationKey; 12 | this.numRemaining = new AtomicInteger(numRemaining); 13 | } 14 | 15 | /** 16 | * Retrieve the target correlation key after all successes have been received. 17 | * @return the target correlation key if after being invoked the required number of times and if it hasn't been 18 | * returned before. {@code null} otherwise. 19 | */ 20 | public Object getCorrelationKeyForSuccess() { 21 | if (numRemaining.updateAndGet(i -> i > RETURNED_KEY ? i - 1 : i) == 0) { 22 | return targetCorrelationKey; 23 | } else { 24 | return null; 25 | } 26 | } 27 | 28 | /** 29 | * Returns the real correlation key in event of failure. 30 | * @return the target correlation key if it hasn't been returned before. {@code null} otherwise. 31 | */ 32 | public Object getCorrelationKeyForFailure() { 33 | if (numRemaining.getAndSet(RETURNED_KEY) != RETURNED_KEY) { 34 | return targetCorrelationKey; 35 | } else { 36 | return null; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/util/BatchWaitStrategy.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.util; 2 | 3 | public enum BatchWaitStrategy { 4 | /** 5 | * Adheres to the {@code batchTimeout} consumer config option. 6 | */ 7 | RESPECT_TIMEOUT, 8 | /** 9 | * Immediately collects the batch once no more messages are available on the endpoint. 10 | */ 11 | IMMEDIATE 12 | } 13 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/util/ClosedChannelBindingException.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.util; 2 | 3 | public class ClosedChannelBindingException extends RuntimeException { 4 | public ClosedChannelBindingException(String message) { 5 | super(message); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/util/CorrelationData.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.util; 2 | 3 | import org.springframework.messaging.Message; 4 | import org.springframework.messaging.MessagingException; 5 | import org.springframework.util.concurrent.ListenableFuture; 6 | import org.springframework.util.concurrent.SettableListenableFuture; 7 | 8 | public class CorrelationData { 9 | private final SettableListenableFuture future = new SettableListenableFuture<>(); 10 | 11 | private Message message; 12 | 13 | /** 14 | * Return a future to check the success/failure of the publish operation. 15 | * @return the future. 16 | */ 17 | public ListenableFuture getFuture() { 18 | return this.future; 19 | } 20 | 21 | public Message getMessage() { 22 | return message; 23 | } 24 | 25 | public void setMessage(Message message) { 26 | this.message = message; 27 | } 28 | 29 | void success() { 30 | this.future.set(null); 31 | } 32 | 33 | void failed(MessagingException cause) { 34 | this.future.setException(cause); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/util/DestinationType.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.util; 2 | 3 | public enum DestinationType { 4 | 5 | TOPIC, 6 | QUEUE 7 | } 8 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/util/EndpointType.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.util; 2 | 3 | public enum EndpointType { 4 | TOPIC_ENDPOINT, 5 | QUEUE 6 | } 7 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/util/ErrorChannelSendingCorrelationKey.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.util; 2 | 3 | import com.solace.spring.cloud.stream.binder.messaging.SolaceBinderHeaders; 4 | import com.solacesystems.jcsmp.XMLMessage; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.core.AttributeAccessor; 8 | import org.springframework.integration.support.ErrorMessageStrategy; 9 | import org.springframework.integration.support.ErrorMessageUtils; 10 | import org.springframework.messaging.Message; 11 | import org.springframework.messaging.MessageChannel; 12 | import org.springframework.messaging.MessagingException; 13 | 14 | import java.util.List; 15 | 16 | public class ErrorChannelSendingCorrelationKey { 17 | private final Message inputMessage; 18 | private final MessageChannel errorChannel; 19 | private final ErrorMessageStrategy errorMessageStrategy; 20 | private List rawMessages; 21 | private CorrelationData confirmCorrelation; 22 | 23 | private static final Logger LOGGER = LoggerFactory.getLogger(ErrorChannelSendingCorrelationKey.class); 24 | 25 | public ErrorChannelSendingCorrelationKey(Message inputMessage, MessageChannel errorChannel, 26 | ErrorMessageStrategy errorMessageStrategy) { 27 | this.inputMessage = inputMessage; 28 | this.errorChannel = errorChannel; 29 | this.errorMessageStrategy = errorMessageStrategy; 30 | } 31 | 32 | public Message getInputMessage() { 33 | return inputMessage; 34 | } 35 | 36 | public List getRawMessages() { 37 | return rawMessages; 38 | } 39 | 40 | public void setRawMessages(List rawMessages) { 41 | this.rawMessages = rawMessages; 42 | } 43 | 44 | public CorrelationData getConfirmCorrelation() { 45 | return confirmCorrelation; 46 | } 47 | 48 | public void setConfirmCorrelation(CorrelationData confirmCorrelation) { 49 | this.confirmCorrelation = confirmCorrelation; 50 | } 51 | 52 | /** 53 | * Send the message to the error channel if defined. 54 | * @param msg the failure description 55 | * @param cause the failure cause 56 | * @return the exception wrapper containing the failed input message 57 | */ 58 | public MessagingException send(String msg, Exception cause) { 59 | MessagingException exception = new MessagingException(inputMessage, msg, cause); 60 | if (errorChannel != null) { 61 | AttributeAccessor attributes = ErrorMessageUtils.getAttributeAccessor(inputMessage, null); 62 | if (rawMessages != null && !rawMessages.isEmpty()) { 63 | attributes.setAttribute(SolaceMessageHeaderErrorMessageStrategy.ATTR_SOLACE_RAW_MESSAGE, 64 | inputMessage.getHeaders().containsKey(SolaceBinderHeaders.BATCHED_HEADERS) ? 65 | rawMessages : rawMessages.get(0)); 66 | } 67 | LOGGER.debug("Sending message {} to error channel {}", inputMessage.getHeaders().getId(), errorChannel); 68 | errorChannel.send(errorMessageStrategy.buildErrorMessage(exception, attributes)); 69 | } 70 | return exception; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/util/ErrorQueueInfrastructure.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.util; 2 | 3 | import com.solace.spring.cloud.stream.binder.properties.SolaceConsumerProperties; 4 | import com.solacesystems.jcsmp.JCSMPException; 5 | import com.solacesystems.jcsmp.JCSMPFactory; 6 | import com.solacesystems.jcsmp.Queue; 7 | import com.solacesystems.jcsmp.XMLMessage; 8 | import com.solacesystems.jcsmp.XMLMessageProducer; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | import org.springframework.messaging.MessagingException; 12 | 13 | public class ErrorQueueInfrastructure { 14 | private final JCSMPSessionProducerManager producerManager; 15 | private final String producerKey; 16 | private final String errorQueueName; 17 | private final SolaceConsumerProperties consumerProperties; 18 | private final XMLMessageMapper xmlMessageMapper = new XMLMessageMapper(); 19 | 20 | private static final Logger LOGGER = LoggerFactory.getLogger(ErrorQueueInfrastructure.class); 21 | 22 | public ErrorQueueInfrastructure(JCSMPSessionProducerManager producerManager, String producerKey, 23 | String errorQueueName, SolaceConsumerProperties consumerProperties) { 24 | this.producerManager = producerManager; 25 | this.producerKey = producerKey; 26 | this.errorQueueName = errorQueueName; 27 | this.consumerProperties = consumerProperties; 28 | } 29 | 30 | public void send(MessageContainer messageContainer, ErrorQueueRepublishCorrelationKey key) throws JCSMPException { 31 | XMLMessage xmlMessage = xmlMessageMapper.mapError(messageContainer.getMessage(), consumerProperties); 32 | xmlMessage.setCorrelationKey(key); 33 | Queue queue = JCSMPFactory.onlyInstance().createQueue(errorQueueName); 34 | XMLMessageProducer producer; 35 | try { 36 | producer = producerManager.get(producerKey); 37 | } catch (Exception e) { 38 | MessagingException wrappedException = new MessagingException( 39 | String.format("Failed to get producer to send message %s to queue %s", xmlMessage.getMessageId(), 40 | errorQueueName), e); 41 | LOGGER.warn(wrappedException.getMessage(), e); 42 | throw wrappedException; 43 | } 44 | 45 | producer.send(xmlMessage, queue); 46 | } 47 | 48 | public ErrorQueueRepublishCorrelationKey createCorrelationKey(MessageContainer messageContainer, 49 | FlowReceiverContainer flowReceiverContainer) { 50 | return new ErrorQueueRepublishCorrelationKey(this, messageContainer, flowReceiverContainer); 51 | } 52 | 53 | public String getErrorQueueName() { 54 | return errorQueueName; 55 | } 56 | 57 | public long getMaxDeliveryAttempts() { 58 | return consumerProperties.getErrorQueueMaxDeliveryAttempts(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/util/ErrorQueueRepublishCorrelationKey.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.util; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | public class ErrorQueueRepublishCorrelationKey { 7 | private final ErrorQueueInfrastructure errorQueueInfrastructure; 8 | private final MessageContainer messageContainer; 9 | private final FlowReceiverContainer flowReceiverContainer; 10 | private long errorQueueDeliveryAttempt = 0; 11 | 12 | private static final Logger LOGGER = LoggerFactory.getLogger(ErrorQueueRepublishCorrelationKey.class); 13 | 14 | public ErrorQueueRepublishCorrelationKey(ErrorQueueInfrastructure errorQueueInfrastructure, 15 | MessageContainer messageContainer, 16 | FlowReceiverContainer flowReceiverContainer) { 17 | this.errorQueueInfrastructure = errorQueueInfrastructure; 18 | this.messageContainer = messageContainer; 19 | this.flowReceiverContainer = flowReceiverContainer; 20 | } 21 | 22 | public void handleSuccess() { 23 | flowReceiverContainer.acknowledge(messageContainer); 24 | } 25 | 26 | public void handleError() { 27 | while (true) { 28 | if (messageContainer.isStale()) { 29 | throw new IllegalStateException(String.format( 30 | "Cannot republish failed message container %s (XMLMessage %s) to error queue %s. Message is stale", 31 | messageContainer.getId(), 32 | messageContainer.getMessage().getMessageId(), 33 | errorQueueInfrastructure.getErrorQueueName()), null); 34 | } else if (errorQueueDeliveryAttempt >= errorQueueInfrastructure.getMaxDeliveryAttempts()) { 35 | fallback(); 36 | break; 37 | } else { 38 | errorQueueDeliveryAttempt++; 39 | LOGGER.info("Republishing XMLMessage {} to error queue {} - attempt {} of {}", 40 | messageContainer.getMessage().getMessageId(), 41 | errorQueueInfrastructure.getErrorQueueName(), 42 | errorQueueDeliveryAttempt, 43 | errorQueueInfrastructure.getMaxDeliveryAttempts()); 44 | try { 45 | errorQueueInfrastructure.send(messageContainer, this); 46 | break; 47 | } catch (Exception e) { 48 | LOGGER.warn("Could not send XMLMessage {} to error queue {}", 49 | messageContainer.getMessage().getMessageId(), errorQueueInfrastructure.getErrorQueueName()); 50 | } 51 | } 52 | } 53 | } 54 | 55 | private void fallback() { 56 | LOGGER.info("Exceeded max error queue delivery attempts. XMLMessage {} will be re-queued onto queue {}", 57 | messageContainer.getMessage().getMessageId(), flowReceiverContainer.getEndpointName()); 58 | flowReceiverContainer.requeue(messageContainer); 59 | } 60 | 61 | public String getSourceMessageId() { 62 | return messageContainer.getMessage().getMessageId(); 63 | } 64 | public String getErrorQueueName() { 65 | return errorQueueInfrastructure.getErrorQueueName(); 66 | } 67 | 68 | long getErrorQueueDeliveryAttempt() { 69 | return errorQueueDeliveryAttempt; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/util/MessageContainer.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.util; 2 | 3 | import com.solacesystems.jcsmp.BytesXMLMessage; 4 | 5 | import java.util.StringJoiner; 6 | import java.util.UUID; 7 | import java.util.concurrent.atomic.AtomicBoolean; 8 | 9 | public class MessageContainer { 10 | private final UUID id = UUID.randomUUID(); 11 | private final BytesXMLMessage message; 12 | private final UUID flowReceiverReferenceId; 13 | private final AtomicBoolean staleFlag; 14 | private boolean acknowledged; 15 | 16 | MessageContainer(BytesXMLMessage message, UUID flowReceiverReferenceId, AtomicBoolean staleFlag) { 17 | this.message = message; 18 | this.flowReceiverReferenceId = flowReceiverReferenceId; 19 | this.staleFlag = staleFlag; 20 | } 21 | 22 | public UUID getId() { 23 | return id; 24 | } 25 | 26 | public BytesXMLMessage getMessage() { 27 | return message; 28 | } 29 | 30 | public UUID getFlowReceiverReferenceId() { 31 | return flowReceiverReferenceId; 32 | } 33 | 34 | public boolean isAcknowledged() { 35 | return acknowledged; 36 | } 37 | 38 | public boolean isStale() { 39 | return staleFlag.get(); 40 | } 41 | 42 | void setAcknowledged(boolean acknowledged) { 43 | this.acknowledged = acknowledged; 44 | } 45 | 46 | @Override 47 | public String toString() { 48 | return new StringJoiner(", ", MessageContainer.class.getSimpleName() + "[", "]") 49 | .add("id=" + id) 50 | .add("message=" + message) 51 | .add("flowReceiverReferenceId=" + flowReceiverReferenceId) 52 | .add("staleFlag=" + staleFlag) 53 | .add("acknowledged=" + acknowledged) 54 | .toString(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/util/SharedResourceManager.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.util; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.util.HashSet; 7 | import java.util.Set; 8 | 9 | abstract class SharedResourceManager { 10 | private final String type; 11 | T sharedResource; 12 | private Set registeredIds = new HashSet<>(); 13 | private final Object lock = new Object(); 14 | 15 | private static final Logger LOGGER = LoggerFactory.getLogger(SharedResourceManager.class); 16 | 17 | SharedResourceManager(String type) { 18 | this.type = type; 19 | } 20 | 21 | abstract T create() throws Exception; 22 | abstract void close(); 23 | 24 | /** 25 | * Register {@code key} to the shared resource. 26 | *

If this is the first key to claim this shared resource, {@link #create()} the resource. 27 | * @param key the registration key of the caller that wants to use this resource 28 | * @return the shared resource 29 | * @throws Exception whatever exception that may be thrown by {@link #create()} 30 | */ 31 | public T get(String key) throws Exception { 32 | synchronized (lock) { 33 | if (registeredIds.isEmpty()) { 34 | LOGGER.info("No {} exists, a new one will be created", type); 35 | sharedResource = create(); 36 | } else { 37 | LOGGER.trace("A message {} already exists, reusing it", type); 38 | } 39 | 40 | registeredIds.add(key); 41 | } 42 | 43 | return sharedResource; 44 | } 45 | 46 | /** 47 | * De-register {@code key} from the shared resource. 48 | *

If this is the last {@code key} associated to the shared resource, {@link #close()} the resource. 49 | * @param key the registration key of the caller that is using the resource 50 | */ 51 | public void release(String key) { 52 | synchronized (lock) { 53 | if (!registeredIds.contains(key)) return; 54 | 55 | if (registeredIds.size() <= 1) { 56 | LOGGER.info("{} is the last user, closing {}...", key, type); 57 | close(); 58 | sharedResource = null; 59 | } else { 60 | LOGGER.info("{} is not the last user, persisting {}...", key, type); 61 | } 62 | registeredIds.remove(key); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/util/SmfMessageHeaderWriteCompatibility.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.util; 2 | 3 | /** 4 | * The compatibility mode for message headers when they're being written to the SMF message. 5 | */ 6 | public enum SmfMessageHeaderWriteCompatibility { 7 | /** 8 | * Only headers which are natively supported by SMF are allowed to be written. 9 | * Unsupported types will throw an exception. 10 | */ 11 | NATIVE_ONLY, 12 | 13 | /** 14 | * Non-native and serializable headers will be serialized to a byte array then encoded into a string with the 15 | * corresponding {@link com.solace.spring.cloud.stream.binder.messaging.SolaceBinderHeaders#SERIALIZED_HEADERS} and 16 | * {@link com.solace.spring.cloud.stream.binder.messaging.SolaceBinderHeaders#SERIALIZED_HEADERS_ENCODING} headers 17 | * set accordingly. 18 | * Native payloads will be written as usual. 19 | */ 20 | SERIALIZE_AND_ENCODE_NON_NATIVE_TYPES 21 | } 22 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/util/SmfMessagePayloadWriteCompatibility.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.util; 2 | 3 | /** 4 | * The compatibility mode for message payloads when they're being written to the SMF message. 5 | */ 6 | public enum SmfMessagePayloadWriteCompatibility { 7 | /** 8 | * Only payloads which are natively supported by SMF are allowed to be written. 9 | * Unsupported types will throw an exception. 10 | */ 11 | NATIVE_ONLY, 12 | 13 | /** 14 | * Non-native and serializable payloads will be serialized into a byte array with the corresponding 15 | * {@link com.solace.spring.cloud.stream.binder.messaging.SolaceBinderHeaders#SERIALIZED_PAYLOAD} header set 16 | * accordingly. 17 | * Native payloads will be written as usual. 18 | */ 19 | SERIALIZE_NON_NATIVE_TYPES 20 | } 21 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/util/SolaceAcknowledgmentException.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.util; 2 | 3 | public class SolaceAcknowledgmentException extends RuntimeException { 4 | public SolaceAcknowledgmentException(String message, Throwable cause) { 5 | super(message, cause); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/util/SolaceBatchAcknowledgementException.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.util; 2 | 3 | import java.util.Set; 4 | 5 | public class SolaceBatchAcknowledgementException extends SolaceAcknowledgmentException { 6 | 7 | private final Set failedMessageIndexes; 8 | 9 | public SolaceBatchAcknowledgementException(Set failedMessageIndexes, String message, 10 | Throwable cause) { 11 | super(message, cause); 12 | this.failedMessageIndexes = failedMessageIndexes; 13 | } 14 | 15 | public Set getFailedMessageIndexes() { 16 | return failedMessageIndexes; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/util/SolaceFlowEventHandler.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.util; 2 | 3 | import com.solacesystems.jcsmp.FlowEvent; 4 | import com.solacesystems.jcsmp.FlowEventArgs; 5 | import com.solacesystems.jcsmp.FlowEventHandler; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | public class SolaceFlowEventHandler implements FlowEventHandler { 10 | 11 | private static final Logger LOGGER = LoggerFactory.getLogger(SolaceFlowEventHandler.class); 12 | private final XMLMessageMapper xmlMessageMapper; 13 | private final String flowReceiverContainerId; 14 | 15 | public SolaceFlowEventHandler(XMLMessageMapper xmlMessageMapper, String flowReceiverContainerId) { 16 | this.xmlMessageMapper = xmlMessageMapper; 17 | this.flowReceiverContainerId = flowReceiverContainerId; 18 | } 19 | 20 | @Override 21 | public void handleEvent(Object source, FlowEventArgs flowEventArgs) { 22 | LOGGER.debug("({}): Received Solace Flow event [{}].", source, flowEventArgs); 23 | 24 | if (flowEventArgs.getEvent() == FlowEvent.FLOW_RECONNECTED && xmlMessageMapper != null) { 25 | LOGGER.debug("Received flow event {} for flow receiver container {}. Will clear ignored properties.", 26 | flowEventArgs.getEvent().name(), flowReceiverContainerId); 27 | xmlMessageMapper.resetIgnoredProperties(flowReceiverContainerId); 28 | } 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/util/SolaceMessageConversionException.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.util; 2 | 3 | public class SolaceMessageConversionException extends RuntimeException { 4 | public SolaceMessageConversionException(String message) { 5 | super(message); 6 | } 7 | 8 | public SolaceMessageConversionException(Throwable throwable) { 9 | super(throwable); 10 | } 11 | 12 | public SolaceMessageConversionException(String message, Throwable throwable) { 13 | super(message, throwable); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/util/SolaceMessageHeaderErrorMessageStrategy.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.util; 2 | 3 | import org.springframework.core.AttributeAccessor; 4 | import org.springframework.integration.IntegrationMessageHeaderAccessor; 5 | import org.springframework.integration.support.ErrorMessageStrategy; 6 | import org.springframework.integration.support.ErrorMessageUtils; 7 | import org.springframework.messaging.Message; 8 | import org.springframework.messaging.support.ErrorMessage; 9 | 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | 13 | public class SolaceMessageHeaderErrorMessageStrategy implements ErrorMessageStrategy { 14 | public static final String ATTR_SOLACE_RAW_MESSAGE = "solace_sourceData"; 15 | public static final String ATTR_SOLACE_ACKNOWLEDGMENT_CALLBACK = "solace_acknowledgmentCallback"; 16 | 17 | @Override 18 | public ErrorMessage buildErrorMessage(Throwable throwable, AttributeAccessor attributeAccessor) { 19 | Object inputMessage; 20 | Map headers = new HashMap<>(); 21 | if (attributeAccessor == null) { 22 | inputMessage = null; 23 | } else { 24 | inputMessage = attributeAccessor.getAttribute(ErrorMessageUtils.INPUT_MESSAGE_CONTEXT_KEY); 25 | Object sourceData = attributeAccessor.getAttribute(ATTR_SOLACE_RAW_MESSAGE); 26 | if (sourceData != null) { 27 | headers.put(IntegrationMessageHeaderAccessor.SOURCE_DATA, sourceData); 28 | } 29 | Object ackCallback = attributeAccessor.getAttribute(ATTR_SOLACE_ACKNOWLEDGMENT_CALLBACK); 30 | if (ackCallback != null) { 31 | headers.put(IntegrationMessageHeaderAccessor.ACKNOWLEDGMENT_CALLBACK, ackCallback); 32 | } 33 | } 34 | return inputMessage instanceof Message ? new ErrorMessage(throwable, headers, (Message) inputMessage) : 35 | new ErrorMessage(throwable, headers); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/util/StaticMessageHeaderMapAccessor.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.util; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * Utility class to perform generic header accessing operations without needing to create a 7 | * {@link org.springframework.messaging.MessageHeaders MessageHeaders} object. 8 | */ 9 | public final class StaticMessageHeaderMapAccessor { 10 | public static T get(Map headers, String key, Class type) { 11 | Object value = headers.get(key); 12 | if (value == null) { 13 | return null; 14 | } 15 | if (!type.isAssignableFrom(value.getClass())) { 16 | throw new IllegalArgumentException(String.format( 17 | "Incorrect type specified for header '%s'. Expected [%s] but actual type is [%s]", 18 | key, type, value.getClass())); 19 | } 20 | 21 | @SuppressWarnings("unchecked") 22 | T toReturn = (T) value; 23 | 24 | return toReturn; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/util/ToStringer.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.util; 2 | 3 | import com.solacesystems.jcsmp.ConsumerFlowProperties; 4 | import com.solacesystems.jcsmp.Endpoint; 5 | import com.solacesystems.jcsmp.EndpointProperties; 6 | 7 | /** 8 | * To string utility for 3'rd party classes that do not override toString in a meaningful way, to be used for logging or debugging purposes 9 | */ 10 | public final class ToStringer { 11 | 12 | /** 13 | * provides a simplified toString for {@link EndpointProperties} 14 | * @param ep to tbe turned to String 15 | * @return string representation of the object 16 | */ 17 | public static String toString(EndpointProperties ep) { 18 | if (ep== null) 19 | return "EndpointProperties{NULL}"; 20 | return "EndpointProperties{" + 21 | "mAccessType=" + ep.getAccessType() + 22 | ", mMaxMsgSize=" + ep.getMaxMsgSize() + 23 | ", mPermission=" + ep.getPermission() + 24 | '}'; 25 | } 26 | 27 | /** 28 | * provides a simplified toString for {@link Endpoint} 29 | * @param e to tbe turned to String 30 | * @return string representation of the object 31 | */ 32 | public static String toString(Endpoint e) { 33 | if (e==null) 34 | return "Endpoint{NULL}"; 35 | return "Endpoint{" + 36 | " class:" + e.getClass()+ 37 | " _name='" + e.getName() + '\'' + 38 | ", _durable=" + e.isDurable() + 39 | '}'; 40 | } 41 | 42 | /** 43 | * provides a simplified toString for {@link ConsumerFlowProperties} 44 | * @param cfp to tbe turned to String 45 | * @return string representation of the object 46 | */ 47 | public static String toString(ConsumerFlowProperties cfp) { 48 | 49 | return "ConsumerFlowProperties{" + 50 | "endpoint=" + toString(cfp.getEndpoint()) + 51 | ", newSubscription=" + cfp.getNewSubscription() + 52 | ", sqlSelector='" + cfp.getSelector() + '\'' + 53 | ", startState=" + cfp.isStartState() + 54 | ", noLocal=" + cfp.isNoLocal() + 55 | ", activeFlowIndication=" + cfp.isActiveFlowIndication() + 56 | ", ackMode='" + cfp.getAckMode() + '\'' + 57 | ", windowSize=" + cfp.getTransportWindowSize() + 58 | ", ackTimerMs=" + cfp.getAckTimerInMsecs() + 59 | ", ackThreshold=" + cfp.getAckThreshold() + 60 | ", reconnectTries=" + cfp.getReconnectTries() + 61 | ", outcomes=" + cfp.getRequiredSettlementOutcomes() + 62 | ", flowSessionProps=" + cfp.getFlowSessionProps() + 63 | ", segmentFlow=" + cfp.isSegmentFlow() + 64 | '}'; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/main/java/com/solace/spring/cloud/stream/binder/util/UnboundFlowReceiverContainerException.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.util; 2 | 3 | /** 4 | *

Flow receiver container is not bound to a flow receiver.

5 | *

Typically caused by one of:

6 | *
    7 | *
  • {@link FlowReceiverContainer#unbind()}
  • 8 | *
9 | */ 10 | public class UnboundFlowReceiverContainerException extends Exception { 11 | public UnboundFlowReceiverContainerException(String message) { 12 | super(message); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/test/java/com/solace/spring/cloud/stream/binder/health/base/SolaceHealthIndicatorTest.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.health.base; 2 | 3 | import com.solacesystems.jcsmp.FlowEvent; 4 | import com.solacesystems.jcsmp.FlowEventArgs; 5 | import org.junit.jupiter.api.BeforeEach; 6 | import org.junit.jupiter.api.Test; 7 | import org.springframework.boot.actuate.health.Health; 8 | import org.springframework.boot.actuate.health.Status; 9 | 10 | import static org.junit.jupiter.api.Assertions.assertEquals; 11 | 12 | class SolaceHealthIndicatorTest { 13 | 14 | private SolaceHealthIndicator solaceHealthIndicator; 15 | 16 | @BeforeEach 17 | void setUp() { 18 | this.solaceHealthIndicator = new SolaceHealthIndicator(); 19 | } 20 | 21 | @Test 22 | void healthUp() { 23 | this.solaceHealthIndicator.healthUp(); 24 | assertEquals(this.solaceHealthIndicator.health(), Health.up().build()); 25 | } 26 | 27 | @Test 28 | void healthReconnecting() { 29 | this.solaceHealthIndicator.healthReconnecting(null); 30 | assertEquals(this.solaceHealthIndicator.health(), Health.status("RECONNECTING").build()); 31 | } 32 | 33 | @Test 34 | void healthDown() { 35 | this.solaceHealthIndicator.healthDown(null); 36 | assertEquals(this.solaceHealthIndicator.health(), Health.down().build()); 37 | } 38 | 39 | @Test 40 | void addFlowEventDetails() { 41 | // as SessionEventArgs constructor has package level access modifier, we have to test with FlowEventArgs only 42 | FlowEventArgs flowEventArgs = new FlowEventArgs(FlowEvent.FLOW_DOWN, "String_infoStr", 43 | new Exception("Test Exception"), 500); 44 | Health health = this.solaceHealthIndicator.addEventDetails(Health.down(),flowEventArgs).build(); 45 | 46 | assertEquals(health.getStatus(), Status.DOWN); 47 | assertEquals(health.getDetails().get("error"), "java.lang.Exception: Test Exception"); 48 | assertEquals(health.getDetails().get("responseCode"), 500); 49 | } 50 | 51 | @Test 52 | void getHealth() { 53 | this.solaceHealthIndicator.setHealth(Health.up().build()); 54 | assertEquals(this.solaceHealthIndicator.health(), Health.up().build()); 55 | } 56 | 57 | @Test 58 | void setHealth() { 59 | this.solaceHealthIndicator.setHealth(Health.down().build()); 60 | assertEquals(this.solaceHealthIndicator.health(), Health.down().build()); 61 | } 62 | } -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/test/java/com/solace/spring/cloud/stream/binder/inbound/InboundXMLMessageListenerTest.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.inbound; 2 | 3 | import com.solace.spring.cloud.stream.binder.util.FlowReceiverContainer; 4 | import com.solace.spring.cloud.stream.binder.util.UnboundFlowReceiverContainerException; 5 | import com.solacesystems.jcsmp.JCSMPException; 6 | import com.solacesystems.jcsmp.StaleSessionException; 7 | import org.junit.jupiter.api.Test; 8 | import org.junit.jupiter.api.extension.ExtendWith; 9 | import org.mockito.Mock; 10 | import org.mockito.Mockito; 11 | import org.mockito.junit.jupiter.MockitoExtension; 12 | import org.springframework.boot.test.system.CapturedOutput; 13 | import org.springframework.boot.test.system.OutputCaptureExtension; 14 | import org.springframework.cloud.stream.provisioning.ConsumerDestination; 15 | 16 | import static org.assertj.core.api.Assertions.assertThat; 17 | import static org.mockito.Mockito.verify; 18 | import static org.mockito.Mockito.when; 19 | 20 | @ExtendWith(MockitoExtension.class) 21 | @ExtendWith(OutputCaptureExtension.class) 22 | public class InboundXMLMessageListenerTest { 23 | 24 | @Mock 25 | private ConsumerDestination consumerDestination; 26 | 27 | @Test 28 | public void testListenerIsStoppedOnStaleSessionException(@Mock FlowReceiverContainer flowReceiverContainer, CapturedOutput output) 29 | throws UnboundFlowReceiverContainerException, JCSMPException { 30 | 31 | when(flowReceiverContainer.receive(Mockito.anyInt())) 32 | .thenThrow(new StaleSessionException("Session has become stale", new JCSMPException("Specific JCSMP exception"))); 33 | 34 | BasicInboundXMLMessageListener inboundXMLMessageListener = new BasicInboundXMLMessageListener( 35 | flowReceiverContainer, consumerDestination, null, null, null, null, null, null, 36 | null, null, false); 37 | 38 | inboundXMLMessageListener.run(); 39 | 40 | assertThat(output) 41 | .contains("Session has lost connection") 42 | .contains("Closing flow receiver to destination"); 43 | 44 | verify(flowReceiverContainer).unbind(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/test/java/com/solace/spring/cloud/stream/binder/meter/SolaceMeterAccessorTest.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.meter; 2 | 3 | import com.solacesystems.jcsmp.BytesMessage; 4 | import com.solacesystems.jcsmp.JCSMPFactory; 5 | import org.junit.jupiter.api.Test; 6 | import org.junit.jupiter.api.extension.ExtendWith; 7 | import org.mockito.Mock; 8 | import org.mockito.Mockito; 9 | import org.mockito.junit.jupiter.MockitoExtension; 10 | 11 | @ExtendWith(MockitoExtension.class) 12 | public class SolaceMeterAccessorTest { 13 | @Test 14 | public void testRecordMessage(@Mock SolaceMessageMeterBinder messageMeterBinder) { 15 | SolaceMeterAccessor solaceMeterAccessor = new SolaceMeterAccessor(messageMeterBinder); 16 | String bindingName = "test-binding"; 17 | BytesMessage message = JCSMPFactory.onlyInstance().createMessage(BytesMessage.class); 18 | 19 | solaceMeterAccessor.recordMessage(bindingName, message); 20 | Mockito.verify(messageMeterBinder).recordMessage(bindingName, message); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/test/java/com/solace/spring/cloud/stream/binder/properties/SmfMessageWriterPropertiesTest.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.properties; 2 | 3 | import com.solace.spring.cloud.stream.binder.util.SmfMessageHeaderWriteCompatibility; 4 | import com.solace.spring.cloud.stream.binder.util.SmfMessagePayloadWriteCompatibility; 5 | import org.junitpioneer.jupiter.cartesian.CartesianTest; 6 | import org.junitpioneer.jupiter.cartesian.CartesianTest.Values; 7 | 8 | import static org.assertj.core.api.Assertions.assertThat; 9 | 10 | class SmfMessageWriterPropertiesTest { 11 | @CartesianTest 12 | void testCreateFromSolaceProducerProperties(@Values(booleans = {false, true}) boolean defaultValues) { 13 | SolaceProducerProperties producerProperties = new SolaceProducerProperties(); 14 | 15 | if (!defaultValues) { 16 | producerProperties.getHeaderExclusions().add("foobar"); 17 | producerProperties.setHeaderTypeCompatibility(SmfMessageHeaderWriteCompatibility.NATIVE_ONLY); 18 | producerProperties.setPayloadTypeCompatibility(SmfMessagePayloadWriteCompatibility.NATIVE_ONLY); 19 | producerProperties.setNonserializableHeaderConvertToString(true); 20 | } 21 | 22 | SmfMessageWriterProperties smfMessageWriterProperties = new SmfMessageWriterProperties(producerProperties); 23 | assertThat(smfMessageWriterProperties.getHeaderExclusions()) 24 | .containsExactlyInAnyOrderElementsOf(producerProperties.getHeaderExclusions()); 25 | assertThat(smfMessageWriterProperties.getHeaderTypeCompatibility()) 26 | .isSameAs(producerProperties.getHeaderTypeCompatibility()); 27 | assertThat(smfMessageWriterProperties.getPayloadTypeCompatibility()) 28 | .isSameAs(producerProperties.getPayloadTypeCompatibility()); 29 | assertThat(smfMessageWriterProperties.isNonSerializableHeaderConvertToString()) 30 | .isEqualTo(producerProperties.isNonserializableHeaderConvertToString()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/test/java/com/solace/spring/cloud/stream/binder/properties/SolaceConsumerPropertiesTest.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.properties; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | import static org.junit.jupiter.api.Assertions.assertThrows; 5 | import static org.junit.jupiter.api.Assertions.assertTrue; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.params.ParameterizedTest; 8 | import org.junit.jupiter.params.provider.ValueSource; 9 | 10 | public class SolaceConsumerPropertiesTest { 11 | @ParameterizedTest 12 | @ValueSource(ints = {1, 256}) 13 | public void testSetBatchMaxSize(int batchMaxSize) { 14 | SolaceConsumerProperties consumerProperties = new SolaceConsumerProperties(); 15 | consumerProperties.setBatchMaxSize(batchMaxSize); 16 | assertEquals(batchMaxSize, consumerProperties.getBatchMaxSize()); 17 | } 18 | 19 | @ParameterizedTest 20 | @ValueSource(ints = {-1, 0}) 21 | public void testFailSetBatchMaxSize(int batchMaxSize) { 22 | assertThrows(IllegalArgumentException.class, () -> new SolaceConsumerProperties() 23 | .setBatchMaxSize(batchMaxSize)); 24 | } 25 | 26 | @ParameterizedTest 27 | @ValueSource(ints = {0, 1, 1000}) 28 | public void testSetBatchTimeout(int batchTimeout) { 29 | SolaceConsumerProperties consumerProperties = new SolaceConsumerProperties(); 30 | consumerProperties.setBatchTimeout(batchTimeout); 31 | assertEquals(batchTimeout, consumerProperties.getBatchTimeout()); 32 | } 33 | 34 | @ParameterizedTest 35 | @ValueSource(ints = {-1}) 36 | public void testFailSetBatchTimeout(int batchTimeout) { 37 | assertThrows(IllegalArgumentException.class, () -> new SolaceConsumerProperties() 38 | .setBatchTimeout(batchTimeout)); 39 | } 40 | 41 | @Test 42 | void testDefaultHeaderExclusionsListIsEmpty() { 43 | assertTrue(new SolaceConsumerProperties().getHeaderExclusions().isEmpty()); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/test/java/com/solace/spring/cloud/stream/binder/test/junit/param/provider/SolaceSpringHeaderArgumentsProvider.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.test.junit.param.provider; 2 | 3 | import com.solace.spring.cloud.stream.binder.messaging.HeaderMeta; 4 | import com.solace.spring.cloud.stream.binder.messaging.SolaceBinderHeaderMeta; 5 | import com.solace.spring.cloud.stream.binder.messaging.SolaceBinderHeaders; 6 | import com.solace.spring.cloud.stream.binder.messaging.SolaceHeaderMeta; 7 | import com.solace.spring.cloud.stream.binder.messaging.SolaceHeaders; 8 | import org.junit.jupiter.api.extension.ExtensionContext; 9 | import org.junit.jupiter.params.provider.Arguments; 10 | import org.junit.jupiter.params.provider.ArgumentsProvider; 11 | 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | import java.util.stream.Stream; 15 | 16 | public class SolaceSpringHeaderArgumentsProvider implements ArgumentsProvider { 17 | private static final Map, Map>> ARGS; 18 | 19 | static { 20 | ARGS = new HashMap<>(); 21 | ARGS.put(SolaceHeaders.class, SolaceHeaderMeta.META); 22 | ARGS.put(SolaceBinderHeaders.class, SolaceBinderHeaderMeta.META); 23 | } 24 | 25 | @Override 26 | public Stream provideArguments(ExtensionContext context) { 27 | return ARGS.entrySet().stream().map(e -> Arguments.of(e.getKey(), e.getValue())); 28 | } 29 | 30 | public static class ClassesOnly implements ArgumentsProvider { 31 | @Override 32 | public Stream provideArguments(ExtensionContext context) { 33 | return ARGS.keySet().stream().map(Arguments::of); 34 | } 35 | } 36 | 37 | public static class MetaOnly implements ArgumentsProvider { 38 | @Override 39 | public Stream provideArguments(ExtensionContext context) { 40 | return ARGS.values().stream().map(Arguments::of); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/test/java/com/solace/spring/cloud/stream/binder/test/spring/BatchedMessageCollector.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.test.spring; 2 | 3 | import com.solace.spring.cloud.stream.binder.messaging.SolaceBinderHeaders; 4 | import org.springframework.integration.support.MessageBuilder; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.Set; 10 | import java.util.function.BiConsumer; 11 | import java.util.function.BinaryOperator; 12 | import java.util.function.Function; 13 | import java.util.function.Supplier; 14 | import java.util.stream.Collector; 15 | 16 | public class BatchedMessageCollector implements Collector>, MessageBuilder>> { 17 | private final Function getPayload; 18 | private final Function> getHeaders; 19 | 20 | public BatchedMessageCollector(Function getPayload, Function> getHeaders) { 21 | this.getPayload = getPayload; 22 | this.getHeaders = getHeaders; 23 | } 24 | 25 | 26 | @Override 27 | public Supplier>> supplier() { 28 | return () -> MessageBuilder.>withPayload(new ArrayList<>()) 29 | .setHeader(SolaceBinderHeaders.BATCHED_HEADERS, new ArrayList>()); 30 | } 31 | 32 | @Override 33 | public BiConsumer>, T> accumulator() { 34 | return (builder, elem) -> { 35 | builder.getPayload().add(getPayload.apply(elem)); 36 | @SuppressWarnings("unchecked") 37 | List> batchedHeaders = (List>) builder.getHeaders() 38 | .get(SolaceBinderHeaders.BATCHED_HEADERS); 39 | batchedHeaders.add(getHeaders.apply(elem)); 40 | }; 41 | } 42 | 43 | @Override 44 | public BinaryOperator>> combiner() { 45 | return (left, right) -> { 46 | @SuppressWarnings("unchecked") 47 | List> leftBatchedHeaders = (List>) left.getHeaders() 48 | .get(SolaceBinderHeaders.BATCHED_HEADERS); 49 | @SuppressWarnings("unchecked") 50 | List> rightBatchedHeaders = (List>) right.getHeaders() 51 | .get(SolaceBinderHeaders.BATCHED_HEADERS); 52 | leftBatchedHeaders.addAll(rightBatchedHeaders); 53 | left.getPayload().addAll(right.getPayload()); 54 | return left; 55 | }; 56 | } 57 | 58 | @Override 59 | public Function>, MessageBuilder>> finisher() { 60 | return b -> b; 61 | } 62 | 63 | @Override 64 | public Set characteristics() { 65 | return Set.of(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/test/java/com/solace/spring/cloud/stream/binder/test/spring/MessageGenerator.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.test.spring; 2 | 3 | import org.apache.commons.lang3.tuple.ImmutablePair; 4 | import org.springframework.integration.support.MessageBuilder; 5 | 6 | import java.util.Map; 7 | import java.util.function.Function; 8 | import java.util.stream.IntStream; 9 | 10 | public final class MessageGenerator { 11 | public static MessageBuilder generateMessage(Function payloadGenerator, 12 | Function> headersGenerator, 13 | BatchingConfig batchingConfig) { 14 | if (batchingConfig.isEnabled()) { 15 | return IntStream.range(0, batchingConfig.getNumberOfMessages()) 16 | .mapToObj(i -> new ImmutablePair<>(payloadGenerator.apply(i), headersGenerator.apply(i))) 17 | .collect(new BatchedMessageCollector<>(ImmutablePair::getLeft, ImmutablePair::getRight)); 18 | } else { 19 | return MessageBuilder.withPayload(payloadGenerator.apply(0)) 20 | .copyHeaders(headersGenerator.apply(0)); 21 | } 22 | } 23 | 24 | public static class BatchingConfig { 25 | private boolean enabled; 26 | private int numberOfMessages = 256; 27 | 28 | public boolean isEnabled() { 29 | return enabled; 30 | } 31 | 32 | public BatchingConfig setEnabled(boolean enabled) { 33 | this.enabled = enabled; 34 | return this; 35 | } 36 | 37 | public int getNumberOfMessages() { 38 | return numberOfMessages; 39 | } 40 | 41 | public BatchingConfig setNumberOfMessages(int numberOfMessages) { 42 | this.numberOfMessages = numberOfMessages; 43 | return this; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/test/java/com/solace/spring/cloud/stream/binder/test/util/RetryableAssertions.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.test.util; 2 | 3 | import org.assertj.core.api.SoftAssertions; 4 | import org.assertj.core.api.SoftAssertionsProvider; 5 | 6 | import java.time.Duration; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | public class RetryableAssertions { 10 | public static Duration RETRY_INTERVAL = Duration.ofMillis(500); 11 | 12 | public static void retryAssert(SoftAssertionsProvider.ThrowingRunnable assertRun) throws InterruptedException { 13 | retryAssert(assertRun, 30, TimeUnit.SECONDS); 14 | } 15 | 16 | @SuppressWarnings("BusyWait") 17 | public static void retryAssert(SoftAssertionsProvider.ThrowingRunnable assertRun, long timeout, TimeUnit unit) 18 | throws InterruptedException { 19 | final long expiry = System.currentTimeMillis() + unit.toMillis(timeout); 20 | SoftAssertions softAssertions; 21 | do { 22 | softAssertions = new SoftAssertions(); 23 | softAssertions.check(assertRun); 24 | if (!softAssertions.wasSuccess()) { 25 | Thread.sleep(RETRY_INTERVAL.toMillis()); 26 | } 27 | } while (!softAssertions.wasSuccess() && System.currentTimeMillis() < expiry); 28 | softAssertions.assertAll(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/test/java/com/solace/spring/cloud/stream/binder/test/util/SerializableFoo.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.test.util; 2 | 3 | import java.io.Serializable; 4 | import java.util.Objects; 5 | 6 | public class SerializableFoo implements Serializable { 7 | private final String someVar0; 8 | private final String someVar1; 9 | 10 | public SerializableFoo(String someVar0, String someVar1) { 11 | this.someVar0 = someVar0; 12 | this.someVar1 = someVar1; 13 | } 14 | 15 | @Override 16 | public boolean equals(Object o) { 17 | if (this == o) return true; 18 | if (o == null || getClass() != o.getClass()) return false; 19 | SerializableFoo that = (SerializableFoo) o; 20 | return Objects.equals(someVar0, that.someVar0) && 21 | Objects.equals(someVar1, that.someVar1); 22 | } 23 | 24 | @Override 25 | public int hashCode() { 26 | return Objects.hash(someVar0, someVar1); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/test/java/com/solace/spring/cloud/stream/binder/test/util/ThrowingFunction.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.test.util; 2 | 3 | 4 | import java.util.function.Function; 5 | 6 | @FunctionalInterface 7 | public interface ThrowingFunction extends Function { 8 | 9 | @Override 10 | default R apply(T t) { 11 | try { 12 | return applyThrows(t); 13 | } catch (Throwable e) { 14 | throw new RuntimeException(e); 15 | } 16 | } 17 | 18 | R applyThrows(T t) throws Throwable; 19 | } 20 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/test/java/com/solace/spring/cloud/stream/binder/util/BatchProxyCorrelationKeyTest.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.util; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.assertj.core.api.Assertions.assertThat; 6 | 7 | public class BatchProxyCorrelationKeyTest { 8 | @Test 9 | public void testSuccess() { 10 | Object target = new Object(); 11 | BatchProxyCorrelationKey correlationKey = new BatchProxyCorrelationKey(target, 3); 12 | assertThat(correlationKey.getCorrelationKeyForSuccess()).isNull(); 13 | assertThat(correlationKey.getCorrelationKeyForSuccess()).isNull(); 14 | assertThat(correlationKey.getCorrelationKeyForSuccess()).isEqualTo(target); 15 | 16 | // ensure subsequent calls always returns null 17 | assertThat(correlationKey.getCorrelationKeyForSuccess()).isNull(); 18 | assertThat(correlationKey.getCorrelationKeyForFailure()).isNull(); 19 | } 20 | 21 | @Test 22 | public void testFailed() { 23 | Object target = new Object(); 24 | BatchProxyCorrelationKey correlationKey = new BatchProxyCorrelationKey(target, 3); 25 | assertThat(correlationKey.getCorrelationKeyForSuccess()).isNull(); 26 | assertThat(correlationKey.getCorrelationKeyForFailure()).isEqualTo(target); 27 | 28 | // ensure subsequent calls always returns null 29 | assertThat(correlationKey.getCorrelationKeyForSuccess()).isNull(); 30 | assertThat(correlationKey.getCorrelationKeyForSuccess()).isNull(); 31 | assertThat(correlationKey.getCorrelationKeyForSuccess()).isNull(); 32 | assertThat(correlationKey.getCorrelationKeyForFailure()).isNull(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/test/java/com/solace/spring/cloud/stream/binder/util/StaticMessageHeaderMapAccessorTest.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.util; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.junitpioneer.jupiter.cartesian.CartesianTest; 5 | import org.junitpioneer.jupiter.cartesian.CartesianTest.Values; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | import static org.assertj.core.api.Assertions.assertThat; 11 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 12 | 13 | public class StaticMessageHeaderMapAccessorTest { 14 | @Test 15 | void testGet() { 16 | assertThat(StaticMessageHeaderMapAccessor.get(Map.ofEntries( 17 | Map.entry("test-key", "foobar"), 18 | Map.entry("other-key", new Object()) 19 | ), "test-key", String.class)).isEqualTo("foobar"); 20 | } 21 | 22 | @CartesianTest(name = "[{index}] definedEntry={0}") 23 | void testGetMissing(@Values(booleans = {false, true}) boolean definedEntry) { 24 | Map headers = new HashMap<>(); 25 | headers.put("other-key", new Object()); 26 | if (definedEntry) { 27 | headers.put("test-key", null); 28 | } 29 | assertThat(StaticMessageHeaderMapAccessor.get(headers, "test-key", String.class)).isNull(); 30 | } 31 | 32 | @Test 33 | void testGetThrow() { 34 | assertThatThrownBy(() -> StaticMessageHeaderMapAccessor.get(Map.of("test-key", new Object()), 35 | "test-key", String.class)) 36 | .isInstanceOf(IllegalArgumentException.class) 37 | .hasMessage("Incorrect type specified for header 'test-key'. Expected [class java.lang.String] but actual type is [class java.lang.Object]"); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/test/resources/META-INF/services/com.solace.test.integration.junit.jupiter.extension.PubSubPlusExtension$ExternalProvider: -------------------------------------------------------------------------------- 1 | com.solace.spring.cloud.stream.binder.test.junit.extension.pubsubplus.provider.PubSubPlusSpringProvider 2 | com.solace.test.integration.junit.jupiter.extension.pubsubplus.provider.PubSubPlusFileProvider 3 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension: -------------------------------------------------------------------------------- 1 | com.solace.test.integration.junit.jupiter.extension.LogTestInfoExtension 2 | org.assertj.core.api.junit.jupiter.SoftAssertionsExtension 3 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/test/resources/junit-platform.properties: -------------------------------------------------------------------------------- 1 | junit.jupiter.extensions.autodetection.enabled=true 2 | 3 | # Parallel test execution is disabled by default for easy debugging in IDEs. 4 | # It is overridden to be enabled by the Maven Surefire/Failsafe plugins. 5 | junit.jupiter.execution.parallel.enabled=false 6 | 7 | # Configured based on Github-hosted runners for public repositories. 8 | # https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories 9 | junit.jupiter.execution.parallel.config.strategy=fixed 10 | # Parallelism should ideally equal to the num of processors on the machine 11 | junit.jupiter.execution.parallel.config.fixed.parallelism=4 12 | junit.jupiter.execution.parallel.config.fixed.max-pool-size=20 13 | 14 | junit.jupiter.execution.parallel.mode.default=concurrent 15 | junit.jupiter.execution.parallel.mode.classes.default=concurrent 16 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder-core/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/main/java-templates/com/solace/spring/cloud/stream/binder/config/SolaceBinderClientInfoProvider.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.config; 2 | 3 | import com.solacesystems.jcsmp.impl.client.ClientInfoProvider; 4 | 5 | public class SolaceBinderClientInfoProvider extends ClientInfoProvider { 6 | 7 | public static final String VERSION = "@project.version@"; 8 | 9 | public String getSoftwareVersion() { 10 | return String.format("%s (%s)", VERSION, super.getSoftwareVersion()); 11 | } 12 | 13 | public String getSoftwareDate() { 14 | return String.format("@build.timestamp@ (%s)", super.getSoftwareDate()); 15 | } 16 | 17 | public String getPlatform() { 18 | return this.getPlatform("@project.name@ (JCSMP SDK)"); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/main/java/com/solace/spring/cloud/stream/binder/config/ExtendedBindingHandlerMappingsProviderConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.config; 2 | 3 | import org.springframework.boot.context.properties.source.ConfigurationPropertyName; 4 | import org.springframework.cloud.stream.config.BindingHandlerAdvise.MappingsProvider; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | @Configuration 12 | public class ExtendedBindingHandlerMappingsProviderConfiguration { 13 | 14 | @Bean 15 | public MappingsProvider solaceExtendedPropertiesDefaultMappingsProvider() { 16 | return () -> { 17 | Map mappings = new HashMap<>(); 18 | mappings.put(ConfigurationPropertyName.of("spring.cloud.stream.solace.bindings"), 19 | ConfigurationPropertyName.of("spring.cloud.stream.solace.default")); 20 | return mappings; 21 | }; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/main/java/com/solace/spring/cloud/stream/binder/config/SolaceHealthIndicatorsConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.config; 2 | 3 | import com.solace.spring.cloud.stream.binder.health.SolaceBinderHealthAccessor; 4 | import com.solace.spring.cloud.stream.binder.health.contributors.BindingsHealthContributor; 5 | import com.solace.spring.cloud.stream.binder.health.contributors.SolaceBinderHealthContributor; 6 | import com.solace.spring.cloud.stream.binder.health.handlers.SolaceSessionEventHandler; 7 | import com.solace.spring.cloud.stream.binder.health.indicators.SessionHealthIndicator; 8 | import com.solace.spring.cloud.stream.binder.properties.SolaceSessionHealthProperties; 9 | import com.solacesystems.jcsmp.JCSMPProperties; 10 | import com.solacesystems.jcsmp.SolaceSessionOAuth2TokenProvider; 11 | import jakarta.annotation.Nullable; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; 15 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 16 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 17 | import org.springframework.context.annotation.Bean; 18 | import org.springframework.context.annotation.Configuration; 19 | 20 | @Configuration 21 | @ConditionalOnClass(name = "org.springframework.boot.actuate.health.HealthIndicator") 22 | @ConditionalOnEnabledHealthIndicator("binders") 23 | @EnableConfigurationProperties({SolaceSessionHealthProperties.class}) 24 | public class SolaceHealthIndicatorsConfiguration { 25 | private static final Logger LOGGER = LoggerFactory.getLogger(SolaceHealthIndicatorsConfiguration.class); 26 | 27 | @Bean 28 | public SolaceBinderHealthAccessor solaceBinderHealthAccessor( 29 | SolaceBinderHealthContributor solaceBinderHealthContributor) { 30 | return new SolaceBinderHealthAccessor(solaceBinderHealthContributor); 31 | } 32 | 33 | @Bean 34 | public SolaceBinderHealthContributor solaceBinderHealthContributor( 35 | SolaceSessionHealthProperties solaceSessionHealthProperties) { 36 | LOGGER.debug("Creating Solace Connection Health Indicators Hierarchy"); 37 | return new SolaceBinderHealthContributor( 38 | new SessionHealthIndicator(solaceSessionHealthProperties), 39 | new BindingsHealthContributor() 40 | ); 41 | } 42 | 43 | @Bean 44 | public SolaceSessionEventHandler solaceSessionEventHandler( 45 | JCSMPProperties jcsmpProperties, 46 | @Nullable SolaceSessionOAuth2TokenProvider solaceSessionOAuth2TokenProvider, 47 | SolaceBinderHealthContributor healthContributor) { 48 | LOGGER.debug("Creating Solace Session Event Handler for monitoring Health"); 49 | return new SolaceSessionEventHandler(jcsmpProperties, solaceSessionOAuth2TokenProvider, healthContributor.getSolaceSessionHealthIndicator()); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/main/java/com/solace/spring/cloud/stream/binder/config/SolaceMeterConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.config; 2 | 3 | import com.solace.spring.cloud.stream.binder.meter.SolaceMessageMeterBinder; 4 | import com.solace.spring.cloud.stream.binder.meter.SolaceMeterAccessor; 5 | import io.micrometer.core.instrument.MeterRegistry; 6 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | @Configuration 11 | @ConditionalOnClass(MeterRegistry.class) 12 | public class SolaceMeterConfiguration { 13 | @Bean 14 | public SolaceMessageMeterBinder solaceMessageMeterBinder() { 15 | return new SolaceMessageMeterBinder(); 16 | } 17 | 18 | @Bean 19 | public SolaceMeterAccessor solaceMeterAccessor(SolaceMessageMeterBinder solaceMessageMeterBinder) { 20 | return new SolaceMeterAccessor(solaceMessageMeterBinder); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/main/java/com/solace/spring/cloud/stream/binder/config/SolaceServiceAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.config; 2 | 3 | import com.solace.spring.boot.autoconfigure.SolaceJavaAutoConfiguration; 4 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 5 | import org.springframework.cloud.stream.binder.Binder; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.context.annotation.Import; 8 | 9 | @Configuration 10 | @ConditionalOnMissingBean(Binder.class) 11 | @Import({ SolaceMessageChannelBinderConfiguration.class, SolaceJavaAutoConfiguration.class }) 12 | public class SolaceServiceAutoConfiguration { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/main/resources/META-INF/shared.beans: -------------------------------------------------------------------------------- 1 | com.solace.spring.cloud.stream.binder.meter.SolaceMessageMeterBinder 2 | com.solace.spring.cloud.stream.binder.meter.SolaceMeterAccessor 3 | org.springframework.security.oauth2.client.registration.ClientRegistrationRepository 4 | org.springframework.security.oauth2.client.OAuth2AuthorizedClientService 5 | org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/main/resources/META-INF/spring.binders: -------------------------------------------------------------------------------- 1 | solace:\ 2 | com.solace.spring.cloud.stream.binder.config.SolaceServiceAutoConfiguration -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | com.solace.spring.cloud.stream.binder.config.ExtendedBindingHandlerMappingsProviderConfiguration 2 | com.solace.spring.cloud.stream.binder.config.SolaceMeterConfiguration -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/java/com/solace/spring/cloud/stream/binder/config/SolaceBinderClientInfoProviderTest.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.config; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.regex.Pattern; 6 | 7 | import static org.assertj.core.api.Assertions.assertThat; 8 | 9 | public class SolaceBinderClientInfoProviderTest { 10 | @Test 11 | public void testSoftwareVersion() { 12 | Pattern versionPattern = Pattern.compile("[0-9]+\\.[0-9]+\\.[0-9]+"); 13 | Pattern pattern = Pattern.compile(String.format("%s(?:-SNAPSHOT)? \\(%s\\)", versionPattern, versionPattern)); 14 | assertThat(new SolaceBinderClientInfoProvider().getSoftwareVersion()).matches(pattern); 15 | } 16 | 17 | @Test 18 | public void testSoftwareDate() { 19 | Pattern datePattern = Pattern.compile("[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}"); 20 | Pattern pattern = Pattern.compile(String.format("%s \\(%s\\)", datePattern, datePattern)); 21 | assertThat(new SolaceBinderClientInfoProvider().getSoftwareDate()).matches(pattern); 22 | } 23 | 24 | @Test 25 | public void testPlatform() { 26 | String platformPostfix = "Solace Spring Cloud Stream Binder (JCSMP SDK)"; 27 | assertThat(new SolaceBinderClientInfoProvider().getPlatform()).endsWith(platformPostfix); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/java/com/solace/spring/cloud/stream/binder/health/handlers/SolaceSessionEventHandlerTest.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.health.handlers; 2 | 3 | import com.solace.spring.cloud.stream.binder.health.indicators.SessionHealthIndicator; 4 | import com.solacesystems.jcsmp.JCSMPProperties; 5 | import com.solacesystems.jcsmp.SessionEvent; 6 | import com.solacesystems.jcsmp.SessionEventArgs; 7 | import org.junit.jupiter.api.Test; 8 | import org.junit.jupiter.api.extension.ExtendWith; 9 | import org.junit.jupiter.params.ParameterizedTest; 10 | import org.junit.jupiter.params.provider.EnumSource; 11 | import org.mockito.Mock; 12 | import org.mockito.Mockito; 13 | import org.mockito.junit.jupiter.MockitoExtension; 14 | 15 | @ExtendWith(MockitoExtension.class) 16 | public class SolaceSessionEventHandlerTest { 17 | @Test 18 | public void testConnected(@Mock SessionHealthIndicator healthIndicator) { 19 | SolaceSessionEventHandler sessionEventHandler = new SolaceSessionEventHandler(new JCSMPProperties(), null, healthIndicator); 20 | sessionEventHandler.setSessionHealthUp(); 21 | Mockito.verify(healthIndicator, Mockito.times(1)).up(); 22 | Mockito.verifyNoMoreInteractions(healthIndicator); 23 | } 24 | 25 | @ParameterizedTest 26 | @EnumSource(SessionEvent.class) 27 | public void testHandleEvent(SessionEvent event, 28 | @Mock SessionEventArgs eventArgs, 29 | @Mock SessionHealthIndicator healthIndicator) { 30 | Mockito.when(eventArgs.getEvent()).thenReturn(event); 31 | 32 | SolaceSessionEventHandler sessionEventHandler = new SolaceSessionEventHandler(new JCSMPProperties(), null, healthIndicator); 33 | sessionEventHandler.handleEvent(eventArgs); 34 | 35 | switch (event) { 36 | case DOWN_ERROR -> Mockito.verify(healthIndicator, Mockito.times(1)).down(eventArgs); 37 | case RECONNECTING -> Mockito.verify(healthIndicator, Mockito.times(1)).reconnecting(eventArgs); 38 | case RECONNECTED -> Mockito.verify(healthIndicator, Mockito.times(1)).up(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/java/com/solace/spring/cloud/stream/binder/health/indicators/SolaceBinderHealthIndicatorTest.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.health.indicators; 2 | 3 | import com.solace.spring.cloud.stream.binder.properties.SolaceSessionHealthProperties; 4 | import org.assertj.core.api.SoftAssertions; 5 | import org.junit.jupiter.api.BeforeEach; 6 | import org.junit.jupiter.api.Test; 7 | import org.springframework.boot.actuate.health.Health; 8 | import org.springframework.boot.actuate.health.Status; 9 | 10 | public class SolaceBinderHealthIndicatorTest { 11 | private SessionHealthIndicator healthIndicator; 12 | 13 | @BeforeEach 14 | void BeforeEach(){ 15 | SolaceSessionHealthProperties solaceSessionHealthProperties = new SolaceSessionHealthProperties(); 16 | solaceSessionHealthProperties.setReconnectAttemptsUntilDown(10); 17 | this.healthIndicator = new SessionHealthIndicator(solaceSessionHealthProperties); 18 | } 19 | 20 | @Test 21 | public void testUp(SoftAssertions softly) { 22 | healthIndicator.up(); 23 | Health health = healthIndicator.health(); 24 | softly.assertThat(health.getStatus()).isEqualTo(Status.UP); 25 | softly.assertThat(health.getDetails()).isEmpty(); 26 | } 27 | 28 | @Test 29 | public void testDown(SoftAssertions softly) { 30 | healthIndicator.down(null); 31 | Health health = healthIndicator.health(); 32 | softly.assertThat(health.getStatus()).isEqualTo(Status.DOWN); 33 | softly.assertThat(health.getDetails()).isEmpty(); 34 | } 35 | 36 | @Test 37 | public void testReconnecting(SoftAssertions softly) { 38 | healthIndicator.reconnecting(null); 39 | Health health = healthIndicator.health(); 40 | softly.assertThat(health.getStatus()).isEqualTo(new Status("RECONNECTING")); 41 | softly.assertThat(health.getDetails()).isEmpty(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/java/com/solace/spring/cloud/stream/binder/springBootTests/customizer/SpringCloudStreamApp.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.springBootTests.customizer; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class SpringCloudStreamApp { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(SpringCloudStreamApp.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/java/com/solace/spring/cloud/stream/binder/springBootTests/multibinder/SpringCloudStreamApp.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.springBootTests.multibinder; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.messaging.Message; 7 | 8 | import java.util.function.Consumer; 9 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 10 | import org.springframework.security.web.SecurityFilterChain; 11 | import org.springframework.security.web.util.matcher.AntPathRequestMatcher; 12 | 13 | @SpringBootApplication 14 | public class SpringCloudStreamApp { 15 | 16 | public static void main(String[] args) { 17 | SpringApplication.run(SpringCloudStreamApp.class, args); 18 | } 19 | 20 | @Bean 21 | public Consumer> consume() { 22 | return (msg -> System.out.println(msg.getPayload())); 23 | } 24 | 25 | @Bean 26 | public Consumer> otherConsume() { 27 | return (msg -> System.out.println(msg.getPayload())); 28 | } 29 | 30 | @Bean 31 | public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { 32 | http.authorizeHttpRequests(requests -> requests 33 | .requestMatchers(new AntPathRequestMatcher("/actuator/*")).permitAll() 34 | .anyRequest().authenticated()); 35 | 36 | return http.build(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/java/com/solace/spring/cloud/stream/binder/springBootTests/oauth2/SpringCloudStreamOAuth2App.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.springBootTests.oauth2; 2 | 3 | import java.util.function.Consumer; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.messaging.Message; 8 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 9 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 10 | import org.springframework.security.web.SecurityFilterChain; 11 | import org.springframework.security.web.util.matcher.AntPathRequestMatcher; 12 | 13 | @SpringBootApplication 14 | @EnableWebSecurity 15 | public class SpringCloudStreamOAuth2App { 16 | 17 | public static void main(String[] args) { 18 | SpringApplication.run(SpringCloudStreamOAuth2App.class, args); 19 | } 20 | 21 | @Bean 22 | public Consumer> consume() { 23 | return (msg -> System.out.println(msg.getPayload())); 24 | } 25 | 26 | @Bean 27 | public Consumer> otherConsume() { 28 | return (msg -> System.out.println(msg.getPayload())); 29 | } 30 | 31 | @Bean 32 | public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { 33 | http.authorizeHttpRequests(requests -> requests 34 | .requestMatchers(new AntPathRequestMatcher("/actuator/*")).permitAll() 35 | .anyRequest().authenticated()); 36 | 37 | return http.build(); 38 | } 39 | } -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/java/com/solace/spring/cloud/stream/binder/test/junit/extension/SpringCloudStreamExtension.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.test.junit.extension; 2 | 3 | import com.solace.spring.cloud.stream.binder.test.spring.SpringCloudStreamContext; 4 | import com.solace.test.integration.junit.jupiter.extension.PubSubPlusExtension; 5 | import org.junit.jupiter.api.extension.AfterEachCallback; 6 | import org.junit.jupiter.api.extension.BeforeEachCallback; 7 | import org.junit.jupiter.api.extension.ExtensionContext; 8 | import org.junit.jupiter.api.extension.ExtensionContext.Namespace; 9 | import org.junit.jupiter.api.extension.ParameterContext; 10 | import org.junit.jupiter.api.extension.ParameterResolutionException; 11 | import org.junit.jupiter.api.extension.ParameterResolver; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | 15 | /** 16 | * JUnit 5 extension to manage and inject {@link SpringCloudStreamContext} into test parameters. 17 | */ 18 | public class SpringCloudStreamExtension implements AfterEachCallback, BeforeEachCallback, ParameterResolver { 19 | private static final Namespace NAMESPACE = Namespace.create(SpringCloudStreamContext.class); 20 | private static final Logger LOGGER = LoggerFactory.getLogger(SpringCloudStreamExtension.class); 21 | 22 | @Override 23 | public void afterEach(ExtensionContext context) { 24 | SpringCloudStreamContext cloudStreamContext = context.getStore(NAMESPACE) 25 | .get(SpringCloudStreamContext.class, SpringCloudStreamContext.class); 26 | if (cloudStreamContext != null) { 27 | cloudStreamContext.cleanup(); 28 | } 29 | } 30 | 31 | @Override 32 | public void beforeEach(ExtensionContext context) { 33 | SpringCloudStreamContext cloudStreamContext = context.getStore(NAMESPACE) 34 | .get(SpringCloudStreamContext.class, SpringCloudStreamContext.class); 35 | if (cloudStreamContext != null) { 36 | cloudStreamContext.before(); 37 | } 38 | } 39 | 40 | @Override 41 | public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) 42 | throws ParameterResolutionException { 43 | return SpringCloudStreamContext.class.isAssignableFrom(parameterContext.getParameter().getType()); 44 | } 45 | 46 | @Override 47 | public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) 48 | throws ParameterResolutionException { 49 | Class paramType = parameterContext.getParameter().getType(); 50 | if (SpringCloudStreamContext.class.isAssignableFrom(paramType)) { 51 | return extensionContext.getStore(NAMESPACE).getOrComputeIfAbsent(SpringCloudStreamContext.class, 52 | key -> { 53 | LOGGER.info("Creating {}", SpringCloudStreamContext.class.getSimpleName()); 54 | SpringCloudStreamContext context = new SpringCloudStreamContext( 55 | PubSubPlusExtension.getJCSMPSession(extensionContext), 56 | PubSubPlusExtension.getSempV2Api(extensionContext)); 57 | context.before(); 58 | return context; 59 | }, 60 | SpringCloudStreamContext.class); 61 | } else { 62 | throw new ParameterResolutionException("Cannot resolve parameter type " + paramType.getSimpleName()); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/java/com/solace/spring/cloud/stream/binder/test/junit/extension/pubsubplus/provider/PubSubPlusSpringProvider.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.test.junit.extension.pubsubplus.provider; 2 | 3 | import com.solace.test.integration.junit.jupiter.extension.PubSubPlusExtension; 4 | import com.solace.test.integration.semp.v2.SempV2Api; 5 | import com.solacesystems.jcsmp.JCSMPProperties; 6 | import org.junit.jupiter.api.extension.ExtensionContext; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.beans.factory.NoSuchBeanDefinitionException; 10 | import org.springframework.context.ApplicationContext; 11 | import org.springframework.core.env.Environment; 12 | import org.springframework.test.context.junit.jupiter.SpringExtension; 13 | 14 | import java.util.stream.Collectors; 15 | import java.util.stream.Stream; 16 | 17 | public class PubSubPlusSpringProvider implements PubSubPlusExtension.ExternalProvider { 18 | private static final Logger LOGGER = LoggerFactory.getLogger(PubSubPlusSpringProvider.class); 19 | 20 | @Override 21 | public boolean isValid(ExtensionContext extensionContext) { 22 | ApplicationContext applicationContext = SpringExtension.getApplicationContext(extensionContext); 23 | Environment contextEnvironment = applicationContext.getEnvironment(); 24 | try { 25 | applicationContext.getBean(JCSMPProperties.class); 26 | } catch (NoSuchBeanDefinitionException e) { 27 | LOGGER.trace("Didn't find required bean: {}", JCSMPProperties.class, e); 28 | return false; 29 | } 30 | 31 | if (!Stream.of(TestProperties.values()).map(TestProperties::getProperty) 32 | .allMatch(contextEnvironment::containsProperty)) { 33 | LOGGER.trace("Didn't find required test properties: [{}]", Stream.of(TestProperties.values()) 34 | .map(TestProperties::getProperty) 35 | .collect(Collectors.joining(", "))); 36 | return false; 37 | } 38 | return true; 39 | } 40 | 41 | @Override 42 | public void init(ExtensionContext extensionContext) { 43 | // Do not cache anything in the root store. 44 | // There are tests which modify the config at runtime and caching will conflict with those tests. 45 | } 46 | 47 | @Override 48 | public JCSMPProperties createJCSMPProperties(ExtensionContext extensionContext) { 49 | return SpringExtension.getApplicationContext(extensionContext).getBean(JCSMPProperties.class); 50 | } 51 | 52 | @Override 53 | public SempV2Api createSempV2Api(ExtensionContext extensionContext) { 54 | Environment contextEnvironment = SpringExtension.getApplicationContext(extensionContext).getEnvironment(); 55 | String mgmtHost = contextEnvironment.getRequiredProperty(TestProperties.MGMT_HOST.getProperty()); 56 | String mgmtUsername = contextEnvironment.getRequiredProperty(TestProperties.MGMT_USERNAME.getProperty()); 57 | String mgmtPassword = contextEnvironment.getRequiredProperty(TestProperties.MGMT_PASSWORD.getProperty()); 58 | return new SempV2Api(mgmtHost, mgmtUsername, mgmtPassword); 59 | } 60 | 61 | private enum TestProperties { 62 | MGMT_HOST("test.solace.mgmt.host"), 63 | MGMT_USERNAME("test.solace.mgmt.username"), 64 | MGMT_PASSWORD("test.solace.mgmt.password"); 65 | 66 | private final String property; 67 | 68 | TestProperties(String propertyName) { 69 | this.property = propertyName; 70 | } 71 | 72 | public String getProperty() { 73 | return property; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/java/com/solace/spring/cloud/stream/binder/test/junit/launcher/filter/PostDiscoveryClassNameExclusionFilter.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.test.junit.launcher.filter; 2 | 3 | import com.solace.spring.cloud.stream.binder.test.spring.SpringCloudStreamContext; 4 | import org.junit.jupiter.engine.descriptor.ClassTestDescriptor; 5 | import org.junit.platform.engine.FilterResult; 6 | import org.junit.platform.engine.TestDescriptor; 7 | import org.junit.platform.launcher.PostDiscoveryFilter; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import java.util.Arrays; 12 | 13 | /** 14 | * Used by the JUnit Jupiter Engine to statically filter tests and test classes. 15 | */ 16 | public class PostDiscoveryClassNameExclusionFilter implements PostDiscoveryFilter { 17 | private static final Logger LOGGER = LoggerFactory.getLogger(PostDiscoveryClassNameExclusionFilter.class); 18 | 19 | @Override 20 | public FilterResult apply(final TestDescriptor object) { 21 | if (excludeByTestClass(object, SpringCloudStreamContext.class)) { 22 | return FilterResult.excluded("Skip tests ran from " + SpringCloudStreamContext.class.getSimpleName()); 23 | } else { 24 | return FilterResult.included("Is a valid test descriptor"); 25 | } 26 | } 27 | 28 | private boolean excludeByTestClass(final TestDescriptor object, Class... excludeClasses) { 29 | for (TestDescriptor testDescriptor = object; 30 | testDescriptor != null; 31 | testDescriptor = testDescriptor.getParent().orElse(null)) { 32 | 33 | if (testDescriptor instanceof ClassTestDescriptor) { 34 | ClassTestDescriptor classTestDescriptor = (ClassTestDescriptor) testDescriptor; 35 | if (Arrays.asList(excludeClasses).contains(classTestDescriptor.getTestClass())) { 36 | LOGGER.debug("Excluding test descriptor: {}", classTestDescriptor); 37 | return true; 38 | } 39 | } 40 | } 41 | return false; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/java/com/solace/spring/cloud/stream/binder/test/junit/param/provider/JCSMPMessageTypeArgumentsProvider.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.test.junit.param.provider; 2 | 3 | import com.solacesystems.jcsmp.BytesMessage; 4 | import com.solacesystems.jcsmp.BytesXMLMessage; 5 | import com.solacesystems.jcsmp.MapMessage; 6 | import com.solacesystems.jcsmp.StreamMessage; 7 | import com.solacesystems.jcsmp.TextMessage; 8 | import com.solacesystems.jcsmp.XMLContentMessage; 9 | import org.junit.jupiter.api.extension.ExtensionContext; 10 | import org.junit.jupiter.params.provider.Arguments; 11 | import org.junit.jupiter.params.provider.ArgumentsProvider; 12 | import org.junitpioneer.jupiter.cartesian.CartesianParameterArgumentsProvider; 13 | 14 | import java.lang.reflect.Parameter; 15 | import java.util.stream.Stream; 16 | 17 | public class JCSMPMessageTypeArgumentsProvider implements ArgumentsProvider, 18 | CartesianParameterArgumentsProvider> { 19 | @Override 20 | public Stream provideArguments(ExtensionContext context) { 21 | return provideArguments(context, null) 22 | .map(Arguments::of); 23 | } 24 | 25 | @Override 26 | public Stream> provideArguments(ExtensionContext context, Parameter parameter) { 27 | return Stream.of(TextMessage.class, 28 | BytesMessage.class, 29 | XMLContentMessage.class, 30 | MapMessage.class, 31 | StreamMessage.class); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/java/com/solace/spring/cloud/stream/binder/test/spring/BatchedMessageCollector.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.test.spring; 2 | 3 | import com.solace.spring.cloud.stream.binder.messaging.SolaceBinderHeaders; 4 | import org.springframework.integration.support.MessageBuilder; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.Set; 10 | import java.util.function.BiConsumer; 11 | import java.util.function.BinaryOperator; 12 | import java.util.function.Function; 13 | import java.util.function.Supplier; 14 | import java.util.stream.Collector; 15 | 16 | public class BatchedMessageCollector implements Collector>, MessageBuilder>> { 17 | private final Function getPayload; 18 | private final Function> getHeaders; 19 | 20 | public BatchedMessageCollector(Function getPayload, Function> getHeaders) { 21 | this.getPayload = getPayload; 22 | this.getHeaders = getHeaders; 23 | } 24 | 25 | 26 | @Override 27 | public Supplier>> supplier() { 28 | return () -> MessageBuilder.>withPayload(new ArrayList<>()) 29 | .setHeader(SolaceBinderHeaders.BATCHED_HEADERS, new ArrayList>()); 30 | } 31 | 32 | @Override 33 | public BiConsumer>, T> accumulator() { 34 | return (builder, elem) -> { 35 | builder.getPayload().add(getPayload.apply(elem)); 36 | @SuppressWarnings("unchecked") 37 | List> batchedHeaders = (List>) builder.getHeaders() 38 | .get(SolaceBinderHeaders.BATCHED_HEADERS); 39 | batchedHeaders.add(getHeaders.apply(elem)); 40 | }; 41 | } 42 | 43 | @Override 44 | public BinaryOperator>> combiner() { 45 | return (left, right) -> { 46 | @SuppressWarnings("unchecked") 47 | List> leftBatchedHeaders = (List>) left.getHeaders() 48 | .get(SolaceBinderHeaders.BATCHED_HEADERS); 49 | @SuppressWarnings("unchecked") 50 | List> rightBatchedHeaders = (List>) right.getHeaders() 51 | .get(SolaceBinderHeaders.BATCHED_HEADERS); 52 | leftBatchedHeaders.addAll(rightBatchedHeaders); 53 | left.getPayload().addAll(right.getPayload()); 54 | return left; 55 | }; 56 | } 57 | 58 | @Override 59 | public Function>, MessageBuilder>> finisher() { 60 | return b -> b; 61 | } 62 | 63 | @Override 64 | public Set characteristics() { 65 | return Set.of(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/java/com/solace/spring/cloud/stream/binder/test/spring/MessageGenerator.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.test.spring; 2 | 3 | import org.apache.commons.lang3.tuple.ImmutablePair; 4 | import org.springframework.integration.support.MessageBuilder; 5 | 6 | import java.util.Map; 7 | import java.util.function.Function; 8 | import java.util.stream.IntStream; 9 | 10 | public final class MessageGenerator { 11 | public static MessageBuilder generateMessage(Function payloadGenerator, 12 | Function> headersGenerator, 13 | BatchingConfig batchingConfig) { 14 | if (batchingConfig.isEnabled()) { 15 | return IntStream.range(0, batchingConfig.getNumberOfMessages()) 16 | .mapToObj(i -> new ImmutablePair<>(payloadGenerator.apply(i), headersGenerator.apply(i))) 17 | .collect(new BatchedMessageCollector<>(ImmutablePair::getLeft, ImmutablePair::getRight)); 18 | } else { 19 | return MessageBuilder.withPayload(payloadGenerator.apply(0)) 20 | .copyHeaders(headersGenerator.apply(0)); 21 | } 22 | } 23 | 24 | public static class BatchingConfig { 25 | private boolean enabled; 26 | private int numberOfMessages = 256; 27 | 28 | public boolean isEnabled() { 29 | return enabled; 30 | } 31 | 32 | public BatchingConfig setEnabled(boolean enabled) { 33 | this.enabled = enabled; 34 | return this; 35 | } 36 | 37 | public int getNumberOfMessages() { 38 | return numberOfMessages; 39 | } 40 | 41 | public BatchingConfig setNumberOfMessages(int numberOfMessages) { 42 | this.numberOfMessages = numberOfMessages; 43 | return this; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/java/com/solace/spring/cloud/stream/binder/test/spring/MessageLayout.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.test.spring; 2 | 3 | import com.solace.spring.cloud.stream.binder.util.BatchWaitStrategy; 4 | import org.springframework.lang.Nullable; 5 | 6 | public enum MessageLayout { 7 | SINGLE(false), 8 | BATCHED_TIMEOUT(true, BatchWaitStrategy.RESPECT_TIMEOUT), 9 | BATCHED_IMMEDIATE(true, BatchWaitStrategy.IMMEDIATE); 10 | 11 | private final boolean isBatched; 12 | @Nullable private final BatchWaitStrategy waitStrategy; 13 | 14 | MessageLayout(boolean isBatched) { 15 | this(isBatched, null); 16 | } 17 | 18 | MessageLayout(boolean isBatched, @Nullable BatchWaitStrategy waitStrategy) { 19 | this.isBatched = isBatched; 20 | this.waitStrategy = waitStrategy; 21 | } 22 | 23 | public boolean isBatched() { 24 | return isBatched; 25 | } 26 | 27 | public BatchWaitStrategy getWaitStrategy() { 28 | if (waitStrategy == null || !isBatched) { 29 | throw new UnsupportedOperationException("Message layout is not batched"); 30 | } 31 | return waitStrategy; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/java/com/solace/spring/cloud/stream/binder/test/spring/configuration/TestMeterRegistryConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.test.spring.configuration; 2 | 3 | import io.micrometer.core.instrument.Clock; 4 | import io.micrometer.core.instrument.MeterRegistry; 5 | import io.micrometer.core.instrument.composite.CompositeMeterRegistry; 6 | import io.micrometer.core.instrument.logging.LoggingMeterRegistry; 7 | import io.micrometer.core.instrument.logging.LoggingRegistryConfig; 8 | import io.micrometer.core.instrument.simple.SimpleMeterRegistry; 9 | import org.springframework.boot.test.context.TestConfiguration; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.context.annotation.Primary; 12 | 13 | import java.time.Duration; 14 | import java.util.List; 15 | 16 | @TestConfiguration 17 | public class TestMeterRegistryConfiguration { 18 | @Bean 19 | @Primary 20 | public CompositeMeterRegistry compositeMeterRegistry(List meterRegistries) { 21 | CompositeMeterRegistry compositeMeterRegistry = new CompositeMeterRegistry(); 22 | meterRegistries.forEach(compositeMeterRegistry::add); 23 | return compositeMeterRegistry; 24 | } 25 | 26 | @Bean 27 | public SimpleMeterRegistry simpleMeterRegistry() { 28 | return new SimpleMeterRegistry(); 29 | } 30 | 31 | @Bean 32 | public LoggingMeterRegistry loggingMeterRegistry() { 33 | return new LoggingMeterRegistry(new LoggingRegistryConfig() { 34 | @Override 35 | public String get(String key) { 36 | if (key.equals(prefix() + ".step")) { 37 | return String.valueOf(Duration.ofMillis(500)); 38 | } else { 39 | return null; 40 | } 41 | } 42 | }, Clock.SYSTEM); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/java/com/solace/spring/cloud/stream/binder/test/util/RetryableAssertions.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.test.util; 2 | 3 | import org.assertj.core.api.SoftAssertions; 4 | import org.assertj.core.api.SoftAssertionsProvider; 5 | 6 | import java.util.concurrent.TimeUnit; 7 | 8 | public class RetryableAssertions { 9 | public static void retryAssert(SoftAssertionsProvider.ThrowingRunnable assertRun) throws InterruptedException { 10 | retryAssert(30, TimeUnit.SECONDS, assertRun); 11 | } 12 | 13 | @SuppressWarnings("BusyWait") 14 | public static void retryAssert(long timeout, TimeUnit unit, SoftAssertionsProvider.ThrowingRunnable assertRun) 15 | throws InterruptedException { 16 | final long expiry = System.currentTimeMillis() + unit.toMillis(timeout); 17 | SoftAssertions softAssertions; 18 | do { 19 | softAssertions = new SoftAssertions(); 20 | softAssertions.check(assertRun); 21 | if (!softAssertions.wasSuccess()) { 22 | Thread.sleep(500); 23 | } 24 | } while (!softAssertions.wasSuccess() && System.currentTimeMillis() < expiry); 25 | softAssertions.assertAll(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/java/com/solace/spring/cloud/stream/binder/test/util/SerializableFoo.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.test.util; 2 | 3 | import java.io.Serializable; 4 | 5 | public record SerializableFoo(String foo) implements Serializable { 6 | } 7 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/java/com/solace/spring/cloud/stream/binder/test/util/SimpleJCSMPEventHandler.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.test.util; 2 | 3 | import com.solacesystems.jcsmp.JCSMPException; 4 | import com.solacesystems.jcsmp.JCSMPStreamingPublishCorrelatingEventHandler; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | public class SimpleJCSMPEventHandler implements JCSMPStreamingPublishCorrelatingEventHandler { 9 | private static final Logger logger = LoggerFactory.getLogger(SimpleJCSMPEventHandler.class); 10 | 11 | private final boolean logErrors; 12 | 13 | public SimpleJCSMPEventHandler() { 14 | this(true); 15 | } 16 | 17 | public SimpleJCSMPEventHandler(boolean logErrors) { 18 | this.logErrors = logErrors; 19 | } 20 | 21 | @Override 22 | public void responseReceivedEx(Object key) { 23 | logger.debug("Got message with key: {}", key); 24 | } 25 | 26 | @Override 27 | public void handleErrorEx(Object key, JCSMPException e, long timestamp) { 28 | if (logErrors) { 29 | logger.error("Failed to receive message at {} with key {}", timestamp, key, e); 30 | } else { 31 | logger.trace("Failed to receive message at {} with key {}", timestamp, key, e); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/java/com/solace/spring/cloud/stream/binder/test/util/ThrowingFunction.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.test.util; 2 | 3 | import java.util.function.Function; 4 | 5 | @FunctionalInterface 6 | public interface ThrowingFunction extends Function { 7 | 8 | @Override 9 | default R apply(T t) { 10 | try { 11 | return getThrows(t); 12 | } catch (Exception e) { 13 | throw new RuntimeException(e); 14 | } 15 | } 16 | 17 | R getThrows(T t) throws Exception; 18 | } 19 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/java/com/solace/spring/cloud/stream/binder/test/util/ThrowingSupplier.java: -------------------------------------------------------------------------------- 1 | package com.solace.spring.cloud.stream.binder.test.util; 2 | 3 | import java.util.function.Supplier; 4 | 5 | @FunctionalInterface 6 | public interface ThrowingSupplier extends Supplier { 7 | 8 | @Override 9 | default T get() { 10 | try { 11 | return getThrows(); 12 | } catch (Exception e) { 13 | throw new RuntimeException(e); 14 | } 15 | } 16 | 17 | T getThrows() throws Exception; 18 | } 19 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/META-INF/services/com.solace.test.integration.junit.jupiter.extension.PubSubPlusExtension$ExternalProvider: -------------------------------------------------------------------------------- 1 | com.solace.spring.cloud.stream.binder.test.junit.extension.pubsubplus.provider.PubSubPlusSpringProvider 2 | com.solace.test.integration.junit.jupiter.extension.pubsubplus.provider.PubSubPlusFileProvider 3 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension: -------------------------------------------------------------------------------- 1 | com.solace.test.integration.junit.jupiter.extension.LogTestInfoExtension 2 | org.assertj.core.api.junit.jupiter.SoftAssertionsExtension 3 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/META-INF/services/org.junit.platform.launcher.PostDiscoveryFilter: -------------------------------------------------------------------------------- 1 | com.solace.spring.cloud.stream.binder.test.junit.launcher.filter.PostDiscoveryClassNameExclusionFilter 2 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/application-multibinder.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | function: 4 | definition: "consume;otherConsume" 5 | stream: 6 | binders: 7 | solace1: 8 | type: solace 9 | environment: 10 | solace: 11 | java: 12 | host: placeholder 13 | solace2: 14 | type: solace 15 | environment: 16 | solace: 17 | java: 18 | host: placeholder 19 | bindings: 20 | consume-in-0: 21 | destination: MultiBinder/Queue/1 22 | group: myConsumerGroup 23 | binder: solace1 24 | otherConsume-in-0: 25 | destination: MultiBinder/Queue/2 26 | group: myConsumerGroup 27 | binder: solace2 28 | default-binder: solace1 29 | management: 30 | endpoint: 31 | health: 32 | show-components: always 33 | show-details: always 34 | endpoints: 35 | web: # Actuator web endpoint configuration. For more info: https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator.endpoints 36 | exposure: 37 | include: 'health,metrics' 38 | health: 39 | binders: 40 | enabled: true 41 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/application-multibinderOAuth2.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | security: 3 | oauth2: 4 | client: 5 | registration: 6 | solace1-oauth2-client: 7 | provider: solace1-auth-server 8 | client-id: solclient_oauth 9 | client-secret: j6gWnw13iqzJfFZzlqzaQabQgXza4oHl 10 | authorization-grant-type: client_credentials 11 | scope: openid 12 | solace2-oauth2-client: 13 | provider: solace2-auth-server 14 | client-id: solclient_oauth 15 | client-secret: j6gWnw13iqzJfFZzlqzaQabQgXza4oHl 16 | authorization-grant-type: client_credentials 17 | scope: openid 18 | provider: 19 | solace1-auth-server: 20 | token-uri: https://localhost:10443/auth/realms/solace-oauth-resource-server1/protocol/openid-connect/token 21 | solace2-auth-server: 22 | token-uri: https://localhost:10443/auth/realms/solace-oauth-resource-server2/protocol/openid-connect/token 23 | 24 | cloud: 25 | function: 26 | definition: "consume;otherConsume" 27 | stream: 28 | binders: 29 | solace1: 30 | type: solace 31 | environment: 32 | solace: 33 | java: 34 | host: placeholder 35 | msgVpn: OAUTH_1 36 | connectRetries: 10 37 | reconnectRetries: 10 38 | reconnectRetryWaitInMillis: 2000 39 | oauth2ClientRegistrationId: solace1-oauth2-client 40 | apiProperties: 41 | SSL_VALIDATE_CERTIFICATE: false ## Because using self-signed certificate 42 | AUTHENTICATION_SCHEME: AUTHENTICATION_SCHEME_OAUTH2 43 | 44 | solace2: 45 | type: solace 46 | environment: 47 | solace: 48 | java: 49 | host: placeholder 50 | msgVpn: OAUTH_2 51 | connectRetries: 10 52 | reconnectRetries: 10 53 | reconnectRetryWaitInMillis: 2000 54 | oauth2ClientRegistrationId: solace2-oauth2-client 55 | apiProperties: 56 | SSL_VALIDATE_CERTIFICATE: false ## Because using self-signed certificate 57 | AUTHENTICATION_SCHEME: AUTHENTICATION_SCHEME_OAUTH2 58 | 59 | bindings: 60 | consume-in-0: 61 | destination: MultiBinder/Queue/1 62 | group: myConsumerGroup 63 | binder: solace1 64 | otherConsume-in-0: 65 | destination: MultiBinder/Queue/2 66 | group: myConsumerGroup 67 | binder: solace2 68 | default-binder: solace1 69 | 70 | # solace: 71 | # default: 72 | # consumer: 73 | # add-destination-as-subscription-to-queue: false 74 | # provision-durable-queue: false 75 | # producer: 76 | # provision-durable-queue: false 77 | 78 | management: 79 | endpoint: 80 | health: 81 | show-components: always 82 | show-details: always 83 | endpoints: 84 | web: # Actuator web endpoint configuration. For more info: https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator.endpoints 85 | exposure: 86 | include: 'health,metrics' 87 | health: 88 | binders: 89 | enabled: true 90 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/application.properties: -------------------------------------------------------------------------------- 1 | solace.java.host=localhost 2 | solace.java.msgVpn=default 3 | solace.java.clientUsername=default 4 | solace.java.clientPassword=default 5 | solace.java.connectRetries=0 6 | solace.java.connectRetriesPerHost=0 7 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/junit-platform.properties: -------------------------------------------------------------------------------- 1 | junit.jupiter.extensions.autodetection.enabled=true 2 | 3 | # Parallel test execution is disabled by default for easy debugging in IDEs. 4 | # It is overridden to be enabled by the Maven Surefire/Failsafe plugins. 5 | junit.jupiter.execution.parallel.enabled=false 6 | 7 | # Configured based on Github-hosted runners for public repositories. 8 | # https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories 9 | junit.jupiter.execution.parallel.config.strategy=fixed 10 | # Parallelism should ideally equal to the num of processors on the machine 11 | junit.jupiter.execution.parallel.config.fixed.parallelism=4 12 | junit.jupiter.execution.parallel.config.fixed.max-pool-size=20 13 | 14 | junit.jupiter.execution.parallel.mode.default=concurrent 15 | junit.jupiter.execution.parallel.mode.classes.default=same_thread 16 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/oauth2/certs/broker/solbroker.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEzDCCArSgAwIBAgIUbAVQlzPN4AFLWLI4lE+Rzw1cG+cwDQYJKoZIhvcNAQEL 3 | BQAwWzELMAkGA1UEBhMCQ0ExEDAOBgNVBAgMB09udGFyaW8xDzANBgNVBAcMBkth 4 | bmF0YTEXMBUGA1UECgwOU29sYWNlIFN5c3RlbXMxEDAOBgNVBAMMB1Jvb3QgQ0Ew 5 | HhcNMjQwNzEwMTUzMDQ3WhcNNDQwNzA1MTUzMDQ3WjB2MQswCQYDVQQGEwJDQTEQ 6 | MA4GA1UECAwHT250YXJpbzEPMA0GA1UEBwwGS2FuYXRhMRcwFQYDVQQKDA5Tb2xh 7 | Y2UgU3lzdGVtczEXMBUGA1UECwwOU29sYWNlIFN5c3RlbXMxEjAQBgNVBAMMCXNv 8 | bGJyb2tlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ1ElE74dz7g 9 | eSeGgnH6KjcyE1p6Dc3y/6mlr6ST7IWtFAfbWRdwALDEZWUYXyDkpvEQtxZDrgkF 10 | Ss8sbL1dskAj3xtdU1wh6ibqgH5hpzlrUhgCIssDVgMOppRxZXnjYEN85nW3r2r5 11 | bbgVST/bJ+YEHX66cb1TK0ISqcugzySd5bQSwW9G0vKMvQv9VWoVRWtVpPm/s5Y3 12 | 2FAd65rTJWBJhPowzsqKMNfx9JYEScFGfq6YOPjgm1SVoAG9nJXaUjt7C9S/fS+i 13 | eIafRYTOhQUIjXw6IgL29CTmoKRajbxjsjpi0C/zPg/1amB4OEceQatNXwc0YZgM 14 | j6dxPTsqKisCAwEAAaNtMGswaQYDVR0RBGIwYIIJc29sYnJva2Vyggpzb2xicm9r 15 | ZXIxggtzb2xicm9rZXJfMYIJbG9jYWxob3N0ggpzb2xicm9rZXIyggtzb2xicm9r 16 | ZXJfMocEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAgEA 17 | TYl/0ObS+eP9sb/IKLOXXaWS6K+1HQaqwRW0HJ0QBgwjfL9WhWupp1eujd+QFIGq 18 | eESZZvhxcF7lQIoaAQe/gn7wAL4ZIPJMlUdLiTBNacKCNqH9z/Meu+UHMN2mxJmD 19 | JlNVbmuWcpbE82nGylv+iZc8DWofnoyoyBRhJLPVqeyv3YUuIchkUxRjl7XbpQ9U 20 | 4nG4+9pACEM4pAZZHG8aXcca8PjwlcdJjfYt0n4700NlCqpREe/w/GJZFjk+Pf87 21 | O1t9Xycrux0k4Q8eLiO0qNNeJWEaKEdoUGkmO5/mu3ghq2/wRB9Vmmq+z/UaZW+j 22 | l62lIowEO1eRtoYthvNh4eZ0kWlfE5m0F2kor69QsiB0Qgfr7ucMamAzNLD+JEgU 23 | +scfnmW48y0eGqipKt9A02Bo6d2X36oG/IbTAYPuPJiDwWej77mgBfHDQhyV/+YI 24 | ayB/9bur4CW3wov6+a+YO/Q2rhU3ONs4EsQNGL8lo4opG9yCop9PR/BrcFcHvu+b 25 | 61I6u1ZLGk2e5KUxKk7XEAkG/L1Y8JEY5D1j2f9HUa0rQ2NO69Ry0qMvMeN0PKQt 26 | XDs0INdK0VGyuD4BxHlwHutKXBVpsZyoxUWsR21UzczxuLqncHGJ7+/MbJBLElwa 27 | /5J9RRDdKubX3mv5tVV8fpBn6bYYYThZsDX7qMU1vgQ= 28 | -----END CERTIFICATE----- 29 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/oauth2/certs/broker/solbroker.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIIDNzCCAh8CAQAwdjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgMB09udGFyaW8xDzAN 3 | BgNVBAcMBkthbmF0YTEXMBUGA1UECgwOU29sYWNlIFN5c3RlbXMxFzAVBgNVBAsM 4 | DlNvbGFjZSBTeXN0ZW1zMRIwEAYDVQQDDAlzb2xicm9rZXIwggEiMA0GCSqGSIb3 5 | DQEBAQUAA4IBDwAwggEKAoIBAQCdRJRO+Hc+4HknhoJx+io3MhNaeg3N8v+ppa+k 6 | k+yFrRQH21kXcACwxGVlGF8g5KbxELcWQ64JBUrPLGy9XbJAI98bXVNcIeom6oB+ 7 | Yac5a1IYAiLLA1YDDqaUcWV542BDfOZ1t69q+W24FUk/2yfmBB1+unG9UytCEqnL 8 | oM8kneW0EsFvRtLyjL0L/VVqFUVrVaT5v7OWN9hQHeua0yVgSYT6MM7KijDX8fSW 9 | BEnBRn6umDj44JtUlaABvZyV2lI7ewvUv30voniGn0WEzoUFCI18OiIC9vQk5qCk 10 | Wo28Y7I6YtAv8z4P9WpgeDhHHkGrTV8HNGGYDI+ncT07KiorAgMBAAGgfDB6Bgkq 11 | hkiG9w0BCQ4xbTBrMGkGA1UdEQRiMGCCCXNvbGJyb2tlcoIKc29sYnJva2VyMYIL 12 | c29sYnJva2VyXzGCCWxvY2FsaG9zdIIKc29sYnJva2VyMoILc29sYnJva2VyXzKH 13 | BH8AAAGHEAAAAAAAAAAAAAAAAAAAAAEwDQYJKoZIhvcNAQELBQADggEBACYEqj5E 14 | A/4Jl45GrqYmVAc2f+3upB4XY6f67A5RR8q4fogtpU6WDZbxleJhlJceT4DaS4zx 15 | lk5sglzRCPEloskaosZ/fWXJsI/OcAGilcdPkpgPnf24iZCFIfLfhf8Vq4CM8m9M 16 | 2pbTyghLPcORkIQ2rATRp/2gHHBWblfXbPw0FCxONyLolMGDMMF6/3z3yjT4pYGd 17 | /wAIgku9dB6og+yZeJ2JozLbml69eXbiASAWVSnkGLNag7u+NXkWiXFRQNQ4jAsi 18 | qYZ0Nl70F5QQ78ko4Nj+96Jo1ET1TON7C2fbl4ueHuHV7pxiGCRxe511OFSFQva6 19 | ubRf1fqacCMvD7w= 20 | -----END CERTIFICATE REQUEST----- 21 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/oauth2/certs/broker/solbroker.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEogIBAAKCAQEAnUSUTvh3PuB5J4aCcfoqNzITWnoNzfL/qaWvpJPsha0UB9tZ 3 | F3AAsMRlZRhfIOSm8RC3FkOuCQVKzyxsvV2yQCPfG11TXCHqJuqAfmGnOWtSGAIi 4 | ywNWAw6mlHFleeNgQ3zmdbevavltuBVJP9sn5gQdfrpxvVMrQhKpy6DPJJ3ltBLB 5 | b0bS8oy9C/1VahVFa1Wk+b+zljfYUB3rmtMlYEmE+jDOyoow1/H0lgRJwUZ+rpg4 6 | +OCbVJWgAb2cldpSO3sL1L99L6J4hp9FhM6FBQiNfDoiAvb0JOagpFqNvGOyOmLQ 7 | L/M+D/VqYHg4Rx5Bq01fBzRhmAyPp3E9OyoqKwIDAQABAoIBAHsUYuVy+xAQaYEP 8 | eiNtX4CXBiJ3Bzq5BHFmpBGvWxo7HEQR3KXFGCU/bwMxkbGSgTyEkmUwTpHsvGFr 9 | KScCnzAnYsJtxYGDYVdXi3xdPJxpa3Qyp7wuPjBiVOgz3vEHjB0FMO/L89NKph29 10 | Ovhosc8IRXUawU0kO+SX6p7cmYDTf/EdvCh1M6N1XlsvcOMb82v4arb5XyQ5IKdl 11 | qpm3Q23B1IPiwv4ErzeLHRbZ0XbMdQrSR85oZVAyFdQUjKZs/Bq0rZbrd9yxclBi 12 | k+4PJS3HpDjDwAmIeRVRIlsZdSOLLUOywieDLY8+inCwLXs6A5kRVbbKYWxewehG 13 | 47n35EECgYEAzojA0NyA7ihtJHvez/CcbAfSW+/uXEhnEPv++ynnUAmz5unDacnx 14 | yICpFqZCMG8Ob/lrXoFvEMrmyFETBWiF9BlGJY17mtTZkKb83Osz1AGvdeKQQ/zB 15 | 5UOLXsQKN+1HAI4VdyI4UutwzIfwcNu6mYqVMFZfBfHZ8iBCR5oR/ZECgYEAwu8o 16 | Tnowfu9uzDMNx8uQRnzCXvkL+jWqqUdfJXiRhsBSgQlfkw62TxByj3wRKIqUjj9E 17 | DzhsXJXsqetzfmVQH12RgVkJ5GkDY060Z8c9GYtx1rPJqtkIu6M+m/yVxZ4Tost6 18 | K3jvXveJXqu0wlJJMvpzupMBYSpvMo0KBj7rPfsCgYAY484o3YoEKYcNsIfnk12m 19 | f0LQpZeaM3eISnYuGpyvvpuZpm5QX2/t8+NswViUsa2RvQM9fme+JFWvqmWab0BF 20 | bI5RlD1jKWeW0SkEDqxOTm2wzT8JknpjgMJZB1Mb7lJyNK1NkCgthgYv/+nwD+rq 21 | +hKEosQM2VqknVKfgmfMoQKBgDWKGjfzt34lpPjQzOgjMO0rNvd+z5tZQhZcU/Wm 22 | t9Ga4Q4v1OA/GjN9APoHyW6pIUQwfDDx/lEvnGDPGlmM2gTDXkN4gQ8LCLMt2r7m 23 | KhHqCso9dxZFpfBjVb7iEQDF+f6shFGMVbJvqnsmDe+RSimGQGLuHWLilMf9lNNC 24 | VLohAoGAKnfkD7NQgeez9fGrWjFN/8jj7jI3yvVjihpLQBEMMbMLma/V8Btm2/7x 25 | lgWiGMBcfYDqCPbe48xGWiHOKkW3tot5wsQCLZzwTPLYqFgjMDOFfCXmtmlOTMYu 26 | +UdceSxN1JU/wyfXSf7CB1kkwcpOQ1awrccJ75DoHQW6seFjTFk= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/oauth2/certs/client/client-keystore.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SolaceProducts/solace-spring-cloud/2acaa5f93dc5d5f05f2516ff75567bea82b60d06/solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/oauth2/certs/client/client-keystore.jks -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/oauth2/certs/client/client-truststore.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SolaceProducts/solace-spring-cloud/2acaa5f93dc5d5f05f2516ff75567bea82b60d06/solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/oauth2/certs/client/client-truststore.p12 -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/oauth2/certs/client/client.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEPzCCAicCFGwFUJczzeABS1iyOJRPkc8NXBvoMA0GCSqGSIb3DQEBCwUAMFsx 3 | CzAJBgNVBAYTAkNBMRAwDgYDVQQIDAdPbnRhcmlvMQ8wDQYDVQQHDAZLYW5hdGEx 4 | FzAVBgNVBAoMDlNvbGFjZSBTeXN0ZW1zMRAwDgYDVQQDDAdSb290IENBMB4XDTI0 5 | MDcxMDE1MzUyNFoXDTQ0MDcwNTE1MzUyNFowXTELMAkGA1UEBhMCQ0ExEDAOBgNV 6 | BAgMB09udGFyaW8xDzANBgNVBAcMBkthbmF0YTEXMBUGA1UECgwOU29sYWNlIFN5 7 | c3RlbXMxEjAQBgNVBAMMCXNvbGNsaWVudDCCASIwDQYJKoZIhvcNAQEBBQADggEP 8 | ADCCAQoCggEBAMPxo1xlJD9Yi+fkR9MK7lNHsQ6VLHTad6ktUG+at0rclQfYG2x/ 9 | G1lp812UaceQexOgEPTc7g4+cL8k9zDfJZhjF0hN5jZPrf5r1vP2v9xwdRRebVeZ 10 | juHsjPOjeu+1IbSWOELLUNqqdgt4zxUbEnMjX693n7jivBPWMtqJiVmXLgB/bdA4 11 | qJQ5DxtTF0jZLpxlVOPKKk/G6HMuW6EevI4XyP2MA1ayUXpTulcj39gCfMN3Bxcp 12 | epIYSV5gzeqV03fuUoh7GrtnBATIQxFe3guJEcoBqT+DUCieH0hRmizA435UK+lp 13 | yzDZWxLjLSh7msnTaIfgKmuNmrJcCk6KulMCAwEAATANBgkqhkiG9w0BAQsFAAOC 14 | AgEAiMRofj8jnppDr+IOCdZTqSUemV/+5+IIYJkMpibPnM/WPQjn95GgxLhfNtAq 15 | gaIOlN/IPEMJCZzCVSX/Fd+5YI10NBX7wBoFVrf0izSp40OAzynqlGrFMPdWQwAJ 16 | 9kyqSuZa7R8phZzRAH6IrdsQcrxr7qGc5yBCEXnLTbd5rCEXYh6Yvq5/CspYvuCJ 17 | 9kieXujn1XDt/bApFxkKJpOzkXZQxRDBKK8oYxH6u/0uN03M0yXnswiUVBjXEGZE 18 | MpBud1qIOfDOnZeS2yxJRKzX9Q0tXg9CHT0CnQTTC9f31FfDYW/ro81pqnLuzlm7 19 | RIPb7M6ovgJgFUmvh8lSqz0wDugNfTZZX6QCa/x3kUlCtmxwbLsC4MYmzgy3wtYw 20 | Bt6B8t9KzWCdLRbk+akGOX3nDn8NUpZhqgXyVUY10IxSIShueZ+IIwvdbKEXdIsz 21 | QNyaU76zeD175gPVOb9upuV7R3gJXcbLRQ6gCNoGkZrnTXOjI4wpGFmWHXJOJTDS 22 | nngQ9n1QiGBqYsEun+PRIod90ucwjTYuG88HSqTS8zsYQSf1qvQCG79Piq2osdMW 23 | jxPzdK/bZDNBObSGl/gHkXy9YmZ2MFyQoEaVeRjPUYRcPquALMFYRB9HDBWlYDsb 24 | GTgiYKVIs3FK90XnX7TzXyzH0GyzOCkC/47/dplWkP3WL+8= 25 | -----END CERTIFICATE----- 26 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/oauth2/certs/client/client.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIICojCCAYoCAQAwXTELMAkGA1UEBhMCQ0ExEDAOBgNVBAgMB09udGFyaW8xDzAN 3 | BgNVBAcMBkthbmF0YTEXMBUGA1UECgwOU29sYWNlIFN5c3RlbXMxEjAQBgNVBAMM 4 | CXNvbGNsaWVudDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMPxo1xl 5 | JD9Yi+fkR9MK7lNHsQ6VLHTad6ktUG+at0rclQfYG2x/G1lp812UaceQexOgEPTc 6 | 7g4+cL8k9zDfJZhjF0hN5jZPrf5r1vP2v9xwdRRebVeZjuHsjPOjeu+1IbSWOELL 7 | UNqqdgt4zxUbEnMjX693n7jivBPWMtqJiVmXLgB/bdA4qJQ5DxtTF0jZLpxlVOPK 8 | Kk/G6HMuW6EevI4XyP2MA1ayUXpTulcj39gCfMN3BxcpepIYSV5gzeqV03fuUoh7 9 | GrtnBATIQxFe3guJEcoBqT+DUCieH0hRmizA435UK+lpyzDZWxLjLSh7msnTaIfg 10 | KmuNmrJcCk6KulMCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQAWOCvnysa8pBPh 11 | H4liajvowUgOBGz8fS87kiy57s9n4IZXYNU/PeNmMrm8RJLseP5UiYRvVaI0Wk8h 12 | 2zJmb0g73brW153TPxU9aNDTTcSkMQmS3NMYvt/okxcEWkBoQ6zbgNE0DvCPnCkz 13 | svPASwYrGY0k3gLCWK8+/znrCHuqOAeQKYpdpYiLwJwPc7/iFfWxzdUp2XWV2141 14 | yRhJPwqlMK5UI8RwpkdkjIljuuaX5zeMtNIHlKtvcxC6B4ZYLii5mpVoOvNS/Wp/ 15 | ZEpoFY6mn70z9uD+gyRyv8Yxwk6IMZnHiJVtcn93+z3O3Ini5hqRTgG9eCiIwFQl 16 | FgEVqEdJ 17 | -----END CERTIFICATE REQUEST----- 18 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/oauth2/certs/client/client.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAw/GjXGUkP1iL5+RH0wruU0exDpUsdNp3qS1Qb5q3StyVB9gb 3 | bH8bWWnzXZRpx5B7E6AQ9NzuDj5wvyT3MN8lmGMXSE3mNk+t/mvW8/a/3HB1FF5t 4 | V5mO4eyM86N677UhtJY4QstQ2qp2C3jPFRsScyNfr3efuOK8E9Yy2omJWZcuAH9t 5 | 0DiolDkPG1MXSNkunGVU48oqT8bocy5boR68jhfI/YwDVrJRelO6VyPf2AJ8w3cH 6 | Fyl6khhJXmDN6pXTd+5SiHsau2cEBMhDEV7eC4kRygGpP4NQKJ4fSFGaLMDjflQr 7 | 6WnLMNlbEuMtKHuaydNoh+Aqa42aslwKToq6UwIDAQABAoIBAHJQFLggoYb7R5Pf 8 | 0C9FX0jiuF8DlE4P7mOadiTGJEzeZ2uOHmGrve7qKvrbTOMKXWNTrNDN22wf7XL2 9 | Q+gVJz/B/6FFIRtqXN3jWCI4QDKAwS1C8ZN7mKohcRHqvBwAlkteoDAHoYIQlJGY 10 | x2dOxfK6Hmal6V7ZmFQSUNTCDIlg7Mguz8WaI0C1Wen+jJHUjiIkPz8xKF/gvddl 11 | 18iqHVGfZFSI1rTvfGeVO1vRwlwHoVV9HeXYEw9pAe0yxDLKKvY2brf8J8+qSWl2 12 | l7Unr89Ti8Yrm0EWQs/xFZpvQRkl7NG7WLIMJBCc4w3wOEvjpyklw7CfJaWGu6lM 13 | sRlk4gECgYEA+LQhF0SaL6Vs36VVAMrTqj8EWyr4V7AB+xAr0aoGawKnSnnlOj4x 14 | BSer4sulyQvL81rQnbekgkpWl05ZCcDp52+ATak+yBq3BvnX5SNjovcKQTuWhqLk 15 | EMHK8SuaMKcp+jUTRdaohsmy+zUtNzkkVEzNMdR93i7+yS1ao6lMHtMCgYEAybFC 16 | vTMhZITXmpvEHQ0qi0Ucgp/J6VQkPAhQMzoUHSIZbL6eXhaFmeQdD/ta9nIoOc3K 17 | enDEenW3ABrz84fPNaRVnS5U7H5448ZxW1HskwbeDx88PjTbUkS+tT8ITF3PiwA3 18 | d+vOw8ngg8Msmve19Sh6ssSPLvIIfxwYpTxIxoECgYEAoSnxS6e8FuYnQGJeTC4j 19 | re46P24AEqrPDcfz7WE12YCVshB9uBl3ILUNkOGRJFBNsPyHtby8kWXk6RXvYv+t 20 | U7mQtkLXmUqekpmzCxy8w209KvqXV9YU3rsGbPRpbd/VtvtP6vDosrfgESPrkh6o 21 | aSx/yCvACQwBNZL7apUZ69sCgYBAuUCohIr3veWOeOQTSpFXhgMjK/HYjabfGO/b 22 | sIyZ2MJ98iHSIboX62skIM5M/c9I1XBfoGZ8wd/LCds1UGS/WxAaU67vAZr7xUfF 23 | PWIEwJRsF+L2N3IWUXc9pI+eKhCbE6O5ORPuIo+I2Q4sYMekd6wASDGGqCbv221R 24 | QSo9gQKBgCRhdvN6Jp0IFrpHtopSaSYUCek0rotWlmXMuX/n4k+3RLdX4/xNn5gV 25 | gR8nvVvfzLz9wmsbERsKmnMILBIWZPD//2O9PXubcMp4Shifl0mKh9zzPvriiF/H 26 | 7E9UU53p9WScYAPW+BonpKnopoGCXxM2smTwE2bdxzPs3jDWM8lJ 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/oauth2/certs/client/client.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SolaceProducts/solace-spring-cloud/2acaa5f93dc5d5f05f2516ff75567bea82b60d06/solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/oauth2/certs/client/client.p12 -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/oauth2/certs/keycloak/keycloak.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFHzCCAwegAwIBAgIUbAVQlzPN4AFLWLI4lE+Rzw1cG+kwDQYJKoZIhvcNAQEL 3 | BQAwWzELMAkGA1UEBhMCQ0ExEDAOBgNVBAgMB09udGFyaW8xDzANBgNVBAcMBkth 4 | bmF0YTEXMBUGA1UECgwOU29sYWNlIFN5c3RlbXMxEDAOBgNVBAMMB1Jvb3QgQ0Ew 5 | HhcNMjQwNzEwMTU0MzMyWhcNNDQwNzA1MTU0MzMyWjB2MQswCQYDVQQGEwJDQTEQ 6 | MA4GA1UECAwHT250YXJpbzEPMA0GA1UEBwwGS2FuYXRhMRcwFQYDVQQKDA5Tb2xh 7 | Y2UgU3lzdGVtczEXMBUGA1UECwwOU29sYWNlIFN5c3RlbXMxEjAQBgNVBAMMCXNv 8 | bGJyb2tlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKuVDvCSYll7 9 | 7eWyEmcDDunp+z/4KziZatEZYGNten2SRzfvhtP+uLJCbexjeJ8NAYtSILE1q1tD 10 | lVAIItU6I2gUxKbJ8iUgX+VB92/35k314dKwvR7/pMivEj7joRdzE/qVszOJDZYu 11 | K9n4JHzpzpQ4fc9JCDOHlDlGjQMNan5HHjlzWloUbTeDlaEK6lGLimenYkTiU/Jt 12 | K9HS9Ep00E8IGNoTTuP7eUOnr+DxHSvdFJCarxe8t/TALkPgRyL/y14JOs9zG3e9 13 | AAblGWXXpexeLnKAUApJK/WX+bscWx9gdsbnAL0RSEO4hPX7BdAx5n3nwhbwWUYz 14 | HCWT72HQs0sCAwEAAaOBvzCBvDCBuQYDVR0RBIGxMIGugglzb2xicm9rZXKCCnNv 15 | bGJyb2tlcjGCC3NvbGJyb2tlcl8xgglsb2NhbGhvc3SCC3NvbGFjZU9BdXRoggtz 16 | b2xhY2VvYXV0aIIMc29sYWNlb2F1dGgyghUqLnNvbGFjZV9pbnRlcm5hbF9uZXSC 17 | ECouc29sYWNlX21zZ19uZXSCFCouc29sYWNlX21zZ19uZXR3b3JrhwR/AAABhxAA 18 | AAAAAAAAAAAAAAAAAAABMA0GCSqGSIb3DQEBCwUAA4ICAQBJ8jD5hSKXPri4NmOx 19 | S3Lh6bMbkq8JcIQesR7sgPFENy3UX+WuAY6Fjm9edXBdG+9OuqfBXoSHEA8jL+oU 20 | gos1Lz/6Sy3kKGIe8E44zgas0CYH3veXJJeLMBaE8RKdKEaiEUT+Ka7OXhhOWDGj 21 | n8QKo5um+ZUzsBzBF5B0zw/5kK02aDE9N/eqvAAm1fZqDC8txZD7i0dBa0rrQp8Q 22 | yYZGQmobis7ban//MOxPnL/lpoWVkwn3HrGlUzhhoG8xwokI0pXGMCga4K3iWvyc 23 | jTbICt8AyEyhwQqOpugzVQxRc7Qs3sTlkrN2bTy6mmS5WrYIYwCKfq9yeH9OR41Q 24 | KVsHpcDrSCtVlwYe8TF/d+HkvFJudKj5VgXPatI3tRAFe1BxXWA0fNHn/Hla9QiC 25 | sYyb3T9dyxW1XVTV9sLNcib8Q8Cew/JqchaemPNG+gek+/tc7lOQfdRNdoKcflPc 26 | ko+2OvPZAoI5tg9kOLYn71KG3sHMJgU/42yZhbwOtPEGJ+AXH+TtIE1Twoum8C2X 27 | qe5uMOuE7MziRD2Zsg6t0Wi7RgLMfz+nKNDWJ1YXHX5tBj+p6CxyKZ+6MUmnj1Cl 28 | toLbj/FgNtJaey9bi1zVK2oy6r3oHn7sdI5NdMPFuRTYacX/Foq5KAeDo/MzN9pa 29 | mnTgszi5F12OP3KbMvw6PyR8tQ== 30 | -----END CERTIFICATE----- 31 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/oauth2/certs/keycloak/keycloak.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIIDjDCCAnQCAQAwdjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgMB09udGFyaW8xDzAN 3 | BgNVBAcMBkthbmF0YTEXMBUGA1UECgwOU29sYWNlIFN5c3RlbXMxFzAVBgNVBAsM 4 | DlNvbGFjZSBTeXN0ZW1zMRIwEAYDVQQDDAlzb2xicm9rZXIwggEiMA0GCSqGSIb3 5 | DQEBAQUAA4IBDwAwggEKAoIBAQCrlQ7wkmJZe+3lshJnAw7p6fs/+Cs4mWrRGWBj 6 | bXp9kkc374bT/riyQm3sY3ifDQGLUiCxNatbQ5VQCCLVOiNoFMSmyfIlIF/lQfdv 7 | 9+ZN9eHSsL0e/6TIrxI+46EXcxP6lbMziQ2WLivZ+CR86c6UOH3PSQgzh5Q5Ro0D 8 | DWp+Rx45c1paFG03g5WhCupRi4pnp2JE4lPybSvR0vRKdNBPCBjaE07j+3lDp6/g 9 | 8R0r3RSQmq8XvLf0wC5D4Eci/8teCTrPcxt3vQAG5Rll16XsXi5ygFAKSSv1l/m7 10 | HFsfYHbG5wC9EUhDuIT1+wXQMeZ958IW8FlGMxwlk+9h0LNLAgMBAAGggdAwgc0G 11 | CSqGSIb3DQEJDjGBvzCBvDCBuQYDVR0RBIGxMIGugglzb2xicm9rZXKCCnNvbGJy 12 | b2tlcjGCC3NvbGJyb2tlcl8xgglsb2NhbGhvc3SCC3NvbGFjZU9BdXRoggtzb2xh 13 | Y2VvYXV0aIIMc29sYWNlb2F1dGgyghUqLnNvbGFjZV9pbnRlcm5hbF9uZXSCECou 14 | c29sYWNlX21zZ19uZXSCFCouc29sYWNlX21zZ19uZXR3b3JrhwR/AAABhxAAAAAA 15 | AAAAAAAAAAAAAAABMA0GCSqGSIb3DQEBCwUAA4IBAQBzBBKrR+MCMi2lv4m5wFuK 16 | vj8/idCcCQeVLhMFCgFu770FMAw2NLvYi0SB56S3J1FUrEkT8XPMfts8S8msrCot 17 | UZGMJMCc5RHeI+A308+xz069Y0i4wo4ajK3CkBRXzoMFejlgzF0oMafOMx2Lp9Tl 18 | k+s6peHvKdXa0KQIvn28DwO2sfRP4fqMy4borJRLYLOJEKGMCjo1ClsJNA4pZvFv 19 | mSJCO4DlUfEn04+H18EOKNLs8ChQXsxKqKAk+1VKvtrvRByPhhfU1Jg0Smmipvcg 20 | Z0uQseLKKZ2MYw6tCuvC1C+LbBtDd43GG1ayCg2G8OtNfKIHoCS0oVWsvUnENgUK 21 | -----END CERTIFICATE REQUEST----- 22 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/oauth2/certs/keycloak/keycloak.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEoQIBAAKCAQEAq5UO8JJiWXvt5bISZwMO6en7P/grOJlq0RlgY216fZJHN++G 3 | 0/64skJt7GN4nw0Bi1IgsTWrW0OVUAgi1TojaBTEpsnyJSBf5UH3b/fmTfXh0rC9 4 | Hv+kyK8SPuOhF3MT+pWzM4kNli4r2fgkfOnOlDh9z0kIM4eUOUaNAw1qfkceOXNa 5 | WhRtN4OVoQrqUYuKZ6diROJT8m0r0dL0SnTQTwgY2hNO4/t5Q6ev4PEdK90UkJqv 6 | F7y39MAuQ+BHIv/LXgk6z3Mbd70ABuUZZdel7F4ucoBQCkkr9Zf5uxxbH2B2xucA 7 | vRFIQ7iE9fsF0DHmfefCFvBZRjMcJZPvYdCzSwIDAQABAoIBAAm/RwD9n96rfqE8 8 | 03TMpK0/IInKxFHLzVihk2syjfHSPH99+O/UGZPu2CXEpNaMO5k5iifm/5wIo9PP 9 | EoOAcQB5pY5ADKR1SV1RuQfAUnH9VN3OMoAvT6Ii5+twrPcTD4B9vpdf4si0SMNy 10 | KEh8U8LxzpvW70NWIWJ7koko2vLfaYVuvDSMZLXll9B9iz6ROYp1qNh0aYrscRC/ 11 | uC2/ziAJzbMEhsPN59AF8upfnyBxEOjxhFJ9LzbsxNoZyRCCMuDu35TUB57q1TZm 12 | rp8RdrqZ2qlknkZMbf5E06xyHBt4QgyzltivxbugShZB9iUe74Mjqyp4LTkAoy8J 13 | U/P9cTkCgYEA4Tg+0mOvMpVE0x5nrV3z5uydNnYOWdDk3W8Q3JVKs5b7QQDFWtEs 14 | stP6jZCNnQkrRnhwY2mlGnWUUJ0CEtZp5eWXHdHsrFL150FOBYBofVdFTZFKdHRk 15 | CXn7zSXLULmrqBRptI0K7DQzAJ9y2agh3iATka22xuHUscm7qrKuqh0CgYEAwwgz 16 | hkruZBO/+6VE2LBy1/ew5btZyaF/x85Q/AiBPfEO/ilT4cKV3eOOZtjpnsyF15U2 17 | p4ubluNbvUYlJ7IPTZEUWwiw94B5hksQXzUfi96zb9GDcaEfoYGsZ+fqEPVkqgzM 18 | Z5rE8Db9QDnsd9uGdzSPMziEnLGqqNEd/lGolocCf1HRHQFRNVQq5dXMNd3FQ9Wg 19 | H3ypZo06VeobbwSzN3AGaUA0B332f0Z3u42x9cAWlKIFHs7+kfwKutaOMzKksdPS 20 | lBNBL7lqaeqYzr8w5sSh74s+PM4RekX3CoJ8OGAbE0D8KWpt0on8bIrNYeuwKJ2J 21 | CZLiiIO3ho0PvB1GzC0CgYEAg//U/5tPZaSIV4Uv54jk8Y7Ox23aA0Gu/kiBP1Ny 22 | Rb4Va6gFAdN1I0yUYL+Gvtel7pcq+pLep20R9jS3iPpWqST8JfDn9Vua5G2Bky6d 23 | P0lnINMop4tpoSHm0hyAqyGrE/y9i5GQoRRWq1WI2kZV5/BGy2ABQRxuaPu/1RTn 24 | iZkCgYB92CW0tnV1PDr4fRbFMQ/KnAHCaQHBjnfyx1pYAn5Km+iC7OiwT9/JFTAx 25 | fic17YAogeOOWnroiH7uUtJRLbo1kyCS1RDIFW0LsreXeGkQ4147cbyQxHORu7s0 26 | SU9voGpGV26zX0Ik0VbefsonMDZrQhoxign568DMLIMGfp/Sqg== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/oauth2/certs/keycloak_san.conf: -------------------------------------------------------------------------------- 1 | [ req ] 2 | req_extensions = req_ext 3 | distinguished_name = req_distinguished_name 4 | prompt = no 5 | 6 | [ req_distinguished_name ] 7 | C = CA 8 | ST = Ontario 9 | L = Kanata 10 | O = Solace Systems 11 | OU = Solace Systems 12 | CN = solbroker 13 | 14 | [ req_ext ] 15 | subjectAltName = @alt_names 16 | 17 | [ alt_names ] 18 | DNS.1 = solbroker 19 | DNS.2 = solbroker1 20 | DNS.3 = solbroker_1 21 | DNS.4 = localhost 22 | DNS.5 = solaceOAuth 23 | DNS.6 = solaceoauth 24 | DNS.7 = solaceoauth2 25 | DNS.8 = *.solace_internal_net 26 | DNS.9 = *.solace_msg_net 27 | DNS.10 = *.solace_msg_network 28 | IP.1 = 127.0.0.1 29 | IP.2 = 0:0:0:0:0:0:0:1 30 | # ... (add more SAN entries) -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/oauth2/certs/rootCA/rootCA.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFlzCCA3+gAwIBAgIUU1biQS/fFJ8bcYNdXYXeaJ7htJIwDQYJKoZIhvcNAQEL 3 | BQAwWzELMAkGA1UEBhMCQ0ExEDAOBgNVBAgMB09udGFyaW8xDzANBgNVBAcMBkth 4 | bmF0YTEXMBUGA1UECgwOU29sYWNlIFN5c3RlbXMxEDAOBgNVBAMMB1Jvb3QgQ0Ew 5 | HhcNMjQwNzEwMTQ0NzM2WhcNNDQwNzA1MTQ0NzM2WjBbMQswCQYDVQQGEwJDQTEQ 6 | MA4GA1UECAwHT250YXJpbzEPMA0GA1UEBwwGS2FuYXRhMRcwFQYDVQQKDA5Tb2xh 7 | Y2UgU3lzdGVtczEQMA4GA1UEAwwHUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQAD 8 | ggIPADCCAgoCggIBAJXSAsGmhmUYSnPoNNDeV09mh5v2ZnMGJuP7+y2cNzaoLdPM 9 | LDV1As/gfnF6n7hGWXj+ZFxOmpMwBEBNnfQVHtzgYWdIW9p34/fdznJr3PIKeC+K 10 | 39s3PacyIIriX8WxD6T+WAO7RjzrbNLq+2XB3sWU3BR2Y0mFCP/u0iEJ2QratWjr 11 | A+Ers85jEGYlAsk5hL9D2jErVzluuW3Th+Rl/ov4ev1NE6vu/tm+k7I4PdTSA0PV 12 | 3T8FrzS/KQK7aBnU982hhB1lHWSWyJl3IOhPE5VzghBhDb0nytn0Y8kTh7+qmSC2 13 | 8LdKwPt16pyvcamCBInxJnQFNQitlvTfTPLDGs0YTD47gBR5CTWLlr2u8grlxviY 14 | T0xALNtf8RqcbMpizAt6+9RJsFKFOip2xKbVuia5KH96TYqMFmPSFs72jJBr2bC1 15 | /JpyokdUh6gquZfmN18igdu8UB58sK03wYdVort+6nLBax8JNYBvj2+hy8r3HVsi 16 | 5xdaZofj3vPyFBC7GHrn7X4cUiff0RSncJC8Fr0LRb3Pi5sXNmN4wFAlJIC/Wd67 17 | QWouvoU1zUe9n8IB0yXGJcJ9u7CMZDxgAj9EAh4xkR0q7gxT5XSBpm4ZhOX35GwO 18 | 50/cZ3zmNsQ/6d/illGwnP7bc6G8cCWKErDquLm5dI2P9OEUdOPFuIwkmLZFAgMB 19 | AAGjUzBRMB0GA1UdDgQWBBQWSokRHFfinJUJY8moOtt3Mt2K/TAfBgNVHSMEGDAW 20 | gBQWSokRHFfinJUJY8moOtt3Mt2K/TAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 21 | DQEBCwUAA4ICAQCSJvzYL7u/Nv0Eq9xBvotNN7Dl1KrgqbSzz0Q5jV68vIZiL9n0 22 | HdP9oe1mQZeYr1DrTnysnlMjU1s/uoMorNu2cd1LBvUKSrjhmeAGg4g2JYBUoeJf 23 | C5kpFWaB3i5IksY8D0PlIsX3jufv35c4aP4NlUzcESu6cr+lO4K/GNV4cS5ACiaF 24 | giPhJvWjW9n/yxQXTki/294RRsEqTxQzcHVC5ZSBRdiMti2BJoV/CgFxiZhKaFPy 25 | dHOX8iHiI55mvLx+UisFc+YsJSMjuL7EjSJJQQVWIa+H7g23jenqbar0shstzfhE 26 | NoPBaB65o9c6qKCruajlcjZBxKuGlgP4wmIZMkFWwktHK5JJorLv9A29EpZp1fFs 27 | VE6kSNQxebbIvgZCqNE2bOTMfGspKVxDENOXDNTNgsf/lArtQk1+PMwjW1zwFGGn 28 | tiH3LbJtLgeeX7HnB80lsohD5d+6/v/xxrB6aWRlpQGT+271trZdR/pixh2dhsPg 29 | 92D0oyR6CQTwuE1CUIthIonN1m+PtMKnpodoVsRkMwMOshcMWzmWVNNNIy5BuEgK 30 | Lhh30MdiiwlpLV5gkcnygd4hkMV2VO9j5sFllo5ttnkQ6OZKmNoAqcYWIHCW2sh8 31 | rDYFzwes5qhK/K+qYLbBroHli14/p6AZRAlkcS8Vc5ew40naHn1Dd7EKRA== 32 | -----END CERTIFICATE----- 33 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/oauth2/certs/rootCA/rootCA.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SolaceProducts/solace-spring-cloud/2acaa5f93dc5d5f05f2516ff75567bea82b60d06/solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/oauth2/certs/rootCA/rootCA.der -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/oauth2/certs/rootCA/rootCA.srl: -------------------------------------------------------------------------------- 1 | 6C05509733CDE0014B58B238944F91CF0D5C1BE9 2 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/oauth2/certs/solbroker_san.conf: -------------------------------------------------------------------------------- 1 | [ req ] 2 | req_extensions = req_ext 3 | distinguished_name = req_distinguished_name 4 | prompt = no 5 | 6 | [ req_distinguished_name ] 7 | C = CA 8 | ST = Ontario 9 | L = Kanata 10 | O = Solace Systems 11 | OU = Solace Systems 12 | CN = solbroker 13 | 14 | [ req_ext ] 15 | subjectAltName = @alt_names 16 | 17 | [ alt_names ] 18 | DNS.1 = solbroker 19 | DNS.2 = solbroker1 20 | DNS.3 = solbroker_1 21 | DNS.4 = localhost 22 | DNS.5 = solbroker2 23 | DNS.6 = solbroker_2 24 | IP.1 = 127.0.0.1 25 | IP.2 = 0:0:0:0:0:0:0:1 26 | # ... (add more SAN entries) -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/oauth2/free-tier-broker-with-tls-and-oauth-docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.5' 2 | 3 | networks: 4 | solace_msg_net: 5 | external: false 6 | 7 | services: 8 | solbroker: 9 | image: solace/solace-pubsub-standard:10.4.0.23 10 | hostname: solbroker 11 | networks: 12 | - solace_msg_net 13 | env_file: 14 | - ./solace_tls.env 15 | shm_size: 2g 16 | ulimits: 17 | memlock: -1 18 | nofile: 19 | soft: 2448 20 | hard: 42192 21 | secrets: 22 | - server.pem 23 | 24 | solaceoauth: # A nginx reverse proxy for enabling SSL access to Keycloak 25 | image: nginx:1.21.6 26 | hostname: solaceoauth 27 | volumes: 28 | - ./oauth/nginx.conf:/etc/nginx/nginx.conf 29 | - ./oauth/www:/data/www 30 | - ./certs/keycloak:/etc/sslcerts/ 31 | networks: 32 | - solace_msg_net 33 | 34 | keycloak: 35 | image: quay.io/keycloak/keycloak:16.1.1 36 | hostname: keycloak 37 | networks: 38 | - solace_msg_net 39 | volumes: 40 | - ./oauth/keycloak/:/tmp/keycloak/ 41 | environment: 42 | - DB_VENDOR=h2 43 | - KEYCLOAK_USER=admin 44 | - KEYCLOAK_PASSWORD=mysecret1! 45 | - PROXY_ADDRESS_FORWARDING=true #important for reverse proxy 46 | - "KEYCLOAK_IMPORT=/tmp/keycloak/solace-oauth-resource-server1-realm-export.json,/tmp/keycloak/solace-oauth-resource-server2-realm-export.json" 47 | command: 48 | - "-Dkeycloak.migration.strategy=IGNORE_EXISTING" 49 | 50 | secrets: 51 | server.pem: 52 | file: "certs/broker/solbroker.pem" ## The server certificate for the Solace PubSub+ broker 53 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/oauth2/oauth/nginx.conf: -------------------------------------------------------------------------------- 1 | events { 2 | } 3 | http { 4 | server { 5 | listen 1080; 6 | 7 | server_name _; 8 | return 301 https://$host:10443$request_uri; # redirect http requests to https 9 | } 10 | server { 11 | 12 | include /etc/nginx/mime.types; 13 | 14 | listen 10443 ssl; 15 | 16 | ssl_ciphers ALL:@SECLEVEL=0; #required for self signed certs and/or for certs signed with weak ciphers 17 | ssl_protocols TLSv1.2 TLSv1.3; 18 | ssl_certificate /etc/sslcerts/keycloak.pem; 19 | ssl_certificate_key /etc/sslcerts/keycloak.key; 20 | 21 | add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; 22 | add_header Content-Security-Policy "default-src 'self'; frame-ancestors 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src http://example.com;"; 23 | #add_header X-Content-Type-Options nosniff; # cannot apply now because of open keycloak issue https://issues.redhat.com/browse/KEYCLOAK-17076 24 | add_header X-XSS-Protection: "1; mode=block"; 25 | 26 | proxy_set_header X-Forwarded-For $proxy_protocol_addr; # To forward the original client's IP address 27 | proxy_set_header X-Forwarded-Proto $scheme; # to forward the original protocol (HTTP or HTTPS) 28 | proxy_set_header Host $host:$server_port; # to forward the original host requested by the client 29 | 30 | location / { 31 | root /data/www; 32 | try_files $uri $uri/ /index.html; #to support in app routing in SPA 33 | } 34 | 35 | location /auth { 36 | proxy_pass http://keycloak:8080; #redirect urls starting with /auth to keycloak 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/oauth2/oauth/www/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Hello World!! 4 | 5 | 6 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/oauth2/solace.env: -------------------------------------------------------------------------------- 1 | username_admin_globalaccesslevel=admin 2 | username_admin_password=admin 3 | system_scaling_maxconnectioncount=1000 4 | webmanager_redirecthttp_enable=false 5 | -------------------------------------------------------------------------------- /solace-spring-cloud-stream-binder/solace-spring-cloud-stream-binder/src/test/resources/oauth2/solace_tls.env: -------------------------------------------------------------------------------- 1 | username_admin_globalaccesslevel=admin 2 | username_admin_password=admin 3 | system_scaling_maxconnectioncount=1000 4 | tls_servercertificate_filepath=/run/secrets/server.pem 5 | webmanager_redirecthttp_enable=false 6 | --------------------------------------------------------------------------------