├── .editorconfig
├── .gitattributes
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.yaml
│ ├── config.yml
│ ├── new_feature.yaml
│ └── other.yaml
├── release.yml
├── renovate.json
└── workflows
│ ├── central-sync.yml
│ ├── graalvm-dev.yml
│ ├── graalvm-latest.yml
│ ├── gradle.yml
│ ├── publish-snapshot.yml
│ └── release.yml
├── .gitignore
├── ISSUE_TEMPLATE.md
├── LICENSE
├── MAINTAINING.md
├── README.md
├── SECURITY.md
├── build-logic
├── build.gradle
├── settings.gradle
└── src
│ └── main
│ └── groovy
│ ├── io.micronaut.build.internal.grpc-base.gradle
│ ├── io.micronaut.build.internal.grpc-minimal-test.gradle
│ ├── io.micronaut.build.internal.grpc-module.gradle
│ └── io.micronaut.build.internal.grpc-tests.gradle
├── build.gradle
├── config
├── HEADER
├── checkstyle
│ ├── checkstyle.xml
│ └── suppressions.xml
└── spotless.license.java
├── gradle.properties
├── gradle
├── libs.versions.toml
├── license.gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── grpc-annotation
├── build.gradle
└── src
│ └── main
│ └── java
│ └── io
│ └── micronaut
│ └── grpc
│ └── annotation
│ ├── GrpcChannel.java
│ └── GrpcService.java
├── grpc-bom
└── build.gradle
├── grpc-client-runtime
├── build.gradle
├── config
│ └── accepted-api-changes.json
└── src
│ ├── main
│ └── java
│ │ └── io
│ │ └── micronaut
│ │ └── grpc
│ │ ├── channels
│ │ ├── GrpcChannelBuilderFactory.java
│ │ ├── GrpcDefaultManagedChannelConfiguration.java
│ │ ├── GrpcManagedChannelConfiguration.java
│ │ ├── GrpcManagedChannelFactory.java
│ │ ├── GrpcNamedManagedChannelConfiguration.java
│ │ └── package-info.java
│ │ └── discovery
│ │ ├── GrpcNameResolverProvider.java
│ │ └── package-info.java
│ └── test
│ ├── groovy
│ └── io
│ │ └── micronaut
│ │ └── grpc
│ │ ├── GrpcNamedChannelSpec.groovy
│ │ ├── HelloWordGrpcSpec.groovy
│ │ ├── ManagedChannelBuilderListener.java
│ │ ├── ServerBuilderListener.java
│ │ └── discovery
│ │ ├── GrpcLoadBalancedServiceSpec.groovy
│ │ └── GrpcServiceDiscoverySpec.groovy
│ ├── proto
│ └── helloworld.proto
│ └── resources
│ └── logback.xml
├── grpc-health
├── build.gradle
└── src
│ ├── main
│ └── java
│ │ └── io
│ │ └── micronaut
│ │ └── grpc
│ │ └── server
│ │ └── health
│ │ ├── GrpcHealthFactory.java
│ │ ├── GrpcServerHealthIndicator.java
│ │ └── HealthStatusManagerContainer.java
│ └── test
│ └── groovy
│ └── io
│ └── micronaut
│ └── grpc
│ └── server
│ └── health
│ ├── GrpcServerHealthIndicatorSpec.groovy
│ └── GrpcServerHealthSpec.groovy
├── grpc-opentracing
├── build.gradle
└── src
│ ├── main
│ └── java
│ │ └── io
│ │ └── micronaut
│ │ └── grpc
│ │ ├── client
│ │ └── tracing
│ │ │ ├── GrpcClientTracingInterceptorConfiguration.java
│ │ │ ├── GrpcClientTracingInterceptorFactory.java
│ │ │ └── package-info.java
│ │ └── server
│ │ └── tracing
│ │ ├── GrpcServerTracingInterceptorConfiguration.java
│ │ ├── GrpcServerTracingInterceptorFactory.java
│ │ └── package-info.java
│ └── test
│ ├── groovy
│ └── io
│ │ └── micronaut
│ │ └── grpc
│ │ └── server
│ │ └── tracing
│ │ └── GrpcTracingSpec.groovy
│ └── proto
│ └── helloworld.proto
├── grpc-runtime
└── build.gradle
├── grpc-server-runtime
├── build.gradle
├── config
│ └── accepted-api-changes.json
└── src
│ ├── main
│ └── java
│ │ └── io
│ │ └── micronaut
│ │ └── grpc
│ │ └── server
│ │ ├── GrpcEmbeddedServer.java
│ │ ├── GrpcEmbeddedServerListener.java
│ │ ├── GrpcServerBuilder.java
│ │ ├── GrpcServerChannel.java
│ │ ├── GrpcServerConfiguration.java
│ │ ├── GrpcServerInstance.java
│ │ ├── GrpcSslConfiguration.java
│ │ ├── interceptor
│ │ └── OrderedServerInterceptor.java
│ │ └── package-info.java
│ └── test
│ ├── groovy
│ └── io
│ │ └── micronaut
│ │ └── grpc
│ │ ├── GrpcEmbeddedServerSpec.groovy
│ │ ├── GrpcNamedChannelSpec.groovy
│ │ ├── GrpcServerConfigurationSpec.groovy
│ │ ├── HelloWordGrpcSpec.groovy
│ │ ├── ManagedChannelBuilderListener.java
│ │ ├── ServerBuilderListener.java
│ │ ├── discovery
│ │ └── GrpcServiceDiscoverySpec.groovy
│ │ └── server
│ │ ├── GrpcServerBuilderSpec.groovy
│ │ └── interceptor
│ │ └── OrderedServerInterceptorSpec.groovy
│ ├── proto
│ └── helloworld.proto
│ └── resources
│ ├── example.crt
│ ├── example.key
│ └── logback.xml
├── protobuff-support
├── build.gradle
└── src
│ ├── main
│ └── java
│ │ └── io
│ │ └── micronaut
│ │ └── protobuf
│ │ ├── codec
│ │ ├── ExtensionRegistryFactory.java
│ │ └── ProtobufferCodec.java
│ │ ├── convert
│ │ ├── ByteBufToProtoMessageConverter.java
│ │ └── ProtoMessageToByteBufConverter.java
│ │ └── handler
│ │ └── ProtobufBodyHandler.java
│ └── test
│ ├── groovy
│ └── io
│ │ └── micronaut
│ │ ├── BaseSpec.groovy
│ │ ├── ProgrammaticController.groovy
│ │ ├── ProgrammaticControllerCreator.groovy
│ │ ├── ProgrammaticControllerSpec.groovy
│ │ ├── SampleController.groovy
│ │ ├── SampleWebsocketClient.groovy
│ │ ├── SampleWebsocketHandler.groovy
│ │ ├── SimpleHttpGetSpec.groovy
│ │ ├── SimpleHttpPostSpec.groovy
│ │ └── SimpleWebsocketSpec.groovy
│ ├── proto
│ └── example.proto
│ └── resources
│ └── logback-test.xml
├── settings.gradle
├── src
└── main
│ └── docs
│ └── guide
│ ├── client.adoc
│ ├── gettingStarted.adoc
│ ├── introduction.adoc
│ ├── protocolBuffers.adoc
│ ├── releaseHistory.adoc
│ ├── repository.adoc
│ ├── server.adoc
│ ├── serviceDiscovery.adoc
│ ├── toc.yml
│ └── tracing.adoc
├── test-suite-groovy
├── build.gradle
└── src
│ ├── main
│ ├── groovy
│ │ └── helloworld
│ │ │ ├── Application.groovy
│ │ │ ├── GreetingEndpoint.groovy
│ │ │ ├── GreetingService.groovy
│ │ │ └── HealthService.groovy
│ ├── proto
│ │ └── helloworld.proto
│ └── resources
│ │ ├── application.yml
│ │ └── logback.xml
│ └── test
│ └── groovy
│ └── helloworld
│ ├── GreetingEndpointSpec.groovy
│ └── HealthCheckSpec.groovy
├── test-suite-java
├── .mvn
│ └── wrapper
│ │ ├── maven-wrapper.jar
│ │ └── maven-wrapper.properties
├── build.gradle
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── helloworld
│ │ │ ├── Application.java
│ │ │ ├── GreetingEndpoint.java
│ │ │ ├── GreetingService.java
│ │ │ └── HealthService.java
│ ├── proto
│ │ └── helloworld.proto
│ └── resources
│ │ ├── application.yml
│ │ └── logback.xml
│ └── test
│ └── java
│ └── helloworld
│ ├── GreetingEndpointTest.java
│ └── HealthCheckTest.java
└── test-suite-kotlin
├── build.gradle
└── src
├── main
├── kotlin
│ └── helloworld
│ │ ├── Application.kt
│ │ ├── GreetingEndpoint.kt
│ │ ├── GreetingService.kt
│ │ └── HealthService.kt
├── proto
│ └── helloworld.proto
└── resources
│ ├── META-INF
│ └── native-image
│ │ └── io.micronaut.grpc
│ │ └── kotlin-runtime
│ │ └── native-image.properties
│ ├── application.yml
│ └── logback.xml
└── test
└── kotlin
└── helloworld
├── GreetingServiceTest.kt
└── HealthCheckTest.kt
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | trim_trailing_whitespace = true
5 | insert_final_newline = true
6 | charset = utf-8
7 | indent_style = space
8 |
9 | [{*.sh,gradlew}]
10 | end_of_line = lf
11 |
12 | [{*.bat,*.cmd}]
13 | end_of_line = crlf
14 |
15 | [{*.mustache,*.ftl}]
16 | insert_final_newline = false
17 |
18 | [*.java]
19 | indent_size = 4
20 | tab_width = 4
21 | max_line_length = 100
22 | # Import order can be configured with ij_java_imports_layout=...
23 | # See documentation https://youtrack.jetbrains.com/issue/IDEA-170643#focus=streamItem-27-3708697.0-0
24 |
25 | [*.xml]
26 | indent_size = 4
27 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | *.java text eol=lf
5 | *.groovy text eol=lf
6 | *.html text eol=lf
7 | *.kt text eol=lf
8 | *.kts text eol=lf
9 | *.md text diff=markdown eol=lf
10 | *.py text diff=python executable
11 | *.pl text diff=perl executable
12 | *.pm text diff=perl
13 | *.css text diff=css eol=lf
14 | *.js text eol=lf
15 | *.sql text eol=lf
16 | *.q text eol=lf
17 |
18 | *.sh text eol=lf
19 | gradlew text eol=lf
20 |
21 | *.bat text eol=crlf
22 | *.cmd text eol=crlf
23 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.yaml:
--------------------------------------------------------------------------------
1 | name: Bug Report
2 | description: File a bug report
3 | body:
4 | - type: markdown
5 | attributes:
6 | value: |
7 | Thanks for reporting an issue, please review the task list below before submitting the issue. Your issue report will be closed if the issue is incomplete and the below tasks not completed.
8 |
9 | NOTE: If you are unsure about something and the issue is more of a question a better place to ask questions is on Github Discussions :arrow_up:, [Stack Overflow](https://stackoverflow.com/tags/micronaut) or [Gitter](https://gitter.im/micronautfw/).
10 | - type: textarea
11 | attributes:
12 | label: Expected Behavior
13 | description: A concise description of what you expected to happen.
14 | placeholder: Tell us what should happen
15 | validations:
16 | required: false
17 | - type: textarea
18 | attributes:
19 | label: Actual Behaviour
20 | description: A concise description of what you're experiencing.
21 | placeholder: Tell us what happens instead
22 | validations:
23 | required: false
24 | - type: textarea
25 | attributes:
26 | label: Steps To Reproduce
27 | description: Steps to reproduce the behavior.
28 | placeholder: |
29 | 1. In this environment...
30 | 2. With this config...
31 | 3. Run '...'
32 | 4. See error...
33 | validations:
34 | required: false
35 | - type: textarea
36 | attributes:
37 | label: Environment Information
38 | description: Environment information where the problem occurs.
39 | placeholder: |
40 | - Operating System:
41 | - JDK Version:
42 | validations:
43 | required: false
44 | - type: input
45 | id: example
46 | attributes:
47 | label: Example Application
48 | description: Example application link.
49 | placeholder: |
50 | Link to GitHub repository with an example that reproduces the issue
51 | validations:
52 | required: false
53 | - type: input
54 | id: version
55 | attributes:
56 | label: Version
57 | description: Micronaut version
58 | validations:
59 | required: true
60 |
61 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | contact_links:
2 | - name: Micronaut Core Discussions
3 | url: https://github.com/micronaut-projects/micronaut-core/discussions
4 | about: Ask questions about Micronaut on Github
5 | - name: Micronaut Data Discussions
6 | url: https://github.com/micronaut-projects/micronaut-data/discussions
7 | about: Ask Micronaut Data related questions on Github
8 | - name: Stack Overflow
9 | url: https://stackoverflow.com/tags/micronaut
10 | about: Ask questions on Stack Overflow
11 | - name: Chat
12 | url: https://gitter.im/micronautfw/
13 | about: Chat with us on Gitter.
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/new_feature.yaml:
--------------------------------------------------------------------------------
1 | name: Feature request
2 | description: Create a new feature request
3 | body:
4 | - type: markdown
5 | attributes:
6 | value: |
7 | Please describe the feature you want for Micronaut to implement, before that check if there is already an existing issue to add it.
8 | - type: textarea
9 | attributes:
10 | label: Feature description
11 | placeholder: Tell us what feature you would like for Micronaut to have and what problem is it going to solve
12 | validations:
13 | required: true
14 |
15 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/other.yaml:
--------------------------------------------------------------------------------
1 | name: Other
2 | description: Something different
3 | body:
4 | - type: textarea
5 | attributes:
6 | label: Issue description
7 | validations:
8 | required: true
9 |
10 |
--------------------------------------------------------------------------------
/.github/release.yml:
--------------------------------------------------------------------------------
1 | changelog:
2 | exclude:
3 | authors:
4 | - micronaut-build
5 | categories:
6 | - title: Breaking Changes 🛠
7 | labels:
8 | - 'type: breaking'
9 | - title: New Features 🎉
10 | labels:
11 | - 'type: enhancement'
12 | - title: Bug Fixes 🐞
13 | labels:
14 | - 'type: bug'
15 | - title: Improvements ⭐
16 | labels:
17 | - 'type: improvement'
18 | - title: Docs 📖
19 | labels:
20 | - 'type: docs'
21 | - title: Dependency updates 🚀
22 | labels:
23 | - 'type: dependency-upgrade'
24 | - 'dependency-upgrade'
25 | - title: Regressions 🧐
26 | labels:
27 | - 'type: regression'
28 | - title: GraalVM 🏆
29 | labels:
30 | - 'relates-to: graal'
31 | - title: Other Changes 💡
32 | labels:
33 | - "*"
34 |
--------------------------------------------------------------------------------
/.github/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "config:recommended"
4 | ],
5 | "addLabels": [
6 | "type: dependency-upgrade"
7 | ],
8 | "schedule": [
9 | "after 10pm"
10 | ],
11 | "prHourlyLimit": 1,
12 | "prConcurrentLimit": 20,
13 | "timezone": "Europe/Prague",
14 | "packageRules": [
15 | {
16 | "dependencyDashboardApproval": true,
17 | "matchUpdateTypes": [
18 | "patch"
19 | ],
20 | "matchCurrentVersion": "!/^0/",
21 | "automerge": true,
22 | "matchPackageNames": [
23 | "/actions.*/"
24 | ]
25 | },
26 | {
27 | "matchUpdateTypes": [
28 | "patch"
29 | ],
30 | "matchCurrentVersion": "!/^0/",
31 | "automerge": true
32 | }
33 | ]
34 | }
35 |
--------------------------------------------------------------------------------
/.github/workflows/central-sync.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Do not edit this file directly. Instead, go to:
2 | #
3 | # https://github.com/micronaut-projects/micronaut-project-template/tree/master/.github/workflows
4 | #
5 | # and edit them there. Note that it will be sync'ed to all the Micronaut repos
6 | name: Maven Central Sync
7 | on:
8 | workflow_dispatch:
9 | inputs:
10 | release_version:
11 | description: 'Release version (eg: 1.2.3)'
12 | required: true
13 | jobs:
14 | central-sync:
15 | runs-on: ubuntu-latest
16 | steps:
17 | - name: Checkout repository
18 | uses: actions/checkout@v4
19 | with:
20 | ref: v${{ github.event.inputs.release_version }}
21 | - uses: gradle/wrapper-validation-action@v3
22 | - name: Set up JDK
23 | uses: actions/setup-java@v4
24 | with:
25 | distribution: 'temurin'
26 | java-version: '17'
27 | - name: Publish to Sonatype OSSRH
28 | env:
29 | SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
30 | SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
31 | GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }}
32 | GPG_PASSWORD: ${{ secrets.GPG_PASSWORD }}
33 | GPG_FILE: ${{ secrets.GPG_FILE }}
34 | DEVELOCITY_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }}
35 | DEVELOCITY_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USERNAME }}
36 | DEVELOCITY_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }}
37 | run: |
38 | echo $GPG_FILE | base64 -d > secring.gpg
39 | ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository
40 |
--------------------------------------------------------------------------------
/.github/workflows/graalvm-dev.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Do not edit this file directly. Instead, go to:
2 | #
3 | # https://github.com/micronaut-projects/micronaut-project-template/tree/master/.github/workflows
4 | #
5 | # and edit them there. Note that it will be sync'ed to all the Micronaut repos
6 | name: GraalVM Dev CI
7 | on:
8 | schedule:
9 | - cron: "0 1 * * 1-5" # Mon-Fri at 1am UTC
10 | jobs:
11 | build_matrix:
12 | if: github.repository != 'micronaut-projects/micronaut-project-template'
13 | runs-on: ubuntu-latest
14 | env:
15 | DEVELOCITY_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }}
16 | DEVELOCITY_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USERNAME }}
17 | DEVELOCITY_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }}
18 | outputs:
19 | matrix: ${{ steps.build-matrix.outputs.matrix }}
20 | steps:
21 | - uses: actions/checkout@v4
22 | - name: Build Matrix
23 | uses: micronaut-projects/github-actions/graalvm/build-matrix@master
24 | id: build-matrix
25 | build:
26 | needs: build_matrix
27 | if: github.repository != 'micronaut-projects/micronaut-project-template'
28 | runs-on: ubuntu-latest
29 | strategy:
30 | max-parallel: 6
31 | matrix:
32 | java: ['dev', 'latest-ea']
33 | distribution: ['graalvm-community', 'graalvm']
34 | native_test_task: ${{ fromJson(needs.build_matrix.outputs.matrix).native_test_task }}
35 | exclude:
36 | - java: 'dev'
37 | distribution: 'graalvm'
38 | - java: 'latest-ea'
39 | distribution: 'graalvm-community'
40 | env:
41 | DEVELOCITY_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }}
42 | DEVELOCITY_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USERNAME }}
43 | DEVELOCITY_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }}
44 | steps:
45 | - uses: actions/checkout@v4
46 | - name: Pre-Build Steps
47 | uses: micronaut-projects/github-actions/graalvm/pre-build@master
48 | id: pre-build
49 | with:
50 | java: ${{ matrix.java }}
51 | distribution: ${{ matrix.distribution }}
52 | - name: Build Steps
53 | uses: micronaut-projects/github-actions/graalvm/build@master
54 | id: build
55 | env:
56 | GH_TOKEN_PUBLIC_REPOS_READONLY: ${{ secrets.GH_TOKEN_PUBLIC_REPOS_READONLY }}
57 | GH_USERNAME: ${{ secrets.GH_USERNAME }}
58 | GRAALVM_QUICK_BUILD: true
59 | with:
60 | nativeTestTask: ${{ matrix.native_test_task }}
61 | - name: Post-Build Steps
62 | uses: micronaut-projects/github-actions/graalvm/post-build@master
63 | id: post-build
64 | with:
65 | java: ${{ matrix.java }}
66 |
--------------------------------------------------------------------------------
/.github/workflows/graalvm-latest.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Do not edit this file directly. Instead, go to:
2 | #
3 | # https://github.com/micronaut-projects/micronaut-project-template/tree/master/.github/workflows
4 | #
5 | # and edit them there. Note that it will be sync'ed to all the Micronaut repos
6 | name: GraalVM Latest CI
7 | on:
8 | push:
9 | branches:
10 | - master
11 | - '[1-9]+.[0-9]+.x'
12 | pull_request:
13 | branches:
14 | - master
15 | - '[1-9]+.[0-9]+.x'
16 | jobs:
17 | build_matrix:
18 | if: github.repository != 'micronaut-projects/micronaut-project-template'
19 | runs-on: ubuntu-latest
20 | env:
21 | DEVELOCITY_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }}
22 | DEVELOCITY_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USERNAME }}
23 | DEVELOCITY_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }}
24 | outputs:
25 | matrix: ${{ steps.build-matrix.outputs.matrix }}
26 | steps:
27 | - uses: actions/checkout@v4
28 | - name: Build Matrix
29 | uses: micronaut-projects/github-actions/graalvm/build-matrix@master
30 | id: build-matrix
31 | build:
32 | needs: build_matrix
33 | if: github.repository != 'micronaut-projects/micronaut-project-template'
34 | runs-on: ubuntu-latest
35 | strategy:
36 | max-parallel: 6
37 | matrix:
38 | java: ['17', '21']
39 | native_test_task: ${{ fromJson(needs.build_matrix.outputs.matrix).native_test_task }}
40 | env:
41 | DEVELOCITY_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }}
42 | DEVELOCITY_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USERNAME }}
43 | DEVELOCITY_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }}
44 | steps:
45 | - uses: actions/checkout@v4
46 | - name: Pre-Build Steps
47 | uses: micronaut-projects/github-actions/graalvm/pre-build@master
48 | id: pre-build
49 | with:
50 | distribution: 'graalvm'
51 | java: ${{ matrix.java }}
52 | - name: Build Steps
53 | uses: micronaut-projects/github-actions/graalvm/build@master
54 | id: build
55 | env:
56 | GH_TOKEN_PUBLIC_REPOS_READONLY: ${{ secrets.GH_TOKEN_PUBLIC_REPOS_READONLY }}
57 | GH_USERNAME: ${{ secrets.GH_USERNAME }}
58 | GRAALVM_QUICK_BUILD: true
59 | with:
60 | nativeTestTask: ${{ matrix.native_test_task }}
61 | - name: Post-Build Steps
62 | uses: micronaut-projects/github-actions/graalvm/post-build@master
63 | id: post-build
64 | with:
65 | java: ${{ matrix.java }}
66 |
--------------------------------------------------------------------------------
/.github/workflows/gradle.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Do not edit this file directly. Instead, go to:
2 | #
3 | # https://github.com/micronaut-projects/micronaut-project-template/tree/master/.github/workflows
4 | #
5 | # and edit them there. Note that it will be sync'ed to all the Micronaut repos
6 | name: Java CI
7 | on:
8 | push:
9 | branches:
10 | - master
11 | - '[1-9]+.[0-9]+.x'
12 | pull_request:
13 | branches:
14 | - master
15 | - '[1-9]+.[0-9]+.x'
16 | jobs:
17 | build:
18 | if: github.repository != 'micronaut-projects/micronaut-project-template'
19 | runs-on: ubuntu-latest
20 | strategy:
21 | matrix:
22 | java: ['17', '21']
23 | env:
24 | DEVELOCITY_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }}
25 | DEVELOCITY_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USERNAME }}
26 | DEVELOCITY_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }}
27 | GH_TOKEN_PUBLIC_REPOS_READONLY: ${{ secrets.GH_TOKEN_PUBLIC_REPOS_READONLY }}
28 | GH_USERNAME: ${{ secrets.GH_USERNAME }}
29 | TESTCONTAINERS_RYUK_DISABLED: true
30 | PREDICTIVE_TEST_SELECTION: "${{ github.event_name == 'pull_request' && 'true' || 'false' }}"
31 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
32 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
33 | OSS_INDEX_USERNAME: ${{ secrets.OSS_INDEX_USERNAME }}
34 | OSS_INDEX_PASSWORD: ${{ secrets.OSS_INDEX_PASSWORD }}
35 | steps:
36 | # https://github.com/actions/virtual-environments/issues/709
37 | - name: "🗑 Free disk space"
38 | run: |
39 | sudo rm -rf "/usr/local/share/boost"
40 | sudo rm -rf "$AGENT_TOOLSDIRECTORY"
41 | sudo apt-get clean
42 | df -h
43 |
44 | - name: "📥 Checkout repository"
45 | uses: actions/checkout@v4
46 | with:
47 | fetch-depth: 0
48 |
49 | - name: "🔧 Setup GraalVM CE"
50 | uses: graalvm/setup-graalvm@v1.3.3
51 | with:
52 | distribution: 'graalvm'
53 | java-version: ${{ matrix.java }}
54 | github-token: ${{ secrets.GITHUB_TOKEN }}
55 |
56 | - name: "🔧 Setup Gradle"
57 | uses: gradle/gradle-build-action@v3.5.0
58 |
59 | - name: "❓ Optional setup step"
60 | run: |
61 | [ -f ./setup.sh ] && ./setup.sh || [ ! -f ./setup.sh ]
62 |
63 | - name: "🚔 Sonatype Scan"
64 | id: sonatypescan
65 | run: |
66 | ./gradlew ossIndexAudit --no-parallel --info
67 |
68 | - name: "🛠 Build with Gradle"
69 | id: gradle
70 | run: |
71 | ./gradlew check --no-daemon --continue
72 |
73 | - name: "🔎 Run static analysis"
74 | if: env.SONAR_TOKEN != '' && matrix.java == '17'
75 | run: |
76 | ./gradlew sonar
77 |
78 | - name: "📊 Publish Test Report"
79 | if: always()
80 | uses: mikepenz/action-junit-report@v5
81 | with:
82 | check_name: Java CI / Test Report (${{ matrix.java }})
83 | report_paths: '**/build/test-results/test/TEST-*.xml'
84 | check_retries: 'true'
85 |
86 | - name: "📜 Upload binary compatibility check results"
87 | if: matrix.java == '17'
88 | uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
89 | with:
90 | name: binary-compatibility-reports
91 | path: "**/build/reports/binary-compatibility-*.html"
92 |
93 | - name: "📦 Publish to Sonatype Snapshots"
94 | if: success() && github.event_name == 'push' && matrix.java == '17'
95 | env:
96 | SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
97 | SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
98 | run: ./gradlew publishToSonatype docs --no-daemon
99 |
100 | - name: "❓ Determine docs target repository"
101 | uses: haya14busa/action-cond@v1
102 | id: docs_target
103 | with:
104 | cond: ${{ github.repository == 'micronaut-projects/micronaut-core' }}
105 | if_true: "micronaut-projects/micronaut-docs"
106 | if_false: ${{ github.repository }}
107 |
108 | - name: "📑 Publish to Github Pages"
109 | if: success() && github.event_name == 'push' && matrix.java == '17'
110 | uses: micronaut-projects/github-pages-deploy-action@master
111 | env:
112 | TARGET_REPOSITORY: ${{ steps.docs_target.outputs.value }}
113 | GH_TOKEN: ${{ secrets.GH_TOKEN }}
114 | BRANCH: gh-pages
115 | FOLDER: build/docs
116 |
--------------------------------------------------------------------------------
/.github/workflows/publish-snapshot.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Do not edit this file directly. Instead, go to:
2 | #
3 | # https://github.com/micronaut-projects/micronaut-project-template/tree/master/.github/workflows
4 | #
5 | # and edit them there. Note that it will be sync'ed to all the Micronaut repos
6 | name: Publish snapshot release
7 | on: [workflow_dispatch]
8 | jobs:
9 | build:
10 | if: github.repository != 'micronaut-projects/micronaut-project-template'
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v4
14 | - uses: actions/cache@v4
15 | with:
16 | path: ~/.gradle/caches
17 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
18 | restore-keys: |
19 | ${{ runner.os }}-gradle-
20 | - name: Set up JDK
21 | uses: actions/setup-java@v4
22 | with:
23 | distribution: 'temurin'
24 | java-version: '17'
25 | - name: Publish to Sonatype Snapshots
26 | if: success()
27 | env:
28 | SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
29 | SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
30 | DEVELOCITY_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }}
31 | DEVELOCITY_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USERNAME }}
32 | DEVELOCITY_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }}
33 | run: ./gradlew publishToSonatype --no-daemon
34 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | dist/
2 | .DS_Store
3 | target/
4 | .gradle/
5 | .idea/
6 | build/
7 | !build-logic/src/main/java/io/micronaut/build
8 | classes/
9 | out/
10 | *.db
11 | *.log
12 | *.iml
13 | .classpath
14 | .factorypath
15 | bin/
16 | .settings/
17 | .project
18 | */test/
19 | */META-INF/
20 | *.ipr
21 | *.iws
22 | .kotlintest
23 | */.kotlintest/
24 |
25 | # ignore resources, are downloaded via a gradle task from micronaut_docs
26 | src/main/docs/resources/css/highlight/*.css
27 | src/main/docs/resources/css/highlight/*.png
28 | src/main/docs/resources/css/highlight/*.jpg
29 | src/main/docs/resources/css/*.css
30 | src/main/docs/resources/js/*.js
31 | src/main/docs/resources/style/*.html
32 | src/main/docs/resources/img/micronaut-logo-white.svg
33 |
34 | # Ignore files generated by test-resources
35 | **/.micronaut/test-resources/
36 |
--------------------------------------------------------------------------------
/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | Thanks for reporting an issue, please review the task list below before submitting the
2 | issue. Your issue report will be closed if the issue is incomplete and the below tasks not completed.
3 |
4 | NOTE: If you are unsure about something and the issue is more of a question a better place to ask questions is on Stack Overflow (https://stackoverflow.com/tags/micronaut) or Gitter (https://gitter.im/micronautfw/). DO NOT use the issue tracker to ask questions.
5 |
6 | ### Task List
7 |
8 | - [ ] Steps to reproduce provided
9 | - [ ] Stacktrace (if present) provided
10 | - [ ] Example that reproduces the problem uploaded to GitHub
11 | - [ ] Full description of the issue provided (see below)
12 |
13 | ### Steps to Reproduce
14 |
15 | 1. TODO
16 | 2. TODO
17 | 3. TODO
18 |
19 | ### Expected Behaviour
20 |
21 | Tell us what should happen
22 |
23 | ### Actual Behaviour
24 |
25 | Tell us what happens instead
26 |
27 | ### Environment Information
28 |
29 | - **Operating System**: TODO
30 | - **Micronaut Version:** TODO
31 | - **JDK Version:** TODO
32 |
33 | ### Example Application
34 |
35 | - TODO: link to GitHub repository with example that reproduces the issue
36 |
37 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Micronaut GRPC
2 |
3 | [](https://search.maven.org/search?q=g:%22io.micronaut.grpc%22%20AND%20a:%22micronaut-grpc-runtime%22)
4 | [](https://github.com/micronaut-projects/micronaut-grpc/actions)
5 | [](https://ge.micronaut.io/scans)
6 |
7 | This project includes integration between [Micronaut](http://micronaut.io) and [GRPC](https://grpc.io).
8 |
9 | ## Documentation
10 |
11 | See the [Documentation](https://micronaut-projects.github.io/micronaut-grpc/latest/guide) for more information.
12 |
13 | See the [Snapshot Documentation](https://micronaut-projects.github.io/micronaut-grpc/snapshot/guide) for the current development docs.
14 |
15 | ## Examples
16 |
17 | Examples for Java, Kotlin and Groovy can be found in the [examples](https://github.com/micronaut-projects/micronaut-grpc/tree/master/doc-examples) directory.
18 |
19 | ## Snapshots and Releases
20 |
21 | Snaphots are automatically published to [JFrog OSS](https://oss.jfrog.org/artifactory/oss-snapshot-local/) using [Github Actions](https://github.com/micronaut-projects/micronaut-grpc/actions).
22 |
23 | See the documentation in the [Micronaut Docs](https://docs.micronaut.io/latest/guide/index.html#usingsnapshots) for how to configure your build to use snapshots.
24 |
25 | Releases are published to JCenter and Maven Central via [Github Actions](https://github.com/micronaut-projects/micronaut-grpc/actions).
26 |
27 | A release is performed with the following steps:
28 |
29 | * [Edit the version](https://github.com/micronaut-projects/micronaut-grpc/edit/master/gradle.properties) specified by `projectVersion` in `gradle.properties` to a semantic, unreleased version. Example `1.0.0`
30 | * [Create a new release](https://github.com/micronaut-projects/micronaut-grpc/releases/new). The Git Tag should start with `v`. For example `v1.0.0`.
31 | * [Monitor the Workflow](https://github.com/micronaut-projects/micronaut-grpc/actions?query=workflow%3ARelease) to check it passed successfully.
32 | * Celebrate!
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | We release patches for security vulnerabilities. Which versions are eligible
4 | receiving such patches depend on the CVSS v3.0 Rating:
5 |
6 | | CVSS v3.0 | Supported Versions |
7 | |-----------|-------------------------------------------|
8 | | 9.0-10.0 | Releases within the previous three months |
9 | | 4.0-8.9 | Most recent release |
10 |
11 | ## Reporting a Vulnerability
12 |
13 | Please responsibly disclose (suspected) security vulnerabilities to
14 | **[The Micronaut Foundation](foundation@micronaut.io)**. You will receive a response from
15 | us within 48 hours. If the issue is confirmed, we will release a patch as soon
16 | as possible depending on complexity but historically within a few days.
17 |
--------------------------------------------------------------------------------
/build-logic/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'groovy-gradle-plugin'
3 | }
4 |
5 | repositories {
6 | gradlePluginPortal()
7 | mavenCentral()
8 | }
9 |
10 | dependencies {
11 | implementation(libs.micronaut.gradle.plugin)
12 | implementation(libs.sonatype.scan)
13 | }
14 |
--------------------------------------------------------------------------------
/build-logic/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'build-logic'
2 |
3 | dependencyResolutionManagement {
4 | versionCatalogs {
5 | libs {
6 | from(files("../gradle/libs.versions.toml"))
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/build-logic/src/main/groovy/io.micronaut.build.internal.grpc-base.gradle:
--------------------------------------------------------------------------------
1 | repositories {
2 | mavenCentral()
3 | }
4 |
5 | tasks.withType(Test) {
6 | testLogging {
7 | showStandardStreams = true
8 | exceptionFormat = 'full'
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/build-logic/src/main/groovy/io.micronaut.build.internal.grpc-minimal-test.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'io.micronaut.build.internal.grpc-base'
3 | id 'io.micronaut.minimal.application'
4 | }
5 |
--------------------------------------------------------------------------------
/build-logic/src/main/groovy/io.micronaut.build.internal.grpc-module.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'io.micronaut.build.internal.grpc-base'
3 | id "io.micronaut.build.internal.module"
4 | id("org.sonatype.gradle.plugins.scan")
5 | }
6 | String ossIndexUsername = System.getenv("OSS_INDEX_USERNAME") ?: project.properties["ossIndexUsername"]
7 | String ossIndexPassword = System.getenv("OSS_INDEX_PASSWORD") ?: project.properties["ossIndexPassword"]
8 | boolean sonatypePluginConfigured = ossIndexUsername != null && ossIndexPassword != null
9 | ossIndexAudit {
10 | if (sonatypePluginConfigured) {
11 | username = ossIndexUsername
12 | password = ossIndexPassword
13 | }
14 | excludeCompileOnly = true
15 | }
16 |
--------------------------------------------------------------------------------
/build-logic/src/main/groovy/io.micronaut.build.internal.grpc-tests.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id "io.micronaut.build.internal.grpc-base"
3 | id 'org.graalvm.buildtools.native'
4 | id "io.micronaut.application"
5 | }
6 |
7 | tasks.named("test") {
8 | useJUnitPlatform()
9 | }
10 |
11 | graalvmNative {
12 | toolchainDetection = false
13 | metadataRepository {
14 | enabled = true
15 | }
16 | binaries {
17 | all {
18 | resources.autodetect()
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id "io.micronaut.build.internal.docs"
3 | id "io.micronaut.build.internal.quality-reporting"
4 | }
5 |
6 | repositories {
7 | mavenCentral()
8 | }
9 |
10 | configurations.all {
11 | resolutionStrategy {
12 | preferProjectModules()
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/config/HEADER:
--------------------------------------------------------------------------------
1 | Copyright ${year} original authors
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | https://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 |
--------------------------------------------------------------------------------
/config/checkstyle/suppressions.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/config/spotless.license.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-$YEAR original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | projectVersion=4.10.0-SNAPSHOT
2 | projectGroup=io.micronaut.grpc
3 | title=Micronaut gRPC
4 | projectDesc=Integration between Micronaut and gRPC
5 | projectUrl=https://micronaut.io
6 | githubSlug=micronaut-projects/micronaut-grpc
7 | developers=Graeme Rocher
8 |
9 | org.gradle.caching=true
10 | # For sonarqube
11 | org.gradle.jvmargs=-XX:MaxMetaspaceSize=1g
12 |
13 | # No matter which Java toolchain we use, the Kotlin Daemon is always invoked by the current JDK.
14 | # Therefor to fix Kapt errors when running tests under Java 21, we need to open up some modules for the Kotlin Daemon.
15 | kotlin.daemon.jvmargs=--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED\
16 | --add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED \
17 | --add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED \
18 | --add-opens=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \
19 | --add-opens=jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED \
20 | --add-opens=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED \
21 | --add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \
22 | --add-opens=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED \
23 | --add-opens=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \
24 | --add-opens=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
25 |
--------------------------------------------------------------------------------
/gradle/libs.versions.toml:
--------------------------------------------------------------------------------
1 | [versions]
2 | managed-grpc = '1.69.1'
3 | managed-protobuf = '3.25.7'
4 | managed-protobuf-gradle = '0.9.4'
5 | managed-grpc-kotlin = '1.4.3'
6 |
7 | jackson-datatype-protobuf = '0.9.17'
8 | jaeger-core = '1.8.1'
9 | opentracing-grpc = '0.2.3'
10 | opentracing-mock = '0.33.0'
11 | graal-svm = '24.2.1'
12 | javax-annotation-api = '1.3.2'
13 |
14 | micronaut-docs = '2.0.0'
15 | micronaut-gradle-plugin = '4.5.3'
16 | micronaut-tracing-legacy = '3.2.7'
17 | micronaut = "4.8.14"
18 | micronaut-platform = "4.7.6"
19 | micronaut-discovery-client = "4.6.0"
20 | micronaut-reactor = "3.7.0"
21 | micronaut-tracing = "6.9.0"
22 | micronaut-validation = "4.9.0"
23 | micronaut-kotlin = "4.6.0"
24 | micronaut-logging = "1.6.1"
25 | micronaut-test = "4.7.0"
26 | sonatype-scan = "3.0.0"
27 |
28 | [libraries]
29 | # Managed
30 | managed-grpc-core = { module = 'io.grpc:grpc-core', version.ref = 'managed-grpc' }
31 | managed-grpc-protobuf = { module = 'io.grpc:grpc-protobuf', version.ref = 'managed-grpc' }
32 | managed-grpc-stub = { module = 'io.grpc:grpc-stub', version.ref = 'managed-grpc' }
33 | managed-grpc-services = { module = 'io.grpc:grpc-services', version.ref = 'managed-grpc' }
34 | managed-protoc-grpc = { module = 'io.grpc:protoc-gen-grpc-java', version.ref = 'managed-grpc' }
35 | managed-grpc-kotlin-stub = { module = 'io.grpc:grpc-kotlin-stub', version.ref = 'managed-grpc-kotlin' }
36 |
37 | managed-protobuf-java = { module = 'com.google.protobuf:protobuf-java', version.ref = 'managed-protobuf' }
38 | managed-protobuf-javalite = { module = 'com.google.protobuf:protobuf-javalite', version.ref = 'managed-protobuf' }
39 | managed-protobuf-kotlin = { module = 'com.google.protobuf:protobuf-kotlin', version.ref = 'managed-protobuf' }
40 | managed-protobuf-kotlin-lite = { module = 'com.google.protobuf:protobuf-kotlin-lite', version.ref = 'managed-protobuf' }
41 | managed-protobuf-java-util = { module = 'com.google.protobuf:protobuf-java-util', version.ref = 'managed-protobuf' }
42 | managed-protoc = { module = 'com.google.protobuf:protoc', version.ref = 'managed-protobuf' }
43 |
44 | ## BOMs
45 | boms-protobuf = { module = 'com.google.protobuf:protobuf-bom', version.ref = 'managed-protobuf' }
46 | boms-grpc = { module = 'io.grpc:grpc-bom', version.ref = 'managed-grpc' }
47 |
48 | # Micronaut
49 | micronaut-core = { module = 'io.micronaut:micronaut-core-bom', version.ref = 'micronaut' }
50 | micronaut-docs-asciidoc-config-props = { module = 'io.micronaut.docs:micronaut-docs-asciidoc-config-props', version.ref = 'micronaut-docs' }
51 | micronaut-tracing-legacy = { module = 'io.micronaut:micronaut-tracing', version.ref = 'micronaut-tracing-legacy' }
52 | micronaut-reactor = { module = 'io.micronaut.reactor:micronaut-reactor-bom', version.ref = 'micronaut-reactor' }
53 | micronaut-tracing = { module = 'io.micronaut.tracing:micronaut-tracing-bom', version.ref = 'micronaut-tracing' }
54 | micronaut-discovery-client = { module = "io.micronaut.discovery:micronaut-discovery-client", version.ref = "micronaut-discovery-client" }
55 | micronaut-validation = { module = 'io.micronaut.validation:micronaut-validation-bom', version.ref = 'micronaut-validation' }
56 | micronaut-kotlin = { module = 'io.micronaut.kotlin:micronaut-kotlin-bom', version.ref = 'micronaut-kotlin' }
57 | micronaut-logging = { module = 'io.micronaut.logging:micronaut-logging-bom', version.ref = 'micronaut-logging' }
58 | micronaut-test = { module = 'io.micronaut.test:micronaut-test-bom', version.ref = 'micronaut-test' }
59 | micronaut-gradle-plugin = { module = 'io.micronaut.gradle:micronaut-gradle-plugin', version.ref = 'micronaut-gradle-plugin' }
60 |
61 | # Other
62 | graal-svm = { module = 'org.graalvm.nativeimage:svm', version.ref = 'graal-svm' }
63 | grpc-netty = { module = 'io.grpc:grpc-netty' }
64 |
65 | jackson-datatype-protobuf = { module = 'com.hubspot.jackson:jackson-datatype-protobuf', version.ref = 'jackson-datatype-protobuf' }
66 | javax-annotation-api = { module = 'javax.annotation:javax.annotation-api', version.ref = 'javax-annotation-api' }
67 |
68 | jaeger-core = { module = 'io.jaegertracing:jaeger-core', version.ref = 'jaeger-core' }
69 |
70 | netty-tcnative-boringssl-static = { module = 'io.netty:netty-tcnative-boringssl-static' }
71 |
72 | opentracing-grpc = { module = 'io.opentracing.contrib:opentracing-grpc', version.ref = 'opentracing-grpc' }
73 | opentracing-mock = { module = 'io.opentracing:opentracing-mock', version.ref = 'opentracing-mock' }
74 | sonatype-scan = { module = "org.sonatype.gradle.plugins:scan-gradle-plugin", version.ref = "sonatype-scan" }
75 | [plugins]
76 | protobuf = { id = 'com.google.protobuf', version.ref = 'managed-protobuf-gradle' }
77 |
--------------------------------------------------------------------------------
/gradle/license.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.github.hierynomus.license'
2 |
3 | license {
4 | header = rootProject.file('config/HEADER')
5 | strictCheck = true
6 | ignoreFailures = true
7 | mapping {
8 | kt = 'SLASHSTAR_STYLE'
9 | java = 'SLASHSTAR_STYLE'
10 | groovy = 'SLASHSTAR_STYLE'
11 | }
12 | ext.year = '2017-2022'
13 |
14 | exclude "**/transaction/**"
15 | exclude '**/*.txt'
16 | exclude '**/*.html'
17 | exclude '**/*.xml'
18 | exclude '**/*.json'
19 | exclude '**/build-info.properties'
20 | exclude '**/git.properties'
21 | exclude '**/othergit.properties'
22 | }
23 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/micronaut-projects/micronaut-grpc/165833157056e97eb0313098a3c2ac7b115cc0ad/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 | @rem SPDX-License-Identifier: Apache-2.0
17 | @rem
18 |
19 | @if "%DEBUG%"=="" @echo off
20 | @rem ##########################################################################
21 | @rem
22 | @rem Gradle startup script for Windows
23 | @rem
24 | @rem ##########################################################################
25 |
26 | @rem Set local scope for the variables with windows NT shell
27 | if "%OS%"=="Windows_NT" setlocal
28 |
29 | set DIRNAME=%~dp0
30 | if "%DIRNAME%"=="" set DIRNAME=.
31 | @rem This is normally unused
32 | set APP_BASE_NAME=%~n0
33 | set APP_HOME=%DIRNAME%
34 |
35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
37 |
38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
40 |
41 | @rem Find java.exe
42 | if defined JAVA_HOME goto findJavaFromJavaHome
43 |
44 | set JAVA_EXE=java.exe
45 | %JAVA_EXE% -version >NUL 2>&1
46 | if %ERRORLEVEL% equ 0 goto execute
47 |
48 | echo. 1>&2
49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
50 | echo. 1>&2
51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
52 | echo location of your Java installation. 1>&2
53 |
54 | goto fail
55 |
56 | :findJavaFromJavaHome
57 | set JAVA_HOME=%JAVA_HOME:"=%
58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
59 |
60 | if exist "%JAVA_EXE%" goto execute
61 |
62 | echo. 1>&2
63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
64 | echo. 1>&2
65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
66 | echo location of your Java installation. 1>&2
67 |
68 | goto fail
69 |
70 | :execute
71 | @rem Setup the command line
72 |
73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
74 |
75 |
76 | @rem Execute Gradle
77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
78 |
79 | :end
80 | @rem End local scope for the variables with windows NT shell
81 | if %ERRORLEVEL% equ 0 goto mainEnd
82 |
83 | :fail
84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
85 | rem the _cmd.exe /c_ return code!
86 | set EXIT_CODE=%ERRORLEVEL%
87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
89 | exit /b %EXIT_CODE%
90 |
91 | :mainEnd
92 | if "%OS%"=="Windows_NT" endlocal
93 |
94 | :omega
95 |
--------------------------------------------------------------------------------
/grpc-annotation/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'io.micronaut.build.internal.grpc-module'
3 | }
4 |
--------------------------------------------------------------------------------
/grpc-annotation/src/main/java/io/micronaut/grpc/annotation/GrpcChannel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut.grpc.annotation;
17 |
18 | import java.lang.annotation.Documented;
19 | import java.lang.annotation.Retention;
20 |
21 | import io.micronaut.context.annotation.AliasFor;
22 |
23 | import static java.lang.annotation.RetentionPolicy.RUNTIME;
24 |
25 | /**
26 | * An annotation that can be used to inject a GRPC {@code ManagedChannel}.
27 | *
28 | * @author graemerocher
29 | * @since 1.0
30 | */
31 | @Documented
32 | @Retention(RUNTIME)
33 | public @interface GrpcChannel {
34 |
35 | /**
36 | * @return The URL or service ID of the remote service
37 | */
38 | @AliasFor(member = "id")
39 | String value() default "";
40 |
41 | /**
42 | * @return The ID of the client
43 | */
44 | @AliasFor(member = "value")
45 | String id() default "";
46 | }
47 |
--------------------------------------------------------------------------------
/grpc-annotation/src/main/java/io/micronaut/grpc/annotation/GrpcService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut.grpc.annotation;
17 |
18 | import java.lang.annotation.Documented;
19 | import java.lang.annotation.ElementType;
20 | import java.lang.annotation.Retention;
21 | import java.lang.annotation.Target;
22 |
23 | import jakarta.inject.Singleton;
24 |
25 | import static java.lang.annotation.RetentionPolicy.RUNTIME;
26 |
27 | /**
28 | * A meta annotation for annotation GRPC services. Note that annotation is more
29 | * for documentation purposes and not strictly necessary.
30 | *
31 | * @author graemerocher
32 | * @since 1.0
33 | */
34 | @Documented
35 | @Retention(RUNTIME)
36 | @Singleton
37 | @Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
38 | public @interface GrpcService {
39 | }
40 |
--------------------------------------------------------------------------------
/grpc-bom/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id "io.micronaut.build.internal.bom"
3 | }
4 |
--------------------------------------------------------------------------------
/grpc-client-runtime/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'io.micronaut.build.internal.grpc-module'
3 | alias libs.plugins.protobuf
4 | }
5 |
6 | dependencies {
7 | api platform(libs.boms.grpc)
8 | api projects.micronautGrpcAnnotation
9 | api projects.micronautGrpcOpentracing
10 | api libs.managed.grpc.core
11 | api libs.managed.grpc.protobuf
12 | api libs.managed.grpc.stub
13 |
14 | compileOnly mn.micronaut.discovery.core
15 |
16 | implementation libs.grpc.netty
17 | implementation mn.reactor
18 | implementation mn.micronaut.buffer.netty
19 |
20 | testCompileOnly libs.javax.annotation.api
21 | testCompileOnly libs.managed.protobuf.java
22 |
23 | testImplementation projects.micronautGrpcServerRuntime
24 | testImplementation mn.micronaut.discovery.core
25 | testImplementation mnReactor.micronaut.reactor.http.client
26 | testImplementation mn.micronaut.jackson.databind
27 | testImplementation libs.opentracing.mock
28 |
29 | testRuntimeOnly mn.micronaut.jackson.databind
30 | }
31 |
32 | // compileJava.options.fork=true
33 | // compileJava.options.forkOptions.jvmArgs = ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005']
34 |
35 | sourceSets {
36 | test {
37 | java {
38 | srcDirs 'build/generated/source/proto/test/grpc'
39 | srcDirs 'build/generated/source/proto/test/java'
40 | }
41 | }
42 | }
43 |
44 | protobuf {
45 | protoc { artifact = libs.managed.protoc.asProvider().get() }
46 | plugins {
47 | grpc { artifact = libs.managed.protoc.grpc.get() }
48 | }
49 | generateProtoTasks {
50 | all()*.plugins { grpc {} }
51 | }
52 | }
53 |
54 | micronautBuild {
55 | binaryCompatibility {
56 | acceptedRegressionsFile = file("config/accepted-api-changes.json")
57 | }
58 | }
59 |
60 |
--------------------------------------------------------------------------------
/grpc-client-runtime/src/main/java/io/micronaut/grpc/channels/GrpcChannelBuilderFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut.grpc.channels;
17 |
18 | import java.util.Collections;
19 | import java.util.List;
20 | import java.util.concurrent.ExecutorService;
21 |
22 | import io.grpc.ClientInterceptor;
23 | import io.grpc.netty.NettyChannelBuilder;
24 | import io.micronaut.context.ApplicationContext;
25 | import io.micronaut.context.annotation.Bean;
26 | import io.micronaut.context.annotation.Factory;
27 | import io.micronaut.context.annotation.Parameter;
28 | import io.micronaut.context.annotation.Prototype;
29 | import io.micronaut.core.util.CollectionUtils;
30 | import io.micronaut.inject.qualifiers.Qualifiers;
31 | import io.micronaut.scheduling.TaskExecutors;
32 |
33 | import jakarta.inject.Named;
34 |
35 | /**
36 | * Factory class for creating {@link NettyChannelBuilder} instances.
37 | *
38 | * @author graemerocher
39 | * @since 1.0
40 | */
41 | @Factory
42 | public class GrpcChannelBuilderFactory {
43 |
44 | private final ApplicationContext beanContext;
45 | private final ExecutorService executorService;
46 |
47 | /**
48 | * Default constructor.
49 | *
50 | * @param beanContext The bean context
51 | * @param executorService The I/O executor service
52 | */
53 | public GrpcChannelBuilderFactory(
54 | ApplicationContext beanContext,
55 | @Named(TaskExecutors.IO) ExecutorService executorService) {
56 | this.beanContext = beanContext;
57 | this.executorService = executorService;
58 | }
59 |
60 | /**
61 | * Constructor a managed channel build for the given target name and interceptors.
62 | *
63 | * @param target The target name
64 | * @param interceptors The interceptors
65 | *
66 | * @return The channel builder
67 | */
68 | @Bean
69 | @Prototype
70 | protected NettyChannelBuilder managedChannelBuilder(@Parameter String target, List interceptors) {
71 | GrpcManagedChannelConfiguration config = beanContext.findBean(GrpcManagedChannelConfiguration.class, Qualifiers.byName(target)).orElseGet(() -> {
72 | final GrpcDefaultManagedChannelConfiguration mcc = new GrpcDefaultManagedChannelConfiguration(
73 | target,
74 | beanContext.getEnvironment(),
75 | executorService
76 | );
77 | beanContext.inject(mcc);
78 | return mcc;
79 | }
80 | );
81 | final NettyChannelBuilder channelBuilder = config.getChannelBuilder();
82 | if (CollectionUtils.isNotEmpty(interceptors)) {
83 | Collections.reverse(interceptors);
84 | channelBuilder.intercept(interceptors);
85 | }
86 | return channelBuilder;
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/grpc-client-runtime/src/main/java/io/micronaut/grpc/channels/GrpcDefaultManagedChannelConfiguration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut.grpc.channels;
17 |
18 | import java.util.concurrent.ExecutorService;
19 |
20 | import io.micronaut.context.annotation.ConfigurationProperties;
21 | import io.micronaut.context.env.Environment;
22 | import io.micronaut.scheduling.TaskExecutors;
23 |
24 | import jakarta.inject.Named;
25 |
26 | /**
27 | * Default configuration for all GRPC clients.
28 | *
29 | * @author graemerocher
30 | * @since 1.0
31 | */
32 | @ConfigurationProperties(GrpcDefaultManagedChannelConfiguration.PREFIX)
33 | public class GrpcDefaultManagedChannelConfiguration extends GrpcManagedChannelConfiguration {
34 |
35 | public static final String NAME = "default";
36 | public static final String PREFIX = "grpc.client";
37 |
38 | /**
39 | * Default constructor.
40 | *
41 | * @param env The environment
42 | * @param executorService The executor service
43 | */
44 | public GrpcDefaultManagedChannelConfiguration(
45 | Environment env,
46 | @Named(TaskExecutors.IO) ExecutorService executorService) {
47 | super(NAME, env, executorService);
48 | }
49 |
50 | /**
51 | * Default constructor.
52 | *
53 | * @param target The target
54 | * @param env The environment
55 | * @param executorService The executor service
56 | */
57 | public GrpcDefaultManagedChannelConfiguration(
58 | String target,
59 | Environment env,
60 | @Named(TaskExecutors.IO) ExecutorService executorService) {
61 | super(target, env, executorService);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/grpc-client-runtime/src/main/java/io/micronaut/grpc/channels/GrpcNamedManagedChannelConfiguration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut.grpc.channels;
17 |
18 | import java.util.concurrent.ExecutorService;
19 |
20 | import io.micronaut.context.annotation.EachProperty;
21 | import io.micronaut.context.annotation.Parameter;
22 | import io.micronaut.context.env.Environment;
23 | import io.micronaut.scheduling.TaskExecutors;
24 |
25 | import jakarta.inject.Named;
26 |
27 | /**
28 | * Constructs a named channel configuration for each property specified in {@link GrpcManagedChannelConfiguration#PREFIX}.
29 | *
30 | * @author graemerocher
31 | * @since 1.0.0
32 | */
33 | @EachProperty(GrpcManagedChannelConfiguration.PREFIX)
34 | public class GrpcNamedManagedChannelConfiguration extends GrpcManagedChannelConfiguration {
35 |
36 | /**
37 | * Default constructor.
38 | *
39 | * @param name The name
40 | * @param env The environment
41 | * @param executorService The executor service
42 | */
43 | public GrpcNamedManagedChannelConfiguration(
44 | @Parameter String name,
45 | Environment env,
46 | @Named(TaskExecutors.IO) ExecutorService executorService) {
47 | super(name, env, executorService);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/grpc-client-runtime/src/main/java/io/micronaut/grpc/channels/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | /**
17 | * Classes related to GRPC channels and clients.
18 | */
19 | package io.micronaut.grpc.channels;
20 |
--------------------------------------------------------------------------------
/grpc-client-runtime/src/main/java/io/micronaut/grpc/discovery/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | /**
17 | * Classes related to GRPC service discovery.
18 | */
19 | package io.micronaut.grpc.discovery;
20 |
--------------------------------------------------------------------------------
/grpc-client-runtime/src/test/groovy/io/micronaut/grpc/ManagedChannelBuilderListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut.grpc;
17 |
18 | import io.grpc.ManagedChannelBuilder;
19 | import io.micronaut.context.event.BeanCreatedEvent;
20 | import io.micronaut.context.event.BeanCreatedEventListener;
21 |
22 | import jakarta.inject.Singleton;
23 |
24 | @Singleton
25 | public class ManagedChannelBuilderListener implements BeanCreatedEventListener> {
26 |
27 | @Override
28 | public ManagedChannelBuilder> onCreated(BeanCreatedEvent> event) {
29 | final ManagedChannelBuilder> channelBuilder = event.getBean();
30 | channelBuilder.maxInboundMessageSize(1024);
31 | return channelBuilder;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/grpc-client-runtime/src/test/groovy/io/micronaut/grpc/ServerBuilderListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut.grpc;
17 |
18 | import io.grpc.ServerBuilder;
19 | import io.micronaut.context.event.BeanCreatedEvent;
20 | import io.micronaut.context.event.BeanCreatedEventListener;
21 |
22 | import jakarta.inject.Singleton;
23 |
24 | @Singleton
25 | public class ServerBuilderListener implements BeanCreatedEventListener> {
26 |
27 | @Override
28 | public ServerBuilder> onCreated(BeanCreatedEvent> event) {
29 | final ServerBuilder> builder = event.getBean();
30 | builder.maxInboundMessageSize(1024);
31 | return builder;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/grpc-client-runtime/src/test/groovy/io/micronaut/grpc/discovery/GrpcLoadBalancedServiceSpec.groovy:
--------------------------------------------------------------------------------
1 | package io.micronaut.grpc.discovery
2 |
3 | import io.grpc.ManagedChannel
4 | import io.grpc.examples.helloworld.HelloReply
5 | import io.grpc.examples.helloworld.HelloRequest
6 | import io.grpc.examples.helloworld.MultiNodeGreeterGrpc
7 | import io.grpc.stub.StreamObserver
8 | import io.micronaut.context.ApplicationContext
9 | import io.micronaut.context.annotation.Factory
10 | import io.micronaut.context.annotation.Requires
11 | import io.micronaut.context.annotation.Value
12 | import io.micronaut.core.io.socket.SocketUtils
13 | import io.micronaut.grpc.annotation.GrpcChannel
14 | import io.micronaut.runtime.server.EmbeddedServer
15 | import jakarta.inject.Singleton
16 | import spock.lang.Specification
17 |
18 | class GrpcLoadBalancedServiceSpec extends Specification {
19 |
20 | void "test GRPC named service discovery with round robin load balancing"() {
21 |
22 | given: "A service is run on multiple servers"
23 | def port1 = SocketUtils.findAvailableTcpPort()
24 | def port2 = SocketUtils.findAvailableTcpPort()
25 | def port3 = SocketUtils.findAvailableTcpPort()
26 |
27 | EmbeddedServer server1 = ApplicationContext.run(EmbeddedServer, [
28 | 'spec.name': 'GrpcLoadBalancedServiceSpec-Server',
29 | 'micronaut.application.name': 'greet',
30 | 'grpc.server.port' : port1
31 | ])
32 |
33 | EmbeddedServer server2 = ApplicationContext.run(EmbeddedServer, [
34 | 'spec.name': 'GrpcLoadBalancedServiceSpec-Server',
35 | 'micronaut.application.name': 'greet',
36 | 'grpc.server.port' : port2
37 | ])
38 |
39 | EmbeddedServer server3 = ApplicationContext.run(EmbeddedServer, [
40 | 'spec.name': 'GrpcLoadBalancedServiceSpec-Server',
41 | 'micronaut.application.name': 'greet',
42 | 'grpc.server.port' : port3
43 | ])
44 |
45 | and: 'then a client is run that declares the service'
46 | ApplicationContext client = ApplicationContext.run([
47 | 'spec.name': 'GrpcLoadBalancedServiceSpec-Client',
48 | (GrpcNameResolverProvider.ENABLED) : true,
49 | 'grpc.channels.greet.plaintext' : true,
50 | 'grpc.channels.greet.default-load-balancing-policy' : 'round_robin',
51 | 'micronaut.http.services.greet.urls[0]': server1.URL.toString(),
52 | 'micronaut.http.services.greet.urls[1]': server2.URL.toString(),
53 | 'micronaut.http.services.greet.urls[2]': server3.URL.toString()
54 | ])
55 |
56 | when: 'the service is called many times'
57 | MultiNodeGreeterGrpc.MultiNodeGreeterFutureStub stub = client.getBean(MultiNodeGreeterGrpc.MultiNodeGreeterFutureStub)
58 | Set results = new HashSet<>()
59 | for (int i=0; i<12; i++) {
60 | results.add(stub.sayHello(HelloRequest.newBuilder().setName("test").build()).get().message)
61 | }
62 |
63 | then: 'the calls are load balanced across the 3 different servers'
64 | results.size() == 3
65 |
66 | cleanup:
67 | client.stop()
68 | server1.stop()
69 | server2.stop()
70 | server3.stop()
71 | }
72 |
73 | @Requires(property = "spec.name", value = "GrpcLoadBalancedServiceSpec-Client")
74 | @Factory
75 | static class Clients {
76 | @Singleton
77 | MultiNodeGreeterGrpc.MultiNodeGreeterFutureStub futureStub(@GrpcChannel("greet") ManagedChannel channel) {
78 | MultiNodeGreeterGrpc.newFutureStub(
79 | channel
80 | )
81 | }
82 | }
83 |
84 | @Singleton
85 | @Requires(property = "spec.name", value = "GrpcLoadBalancedServiceSpec-Server")
86 | static class MultiNodeGreeterImpl extends MultiNodeGreeterGrpc.MultiNodeGreeterImplBase {
87 |
88 | @Value('${grpc.server.port}')
89 | Integer port
90 |
91 | @Override
92 | void sayHello(HelloRequest request, StreamObserver responseObserver) {
93 | HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + request.getName() + " from " + port).build()
94 | responseObserver.onNext(reply)
95 | responseObserver.onCompleted()
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/grpc-client-runtime/src/test/proto/helloworld.proto:
--------------------------------------------------------------------------------
1 | // Copyright 2015 The gRPC Authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | syntax = "proto3";
15 |
16 | option java_multiple_files = true;
17 | option java_package = "io.grpc.examples.helloworld";
18 | option java_outer_classname = "HelloWorldProto";
19 | option objc_class_prefix = "HLW";
20 |
21 | package helloworld;
22 |
23 | // The greeting service definition.
24 | service Greeter {
25 | // Sends a greeting
26 | rpc SayHello (HelloRequest) returns (HelloReply) {}
27 | }
28 |
29 | // The greeting service definition.
30 | service Greeter2 {
31 | // Sends a greeting
32 | rpc SayHello (HelloRequest) returns (HelloReply) {}
33 | }
34 |
35 | // Multi-node greeting service definition
36 | service MultiNodeGreeter {
37 | rpc SayHello (HelloRequest) returns (HelloReply) {}
38 | }
39 |
40 | // The request message containing the user's name.
41 | message HelloRequest {
42 | string name = 1;
43 | }
44 |
45 | // The response message containing the greetings
46 | message HelloReply {
47 | string message = 1;
48 | }
49 |
--------------------------------------------------------------------------------
/grpc-client-runtime/src/test/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/grpc-health/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'io.micronaut.build.internal.grpc-module'
3 | alias libs.plugins.protobuf
4 | }
5 |
6 | dependencies {
7 |
8 | api platform(libs.boms.grpc)
9 | api projects.micronautGrpcAnnotation
10 | api libs.managed.grpc.core
11 | api libs.managed.grpc.protobuf
12 | api libs.managed.grpc.stub
13 |
14 | // change these to "api" dependencies when this module
15 | // is removed as a dependency of "grpc-server-runtime"
16 | compileOnly libs.managed.grpc.services
17 | compileOnly mn.micronaut.management
18 |
19 | testImplementation libs.managed.grpc.services
20 | testImplementation mn.micronaut.management
21 | testImplementation mnReactor.micronaut.reactor.http.client
22 | testImplementation projects.micronautGrpcServerRuntime
23 | }
24 |
25 | protobuf {
26 | protoc { artifact = libs.managed.protoc.asProvider().get() }
27 | plugins {
28 | grpc { artifact = libs.managed.protoc.grpc.get() }
29 | }
30 | generateProtoTasks {
31 | all()*.plugins { grpc {} }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/grpc-health/src/main/java/io/micronaut/grpc/server/health/GrpcHealthFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2022 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut.grpc.server.health;
17 |
18 | import io.grpc.protobuf.services.HealthStatusManager;
19 | import io.micronaut.context.annotation.Factory;
20 | import io.micronaut.context.annotation.Requires;
21 | import io.micronaut.core.util.StringUtils;
22 |
23 | import jakarta.inject.Singleton;
24 |
25 | /**
26 | * @since 3.3.0
27 | */
28 | @Factory
29 | public class GrpcHealthFactory {
30 |
31 | public static final String HEALTH_ENABLED = "grpc.server.health.enabled";
32 |
33 | /**
34 | * Creates a {@link HealthStatusManager} bean if GRPC health is enabled.
35 | *
36 | * @return The Singleton{@link HealthStatusManager} bean.
37 | */
38 | @Singleton
39 | @Requires(property = GrpcHealthFactory.HEALTH_ENABLED, value = StringUtils.TRUE, defaultValue = StringUtils.TRUE)
40 | @Requires(classes = HealthStatusManager.class)
41 | public HealthStatusManager healthStatusManager() {
42 | return new HealthStatusManager();
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/grpc-health/src/main/java/io/micronaut/grpc/server/health/GrpcServerHealthIndicator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut.grpc.server.health;
17 |
18 | import java.util.Map;
19 |
20 | import io.micronaut.context.annotation.Requires;
21 | import io.micronaut.core.async.publisher.AsyncSingleResultPublisher;
22 | import io.micronaut.core.util.StringUtils;
23 | import io.micronaut.health.HealthStatus;
24 | import io.micronaut.management.endpoint.health.HealthEndpoint;
25 | import io.micronaut.management.health.indicator.HealthIndicator;
26 | import io.micronaut.management.health.indicator.HealthResult;
27 | import io.micronaut.runtime.server.EmbeddedServer;
28 |
29 | import org.reactivestreams.Publisher;
30 |
31 | import jakarta.inject.Named;
32 | import jakarta.inject.Singleton;
33 |
34 | import static io.micronaut.core.util.CollectionUtils.mapOf;
35 |
36 | /**
37 | * A {@link HealthIndicator} for Grpc server.
38 | *
39 | * @author Moe Haydar
40 | * @since 2.1.0
41 | */
42 | @Singleton
43 | @Requires(property = GrpcHealthFactory.HEALTH_ENABLED, value = StringUtils.TRUE, defaultValue = StringUtils.TRUE)
44 | @Requires(beans = HealthEndpoint.class)
45 | @Requires(beans = EmbeddedServer.class)
46 | public class GrpcServerHealthIndicator implements HealthIndicator {
47 |
48 | private static final String ID = "grpc-server";
49 |
50 | private final EmbeddedServer server;
51 |
52 | /**
53 | * Default constructor.
54 | *
55 | * @param server The grpc embedded server
56 | */
57 | public GrpcServerHealthIndicator(@Named("grpc.server") EmbeddedServer server) {
58 | this.server = server;
59 | }
60 |
61 | @Override
62 | public Publisher getResult() {
63 | return new AsyncSingleResultPublisher<>(this::getHealthResult);
64 | }
65 |
66 | /**
67 | * Checks if grpc is running and return status UP otherwise return status DOWN.
68 | *
69 | * @return Result with server address in the details and status UP or DOWN.
70 | */
71 | private HealthResult getHealthResult() {
72 | final HealthStatus healthStatus = server.isRunning() ? HealthStatus.UP : HealthStatus.DOWN;
73 | final String serverHost = server.getHost();
74 | try {
75 |
76 | int serverPort = server.getPort();
77 | final Map, ?> details = mapOf("host", serverHost, "port", serverPort);
78 |
79 | return HealthResult
80 | .builder(ID, healthStatus)
81 | .details(details)
82 | .build();
83 | } catch (IllegalStateException e) {
84 | /**
85 | * BUGFIX: it avoids to call the server.getPort() method when the gRPC-Server is DOWN because
86 | * it throws an unexpected exception that breaks the /health endpoint
87 | */
88 |
89 | final Map, ?> details = mapOf("host", serverHost, "port", "N/A");
90 | return HealthResult
91 | .builder(ID, healthStatus)
92 | .details(details)
93 | .build();
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/grpc-health/src/main/java/io/micronaut/grpc/server/health/HealthStatusManagerContainer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2022 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut.grpc.server.health;
17 |
18 | import io.grpc.protobuf.services.HealthStatusManager;
19 | import io.micronaut.context.annotation.Requires;
20 | import io.micronaut.core.util.StringUtils;
21 |
22 | import jakarta.inject.Singleton;
23 |
24 | /**
25 | * A container for the {@link HealthStatusManager}.
26 | *
27 | * @since 3.3.0
28 | */
29 | @Singleton
30 | @Requires(classes = HealthStatusManager.class)
31 | @Requires(property = GrpcHealthFactory.HEALTH_ENABLED, value = StringUtils.TRUE, defaultValue = StringUtils.TRUE)
32 | public class HealthStatusManagerContainer {
33 |
34 | private final HealthStatusManager healthStatusManager;
35 |
36 | public HealthStatusManagerContainer(HealthStatusManager healthStatusManager) {
37 | this.healthStatusManager = healthStatusManager;
38 | }
39 |
40 | /**
41 | * @return The {@link HealthStatusManager}
42 | */
43 | public HealthStatusManager getHealthStatusManager() {
44 | return healthStatusManager;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/grpc-health/src/test/groovy/io/micronaut/grpc/server/health/GrpcServerHealthIndicatorSpec.groovy:
--------------------------------------------------------------------------------
1 | package io.micronaut.grpc.server.health
2 |
3 | import io.micronaut.context.ApplicationContext
4 | import io.micronaut.core.io.socket.SocketUtils
5 | import io.micronaut.core.util.CollectionUtils
6 | import io.micronaut.grpc.server.GrpcEmbeddedServer
7 | import io.micronaut.health.HealthStatus
8 | import io.micronaut.management.health.indicator.HealthResult
9 | import reactor.core.publisher.Mono
10 | import spock.lang.Specification
11 | import spock.lang.Unroll
12 |
13 | class GrpcServerHealthIndicatorSpec extends Specification {
14 | void "test grpc health indicator - UP"() {
15 | def port = SocketUtils.findAvailableTcpPort()
16 |
17 | given:
18 | GrpcEmbeddedServer server = ApplicationContext.run(GrpcEmbeddedServer, ["grpc.server.port": port])
19 |
20 | when:
21 | GrpcServerHealthIndicator healthIndicator = server.getApplicationContext().getBean(GrpcServerHealthIndicator)
22 | HealthResult result = Mono.from(healthIndicator.result).block()
23 |
24 | then:
25 | result.status == HealthStatus.UP
26 | result.details.port == port
27 | result.details.host == "localhost"
28 |
29 | cleanup:
30 | server.close()
31 | }
32 |
33 | @Unroll
34 | void "test grpc health indicator - Disabled #configvalue"() {
35 | given:
36 | GrpcEmbeddedServer server = ApplicationContext.run(GrpcEmbeddedServer, CollectionUtils.mapOf(
37 | "grpc.server.health.enabled", configvalue))
38 |
39 | when:
40 | def optional = server.getApplicationContext().findBean(GrpcServerHealthIndicator)
41 |
42 | then:
43 | !optional.isPresent()
44 |
45 | cleanup:
46 | server.stop()
47 |
48 | where:
49 | configvalue << [false, "false", "no", ""]
50 | }
51 |
52 | void "test grpc health indicator after gRPC-Server is stopped"() {
53 |
54 | given:
55 | GrpcEmbeddedServer server = ApplicationContext.run(GrpcEmbeddedServer)
56 |
57 | when:
58 | server.stop()
59 |
60 | and:
61 | GrpcServerHealthIndicator healthIndicator = server.getApplicationContext().getBean(GrpcServerHealthIndicator)
62 | HealthResult result = Mono.from(healthIndicator.result).block()
63 |
64 | then:
65 | result.status == HealthStatus.DOWN
66 | result.details.port == "N/A"
67 | result.details.host == server.host
68 |
69 | cleanup:
70 | server.close()
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/grpc-opentracing/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'io.micronaut.build.internal.grpc-module'
3 | alias libs.plugins.protobuf
4 | }
5 |
6 | dependencies {
7 |
8 | api platform(libs.boms.grpc)
9 | api projects.micronautGrpcAnnotation
10 | api libs.managed.grpc.core
11 | api libs.managed.grpc.protobuf
12 | api libs.managed.grpc.stub
13 |
14 | // change these to "api" dependencies when this module
15 | // is removed as a dependency of "grpc-server-runtime"
16 | compileOnly libs.managed.grpc.services
17 | compileOnly libs.micronaut.tracing.legacy
18 | compileOnly mn.micronaut.management
19 | compileOnly libs.opentracing.grpc
20 | compileOnly libs.javax.annotation.api
21 |
22 | testCompileOnly libs.javax.annotation.api
23 | testCompileOnly libs.managed.protobuf.java
24 |
25 | testImplementation projects.micronautGrpcServerRuntime
26 | testImplementation libs.managed.grpc.services
27 | testImplementation libs.opentracing.mock
28 | testImplementation libs.micronaut.tracing.legacy
29 | testImplementation libs.opentracing.grpc
30 | testImplementation libs.jaeger.core
31 | testImplementation mnReactor.micronaut.reactor.http.client
32 | testImplementation mn.micronaut.management
33 | }
34 |
35 | protobuf {
36 | protoc { artifact = libs.managed.protoc.asProvider().get() }
37 | plugins {
38 | grpc { artifact = libs.managed.protoc.grpc.get() }
39 | }
40 | generateProtoTasks {
41 | all()*.plugins { grpc {} }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/grpc-opentracing/src/main/java/io/micronaut/grpc/client/tracing/GrpcClientTracingInterceptorConfiguration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut.grpc.client.tracing;
17 |
18 | import io.micronaut.context.annotation.ConfigurationBuilder;
19 | import io.micronaut.context.annotation.ConfigurationProperties;
20 | import io.micronaut.core.annotation.NonNull;
21 | import io.micronaut.core.annotation.Nullable;
22 | import io.opentracing.Tracer;
23 | import io.opentracing.contrib.grpc.ClientCloseDecorator;
24 | import io.opentracing.contrib.grpc.ClientSpanDecorator;
25 | import io.opentracing.contrib.grpc.TracingClientInterceptor;
26 |
27 | import jakarta.inject.Inject;
28 |
29 | /**
30 | * Adds a {@link TracingClientInterceptor} when OpenTracing for GRPC is on the classpath
31 | * and allows integration with Zipkin and Jaeger.
32 | *
33 | * @author graemerocher
34 | * @since 1.0
35 | */
36 | @ConfigurationProperties(GrpcClientTracingInterceptorConfiguration.PREFIX)
37 | public class GrpcClientTracingInterceptorConfiguration {
38 |
39 | public static final String PREFIX = "grpc.client.tracing";
40 |
41 | @ConfigurationBuilder(prefixes = "with", allowZeroArgs = true)
42 | protected final TracingClientInterceptor.Builder builder;
43 |
44 | /**
45 | * Default constructor.
46 | *
47 | * @param tracer The tracer
48 | */
49 | protected GrpcClientTracingInterceptorConfiguration(Tracer tracer) {
50 | this.builder = TracingClientInterceptor.newBuilder().withTracer(tracer);
51 | }
52 |
53 | /**
54 | * @return The {@link TracingClientInterceptor.Builder}
55 | */
56 | public @NonNull TracingClientInterceptor.Builder getBuilder() {
57 | return builder;
58 | }
59 |
60 | /**
61 | * Decorates the server span with custom data.
62 | *
63 | * @param clientSpanDecorator used to decorate the server span
64 | */
65 | @Inject
66 | public void setClientSpanDecorator(@Nullable ClientSpanDecorator clientSpanDecorator) {
67 | if (clientSpanDecorator != null) {
68 | builder.withClientSpanDecorator(clientSpanDecorator);
69 | }
70 | }
71 |
72 | /**
73 | * Decorates the server span with custom data when the gRPC call is closed.
74 | *
75 | * @param clientCloseDecorator used to decorate the server span
76 | */
77 | @Inject
78 | public void setClientCloseDecorator(@Nullable ClientCloseDecorator clientCloseDecorator) {
79 | if (clientCloseDecorator != null) {
80 | builder.withClientCloseDecorator(clientCloseDecorator);
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/grpc-opentracing/src/main/java/io/micronaut/grpc/client/tracing/GrpcClientTracingInterceptorFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut.grpc.client.tracing;
17 |
18 | import io.grpc.ClientInterceptor;
19 | import io.micronaut.context.annotation.Bean;
20 | import io.micronaut.context.annotation.Factory;
21 | import io.micronaut.context.annotation.Requires;
22 | import io.micronaut.core.annotation.NonNull;
23 |
24 | import jakarta.inject.Singleton;
25 |
26 | /**
27 | * Factory that builds the Tracing interceptors.
28 | *
29 | * @author graemerocher
30 | * @since 1.0
31 | */
32 | @Factory
33 | public class GrpcClientTracingInterceptorFactory {
34 |
35 | /**
36 | * The client interceptor.
37 | *
38 | * @param configuration The configuration
39 | *
40 | * @return The client interceptor
41 | */
42 | @Requires(beans = GrpcClientTracingInterceptorConfiguration.class)
43 | @Singleton
44 | @Bean
45 | protected @NonNull ClientInterceptor clientTracingInterceptor(@NonNull GrpcClientTracingInterceptorConfiguration configuration) {
46 | return configuration.getBuilder().build();
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/grpc-opentracing/src/main/java/io/micronaut/grpc/client/tracing/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | /**
17 | * Classes related to distributed tracing.
18 | */
19 | @Configuration
20 | @Requires(classes = {Tracer.class, TracingClientInterceptor.class})
21 | @Requires(beans = Tracer.class)
22 | package io.micronaut.grpc.client.tracing;
23 |
24 | import io.micronaut.context.annotation.Configuration;
25 | import io.micronaut.context.annotation.Requires;
26 | import io.opentracing.Tracer;
27 | import io.opentracing.contrib.grpc.TracingClientInterceptor;
28 |
--------------------------------------------------------------------------------
/grpc-opentracing/src/main/java/io/micronaut/grpc/server/tracing/GrpcServerTracingInterceptorConfiguration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut.grpc.server.tracing;
17 |
18 | import io.micronaut.context.annotation.ConfigurationBuilder;
19 | import io.micronaut.context.annotation.ConfigurationProperties;
20 | import io.micronaut.core.annotation.NonNull;
21 | import io.micronaut.core.annotation.Nullable;
22 | import io.opentracing.Tracer;
23 | import io.opentracing.contrib.grpc.ServerCloseDecorator;
24 | import io.opentracing.contrib.grpc.ServerSpanDecorator;
25 | import io.opentracing.contrib.grpc.TracingServerInterceptor;
26 |
27 | import jakarta.inject.Inject;
28 |
29 | /**
30 | * Adds a {@link TracingServerInterceptor} when OpenTracing for GRPC is on the classpath
31 | * and allows integration with Zipkin and Jaeger.
32 | *
33 | * @author graemerocher
34 | * @since 1.0
35 | */
36 | @ConfigurationProperties(GrpcServerTracingInterceptorConfiguration.PREFIX)
37 | public class GrpcServerTracingInterceptorConfiguration {
38 |
39 | public static final String PREFIX = "grpc.server.tracing";
40 |
41 | @ConfigurationBuilder(prefixes = "with", allowZeroArgs = true)
42 | protected final TracingServerInterceptor.Builder builder;
43 |
44 | /**
45 | * Default constructor.
46 | *
47 | * @param tracer The tracer
48 | */
49 | protected GrpcServerTracingInterceptorConfiguration(Tracer tracer) {
50 | this.builder = TracingServerInterceptor.newBuilder().withTracer(tracer);
51 | }
52 |
53 | /**
54 | * @return The {@link TracingServerInterceptor.Builder}
55 | */
56 | public @NonNull TracingServerInterceptor.Builder getBuilder() {
57 | return builder;
58 | }
59 |
60 | /**
61 | * Decorates the server span with custom data.
62 | *
63 | * @param serverSpanDecorator used to decorate the server span
64 | */
65 | @Inject
66 | public void setServerSpanDecorator(@Nullable ServerSpanDecorator serverSpanDecorator) {
67 | if (serverSpanDecorator != null) {
68 | builder.withServerSpanDecorator(serverSpanDecorator);
69 | }
70 | }
71 |
72 | /**
73 | * Decorates the server span with custom data when the gRPC call is closed.
74 | *
75 | * @param serverCloseDecorator used to decorate the server span
76 | */
77 | @Inject
78 | public void setServerCloseDecorator(@Nullable ServerCloseDecorator serverCloseDecorator) {
79 | if (serverCloseDecorator != null) {
80 | builder.withServerCloseDecorator(serverCloseDecorator);
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/grpc-opentracing/src/main/java/io/micronaut/grpc/server/tracing/GrpcServerTracingInterceptorFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut.grpc.server.tracing;
17 |
18 | import io.grpc.ServerInterceptor;
19 | import io.micronaut.context.annotation.Bean;
20 | import io.micronaut.context.annotation.Factory;
21 | import io.micronaut.context.annotation.Requires;
22 | import io.micronaut.core.annotation.NonNull;
23 |
24 | import jakarta.inject.Singleton;
25 |
26 | /**
27 | * Factory that builds the Tracing interceptors.
28 | *
29 | * @author graemerocher
30 | * @since 1.0
31 | */
32 | @Factory
33 | public class GrpcServerTracingInterceptorFactory {
34 |
35 | /**
36 | * The server interceptor.
37 | *
38 | * @param configuration The configuration
39 | *
40 | * @return The server interceptor
41 | */
42 | @Requires(beans = GrpcServerTracingInterceptorConfiguration.class)
43 | @Singleton
44 | @Bean
45 | protected @NonNull ServerInterceptor serverTracingInterceptor(@NonNull GrpcServerTracingInterceptorConfiguration configuration) {
46 | return configuration.getBuilder().build();
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/grpc-opentracing/src/main/java/io/micronaut/grpc/server/tracing/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | /**
17 | * Classes related to distributed tracing.
18 | */
19 | @Configuration
20 | @Requires(classes = {Tracer.class, TracingClientInterceptor.class, TracingServerInterceptor.class})
21 | @Requires(beans = Tracer.class)
22 | package io.micronaut.grpc.server.tracing;
23 |
24 | import io.micronaut.context.annotation.Configuration;
25 | import io.micronaut.context.annotation.Requires;
26 | import io.opentracing.Tracer;
27 | import io.opentracing.contrib.grpc.TracingClientInterceptor;
28 | import io.opentracing.contrib.grpc.TracingServerInterceptor;
29 |
--------------------------------------------------------------------------------
/grpc-opentracing/src/test/groovy/io/micronaut/grpc/server/tracing/GrpcTracingSpec.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut.grpc.server.tracing
17 |
18 | import io.grpc.Channel
19 | import io.grpc.Metadata
20 | import io.grpc.ServerCall
21 | import io.grpc.ServerCallHandler
22 | import io.grpc.ServerInterceptor
23 | import io.grpc.examples.helloworld.GreeterGrpc
24 | import io.grpc.examples.helloworld.HelloReply
25 | import io.grpc.examples.helloworld.HelloRequest
26 | import io.grpc.stub.StreamObserver
27 | import io.micronaut.context.annotation.Factory
28 | import io.micronaut.context.annotation.Property
29 | import io.micronaut.context.annotation.Requires
30 | import io.micronaut.grpc.annotation.GrpcChannel
31 | import io.micronaut.grpc.server.GrpcServerChannel
32 | import io.micronaut.test.annotation.MockBean
33 | import io.micronaut.test.extensions.spock.annotation.MicronautTest
34 | import io.opentracing.Tracer
35 | import io.opentracing.mock.MockTracer
36 | import jakarta.inject.Inject
37 | import jakarta.inject.Singleton
38 | import spock.lang.Specification
39 | import spock.util.concurrent.PollingConditions
40 |
41 | @MicronautTest
42 | @Property(name = 'mock.tracer', value = 'true')
43 | class GrpcTracingSpec extends Specification {
44 |
45 | @Inject
46 | TestBean testBean
47 |
48 | @Inject
49 | TracingInterceptor myInterceptor
50 |
51 | @Inject
52 | Tracer tracer
53 |
54 | MockTracer mockTracer = new MockTracer()
55 |
56 | void "test hello world grpc with tracing enabled"() {
57 | given:
58 | MockTracer tracer = mockTracer
59 | PollingConditions conditions = new PollingConditions(timeout: 3, delay: 0.5)
60 | testBean.sayHello("Fred") == "Hello Fred"
61 |
62 | expect:
63 | conditions.eventually {
64 | myInterceptor.intercepted
65 | tracer.finishedSpans().size() == 2
66 | tracer.finishedSpans()[0].operationName() == 'helloworld.Greeter/SayHello'
67 | tracer.finishedSpans()[1].operationName() == 'helloworld.Greeter/SayHello'
68 | tracer.finishedSpans().find { it.tags().get('span.kind') == 'client' }
69 | tracer.finishedSpans().find { it.tags().get('span.kind') == 'server' }
70 | }
71 | }
72 |
73 | @Singleton
74 | static class TracingInterceptor implements ServerInterceptor {
75 |
76 | boolean intercepted = false
77 |
78 | @Override
79 | ServerCall.Listener interceptCall(ServerCall call, Metadata headers, ServerCallHandler next) {
80 | intercepted = true
81 | return next.startCall(call, headers)
82 | }
83 | }
84 |
85 | @MockBean
86 | @Requires(property = "mock.tracer", value = "true")
87 | Tracer tracer() {
88 | return mockTracer
89 | }
90 |
91 | @Factory
92 | static class Clients {
93 | @Singleton
94 | GreeterGrpc.GreeterBlockingStub blockingStub(@GrpcChannel(GrpcServerChannel.NAME) Channel channel) {
95 | GreeterGrpc.newBlockingStub(channel)
96 | }
97 | }
98 |
99 | @Singleton
100 | static class TestBean {
101 | @Inject
102 | GreeterGrpc.GreeterBlockingStub blockingStub
103 |
104 | String sayHello(String message) {
105 | blockingStub.sayHello(
106 | HelloRequest.newBuilder().setName(message).build()
107 | ).message
108 | }
109 | }
110 |
111 | @Singleton
112 | static class GreeterService extends GreeterGrpc.GreeterImplBase {
113 | @Override
114 | void sayHello(HelloRequest request, StreamObserver responseObserver) {
115 | HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + request.getName()).build()
116 | responseObserver.onNext(reply)
117 | responseObserver.onCompleted()
118 | }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/grpc-opentracing/src/test/proto/helloworld.proto:
--------------------------------------------------------------------------------
1 | // Copyright 2015 The gRPC Authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | syntax = "proto3";
15 |
16 | option java_multiple_files = true;
17 | option java_package = "io.grpc.examples.helloworld";
18 | option java_outer_classname = "HelloWorldProto";
19 | option objc_class_prefix = "HLW";
20 |
21 | package helloworld;
22 |
23 | // The greeting service definition.
24 | service Greeter {
25 | // Sends a greeting
26 | rpc SayHello (HelloRequest) returns (HelloReply) {}
27 | }
28 |
29 | // The greeting service definition.
30 | service Greeter2 {
31 | // Sends a greeting
32 | rpc SayHello (HelloRequest) returns (HelloReply) {}
33 | }
34 |
35 | // The request message containing the user's name.
36 | message HelloRequest {
37 | string name = 1;
38 | }
39 |
40 | // The response message containing the greetings
41 | message HelloReply {
42 | string message = 1;
43 | }
--------------------------------------------------------------------------------
/grpc-runtime/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'io.micronaut.build.internal.grpc-module'
3 | }
4 |
5 | dependencies {
6 | api projects.micronautGrpcClientRuntime
7 | api projects.micronautGrpcServerRuntime
8 | }
9 |
--------------------------------------------------------------------------------
/grpc-server-runtime/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'io.micronaut.build.internal.grpc-module'
3 | alias libs.plugins.protobuf
4 | }
5 |
6 | dependencies {
7 |
8 | api platform(libs.boms.grpc)
9 | api projects.micronautGrpcAnnotation
10 | api projects.micronautGrpcHealth
11 | api projects.micronautGrpcOpentracing
12 | api libs.managed.grpc.core
13 | api libs.managed.grpc.protobuf
14 | api libs.managed.grpc.stub
15 |
16 | compileOnly libs.managed.grpc.services
17 | compileOnly mn.micronaut.management
18 | compileOnly libs.graal.svm
19 |
20 | implementation libs.grpc.netty
21 | implementation mn.micronaut.buffer.netty
22 | implementation mn.micronaut.discovery.core
23 |
24 | testCompileOnly libs.javax.annotation.api
25 | testCompileOnly libs.managed.protobuf.java
26 |
27 | testImplementation libs.managed.grpc.services
28 | testImplementation mn.micronaut.discovery.core
29 | testImplementation mnReactor.micronaut.reactor.http.client
30 | testImplementation mn.micronaut.management
31 | testImplementation projects.micronautGrpcClientRuntime
32 |
33 | testRuntimeOnly libs.netty.tcnative.boringssl.static
34 | }
35 |
36 | sourceSets {
37 | test {
38 | java {
39 | srcDirs 'build/generated/source/proto/test/grpc'
40 | srcDirs 'build/generated/source/proto/test/java'
41 | }
42 | }
43 | }
44 |
45 | protobuf {
46 | protoc { artifact = libs.managed.protoc.asProvider().get() }
47 | plugins {
48 | grpc { artifact = libs.managed.protoc.grpc.get() }
49 | }
50 | generateProtoTasks {
51 | all()*.plugins { grpc {} }
52 | }
53 | }
54 |
55 | micronautBuild {
56 | binaryCompatibility {
57 | acceptedRegressionsFile = file("config/accepted-api-changes.json")
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/grpc-server-runtime/src/main/java/io/micronaut/grpc/server/GrpcEmbeddedServerListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut.grpc.server;
17 |
18 | import io.micronaut.context.BeanContext;
19 | import io.micronaut.context.annotation.Requires;
20 | import io.micronaut.core.annotation.Internal;
21 | import io.micronaut.runtime.event.annotation.EventListener;
22 | import io.micronaut.runtime.server.EmbeddedServer;
23 | import io.micronaut.runtime.server.event.ServerShutdownEvent;
24 | import io.micronaut.runtime.server.event.ServerStartupEvent;
25 |
26 | import jakarta.annotation.PreDestroy;
27 | import org.slf4j.Logger;
28 | import org.slf4j.LoggerFactory;
29 |
30 | import jakarta.inject.Singleton;
31 |
32 | /**
33 | * Application event listener that will start up the {@link GrpcEmbeddedServer} as a secondary server
34 | * on a different port allowing Micronaut's HTTP server and GRPC to run side by side.
35 | *
36 | * @author graemerocher
37 | * @since 1.0
38 | */
39 | @Internal
40 | @Singleton
41 | @Requires(beans = GrpcEmbeddedServer.class)
42 | class GrpcEmbeddedServerListener implements AutoCloseable{
43 |
44 | private static final Logger LOG = LoggerFactory.getLogger(GrpcEmbeddedServerListener.class);
45 |
46 | private final BeanContext beanContext;
47 | private GrpcEmbeddedServer grpcServer;
48 |
49 | /**
50 | * Default constructor.
51 | *
52 | * @param beanContext The bean context
53 | */
54 | GrpcEmbeddedServerListener(BeanContext beanContext) {
55 | this.beanContext = beanContext;
56 | }
57 |
58 | @EventListener
59 | public void onServerStartupEvent(ServerStartupEvent event) {
60 | final EmbeddedServer server = event.getSource();
61 | if (!(server instanceof GrpcEmbeddedServer)) {
62 | this.grpcServer = beanContext.getBean(GrpcEmbeddedServer.class);
63 | grpcServer.start();
64 | if (LOG.isInfoEnabled()) {
65 | LOG.info("GRPC started on port {}", grpcServer.getPort());
66 | }
67 | }
68 | }
69 |
70 | @EventListener
71 | public void onServerShutdownEvent(ServerShutdownEvent event) {
72 | final EmbeddedServer server = event.getSource();
73 | if (!(server instanceof GrpcEmbeddedServer)) {
74 | this.close();
75 | }
76 | }
77 |
78 | @Override
79 | @PreDestroy
80 | public void close() {
81 | if (grpcServer != null && grpcServer.isRunning()) {
82 | grpcServer.stop();
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/grpc-server-runtime/src/main/java/io/micronaut/grpc/server/GrpcServerChannel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut.grpc.server;
17 |
18 | import java.util.Collections;
19 | import java.util.List;
20 | import java.util.concurrent.ExecutorService;
21 |
22 | import io.grpc.ClientInterceptor;
23 | import io.grpc.ManagedChannel;
24 | import io.grpc.ManagedChannelBuilder;
25 | import io.micronaut.context.annotation.Bean;
26 | import io.micronaut.context.annotation.Factory;
27 | import io.micronaut.context.annotation.Requires;
28 | import io.micronaut.core.util.CollectionUtils;
29 | import io.micronaut.scheduling.TaskExecutors;
30 |
31 | import jakarta.inject.Named;
32 | import jakarta.inject.Singleton;
33 |
34 | /**
35 | * A factory that returns a {@link ManagedChannel} allowing communication with the embedded server.
36 | * Primarily used for testing.
37 | *
38 | * @author graemerocher
39 | * @since 1.0
40 | */
41 | @Factory
42 | public class GrpcServerChannel {
43 |
44 | public static final String NAME = "grpc-server";
45 |
46 | /**
47 | * Constructs a managed server channel.
48 | *
49 | * @param server The server
50 | * @param executorService The executor service
51 | * @param clientInterceptors The client interceptors
52 | *
53 | * @return The channel
54 | */
55 | @Singleton
56 | @Named(NAME)
57 | @Requires(beans = GrpcEmbeddedServer.class)
58 | @Bean(preDestroy = "shutdown")
59 | protected ManagedChannel serverChannel(
60 | GrpcEmbeddedServer server,
61 | @Named(TaskExecutors.IO) ExecutorService executorService,
62 | List clientInterceptors) {
63 | final ManagedChannelBuilder> builder = ManagedChannelBuilder.forAddress(
64 | server.getHost(),
65 | server.getPort()
66 | ).executor(executorService);
67 | if (!server.getServerConfiguration().isSecure()) {
68 | builder.usePlaintext();
69 | }
70 | if (CollectionUtils.isNotEmpty(clientInterceptors)) {
71 | Collections.reverse(clientInterceptors);
72 | builder.intercept(clientInterceptors);
73 | }
74 | return builder.build();
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/grpc-server-runtime/src/main/java/io/micronaut/grpc/server/GrpcServerInstance.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut.grpc.server;
17 |
18 | import java.net.URI;
19 | import java.util.LinkedHashMap;
20 | import java.util.List;
21 | import java.util.Map;
22 |
23 | import io.micronaut.core.annotation.Nullable;
24 | import io.micronaut.core.convert.value.ConvertibleValues;
25 | import io.micronaut.core.util.CollectionUtils;
26 | import io.micronaut.core.util.StringUtils;
27 | import io.micronaut.discovery.EmbeddedServerInstance;
28 | import io.micronaut.discovery.metadata.ServiceInstanceMetadataContributor;
29 | import io.micronaut.runtime.server.EmbeddedServer;
30 |
31 | /**
32 | * Implementation of the {@link EmbeddedServerInstance} interface for GRPC.
33 | *
34 | * @author graemerocher
35 | * @author Iván López
36 | * @since 1.0
37 | */
38 | class GrpcServerInstance implements EmbeddedServerInstance {
39 |
40 | private final String id;
41 | private final URI uri;
42 | private final ConvertibleValues metadata;
43 | private final EmbeddedServer embeddedServer;
44 |
45 | /**
46 | * Default constructor.
47 | *
48 | * @param embeddedServer The embedded server
49 | * @param id The ID
50 | * @param uri The URI
51 | * @param metadata The metadata
52 | * @param metadataContributors The metadata contributors
53 | * @param grpcConfiguration The GRPC Configuration
54 | */
55 | GrpcServerInstance(
56 | EmbeddedServer embeddedServer,
57 | String id,
58 | URI uri,
59 | @Nullable Map metadata,
60 | @Nullable List metadataContributors,
61 | GrpcServerConfiguration grpcConfiguration) {
62 | this.embeddedServer = embeddedServer;
63 | this.id = calculateInstanceId(id, grpcConfiguration);
64 | this.uri = uri;
65 | if (metadata == null) {
66 | metadata = new LinkedHashMap<>(5);
67 | }
68 |
69 | if (CollectionUtils.isNotEmpty(metadataContributors)) {
70 | for (ServiceInstanceMetadataContributor contributor : metadataContributors) {
71 | contributor.contribute(this, metadata);
72 | }
73 | }
74 |
75 | this.metadata = ConvertibleValues.of(metadata);
76 | }
77 |
78 | @Override
79 | public String getId() {
80 | return id;
81 | }
82 |
83 | @Override
84 | public URI getURI() {
85 | return uri;
86 | }
87 |
88 | @Override
89 | public ConvertibleValues getMetadata() {
90 | return metadata;
91 | }
92 |
93 | @Override
94 | public EmbeddedServer getEmbeddedServer() {
95 | return embeddedServer;
96 | }
97 |
98 | private String calculateInstanceId(String id, @Nullable GrpcServerConfiguration grpcConfiguration) {
99 | if (grpcConfiguration != null && StringUtils.isNotEmpty(grpcConfiguration.getInstanceId())) {
100 | return grpcConfiguration.getInstanceId();
101 | } else {
102 | return id;
103 | }
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/grpc-server-runtime/src/main/java/io/micronaut/grpc/server/GrpcSslConfiguration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut.grpc.server;
17 |
18 | import java.util.Optional;
19 |
20 | import io.micronaut.context.annotation.ConfigurationProperties;
21 | import io.micronaut.core.annotation.Nullable;
22 |
23 | /**
24 | * Configuration for the SSL properties of GRPC.
25 | *
26 | * @author graemerocher
27 | * @since 1.0
28 | */
29 | @ConfigurationProperties(GrpcServerConfiguration.PREFIX + ".ssl")
30 | public class GrpcSslConfiguration {
31 |
32 | private String certChain;
33 |
34 | private String privateKey;
35 |
36 | /**
37 | * @return The cert chain
38 | */
39 | public Optional getCertChain() {
40 | return Optional.ofNullable(certChain);
41 | }
42 |
43 | /**
44 | * @param certChain Sets the cert chain
45 | */
46 | public void setCertChain(@Nullable String certChain) {
47 | this.certChain = certChain;
48 | }
49 |
50 | /**
51 | * @return The private key
52 | */
53 | public Optional getPrivateKey() {
54 | return Optional.ofNullable(privateKey);
55 | }
56 |
57 | /**
58 | * @param privateKey Sets the private key
59 | */
60 | public void setPrivateKey(@Nullable String privateKey) {
61 | this.privateKey = privateKey;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/grpc-server-runtime/src/main/java/io/micronaut/grpc/server/interceptor/OrderedServerInterceptor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2020 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut.grpc.server.interceptor;
17 |
18 | import io.grpc.Metadata;
19 | import io.grpc.ServerCall;
20 | import io.grpc.ServerCallHandler;
21 | import io.grpc.ServerInterceptor;
22 | import io.micronaut.core.order.Ordered;
23 |
24 | /**
25 | * A {@link ServerInterceptor} implementation which allows ordering and simply passes all
26 | * calls to a delegate interceptor.
27 | *
28 | * @author brianwyka
29 | * @since 2.0.2
30 | */
31 | public class OrderedServerInterceptor implements ServerInterceptor, Ordered {
32 |
33 | private final ServerInterceptor delegate;
34 | private final int order;
35 |
36 | /**
37 | * Constructs an instance of this interceptor with the provided delegate interceptor and order.
38 | *
39 | * @param delegate the interceptor to delegate to
40 | * @param order the order number
41 | */
42 | public OrderedServerInterceptor(final ServerInterceptor delegate, final int order) {
43 | this.delegate = delegate;
44 | this.order = order;
45 | }
46 |
47 | /**
48 | * Delegates interceptor logic to {@link #delegate} interceptor.
49 | *
50 | * {@inheritDoc}
51 | */
52 | @Override
53 | public ServerCall.Listener interceptCall(final ServerCall call, final Metadata headers, final ServerCallHandler next) {
54 | return delegate.interceptCall(call, headers, next);
55 | }
56 |
57 | /**
58 | * Get the order in which this interceptor should execute in the interceptor chain.
59 | *
60 | * @return the order
61 | */
62 | @Override
63 | public int getOrder() {
64 | return order;
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/grpc-server-runtime/src/main/java/io/micronaut/grpc/server/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | /**
17 | * Classes related to the GRPC server.
18 | */
19 | package io.micronaut.grpc.server;
20 |
--------------------------------------------------------------------------------
/grpc-server-runtime/src/test/groovy/io/micronaut/grpc/GrpcNamedChannelSpec.groovy:
--------------------------------------------------------------------------------
1 | package io.micronaut.grpc
2 |
3 | import io.grpc.Channel
4 | import io.grpc.examples.helloworld.Greeter2Grpc
5 | import io.grpc.examples.helloworld.HelloReply
6 | import io.grpc.examples.helloworld.HelloRequest
7 | import io.grpc.stub.StreamObserver
8 | import io.micronaut.context.ApplicationContext
9 | import io.micronaut.context.annotation.Factory
10 | import io.micronaut.core.io.socket.SocketUtils
11 | import io.micronaut.grpc.annotation.GrpcChannel
12 | import io.micronaut.grpc.channels.GrpcManagedChannelConfiguration
13 | import io.micronaut.inject.qualifiers.Qualifiers
14 | import io.micronaut.runtime.server.EmbeddedServer
15 | import jakarta.inject.Inject
16 | import jakarta.inject.Singleton
17 | import spock.lang.Retry
18 | import spock.lang.Specification
19 |
20 | class GrpcNamedChannelSpec extends Specification {
21 |
22 | // retry because on Cloud CI you may have a race condition regarding port availability and binding
23 | @Retry
24 | void "test named client"() {
25 | given:
26 | def port = SocketUtils.findAvailableTcpPort()
27 | EmbeddedServer embeddedServer = ApplicationContext.run(EmbeddedServer, [
28 | 'grpc.server.port' : port,
29 | 'grpc.channels.greeter.address' : "localhost:$port",
30 | 'grpc.channels.greeter.plaintext': true
31 | ])
32 | def context = embeddedServer.getApplicationContext()
33 | def testBean = context.getBean(TestBean)
34 | def config = context.getBean(GrpcManagedChannelConfiguration, Qualifiers.byName("greeter"))
35 | def channel = testBean.blockingStub.channel
36 |
37 | expect:
38 | channel != null
39 |
40 | testBean.sayHello("Fred") == "Hello 2 Fred"
41 | config.name == 'greeter'
42 |
43 | cleanup:
44 | embeddedServer.close()
45 | }
46 |
47 | @Singleton
48 | static class TestBean {
49 | @Inject
50 | Greeter2Grpc.Greeter2BlockingStub blockingStub
51 |
52 | String sayHello(String message) {
53 | blockingStub.sayHello(
54 | HelloRequest.newBuilder().setName(message).build()
55 | ).message
56 | }
57 | }
58 |
59 |
60 | @Factory
61 | static class Clients {
62 | @Singleton
63 | Greeter2Grpc.Greeter2BlockingStub blockingStub(@GrpcChannel("greeter") Channel channel) {
64 | Greeter2Grpc.newBlockingStub(channel)
65 | }
66 | }
67 |
68 | @Singleton
69 | static class GreeterImpl extends Greeter2Grpc.Greeter2ImplBase {
70 | @Override
71 | void sayHello(HelloRequest request, StreamObserver responseObserver) {
72 | HelloReply reply = HelloReply.newBuilder().setMessage("Hello 2 " + request.getName()).build()
73 | responseObserver.onNext(reply)
74 | responseObserver.onCompleted()
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/grpc-server-runtime/src/test/groovy/io/micronaut/grpc/GrpcServerConfigurationSpec.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut.grpc
17 |
18 | import io.grpc.ServerBuilder
19 | import io.micronaut.context.ApplicationContext
20 | import io.micronaut.core.io.socket.SocketUtils
21 | import io.micronaut.grpc.server.GrpcServerConfiguration
22 | import io.micronaut.test.extensions.spock.annotation.MicronautTest
23 | import spock.lang.Specification
24 |
25 | @MicronautTest
26 | class GrpcServerConfigurationSpec extends Specification {
27 |
28 | void "test GRPC configuration"() {
29 | given:
30 | def port = SocketUtils.findAvailableTcpPort()
31 | def ctx = ApplicationContext.run([
32 | 'grpc.server.port' : port,
33 | 'grpc.server.handshake-timeout': '11s',
34 | 'grpc.server.instance-id' : 'hello-grpc'
35 | ])
36 |
37 | GrpcServerConfiguration configuration = ctx.getBean(GrpcServerConfiguration)
38 | ServerBuilder serverBuilder = configuration.getServerBuilder()
39 | def server = serverBuilder.build()
40 | server.start()
41 |
42 | expect:
43 | serverBuilder != null
44 | server.getPort() == port
45 | configuration.instanceId == 'hello-grpc'
46 |
47 | cleanup:
48 | server.shutdown().awaitTermination()
49 | ctx.close()
50 | }
51 |
52 | void "test GRPC SSL configuration"() {
53 | given:
54 | def port = SocketUtils.findAvailableTcpPort()
55 | def ctx = ApplicationContext.run([
56 | 'grpc.server.port' : port,
57 | 'grpc.server.ssl.cert-chain' : 'classpath:example.crt',
58 | 'grpc.server.ssl.private-key': 'classpath:example.key',
59 | ])
60 |
61 | when:
62 | GrpcServerConfiguration configuration = ctx.getBean(GrpcServerConfiguration)
63 | ServerBuilder serverBuilder = configuration.getServerBuilder()
64 | def server = serverBuilder.build()
65 | server.start()
66 |
67 | then:
68 | noExceptionThrown()
69 |
70 | cleanup:
71 | server.shutdown().awaitTermination()
72 | ctx.close()
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/grpc-server-runtime/src/test/groovy/io/micronaut/grpc/HelloWordGrpcSpec.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut.grpc
17 |
18 |
19 | import io.grpc.Channel
20 | import io.grpc.Metadata
21 | import io.grpc.ServerCall
22 | import io.grpc.ServerCallHandler
23 | import io.grpc.ServerInterceptor
24 | import io.grpc.examples.helloworld.GreeterGrpc
25 | import io.grpc.examples.helloworld.HelloReply
26 | import io.grpc.examples.helloworld.HelloRequest
27 | import io.grpc.stub.StreamObserver
28 | import io.micronaut.context.annotation.Factory
29 | import io.micronaut.grpc.annotation.GrpcChannel
30 | import io.micronaut.grpc.server.GrpcServerChannel
31 | import io.micronaut.test.extensions.spock.annotation.MicronautTest
32 | import jakarta.inject.Inject
33 | import jakarta.inject.Singleton
34 | import spock.lang.Specification
35 |
36 | @MicronautTest
37 | class HelloWordGrpcSpec extends Specification {
38 |
39 |
40 | @Inject
41 | TestBean testBean
42 |
43 | @Inject
44 | MyInterceptor myInterceptor
45 |
46 | void "test hello world grpc"() {
47 | expect:
48 | testBean.sayHello("Fred") == "Hello Fred"
49 | myInterceptor.intercepted
50 | }
51 |
52 |
53 | @Factory
54 | static class Clients {
55 | @Singleton
56 | GreeterGrpc.GreeterBlockingStub blockingStub(@GrpcChannel(GrpcServerChannel.NAME) Channel channel) {
57 | GreeterGrpc.newBlockingStub(channel)
58 | }
59 | }
60 |
61 | @Singleton
62 | static class MyInterceptor implements ServerInterceptor {
63 |
64 | boolean intercepted = false
65 |
66 | @Override
67 | ServerCall.Listener interceptCall(ServerCall call, Metadata headers, ServerCallHandler next) {
68 | intercepted = true
69 | return next.startCall(call, headers)
70 | }
71 | }
72 |
73 | @Singleton
74 | static class TestBean {
75 | @Inject
76 | GreeterGrpc.GreeterBlockingStub blockingStub
77 |
78 | String sayHello(String message) {
79 | blockingStub.sayHello(
80 | HelloRequest.newBuilder().setName(message).build()
81 | ).message
82 | }
83 | }
84 |
85 | @Singleton
86 | static class GreeterImpl extends GreeterGrpc.GreeterImplBase {
87 | @Override
88 | void sayHello(HelloRequest request, StreamObserver responseObserver) {
89 | HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + request.getName()).build()
90 | responseObserver.onNext(reply)
91 | responseObserver.onCompleted()
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/grpc-server-runtime/src/test/groovy/io/micronaut/grpc/ManagedChannelBuilderListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut.grpc;
17 |
18 | import io.grpc.ManagedChannelBuilder;
19 | import io.micronaut.context.event.BeanCreatedEvent;
20 | import io.micronaut.context.event.BeanCreatedEventListener;
21 |
22 | import jakarta.inject.Singleton;
23 |
24 | @Singleton
25 | public class ManagedChannelBuilderListener implements BeanCreatedEventListener> {
26 |
27 | @Override
28 | public ManagedChannelBuilder> onCreated(BeanCreatedEvent> event) {
29 | final ManagedChannelBuilder> channelBuilder = event.getBean();
30 | channelBuilder.maxInboundMessageSize(1024);
31 | return channelBuilder;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/grpc-server-runtime/src/test/groovy/io/micronaut/grpc/ServerBuilderListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut.grpc;
17 |
18 | import io.grpc.ServerBuilder;
19 | import io.micronaut.context.event.BeanCreatedEvent;
20 | import io.micronaut.context.event.BeanCreatedEventListener;
21 |
22 | import jakarta.inject.Singleton;
23 |
24 | @Singleton
25 | public class ServerBuilderListener implements BeanCreatedEventListener> {
26 |
27 | @Override
28 | public ServerBuilder> onCreated(BeanCreatedEvent> event) {
29 | final ServerBuilder> builder = event.getBean();
30 | builder.maxInboundMessageSize(1024);
31 | return builder;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/grpc-server-runtime/src/test/groovy/io/micronaut/grpc/server/interceptor/OrderedServerInterceptorSpec.groovy:
--------------------------------------------------------------------------------
1 | package io.micronaut.grpc.server.interceptor
2 |
3 | import io.grpc.Metadata
4 | import io.grpc.ServerCall
5 | import io.grpc.ServerCallHandler
6 | import io.grpc.ServerInterceptor
7 | import spock.lang.Specification
8 |
9 | class OrderedServerInterceptorSpec extends Specification {
10 |
11 | def "test interceptCall"() {
12 | given:
13 | ServerInterceptor mockDelegate = Mock()
14 | OrderedServerInterceptor orderedServerInterceptor = new OrderedServerInterceptor(mockDelegate, 1)
15 |
16 | ServerCall mockServerCall = Mock()
17 | Metadata metadata = new Metadata()
18 | ServerCallHandler mockServerCallHandler = Mock()
19 |
20 | ServerCall.Listener returnedListener = new ServerCall.Listener() {}
21 |
22 | when:
23 | ServerCall.Listener listener = orderedServerInterceptor.interceptCall(mockServerCall, metadata, mockServerCallHandler)
24 |
25 | then:
26 | 1 * mockDelegate.interceptCall(mockServerCall, metadata, mockServerCallHandler) >> returnedListener
27 | 0 * _
28 |
29 | and:
30 | listener == returnedListener
31 | }
32 |
33 | def "test getOrder"() {
34 | given:
35 | int order = 10
36 | OrderedServerInterceptor orderedServerInterceptor = new OrderedServerInterceptor(Mock(ServerInterceptor), 10)
37 |
38 | expect:
39 | orderedServerInterceptor.order == order
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/grpc-server-runtime/src/test/proto/helloworld.proto:
--------------------------------------------------------------------------------
1 | // Copyright 2015 The gRPC Authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | syntax = "proto3";
15 |
16 | option java_multiple_files = true;
17 | option java_package = "io.grpc.examples.helloworld";
18 | option java_outer_classname = "HelloWorldProto";
19 | option objc_class_prefix = "HLW";
20 |
21 | package helloworld;
22 |
23 | // The greeting service definition.
24 | service Greeter {
25 | // Sends a greeting
26 | rpc SayHello (HelloRequest) returns (HelloReply) {}
27 | }
28 |
29 | // The greeting service definition.
30 | service Greeter2 {
31 | // Sends a greeting
32 | rpc SayHello (HelloRequest) returns (HelloReply) {}
33 | }
34 |
35 | // The request message containing the user's name.
36 | message HelloRequest {
37 | string name = 1;
38 | }
39 |
40 | // The response message containing the greetings
41 | message HelloReply {
42 | string message = 1;
43 | }
--------------------------------------------------------------------------------
/grpc-server-runtime/src/test/resources/example.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIFazCCA1OgAwIBAgIUeNH4sv/Qq1xJ9AhhsjAfN8x2E6EwDQYJKoZIhvcNAQEL
3 | BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
4 | GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDA4MjEwODUzMjdaFw0zMDA4
5 | MTkwODUzMjdaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
6 | HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggIiMA0GCSqGSIb3DQEB
7 | AQUAA4ICDwAwggIKAoICAQCuCTdpW29qrE2VR+HYClgMGWzMSi10aAbMBVnk03Wh
8 | sxWKamAD7JKTi+GTZnUaSCQDd2z/BanK0B2dz70b9vIpdIOivOEZdkeoZ0/Frhma
9 | elAnrFUU8u1af+V6jD3m5PIMwwClcPRY1hbs2ojjuOSQ0HikksLjbqrorm9eFFu9
10 | LdfgpZi3A40ud+75zACOkS3yyBMVjI1LXsklbPBPVVU1PVQhENCM1a36OBqiC/3Q
11 | Y5jqG6K2equiqDw6rHSANWc4GnE6vQHXU2HYzC+YDC3VgJ4xArZbKcihqTWHHrqx
12 | amaYGgCybWaimj+aUDH8Uhr5iieZx2TGRh6rwuekTzxNF6KEeJcmQd1nFFG4er5x
13 | Zltdyf50galo+qYePkFS6RSfIBeDXU8X1e1HxPSd+TyKsHtuHzxOIAkUrQu9ABAS
14 | 7CsOP+34rWmafnHsx/IDS+O6KSPP9c2So6esMyR+yaHLjDUM3dL3u+yKq/48g4LL
15 | Lx0yOtaqtJfpeeaWjp88mFlA33XQURJnTC2xp2pr6m9ey94MXPEIw+CqpZ9ficbz
16 | KAbeBqW/iUTSnyLtxc2qlLKV6kszJxQ10p9gnd40mz+iloosIScehZOVuGmGeNdw
17 | C/xiiCxrYMl+7gDLPIADnTkAMtyhKsnmfalf1ic35l5wl06ZuU4SOKPiZPBlDlXc
18 | yQIDAQABo1MwUTAdBgNVHQ4EFgQU5/rVJIPrMRDEayzRPQ3A24Q7hikwHwYDVR0j
19 | BBgwFoAU5/rVJIPrMRDEayzRPQ3A24Q7hikwDwYDVR0TAQH/BAUwAwEB/zANBgkq
20 | hkiG9w0BAQsFAAOCAgEAQcYjKCNf6mnMZ4CZ6lWv00B2FcJj2p57tQ6DY+nEZU8P
21 | fTiCFdC2Kjl/st2y5T6JapWd//L+RNaFPGw4AHL4193tTAX5klgGjOhL28Wd7LVF
22 | 50mELYzbXGXAcGPyMqxIyc1ByRP4/rPoa0gjLz+/vnxuiNHzHPX0JxmrBK1P6yCG
23 | jOGvt30BOMzljrsLKGAK9NRZ/OweWHim8p8osTH00FbAbY85YqA0I/oKO/ta1Hiw
24 | hK+RCN/1xixoW4JZ5D1bzMdpW0BluaivLrHV5OuBlzYjHq5ACMXoRyqI5Lqhbptp
25 | OxxMnxE8ESzFEqGZ4gdvoGsMu2ibpmfJZKMGGIKoE/EgglltPRcmDwUe48Xmn0SB
26 | BV4AN49+BaDi0rczC1kt4XUKfBkPOZuVyfds6dUJuKdziy0yrnPGR87IhL269KTS
27 | JDKgmtYpvVZ7aptShWCQ3Wvq6B45FBCQmCdBkcnlbYDA7aRtnCawRWgqNmj3sDWF
28 | DM+3qEXZxKVQhWw+ccKBJLnA9gs+pfCgYxyH7IAPEN28NVY5MOOBW8jsIT0xPE84
29 | Operh1jv9wXV3Bgmgm0KJe9C3CKYvqrELMXkSFDnnIyAnE22zOys3vUINSHAth71
30 | TZQPAVxZ9Evf0ogZ1yMauXaafKWcLxvkAUVBCNmwlmVJH28BCvcTJEkVRWz3f8w=
31 | -----END CERTIFICATE-----
32 |
--------------------------------------------------------------------------------
/grpc-server-runtime/src/test/resources/example.key:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQCuCTdpW29qrE2V
3 | R+HYClgMGWzMSi10aAbMBVnk03WhsxWKamAD7JKTi+GTZnUaSCQDd2z/BanK0B2d
4 | z70b9vIpdIOivOEZdkeoZ0/FrhmaelAnrFUU8u1af+V6jD3m5PIMwwClcPRY1hbs
5 | 2ojjuOSQ0HikksLjbqrorm9eFFu9LdfgpZi3A40ud+75zACOkS3yyBMVjI1LXskl
6 | bPBPVVU1PVQhENCM1a36OBqiC/3QY5jqG6K2equiqDw6rHSANWc4GnE6vQHXU2HY
7 | zC+YDC3VgJ4xArZbKcihqTWHHrqxamaYGgCybWaimj+aUDH8Uhr5iieZx2TGRh6r
8 | wuekTzxNF6KEeJcmQd1nFFG4er5xZltdyf50galo+qYePkFS6RSfIBeDXU8X1e1H
9 | xPSd+TyKsHtuHzxOIAkUrQu9ABAS7CsOP+34rWmafnHsx/IDS+O6KSPP9c2So6es
10 | MyR+yaHLjDUM3dL3u+yKq/48g4LLLx0yOtaqtJfpeeaWjp88mFlA33XQURJnTC2x
11 | p2pr6m9ey94MXPEIw+CqpZ9ficbzKAbeBqW/iUTSnyLtxc2qlLKV6kszJxQ10p9g
12 | nd40mz+iloosIScehZOVuGmGeNdwC/xiiCxrYMl+7gDLPIADnTkAMtyhKsnmfalf
13 | 1ic35l5wl06ZuU4SOKPiZPBlDlXcyQIDAQABAoICACCt1lvQMYGkTQUk9EFu382V
14 | 0Jojq5laFzykHJcdJc9xIzBUfSb/ex59e6QD7yU6Opj0CeFxHMrafVUutuHTYvFp
15 | 0XXzZYk0bowuqgoCgQhCw15Pu8ItQ2hk76AtSUpb3x+KVkq6hQdRXAipmF66TyDq
16 | JF0yuamfFDSQ3JSb2gYR36FtNtnWruH030jEh649kJUwAHVhaP6oE7kVVaJv8YoH
17 | tA5pa9+mF/8OHeIjwkspCIOdINaG/keSs4yI6W9Rl8ovHOfcqcXXAF6HKMCyOMEI
18 | X6vwSHGhzOyeK1Dt8jxyMEWLTGo0pLsPn7XILTql6C7HRFxZ1pBshkHWXUy7HCVG
19 | Y+kwBiO75D86EqBZwOr9pkcjdcc9YDtntA/Ug5TLkw3umMXXTgV/eS+UiVakcdz9
20 | h8b1KhKzKyiUmaHy27t/3W6UKOhAXULBIeV+fy5FabTtz7QE+SP1/6VJ+zwp3nHy
21 | CBwh15q1taiKbyLWdbkrcmSYRVPmxtS8EbLEG5TowEtlGVdYjzGS1iRCYwHzJHcM
22 | QVdO5xLseTv1/lXmkiLV7Qyf+HE3mEBvQnyN8DajBY1s6y79WUKY66+PEYr2Mmhg
23 | OLbrlaPYsRn8F44rVBJrkMxSLc5pdVjjpgcQyQRlV2gAL/EdLkkdCC8AFezfev6h
24 | FDlyR8wmQkpYrBQbys5pAoIBAQDacRC6UDKcP1F+z+HnCIteH/s1t7NF3+f3/+Ia
25 | 9BMOmzN/uiD7xVSxv7eR7xh9+9R3tQdNaNJa9FGS3BOnWd2bXq32NukElOc9AhsP
26 | mjoqHYEQBmNFJs43wmQgvTRWmldtbaUrG1Rt5UEMYdjfg3oL32QmVtGFpcvefN2X
27 | WN+X4oAXXlQ/nAL2hs0D64u6tAy+RryHvhPSesjXRG1AXnc0Tg7QnfTLpg83VePU
28 | +JvOgpTxXAR8w28Y0WQUiU3UVfoC3kIi0gi+OoxHt595alwtPhIFJhV0IW7vZ7Qq
29 | u6GQ36mtRZtfUWpgisCerXcNvc6P5Dt2mDWkqbOqekfE99KXAoIBAQDL9ZccB2Ic
30 | Bx2QzwyyuNZLG4pRcENE3j+7eRo3nhqM90m5mtOr+T+4J8IXIGpxNxzVh4Z2RacD
31 | k2pHcuKLT5nikL7zD6GV/l2qGm5mKFbUI3RQJWqYfvkHbQ5KD5/ib8NT3d5mdaPG
32 | 2ASuTe+cVIh9k5hacLNHRRZuot8UrtBovo+9t3MKtgvBYAQKPEIKPICYS+PHFjX7
33 | a/KMMizOoP9CJq29JMQ1NMBWOWJNbjzuSp9Fuc3WdDm4YletzASdHLJh+Lxt0vRH
34 | eURpjF5Yn6znSfIWjlUbjRhA21ppgwmWRquye9O4QuP5z5ysU6oEW5tUM6/2tmTA
35 | nG6oBW4LxZefAoIBAF9u9jfvwayxnREiETe2a+z7W+zkDNaCM/4NNONBrvG6rI0o
36 | 7DASziW59KE1LCYeV3zVAhO3r+88vkbDD3MVt9OhUa833iW6SCxHNzthzfeIXFJ7
37 | 9/LGOWHy83u6LZuIYpnURUzH6+L3PawDM5SzBCcbuc1mMLOK876IHud4VHcu5XdQ
38 | Js6DgmfiDL+hsLIo50hZ7xP+3vod2pDxvClbHAkl8SMDX2d5bTxnsdnho3BdbGTm
39 | Jq+7UlYtZOPz+KTDyy5lm89Ko7c4LQFIH8wTw6GgdI77THQoBydgzz28K6H3lVG2
40 | D2NdVnRHKlAoyNKgEhabR79QUF9YJL5eHezXuJECggEAZYIYL8n46SwdadmyXyyg
41 | 8oaFY5y0zgyyuXI/OxkD686TMb29xWRqcxPOhEYM08XzIs6tfCWURrJSfbbOyzjV
42 | xK33au8Ho6gSI7u94DgJZtEybUUB9V2UQT7kkrWOBFtNYmsU6fd4iFkwkzOUokBs
43 | IduYQsK+ZyUaUfvbfOa4MLlOvsQTjGwoE5jeyd1NnNyZv7JdbdM/EJ+b+mxqYng8
44 | MkcfxvgKctSLOR6cLx9DUfFvrXsY17fGll7TdlsInM0QdrQdy6bnDr9q7gD/X6ow
45 | mnfx9YnnD6w8OuMw7zxZRCJuB4mbSKR54/WQ6y9EeaDCALksxWPnZvk0FYmGSHOR
46 | zwKCAQEAtUsT91bOzB/wSo3T7qethdNn7r02VneBB4j93m4UJHHxyIMHROx1iBoK
47 | 9Ptne0cAI3lQzwZ/FKIj/0qPcHFhemuA5RMe6hB3JTfNoyxVYHwB6FU6RyE4cW8y
48 | rcsXAAiXNB3Z7aA3AX2zkAb4TRea+tBiyHLlIR6+dBFDHVf1e7auVREIg18hH3DJ
49 | zQ/g3yhJlucz9FbBDV77oHv1jpPH0ONNXoMGg/qhEV6iE2rRbSsinO2ZQBpzoOjQ
50 | fx69d+Xu8rXEgFlCnsXuiQ9q7Bct4tvv4QMLN8Jn0CNC+/UB+r9Oihh51/QKW3sL
51 | 7aK5AkoUiB014BYf67L01eOs0o0Xmg==
52 | -----END PRIVATE KEY-----
53 |
--------------------------------------------------------------------------------
/grpc-server-runtime/src/test/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/protobuff-support/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'io.micronaut.build.internal.grpc-module'
3 | alias libs.plugins.protobuf
4 | }
5 |
6 | dependencies {
7 | api platform(libs.boms.protobuf)
8 | api mn.micronaut.http
9 | api mn.micronaut.http.netty
10 | //protobuf
11 | api libs.managed.protobuf.java
12 | api libs.managed.protobuf.java.util
13 |
14 | testImplementation mn.micronaut.http.server.netty
15 | testImplementation mnReactor.micronaut.reactor.http.client
16 | testImplementation mn.micronaut.jackson.databind
17 | testImplementation libs.jackson.datatype.protobuf
18 |
19 | testRuntimeOnly mn.micronaut.jackson.databind
20 | }
21 |
22 | protobuf {
23 | protoc { artifact = libs.managed.protoc.asProvider().get() }
24 | }
25 |
--------------------------------------------------------------------------------
/protobuff-support/src/main/java/io/micronaut/protobuf/codec/ExtensionRegistryFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut.protobuf.codec;
17 |
18 | import com.google.protobuf.ExtensionRegistry;
19 | import io.micronaut.context.annotation.Factory;
20 | import io.micronaut.context.annotation.Requires;
21 |
22 | import jakarta.inject.Singleton;
23 |
24 | /**
25 | * Creates the default {@link ExtensionRegistry}.
26 | *
27 | * @author graemerocher
28 | * @since 1.0
29 | */
30 | @Factory
31 | @Requires(classes = ExtensionRegistry.class)
32 | public class ExtensionRegistryFactory {
33 |
34 | /**
35 | * Constructs the extension registry.
36 | * @return The extension registry
37 | */
38 | @Singleton
39 | protected ExtensionRegistry extensionRegistry() {
40 | return ExtensionRegistry.newInstance();
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/protobuff-support/src/main/java/io/micronaut/protobuf/convert/ByteBufToProtoMessageConverter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut.protobuf.convert;
17 |
18 | import java.io.IOException;
19 | import java.util.Optional;
20 |
21 | import jakarta.inject.Singleton;
22 |
23 | import com.google.protobuf.Message;
24 |
25 | import io.micronaut.context.annotation.Requires;
26 | import io.micronaut.core.convert.ConversionContext;
27 | import io.micronaut.core.convert.TypeConverter;
28 | import io.micronaut.protobuf.codec.ProtobufferCodec;
29 | import io.netty.buffer.ByteBuf;
30 | import io.netty.buffer.ByteBufInputStream;
31 |
32 | /**
33 | * Converts Protocol buffer messages from Netty {@link ByteBuf}.
34 | *
35 | * @author graemerocher
36 | * @author luistrigueiros
37 | */
38 | @Singleton
39 | @Requires(classes = {Message.class, ByteBuf.class})
40 | public class ByteBufToProtoMessageConverter implements TypeConverter {
41 |
42 | private final ProtobufferCodec codec;
43 |
44 | /**
45 | * Default constructor.
46 | *
47 | * @param codec The codec
48 | */
49 | public ByteBufToProtoMessageConverter(ProtobufferCodec codec) {
50 | this.codec = codec;
51 | }
52 |
53 | @Override
54 | public Optional convert(ByteBuf object, Class targetType, ConversionContext context) {
55 | return codec
56 | .getMessageBuilder(targetType)
57 | .flatMap(builder -> rehydrate(object, builder, context));
58 | }
59 |
60 | private Optional rehydrate(ByteBuf object, Message.Builder builder, ConversionContext context) {
61 | try (ByteBufInputStream byteBufInputStream = new ByteBufInputStream(object.copy(), true)) {
62 | builder.mergeFrom(byteBufInputStream, codec.getExtensionRegistry());
63 | return Optional.of(builder.build());
64 | } catch (IOException e) {
65 | context.reject(e);
66 | return Optional.empty();
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/protobuff-support/src/main/java/io/micronaut/protobuf/convert/ProtoMessageToByteBufConverter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut.protobuf.convert;
17 |
18 | import com.google.protobuf.Message;
19 | import io.micronaut.context.annotation.Requires;
20 | import io.micronaut.core.convert.ConversionContext;
21 | import io.micronaut.core.convert.ConversionService;
22 | import io.micronaut.core.convert.TypeConverter;
23 | import io.netty.buffer.ByteBuf;
24 |
25 | import jakarta.inject.Singleton;
26 | import java.util.Optional;
27 |
28 | /**
29 | * Converts Protocol buffer messages to Netty {@link ByteBuf}.
30 | *
31 | * @author graemerocher
32 | * @author luistrigueiros
33 | */
34 | @Singleton
35 | @Requires(classes = {Message.class, ByteBuf.class})
36 | public class ProtoMessageToByteBufConverter implements TypeConverter {
37 | private final ConversionService conversionService;
38 |
39 | /**
40 | * @param conversionService The conversion service
41 | */
42 | public ProtoMessageToByteBufConverter(ConversionService conversionService) {
43 | this.conversionService = conversionService;
44 | }
45 |
46 | @Override
47 | public Optional convert(Message object, Class targetType, ConversionContext context) {
48 | return conversionService.convert(object.toByteArray(), targetType, context);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/protobuff-support/src/main/java/io/micronaut/protobuf/handler/ProtobufBodyHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2023 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut.protobuf.handler;
17 |
18 | import com.google.protobuf.ExtensionRegistry;
19 | import com.google.protobuf.Message;
20 | import io.micronaut.core.type.Argument;
21 | import io.micronaut.core.type.Headers;
22 | import io.micronaut.core.type.MutableHeaders;
23 | import io.micronaut.http.HttpHeaders;
24 | import io.micronaut.http.MediaType;
25 | import io.micronaut.http.annotation.Consumes;
26 | import io.micronaut.http.annotation.Produces;
27 | import io.micronaut.http.body.MessageBodyHandler;
28 | import io.micronaut.http.codec.CodecException;
29 | import io.micronaut.protobuf.codec.ProtobufferCodec;
30 | import jakarta.inject.Singleton;
31 |
32 | import java.io.IOException;
33 | import java.io.InputStream;
34 | import java.io.OutputStream;
35 | import java.util.Optional;
36 |
37 | /**
38 | * Message body handler for protobuf {@link Message}s.
39 | *
40 | * @param The body type
41 | * @since 4.0.0
42 | * @author Jonas Konrad
43 | */
44 | @Singleton
45 | @Produces({ProtobufferCodec.PROTOBUFFER_ENCODED, ProtobufferCodec.PROTOBUFFER_ENCODED2})
46 | @Consumes({ProtobufferCodec.PROTOBUFFER_ENCODED, ProtobufferCodec.PROTOBUFFER_ENCODED2})
47 | public final class ProtobufBodyHandler implements MessageBodyHandler {
48 | private final ProtobufferCodec codec;
49 | private final ExtensionRegistry extensionRegistry;
50 |
51 | public ProtobufBodyHandler(ProtobufferCodec codec, ExtensionRegistry extensionRegistry) {
52 | this.codec = codec;
53 | this.extensionRegistry = extensionRegistry;
54 | }
55 |
56 | @Override
57 | public T read(Argument type, MediaType mediaType, Headers httpHeaders, InputStream inputStream) throws CodecException {
58 | Message.Builder builder = getBuilder(type)
59 | .orElseThrow(() -> new CodecException("Unable to create builder"));
60 | if (type.hasTypeVariables()) {
61 | throw new IllegalStateException("Generic type arguments are not supported");
62 | } else {
63 | try {
64 | builder.mergeFrom(inputStream, extensionRegistry);
65 | } catch (IOException e) {
66 | throw new CodecException("Failed to read protobuf", e);
67 | }
68 | return type.getType().cast(builder.build());
69 | }
70 | }
71 |
72 | @Override
73 | public void writeTo(Argument type, MediaType mediaType, T object, MutableHeaders outgoingHeaders, OutputStream outputStream) throws CodecException {
74 | outgoingHeaders.set(HttpHeaders.CONTENT_TYPE, mediaType != null ? mediaType : ProtobufferCodec.PROTOBUFFER_ENCODED_TYPE);
75 | try {
76 | object.writeTo(outputStream);
77 | } catch (IOException e) {
78 | throw new CodecException("Failed to write protobuf", e);
79 | }
80 | }
81 |
82 | private Optional getBuilder(Argument type) {
83 | return codec.getMessageBuilder(type.getType());
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/protobuff-support/src/test/groovy/io/micronaut/BaseSpec.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut
17 |
18 | import com.google.protobuf.ExtensionRegistry
19 | import com.google.protobuf.Message
20 | import io.micronaut.context.ApplicationContext
21 | import io.micronaut.context.annotation.Factory
22 | import io.micronaut.context.annotation.Replaces
23 | import io.micronaut.http.HttpHeaders
24 | import io.micronaut.http.HttpRequest
25 | import io.micronaut.http.client.HttpClient
26 | import io.micronaut.protobuf.codec.ProtobufferCodec
27 | import io.micronaut.runtime.server.EmbeddedServer
28 | import io.micronaut.websocket.WebSocketClient
29 | import jakarta.inject.Singleton
30 | import spock.lang.AutoCleanup
31 | import spock.lang.Shared
32 | import spock.lang.Specification
33 |
34 | abstract class BaseSpec extends Specification {
35 | @Shared
36 | @AutoCleanup
37 | EmbeddedServer embeddedServer = ApplicationContext.run(EmbeddedServer, [
38 | "micronaut.codec.protobuf.additional-types": [SampleController.MY_PROTO_ENCODED]
39 | ])
40 |
41 | @Shared
42 | @AutoCleanup
43 | HttpClient httpClient = embeddedServer.applicationContext.createBean(
44 | HttpClient,
45 | embeddedServer.getURL()
46 | )
47 |
48 | @Shared
49 | @AutoCleanup
50 | WebSocketClient webSocketClient = embeddedServer.applicationContext.createBean(
51 | WebSocketClient,
52 | embeddedServer.getURL()
53 | )
54 |
55 | byte[] getMessage(String url, Class aClass, String mediaType) {
56 | return httpClient.toBlocking().retrieve(
57 | HttpRequest.GET(url)
58 | .header(ProtobufferCodec.X_PROTOBUF_MESSAGE_HEADER, aClass.name)
59 | .header(HttpHeaders.ACCEPT, mediaType),
60 | byte[].class
61 | )
62 | }
63 |
64 | byte[] postMessage(String url, Message message, String mediaType) {
65 | return httpClient.toBlocking().retrieve(
66 | HttpRequest.POST(url, message)
67 | .header(HttpHeaders.CONTENT_TYPE, mediaType)
68 | .header(ProtobufferCodec.X_PROTOBUF_MESSAGE_HEADER, message.class.name)
69 | .header(HttpHeaders.ACCEPT, mediaType),
70 | byte[].class
71 | )
72 | }
73 |
74 | byte[] postMessage(String url, byte[] message, String mediaType) {
75 | return httpClient.toBlocking().retrieve(
76 | HttpRequest.POST(url, message)
77 | .header(HttpHeaders.CONTENT_TYPE, mediaType)
78 | .header(ProtobufferCodec.X_PROTOBUF_MESSAGE_HEADER, message.class.name)
79 | .header(HttpHeaders.ACCEPT, mediaType),
80 | byte[].class
81 | )
82 | }
83 | }
84 |
85 |
--------------------------------------------------------------------------------
/protobuff-support/src/test/groovy/io/micronaut/ProgrammaticController.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut
17 |
18 | import com.example.wire.Example
19 | import groovy.transform.CompileStatic
20 | import io.micronaut.http.annotation.Get
21 | import io.micronaut.protobuf.codec.ProtobufferCodec
22 | import jakarta.inject.Singleton
23 |
24 | @CompileStatic
25 | @Singleton
26 | class ProgrammaticController {
27 | public static Example.GeoPoint DUBLIN = Example.GeoPoint.newBuilder()
28 | .setLat(53.350140D)
29 | .setLng(-6.266155D)
30 | .build()
31 |
32 | @Get(processes = [ProtobufferCodec.PROTOBUFFER_ENCODED, ProtobufferCodec.PROTOBUFFER_ENCODED2, "my/myAppType"])
33 | Example.GeoPoint city() {
34 | DUBLIN
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/protobuff-support/src/test/groovy/io/micronaut/ProgrammaticControllerCreator.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut
17 |
18 | import groovy.transform.CompileStatic
19 | import io.micronaut.context.ExecutionHandleLocator
20 | import io.micronaut.web.router.DefaultRouteBuilder
21 |
22 | import jakarta.inject.Inject
23 | import jakarta.inject.Singleton
24 |
25 | @CompileStatic
26 | @Singleton
27 | class ProgrammaticControllerCreator extends DefaultRouteBuilder {
28 | ProgrammaticControllerCreator(ExecutionHandleLocator executionHandleLocator, UriNamingStrategy uriNamingStrategy) {
29 | super(executionHandleLocator, uriNamingStrategy)
30 | }
31 |
32 | @Inject
33 | void issuesRoutes(ProgrammaticController controller) {
34 | GET("/town", controller, "city")
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/protobuff-support/src/test/groovy/io/micronaut/ProgrammaticControllerSpec.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut
17 |
18 | import com.example.wire.Example
19 | import io.micronaut.protobuf.codec.ProtobufferCodec
20 |
21 | class ProgrammaticControllerSpec extends BaseSpec {
22 |
23 | String url = embeddedServer.getURL().toString() + '/town'
24 |
25 | void "sample city should be dublin/using programmatic controller controller"() {
26 | when: 'The message is requested from the sever=[#url]'
27 | def response = getMessage(url, Example.GeoPoint.class, ProtobufferCodec.PROTOBUFFER_ENCODED)
28 | and: 'The message is parser'
29 | Example.GeoPoint city = Example.GeoPoint.parseFrom(response)
30 | then: 'Should be Dublin'
31 | SampleController.DUBLIN == city
32 | }
33 |
34 | void "sample city should be dublin/using programmatic controller controller with second codec header"() {
35 | when: 'The message is requested from the sever=[#url]'
36 | def response = getMessage(url, Example.GeoPoint.class, ProtobufferCodec.PROTOBUFFER_ENCODED2)
37 | and: 'The message is parser'
38 | Example.GeoPoint city = Example.GeoPoint.parseFrom(response)
39 | then: 'Should be Dublin'
40 | SampleController.DUBLIN == city
41 | }
42 |
43 | void "sample city should be dublin/using programmatic controller controller with custom codec header"() {
44 | when: 'The message is requested from the sever=[#url]'
45 | def response = getMessage(url, Example.GeoPoint.class, SampleController.MY_PROTO_ENCODED)
46 | and: 'The message is parser'
47 | Example.GeoPoint city = Example.GeoPoint.parseFrom(response)
48 | then: 'Should be Dublin'
49 | SampleController.DUBLIN == city
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/protobuff-support/src/test/groovy/io/micronaut/SampleController.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut
17 |
18 | import com.example.wire.Example
19 | import groovy.transform.CompileStatic
20 | import io.micronaut.http.MediaType
21 | import io.micronaut.http.annotation.Body
22 | import io.micronaut.http.annotation.Controller
23 | import io.micronaut.http.annotation.Get
24 | import io.micronaut.http.annotation.Post
25 | import io.micronaut.protobuf.codec.ProtobufferCodec
26 |
27 | @Controller
28 | @CompileStatic
29 | class SampleController {
30 |
31 | public static final String MY_PROTO_ENCODED = "my/myAppType"
32 | public static final MediaType MY_PROTO_ENCODED_TYPE = new MediaType(MY_PROTO_ENCODED)
33 |
34 | public static Example.GeoPoint DUBLIN = Example.GeoPoint.newBuilder()
35 | .setLat(53.350140D)
36 | .setLng(-6.266155D)
37 | .build()
38 |
39 | @Get(value = "/city", processes = [ProtobufferCodec.PROTOBUFFER_ENCODED, ProtobufferCodec.PROTOBUFFER_ENCODED2, "my/myAppType"])
40 | Example.GeoPoint city() {
41 | DUBLIN
42 | }
43 |
44 | @Post(value = "/nearby", processes = [ProtobufferCodec.PROTOBUFFER_ENCODED, ProtobufferCodec.PROTOBUFFER_ENCODED2, "my/myAppType"])
45 | Example.GeoPoint suggestVisitNearBy(@Body Example.GeoPoint point) {
46 | DUBLIN
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/protobuff-support/src/test/groovy/io/micronaut/SampleWebsocketClient.groovy:
--------------------------------------------------------------------------------
1 | package io.micronaut
2 |
3 | import com.example.wire.Example
4 | import io.micronaut.http.MediaType
5 | import io.micronaut.http.annotation.Consumes
6 | import io.micronaut.http.annotation.Produces
7 | import io.micronaut.websocket.annotation.ClientWebSocket
8 | import io.micronaut.websocket.annotation.OnMessage
9 |
10 | import java.util.concurrent.ConcurrentLinkedQueue
11 |
12 | @ClientWebSocket("/ws/echo")
13 | abstract class SampleWebsocketClient implements AutoCloseable {
14 |
15 | Collection replies = new ConcurrentLinkedQueue<>()
16 |
17 | @OnMessage
18 | @Consumes(MediaType.APPLICATION_JSON)
19 | void onMessage(Example.GeoPoint message) {
20 | replies.add(message)
21 | }
22 |
23 | @Produces(MediaType.APPLICATION_JSON)
24 | abstract void sendJson(Example.GeoPoint geoPoint)
25 | }
26 |
--------------------------------------------------------------------------------
/protobuff-support/src/test/groovy/io/micronaut/SampleWebsocketHandler.groovy:
--------------------------------------------------------------------------------
1 | package io.micronaut
2 |
3 | import com.example.wire.Example
4 | import io.micronaut.http.MediaType
5 | import io.micronaut.http.annotation.Body
6 | import io.micronaut.http.annotation.Consumes
7 | import io.micronaut.http.annotation.Produces
8 | import io.micronaut.websocket.WebSocketSession
9 | import io.micronaut.websocket.annotation.OnMessage
10 | import io.micronaut.websocket.annotation.ServerWebSocket
11 |
12 | @ServerWebSocket("/ws/echo")
13 | class SampleWebsocketHandler {
14 |
15 | @OnMessage
16 | @Consumes(MediaType.APPLICATION_JSON)
17 | @Produces(MediaType.APPLICATION_JSON)
18 | void onMessage(WebSocketSession session, @Body Example.GeoPoint payload) {
19 | session.sendSync(payload)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/protobuff-support/src/test/groovy/io/micronaut/SimpleHttpGetSpec.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut
17 |
18 | import com.example.wire.Example
19 | import io.micronaut.protobuf.codec.ProtobufferCodec
20 |
21 | class SimpleHttpGetSpec extends BaseSpec {
22 |
23 | String url = embeddedServer.getURL().toString() + '/city'
24 |
25 | void "sample city should be dublin/using sample controller"() {
26 | when: 'The message is requested from the sever=[#url]'
27 | def response = getMessage(url, Example.GeoPoint.class, ProtobufferCodec.PROTOBUFFER_ENCODED)
28 | and: 'The message is parser'
29 | Example.GeoPoint city = Example.GeoPoint.parseFrom(response)
30 | then: 'Should be Dublin'
31 | SampleController.DUBLIN == city
32 | }
33 |
34 | void "test second protobuff content type header"() {
35 | when: 'The message is requested from the sever=[#url]'
36 | def response = getMessage(url, Example.GeoPoint.class, ProtobufferCodec.PROTOBUFFER_ENCODED2)
37 | and: 'The message is parser'
38 | Example.GeoPoint city = Example.GeoPoint.parseFrom(response)
39 | then: 'Should be Dublin'
40 | SampleController.DUBLIN == city
41 | }
42 |
43 | void "test cutom protobuff content type header"() {
44 | when: 'The message is requested from the sever=[#url]'
45 | def response = getMessage(url, Example.GeoPoint.class, SampleController.MY_PROTO_ENCODED)
46 | and: 'The message is parser'
47 | Example.GeoPoint city = Example.GeoPoint.parseFrom(response)
48 | then: 'Should be Dublin'
49 | SampleController.DUBLIN == city
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/protobuff-support/src/test/groovy/io/micronaut/SimpleHttpPostSpec.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.micronaut
17 |
18 | import com.example.wire.Example
19 | import io.micronaut.context.annotation.Property
20 | import io.micronaut.protobuf.codec.ProtobufferCodec
21 |
22 | class SimpleHttpPostSpec extends BaseSpec {
23 |
24 | String url = embeddedServer.getURL().toString() + '/nearby'
25 |
26 | void "near by Dublin should be Dublin"() {
27 | setup:
28 | Example.GeoPoint message = SampleController.DUBLIN
29 | when: 'The message is posted to the server=[#url]'
30 | def response = postMessage(url, message, ProtobufferCodec.PROTOBUFFER_ENCODED)
31 | and: 'The message is parsed'
32 | Example.GeoPoint city = Example.GeoPoint.parseFrom(response)
33 | then: 'Should be Dublin'
34 | SampleController.DUBLIN == city
35 |
36 | when: 'The byte[] is posted to the server=[#url]'
37 | response = postMessage(url, message.toByteArray(), ProtobufferCodec.PROTOBUFFER_ENCODED)
38 | then: 'The message is parsed'
39 | Example.GeoPoint.parseFrom(response) == SampleController.DUBLIN
40 | }
41 |
42 | void "test second protobuff content type header"() {
43 | setup:
44 | Example.GeoPoint message = SampleController.DUBLIN
45 | when: 'The message is posted to the server=[#url]'
46 | def response = postMessage(url, message, ProtobufferCodec.PROTOBUFFER_ENCODED2)
47 | and: 'The message is parsed'
48 | Example.GeoPoint city = Example.GeoPoint.parseFrom(response)
49 | then: 'Should be Dublin'
50 | SampleController.DUBLIN == city
51 |
52 | when: 'The byte[] is posted to the server=[#url]'
53 | response = postMessage(url, message.toByteArray(), ProtobufferCodec.PROTOBUFFER_ENCODED2)
54 | then: 'The message is parsed'
55 | Example.GeoPoint.parseFrom(response) == SampleController.DUBLIN
56 | }
57 |
58 | void "test custom protobuff content type header"() {
59 | setup:
60 | Example.GeoPoint message = SampleController.DUBLIN
61 | when: 'The message is posted to the server=[#url]'
62 | def response = postMessage(url, message, SampleController.MY_PROTO_ENCODED)
63 | and: 'The message is parsed'
64 | Example.GeoPoint city = Example.GeoPoint.parseFrom(response)
65 | then: 'Should be Dublin'
66 | SampleController.DUBLIN == city
67 |
68 | when: 'The byte[] is posted to the server=[#url]'
69 | response = postMessage(url, message.toByteArray(), SampleController.MY_PROTO_ENCODED)
70 | then: 'The message is parsed'
71 | Example.GeoPoint.parseFrom(response) == SampleController.DUBLIN
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/protobuff-support/src/test/groovy/io/micronaut/SimpleWebsocketSpec.groovy:
--------------------------------------------------------------------------------
1 | package io.micronaut
2 |
3 | import com.example.wire.Example
4 | import reactor.core.publisher.Mono
5 | import spock.util.concurrent.PollingConditions
6 |
7 | class SimpleWebsocketSpec extends BaseSpec {
8 |
9 | String url = embeddedServer.getURL().toString() + '/ws/echo'
10 |
11 | void "test json from proto generated classes websocket exchange"() {
12 | setup:
13 | Example.GeoPoint message = SampleController.DUBLIN
14 | SampleWebsocketClient sampleWebsocketClient = Mono.from(webSocketClient.connect(SampleWebsocketClient, url)).block()
15 | PollingConditions conditions = new PollingConditions(timeout: 15, delay: 0.5)
16 | when: 'Json is sent over ws to the server=[#url]'
17 | sampleWebsocketClient.sendJson(message)
18 | then: 'Echoed message is parsed'
19 | conditions.eventually {
20 | sampleWebsocketClient.replies.contains(message)
21 | }
22 |
23 | cleanup:
24 | sampleWebsocketClient.close()
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/protobuff-support/src/test/proto/example.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package com.example.wire;
3 |
4 | import "google/protobuf/timestamp.proto";
5 | option java_package = "com.example.wire";
6 | option java_outer_classname = "Example";
7 |
8 | message CurrencyAmount {
9 | string currency = 1;
10 | double amount = 2;
11 | }
12 |
13 | message PhoneNumber {
14 | string international_code = 100;
15 | string area_code = 101;
16 | string local_number = 102;
17 | }
18 |
19 | message GeoPoint {
20 | // The latitude in degrees. It must be in the range [-90.0, +90.0].
21 | double lat = 1;
22 |
23 | // The longitude in degrees. It must be in the range [-180.0, +180.0].
24 | double lng = 2;
25 | }
26 |
--------------------------------------------------------------------------------
/protobuff-support/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | build/test.log.txt
4 | false
5 |
6 | %d %-5p %c - %m%n
7 |
8 |
9 |
10 |
11 |
13 |
14 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | mavenCentral()
5 | }
6 | includeBuild "build-logic"
7 | }
8 |
9 | plugins {
10 | id 'io.micronaut.build.shared.settings' version '7.4.0'
11 | }
12 |
13 | enableFeaturePreview 'TYPESAFE_PROJECT_ACCESSORS'
14 |
15 | rootProject.name = 'grpc-parent'
16 |
17 | include 'grpc-bom'
18 | include 'grpc-annotation'
19 | include 'grpc-client-runtime'
20 | include 'grpc-server-runtime'
21 | include 'grpc-runtime'
22 | include 'protobuff-support'
23 |
24 | // documentation samples
25 | include 'test-suite-java'
26 | include 'test-suite-groovy'
27 | include 'test-suite-kotlin'
28 | include 'grpc-health'
29 | include 'grpc-opentracing'
30 |
31 | micronautBuild {
32 | useStandardizedProjectNames = true
33 | importMicronautCatalog()
34 | importMicronautCatalog("micronaut-reactor")
35 | importMicronautCatalog("micronaut-tracing")
36 | importMicronautCatalog("micronaut-validation")
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/docs/guide/client.adoc:
--------------------------------------------------------------------------------
1 | Micronaut for gRPC does not create client beans automatically for you. Instead, you must expose which client stubs your application needs using a `@Factory`.
2 |
3 | You can dependency inject a `io.grpc.ManagedChannel` into the factory. Each injected `io.grpc.ManagedChannel` will automatically be shutdown when the application shuts down.
4 |
5 | === Configuring ManagedChannel Instances
6 |
7 | The channel can be configured using properties defined under `grpc.client` by default.
8 |
9 | For example, if you wish to disable secure communication:
10 |
11 | [source,yaml]
12 | ----
13 | grpc:
14 | client:
15 | plaintext: true
16 | max-retry-attempts: 10
17 | ----
18 |
19 | Properties under `grpc.client` are global properties and are the defaults used unless named configuration exists under `grpc.channels.[NAME]`.
20 |
21 | Any property of the `io.grpc.netty.NettyChannelBuilder` type can be configured.
22 |
23 | Alternatively if you prefer programmatic configuration you can write a `BeanCreationListener` for example:
24 |
25 | .Configuring the NettyChannelBuilder
26 | [source,java]
27 | ----
28 | include::grpc-server-runtime/src/test/groovy/io/micronaut/grpc/ManagedChannelBuilderListener.java[]
29 | ----
30 |
31 | === Auto Injected Types
32 |
33 | By default, each channel will automatically be dependency injected with beans of the following types:
34 |
35 | * `io.grpc.ClientInterceptor` - Any client interceptors declared as beans
36 | * `io.grpc.NameResolver` - The configured name resolver
37 |
38 | === Creating Client Stub Beans
39 |
40 | The value of the `@GrpcChannel` annotation can be used to specify the target server, the configuration for which can also be externalized:
41 |
42 | [source,java]
43 | ----
44 | @Factory
45 | class Clients {
46 | @Singleton
47 | GreeterGrpc.GreeterStub reactiveStub(
48 | @GrpcChannel("https://${my.server}:${my.port}")
49 | ManagedChannel channel) {
50 | return GreeterGrpc.newStub(
51 | channel
52 | );
53 | }
54 | }
55 | ----
56 |
57 | The above example requires that `my.server` and `my.port` are specified in `application.yml` (or via environment variables `MY_SERVER` and `MY_PORT`). You can also externalize this further into configuration and provide channel specific configuration.
58 |
59 | For example given the following configuration:
60 |
61 | [source,yaml]
62 | ----
63 | grpc:
64 | channels:
65 | greeter:
66 | address: '${my.server}:${my.port}'
67 | plaintext: true
68 | max-retry-attempts: 10
69 | ----
70 |
71 | You can then define the `@GrpcChannel` annotation as follows:
72 |
73 | [source,java]
74 | ----
75 | @Singleton
76 | GreeterGrpc.GreeterStub reactiveStub(
77 | @GrpcChannel("greeter")
78 | ManagedChannel channel) {
79 | return GreeterGrpc.newStub(
80 | channel
81 | );
82 | }
83 | ----
84 |
85 | The ID `greeter` is used to reference the configuration for `grpc.channels.greeter`.
86 |
87 | Using service IDs in this way is the preferred way to set up gRPC clients, because it works nicely with Service Discovery (see the next section).
88 |
--------------------------------------------------------------------------------
/src/main/docs/guide/gettingStarted.adoc:
--------------------------------------------------------------------------------
1 | To get started you need first create a Micronaut project. The easiest way to do this is with the Micronaut Launch:
2 |
3 | * Go to https://micronaut.io/launch/[Micronaut Launch]
4 | * Select "gRPC Application" under "Application Type"
5 | * Choose a Language / Build System etc.
6 | * Click Generate
7 |
8 | TIP: Replace `java` with `kotlin` or `groovy` to change language and the `build` flag with `maven` to use Maven instead.
9 |
10 | Or alternatively you can create a project with `curl`:
11 |
12 | [source,bash]
13 | ----
14 | curl --location --request GET 'https://launch.micronaut.io/create/grpc/demo?lang=JAVA&build=GRADLE' --output demo.zip
15 | unzip demo.zip -d demo
16 | cd demo
17 | ----
18 |
19 | To manually setup gRPC you can create an application:
20 |
21 | [source,bash]
22 | ----
23 | $ mn create-app helloworld
24 | ----
25 |
26 | Then follow the below steps depending on the build system chosen.
27 |
28 |
29 | === Configuring Gradle
30 |
31 | To configure Gradle, first apply the `com.google.protobuf` plugin:
32 |
33 | [source,groovy]
34 | ----
35 | plugins {
36 | ...
37 | include::test-suite-java/build.gradle[tags=plugin]
38 | }
39 |
40 | ----
41 |
42 | Then configure the gRPC and protobuf plugins:
43 |
44 | [source,groovy]
45 | ----
46 | include::test-suite-java/build.gradle[tags=config]
47 | ----
48 | NOTE: If you are using JDK9 or above, in order to avoid issues javax packages, provide the following compiler option to the grpc plugin to skip these stubs: `option '@generated=omit'` (added on link:https://github.com/grpc/grpc-java/releases/tag/v1.64.0[grpc-kava v1.64.0]) See discussion here: link:https://github.com/grpc/grpc-java/issues/9179[issue 9179]
49 |
50 | [source,groovy]
51 | ----
52 | ...
53 | generateProtoTasks {
54 | all()*.plugins {
55 | grpc {
56 | option '@generated=omit'
57 | } }
58 | }
59 | ----
60 |
61 | Use this configuration for Kotlin projects:
62 |
63 | [source,groovy]
64 | ----
65 | include::test-suite-kotlin/build.gradle[tags=variables]
66 |
67 | dependencies {
68 | ...
69 | include::test-suite-kotlin/build.gradle[tags=dependencies]
70 | }
71 |
72 | include::test-suite-kotlin/build.gradle[tags=config]
73 |
74 | ----
75 |
76 | Finally, add the following dependencies to your build:
77 |
78 | For gRPC servers:
79 |
80 | dependency:micronaut-grpc-server-runtime[groupId="io.micronaut.grpc"]
81 |
82 | For gRPC clients:
83 |
84 | dependency:micronaut-grpc-client-runtime[groupId="io.micronaut.grpc"]
85 |
86 | NOTE: If you wish to use gRPC standalone without the Micronaut HTTP server you should comment out the `micronaut-http-server-netty` dependency.
87 |
88 | You can then run:
89 |
90 | [source,bash]
91 | $ ./gradlew generateProto
92 |
93 | To generate the Java sources from protobuf definitions in `src/main/proto`.
94 |
95 | === Configuring Maven
96 |
97 | For Maven create a maven project first:
98 |
99 | [source,bash]
100 | ----
101 | $ mn create-app helloworld --build
102 | ----
103 |
104 | Then configure the Protobuf plugin appropriately:
105 |
106 | [source,xml]
107 | ----
108 | include::test-suite-java/pom.xml[tags=plugin, indent=0]
109 | ----
110 |
111 | You can then run:
112 |
113 | [source,bash]
114 | $ ./mvnw generate-sources
115 |
116 | To generate the Java sources from protobuf definitions in `src/main/proto`.
117 |
118 | === Defining a Protobuf File
119 |
120 | Once you have the build setup you can define a Protobuf file for your gRPC service. For example:
121 |
122 | .src/main/proto/helloworld.proto
123 | [source,protobuf]
124 | ----
125 | include::test-suite-java/src/main/proto/helloworld.proto[]
126 | ----
127 |
128 | TIP: With the Micronaut 1.1 or above CLI you can generate a service with `mn create-grpc-service helloworld` which will create the `proto` file and class that implements the stub.
129 |
--------------------------------------------------------------------------------
/src/main/docs/guide/introduction.adoc:
--------------------------------------------------------------------------------
1 | This project allows building https://grpc.io[gRPC] servers and clients with Micronaut.
2 |
3 | Micronaut adds the following features to the gRPC experience:
4 |
5 | * Compile Time Dependency Injection (DI) and Aspect Oriented Programming (AOP)
6 | * Service Discovery and Registrations
7 | * Distributed Tracing
8 | * Cloud Native Configuration
9 |
10 |
--------------------------------------------------------------------------------
/src/main/docs/guide/protocolBuffers.adoc:
--------------------------------------------------------------------------------
1 | This project also includes a module that adds the ability to encode and decode Protocol buffers messages with the Micronaut HTTP server.
2 |
3 | To use this adds the `micronaut-protobuff-support` dependency:
4 |
5 | dependency:micronaut-protobuff-support[groupId="io.micronaut.grpc"]
6 |
7 | Micronaut will now support the encoding and decoding requests / responses of type `application/x-protobuf`.
8 |
--------------------------------------------------------------------------------
/src/main/docs/guide/releaseHistory.adoc:
--------------------------------------------------------------------------------
1 | For this project, you can find a list of releases (with release notes) here:
2 |
3 | https://github.com/{githubSlug}/releases[https://github.com/{githubSlug}/releases]
4 |
--------------------------------------------------------------------------------
/src/main/docs/guide/repository.adoc:
--------------------------------------------------------------------------------
1 | You can find the source code of this project in this repository:
2 |
3 | https://github.com/{githubSlug}[https://github.com/{githubSlug}]
--------------------------------------------------------------------------------
/src/main/docs/guide/serviceDiscovery.adoc:
--------------------------------------------------------------------------------
1 | When using `@GrpcChannel` with a service ID without explicitly configuring the address of the service will trigger gRPC's `NameResolver` and attempt to do service discovery.
2 |
3 | The default strategy for this is to use DNS based discovery. So for example you can do:
4 |
5 | [source,java]
6 | ----
7 | @GrpcChannel("dns://greeter")
8 | ----
9 |
10 | Where DNS has been configured to know the address of the `greeter` service.
11 |
12 | Alternatively, if you prefer to use a service discovery server then you can use integration with Micronaut service discovery.
13 |
14 | === Service Discovery with Consul
15 |
16 | You can use Micronaut's built-in service discovery features with any supported server (Consul and Eureka currently).
17 |
18 | The way in which this is done is the https://docs.micronaut.io/latest/guide/index.html#serviceDiscoveryConsul[same as a regular Micronaut service].
19 |
20 | ==== Registering a gRPC Service with Consul
21 |
22 | To register a gRPC service with Consul first add the `micronaut-discovery-client` dependency:
23 |
24 | dependency:micronaut-discovery-client[groupId="io.micronaut.discovery", scope="runtime"]
25 |
26 | Then setup Consul correctly:
27 |
28 | [source,yaml]
29 | ----
30 | micronaut:
31 | application:
32 | name: greeter
33 | consul:
34 | client:
35 | registration:
36 | enabled: true
37 | defaultZone: "${CONSUL_HOST:localhost}:${CONSUL_PORT:8500}"
38 | ----
39 |
40 | When using Service Discovery, Micronaut will register the service in Consul using the name defined in `micronaut.application.name`.
41 | If the application also uses an HTTP Server (Netty, Tomcat,...), Micronaut will register the application with the same
42 | name and a different port in Consul. In case you want to use a different name for the gRPC service in Consul:
43 |
44 | [source,yaml]
45 | ----
46 | micronaut:
47 | application:
48 | name: greeter # <1>
49 | grpc:
50 | server:
51 | instance-id: 'hello-grpc' # <2>
52 | ----
53 | <1> The HTTP port will be registered in Consul with the name `greeter`
54 | <2> The gRPC port will be registered in Consul with the name `hello-grpc`
55 |
56 |
57 | ==== Discoverying Services via Consul
58 |
59 | To discovery services via Consul and the Micronaut `DiscoveryClient` abstraction enable Consul and gRPC service discovery:
60 |
61 | [source,yaml]
62 | ----
63 | grpc:
64 | client:
65 | discovery:
66 | enabled: true
67 | consul:
68 | client:
69 | defaultZone: "${CONSUL_HOST:localhost}:${CONSUL_PORT:8500}"
70 | ----
71 |
72 | Then use the value `greeter` to discover the service when injecting the channel:
73 |
74 | [source,java]
75 | ----
76 | @Singleton
77 | @Bean
78 | GreeterGrpc.GreeterStub greeterStub(
79 | @GrpcChannel("greeter")
80 | ManagedChannel channel) {
81 | return GreeterGrpc.newStub(
82 | channel
83 | );
84 | }
85 | ----
86 |
--------------------------------------------------------------------------------
/src/main/docs/guide/toc.yml:
--------------------------------------------------------------------------------
1 | introduction:
2 | title: Introduction
3 | releaseHistory: Release History
4 | gettingStarted: Getting Started
5 | server: gRPC Server
6 | client: gRPC Clients
7 | serviceDiscovery: Service Discovery
8 | tracing: Distributed Tracing
9 | protocolBuffers: Protocol Buffers Support
10 | repository: Repository
11 |
--------------------------------------------------------------------------------
/src/main/docs/guide/tracing.adoc:
--------------------------------------------------------------------------------
1 | gRPC includes tracing based on OpenCensus, however if you wish to use Micronaut's integration with Jaeger or Zipkin you can do so by adding the following dependencies:
2 |
3 | dependency:micronaut-tracing-brave-http[scope="compile", groupId="io.micronaut.tracing"]
4 |
5 | dependency:opentracing-grpc[scope="runtime", version="0.2.1", groupId="io.opentracing.contrib"]
6 |
7 | You then need to https://micronaut-projects.github.io/micronaut-tracing/latest/guide/#jaeger[configure either Jaeger or Zipkin] appropriately.
8 |
--------------------------------------------------------------------------------
/test-suite-groovy/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id "groovy"
3 | alias(libs.plugins.protobuf)
4 | id "io.micronaut.build.internal.grpc-minimal-test"
5 | }
6 |
7 | // tag::variables[]
8 | ext {
9 | grpcVersion = libs.versions.managed.grpc.asProvider().get()
10 | protobufVersion = libs.versions.managed.protobuf.asProvider().get()
11 | }
12 | // end::variables[]
13 |
14 | mainClassName = "helloworld.Application"
15 | micronaut {
16 | version.set(libs.versions.micronaut.platform.get())
17 | coreVersion.set(libs.versions.micronaut.asProvider().get())
18 | testRuntime "spock"
19 | enableNativeImage false
20 | processing {
21 | incremental(true)
22 | annotations("helloworld.*")
23 | }
24 | }
25 |
26 | dependencies {
27 | compileOnly libs.managed.grpc.stub
28 | compileOnly libs.javax.annotation.api
29 | compileOnly mnValidation.micronaut.validation.processor
30 |
31 | implementation mnValidation.micronaut.validation
32 | implementation mn.micronaut.runtime
33 | implementation projects.micronautGrpcRuntime
34 | implementation libs.micronaut.discovery.client
35 | implementation libs.managed.grpc.services
36 | implementation libs.managed.grpc.protobuf
37 | implementation libs.managed.protobuf.java.util
38 | implementation mn.snakeyaml
39 |
40 | runtimeOnly mnLogging.logback.classic
41 |
42 | testCompileOnly libs.javax.annotation.api
43 |
44 | testImplementation mn.groovy
45 |
46 | testCompileOnly libs.managed.protobuf.java
47 | testRuntimeOnly mnLogging.logback.classic
48 | }
49 |
50 | tasks.withType(GroovyCompile) {
51 | groovyOptions.forkOptions.jvmArgs.add('-Dgroovy.parameters=true')
52 | }
53 |
54 | tasks.withType(org.gradle.jvm.tasks.Jar) {
55 | duplicatesStrategy = DuplicatesStrategy.INCLUDE
56 | }
57 |
58 | sourceSets {
59 | main {
60 | groovy {
61 | srcDirs 'build/generated/source/proto/main/grpc'
62 | srcDirs 'build/generated/source/proto/main/java'
63 | }
64 | }
65 | }
66 |
67 | protobuf {
68 | protoc { artifact = "com.google.protobuf:protoc:$protobufVersion" }
69 | plugins {
70 | grpc { artifact = "io.grpc:protoc-gen-grpc-java:$grpcVersion" }
71 | }
72 | generateProtoTasks {
73 | all()*.plugins { grpc {} }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/test-suite-groovy/src/main/groovy/helloworld/Application.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package helloworld
17 |
18 | import groovy.transform.CompileStatic
19 | import io.micronaut.runtime.Micronaut
20 |
21 | @CompileStatic
22 | class Application {
23 | static void main(String[] args) {
24 | Micronaut.build(args)
25 | .packages("helloworld")
26 | .mainClass(Application.class)
27 | .start()
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/test-suite-groovy/src/main/groovy/helloworld/GreetingEndpoint.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package helloworld
17 |
18 | // tag::imports[]
19 | import groovy.transform.CompileStatic
20 | import io.grpc.stub.StreamObserver
21 | import jakarta.inject.Singleton
22 |
23 | // end::imports[]
24 |
25 |
26 | // tag::clazz[]
27 | @CompileStatic
28 | @Singleton
29 | class GreetingEndpoint extends GreeterGrpc.GreeterImplBase { // <1>
30 |
31 | final GreetingService greetingService
32 |
33 | // <2>
34 | GreetingEndpoint(GreetingService greetingService) {
35 | this.greetingService = greetingService
36 | }
37 |
38 | @Override
39 | void sayHello(HelloRequest request, StreamObserver responseObserver) {
40 | // <3>
41 | HelloReply.newBuilder().with {
42 | message = greetingService.sayHello(request.name)
43 | responseObserver.onNext(build())
44 | responseObserver.onCompleted()
45 | }
46 | }
47 | }
48 | // end::clazz[]
49 |
--------------------------------------------------------------------------------
/test-suite-groovy/src/main/groovy/helloworld/GreetingService.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package helloworld
17 |
18 | import groovy.transform.CompileStatic
19 | import jakarta.inject.Singleton
20 |
21 | @Singleton
22 | @CompileStatic
23 | class GreetingService {
24 |
25 | String sayHello(String name) {
26 | return "Hello $name"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/test-suite-groovy/src/main/groovy/helloworld/HealthService.groovy:
--------------------------------------------------------------------------------
1 | package helloworld
2 |
3 | // tag::imports[]
4 | import io.grpc.health.v1.HealthCheckResponse
5 | import io.grpc.protobuf.services.HealthStatusManager
6 | import io.micronaut.core.annotation.NonNull
7 | import io.micronaut.core.annotation.Nullable
8 | import jakarta.inject.Singleton
9 |
10 | // end::imports[]
11 |
12 | // tag::clazz[]
13 | @Singleton
14 | class HealthService {
15 |
16 | private final HealthStatusManager healthStatusManager
17 |
18 | HealthService(@Nullable HealthStatusManager healthStatusManager) {
19 | this.healthStatusManager = healthStatusManager
20 | }
21 |
22 | void setStatus(@NonNull String serviceName, @NonNull HealthCheckResponse.ServingStatus status) {
23 | healthStatusManager?.setStatus(serviceName, status)
24 | }
25 | }
26 | // end::clazz[]
27 |
--------------------------------------------------------------------------------
/test-suite-groovy/src/main/proto/helloworld.proto:
--------------------------------------------------------------------------------
1 | // Copyright 2015 The gRPC Authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | syntax = "proto3";
15 |
16 | option java_multiple_files = true;
17 | option java_package = "helloworld";
18 | option java_outer_classname = "HelloWorldProto";
19 | option objc_class_prefix = "HLW";
20 |
21 | package helloworld;
22 |
23 | // The greeting service definition.
24 | service Greeter {
25 | // Sends a greeting
26 | rpc SayHello (HelloRequest) returns (HelloReply) {}
27 | }
28 |
29 | // The request message containing the user's name.
30 | message HelloRequest {
31 | string name = 1;
32 | }
33 |
34 | // The response message containing the greetings
35 | message HelloReply {
36 | string message = 1;
37 | }
--------------------------------------------------------------------------------
/test-suite-groovy/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | micronaut:
2 | application:
3 | name: helloworld
4 |
--------------------------------------------------------------------------------
/test-suite-groovy/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/test-suite-groovy/src/test/groovy/helloworld/GreetingEndpointSpec.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package helloworld
17 |
18 | import io.grpc.ManagedChannel
19 | import io.micronaut.context.annotation.Factory
20 | import io.micronaut.grpc.annotation.GrpcChannel
21 | import io.micronaut.grpc.server.GrpcServerChannel
22 | import io.micronaut.test.extensions.spock.annotation.MicronautTest
23 | import jakarta.inject.Inject
24 | import jakarta.inject.Singleton
25 | import spock.lang.Specification
26 |
27 | @MicronautTest
28 | class GreetingEndpointSpec extends Specification {
29 |
30 | @Inject
31 | GreeterGrpc.GreeterBlockingStub blockingStub
32 |
33 | void "test greeting endpoint"() {
34 | given:
35 | HelloRequest request = HelloRequest.newBuilder().with {
36 | name = "Fred"
37 | build()
38 | }
39 |
40 | expect:
41 | blockingStub.sayHello(
42 | request
43 | ).message == 'Hello Fred'
44 | }
45 |
46 | @Factory
47 | static class Clients {
48 | @Singleton
49 | GreeterGrpc.GreeterBlockingStub blockingStub(
50 | @GrpcChannel(GrpcServerChannel.NAME) ManagedChannel channel) {
51 | GreeterGrpc.newBlockingStub(
52 | channel
53 | )
54 | }
55 | }
56 | }
57 |
58 |
--------------------------------------------------------------------------------
/test-suite-groovy/src/test/groovy/helloworld/HealthCheckSpec.groovy:
--------------------------------------------------------------------------------
1 | package helloworld
2 |
3 | import io.grpc.Channel
4 | import io.grpc.health.v1.HealthCheckRequest
5 | import io.grpc.health.v1.HealthCheckResponse
6 | import io.grpc.health.v1.HealthGrpc
7 | import io.grpc.protobuf.services.HealthStatusManager
8 | import io.micronaut.context.annotation.Factory
9 | import io.micronaut.grpc.annotation.GrpcChannel
10 | import io.micronaut.grpc.server.GrpcServerChannel
11 | import io.micronaut.test.extensions.spock.annotation.MicronautTest
12 | import jakarta.inject.Inject
13 | import jakarta.inject.Singleton
14 | import spock.lang.Specification
15 |
16 | @MicronautTest
17 | class HealthCheckSpec extends Specification {
18 |
19 | @Inject
20 | HealthGrpc.HealthBlockingStub healthStub
21 |
22 | @Inject
23 | HealthService healthService
24 |
25 | void "test health check"() {
26 | when:
27 | def result = healthStub.check(HealthCheckRequest.newBuilder().build())
28 |
29 | then:
30 | result.status == HealthCheckResponse.ServingStatus.SERVING
31 |
32 | when:
33 | healthService.setStatus(HealthStatusManager.SERVICE_NAME_ALL_SERVICES, HealthCheckResponse.ServingStatus.NOT_SERVING)
34 | result = healthStub.check(HealthCheckRequest.newBuilder().build())
35 |
36 | then:
37 | result.status == HealthCheckResponse.ServingStatus.NOT_SERVING
38 | }
39 |
40 | @Factory
41 | static class Clients {
42 |
43 | @Singleton
44 | HealthGrpc.HealthBlockingStub healthStub(@GrpcChannel(GrpcServerChannel.NAME) Channel channel) {
45 | HealthGrpc.newBlockingStub(channel)
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/test-suite-java/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/micronaut-projects/micronaut-grpc/165833157056e97eb0313098a3c2ac7b115cc0ad/test-suite-java/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/test-suite-java/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | # Licensed to the Apache Software Foundation (ASF) under one
2 | # or more contributor license agreements. See the NOTICE file
3 | # distributed with this work for additional information
4 | # regarding copyright ownership. The ASF licenses this file
5 | # to you under the Apache License, Version 2.0 (the
6 | # "License"); you may not use this file except in compliance
7 | # with the License. You may obtain a copy of the License at
8 | #
9 | # https://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar
19 |
--------------------------------------------------------------------------------
/test-suite-java/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id "java"
3 | // tag::plugin[]
4 | alias(libs.plugins.protobuf)
5 | // end::plugin[]
6 | id "io.micronaut.build.internal.grpc-tests"
7 | }
8 |
9 | // tag::variables[]
10 | ext {
11 | grpcVersion = libs.versions.managed.grpc.asProvider().get()
12 | protobufVersion = libs.versions.managed.protobuf.asProvider().get()
13 | }
14 | // end::variables[]
15 |
16 | mainClassName = "helloworld.Application"
17 | micronaut {
18 | version.set(libs.versions.micronaut.platform.get())
19 | coreVersion.set(libs.versions.micronaut.asProvider().get())
20 | testRuntime "junit5"
21 | enableNativeImage false
22 | processing {
23 | incremental(true)
24 | annotations("helloworld.*")
25 | }
26 | }
27 |
28 | dependencies {
29 |
30 | annotationProcessor mnValidation.micronaut.validation.processor
31 |
32 | compileOnly libs.managed.grpc.stub
33 | compileOnly libs.javax.annotation.api
34 |
35 | implementation mnValidation.micronaut.validation
36 | implementation mn.micronaut.runtime
37 | implementation projects.micronautGrpcServerRuntime
38 | implementation libs.micronaut.discovery.client
39 | implementation libs.managed.grpc.services
40 | implementation mn.snakeyaml
41 |
42 | runtimeOnly mnLogging.logback.classic
43 |
44 | testAnnotationProcessor mnValidation.micronaut.validation.processor
45 |
46 | testCompileOnly libs.javax.annotation.api
47 | testRuntimeOnly mnLogging.logback.classic
48 | testCompileOnly libs.managed.protobuf.java
49 |
50 | }
51 |
52 | // tag::config[]
53 |
54 | sourceSets {
55 | main {
56 | java {
57 | srcDirs 'build/generated/source/proto/main/grpc'
58 | srcDirs 'build/generated/source/proto/main/java'
59 | }
60 | }
61 | }
62 |
63 | protobuf {
64 | protoc { artifact = "com.google.protobuf:protoc:$protobufVersion" }
65 | plugins {
66 | grpc { artifact = "io.grpc:protoc-gen-grpc-java:$grpcVersion" }
67 | }
68 | generateProtoTasks {
69 | all()*.plugins { grpc {} }
70 | }
71 | }
72 | // end::config[]
73 |
--------------------------------------------------------------------------------
/test-suite-java/src/main/java/helloworld/Application.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package helloworld;
17 |
18 | import io.micronaut.runtime.Micronaut;
19 |
20 | public class Application {
21 |
22 | public static void main(String[] args) {
23 | Micronaut.build(args)
24 | .packages("helloworld")
25 | .mainClass(Application.class)
26 | .start();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/test-suite-java/src/main/java/helloworld/GreetingEndpoint.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package helloworld;
17 |
18 | // tag::imports[]
19 | import io.grpc.stub.StreamObserver;
20 |
21 | import jakarta.inject.Singleton;
22 | // end::imports[]
23 |
24 | // tag::clazz[]
25 | @Singleton
26 | public class GreetingEndpoint extends GreeterGrpc.GreeterImplBase { // <1>
27 |
28 | private final GreetingService greetingService;
29 |
30 | // <2>
31 | public GreetingEndpoint(GreetingService greetingService) {
32 | this.greetingService = greetingService;
33 | }
34 |
35 | @Override
36 | public void sayHello(HelloRequest request, StreamObserver responseObserver) {
37 | // <3>
38 | final String message = greetingService.sayHello(request.getName());
39 | HelloReply reply = HelloReply.newBuilder().setMessage(message).build();
40 | responseObserver.onNext(reply);
41 | responseObserver.onCompleted();
42 | }
43 | }
44 | // end::clazz[]
45 |
--------------------------------------------------------------------------------
/test-suite-java/src/main/java/helloworld/GreetingService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package helloworld;
17 |
18 | import jakarta.inject.Singleton;
19 |
20 | @Singleton
21 | public class GreetingService {
22 |
23 | String sayHello(String name) {
24 | return "Hello " + name;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/test-suite-java/src/main/java/helloworld/HealthService.java:
--------------------------------------------------------------------------------
1 | package helloworld;
2 |
3 | // tag::imports[]
4 | import io.grpc.health.v1.HealthCheckResponse;
5 | import io.grpc.protobuf.services.HealthStatusManager;
6 | import io.micronaut.core.annotation.NonNull;
7 | import io.micronaut.core.annotation.Nullable;
8 |
9 | import jakarta.inject.Singleton;
10 | // end::imports[]
11 |
12 | // tag::clazz[]
13 | @Singleton
14 | public class HealthService {
15 |
16 | private final HealthStatusManager healthStatusManager;
17 |
18 | public HealthService(@Nullable HealthStatusManager healthStatusManager) {
19 | this.healthStatusManager = healthStatusManager;
20 | }
21 |
22 | public void setStatus(@NonNull String serviceName, @NonNull HealthCheckResponse.ServingStatus status) {
23 | if (healthStatusManager != null) {
24 | healthStatusManager.setStatus(serviceName, status);
25 | }
26 | }
27 | }
28 | // end::clazz[]
29 |
--------------------------------------------------------------------------------
/test-suite-java/src/main/proto/helloworld.proto:
--------------------------------------------------------------------------------
1 | // Copyright 2015 The gRPC Authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | syntax = "proto3";
15 |
16 | option java_multiple_files = true;
17 | option java_package = "helloworld";
18 | option java_outer_classname = "HelloWorldProto";
19 | option objc_class_prefix = "HLW";
20 |
21 | package helloworld;
22 |
23 | // The greeting service definition.
24 | service Greeter {
25 | // Sends a greeting
26 | rpc SayHello (HelloRequest) returns (HelloReply) {}
27 | }
28 |
29 | // The request message containing the user's name.
30 | message HelloRequest {
31 | string name = 1;
32 | }
33 |
34 | // The response message containing the greetings
35 | message HelloReply {
36 | string message = 1;
37 | }
--------------------------------------------------------------------------------
/test-suite-java/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | micronaut:
2 | application:
3 | name: hello-world-java
4 | # Uncomment to enable service discovery with Consul
5 | #consul:
6 | # client:
7 | # registration:
8 | # enabled: true
9 | # defaultZone: "${CONSUL_HOST:localhost}:${CONSUL_PORT:8500}"
10 |
--------------------------------------------------------------------------------
/test-suite-java/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/test-suite-java/src/test/java/helloworld/GreetingEndpointTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package helloworld;
17 | // tag::imports[]
18 |
19 | import io.grpc.ManagedChannel;
20 | import io.micronaut.context.annotation.Bean;
21 | import io.micronaut.context.annotation.Factory;
22 | import io.micronaut.grpc.annotation.GrpcChannel;
23 | import io.micronaut.grpc.server.GrpcServerChannel;
24 | import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
25 |
26 | import org.junit.jupiter.api.Test;
27 |
28 | import jakarta.inject.Inject;
29 |
30 | import static org.junit.jupiter.api.Assertions.assertEquals;
31 | // end::imports[]
32 |
33 | // tag::test[]
34 | @MicronautTest // <1>
35 | class GreetingEndpointTest {
36 |
37 | @Inject
38 | GreeterGrpc.GreeterBlockingStub blockingStub; // <2>
39 |
40 | @Test
41 | void testHelloWorld() {
42 | final HelloRequest request = HelloRequest.newBuilder() // <3>
43 | .setName("Fred")
44 | .build();
45 | assertEquals(
46 | "Hello Fred",
47 | blockingStub.sayHello(request)
48 | .getMessage()
49 | );
50 | }
51 |
52 | }
53 | // end::test[]
54 |
55 | // tag::clients[]
56 | @Factory
57 | class Clients {
58 |
59 | @Bean
60 | GreeterGrpc.GreeterBlockingStub blockingStub(
61 | @GrpcChannel(GrpcServerChannel.NAME) ManagedChannel channel) { // <1>
62 | return GreeterGrpc.newBlockingStub( // <2>
63 | channel
64 | );
65 | }
66 | }
67 | // end::clients[]
68 |
--------------------------------------------------------------------------------
/test-suite-java/src/test/java/helloworld/HealthCheckTest.java:
--------------------------------------------------------------------------------
1 | package helloworld;
2 |
3 | import io.grpc.ManagedChannel;
4 | import io.grpc.health.v1.HealthCheckRequest;
5 | import io.grpc.health.v1.HealthCheckResponse;
6 | import io.grpc.health.v1.HealthGrpc;
7 | import io.grpc.protobuf.services.HealthStatusManager;
8 | import io.micronaut.context.annotation.Bean;
9 | import io.micronaut.context.annotation.Factory;
10 | import io.micronaut.grpc.annotation.GrpcChannel;
11 | import io.micronaut.grpc.server.GrpcServerChannel;
12 | import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
13 |
14 | import org.junit.jupiter.api.Test;
15 |
16 | import jakarta.inject.Inject;
17 |
18 | import static org.junit.jupiter.api.Assertions.assertEquals;
19 |
20 | @MicronautTest
21 | class HealthCheckTest {
22 |
23 | @Inject
24 | HealthGrpc.HealthBlockingStub healthStub;
25 |
26 | @Inject
27 | HealthService healthService;
28 |
29 | @Test
30 | void testHealth() {
31 | assertEquals(
32 | HealthCheckResponse.ServingStatus.SERVING,
33 | healthStub.check(HealthCheckRequest.newBuilder().build()).getStatus()
34 | );
35 |
36 | healthService.setStatus(HealthStatusManager.SERVICE_NAME_ALL_SERVICES, HealthCheckResponse.ServingStatus.NOT_SERVING);
37 |
38 | assertEquals(
39 | HealthCheckResponse.ServingStatus.NOT_SERVING,
40 | healthStub.check(HealthCheckRequest.newBuilder().build()).getStatus()
41 | );
42 | }
43 |
44 | @Factory
45 | static class HealthClients {
46 |
47 | @Bean
48 | HealthGrpc.HealthBlockingStub blockingStub(@GrpcChannel(GrpcServerChannel.NAME) ManagedChannel channel) {
49 | return HealthGrpc.newBlockingStub(channel);
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/test-suite-kotlin/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | alias(mn.plugins.kotlin.jvm)
3 | alias(mn.plugins.kotlin.kapt)
4 | alias(mn.plugins.kotlin.allopen)
5 | alias(libs.plugins.protobuf)
6 | id "io.micronaut.build.internal.grpc-minimal-test"
7 | }
8 |
9 | kotlin {
10 | jvmToolchain {
11 | languageVersion.set(JavaLanguageVersion.of(17))
12 | }
13 | }
14 |
15 | // tag::variables[]
16 | ext {
17 | grpcVersion = libs.versions.managed.grpc.asProvider().get()
18 | grpcKotlinVersion = libs.versions.managed.grpc.kotlin.get()
19 | protobufVersion = libs.versions.managed.protobuf.asProvider().get()
20 | }
21 | // end::variables[]
22 |
23 | mainClassName = "helloworld.Application"
24 | micronaut {
25 | version.set(libs.versions.micronaut.platform.get())
26 | coreVersion.set(libs.versions.micronaut.asProvider().get())
27 | testRuntime "junit5"
28 | enableNativeImage false
29 | processing {
30 | incremental(true)
31 | annotations("helloworld.*")
32 | }
33 | }
34 |
35 | dependencies {
36 | kapt mnValidation.micronaut.validation.processor
37 | implementation mnValidation.micronaut.validation
38 | implementation mn.kotlin.stdlib.jdk8
39 | implementation mn.kotlin.reflect
40 | implementation mn.kotlinx.coroutines.core
41 | implementation mn.micronaut.runtime
42 | implementation projects.micronautGrpcServerRuntime
43 | implementation mn.snakeyaml
44 |
45 | // tag::dependencies[]
46 | implementation libs.managed.grpc.kotlin.stub
47 | implementation libs.managed.grpc.services
48 | compileOnly libs.managed.grpc.stub
49 | compileOnly libs.managed.protobuf.java
50 | compileOnly libs.javax.annotation.api
51 | // end::dependencies[]
52 |
53 | runtimeOnly mnLogging.logback.classic
54 | runtimeOnly mn.jackson.module.kotlin
55 |
56 | testCompileOnly libs.javax.annotation.api
57 |
58 | testRuntimeOnly mnLogging.logback.classic
59 | testRuntimeOnly mn.jackson.module.kotlin
60 | }
61 |
62 | // tag::config[]
63 |
64 | sourceSets {
65 | main {
66 | java {
67 | srcDirs 'build/generated/source/proto/main/grpc'
68 | srcDirs 'build/generated/source/proto/main/grpckt'
69 | srcDirs 'build/generated/source/proto/main/java'
70 | }
71 | }
72 | }
73 |
74 | protobuf {
75 | protoc { artifact = "com.google.protobuf:protoc:$protobufVersion" }
76 | plugins {
77 | grpc { artifact = "io.grpc:protoc-gen-grpc-java:$grpcVersion" }
78 | grpckt { artifact = "io.grpc:protoc-gen-grpc-kotlin:${grpcKotlinVersion}:jdk8@jar" }
79 | }
80 | generateProtoTasks {
81 | all()*.plugins {
82 | grpc {}
83 | grpckt {}
84 | }
85 | }
86 | }
87 |
88 | // end::config[]
89 |
--------------------------------------------------------------------------------
/test-suite-kotlin/src/main/kotlin/helloworld/Application.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package helloworld
17 |
18 | import io.micronaut.runtime.Micronaut
19 |
20 | object Application {
21 |
22 | @JvmStatic
23 | fun main(args: Array) {
24 | Micronaut.build()
25 | .packages("helloworld")
26 | .mainClass(Application.javaClass)
27 | .start()
28 | }
29 | }
--------------------------------------------------------------------------------
/test-suite-kotlin/src/main/kotlin/helloworld/GreetingEndpoint.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package helloworld
17 |
18 | // tag::imports[]
19 | import jakarta.inject.Singleton
20 | // end::imports[]
21 |
22 | // tag::clazz[]
23 | @Singleton // <1>
24 | class GreetingEndpoint(val greetingService: GreetingService) : GreeterGrpcKt.GreeterCoroutineImplBase() { // <2>
25 | override suspend fun sayHello(request: HelloRequest): HelloReply {
26 | // <3>
27 | val message = greetingService.sayHello(request.name)
28 | val reply = HelloReply.newBuilder().setMessage(message).build()
29 | return reply
30 | }
31 | }
32 | // end::clazz[]
33 |
--------------------------------------------------------------------------------
/test-suite-kotlin/src/main/kotlin/helloworld/GreetingService.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package helloworld
17 |
18 | import jakarta.inject.Singleton
19 |
20 | @Singleton
21 | class GreetingService {
22 |
23 | fun sayHello(name: String): String {
24 | return "Hello $name"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/test-suite-kotlin/src/main/kotlin/helloworld/HealthService.kt:
--------------------------------------------------------------------------------
1 | package helloworld
2 |
3 | // tag::imports[]
4 | import io.grpc.health.v1.HealthCheckResponse.ServingStatus
5 | import io.grpc.protobuf.services.HealthStatusManager
6 | import jakarta.inject.Singleton
7 | // end::imports[]
8 |
9 | // tag::clazz[]
10 | @Singleton
11 | class HealthService(private val healthStatusManager: HealthStatusManager?) {
12 |
13 | fun setStatus(serviceName: String, status: ServingStatus) {
14 | healthStatusManager?.setStatus(serviceName, status)
15 | }
16 | }
17 | // end::clazz[]
18 |
--------------------------------------------------------------------------------
/test-suite-kotlin/src/main/proto/helloworld.proto:
--------------------------------------------------------------------------------
1 | // Copyright 2015 The gRPC Authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | syntax = "proto3";
15 |
16 | option java_multiple_files = true;
17 | option java_package = "helloworld";
18 | option java_outer_classname = "HelloWorldProto";
19 | option objc_class_prefix = "HLW";
20 |
21 | package helloworld;
22 |
23 | // The greeting service definition.
24 | service Greeter {
25 | // Sends a greeting
26 | rpc SayHello (HelloRequest) returns (HelloReply) {}
27 | }
28 |
29 | // The request message containing the user's name.
30 | message HelloRequest {
31 | string name = 1;
32 | }
33 |
34 | // The response message containing the greetings
35 | message HelloReply {
36 | string message = 1;
37 | }
--------------------------------------------------------------------------------
/test-suite-kotlin/src/main/resources/META-INF/native-image/io.micronaut.grpc/kotlin-runtime/native-image.properties:
--------------------------------------------------------------------------------
1 | # This comes in the next minor update of micronaut-kotlin, but we're still on 4.0.x here
2 | Args = --initialize-at-build-time=kotlin.annotation.AnnotationRetention,kotlin.annotation.AnnotationTarget,kotlin.coroutines.intrinsics.CoroutineSingletons
3 |
--------------------------------------------------------------------------------
/test-suite-kotlin/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | micronaut:
2 | application:
3 | name: helloworld
4 | # Uncomment to enable service discovery with Consul
5 | #consul:
6 | # client:
7 | # registration:
8 | # enabled: true
9 | # defaultZone: "${CONSUL_HOST:localhost}:${CONSUL_PORT:8500}"
10 |
--------------------------------------------------------------------------------
/test-suite-kotlin/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/test-suite-kotlin/src/test/kotlin/helloworld/GreetingServiceTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-2019 original authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package helloworld
17 |
18 | import io.grpc.ManagedChannel
19 | import io.micronaut.context.annotation.Factory
20 | import io.micronaut.grpc.annotation.GrpcChannel
21 | import io.micronaut.grpc.server.GrpcServerChannel
22 | import io.micronaut.test.extensions.junit5.annotation.MicronautTest
23 | import jakarta.inject.Inject
24 | import jakarta.inject.Singleton
25 | import kotlinx.coroutines.runBlocking
26 | import org.junit.jupiter.api.Assertions
27 | import org.junit.jupiter.api.Test
28 |
29 | @MicronautTest
30 | class GreetingServiceTest {
31 |
32 | @Inject
33 | lateinit var greetingClient: GreeterGrpcKt.GreeterCoroutineStub
34 |
35 | @Test
36 | fun testGreetingService() = runBlocking {
37 | Assertions.assertEquals(
38 | "Hello John",
39 | greetingClient.sayHello(
40 | HelloRequest.newBuilder().setName("John").build()
41 | ).message
42 | )
43 | }
44 | }
45 |
46 | @Factory
47 | class Clients {
48 | @Singleton
49 | fun greetingClient(@GrpcChannel(GrpcServerChannel.NAME) channel: ManagedChannel): GreeterGrpcKt.GreeterCoroutineStub {
50 | return GreeterGrpcKt.GreeterCoroutineStub(
51 | channel
52 | )
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/test-suite-kotlin/src/test/kotlin/helloworld/HealthCheckTest.kt:
--------------------------------------------------------------------------------
1 | package helloworld
2 |
3 | import io.grpc.Channel
4 | import io.grpc.health.v1.HealthCheckRequest
5 | import io.grpc.health.v1.HealthCheckResponse
6 | import io.grpc.health.v1.HealthGrpc
7 | import io.grpc.protobuf.services.HealthStatusManager
8 | import io.micronaut.context.annotation.Factory
9 | import io.micronaut.grpc.annotation.GrpcChannel
10 | import io.micronaut.grpc.server.GrpcServerChannel
11 | import io.micronaut.test.extensions.junit5.annotation.MicronautTest
12 | import jakarta.inject.Inject
13 | import jakarta.inject.Singleton
14 | import kotlinx.coroutines.runBlocking
15 | import org.junit.jupiter.api.Assertions
16 | import org.junit.jupiter.api.Test
17 |
18 | @MicronautTest
19 | class HealthCheckTest {
20 |
21 | @Inject
22 | lateinit var healthStub: HealthGrpc.HealthBlockingStub
23 |
24 | @Inject
25 | lateinit var healthService: HealthService
26 |
27 | @Test
28 | fun testHealthCheck() = runBlocking {
29 | Assertions.assertEquals(
30 | HealthCheckResponse.ServingStatus.SERVING,
31 | healthStub.check(HealthCheckRequest.newBuilder().build()).status
32 | )
33 |
34 | healthService.setStatus(
35 | HealthStatusManager.SERVICE_NAME_ALL_SERVICES,
36 | HealthCheckResponse.ServingStatus.NOT_SERVING
37 | )
38 |
39 | Assertions.assertEquals(
40 | HealthCheckResponse.ServingStatus.NOT_SERVING,
41 | healthStub.check(HealthCheckRequest.newBuilder().build()).status
42 | )
43 | }
44 | }
45 |
46 | @Factory
47 | class HealthClient {
48 |
49 | @Singleton
50 | fun healthClient(@GrpcChannel(GrpcServerChannel.NAME) channel: Channel): HealthGrpc.HealthBlockingStub =
51 | HealthGrpc.newBlockingStub(channel)
52 | }
53 |
--------------------------------------------------------------------------------