├── .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 ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── LICENSE ├── MAINTAINING.md ├── README.md ├── SECURITY.md ├── build.gradle ├── buildSrc ├── build.gradle ├── settings.gradle └── src │ └── main │ └── groovy │ ├── io.micronaut.build.internal.elasticsearch-base.gradle │ ├── io.micronaut.build.internal.elasticsearch-module.gradle │ ├── io.micronaut.build.internal.elasticsearch-native-tests.gradle │ └── io.micronaut.build.internal.elasticsearch-tests.gradle ├── config ├── HEADER ├── checkstyle │ ├── checkstyle.xml │ └── suppressions.xml └── spotless.license.java ├── elasticsearch-bom └── build.gradle.kts ├── elasticsearch ├── build.gradle.kts └── src │ ├── main │ └── java │ │ └── io │ │ └── micronaut │ │ └── elasticsearch │ │ ├── DefaultElasticsearchClientFactory.java │ │ ├── DefaultElasticsearchConfiguration.java │ │ ├── DefaultElasticsearchConfigurationProperties.java │ │ ├── DefaultHttpAsyncClientBuilderFactory.java │ │ ├── ElasticsearchSettings.java │ │ ├── conditon │ │ ├── RequiresElasticsearch.java │ │ └── package-info.java │ │ ├── convert │ │ ├── StringToHeaderConverter.java │ │ ├── StringToHttpHostConverter.java │ │ ├── StringToInetAddressConverter.java │ │ ├── StringToNodeSelectorConverter.java │ │ └── package-info.java │ │ ├── health │ │ └── ElasticsearchClientHealthIndicator.java │ │ └── package-info.java │ └── test │ ├── groovy │ └── io │ │ └── micronaut │ │ └── elasticsearch │ │ ├── DefaultElasticsearchConfigurationPropertiesSpec.groovy │ │ ├── ElasticsearchAuthorizationSpec.groovy │ │ ├── ElasticsearchMappingSpec.groovy │ │ └── health │ │ └── ElasticsearchClientHealthIndicatorSpec.groovy │ └── resources │ ├── application.properties │ └── logback.xml ├── gradle.properties ├── gradle ├── libs.versions.toml ├── license.gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle ├── src └── main │ └── docs │ └── guide │ ├── configuration.adoc │ ├── graalvm.adoc │ ├── healthChecks.adoc │ ├── introduction.adoc │ ├── releaseHistory.adoc │ ├── repository.adoc │ └── toc.yml ├── test-suite-groovy ├── build.gradle.kts └── src │ └── test │ ├── groovy │ └── io │ │ └── micronaut │ │ └── docs │ │ └── configuration │ │ └── elasticsearch │ │ └── ElasticsearchSpec.groovy │ └── resources │ └── logback.xml └── test-suite-java ├── build.gradle └── src └── test ├── java └── micronaut │ └── example │ ├── ElasticSearchTest.java │ ├── exception │ └── MovieServiceException.java │ └── service │ ├── Movie.java │ ├── MovieService.java │ └── MovieServiceImpl.java └── resources ├── application.yml └── logback.xml /.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@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 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 | -------------------------------------------------------------------------------- /.github/workflows/release.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: Release 7 | on: 8 | release: 9 | types: [published] 10 | jobs: 11 | release: 12 | outputs: 13 | artifacts-sha256: ${{ steps.hash.outputs.artifacts-sha256 }} # Computed hashes for build artifacts. 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v4 18 | with: 19 | token: ${{ secrets.GH_TOKEN }} 20 | - uses: gradle/wrapper-validation-action@v3 21 | - name: Set up JDK 22 | uses: actions/setup-java@v4 23 | with: 24 | distribution: 'temurin' 25 | java-version: '17' 26 | - name: Set the current release version 27 | id: release_version 28 | run: echo "release_version=${GITHUB_REF:11}" >> $GITHUB_OUTPUT 29 | - name: Run pre-release 30 | uses: micronaut-projects/github-actions/pre-release@master 31 | env: 32 | MICRONAUT_BUILD_EMAIL: ${{ secrets.MICRONAUT_BUILD_EMAIL }} 33 | with: 34 | token: ${{ secrets.GITHUB_TOKEN }} 35 | - name: Publish to Sonatype OSSRH 36 | id: publish 37 | env: 38 | SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} 39 | SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} 40 | GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }} 41 | GPG_PASSWORD: ${{ secrets.GPG_PASSWORD }} 42 | GPG_FILE: ${{ secrets.GPG_FILE }} 43 | DEVELOCITY_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} 44 | DEVELOCITY_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USERNAME }} 45 | DEVELOCITY_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }} 46 | run: | 47 | echo $GPG_FILE | base64 -d > secring.gpg 48 | # Publish both locally and to Sonatype. 49 | # The artifacts stored locally will be used to generate the SLSA provenance. 50 | ./gradlew publishAllPublicationsToBuildRepository publishToSonatype closeAndReleaseSonatypeStagingRepository 51 | # Read the current version from gradle.properties. 52 | VERSION=$(./gradlew properties | grep 'version:' | awk '{print $2}') 53 | # Read the project group from gradle.properties. 54 | GROUP_PATH=$(./gradlew properties| grep "projectGroup" | awk '{print $2}' | sed 's/\./\//g') 55 | echo "version=$VERSION" >> "$GITHUB_OUTPUT" 56 | echo "group=$GROUP_PATH" >> "$GITHUB_OUTPUT" 57 | - name: Generate subject 58 | id: hash 59 | run: | 60 | # Find the artifact JAR and POM files in the local repository. 61 | ARTIFACTS=$(find build/repo/${{ steps.publish.outputs.group }}/*/${{ steps.publish.outputs.version }}/* \ 62 | -type f \( \( -iname "*.jar" -not -iname "*-javadoc.jar" -not -iname "*-sources.jar" \) -or -iname "*.pom" \)) 63 | # Compute the hashes for the artifacts. 64 | # Set the hash as job output for debugging. 65 | echo "artifacts-sha256=$(sha256sum $ARTIFACTS | base64 -w0)" >> "$GITHUB_OUTPUT" 66 | # Store the hash in a file, which is uploaded as a workflow artifact. 67 | sha256sum $ARTIFACTS | base64 -w0 > artifacts-sha256 68 | - name: Upload build artifacts 69 | uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 70 | with: 71 | name: gradle-build-outputs 72 | path: build/repo/${{ steps.publish.outputs.group }}/*/${{ steps.publish.outputs.version }}/* 73 | retention-days: 5 74 | - name: Upload artifacts-sha256 75 | uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 76 | with: 77 | name: artifacts-sha256 78 | path: artifacts-sha256 79 | retention-days: 5 80 | - name: Generate docs 81 | run: ./gradlew docs 82 | env: 83 | DEVELOCITY_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} 84 | DEVELOCITY_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USERNAME }} 85 | DEVELOCITY_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }} 86 | GH_TOKEN_PUBLIC_REPOS_READONLY: ${{ secrets.GH_TOKEN_PUBLIC_REPOS_READONLY }} 87 | GH_USERNAME: ${{ secrets.GH_USERNAME }} 88 | - name: Export Gradle Properties 89 | uses: micronaut-projects/github-actions/export-gradle-properties@master 90 | - name: Publish to Github Pages 91 | if: success() 92 | uses: micronaut-projects/github-pages-deploy-action@master 93 | env: 94 | BETA: ${{ !(github.event.release.target_commitish == github.event.repository.default_branch) || contains(steps.release_version.outputs.release_version, 'M') || contains(steps.release_version.outputs.release_version, 'RC') }} 95 | GH_TOKEN: ${{ secrets.GH_TOKEN }} 96 | BRANCH: gh-pages 97 | FOLDER: build/docs 98 | VERSION: ${{ steps.release_version.outputs.release_version }} 99 | TARGET_REPOSITORY: ${{ github.repository == 'micronaut-projects/micronaut-core' && env.docsRepository || github.repository }} 100 | DEVELOCITY_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} 101 | DEVELOCITY_CACHE_USERNAME: ${{ secrets.GRADLE_ENTERPRISE_CACHE_USERNAME }} 102 | DEVELOCITY_CACHE_PASSWORD: ${{ secrets.GRADLE_ENTERPRISE_CACHE_PASSWORD }} 103 | - name: Run post-release 104 | if: success() 105 | uses: micronaut-projects/github-actions/post-release@master 106 | env: 107 | MICRONAUT_BUILD_EMAIL: ${{ secrets.MICRONAUT_BUILD_EMAIL }} 108 | with: 109 | token: ${{ secrets.GITHUB_TOKEN }} 110 | 111 | provenance-subject: 112 | needs: [release] 113 | runs-on: ubuntu-latest 114 | outputs: 115 | artifacts-sha256: ${{ steps.set-hash.outputs.artifacts-sha256 }} 116 | steps: 117 | - name: Download artifacts-sha256 118 | uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 119 | with: 120 | name: artifacts-sha256 121 | # The SLSA provenance generator expects the hash digest of artifacts to be passed as a job 122 | # output. So we need to download the artifacts-sha256 and set it as job output. The hash of 123 | # the artifacts should be set as output directly in the release job. But due to a known bug 124 | # in GitHub Actions we have to use a workaround. 125 | # See https://github.com/community/community/discussions/37942. 126 | - name: Set artifacts-sha256 as output 127 | id: set-hash 128 | shell: bash 129 | run: echo "artifacts-sha256=$(cat artifacts-sha256)" >> "$GITHUB_OUTPUT" 130 | 131 | provenance: 132 | needs: [release, provenance-subject] 133 | permissions: 134 | actions: read # To read the workflow path. 135 | id-token: write # To sign the provenance. 136 | contents: write # To add assets to a release. 137 | uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0 138 | with: 139 | base64-subjects: "${{ needs.provenance-subject.outputs.artifacts-sha256 }}" 140 | upload-assets: true # Upload to a new release. 141 | compile-generator: true # Build the generator from source. 142 | 143 | github_release: 144 | needs: [release, provenance] 145 | runs-on: ubuntu-latest 146 | if: startsWith(github.ref, 'refs/tags/') 147 | steps: 148 | - name: Checkout repository 149 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 150 | - name: Download artifacts 151 | uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 152 | with: 153 | name: gradle-build-outputs 154 | path: build/repo 155 | - name: Create artifacts archive 156 | shell: bash 157 | run: | 158 | find build/repo -type f \( \( -iname "*.jar" -not -iname "*-javadoc.jar" -not \ 159 | -iname "*-sources.jar" \) -or -iname "*.pom" \) | xargs zip artifacts.zip 160 | - name: Upload assets 161 | # Upload the artifacts to the existing release. Note that the SLSA provenance will 162 | # attest to each artifact file and not the aggregated ZIP file. 163 | uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2 164 | with: 165 | files: artifacts.zip 166 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Code or Documentation to Micronaut 2 | 3 | Sign the [Contributor License Agreement (CLA)](https://cla-assistant.io/micronaut-projects/micronaut-project-template). This is required before any of your code or pull-requests are accepted. 4 | 5 | ## Finding Issues to Work on 6 | 7 | If you are interested in contributing to Micronaut and are looking for issues to work on, take a look at the issues tagged with [help wanted](https://github.com/micronaut-projects/micronaut-elasticsearch/issues?q=is%3Aopen+is%3Aissue+label%3A%22status%3A+help+wanted%22). 8 | 9 | ## JDK Setup 10 | 11 | Micronaut Elasticsearch currently requires JDK 8. 12 | 13 | ## IDE Setup 14 | 15 | Micronaut Elasticsearch can be imported into IntelliJ IDEA by opening the `build.gradle` file. 16 | 17 | ## Docker Setup 18 | 19 | Micronaut Elasticsearch tests currently require Docker to be installed. 20 | 21 | ## Running Tests 22 | 23 | To run the tests, use `./gradlew check`. 24 | 25 | ## Building Documentation 26 | 27 | The documentation sources are located at `src/main/docs/guide`. 28 | 29 | To build the documentation, run `./gradlew publishGuide` (or `./gradlew pG`), then open `build/docs/index.html` 30 | 31 | To also build the Javadocs, run `./gradlew docs`. 32 | 33 | ## Working on the code base 34 | 35 | If you use IntelliJ IDEA, you can import the project using the Intellij Gradle Tooling ("File / Import Project" and selecting the "settings.gradle" file). 36 | 37 | To get a local development version of Micronaut Elasticsearch working, first run the `publishToMavenLocal` task. 38 | 39 | ``` 40 | ./gradlew pTML 41 | ``` 42 | 43 | You can then reference the version specified with `projectVersion` in `gradle.properties` in a test project's `build.gradle` or `pom.xml`. If you use Gradle, add the `mavenLocal` repository (Maven automatically does this): 44 | 45 | ``` 46 | repositories { 47 | mavenLocal() 48 | mavenCentral() 49 | } 50 | ``` 51 | 52 | ## Creating a pull request 53 | 54 | Once you are satisfied with your changes: 55 | 56 | - Commit your changes in your local branch 57 | - Push your changes to your remote branch on GitHub 58 | - Send us a [pull request](https://help.github.com/articles/creating-a-pull-request) 59 | 60 | ## Checkstyle 61 | 62 | We want to keep the code clean, following good practices about organization, Javadoc, and style as much as possible. 63 | 64 | Micronaut Elasticsearch uses [Checkstyle](https://checkstyle.sourceforge.io/) to make sure that the code follows those standards. The configuration is defined in `config/checkstyle/checkstyle.xml`. To execute Checkstyle, run: 65 | 66 | ``` 67 | ./gradlew :checkstyleMain 68 | ``` 69 | 70 | Before starting to contribute new code we recommended that you install the IntelliJ [CheckStyle-IDEA](https://plugins.jetbrains.com/plugin/1065-checkstyle-idea) plugin and configure it to use Micronaut's checkstyle configuration file. 71 | 72 | IntelliJ will mark in red the issues Checkstyle finds. For example: 73 | 74 | ![](https://github.com/micronaut-projects/micronaut-core/raw/master/src/main/docs/resources/img/checkstyle-issue.png) 75 | 76 | In this case, to fix the issues, we need to: 77 | 78 | - Add one empty line before `package` in line 16 79 | - Add the Javadoc for the constructor in line 27 80 | - Add an space after `if` in line 34 81 | 82 | The plugin also adds a new tab in the bottom of the IDE to run Checkstyle and show errors and warnings. We recommend that you run the report and fix all issues before submitting a pull request. 83 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | https://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /MAINTAINING.md: -------------------------------------------------------------------------------- 1 | # Micronaut module maintenance tasks 2 | 3 | ## Triage incoming issues 4 | 5 | New issues need to be categorised. At least with one of the following labels: 6 | 7 | * `type: bug`: when something is not working as designed. 8 | * `type: improvement`: a minor improvement over an existing feature. 9 | * `type: enhancement`: a completely new feature. 10 | * `type: docs`: documentation change. 11 | 12 | There are other labels that are useful for changelog generation: 13 | 14 | * `type: breaking`. 15 | * `type: deprecated`. 16 | * `type: removed`. 17 | 18 | Issues with the above labels will show up in their own section in the changelog. 19 | 20 | Sometimes, before accepting bugs, we need to ask more information to the requester, or need to validate ourselves that it 21 | is actually a bug. There are some labels to help with these situations: 22 | 23 | * `status: awaiting feedback`: used to mark that we are waiting for more information to the user. 24 | * `status: awaiting validation`: we need to validate ourselves that it is actually an issue. 25 | * `status: awaiting third-party`: the issue is blocked by another bug in a third-party library 26 | 27 | Note that when the blockers are cleared, the awaiting labels need to be manually removed. There are some other labels 28 | around this: 29 | 30 | * `status: validated`: the issue is ready to be being worked on. 31 | * `status: acknowledged` (possibly duplicate?). 32 | * `status: in progress`: (could be removed, we assign issues to mark them being worked on) 33 | 34 | There are sometimes where we are not sure whether we want or can solve an issue. The labels about this are: 35 | 36 | * `status: under consideration`: the issue is being considered, but has not been accepted yet. 37 | * `status: future consideration`: we won't fix it now (because either we can't or we don't want to), but this can be 38 | revisited in the future. 39 | * `status: next major version`: it is a breaking change and therefore needs to be implemented in the next major version. 40 | 41 | There are also a bunch of `relates-to` labels that can be used to further categorise issues. This is helpful in projects 42 | with a lot of issues, or projects where different people work on different parts or modules. 43 | 44 | The majority of the issues are defined in the 45 | [management](https://github.com/micronaut-projects/management/blob/master/labels.tf) repo, and propagated via Terraform. 46 | If you want new labels: 47 | 48 | * If they can be beneficial to several repos, send a pull request to the management repo. 49 | * If they are repo-specific, just go ahead and create them with the GitHub UI. 50 | 51 | Finally, issues (especially bugs) should be prioritised with either `priority: high`, `priority: medium` or 52 | `priority: low`. Checkout the 53 | [Issue Priority Labels](https://github.com/micronaut-projects/micronaut-core/wiki/Issue-Priority-Labels) document for 54 | guidelines about when to use each of them. 55 | 56 | ## Review pull requests 57 | 58 | Pull requests, regardless of whether they are created by internal or external contributors, should meet the following 59 | criteria: 60 | 61 | * All the GitHub checks are passing (CLA signed and builds passing). 62 | * Code has a minimum quality, it uses the Micronaut APIs correctly, doesn't contain bad smells, etc. Essentially, the 63 | type of things you would review in every other software project. 64 | * Contains tests. 65 | * Includes documentation. 66 | * If it closes any issues, 67 | [they should be linked](https://docs.github.com/en/free-pro-team@latest/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue) 68 | either using closing keywords, or manually. 69 | 70 | Regarding the target branch, backwards-compatible bug fixes and improvements typically target the default branch, 71 | backwards-compatible enhancements target the next minor version branch, and breaking changes target the next major version 72 | branch. Check the 73 | [Micronaut Module Versioning](https://github.com/micronaut-projects/micronaut-core/wiki/Micronaut-Module-Versioning) 74 | document for more information. 75 | 76 | Before merging pull requests, it is really important to ensure they target the correct branch, so that in the next 77 | patch/minor release we don't leak breaking changes. Check the 78 | [Micronaut Module Branch Naming](https://github.com/micronaut-projects/micronaut-core/wiki/Micronaut-Module-Branch-Naming) 79 | document for more information. 80 | 81 | Note that 82 | [Micronaut Core and Starter](https://github.com/micronaut-projects/micronaut-core/wiki/Micronaut-Core-and-Starter-Branching-Strategy) 83 | follow a slightly different strategy. 84 | 85 | ### Automated pull requests 86 | 87 | #### Dependency upgrades 88 | 89 | All Micronaut repos have 2 dependency upgrade checking mechanism: 90 | 91 | 1. Renovate: it has the advantage that it performs dependency upgrades not only on build dependencies, but also on 92 | GitHub Actions workflows. On the other hand, its biggest downside is that it's unable to find newer versions for 93 | those defined in `gradle.properties`. It will also send different PRs for the same version upgrade if the artifact ID 94 | is different. For example, if you have `com.example:client:1.0` and `com.example:server:1.0`, and a new 1.1 version 95 | arrives for both, it will send 2 PRs, where they should both be upgraded at the same time. 96 | 97 | 2. To overcome those disadvantages, we have our own dependency upgrade solution based on the 98 | [Gradle Use Latest Versions Plugin](https://github.com/patrikerdes/gradle-use-latest-versions-plugin). It runs daily 99 | during weekdays. 100 | 101 | The consequence of having both approaches in place is that we get multiple dependency upgrade PRs: one created by 102 | `micronaut-build` via our automation, and one or many (one per dependency) created by Renovate. When merging those, it 103 | is better to prefer the `micronaut-build` ones, if possible, for 2 reasons: a) they attempt to upgrade multiple dependencies 104 | in a single PR, which creates less noise in the Git history; b) Once you merge that, Renovate will react and automatically 105 | close its own PRs if the dependency is up-to-date. 106 | 107 | When an upgrade to a new version arrives, we need to be careful when merging, so that we don't introduce an 108 | unnecessary upgrade burden on our users. Read the 109 | [Module Upgrade Strategy](https://github.com/micronaut-projects/micronaut-core/wiki/Module-Upgrade-Strategy) for more 110 | information. 111 | 112 | Note that if a new version arrives, and we are not ready yet to do the upgrade, you need to 113 | [pin the old version](https://github.com/micronaut-projects/micronaut-build/#configuration-options), because otherwise, 114 | Renovate and our workflow will keep sending PRs. You should also create an issue to upgrade so that it's not forgotten. 115 | 116 | #### Files sync 117 | 118 | We have a [template repo](https://github.com/micronaut-projects/micronaut-project-template) that we use as the single 119 | source of truth for certain files. It is used as a template to create new repos, and changes to certain files in the 120 | template repo will get propagated automatically. The files propagated are: 121 | 122 | * Workflow files (`.github/workflows/*`). They are copied using rsync" 123 | * `central-sync.yml`. 124 | * `dependency-update.yml`. 125 | * `graalvm.yml`. 126 | * `gradle.yml`. 127 | * `release.yml`. 128 | * `release-notes.yml`. 129 | * Renovate configuration (`.github/renovate.json`). 130 | * Gradle wrapper. 131 | * `.gitignore`. 132 | * `ISSUE_TEMPLATE.md`, `LICENSE`, `MAINTAINING.md`, `config/HEADER` and `config/spotless.license.java`. 133 | * Checkstyle's `config/checkstyle/checkstyle.xml` and `config/checkstyle/suppressions.xml`. 134 | 135 | Regarding the Gradle wrapper, the template repo checks every week if there is a new Gradle version. If there is, it will 136 | upgrade the wrapper in the template repo itself, and via the files sync workflow this gets propagated to all repos. This 137 | way we make sure we stay up-to-date regarding Gradle versions in all repos. 138 | 139 | ##### Customised workflow files 140 | 141 | Due to limitations in the GitHub Actions design (such that they don't allow including snippets or any other kind of 142 | reusability), for the sync'ed workflow files listed above, it is not possible to have custom steps and still be part of 143 | the sync process, since any modification to those files will be overwritten the next time the files sync workflow is 144 | executed. 145 | 146 | The "Java CI" (`gradle.yml`) workflow does have the ability to have an optional setup step, though. If there is a `setup.sh` 147 | file in the project root, it will be executed before invoking Gradle. 148 | 149 | There are projects, such as micronaut-gcp and micronaut-kubernetes, that have made customisations to sync'ed workflows 150 | because it's absolutely necessary. In those projects, the sync pull requests are manually merged so that the customisations 151 | aren't lost. 152 | 153 | Note that it is perfectly possible to have new workflows that aren't part of the sync process. 154 | 155 | ## Releases 156 | 157 | The release process is highly automated and normally involves just publishing a GitHub release. But before you get there, 158 | there are some parts you need to understand first. 159 | 160 | First of all, all the repos have an automatic changelog generation mechanism: when a change is made to the repo 161 | (a push event), it creates (or updates if there is already one) a draft release, calculating the next patch version. The 162 | release notes will contain pull requests merged and issues closed since the last release. 163 | 164 | When the module is ready for a new release, check the generated release notes, and make changes if needed (for example, 165 | you can add an introduction paragraph highlighting some items included in the release). If the version you are going to 166 | publish is not a new patch version, but a new minor or major, update the release notes text to reflect the new version. 167 | If you are publishing a milestone or release candidate, check the pre-release checkbox. 168 | 169 | Note that the release tags must be preceded with `v`, e.g.: `v1.2.3`. 170 | 171 | Once you publish the GitHub release, the 172 | [Release GitHub Action workflow](https://github.com/micronaut-projects/micronaut-project-template/blob/master/.github/workflows/release.yml) 173 | will kick off, performing the following steps: 174 | 175 | * Pre-release: sets the `projectVersion` property in `gradle.properties` to the release version, and commit and pushes 176 | the result. 177 | * Generates documentation guide and publishes it to the `gh-pages` branch. 178 | * Sends a pull request to Core to update the BOM. 179 | * Post-release: 180 | * Determines the next patch version, and sets it as a `SNAPSHOT` version. 181 | * Closes the milestone that matches the release version, and creates a new one for the next patch. 182 | 183 | If everything goes well, you now need to manually trigger the Maven Central publishing workflow via the GitHub UI. 184 | 185 | If there is an issue with the release, it's important not to trigger the Maven Central publishing workflow because once 186 | we publish a version to Maven Central we cannot change or remove it anymore. 187 | 188 | There are some properties in `gradle.properties` that affect the release process: 189 | 190 | * `githubBranch`: the current branch, usually `master`. 191 | * `githubCoreBranch`: the Micronaut Core branch where the BOM update pull requests will be sent to. 192 | * `bomProperty`: in Micronaut Core's `gradle.properties`, the property that represents this module's version. 193 | * `bomProperties`: if needed, additional properties for the BOM pull request. 194 | 195 | For example, assuming a module has the release `1.0.0` as the latest version published, which was included in the 196 | Micronaut `2.2.0` BOM. If the next version you want to publish is: 197 | 198 | * A new patch release (`1.0.1`): simply publish the existing draft release. 199 | * A new minor release (`1.1.0`): 200 | * Before the release, push a `1.0.x` branch off `master`. 201 | * Bump the version in master to `1.1.0-SNAPSHOT`. 202 | * Set the `githubCoreBranch` property to `2.3.x` (or `3.0.x` if it will be the next one). 203 | * Edit the draft release setting the version to `1.1.0` in the release title, body, tag, etc. 204 | * Publish the release. 205 | * A new major release (`2.0.0`): 206 | * Before the release, push a `1.0.x` branch off `master`. 207 | * Bump the version in master to `2.0.0-SNAPSHOT`. 208 | * Set the `githubCoreBranch` property to `3.0.x` (or `2.3.x` if this new major version doesn't introduce breaking changes). 209 | * Edit the draft release setting the version to `2.0.0` in the release title, body, tag, etc. 210 | * Publish the release. 211 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Micronaut Elasticsearch Configuration 2 | 3 | [![Maven Central](https://img.shields.io/maven-central/v/io.micronaut.elasticsearch/micronaut-elasticsearch.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22io.micronaut.elasticsearch%22%20AND%20a:%22micronaut-elasticsearch%22) 4 | [![Build Status](https://github.com/micronaut-projects/micronaut-elasticsearch/workflows/Java%20CI/badge.svg)](https://github.com/micronaut-projects/micronaut-elasticsearch/actions) 5 | [![Revved up by Develocity](https://img.shields.io/badge/Revved%20up%20by-Develocity-06A0CE?logo=Gradle&labelColor=02303A)](https://ge.micronaut.io/scans) 6 | 7 | Micronaut Elasticsearch includes integration between [Micronaut](https://micronaut.io/) and [Elasticsearch](https://www.elastic.co/). 8 | 9 | ## Documentation 10 | 11 | See the [Documentation](https://micronaut-projects.github.io/micronaut-elasticsearch/latest/guide/) for more information. 12 | 13 | See the [Snapshot Documentation](https://micronaut-projects.github.io/micronaut-elasticsearch/snapshot/guide/) for the current development docs. 14 | 15 | ## Snapshots and Releases 16 | 17 | Snapshots are automatically published to [Sonatype Snapshots](https://s01.oss.sonatype.org/content/repositories/snapshots/io/micronaut/) using [Github Actions](https://github.com/micronaut-projects/micronaut-elasticsearch/actions). 18 | 19 | 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. 20 | 21 | Releases are published to Maven Central via [Github Actions](https://github.com/micronaut-projects/micronaut-elasticsearch/actions). 22 | 23 | Releases are completely automated. To perform a release use the following steps: 24 | 25 | * [Publish the draft release](https://github.com/micronaut-projects/micronaut-elasticsearch/releases). There should be already a draft release created, edit and publish it. The Git Tag should start with `v`. For example `v1.0.0`. 26 | * [Monitor the Workflow](https://github.com/micronaut-projects/micronaut-elasticsearch/actions?query=workflow%3ARelease) to check it passed successfully. 27 | * If everything went fine, [publish to Maven Central](https://github.com/micronaut-projects/micronaut-elasticsearch/actions?query=workflow%3A"Maven+Central+Sync"). 28 | * 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.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 | -------------------------------------------------------------------------------- /buildSrc/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'groovy-gradle-plugin' 3 | } 4 | 5 | repositories { 6 | gradlePluginPortal() 7 | mavenCentral() 8 | } 9 | 10 | dependencies { 11 | implementation libs.gradle.micronaut 12 | implementation(libs.sonatype.scan) 13 | } 14 | -------------------------------------------------------------------------------- /buildSrc/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'elasticsearch-parent' 2 | dependencyResolutionManagement { 3 | versionCatalogs { 4 | libs { 5 | from(files("../gradle/libs.versions.toml")) 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /buildSrc/src/main/groovy/io.micronaut.build.internal.elasticsearch-base.gradle: -------------------------------------------------------------------------------- 1 | repositories { 2 | mavenCentral() 3 | } 4 | 5 | configurations.all { 6 | resolutionStrategy.preferProjectModules() 7 | } 8 | -------------------------------------------------------------------------------- /buildSrc/src/main/groovy/io.micronaut.build.internal.elasticsearch-module.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "io.micronaut.build.internal.elasticsearch-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 | if (sonatypePluginConfigured) { 10 | ossIndexAudit { 11 | username = ossIndexUsername 12 | password = ossIndexPassword 13 | excludeCompileOnly = true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /buildSrc/src/main/groovy/io.micronaut.build.internal.elasticsearch-native-tests.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "io.micronaut.build.internal.elasticsearch-tests" 3 | id 'org.graalvm.buildtools.native' 4 | } 5 | 6 | graalvmNative { 7 | toolchainDetection = false 8 | metadataRepository { 9 | enabled = true 10 | } 11 | binaries { 12 | all { 13 | resources.autodetect() 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /buildSrc/src/main/groovy/io.micronaut.build.internal.elasticsearch-tests.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "io.micronaut.build.internal.elasticsearch-base" 3 | } 4 | 5 | tasks.named("test") { 6 | useJUnitPlatform() 7 | systemProperty("elasticsearch.version", libs.versions.managed.elasticsearch.get()) 8 | } 9 | 10 | java { 11 | sourceCompatibility = JavaVersion.toVersion("17") 12 | targetCompatibility = JavaVersion.toVersion("17") 13 | } 14 | -------------------------------------------------------------------------------- /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/checkstyle.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 33 | 34 | 35 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | -------------------------------------------------------------------------------- /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 | */ -------------------------------------------------------------------------------- /elasticsearch-bom/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("io.micronaut.build.internal.bom") 3 | } 4 | micronautBuild { 5 | micronautBuild { 6 | // required because elasticsearch-rest-high-level-client was removed 7 | tasks.named("checkVersionCatalogCompatibility") { onlyIf { false } } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /elasticsearch/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("io.micronaut.build.internal.elasticsearch-module") 3 | } 4 | 5 | dependencies { 6 | annotationProcessor(mn.micronaut.graal) 7 | 8 | compileOnly(libs.graal.svm) 9 | implementation(mn.micronaut.management) 10 | api(libs.managed.elasticsearch.java) { 11 | exclude(group="org.elasticsearch.client", module = "elasticsearch-rest-client") 12 | } 13 | implementation(libs.managed.elasticsearch.rest.client) { 14 | exclude(group="commons-logging", module = "commons-logging") 15 | } 16 | runtimeOnly(mnLogging.slf4j.jcl.over.slf4j) 17 | api(mn.micronaut.http) 18 | 19 | implementation(mn.micronaut.jackson.databind) 20 | 21 | testImplementation(mnTestResources.testcontainers.elasticsearch) 22 | testImplementation(mn.groovy.json) 23 | testImplementation(mnSecurity.micronaut.security) 24 | testImplementation(mn.reactor) 25 | } 26 | 27 | 28 | tasks { 29 | named("test") { 30 | systemProperty("elasticsearch.version", libs.versions.managed.elasticsearch.get()) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /elasticsearch/src/main/java/io/micronaut/elasticsearch/DefaultElasticsearchClientFactory.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.elasticsearch; 17 | 18 | import io.micronaut.context.annotation.Bean; 19 | import io.micronaut.context.annotation.Factory; 20 | import io.micronaut.context.annotation.Requires; 21 | import io.micronaut.core.util.ArrayUtils; 22 | import jakarta.inject.Singleton; 23 | 24 | import com.fasterxml.jackson.databind.ObjectMapper; 25 | 26 | import org.elasticsearch.client.RestClient; 27 | import org.elasticsearch.client.RestClientBuilder; 28 | 29 | import co.elastic.clients.elasticsearch.ElasticsearchAsyncClient; 30 | import co.elastic.clients.elasticsearch.ElasticsearchClient; 31 | import co.elastic.clients.json.jackson.JacksonJsonpMapper; 32 | import co.elastic.clients.transport.ElasticsearchTransport; 33 | import co.elastic.clients.transport.rest_client.RestClientTransport; 34 | 35 | /** 36 | * The default Factory for creating Elasticsearch client. 37 | * 38 | * @author lishuai 39 | * @author Puneet Behl 40 | * @since 1.0.0 41 | */ 42 | @Requires(beans = DefaultElasticsearchConfigurationProperties.class) 43 | @Factory 44 | public class DefaultElasticsearchClientFactory { 45 | 46 | /** 47 | * @param elasticsearchConfiguration The {@link DefaultElasticsearchConfigurationProperties} object 48 | * @return The Elasticsearch Rest Client 49 | */ 50 | @Bean(preDestroy = "close") 51 | RestClient restClient(DefaultElasticsearchConfigurationProperties elasticsearchConfiguration) { 52 | return restClientBuilder(elasticsearchConfiguration).build(); 53 | } 54 | 55 | /** 56 | * @param transport The {@link ElasticsearchTransport} object. 57 | * @return The ElasticsearchClient. 58 | * @since 4.2.0 59 | */ 60 | @Singleton 61 | ElasticsearchClient elasticsearchClient(ElasticsearchTransport transport) { 62 | return new ElasticsearchClient(transport); 63 | } 64 | 65 | /** 66 | * @param transport The {@link ElasticsearchTransport} object. 67 | * @return The ElasticsearchAsyncClient. 68 | * @since 4.2.0 69 | */ 70 | @Singleton 71 | ElasticsearchAsyncClient elasticsearchAsyncClient(ElasticsearchTransport transport) { 72 | return new ElasticsearchAsyncClient(transport); 73 | } 74 | 75 | /** 76 | * @param elasticsearchConfiguration The {@link DefaultElasticsearchConfigurationProperties} object. 77 | * @param objectMapper The {@link ObjectMapper} object. 78 | * @return The {@link ElasticsearchTransport}. 79 | * @since 4.2.0 80 | */ 81 | @Singleton 82 | @Bean(preDestroy = "close") 83 | ElasticsearchTransport elasticsearchTransport(DefaultElasticsearchConfigurationProperties elasticsearchConfiguration, ObjectMapper objectMapper) { 84 | RestClient restClient = restClientBuilder(elasticsearchConfiguration).build(); 85 | 86 | ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper(objectMapper)); 87 | return transport; 88 | } 89 | 90 | /** 91 | * @param elasticsearchConfiguration The {@link DefaultElasticsearchConfigurationProperties} object 92 | * @return The {@link RestClientBuilder} 93 | */ 94 | protected RestClientBuilder restClientBuilder(DefaultElasticsearchConfigurationProperties elasticsearchConfiguration) { 95 | RestClientBuilder builder = RestClient.builder(elasticsearchConfiguration.getHttpHosts()) 96 | .setRequestConfigCallback(requestConfigBuilder -> { 97 | requestConfigBuilder = elasticsearchConfiguration.requestConfigBuilder; 98 | return requestConfigBuilder; 99 | }) 100 | .setHttpClientConfigCallback(httpClientBuilder -> { 101 | httpClientBuilder = elasticsearchConfiguration.httpAsyncClientBuilder; 102 | return httpClientBuilder; 103 | }); 104 | 105 | if (ArrayUtils.isNotEmpty(elasticsearchConfiguration.getDefaultHeaders())) { 106 | builder.setDefaultHeaders(elasticsearchConfiguration.getDefaultHeaders()); 107 | } 108 | 109 | return builder; 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /elasticsearch/src/main/java/io/micronaut/elasticsearch/DefaultElasticsearchConfiguration.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.elasticsearch; 17 | 18 | import org.apache.http.Header; 19 | import org.apache.http.HttpHost; 20 | import org.apache.http.client.config.RequestConfig; 21 | import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; 22 | import org.elasticsearch.client.NodeSelector; 23 | 24 | /** 25 | * Elasticsearch Configuration. 26 | * 27 | * @author Puneet Behl 28 | * @since 1.0.0 29 | */ 30 | public interface DefaultElasticsearchConfiguration { 31 | 32 | /** 33 | * The one or more hosts that the client will communicate with, provided as instances of {@link HttpHost}. 34 | * 35 | * @return An array of {@link HttpHost} 36 | */ 37 | HttpHost[] getHttpHosts(); 38 | 39 | /** 40 | * The default headers that need to be sent with each request, to prevent having to 41 | * specify them with each single request. 42 | * 43 | * @return An array of {@link Header}. 44 | */ 45 | Header[] getDefaultHeaders(); 46 | 47 | /** 48 | * The timeout that should be honoured in case multiple attempts are made for the same request. 49 | * The default value is 30 seconds. 50 | * 51 | * @return The maximum retry timeout in millis. 52 | */ 53 | int getMaxRetryTimeoutMillis(); 54 | 55 | /** 56 | * The node selector to be used to filter the nodes the client will send requests to among the 57 | * ones that are set to the client itself. By default the client sends requests to every configured node. 58 | * 59 | * @return The {@link NodeSelector} to be used. 60 | */ 61 | NodeSelector getNodeSelector(); 62 | 63 | /** 64 | * @return The builder to create default request configurations. 65 | */ 66 | RequestConfig.Builder getRequestConfigBuilder(); 67 | 68 | /** 69 | * The http client configuration (e.g. encrypted communication over ssl, or anything that 70 | * the {@link HttpAsyncClientBuilder} allows to set). 71 | * 72 | * @return The {@link HttpAsyncClientBuilder} bean 73 | */ 74 | HttpAsyncClientBuilder getHttpAsyncClientBuilder(); 75 | 76 | } 77 | -------------------------------------------------------------------------------- /elasticsearch/src/main/java/io/micronaut/elasticsearch/DefaultElasticsearchConfigurationProperties.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.elasticsearch; 17 | 18 | import io.micronaut.context.annotation.ConfigurationBuilder; 19 | import io.micronaut.context.annotation.ConfigurationProperties; 20 | import io.micronaut.context.annotation.Requires; 21 | import org.apache.http.Header; 22 | import org.apache.http.HttpHost; 23 | import org.apache.http.client.config.RequestConfig; 24 | import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; 25 | import org.elasticsearch.client.NodeSelector; 26 | import org.elasticsearch.client.RestClientBuilder; 27 | 28 | import jakarta.inject.Inject; 29 | import java.util.Collections; 30 | 31 | /** 32 | * Default configurations for Elasticsearch. 33 | * 34 | * @author lishuai 35 | * @author Puneet Behl 36 | * @since 1.0.0 37 | */ 38 | @Requires(classes = RestClientBuilder.class) 39 | @ConfigurationProperties(ElasticsearchSettings.PREFIX) 40 | public class DefaultElasticsearchConfigurationProperties implements DefaultElasticsearchConfiguration { 41 | 42 | @SuppressWarnings("WeakerAccess") 43 | protected HttpAsyncClientBuilder httpAsyncClientBuilder; 44 | 45 | /** 46 | * The default request configurations. 47 | */ 48 | @ConfigurationBuilder(configurationPrefix = "request.default") 49 | @SuppressWarnings("WeakerAccess") 50 | protected RequestConfig.Builder requestConfigBuilder = RequestConfig.custom(); 51 | 52 | private int maxRetryTimeoutMillis; 53 | private NodeSelector nodeSelector; 54 | private HttpHost[] httpHosts = Collections.singletonList(ElasticsearchSettings.DEFAULT_HOST).toArray(new HttpHost[1]); 55 | private Header[] defaultHeaders; 56 | 57 | @Override 58 | public HttpHost[] getHttpHosts() { 59 | return this.httpHosts; 60 | } 61 | 62 | @Override 63 | public Header[] getDefaultHeaders() { 64 | return this.defaultHeaders; 65 | } 66 | 67 | @Override 68 | public int getMaxRetryTimeoutMillis() { 69 | return this.maxRetryTimeoutMillis; 70 | } 71 | 72 | @Override 73 | public NodeSelector getNodeSelector() { 74 | return this.nodeSelector; 75 | } 76 | 77 | @Override 78 | public RequestConfig.Builder getRequestConfigBuilder() { 79 | return this.requestConfigBuilder; 80 | } 81 | 82 | @Override 83 | public HttpAsyncClientBuilder getHttpAsyncClientBuilder() { 84 | return httpAsyncClientBuilder; 85 | } 86 | 87 | /** 88 | * @param httpHosts One or more hosts that client will connect to. 89 | */ 90 | public void setHttpHosts(HttpHost[] httpHosts) { 91 | this.httpHosts = httpHosts; 92 | } 93 | 94 | /** 95 | * @param defaultHeaders The defaults {@link Header} to sent with each request. 96 | */ 97 | public void setDefaultHeaders(Header[] defaultHeaders) { 98 | this.defaultHeaders = defaultHeaders; 99 | } 100 | 101 | /** 102 | * @param maxRetryTimeoutMillis The maximum retry timeout in millis. 103 | */ 104 | public void setMaxRetryTimeoutMillis(int maxRetryTimeoutMillis) { 105 | this.maxRetryTimeoutMillis = maxRetryTimeoutMillis; 106 | } 107 | 108 | /** 109 | * @param nodeSelector The {@link NodeSelector} to be used, in case of multiple nodes. 110 | */ 111 | public void setNodeSelector(NodeSelector nodeSelector) { 112 | this.nodeSelector = nodeSelector; 113 | } 114 | 115 | /** 116 | * @param httpAsyncClientBuilder The {@link HttpAsyncClientBuilder} bean 117 | */ 118 | @Inject 119 | public void setHttpAsyncClientBuilder(HttpAsyncClientBuilder httpAsyncClientBuilder) { 120 | this.httpAsyncClientBuilder = httpAsyncClientBuilder; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /elasticsearch/src/main/java/io/micronaut/elasticsearch/DefaultHttpAsyncClientBuilderFactory.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.elasticsearch; 17 | 18 | import io.micronaut.context.annotation.Bean; 19 | import io.micronaut.context.annotation.Factory; 20 | import io.micronaut.context.annotation.Requires; 21 | import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; 22 | import org.elasticsearch.client.RestClient; 23 | import jakarta.inject.Singleton; 24 | 25 | /** 26 | * The default factory used to create {@link HttpAsyncClientBuilder} for HTTP client configurations. 27 | * 28 | * @author Puneet Behl 29 | * @since 1.0.0 30 | */ 31 | @Requires(classes = {RestClient.class}) 32 | @Factory 33 | public class DefaultHttpAsyncClientBuilderFactory { 34 | 35 | /** 36 | * The http client configuration (e.g. encrypted communication over ssl, or anything that 37 | * the {@link HttpAsyncClientBuilder} allows to set). 38 | * 39 | * @return The {@link HttpAsyncClientBuilder} bean with default configurations. 40 | */ 41 | @Bean 42 | @Singleton 43 | protected HttpAsyncClientBuilder httpAsyncClientBuilder() { 44 | return HttpAsyncClientBuilder.create(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /elasticsearch/src/main/java/io/micronaut/elasticsearch/ElasticsearchSettings.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.elasticsearch; 17 | 18 | import org.apache.http.HttpHost; 19 | 20 | /** 21 | * Common constants for Elasticsearch settings. 22 | * 23 | * @author lishuai 24 | * @since 1.0.0 25 | */ 26 | public interface ElasticsearchSettings { 27 | 28 | /** 29 | * The prefix to use for all Elasticsearch settings. 30 | */ 31 | String PREFIX = "elasticsearch"; 32 | 33 | /** 34 | * Default Elasticsearch host. 35 | */ 36 | HttpHost DEFAULT_HOST = new HttpHost("127.0.0.1", 9200, "http"); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /elasticsearch/src/main/java/io/micronaut/elasticsearch/conditon/RequiresElasticsearch.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.elasticsearch.conditon; 17 | 18 | import io.micronaut.elasticsearch.ElasticsearchSettings; 19 | import io.micronaut.context.annotation.Requires; 20 | import org.elasticsearch.client.RestClient; 21 | 22 | import java.lang.annotation.*; 23 | 24 | /** 25 | * Meta annotation for Elasticsearch that can be added to any component that requires Elasticsearch to load. 26 | * 27 | * @author Puneet Behl 28 | * @since 1.0.0 29 | */ 30 | @Documented 31 | @Retention(RetentionPolicy.RUNTIME) 32 | @Target({ElementType.PACKAGE, ElementType.TYPE}) 33 | @Requires(property = ElasticsearchSettings.PREFIX) 34 | @Requires(classes = {RestClient.class}) 35 | public @interface RequiresElasticsearch { 36 | } 37 | -------------------------------------------------------------------------------- /elasticsearch/src/main/java/io/micronaut/elasticsearch/conditon/package-info.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 | /** 17 | * Elasticsearch Client condition. 18 | * 19 | * @author Puneet Behl 20 | * @since 1.0.0 21 | */ 22 | 23 | package io.micronaut.elasticsearch.conditon; 24 | -------------------------------------------------------------------------------- /elasticsearch/src/main/java/io/micronaut/elasticsearch/convert/StringToHeaderConverter.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.elasticsearch.convert; 17 | 18 | import io.micronaut.context.annotation.Requires; 19 | import io.micronaut.core.convert.ConversionContext; 20 | import io.micronaut.core.convert.TypeConverter; 21 | import org.apache.http.Header; 22 | import org.apache.http.message.BasicHeader; 23 | import org.elasticsearch.client.RestClientBuilder; 24 | 25 | import jakarta.inject.Singleton; 26 | import java.util.Optional; 27 | 28 | /** 29 | * Converts String to {@link Header}. 30 | * 31 | * @author Puneet Behl 32 | * @since 1.0.0 33 | */ 34 | @Singleton 35 | @Requires(classes = RestClientBuilder.class) 36 | public class StringToHeaderConverter implements TypeConverter { 37 | 38 | @Override 39 | public Optional
convert(CharSequence object, Class
targetType, ConversionContext context) { 40 | String header = object.toString(); 41 | if (header.contains(":")) { 42 | String[] nameAndValue = header.split(":"); 43 | return Optional.of(new BasicHeader(nameAndValue[0], nameAndValue[1])); 44 | } else { 45 | return Optional.empty(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /elasticsearch/src/main/java/io/micronaut/elasticsearch/convert/StringToHttpHostConverter.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.elasticsearch.convert; 17 | 18 | import io.micronaut.context.annotation.Requires; 19 | import io.micronaut.core.convert.ConversionContext; 20 | import io.micronaut.core.convert.TypeConverter; 21 | import org.apache.http.HttpHost; 22 | import org.elasticsearch.client.RestClientBuilder; 23 | 24 | import jakarta.inject.Singleton; 25 | import java.net.URI; 26 | import java.util.Optional; 27 | 28 | /** 29 | * Converts String to {@link HttpHost}. 30 | * 31 | * @author Puneet Behl 32 | * @since 1.0.0 33 | */ 34 | @Singleton 35 | @Requires(classes = RestClientBuilder.class) 36 | public class StringToHttpHostConverter implements TypeConverter { 37 | 38 | @Override 39 | public Optional convert(CharSequence object, Class targetType, ConversionContext context) { 40 | String uriString = object.toString(); 41 | URI uri = URI.create(uriString); 42 | return Optional.of(new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme())); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /elasticsearch/src/main/java/io/micronaut/elasticsearch/convert/StringToInetAddressConverter.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.elasticsearch.convert; 17 | 18 | import io.micronaut.context.annotation.Requires; 19 | import io.micronaut.core.convert.ConversionContext; 20 | import io.micronaut.core.convert.TypeConverter; 21 | import org.elasticsearch.client.RestClientBuilder; 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | import jakarta.inject.Singleton; 26 | import java.net.InetAddress; 27 | import java.net.UnknownHostException; 28 | import java.util.Optional; 29 | 30 | /** 31 | * Converts String to {@link InetAddress}. 32 | * 33 | * @author Puneet Behl 34 | * @since 1.0.0 35 | */ 36 | @Singleton 37 | @Requires(classes = RestClientBuilder.class) 38 | public class StringToInetAddressConverter implements TypeConverter { 39 | 40 | private static final Logger LOG = LoggerFactory.getLogger(StringToInetAddressConverter.class); 41 | 42 | @Override 43 | public Optional convert(CharSequence object, Class targetType, ConversionContext context) { 44 | String address = object.toString(); 45 | try { 46 | return Optional.of(InetAddress.getByName(address)); 47 | } catch (UnknownHostException e) { 48 | LOG.error(e.getMessage(), e); 49 | return Optional.empty(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /elasticsearch/src/main/java/io/micronaut/elasticsearch/convert/StringToNodeSelectorConverter.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.elasticsearch.convert; 17 | 18 | import io.micronaut.context.annotation.Requires; 19 | import io.micronaut.core.convert.ConversionContext; 20 | import io.micronaut.core.convert.TypeConverter; 21 | import org.elasticsearch.client.NodeSelector; 22 | import org.elasticsearch.client.RestClientBuilder; 23 | 24 | import jakarta.inject.Singleton; 25 | import java.util.Locale; 26 | import java.util.Optional; 27 | 28 | /** 29 | * Converts String to {@link NodeSelector}. 30 | * 31 | * @author Puneet Behl 32 | * @since 1.0.0 33 | */ 34 | @Singleton 35 | @Requires(classes = RestClientBuilder.class) 36 | public class StringToNodeSelectorConverter implements TypeConverter { 37 | 38 | @Override 39 | public Optional convert(CharSequence object, Class targetType, ConversionContext context) { 40 | String nodeSelector = object.toString().toUpperCase(Locale.ENGLISH); 41 | switch (nodeSelector) { 42 | case "SKIP_DEDICATED_MASTERS": 43 | return Optional.of(NodeSelector.SKIP_DEDICATED_MASTERS); 44 | case "ANY": 45 | return Optional.of(NodeSelector.ANY); 46 | default: 47 | return Optional.empty(); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /elasticsearch/src/main/java/io/micronaut/elasticsearch/convert/package-info.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 | /** 17 | * Elasticsearch converters. 18 | * 19 | * @author Puneet Behl 20 | * @since 1.0.0 21 | */ 22 | 23 | package io.micronaut.elasticsearch.convert; 24 | -------------------------------------------------------------------------------- /elasticsearch/src/main/java/io/micronaut/elasticsearch/health/ElasticsearchClientHealthIndicator.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.elasticsearch.health; 17 | 18 | import io.micronaut.context.annotation.Requires; 19 | import io.micronaut.health.HealthStatus; 20 | import io.micronaut.management.endpoint.health.HealthEndpoint; 21 | import io.micronaut.management.health.indicator.HealthIndicator; 22 | import io.micronaut.management.health.indicator.HealthResult; 23 | import org.reactivestreams.Publisher; 24 | 25 | import co.elastic.clients.elasticsearch.ElasticsearchAsyncClient; 26 | import co.elastic.clients.elasticsearch.cluster.HealthResponse; 27 | import jakarta.inject.Singleton; 28 | 29 | import static io.micronaut.health.HealthStatus.DOWN; 30 | import static io.micronaut.health.HealthStatus.UP; 31 | import java.util.Locale; 32 | 33 | /** 34 | * A {@link HealthIndicator} for Elasticsearch that uses an automatically-configured high-level REST client, injected as a dependency, to communicate 35 | * with Elasticsearch. 36 | * 37 | * @author Puneet Behl 38 | * @author Robyn Dalgleish 39 | * @since 1.0.0 40 | */ 41 | @Requires(beans = HealthEndpoint.class) 42 | @Requires(property = HealthEndpoint.PREFIX + ".elasticsearch.enabled", notEquals = "false") 43 | @Singleton 44 | public class ElasticsearchClientHealthIndicator implements HealthIndicator { 45 | 46 | private static final String NAME = "elasticsearchclient"; 47 | 48 | private final ElasticsearchAsyncClient client; 49 | 50 | /** 51 | * Constructor. 52 | * 53 | * @param client The Elasticsearch high level REST client. 54 | */ 55 | public ElasticsearchClientHealthIndicator(ElasticsearchAsyncClient client) { 56 | this.client = client; 57 | } 58 | 59 | /** 60 | * Tries to call the cluster info API on Elasticsearch to obtain information about the cluster. If the call succeeds, the Elasticsearch cluster 61 | * health status (GREEN / YELLOW / RED) will be included in the health indicator details. 62 | * 63 | * @return A positive health result UP if the cluster can be communicated with and is in either GREEN or YELLOW status. A negative health result 64 | * DOWN if the cluster cannot be communicated with or is in RED status. 65 | */ 66 | @Override 67 | public Publisher getResult() { 68 | return (subscriber -> client.cluster().health() 69 | .handle((health, exception) -> { 70 | final HealthResult.Builder resultBuilder = HealthResult.builder(NAME); 71 | if (exception != null) { 72 | subscriber.onNext(resultBuilder.status(DOWN).exception(exception).build()); 73 | subscriber.onComplete(); 74 | } else { 75 | HealthStatus status = health.status() == co.elastic.clients.elasticsearch._types.HealthStatus.Red ? DOWN : UP; 76 | subscriber.onNext(resultBuilder.status(status).details(healthResultDetails(health)).build()); 77 | subscriber.onComplete(); 78 | } 79 | return health; 80 | })); 81 | } 82 | 83 | private String healthResultDetails(HealthResponse response) { 84 | return "{" 85 | + "\"cluster_name\":\"" + response.clusterName() + "\"," 86 | + "\"status\":\"" + response.status().name().toLowerCase(Locale.ENGLISH) + "\"," 87 | + "\"timed_out\":" + response.timedOut() + "," 88 | + "\"number_of_nodes\":" + response.numberOfNodes() + "," 89 | + "\"number_of_data_nodes\":" + response.numberOfDataNodes() + "," 90 | + "\"number_of_pending_tasks\":" + response.numberOfPendingTasks() + "," 91 | + "\"number_of_in_flight_fetch\":" + response.numberOfInFlightFetch() + "," 92 | + "\"task_max_waiting_in_queue\":\"" + response.taskMaxWaitingInQueueMillis() + "\"," 93 | + "\"task_max_waiting_in_queue_millis\":" + response.taskMaxWaitingInQueueMillis() + "," 94 | + "\"active_shards_percent_as_number\":\"" + response.activeShardsPercentAsNumber() + "\"," 95 | + "\"active_primary_shards\":" + response.activePrimaryShards() + "," 96 | + "\"active_shards\":" + response.activeShards() + "," 97 | + "\"relocating_shards\":" + response.relocatingShards() + "," 98 | + "\"initializing_shards\":" + response.initializingShards() + "," 99 | + "\"unassigned_shards\":" + response.unassignedShards() + "," 100 | + "\"delayed_unassigned_shards\":" + response.delayedUnassignedShards() 101 | + "}"; 102 | } 103 | } 104 | 105 | 106 | -------------------------------------------------------------------------------- /elasticsearch/src/main/java/io/micronaut/elasticsearch/package-info.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 | /** 17 | * Configuration for Elasticsearch RestHighLevelClient. 18 | * refer to https://www.elastic.co/guide/en/elasticsearch/client/java-rest/6.3/java-rest-high.html 19 | * 20 | * @author lishuai 21 | * @since 1.0.0 22 | */ 23 | @Configuration 24 | @RequiresElasticsearch 25 | package io.micronaut.elasticsearch; 26 | 27 | import io.micronaut.elasticsearch.conditon.RequiresElasticsearch; 28 | import io.micronaut.context.annotation.Configuration; 29 | -------------------------------------------------------------------------------- /elasticsearch/src/test/groovy/io/micronaut/elasticsearch/DefaultElasticsearchConfigurationPropertiesSpec.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2018 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 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.micronaut.elasticsearch 18 | 19 | import co.elastic.clients.elasticsearch.ElasticsearchClient 20 | import io.micronaut.context.ApplicationContext 21 | import io.micronaut.context.annotation.Factory 22 | import io.micronaut.context.annotation.Replaces 23 | import org.apache.http.HttpHost 24 | import org.apache.http.auth.AuthScope 25 | import org.apache.http.auth.UsernamePasswordCredentials 26 | import org.apache.http.client.CredentialsProvider 27 | import org.apache.http.impl.client.BasicCredentialsProvider 28 | import org.apache.http.impl.nio.client.HttpAsyncClientBuilder 29 | import org.apache.http.impl.nio.reactor.IOReactorConfig 30 | import org.elasticsearch.client.NodeSelector 31 | import spock.lang.Specification 32 | 33 | import jakarta.inject.Singleton 34 | 35 | /** 36 | * @author Puneet Behl 37 | * @since 1.0.0 38 | */ 39 | class DefaultElasticsearchConfigurationPropertiesSpec extends Specification { 40 | 41 | void "Test Elasticsearch rest client configrations"() { 42 | when: 43 | ApplicationContext applicationContext = ApplicationContext.run( 44 | 45 | 'elasticsearch.httpHosts': 'http://127.0.0.1:9200', 46 | 'elasticsearch.defaultHeaders': 'Content-Type:application/json', 47 | 'elasticsearch.maxRetryTimeoutMillis': 1000, 48 | 'elasticsearch.nodeSelector': "SKIP_DEDICATED_MASTERS", 49 | ) 50 | 51 | then: 52 | applicationContext.containsBean(DefaultElasticsearchConfigurationProperties) 53 | applicationContext.getBean(DefaultElasticsearchConfigurationProperties).httpHosts == [new HttpHost('127.0.0.1', 9200, 'http')].toArray() 54 | applicationContext.getBean(DefaultElasticsearchConfigurationProperties).defaultHeaders.length == 1 55 | applicationContext.getBean(DefaultElasticsearchConfigurationProperties).maxRetryTimeoutMillis == 1000 56 | applicationContext.getBean(DefaultElasticsearchConfigurationProperties).nodeSelector == NodeSelector.SKIP_DEDICATED_MASTERS 57 | 58 | cleanup: 59 | applicationContext.close() 60 | 61 | } 62 | 63 | void "Test configure multiple hosts"() { 64 | 65 | when: 66 | ApplicationContext applicationContext = ApplicationContext.run( 67 | 'elasticsearch.httpHosts': 'http://127.0.0.1:9200,http://127.0.1.1:9200', 68 | 'elasticsearch.maxRetryTimeoutMillis': 1000 69 | ) 70 | 71 | then: 72 | applicationContext.containsBean(DefaultElasticsearchConfigurationProperties) 73 | applicationContext.getBean(DefaultElasticsearchConfigurationProperties).httpHosts == [new HttpHost('127.0.0.1', 9200, 'http'), 74 | new HttpHost('127.0.1.1', 9200, 'http')].toArray() 75 | 76 | cleanup: 77 | applicationContext.close() 78 | 79 | } 80 | 81 | void "Test Elasticsearch default request configurations"() { 82 | 83 | when: 84 | ApplicationContext applicationContext = ApplicationContext.run( 85 | "elasticsearch.httpHosts": "http://127.0.0.1:9200,http://127.0.1.1:9200", 86 | "elasticsearch.maxRetryTimeoutMillis": 1000, 87 | "elasticsearch.request.default.localAddress": "198.57.151.22", 88 | "elasticsearch.request.default.expectContinueEnabled": true 89 | 90 | 91 | ) 92 | 93 | then: 94 | applicationContext.containsBean(DefaultElasticsearchConfigurationProperties) 95 | applicationContext.getBean(DefaultElasticsearchConfigurationProperties).httpHosts == [new HttpHost('127.0.0.1', 9200, 'http'), 96 | new HttpHost('127.0.1.1', 9200, 'http')].toArray() 97 | 98 | cleanup: 99 | applicationContext.close() 100 | 101 | } 102 | 103 | void "Test Elasticsearch configuration with file"() { 104 | 105 | given: 106 | ApplicationContext applicationContext = ApplicationContext.run() 107 | 108 | expect: 109 | applicationContext.containsBean(DefaultElasticsearchConfigurationProperties) 110 | applicationContext.containsBean(ElasticsearchClient) 111 | applicationContext.getBean(DefaultElasticsearchConfigurationProperties).httpHosts.size() == 2 112 | 113 | } 114 | 115 | void "Test that HttpAsyncClientBuilder bean is created"() { 116 | 117 | when: 118 | ApplicationContext applicationContext = ApplicationContext.run("elasticsearch.httpHosts": "http://127.0.0.1:9200,http://127.0.1.1:9200") 119 | 120 | then: 121 | applicationContext.containsBean(HttpAsyncClientBuilder) 122 | 123 | cleanup: 124 | applicationContext.close() 125 | 126 | } 127 | 128 | void "Test overiding HttpAsyncClientBuilder bean"() { 129 | 130 | when: 131 | ApplicationContext applicationContext = ApplicationContext.run("elasticsearch.httpHosts": "http://127.0.0.1:9200,http://127.0.1.1:9200") 132 | 133 | then: 134 | applicationContext.containsBean(HttpAsyncClientBuilder) 135 | applicationContext.getBean(DefaultElasticsearchConfigurationProperties).httpAsyncClientBuilder 136 | "Bar" == ((MyHttpAsyncClientBuilder) applicationContext.getBean(DefaultElasticsearchConfigurationProperties).httpAsyncClientBuilder).foo 137 | 138 | cleanup: 139 | applicationContext.close() 140 | 141 | } 142 | 143 | @Factory 144 | static class MyFactory { 145 | 146 | @Replaces(HttpAsyncClientBuilder.class) 147 | @Singleton 148 | HttpAsyncClientBuilder httpAsyncClientBuilder() { 149 | final CredentialsProvider credentialsProvider = new BasicCredentialsProvider() 150 | credentialsProvider.setCredentials(AuthScope.ANY, 151 | new UsernamePasswordCredentials("user", "password")) 152 | 153 | return MyHttpAsyncClientBuilder.create() 154 | .setFoo("Bar") 155 | .setDefaultIOReactorConfig(IOReactorConfig.custom().setIoThreadCount(1).build()) 156 | .setDefaultCredentialsProvider(credentialsProvider) 157 | } 158 | } 159 | 160 | static class MyHttpAsyncClientBuilder extends HttpAsyncClientBuilder { 161 | public String foo 162 | 163 | MyHttpAsyncClientBuilder() { 164 | super() 165 | } 166 | 167 | MyHttpAsyncClientBuilder setFoo(String foo) { 168 | this.foo = foo 169 | return this 170 | } 171 | 172 | static MyHttpAsyncClientBuilder create() { 173 | new MyHttpAsyncClientBuilder() 174 | } 175 | } 176 | 177 | } 178 | -------------------------------------------------------------------------------- /elasticsearch/src/test/groovy/io/micronaut/elasticsearch/ElasticsearchAuthorizationSpec.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2018 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 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.micronaut.elasticsearch 17 | 18 | import co.elastic.clients.elasticsearch.ElasticsearchClient 19 | import co.elastic.clients.elasticsearch.core.InfoResponse 20 | import io.micronaut.context.ApplicationContext 21 | import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy 22 | import org.testcontainers.elasticsearch.ElasticsearchContainer 23 | import spock.lang.Requires 24 | import spock.lang.Specification 25 | 26 | @Requires({ sys['elasticsearch.version'] }) 27 | class ElasticsearchAuthorizationSpec extends Specification { 28 | 29 | static final String ELASTICSEARCH_VERSION = System.getProperty("elasticsearch.version") 30 | static final String ELASTICSEARCH_USERNAME = "elastic" 31 | static final String ELASTICSEARCH_PASSWORD = "changeme" 32 | static final ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:$ELASTICSEARCH_VERSION") 33 | .withExposedPorts(9200) 34 | .withEnv("xpack.security.enabled", "false") 35 | .withPassword(ELASTICSEARCH_PASSWORD) 36 | .waitingFor(new LogMessageWaitStrategy().withRegEx(".*\"message\":\"started.*")) 37 | 38 | void setupSpec() { 39 | container.start() 40 | } 41 | 42 | void cleanupSpec() { 43 | container.stop() 44 | } 45 | 46 | void "Test Elasticsearch authorization"() { 47 | 48 | given: 49 | 50 | String token = new String(Base64.getEncoder().encode((ELASTICSEARCH_USERNAME + ':' + ELASTICSEARCH_PASSWORD).getBytes())) 51 | 52 | ApplicationContext applicationContext = ApplicationContext.run( 53 | 'elasticsearch.httpHosts': "http://${container.httpHostAddress}", 54 | 'elasticsearch.default-headers': "Authorization:Basic $token" 55 | ) 56 | 57 | expect: 58 | applicationContext.containsBean(ElasticsearchClient) 59 | applicationContext.getBean(ElasticsearchClient).ping() 60 | InfoResponse response = applicationContext.getBean(ElasticsearchClient).info() 61 | System.out.println(String.format("cluster: %s, node: %s, version: %s %s", response.clusterName(), response.name(), response.version().number(), response.version().buildDate())) 62 | 63 | cleanup: 64 | applicationContext.close() 65 | 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /elasticsearch/src/test/groovy/io/micronaut/elasticsearch/ElasticsearchMappingSpec.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2018 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 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.micronaut.elasticsearch 18 | 19 | import co.elastic.clients.elasticsearch.ElasticsearchClient 20 | import co.elastic.clients.elasticsearch._types.Result 21 | import co.elastic.clients.elasticsearch.core.* 22 | import co.elastic.clients.elasticsearch.indices.ExistsRequest 23 | import io.micronaut.context.ApplicationContext 24 | import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy 25 | import org.testcontainers.elasticsearch.ElasticsearchContainer 26 | import spock.lang.Requires 27 | import spock.lang.Specification 28 | 29 | /** 30 | * @author lishuai 31 | * @author Puneet Behl 32 | * @since 1.0.1 33 | */ 34 | @Requires({ sys['elasticsearch.version'] }) 35 | class ElasticsearchMappingSpec extends Specification { 36 | 37 | final static String ELASTICSEARCH_VERSION = System.getProperty("elasticsearch.version") 38 | static final ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:$ELASTICSEARCH_VERSION") 39 | .withExposedPorts(9200) 40 | .withEnv("xpack.security.enabled", "false") 41 | .waitingFor(new LogMessageWaitStrategy().withRegEx(".*\"message\":\"started.*")) 42 | 43 | void setupSpec() { 44 | container.start() 45 | } 46 | 47 | void cleanupSpec() { 48 | container.stop() 49 | } 50 | 51 | 52 | void "Test Elasticsearch connection"() { 53 | given: 54 | ApplicationContext applicationContext = ApplicationContext.run('elasticsearch.httpHosts': 'http://' + container.httpHostAddress) 55 | 56 | expect: 57 | applicationContext.containsBean(ElasticsearchClient) 58 | applicationContext.getBean(ElasticsearchClient).ping() 59 | InfoResponse response = applicationContext.getBean(ElasticsearchClient).info() 60 | System.out.println(String.format("cluser: %s, node: %s, version: %s %s", response.clusterName(), response.name(), response.version().number(), response.version().buildDate())) 61 | 62 | cleanup: 63 | applicationContext.close() 64 | } 65 | 66 | void "Test Elasticsearch(8.x) Mapping API"() { 67 | given: 68 | ApplicationContext applicationContext = ApplicationContext.run('elasticsearch.httpHosts': 'http://' + container.getHttpHostAddress()) 69 | ElasticsearchClient client = applicationContext.getBean(ElasticsearchClient) 70 | 71 | expect: "Make sure the version of ES is up to date because these tests may cause unexpected results" 72 | ELASTICSEARCH_VERSION == client.info().version().number() 73 | 74 | when: 75 | ExistsRequest existsRequest = new ExistsRequest.Builder().index("posts").build() 76 | 77 | then: "index does not exists" 78 | !client.indices().exists(existsRequest).value() 79 | 80 | when: "create index request" 81 | IndexRequest.Builder requestBuilder = new IndexRequest.Builder<>() 82 | .index("posts") 83 | .id("1") 84 | 85 | Map document = new HashMap<>() 86 | document.put("user", "kimchy") 87 | document.put("postDate", "2013-01-30") 88 | document.put("message", "trying out Elasticsearch") 89 | requestBuilder.document(document) 90 | 91 | IndexResponse response = client.index(requestBuilder.build()) 92 | 93 | then: "verify version and result" 94 | response.index() == "posts" 95 | response.version() == 1 96 | response.result() == Result.Created 97 | 98 | when: "update index request" 99 | requestBuilder = new IndexRequest.Builder<>() 100 | .index("posts") 101 | .id("1") 102 | 103 | document = new HashMap<>() 104 | document.put("user", "kimchy1") 105 | document.put("postDate", "2018-10-30") 106 | document.put("message", "Trying out Elasticsearch6") 107 | requestBuilder.document(document) 108 | 109 | response = client.index(requestBuilder.build()) 110 | 111 | then: "verify version and result" 112 | response.index() == "posts" 113 | response.version() == 2 114 | response.result() == Result.Updated 115 | 116 | when: "get request" 117 | GetRequest getRequest = new GetRequest.Builder() 118 | .index("posts") 119 | .id("1") 120 | .sourceIncludes("message", "*Date") 121 | .build() 122 | 123 | GetResponse getResponse = client.get(getRequest, Map.class) 124 | 125 | then: "verify source" 126 | getResponse.index() == "posts" 127 | getResponse.version() == 2 128 | getResponse.source() == [postDate: "2018-10-30", message: "Trying out Elasticsearch6"] 129 | 130 | when: "exits request" 131 | co.elastic.clients.elasticsearch.core.ExistsRequest existsRequest2 = new co.elastic.clients.elasticsearch.core.ExistsRequest.Builder() 132 | .index("posts") 133 | .id("1") 134 | .build() 135 | 136 | then: 137 | client.exists(existsRequest2) 138 | 139 | when: "delete request" 140 | DeleteRequest deleteRequest = new DeleteRequest.Builder() 141 | .index("posts") 142 | .id("1") 143 | .build() 144 | DeleteResponse deleteResponse = client.delete(deleteRequest) 145 | 146 | then: 147 | deleteResponse.index() == "posts" 148 | 149 | cleanup: 150 | applicationContext.close() 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /elasticsearch/src/test/groovy/io/micronaut/elasticsearch/health/ElasticsearchClientHealthIndicatorSpec.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2018 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 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.micronaut.elasticsearch.health 18 | 19 | import groovy.json.JsonSlurper 20 | import io.micronaut.context.ApplicationContext 21 | import io.micronaut.context.exceptions.NoSuchBeanException 22 | import io.micronaut.elasticsearch.DefaultElasticsearchConfigurationProperties 23 | import io.micronaut.health.HealthStatus 24 | import io.micronaut.management.health.indicator.HealthResult 25 | import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy 26 | import org.testcontainers.elasticsearch.ElasticsearchContainer 27 | import reactor.core.publisher.Flux 28 | import spock.lang.Requires 29 | import spock.lang.Specification 30 | /** 31 | * @author Puneet Behl 32 | * @since 1.0.0 33 | */ 34 | @Requires({ sys['elasticsearch.version'] }) 35 | class ElasticsearchClientHealthIndicatorSpec extends Specification { 36 | 37 | final static String ELASTICSEARCH_VERSION = System.getProperty("elasticsearch.version") 38 | 39 | void "test elasticsearch health indicator"() { 40 | given: 41 | ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:$ELASTICSEARCH_VERSION") 42 | .withExposedPorts(9200) 43 | .withEnv("xpack.security.enabled", "false") 44 | .waitingFor(new LogMessageWaitStrategy().withRegEx(".*\"message\":\"started.*")) 45 | container.start() 46 | 47 | ApplicationContext applicationContext = ApplicationContext.run('elasticsearch.httpHosts': "http://$container.httpHostAddress") 48 | 49 | expect: 50 | applicationContext.containsBean(DefaultElasticsearchConfigurationProperties) 51 | 52 | when: 53 | ElasticsearchClientHealthIndicator indicator = applicationContext.getBean(ElasticsearchClientHealthIndicator) 54 | HealthResult result = Flux.from(indicator.getResult()).blockFirst() 55 | 56 | then: 57 | result.status == HealthStatus.UP 58 | new JsonSlurper().parseText((String) result.details).status == co.elastic.clients.elasticsearch._types.HealthStatus.Green.name().toLowerCase(Locale.ENGLISH) 59 | 60 | when: 61 | container.stop() 62 | result = Flux.from(indicator.getResult()).blockFirst() 63 | 64 | then: 65 | result.status == HealthStatus.DOWN 66 | 67 | cleanup: 68 | applicationContext?.stop() 69 | container.stop() 70 | } 71 | 72 | void "test that ElasticsearchClientHealthIndicator is not created when the endpoints.health.elasticsearch.rest.high.level.enabled is set to false "() { 73 | ApplicationContext applicationContext = ApplicationContext.run( 74 | 'elasticsearch.httpHosts': "http://localhost:9200", 75 | 'endpoints.health.elasticsearch.enabled': "false" 76 | ) 77 | 78 | when: 79 | applicationContext.getBean(ElasticsearchClientHealthIndicator) 80 | 81 | then: 82 | thrown(NoSuchBeanException) 83 | 84 | cleanup: 85 | applicationContext?.stop() 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /elasticsearch/src/test/resources/application.properties: -------------------------------------------------------------------------------- 1 | elasticsearch.httpHosts=http://localhost:9200,http://127.0.0.1:9200 -------------------------------------------------------------------------------- /elasticsearch/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | %d{HH:mm:ss.SSS} %-5level [%thread] %logger{25} [%file:%line] - %msg%n 7 | UTF-8 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | projectVersion=5.8.1-SNAPSHOT 2 | projectGroup=io.micronaut.elasticsearch 3 | 4 | title=Micronaut Elasticsearch 5 | projectDesc=Integration between Micronaut and Elasticsearch 6 | projectUrl=https://micronaut.io 7 | githubSlug=micronaut-projects/micronaut-elasticsearch 8 | developers=Puneet Behl 9 | 10 | 11 | testsuite=test-suite/src/test/groovy/io/micronaut/docs 12 | 13 | org.gradle.caching=true 14 | org.gradle.jvmargs=-Xmx1g 15 | -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | [versions] 2 | micronaut-docs = "2.0.0" 3 | micronaut = "4.8.14" 4 | micronaut-platform = "4.5.1" 5 | micronaut-security = "4.12.1" 6 | micronaut-logging = "1.4.0" 7 | micronaut-test = "4.5.0" 8 | micronaut-test-resources="2.7.3" 9 | micronaut-gradle-plugin = "4.4.5" 10 | managed-elasticsearch = "8.17.4" 11 | 12 | graal-svm = "23.1.7" 13 | groovy = "4.0.15" 14 | spock = "2.3-groovy-4.0" 15 | awaitility = "4.3.0" 16 | apache-http-client = "4.5.14" 17 | apache-http-async-client = "4.1.5" 18 | sonatype-scan = "3.0.0" 19 | 20 | [libraries] 21 | # Core 22 | micronaut-core = { module = 'io.micronaut:micronaut-core-bom', version.ref = 'micronaut' } 23 | 24 | micronaut-security = { module = "io.micronaut.security:micronaut-security-bom", version.ref = "micronaut-security" } 25 | micronaut-test-resources = { module = "io.micronaut.testresources:micronaut-test-resources-bom", version.ref = "micronaut-test-resources" } 26 | 27 | managed-elasticsearch-java = { module = "co.elastic.clients:elasticsearch-java", version.ref = "managed-elasticsearch" } 28 | managed-elasticsearch-rest-client = { module = "org.elasticsearch.client:elasticsearch-rest-client", version.ref = "managed-elasticsearch" } 29 | apache-http-client = { module = "org.apache.httpcomponents:httpclient", version.ref = "apache-http-client" } 30 | apache-http-async-client = { module = "org.apache.httpcomponents:httpasyncclient", version.ref = "apache-http-async-client" } 31 | graal-svm = { module = "org.graalvm.nativeimage:svm", version.ref = "graal-svm" } 32 | 33 | awaitility = { module = "org.awaitility:awaitility", version.ref = "awaitility" } 34 | gradle-micronaut = { module = "io.micronaut.gradle:micronaut-gradle-plugin", version.ref = "micronaut-gradle-plugin" } 35 | sonatype-scan = { module = "org.sonatype.gradle.plugins:scan-gradle-plugin", version.ref = "sonatype-scan" } 36 | -------------------------------------------------------------------------------- /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-2021' 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-elasticsearch/9a6879a37d5335eebe88cab4ecd60b56d6406ff7/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.12.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # SPDX-License-Identifier: Apache-2.0 19 | # 20 | 21 | ############################################################################## 22 | # 23 | # Gradle start up script for POSIX generated by Gradle. 24 | # 25 | # Important for running: 26 | # 27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 28 | # noncompliant, but you have some other compliant shell such as ksh or 29 | # bash, then to run this script, type that shell name before the whole 30 | # command line, like: 31 | # 32 | # ksh Gradle 33 | # 34 | # Busybox and similar reduced shells will NOT work, because this script 35 | # requires all of these POSIX shell features: 36 | # * functions; 37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 39 | # * compound commands having a testable exit status, especially «case»; 40 | # * various built-in commands including «command», «set», and «ulimit». 41 | # 42 | # Important for patching: 43 | # 44 | # (2) This script targets any POSIX shell, so it avoids extensions provided 45 | # by Bash, Ksh, etc; in particular arrays are avoided. 46 | # 47 | # The "traditional" practice of packing multiple parameters into a 48 | # space-separated string is a well documented source of bugs and security 49 | # problems, so this is (mostly) avoided, by progressively accumulating 50 | # options in "$@", and eventually passing that to Java. 51 | # 52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 54 | # see the in-line comments for details. 55 | # 56 | # There are tweaks for specific operating systems such as AIX, CygWin, 57 | # Darwin, MinGW, and NonStop. 58 | # 59 | # (3) This script is generated from the Groovy template 60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 61 | # within the Gradle project. 62 | # 63 | # You can find Gradle at https://github.com/gradle/gradle/. 64 | # 65 | ############################################################################## 66 | 67 | # Attempt to set APP_HOME 68 | 69 | # Resolve links: $0 may be a link 70 | app_path=$0 71 | 72 | # Need this for daisy-chained symlinks. 73 | while 74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 75 | [ -h "$app_path" ] 76 | do 77 | ls=$( ls -ld "$app_path" ) 78 | link=${ls#*' -> '} 79 | case $link in #( 80 | /*) app_path=$link ;; #( 81 | *) app_path=$APP_HOME$link ;; 82 | esac 83 | done 84 | 85 | # This is normally unused 86 | # shellcheck disable=SC2034 87 | APP_BASE_NAME=${0##*/} 88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | if ! command -v java >/dev/null 2>&1 137 | then 138 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 139 | 140 | Please set the JAVA_HOME variable in your environment to match the 141 | location of your Java installation." 142 | fi 143 | fi 144 | 145 | # Increase the maximum file descriptors if we can. 146 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 147 | case $MAX_FD in #( 148 | max*) 149 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 150 | # shellcheck disable=SC2039,SC3045 151 | MAX_FD=$( ulimit -H -n ) || 152 | warn "Could not query maximum file descriptor limit" 153 | esac 154 | case $MAX_FD in #( 155 | '' | soft) :;; #( 156 | *) 157 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 158 | # shellcheck disable=SC2039,SC3045 159 | ulimit -n "$MAX_FD" || 160 | warn "Could not set maximum file descriptor limit to $MAX_FD" 161 | esac 162 | fi 163 | 164 | # Collect all arguments for the java command, stacking in reverse order: 165 | # * args from the command line 166 | # * the main class name 167 | # * -classpath 168 | # * -D...appname settings 169 | # * --module-path (only if needed) 170 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 171 | 172 | # For Cygwin or MSYS, switch paths to Windows format before running java 173 | if "$cygwin" || "$msys" ; then 174 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 175 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 176 | 177 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 178 | 179 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 180 | for arg do 181 | if 182 | case $arg in #( 183 | -*) false ;; # don't mess with options #( 184 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 185 | [ -e "$t" ] ;; #( 186 | *) false ;; 187 | esac 188 | then 189 | arg=$( cygpath --path --ignore --mixed "$arg" ) 190 | fi 191 | # Roll the args list around exactly as many times as the number of 192 | # args, so each arg winds up back in the position where it started, but 193 | # possibly modified. 194 | # 195 | # NB: a `for` loop captures its iteration list before it begins, so 196 | # changing the positional parameters here affects neither the number of 197 | # iterations, nor the values presented in `arg`. 198 | shift # remove old arg 199 | set -- "$@" "$arg" # push replacement arg 200 | done 201 | fi 202 | 203 | 204 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 205 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 206 | 207 | # Collect all arguments for the java command: 208 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 209 | # and any embedded shellness will be escaped. 210 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 211 | # treated as '${Hostname}' itself on the command line. 212 | 213 | set -- \ 214 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 215 | -classpath "$CLASSPATH" \ 216 | org.gradle.wrapper.GradleWrapperMain \ 217 | "$@" 218 | 219 | # Stop when "xargs" is not available. 220 | if ! command -v xargs >/dev/null 2>&1 221 | then 222 | die "xargs is not available" 223 | fi 224 | 225 | # Use "xargs" to parse quoted args. 226 | # 227 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 228 | # 229 | # In Bash we could simply go: 230 | # 231 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 232 | # set -- "${ARGS[@]}" "$@" 233 | # 234 | # but POSIX shell has neither arrays nor command substitution, so instead we 235 | # post-process each arg (as a line of input to sed) to backslash-escape any 236 | # character that might be a shell metacharacter, then use eval to reverse 237 | # that process (while maintaining the separation between arguments), and wrap 238 | # the whole thing up as a single "set" statement. 239 | # 240 | # This will of course break if any of these variables contains a newline or 241 | # an unmatched quote. 242 | # 243 | 244 | eval "set -- $( 245 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 246 | xargs -n1 | 247 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 248 | tr '\n' ' ' 249 | )" '"$@"' 250 | 251 | exec "$JAVACMD" "$@" 252 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | plugins { 9 | id("io.micronaut.build.shared.settings") version "7.3.2" 10 | } 11 | 12 | rootProject.name = 'elasticsearch-parent' 13 | 14 | include 'elasticsearch-bom' 15 | include 'elasticsearch' 16 | include 'test-suite-groovy' 17 | include 'test-suite-java' 18 | 19 | enableFeaturePreview 'TYPESAFE_PROJECT_ACCESSORS' 20 | 21 | micronautBuild { 22 | useStandardizedProjectNames = true 23 | importMicronautCatalog() 24 | importMicronautCatalog("micronaut-security") 25 | importMicronautCatalog("micronaut-test-resources") 26 | } 27 | -------------------------------------------------------------------------------- /src/main/docs/guide/configuration.adoc: -------------------------------------------------------------------------------- 1 | == Configuring the Elasticsearch Client 2 | [TIP] 3 | .Using the CLI 4 | ==== 5 | If you are creating your project using the Micronaut CLI, supply the `elasticsearch` feature to configure the https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/current/index.html[ElasticsearchClient^] in your project: 6 | ---- 7 | $ mn create-app my-app --features elasticsearch 8 | ---- 9 | ==== 10 | 11 | To configure the https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/current/index.html[ElasticsearchClient^] you should first add `elasticsearch` module to your classpath: 12 | 13 | [source,groovy] 14 | .build.gradle 15 | ---- 16 | implementation("io.micronaut.elasticsearch:micronaut-elasticsearch") 17 | ---- 18 | 19 | You should then configure the `httpHosts` of the Elasticsearch server you wish to communicate with in `application.yml` as: 20 | 21 | [source,yaml] 22 | .application.yml 23 | ---- 24 | elasticsearch: 25 | httpHosts: "http://localhost:9200,http://127.0.0.2:9200" 26 | ---- 27 | 28 | See the API for api:elasticsearch.DefaultElasticsearchConfigurationProperties[] for more information on the available configuration options. 29 | 30 | Once you have the above configuration in place then you can inject the `co.elastic.clients.elasticsearch.ElasticsearchClient`, the `co.elastic.clients.elasticsearch.ElasticsearchAsyncClient` or the `org.elasticsearch.client.RestClient` bean. The following is the simplest way to get Elasticsearch information using the ElasticsearchClient: 31 | 32 | [source,groovy] 33 | ---- 34 | include::test-suite-groovy/src/test/groovy/io/micronaut/docs/configuration/elasticsearch/ElasticsearchSpec.groovy[tags=query,indent=0] 35 | ---- 36 | 37 | <1> `client` is an instance of the `co.elastic.clients.elasticsearch.ElasticsearchClient` bean. 38 | 39 | For more information on executing different operations using ElasticsearchClient please read the https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/current/index.html[Elasticsearch Documentation^]. 40 | 41 | == Modify the Default Request Configurations 42 | 43 | Often times you want to change the default configurations. To achieve this Micronaut, includes the ability to change the default request configurations. You can set the default request configurations under key `elasticsearch.request.default` as: 44 | 45 | [source,yaml] 46 | .application.yml 47 | ---- 48 | elasticsearch: 49 | httpHosts: http://localhost:9200,http://127.0.0.2:9200 50 | request: 51 | default: 52 | expectContinueEnabled: true 53 | localAddress: 198.57.151.22 54 | ---- 55 | 56 | See the API https://hc.apache.org/httpcomponents-client-5.2.x/current/httpclient5/apidocs/org/apache/hc/client5/http/config/RequestConfig.Builder.html[RequestConfig.Builder^] for more information on the available configuration options. 57 | 58 | == Modify the HTTP Client Configurations 59 | 60 | To modify the HTTP Client configurations (e.g. request timeouts, authentication, or anything that the https://hc.apache.org/httpcomponents-client-5.1.x/current/httpclient5/apidocs/org/apache/hc/client5/http/impl/async/HttpAsyncClientBuilder.html[HttpAsyncClientBuilder^] allows to set). You can define a bean using https://docs.micronaut.io/latest/api/io/micronaut/context/annotation/Factory.html[Factory] which replaces `org.apache.http.impl.nio.client.HttpAsyncClientBuilder`. 61 | 62 | Following is an example to change the default credentials provider: 63 | 64 | [source,groovy] 65 | ---- 66 | include::test-suite-groovy/src/test/groovy/io/micronaut/docs/configuration/elasticsearch/ElasticsearchSpec.groovy[tags=httpClientFactoryImports,indent=0] 67 | include::test-suite-groovy/src/test/groovy/io/micronaut/docs/configuration/elasticsearch/ElasticsearchSpec.groovy[tags=singletonImports,indent=0] 68 | include::test-suite-groovy/src/test/groovy/io/micronaut/docs/configuration/elasticsearch/ElasticsearchSpec.groovy[tags=httpClientFactory,indent=0] 69 | ---- 70 | 71 | === Logging 72 | 73 | Elasticsearch uses log4j for logging but Micronaut uses slf4j with Logback. To make it work properly, add the following dependency: 74 | 75 | dependency:org.slf4j:log4j-over-slf4j[version="1.7.30", scope="runtimeOnly"] 76 | -------------------------------------------------------------------------------- /src/main/docs/guide/graalvm.adoc: -------------------------------------------------------------------------------- 1 | 2 | Micronaut Elasticsearch is compatible with https://www.graalvm.org/[GraalVM] out of the box. 3 | 4 | NOTE: See the section on https://docs.micronaut.io/latest/guide/index.html#graal[GraalVM] in the user guide for more 5 | information. 6 | -------------------------------------------------------------------------------- /src/main/docs/guide/healthChecks.adoc: -------------------------------------------------------------------------------- 1 | When the `elasticsearch` module is activated a api:elasticsearch.health.ElasticsearchClientHealthIndicator[] is 2 | activated resulting in the `/health` endpoint and https://docs.micronaut.io/latest/api/io/micronaut/health/CurrentHealthStatus.html[CurrentHealthStatus] 3 | interface resolving the health of the Elasticsearch cluster. 4 | 5 | To enable or disable the indicator use: 6 | 7 | [source,yaml] 8 | .application.yml 9 | ---- 10 | endpoints: 11 | health: 12 | elasticsearch: 13 | enabled: true 14 | ---- 15 | 16 | 17 | To use the deprecated health indicator use: 18 | 19 | [source,yaml] 20 | .application.yml 21 | ---- 22 | endpoints: 23 | health: 24 | elasticsearch: 25 | rest: 26 | high: 27 | level: 28 | enabled: false 29 | ---- 30 | 31 | See the section on the https://docs.micronaut.io/latest/guide/index.html#healthEndpoint[Health Endpoint] for more information. 32 | -------------------------------------------------------------------------------- /src/main/docs/guide/introduction.adoc: -------------------------------------------------------------------------------- 1 | Micronaut supports automatic configuration of Elasticsearch https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/current/index.html[ElasticsearchClient^] via the `elasticsearch` module. 2 | 3 | -------------------------------------------------------------------------------- /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/toc.yml: -------------------------------------------------------------------------------- 1 | introduction: 2 | title: Introduction 3 | releaseHistory: Release History 4 | configuration: Configuration 5 | healthChecks: Health Checks 6 | graalvm: GraalVM Support 7 | repository: Repository -------------------------------------------------------------------------------- /test-suite-groovy/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("groovy") 3 | id("io.micronaut.build.internal.elasticsearch-tests") 4 | } 5 | 6 | dependencies { 7 | testCompileOnly(mn.micronaut.inject.groovy) 8 | 9 | testImplementation(platform(mn.micronaut.core.bom)) 10 | testImplementation(mnTest.micronaut.test.spock) 11 | 12 | // tag::testcontainers-dependencies[] 13 | testImplementation(mnTestResources.testcontainers.elasticsearch) 14 | // end::testcontainers-dependencies[] 15 | testImplementation(libs.apache.http.client) 16 | testImplementation(libs.apache.http.async.client) 17 | testImplementation(projects.micronautElasticsearch) 18 | testRuntimeOnly(mnLogging.logback.classic) 19 | } 20 | 21 | -------------------------------------------------------------------------------- /test-suite-groovy/src/test/groovy/io/micronaut/docs/configuration/elasticsearch/ElasticsearchSpec.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2018 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 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.micronaut.docs.configuration.elasticsearch 18 | 19 | import co.elastic.clients.elasticsearch.ElasticsearchAsyncClient 20 | import co.elastic.clients.elasticsearch.ElasticsearchClient 21 | import co.elastic.clients.elasticsearch.core.InfoResponse 22 | import io.micronaut.context.ApplicationContext 23 | import io.micronaut.context.annotation.Factory 24 | import io.micronaut.context.annotation.Replaces 25 | import io.micronaut.elasticsearch.DefaultElasticsearchConfigurationProperties 26 | //tag::httpClientFactoryImports[] 27 | 28 | import jakarta.inject.Singleton 29 | import org.apache.http.auth.AuthScope 30 | //end::httpClientFactoryImports[] 31 | 32 | import org.apache.http.auth.UsernamePasswordCredentials 33 | import org.apache.http.client.CredentialsProvider 34 | import org.apache.http.impl.client.BasicCredentialsProvider 35 | import org.apache.http.impl.nio.client.HttpAsyncClientBuilder 36 | import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy 37 | import org.testcontainers.elasticsearch.ElasticsearchContainer 38 | import spock.lang.Requires 39 | import spock.lang.Shared 40 | import spock.lang.Specification 41 | //tag::singletonImports[] 42 | //end::singletonImports[] 43 | /** 44 | * @author Puneet Behl 45 | * @since 1.0.0 46 | */ 47 | @Requires({ sys['elasticsearch.version'] }) 48 | class ElasticsearchSpec extends Specification { 49 | 50 | // tag::es-testcontainer[] 51 | final static String ELASTICSEARCH_VERSION = System.getProperty("elasticsearch.version") 52 | 53 | @Shared 54 | static final ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:$ELASTICSEARCH_VERSION") 55 | .withExposedPorts(9200) 56 | .withEnv("xpack.security.enabled", "false") 57 | .waitingFor(new LogMessageWaitStrategy().withRegEx(".*\"message\":\"started.*")) 58 | // end::es-testcontainer[] 59 | 60 | void setupSpec() { 61 | container.start() 62 | } 63 | 64 | void cleanupSpec() { 65 | container.stop() 66 | } 67 | 68 | void "Test simple info for Elasticsearch stats using the ElasticsearchClient"() { 69 | given: 70 | ApplicationContext applicationContext = ApplicationContext.run("elasticsearch.httpHosts": "http://$container.httpHostAddress", "test") 71 | String stats 72 | 73 | when: 74 | ElasticsearchClient client = applicationContext.getBean(ElasticsearchClient) 75 | //tag::query[] 76 | InfoResponse response = 77 | client.info() // <1> 78 | //end::query[] 79 | 80 | then: 81 | "docker-cluster" == response.clusterName() 82 | ELASTICSEARCH_VERSION == response.version().number() 83 | 84 | cleanup: 85 | applicationContext.close() 86 | } 87 | 88 | void "Test simple info for Elasticsearch stats using the ElasticsearchAsyncClient"() { 89 | given: 90 | ApplicationContext applicationContext = ApplicationContext.run("elasticsearch.httpHosts": "http://$container.httpHostAddress", "test") 91 | String stats 92 | 93 | when: 94 | ElasticsearchAsyncClient client = applicationContext.getBean(ElasticsearchAsyncClient) 95 | InfoResponse response = 96 | client.info().get() // <1> 97 | 98 | then: 99 | "docker-cluster" == response.clusterName() 100 | ELASTICSEARCH_VERSION == response.version().number() 101 | 102 | cleanup: 103 | applicationContext.close() 104 | } 105 | 106 | void "Test overiding HttpAsyncClientBuilder bean"() { 107 | 108 | when: 109 | ApplicationContext applicationContext = ApplicationContext.run("elasticsearch.httpHosts": "http://127.0.0.1:9200,http://127.0.1.1:9200") 110 | 111 | then: 112 | applicationContext.containsBean(HttpAsyncClientBuilder) 113 | applicationContext.getBean(DefaultElasticsearchConfigurationProperties).httpAsyncClientBuilder 114 | 115 | cleanup: 116 | applicationContext.close() 117 | 118 | } 119 | 120 | //tag::httpClientFactory[] 121 | @Factory 122 | static class HttpAsyncClientBuilderFactory { 123 | 124 | @Replaces(HttpAsyncClientBuilder.class) 125 | @Singleton 126 | HttpAsyncClientBuilder builder() { 127 | final CredentialsProvider credentialsProvider = new BasicCredentialsProvider() 128 | credentialsProvider.setCredentials(AuthScope.ANY, 129 | new UsernamePasswordCredentials("user", "password")) 130 | 131 | return HttpAsyncClientBuilder.create() 132 | .setDefaultCredentialsProvider(credentialsProvider) 133 | } 134 | } 135 | //end::httpClientFactory[] 136 | } 137 | -------------------------------------------------------------------------------- /test-suite-groovy/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 | -------------------------------------------------------------------------------- /test-suite-java/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("io.micronaut.application") 3 | id("io.micronaut.test-resources") 4 | id("io.micronaut.build.internal.elasticsearch-native-tests") 5 | } 6 | 7 | mainClassName = "micronaut.example.Application" 8 | micronaut { 9 | version libs.versions.micronaut.platform.get() 10 | coreVersion.set(libs.versions.micronaut.asProvider().get()) 11 | testRuntime "junit5" 12 | enableNativeImage false 13 | processing { 14 | incremental(true) 15 | annotations("helloworld.*") 16 | } 17 | } 18 | 19 | configurations.all { 20 | resolutionStrategy.dependencySubstitution { 21 | substitute module('io.micronaut.elasticsearch:micronaut-elasticsearch') using project(':micronaut-elasticsearch') 22 | } 23 | } 24 | 25 | dependencies { 26 | annotationProcessor("io.micronaut.validation:micronaut-validation-processor") 27 | implementation(mn.micronaut.context) 28 | implementation(mn.micronaut.jackson.databind) 29 | implementation("io.micronaut.validation:micronaut-validation") 30 | testImplementation(libs.awaitility) 31 | implementation(project(":micronaut-elasticsearch")) 32 | implementation(mn.snakeyaml) 33 | runtimeOnly(mnLogging.logback.classic) 34 | } 35 | micronaut { 36 | testResources { 37 | clientTimeout = 300 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test-suite-java/src/test/java/micronaut/example/ElasticSearchTest.java: -------------------------------------------------------------------------------- 1 | package micronaut.example; 2 | 3 | import io.micronaut.test.extensions.junit5.annotation.MicronautTest; 4 | import micronaut.example.service.Movie; 5 | import micronaut.example.service.MovieService; 6 | import org.junit.jupiter.api.Assertions; 7 | import org.junit.jupiter.api.Test; 8 | 9 | import static java.util.concurrent.TimeUnit.SECONDS; 10 | import static org.awaitility.Awaitility.await; 11 | 12 | @MicronautTest 13 | class ElasticSearchTest { 14 | @Test 15 | void testElasticSearch(MovieService movieService) { 16 | String title = "Die Hard"; 17 | movieService.saveMovie(new Movie("KJFDOD", title)); 18 | await().atMost(10, SECONDS).until(() -> 19 | movieService.searchMovies(title) != null 20 | ); 21 | Movie result = movieService.searchMovies(title); 22 | Assertions.assertNotNull(result); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test-suite-java/src/test/java/micronaut/example/exception/MovieServiceException.java: -------------------------------------------------------------------------------- 1 | package micronaut.example.exception; 2 | 3 | public class MovieServiceException extends RuntimeException { 4 | 5 | public MovieServiceException(String message, Throwable cause) { 6 | super(message, cause); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test-suite-java/src/test/java/micronaut/example/service/Movie.java: -------------------------------------------------------------------------------- 1 | package micronaut.example.service; 2 | 3 | import io.micronaut.core.annotation.Introspected; 4 | 5 | @Introspected 6 | public class Movie { 7 | 8 | private String imdb; 9 | private String title; 10 | 11 | public Movie(String imdb, String title) { 12 | this.imdb = imdb; 13 | this.title = title; 14 | } 15 | 16 | public String getImdb() { 17 | return imdb; 18 | } 19 | 20 | public void setImdb(String imdb) { 21 | this.imdb = imdb; 22 | } 23 | 24 | public String getTitle() { 25 | return title; 26 | } 27 | 28 | public void setTitle(String title) { 29 | this.title = title; 30 | } 31 | 32 | @Override 33 | public String toString() { 34 | return "Movie{" + 35 | "imdb='" + imdb + '\'' + 36 | ", title='" + title + '\'' + 37 | '}'; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test-suite-java/src/test/java/micronaut/example/service/MovieService.java: -------------------------------------------------------------------------------- 1 | package micronaut.example.service; 2 | 3 | 4 | public interface MovieService { 5 | 6 | String saveMovie(Movie movie); 7 | 8 | Movie searchMovies(String title); 9 | 10 | } 11 | -------------------------------------------------------------------------------- /test-suite-java/src/test/java/micronaut/example/service/MovieServiceImpl.java: -------------------------------------------------------------------------------- 1 | package micronaut.example.service; 2 | 3 | import java.util.Iterator; 4 | 5 | import co.elastic.clients.elasticsearch.ElasticsearchClient; 6 | import co.elastic.clients.elasticsearch.core.IndexRequest; 7 | import co.elastic.clients.elasticsearch.core.IndexResponse; 8 | import co.elastic.clients.elasticsearch.core.SearchResponse; 9 | import co.elastic.clients.elasticsearch.core.search.Hit; 10 | import io.micronaut.context.annotation.Value; 11 | import jakarta.inject.Singleton; 12 | import micronaut.example.exception.MovieServiceException; 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | 16 | @Singleton 17 | public class MovieServiceImpl implements MovieService { 18 | 19 | private static final Logger LOG = LoggerFactory.getLogger(MovieServiceImpl.class); 20 | 21 | @Value("${elasticsearch.indexes.movies}") 22 | String moviesIndex; 23 | 24 | private final ElasticsearchClient client; 25 | 26 | public MovieServiceImpl(ElasticsearchClient client) { 27 | this.client = client; 28 | } 29 | 30 | @Override 31 | public String saveMovie(Movie movie) { 32 | try { 33 | IndexRequest indexRequest = new IndexRequest.Builder() 34 | .index(moviesIndex) 35 | .document(movie) 36 | .build(); 37 | 38 | IndexResponse indexResponse = client.index(indexRequest); 39 | String id = indexResponse.id(); 40 | 41 | LOG.info("Document for '{}' {} successfully in ES. The id is: {}", movie, indexResponse.result(), id); 42 | return id; 43 | } catch (Exception e) { 44 | String errorMessage = String.format("An exception occurred while indexing '%s'", movie); 45 | LOG.error(errorMessage); 46 | throw new MovieServiceException(errorMessage, e); 47 | } 48 | } 49 | 50 | @Override 51 | public Movie searchMovies(String title) { 52 | try { 53 | SearchResponse searchResponse = client.search((s) -> 54 | s.index(moviesIndex) 55 | .query(q -> q.match(m -> 56 | m.field("title") 57 | .query(title) 58 | )), Movie.class 59 | ); 60 | LOG.info("Searching for '{}' took {} and found {}", title, searchResponse.took(), searchResponse.hits().total().value()); 61 | 62 | Iterator> hits = searchResponse.hits().hits().iterator(); 63 | if (hits.hasNext()) { 64 | return hits.next().source(); 65 | } 66 | return null; 67 | 68 | } catch (Exception e) { 69 | String errorMessage = String.format("An exception occurred while searching for title '%s'", title); 70 | LOG.error(errorMessage); 71 | throw new MovieServiceException(errorMessage, e); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /test-suite-java/src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | micronaut: 2 | application: 3 | name: micronaut-elasticsearch-graal 4 | elasticsearch: 5 | indexes: 6 | movies: micronaut.movies 7 | test-resources: 8 | containers: 9 | elasticsearch: 10 | startup-timeout: 300s 11 | -------------------------------------------------------------------------------- /test-suite-java/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | %cyan(%d{HH:mm:ss.SSS}) %gray([%thread]) %highlight(%-5level) %magenta(%logger{36}) - %msg%n 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | --------------------------------------------------------------------------------