├── .github
├── dependabot.yml
└── workflows
│ ├── maven.yml
│ └── pr.yml
├── .gitignore
├── .mergify.yml
├── .mvn
├── jvm.config
└── maven.config
├── LICENSE
├── NOTICE
├── README.md
├── pom.xml
└── src
├── main
├── java
│ └── fr
│ │ └── pilato
│ │ └── spring
│ │ └── elasticsearch
│ │ ├── ElasticsearchClientFactoryBean.java
│ │ ├── SSLUtils.java
│ │ └── Tuple.java
└── resources
│ └── org
│ └── apache
│ └── maven
│ └── plugin
│ └── announcement
│ └── announcement.vm
└── test
├── java
└── fr
│ └── pilato
│ └── spring
│ └── elasticsearch
│ ├── it
│ ├── BaseTest.java
│ └── annotation
│ │ ├── AbstractAnnotationContextModel.java
│ │ └── rest
│ │ ├── AbstractRestAnnotationContextModel.java
│ │ ├── RestAppConfig.java
│ │ ├── aliases
│ │ ├── AliasesTest.java
│ │ └── AppConfig.java
│ │ ├── badclasspath
│ │ ├── AppConfig.java
│ │ └── BadClasspath7Test.java
│ │ ├── configuration
│ │ ├── AppConfig.java
│ │ └── ConfigurationTest.java
│ │ ├── customanalyzers
│ │ ├── AppConfig.java
│ │ └── CustomAnalyzers12Test.java
│ │ ├── indextemplates
│ │ ├── AppConfig.java
│ │ └── IndexTemplatesTest.java
│ │ ├── indicesalreadyexist
│ │ ├── AppConfig.java
│ │ └── IndicesAlreadyExistTest.java
│ │ ├── lifecycles
│ │ ├── AppConfig.java
│ │ └── LifecyclesTest.java
│ │ ├── manualsettings
│ │ ├── AppConfig.java
│ │ └── ManualSettingsTest.java
│ │ ├── mapping
│ │ ├── AppConfig.java
│ │ └── MappingTest.java
│ │ ├── mappingconvention
│ │ ├── AppConfig.java
│ │ └── MappingConventionTest.java
│ │ ├── mappingfailed
│ │ ├── AppConfig.java
│ │ └── MappingFailedTest.java
│ │ ├── multipleclients
│ │ ├── AppConfig.java
│ │ └── MultipleClientsTest.java
│ │ ├── pipelines
│ │ ├── AppConfig.java
│ │ └── PipelinesTest.java
│ │ ├── settings13
│ │ ├── AppConfig.java
│ │ └── Settings13Test.java
│ │ ├── settingsfailed
│ │ ├── AppConfig.java
│ │ └── SettingsFailedTest.java
│ │ ├── settingsnomapping21
│ │ ├── AppConfig.java
│ │ └── SettingsNoMapping21Test.java
│ │ ├── shards
│ │ └── AppConfig.java
│ │ ├── updatesettingsdisabled31
│ │ ├── AppConfig.java
│ │ └── UpdateSettingsDisabled31Test.java
│ │ └── updatesettingsenabled31
│ │ ├── AppConfig.java
│ │ └── UpdateSettings31Test.java
│ └── unit
│ └── ClassPathReaderTest.java
└── resources
├── classpath-reader-test.txt
├── es
└── twitter
│ └── _settings.json
├── log4j2.xml
└── models
└── root
├── aliases
├── _aliases.json
├── test_1
│ └── _settings.json
├── test_2
│ └── _settings.json
└── twitter
│ └── _settings.json
├── custom-analyzers-12
└── client
│ └── twitter
│ └── _settings.json
├── index-templates
└── client
│ ├── _component_templates
│ ├── component1.json
│ └── component2.json
│ └── _index_templates
│ └── template_1.json
├── index-with-type
└── client
│ └── twitter
│ └── _doc.json
├── indices-already-exist-86
└── client
│ ├── badindex
│ └── _settings.json
│ └── twitter
│ └── _settings.json
├── lifecycles
├── _index_lifecycles
│ └── policy1.json
└── twitter
│ └── _settings.json
├── manual-settings
├── _aliases.json
├── _component_templates
│ ├── component1.json
│ └── component2.json
├── _index_templates
│ ├── template_1.json
│ └── template_2.json
├── _pipelines
│ ├── pipeline1.json
│ └── pipeline2.json
└── foobar
│ └── _settings.json
├── mapping-failed
├── client1
│ └── twitter
│ │ └── _settings.json
└── client2
│ └── twitter
│ └── _update_settings.json
├── mapping
├── client1
│ └── twitter
│ │ └── _settings.json
└── client2
│ └── twitter
│ └── _settings.json
├── multiple-clients
├── client1
│ └── twitter
│ │ └── _settings.json
└── client2
│ └── twitter
│ └── _settings.json
├── no-namespace
└── client
│ ├── rss
│ └── _settings.json
│ └── twitter
│ └── _settings.json
├── pipelines
└── _pipelines
│ └── pipeline1.json
├── plugins
└── client
│ └── twitter
│ ├── _doc.json
│ └── _settings.json
├── rest-client-namespace
└── client
│ └── twitter
│ └── _settings.json
├── settings-13
└── client
│ ├── rss
│ └── _settings.json
│ └── twitter
│ └── _settings.json
├── settings-failed
├── client1
│ └── twitter
│ │ └── _settings.json
└── client2
│ └── twitter
│ └── _update_settings.json
├── settings-no-mapping-21
└── client
│ └── twitter
│ └── _settings.json
├── shards
└── client
│ └── twitter
│ └── _settings.json
├── update-settings-31
├── client1
│ └── twitter
│ │ └── _settings.json
└── client2
│ └── twitter
│ └── _update_settings.json
└── update-settings-disabled-31
├── client1
└── twitter
│ └── _settings.json
└── client2
└── twitter
└── _update_settings.json
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: maven
4 | directory: "/"
5 | schedule:
6 | interval: daily
7 | time: "04:00"
8 | open-pull-requests-limit: 99
9 | reviewers:
10 | - dadoonet
11 | assignees:
12 | - dadoonet
13 | labels:
14 | - update
15 |
--------------------------------------------------------------------------------
/.github/workflows/maven.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a Java project with Maven
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
3 |
4 | name: Build and Deploy the master branch
5 |
6 | on:
7 | push:
8 | branches: [ master ]
9 |
10 | jobs:
11 | build:
12 |
13 | runs-on: ubuntu-latest
14 |
15 | steps:
16 | - uses: actions/checkout@v2
17 | - name: Set up JDK 17 and Maven Central Repository
18 | uses: actions/setup-java@v2
19 | with:
20 | java-version: '17'
21 | distribution: 'adopt'
22 | - name: Cache Maven packages
23 | uses: actions/cache@v2
24 | with:
25 | path: ~/.m2
26 | key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
27 | restore-keys: ${{ runner.os }}-m2
28 | - name: Build with Maven
29 | run: mvn --batch-mode --update-snapshots verify
30 |
31 | deploy:
32 | needs: build
33 | runs-on: ubuntu-latest
34 |
35 | steps:
36 | - uses: actions/checkout@v2
37 | - name: Cache Maven packages
38 | uses: actions/cache@v2
39 | with:
40 | path: ~/.m2
41 | key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
42 | restore-keys: ${{ runner.os }}-m2
43 | - name: Set up JDK 14 and Maven Central Repository
44 | uses: actions/setup-java@v2
45 | with:
46 | java-version: '17'
47 | distribution: 'adopt'
48 | server-id: sonatype-nexus-snapshots
49 | server-username: MAVEN_USERNAME
50 | server-password: MAVEN_PASSWORD
51 | - name: Deploy with Maven
52 | run: mvn deploy -DskipTests
53 | env:
54 | MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}
55 | MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }}
56 |
--------------------------------------------------------------------------------
/.github/workflows/pr.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a Java project with Maven
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
3 |
4 | name: Build Pull Requests
5 |
6 | on: [pull_request]
7 |
8 | jobs:
9 | build:
10 |
11 | runs-on: ubuntu-latest
12 |
13 | steps:
14 | - uses: actions/checkout@v2
15 | - name: Set up JDK 17 and Maven Central Repository
16 | uses: actions/setup-java@v2
17 | with:
18 | java-version: '17'
19 | distribution: 'adopt'
20 | - name: Cache Maven packages
21 | uses: actions/cache@v2
22 | with:
23 | path: ~/.m2
24 | key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
25 | restore-keys: ${{ runner.os }}-m2
26 | - name: Build with Maven
27 | run: mvn --batch-mode --update-snapshots verify
28 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.project
2 | /.classpath
3 | /.settings
4 | /target
5 | *.iml
6 | *.idea
7 |
--------------------------------------------------------------------------------
/.mergify.yml:
--------------------------------------------------------------------------------
1 | pull_request_rules:
2 | - name: automatic merge on CI success and review
3 | conditions:
4 | - check-success=build
5 | - "#approved-reviews-by>=1"
6 | actions:
7 | merge:
8 | method: merge
9 |
--------------------------------------------------------------------------------
/.mvn/jvm.config:
--------------------------------------------------------------------------------
1 | -Xmx1024m -Xms1024m -Djava.awt.headless=true
2 |
3 |
--------------------------------------------------------------------------------
/.mvn/maven.config:
--------------------------------------------------------------------------------
1 | -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/NOTICE:
--------------------------------------------------------------------------------
1 | Copyright (c) David Pilato - 2012
2 |
3 | This product includes software developed by The Apache Software
4 | Foundation (http://www.apache.org/).
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Spring factories for Elasticsearch
2 |
3 | Welcome to the Spring factories for [Elasticsearch](https://www.elastic.co/elasticsearch/) project.
4 |
5 | The factory provides a [Java Rest Client for Elasticsearch](https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/current/)
6 | and automatically create index settings and templates based on what is found in the classpath:
7 |
8 | * `/es/_index_lifecycles/` for [index lifecycles policies](#index-lifecycles-policies)
9 | * `/es/INDEXNAME/_settings.json` for [index settings and mappings](#indices) for a given index `INDEXNAME`
10 | * `/es/INDEXNAME/_update_settings.json` to [update existing index settings and mappings](#indices) for a given index `INDEXNAME`
11 | * `/es/_component_templates/` for [component templates](#component-templates)
12 | * `/es/_index_templates/` for [index templates](#index-templates)
13 | * `/es/_pipelines/` for [ingest pipelines](#ingest-pipelines)
14 | * `/es/_aliases.json` for [aliases](#aliases)
15 |
16 | ## Documentation
17 |
18 | * For 8.x elasticsearch versions, you are reading the latest documentation.
19 | * For 7.x elasticsearch versions, look at [es-7.x branch](https://github.com/dadoonet/spring-elasticsearch/tree/es-7.x).
20 | * For 6.x elasticsearch versions, look at [es-6.x branch](https://github.com/dadoonet/spring-elasticsearch/tree/es-6.x).
21 | * For 5.x elasticsearch versions, look at [es-5.x branch](https://github.com/dadoonet/spring-elasticsearch/tree/es-5.x).
22 | * For 2.x elasticsearch versions, look at [es-2.x branch](https://github.com/dadoonet/spring-elasticsearch/tree/es-2.x).
23 | * For 1.x elasticsearch versions, look at [es-1.4 branch](https://github.com/dadoonet/spring-elasticsearch/tree/es-1.4).
24 | * For 0.x elasticsearch versions, look at [0.x branch](https://github.com/dadoonet/spring-elasticsearch/tree/0.x).
25 |
26 | | spring-elasticsearch | elasticsearch | Spring | Release date |
27 | |:--------------------:|:-------------:|:------:|:------------:|
28 | | 8.7-SNAPSHOT | 8.x | 6.0.7 | |
29 | | 7.1 | 7.0 - 7.x | 5.3.15 | 2022-01-13 |
30 | | 7.0 | 7.0 - 7.x | 5.3.8 | 2021-06-21 |
31 | | 6.7 | 6.7 - 6.x | 5.1.3 | 2019-04-13 |
32 | | 6.2 | 6.0 - 6.x | 5.1.3 | 2019-01-08 |
33 | | 6.1 | 6.0 - 6.x | 5.0.7 | 2018-07-22 |
34 | | 6.0 | 6.0 - 6.x | 5.0.3 | 2018-02-08 |
35 | | 5.0 | 5.0 - 5.x | 4.3.10 | 2018-02-04 |
36 | | 2.2.0 | 2.0 - 2.4 | 4.2.3 | 2017-03-09 |
37 | | 2.1.0 | 2.0, 2.1 | 4.2.3 | 2015-11-25 |
38 | | 2.0.0 | 2.0 | 4.1.4 | 2015-10-25 |
39 | | 1.4.2 | < 2.0 | 4.1.4 | 2015-03-03 |
40 | | 1.4.1 | 1.4 | 4.1.4 | 2015-02-28 |
41 | | 1.4.0 | 1.4 | 4.1.4 | 2015-01-03 |
42 | | 1.3.0 | 1.3 | 4.0.6 | 2014-09-01 |
43 | | 1.0.0 | 1.0 | 3.2.2 | 2014-02-14 |
44 |
45 | ## Build Status
46 |
47 | [](https://maven-badges.herokuapp.com/maven-central/fr.pilato.spring/spring-elasticsearch/)
48 | [](https://github.com/dadoonet/spring-elasticsearch/actions/workflows/maven.yml)
49 |
50 | ## Release notes
51 |
52 | ### Changes in 8.7
53 |
54 | * Update to Spring 6.0.7
55 | * Update to Java 17 (needed by Spring 6)
56 | * Update to Beyonder 8.6
57 | * Provides now the new official [Java Rest Client for Elasticsearch](https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/current/)
58 | * Removed deprecated templates
59 | * Removed deprecated XML support
60 | * As a side effect of a previous removal (TransportClient), async initialization of the client has been removed.
61 | * Deprecated `setProperties(Properties)` method.
62 | * Add a wait for yellow health when creating a new index
63 |
64 | ### Changes in 7.1
65 |
66 | * Update to Beyonder 7.16 which brings in support for index lifecycles.
67 | You can add your index lifecycles policies in the `_index_lifecycles` dir.
68 |
69 | ### Major (breaking) changes in 7.0
70 |
71 | * The `TransportClient` has been removed.
72 |
73 | * As in Elasticsearch 7.x, only one single type is supported, you need to provide the mapping within
74 | the index settings ( `_settings.json` file). As a consequence:
75 | * `forceMapping` setting has been replaced by `forceIndex`.
76 | * `mappings` setting has been replaced by `indices`.
77 | * `mergeMapping` setting has been removed.
78 |
79 | * `forceTemplate` setting has been removed. A template should be always updated.
80 |
81 | * `_template` dir has been deprecated by `_templates` dir.
82 |
83 | ## Getting Started
84 |
85 | ### Maven dependency
86 |
87 | Import spring-elasticsearch in you project `pom.xml` file:
88 |
89 | ```xml
90 |
91 | fr.pilato.spring
92 | spring-elasticsearch
93 | 8.7
94 |
95 | ```
96 |
97 | If you want to set a specific version of the Elasticsearch Java client, add it to your `pom.xml` file:
98 |
99 | ```xml
100 |
101 |
102 | co.elastic.clients
103 | elasticsearch-java
104 | ${elasticsearch.version}
105 |
106 |
107 | org.elasticsearch.client
108 | elasticsearch-rest-client
109 | ${elasticsearch.version}
110 |
111 |
112 | ```
113 |
114 | If you want to try out the most recent SNAPSHOT version [deployed on Sonatype](https://oss.sonatype.org/content/repositories/snapshots/fr/pilato/spring/spring-elasticsearch/):
115 |
116 | ```xml
117 |
118 | fr.pilato.spring
119 | spring-elasticsearch
120 | 8.8-SNAPSHOT
121 |
122 | ```
123 |
124 | Don't forget to add if needed the following repository in your `pom.xml`:
125 |
126 | ```xml
127 |
128 |
129 | oss-snapshots
130 | Sonatype OSS Snapshots
131 | https://s01.oss.sonatype.org/content/repositories/snapshots/
132 | false
133 | true
134 |
135 |
136 | ```
137 |
138 | If you depend on an elasticsearch SNAPSHOT version, you need to add the following repository to your `pom.xml`:
139 |
140 | ```xml
141 |
142 |
143 | elastic-snapshots
144 | Elastic Snapshots
145 | http://snapshots.elastic.co/maven/
146 | false
147 | true
148 |
149 |
150 | ```
151 |
152 | ### Logger
153 |
154 | We are using [slf4j](http://www.slf4j.org/) for logging but you have to provide the logging implementation
155 | you want to use and bind it.
156 |
157 | For example for this project we are using for tests [log4j2](http://logging.apache.org/log4j/).
158 | If you want to do so, add to your `pom.xml`:
159 |
160 | ```xml
161 |
162 |
163 | org.apache.logging.log4j
164 | log4j-api
165 | 2.20.0
166 |
167 |
168 | org.apache.logging.log4j
169 | log4j-slf4j2-impl
170 | 2.20.0
171 |
172 |
173 | org.apache.logging.log4j
174 | log4j-core
175 | 2.20.0
176 |
177 |
178 | ```
179 |
180 | ## Using Java Annotations
181 |
182 | Let's say you want to use Spring Java Annotations, here is a typical application you can build.
183 |
184 | `pom.xml`:
185 |
186 | ```xml
187 |
188 |
191 | 4.0.0
192 |
193 | fr.pilato.tests
194 | spring-elasticsearch-test
195 | 1.0-SNAPSHOT
196 |
197 |
198 |
199 | fr.pilato.spring
200 | spring-elasticsearch
201 | 8.7
202 |
203 |
204 |
205 | ```
206 |
207 | `App.java`:
208 |
209 | ```java
210 | package fr.pilato.tests;
211 |
212 | import org.springframework.beans.factory.annotation.Autowired;
213 | import org.springframework.context.annotation.AnnotationConfigApplicationContext;
214 | import org.springframework.context.annotation.Bean;
215 | import org.springframework.context.annotation.Configuration;
216 | import org.springframework.stereotype.Component;
217 |
218 | import java.io.IOException;
219 |
220 | @Component
221 | public class RestApp {
222 |
223 | @Configuration
224 | public class AppConfig {
225 | @Bean
226 | public ElasticsearchClient esClient() {
227 | ElasticsearchClientFactoryBean factory = new ElasticsearchClientFactoryBean();
228 | factory.setEsNodes(new String[]{"https://127.0.0.1:9200"});
229 | factory.setUsername("elastic");
230 | factory.setPassword("changeme");
231 | factory.afterPropertiesSet();
232 | return factory.getObject();
233 | }
234 | }
235 |
236 | @Autowired
237 | private ElasticsearchClient client;
238 |
239 | public static void main(String[] args) {
240 | AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
241 | context.scan("fr.pilato.tests");
242 | context.refresh();
243 |
244 | RestApp p = context.getBean(RestApp.class);
245 | p.run();
246 |
247 | context.close();
248 | }
249 |
250 | private void run() {
251 | // Run an advanced request
252 | client.info();
253 |
254 | // You still have access to the Low Level client
255 | client.getLowLevel().performRequest(new Request("GET", "/"));
256 | }
257 | }
258 | ```
259 |
260 | ## Features
261 |
262 | The factory provides a [Java Rest Client for Elasticsearch](https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/current/)
263 | and automatically create index settings and templates based on what is found in the classpath:
264 |
265 | * `/es/INDEXNAME/_settings.json` for [index settings and mappings](#indices) for a given index `INDEXNAME`
266 | * `/es/INDEXNAME/_update_settings.json` to [update existing index settings and mappings](#indices) for a given index `INDEXNAME`
267 | * `/es/_component_templates/` for [component templates](#component-templates)
268 | * `/es/_index_templates/` for [index templates](#index-templates)
269 | * `/es/_pipelines/` for [ingest pipelines](#ingest-pipelines)
270 | * `/es/_aliases.json` for [aliases](#aliases)
271 | * `/es/_index_lifecycles/` for [index lifecycles policies](#index-lifecycles-policies)
272 |
273 | ### Autoscan
274 |
275 | By default, the factory will scan the classpath inside the default `/es` directory.
276 | You can disable the autoscan and then provide manually every name for indices, templates...
277 |
278 | ```java
279 | ElasticsearchClientFactoryBean factory = new ElasticsearchClientFactoryBean();
280 | factory.setAutoscan(false);
281 | factory.setIndices(new String[]{"twitter"});
282 | ```
283 |
284 | ### Default directory
285 |
286 | You can change the default directory from `/es` to something else. The factory will look into this
287 | directory to find the indices and the settings for the indices, templates...
288 |
289 | ```java
290 | ElasticsearchClientFactoryBean factory = new ElasticsearchClientFactoryBean();
291 | factory.setClasspathRoot("/foo");
292 | ```
293 |
294 | ### Indices
295 |
296 | If you add in your classpath a file named `/es/twitter/_settings.json`, it will be automatically applied to define
297 | settings for your `twitter` index.
298 |
299 | For example, create the following file `src/main/resources/es/twitter/_settings.json` in your project:
300 |
301 | ```json
302 | {
303 | "settings" : {
304 | "number_of_shards" : 3,
305 | "number_of_replicas" : 2
306 | },
307 | "mappings": {
308 | "properties" : {
309 | "message" : {"type" : "text", "store" : "yes"}
310 | }
311 | }
312 | }
313 | ```
314 |
315 | If you need to update settings for an existing index, let say `twitter`, add a file named `/es/twitter/_update_settings.json`
316 | in your classpath. The factory will detect it and will try to update the settings:
317 |
318 | ```json
319 | {
320 | "index" : {
321 | "number_of_replicas" : 1
322 | }
323 | }
324 | ```
325 |
326 | If you want to remove the existing indices every time the factory starts, you can use the `forceIndex` option:
327 |
328 | ```java
329 | ElasticsearchClientFactoryBean factory = new ElasticsearchClientFactoryBean();
330 | // Be careful: IT WILL REMOVE ALL EXISTING DATA FOR THE MANAGED INDICES.
331 | factory.setForceIndex(true);
332 | ```
333 |
334 | Be careful: **IT WILL REMOVE ALL EXISTING DATA** FOR THE MANAGED INDICES.
335 |
336 |
337 | ### Component templates
338 |
339 | This feature will call the [Component Templates APIs](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-component-template.html).
340 | It's very common to use it with [index templates](#index-templates).
341 |
342 | Let say you want to create a component template named `component1`. Just create a file named
343 | `/es/_component_templates/component1.json`:
344 |
345 | ```json
346 | {
347 | "template": {
348 | "mappings": {
349 | "properties": {
350 | "@timestamp": {
351 | "type": "date"
352 | }
353 | }
354 | }
355 | }
356 | }
357 | ```
358 |
359 | Let say you want to create a component template named `component2`. Just create a file named
360 | `/es/_component_templates/component2.json`:
361 |
362 | ```json
363 | {
364 | "template": {
365 | "mappings": {
366 | "runtime": {
367 | "day_of_week": {
368 | "type": "keyword",
369 | "script": {
370 | "source": "emit(doc['@timestamp'].value.dayOfWeekEnum.getDisplayName(TextStyle.FULL, Locale.ROOT))"
371 | }
372 | }
373 | }
374 | }
375 | }
376 | }
377 | ```
378 |
379 | You can use then the 2 component templates in an index template as shown below.
380 |
381 | ### Index templates
382 |
383 | This feature will call the [Index Templates APIs](https://www.elastic.co/guide/en/elasticsearch/reference/current/index-templates.html).
384 | It can be used with [component templates](#component-templates).
385 |
386 | Let say you want to create an index template named `template_1`. Just create a file named
387 | `/es/_index_templates/template_1.json`:
388 |
389 | ```json
390 | {
391 | "index_patterns": ["te*", "bar*"],
392 | "template": {
393 | "settings": {
394 | "number_of_shards": 1
395 | },
396 | "mappings": {
397 | "_source": {
398 | "enabled": true
399 | },
400 | "properties": {
401 | "host_name": {
402 | "type": "keyword"
403 | },
404 | "created_at": {
405 | "type": "date",
406 | "format": "EEE MMM dd HH:mm:ss Z yyyy"
407 | }
408 | }
409 | },
410 | "aliases": {
411 | "mydata": { }
412 | }
413 | },
414 | "priority": 500,
415 | "composed_of": ["component1", "component2"],
416 | "version": 3,
417 | "_meta": {
418 | "description": "my custom"
419 | }
420 | }
421 | ```
422 |
423 | Note that this index template is using the 2 component templates that have been defined in the previous section.
424 |
425 | ### Aliases
426 |
427 | An alias is helpful to define or remove an alias to a given index. You could also use an [index templates](#index-templates)
428 | to do that automatically when at index creation time, but you can also define a file `/es/_aliases.json`:
429 |
430 | ```json
431 | {
432 | "actions" : [
433 | { "remove": { "index": "test_1", "alias": "test" } },
434 | { "add": { "index": "test_2", "alias": "test" } }
435 | ]
436 | }
437 | ```
438 |
439 | When the factory starts, it will automatically send the content to the [Aliases API](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-aliases.html)
440 | and move the alias `test` from index `test_1` to index `test_2`.
441 |
442 | ### Ingest Pipelines
443 |
444 | This feature will call the [Ingest Pipelines APIs](https://www.elastic.co/guide/en/elasticsearch/reference/current/ingest.html)
445 |
446 | Let say you want to create an ingest pipeline named `pipeline1`. Just create a file named
447 | `/es/_pipeline/pipeline1.json`:
448 |
449 | ```json
450 | {
451 | "description": "My optional pipeline description",
452 | "processors": [
453 | {
454 | "set": {
455 | "description": "My optional processor description",
456 | "field": "my-long-field",
457 | "value": 10
458 | }
459 | },
460 | {
461 | "set": {
462 | "description": "Set 'my-boolean-field' to true",
463 | "field": "my-boolean-field",
464 | "value": true
465 | }
466 | },
467 | {
468 | "lowercase": {
469 | "field": "my-keyword-field"
470 | }
471 | }
472 | ]
473 | }
474 | ```
475 |
476 | ### Index Lifecycles Policies
477 |
478 | This feature will call the [Index Lifecycle APIs](https://www.elastic.co/guide/en/elasticsearch/reference/current/index-lifecycle-management.html).
479 |
480 | Let say you want to create a policy named `policy1`. Just create a file named
481 | `/es/_index_lifecycles/policy1.json`:
482 |
483 | ```json
484 | {
485 | "policy": {
486 | "phases": {
487 | "warm": {
488 | "min_age": "10d",
489 | "actions": {
490 | "forcemerge": {
491 | "max_num_segments": 1
492 | }
493 | }
494 | },
495 | "delete": {
496 | "min_age": "30d",
497 | "actions": {
498 | "delete": {}
499 | }
500 | }
501 | }
502 | }
503 | }
504 | ```
505 |
506 | It will be automatically loaded into elasticsearch when you start the factory.
507 | If you want to apply this policy to your index, you can define the following settings for the index in
508 | `/es/twitter/_settings.json`:
509 |
510 | ```json
511 | {
512 | "settings" : {
513 | "index.lifecycle.name": "policy1"
514 | }
515 | }
516 | ```
517 |
518 | ### SSL certificates
519 |
520 | If you need to specify your own SSL certificates (self-signed certificates), you can use the `setSSLContext(SSLContext)`
521 | method to do this.
522 | You can refer to the Elasticsearch [Low Level client documentation](https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/current/_encrypted_communication.html)
523 | to see some examples. Once you have created a SSLContext, you can use it in the factory:
524 |
525 | ```java
526 | Path trustStorePath = Paths.get("/path/to/truststore.p12");
527 | KeyStore truststore = KeyStore.getInstance("pkcs12");
528 | try (InputStream is = Files.newInputStream(trustStorePath)) {
529 | truststore.load(is, keyStorePass.toCharArray());
530 | }
531 | SSLContextBuilder sslBuilder = SSLContexts.custom().loadTrustMaterial(truststore, null);
532 | final SSLContext sslContext = sslBuilder.build();
533 |
534 | ElasticsearchClientFactoryBean factory = new ElasticsearchClientFactoryBean();
535 | factory.setSslContext(sslContext);
536 | ```
537 |
538 | # Thanks
539 |
540 | Special thanks to
541 |
542 | - [Nicolas Huray](https://github.com/nhuray) for his contribution about
543 | [templates](https://github.com/dadoonet/spring-elasticsearch/pull/4)
544 | - [Nicolas Labrot](https://github.com/nithril) for his contribution about
545 | [async](https://github.com/dadoonet/spring-elasticsearch/pull/30)
546 |
547 | # Running tests
548 |
549 | If you want to run tests (integration tests) from your IDE, you need to start first an elasticsearch instance.
550 | Tests are expecting a node running at `https://localhost:9200` with the user `elastic` and `changeme` as the password.
551 |
552 | To run the tests using Maven (on the CLI), just run:
553 |
554 | ```sh
555 | mvn clean install
556 | ```
557 |
558 | You can change the target to run the tests. For example, if you want to run the tests against an elastic cloud instance:
559 |
560 | ```shell
561 | mvn clean install -Dtests.cluster=https://ID.es.ZONE.PROVIDER.cloud.es.io -Dtests.cluster.user=myuser -Dtests.cluster.pass=YOURPASSWORD
562 | ```
563 |
564 | # Release guide
565 |
566 | To release the project you need to run the release plugin with the `release` profile as you need to sign the artifacts:
567 |
568 | ```sh
569 | mvn release:prepare
570 | git push --tags
571 | git push
572 | mvn release:perform -Prelease
573 | ```
574 |
575 | If you need to skip the tests, run:
576 |
577 | ```sh
578 | mvn release:perform -Prelease -Darguments="-DskipTests"
579 | ```
580 |
581 | If everything is ok in https://s01.oss.sonatype.org/#stagingRepositories, you can perform the release with:
582 |
583 | ```sh
584 | mvn nexus-staging:release
585 | mvn nexus-staging:drop
586 | ```
587 |
588 | To announce the release, run:
589 |
590 | ```sh
591 | cd target/checkout
592 | # Run the following command if you want to check the announcement email
593 | mvn changes:announcement-generate
594 | cat target/announcement/announcement.vm
595 |
596 | # Announce the release (change your smtp username and password)
597 | mvn changes:announcement-mail -Dchanges.username='YourSmtpUserName' -Dchanges.password='YourSmtpUserPassword'
598 | ```
599 |
600 | # License
601 |
602 | This software is licensed under the Apache 2 license, quoted below.
603 |
604 | Copyright 2011-2023 David Pilato
605 |
606 | Licensed under the Apache License, Version 2.0 (the "License"); you may not
607 | use this file except in compliance with the License. You may obtain a copy of
608 | the License at
609 |
610 | http://www.apache.org/licenses/LICENSE-2.0
611 |
612 | Unless required by applicable law or agreed to in writing, software
613 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
614 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
615 | License for the specific language governing permissions and limitations under
616 | the License.
617 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 4.0.0
5 | fr.pilato.spring
6 | spring-elasticsearch
7 | jar
8 | spring-elasticsearch
9 | 8.7-SNAPSHOT
10 | https://github.com/dadoonet/spring-elasticsearch
11 | Spring factories for Elasticsearch
12 |
13 |
14 |
15 | The Apache Software License, Version 2.0
16 | http://www.apache.org/licenses/LICENSE-2.0.txt
17 | repo
18 |
19 |
20 |
21 |
22 | UTF-8
23 | UTF-8
24 | 17
25 |
26 | 6.0.9
27 | 8.8.1
28 | 8.6-SNAPSHOT
29 | 2.0.7
30 | 2.20.0
31 | 2.11.0
32 | 2.15.2
33 | 5.9.3
34 |
35 | false
36 | ${skipTests}
37 | ${skipTests}
38 | elastic
39 | changeme
40 | ${tests.cluster.username}:${tests.cluster.password}
41 |
42 |
43 | docker.elastic.co/elasticsearch/elasticsearch
44 | ${elasticsearch.version}
45 | 9200
46 | 9300
47 |
48 |
49 | smtp.ionos.fr
50 | 465
51 |
52 |
53 |
54 |
55 | sonatype-nexus-snapshots
56 | https://s01.oss.sonatype.org/content/repositories/snapshots
57 |
58 |
59 | sonatype-nexus-staging
60 | https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/
61 |
62 |
63 |
64 |
65 |
66 | dadoonet
67 | David Pilato
68 | david@pilato.fr
69 | http://david.pilato.fr/
70 | +1
71 |
72 |
73 | nhuray
74 | Nicolas Huray
75 | https://github.com/nhuray/
76 | +1
77 |
78 |
79 | nlabrot
80 | Nicolas Labrot
81 | https://github.com/nithril/
82 | Europe/Paris
83 |
84 |
85 |
86 |
87 | scm:git:git@github.com:dadoonet/spring-elasticsearch.git
88 | scm:git:git@github.com:dadoonet/spring-elasticsearch.git
89 | scm:git:git@github.com:dadoonet/spring-elasticsearch.git
90 | HEAD
91 |
92 |
93 |
94 | GitHub
95 | https://github.com/dadoonet/spring-elasticsearch/issues/
96 |
97 |
98 |
99 |
100 | elastic-download-service
101 | Elastic Download Service
102 | https://artifacts.elastic.co/maven/
103 | true
104 | false
105 |
106 |
107 |
108 | elastic-snapshots
109 | Elastic Snapshots
110 | https://snapshots.elastic.co/maven/
111 | false
112 | true
113 |
114 |
115 |
116 | oss-snapshots
117 | Sonatype OSS Snapshots
118 | https://s01.oss.sonatype.org/content/repositories/snapshots/
119 | false
120 | true
121 |
122 |
123 |
124 |
125 |
126 | org.hamcrest
127 | hamcrest-all
128 | 1.3
129 | test
130 |
131 |
132 |
133 | org.springframework
134 | spring-core
135 | ${spring.version}
136 |
137 |
138 | org.springframework
139 | spring-beans
140 | ${spring.version}
141 |
142 |
143 | org.springframework
144 | spring-context
145 | ${spring.version}
146 |
147 |
148 |
149 |
150 | org.slf4j
151 | slf4j-api
152 | ${slf4j.version}
153 |
154 |
155 |
156 |
157 | org.apache.logging.log4j
158 | log4j-api
159 | ${log4j.version}
160 | true
161 |
162 |
163 | org.apache.logging.log4j
164 | log4j-slf4j2-impl
165 | ${log4j.version}
166 | true
167 |
168 |
169 | org.apache.logging.log4j
170 | log4j-core
171 | ${log4j.version}
172 | true
173 |
174 |
175 |
176 |
177 | co.elastic.clients
178 | elasticsearch-java
179 | ${elasticsearch.version}
180 |
181 |
182 | org.elasticsearch.client
183 | elasticsearch-rest-client
184 | ${elasticsearch.version}
185 |
186 |
187 | fr.pilato.elasticsearch
188 | elasticsearch-beyonder
189 | ${beyonder.version}
190 |
191 |
192 | commons-io
193 | commons-io
194 | ${commons.io.version}
195 |
196 |
197 |
198 | org.springframework
199 | spring-test
200 | ${spring.version}
201 | test
202 |
203 |
204 | org.junit.jupiter
205 | junit-jupiter-api
206 | ${junit.version}
207 | test
208 |
209 |
210 | org.junit.jupiter
211 | junit-jupiter-engine
212 | ${junit.version}
213 | test
214 |
215 |
216 | cglib
217 | cglib
218 | 3.3.0
219 | test
220 |
221 |
222 | com.fasterxml.jackson.core
223 | jackson-core
224 | ${jackson.version}
225 | test
226 |
227 |
228 | com.fasterxml.jackson.core
229 | jackson-databind
230 | ${jackson.version}
231 | test
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 | org.apache.maven.plugins
240 | maven-help-plugin
241 | 3.4.0
242 |
243 |
244 | org.apache.maven.plugins
245 | maven-resources-plugin
246 | 3.3.1
247 |
248 |
249 | org.apache.maven.plugins
250 | maven-compiler-plugin
251 | 3.11.0
252 |
253 | ${java.compiler.version}
254 | ${java.compiler.version}
255 | UTF-8
256 | true
257 | true
258 | true
259 | -Xlint:all,-serial,-path,-rawtypes,-unchecked
260 |
261 |
262 |
263 | org.apache.maven.plugins
264 | maven-dependency-plugin
265 | 3.5.0
266 |
267 |
268 | org.apache.maven.plugins
269 | maven-enforcer-plugin
270 | 3.3.0
271 |
272 |
273 |
274 | ${java.compiler.version}
275 |
276 |
277 |
278 |
279 |
280 | org.sonatype.plugins
281 | nexus-staging-maven-plugin
282 | 1.6.13
283 | true
284 |
285 | sonatype-nexus-staging
286 | https://s01.oss.sonatype.org/
287 | false
288 |
289 |
290 |
291 | org.apache.maven.plugins
292 | maven-jar-plugin
293 | 3.3.0
294 |
295 |
296 | org.apache.maven.plugins
297 | maven-scm-plugin
298 | 2.0.0
299 |
300 |
301 | org.apache.maven.plugins
302 | maven-changes-plugin
303 | 2.12.1
304 |
305 | true
306 | dadoonet
307 |
308 | discuss+community-plugins@elastic.co
309 |
310 |
311 | GitHub
312 |
313 |
314 | new,doc
315 | bug
316 | update
317 | remove
318 |
319 | true
320 |
321 | https://repo1.maven.org/maven2/fr/pilato/spring/spring-elasticsearch/${project.version}/
322 |
323 |
324 |
325 |
326 | org.apache.maven.plugins
327 | maven-release-plugin
328 | 3.0.0
329 |
330 | false
331 |
332 |
333 |
334 |
335 | io.fabric8
336 | docker-maven-plugin
337 | 0.43.2
338 |
339 |
340 |
341 | spring-elasticsearch
342 | dadoonet/spring-elasticsearch:${project.version}
343 |
344 | ${integ.elasticsearch.image}:${integ.elasticsearch.version}
345 |
346 | single-node
347 | ${tests.cluster.password}
348 |
349 |
350 |
351 |
352 | tests.cluster.rest.port:9200
353 |
354 |
355 |
356 | https://localhost:${tests.cluster.rest.port}/
357 | 200..499
358 | true
359 |
360 |
361 |
362 |
363 |
364 |
365 | ${skip.integration.tests}
366 |
367 |
368 |
369 | start-elasticsearch
370 | pre-integration-test
371 |
372 | build
373 | stop
374 | start
375 |
376 |
377 |
378 | stop-elasticsearch
379 | post-integration-test
380 |
381 | stop
382 |
383 |
384 |
385 |
386 |
387 | org.apache.maven.plugins
388 | maven-surefire-plugin
389 | 3.1.0
390 |
391 |
392 | ${skip.unit.tests}
393 |
394 |
395 | **/it/**/*Test.java
396 |
397 |
398 |
399 |
400 | org.apache.maven.plugins
401 | maven-failsafe-plugin
402 | 3.1.0
403 |
404 |
407 |
408 | org.apache.maven.surefire
409 | surefire-api
410 | 3.1.0
411 |
412 |
413 |
414 |
418 |
419 | integration-tests
420 |
421 | integration-test
422 | verify
423 |
424 |
425 |
429 | ${skip.integration.tests}
430 |
431 |
432 | **/it/**/*Test.java
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 | src/test/resources
442 | true
443 |
444 |
445 |
446 |
447 |
448 |
449 | release
450 |
451 |
452 |
453 | org.apache.maven.plugins
454 | maven-javadoc-plugin
455 | 3.5.0
456 |
457 |
458 | attach-javadocs
459 |
460 | jar
461 |
462 |
463 |
464 |
465 |
466 | org.apache.maven.plugins
467 | maven-source-plugin
468 | 3.2.1
469 |
470 |
471 | attach-sources
472 |
473 | jar-no-fork
474 |
475 |
476 |
477 |
478 |
479 | org.apache.maven.plugins
480 | maven-gpg-plugin
481 | 3.1.0
482 |
483 |
484 | sign-artifacts
485 | verify
486 |
487 | sign
488 |
489 |
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
--------------------------------------------------------------------------------
/src/main/java/fr/pilato/spring/elasticsearch/ElasticsearchClientFactoryBean.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to David Pilato (the "Author") under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. Author licenses this
6 | * file to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 |
20 | package fr.pilato.spring.elasticsearch;
21 |
22 | import co.elastic.clients.elasticsearch.ElasticsearchClient;
23 | import co.elastic.clients.elasticsearch._types.HealthStatus;
24 | import co.elastic.clients.json.jackson.JacksonJsonpMapper;
25 | import co.elastic.clients.transport.ElasticsearchTransport;
26 | import co.elastic.clients.transport.rest_client.RestClientTransport;
27 | import fr.pilato.elasticsearch.tools.util.ResourceList;
28 | import fr.pilato.elasticsearch.tools.util.SettingsFinder;
29 | import org.apache.http.HttpHost;
30 | import org.apache.http.auth.AuthScope;
31 | import org.apache.http.auth.UsernamePasswordCredentials;
32 | import org.apache.http.client.CredentialsProvider;
33 | import org.apache.http.impl.client.BasicCredentialsProvider;
34 | import org.elasticsearch.client.RestClient;
35 | import org.elasticsearch.client.RestClientBuilder;
36 | import org.slf4j.Logger;
37 | import org.slf4j.LoggerFactory;
38 | import org.springframework.beans.factory.DisposableBean;
39 | import org.springframework.beans.factory.FactoryBean;
40 | import org.springframework.beans.factory.InitializingBean;
41 | import org.springframework.util.Assert;
42 |
43 | import javax.net.ssl.SSLContext;
44 | import java.io.IOException;
45 | import java.net.URISyntaxException;
46 | import java.util.ArrayList;
47 | import java.util.Arrays;
48 | import java.util.Collection;
49 | import java.util.List;
50 | import java.util.Properties;
51 |
52 | import static fr.pilato.elasticsearch.tools.updaters.ElasticsearchAliasUpdater.manageAliases;
53 | import static fr.pilato.elasticsearch.tools.updaters.ElasticsearchAliasUpdater.manageAliasesWithJsonInElasticsearch;
54 | import static fr.pilato.elasticsearch.tools.updaters.ElasticsearchComponentTemplateUpdater.createComponentTemplate;
55 | import static fr.pilato.elasticsearch.tools.updaters.ElasticsearchIndexLifecycleUpdater.createIndexLifecycle;
56 | import static fr.pilato.elasticsearch.tools.updaters.ElasticsearchIndexTemplateUpdater.createIndexTemplate;
57 | import static fr.pilato.elasticsearch.tools.updaters.ElasticsearchIndexUpdater.createIndex;
58 | import static fr.pilato.elasticsearch.tools.updaters.ElasticsearchIndexUpdater.updateSettings;
59 | import static fr.pilato.elasticsearch.tools.updaters.ElasticsearchPipelineUpdater.createPipeline;
60 | import static fr.pilato.elasticsearch.tools.util.ResourceList.findIndexNames;
61 |
62 | /**
63 | * An abstract {@link FactoryBean} used to create an Elasticsearch
64 | * {@link ElasticsearchClient}.
65 | *
66 | * The lifecycle of the underlying {@link ElasticsearchClient} instance is tied to the
67 | * lifecycle of the bean via the {@link #destroy()} method which calls
68 | * {@link RestClient#close()}
69 | *
70 | *
71 | * If not using the default https://localhost:9200, you need to define the nodes you want to communicate with
72 | * and probably the credentials.
73 | *
91 | * The factory is meant to be used with some classpath files which are automatically
92 | * loaded from {@code /es} directory to define your:
93 | *
You can force the manual creation of the above components but this is
103 | * not the goal of this factory. So it should be used only for some specific use cases:
104 | *
105 | *
106 | * Example :
107 | *
108 | *
109 | * {@code
110 | * @Configuration
111 | * public class AppConfig {
112 | * @Bean
113 | * public ElasticsearchClient esClient() throws Exception {
114 | * ElasticsearchClientFactoryBean factory = new ElasticsearchClientFactoryBean();
115 | * // Create two indices twitter and rss
116 | * factory.setIndices(new String[]{ "twitter", "rss" });
117 | * // Create an alias alltheworld on top of twitter and rss indices
118 | * factory.setAliases(new String[]{ "alltheworld:twitter", "alltheworld:rss" });
119 | * // Remove all the existing declared indices (twitter and rss). VERY DANGEROUS SETTING!
120 | * factory.setForceIndex(true);
121 | * // If setForceIndex is not set, we try to merge existing index settings
122 | * // with the provided ones
123 | * factory.setMergeSettings(true);
124 | * // Disable automatic scanning of the classpath.
125 | * factory.setAutoscan(false);
126 | * factory.afterPropertiesSet();
127 | * return factory.getObject();
128 | * }
129 | * }
130 | * }
131 | *
132 | * By default, indexes are created with their default Elasticsearch settings. You can specify
133 | * your own settings for your index by putting a /es/indexname/_settings.json in your classpath.
134 | *
135 | * So if you create a file named /es/twitter/_settings.json in your src/main/resources folder (for maven lovers),
136 | * it will be used by the factory to create the twitter index.
137 | *
342 | * That means that the factory will look in es folder to find index settings.
343 | * So if you want to define settings or mappings for the twitter index, you
344 | * should put a _settings.json file under /es/twitter/ folder.
345 | * @param classpathRoot Classpath root for index and mapping files
346 | */
347 | public void setClasspathRoot(String classpathRoot) {
348 | // For compatibility reasons, we need to convert "/classpathroot" to "classpathroot"
349 | if (classpathRoot.startsWith("/")) {
350 | this.classpathRoot = classpathRoot.substring(1);
351 | } else {
352 |
353 | this.classpathRoot = classpathRoot;
354 | }
355 | }
356 |
357 | /**
358 | * Define ES nodes to communicate with.
359 | * Defaults to [ "https://localhost:9200" ].
360 | * @param esNodes A collection of nodes
361 | */
362 | public void setEsNodes(Collection esNodes) {
363 | this.esNodes = esNodes;
364 | }
365 |
366 | /**
367 | * Define ES nodes to communicate with.
368 | * use : protocol://hostname:port form
369 | * @param esNodes An array of nodes hostname:port
370 | * @deprecated #setEsNodes(HttpHost[])
371 | */
372 | @Deprecated
373 | public void setEsNodes(String[] esNodes) {
374 | Collection hosts = new ArrayList<>(esNodes.length);
375 | for (String esNode : esNodes) {
376 | hosts.add(HttpHost.create(esNode));
377 | }
378 |
379 | this.esNodes = hosts;
380 | }
381 |
382 | /**
383 | * Define the SSLContext to use if any
384 | * @param sslContext SSLContext
385 | * @see SSLUtils#yesSSLContext() for test purposes
386 | * @see SSLUtils#createSslContextFromCa(String) when you want to pass the Elasticsearch self-signed certificate
387 | */
388 | public void setSslContext(SSLContext sslContext) {
389 | this.sslContext = sslContext;
390 | }
391 |
392 | @Override
393 | public void afterPropertiesSet() throws Exception {
394 | logger.info("Starting Elasticsearch Low Level client");
395 | lowLevelClient = buildElasticsearchLowLevelClient();
396 |
397 | logger.info("Starting Elasticsearch client");
398 | // Create the transport with a Jackson mapper
399 | ElasticsearchTransport transport = new RestClientTransport(lowLevelClient, new JacksonJsonpMapper());
400 | // And create the API client
401 | client = new ElasticsearchClient(transport);
402 |
403 | // Automagically initialize the cluster/indices
404 | initLifecycles();
405 | initPipelines();
406 | initTemplates();
407 | initSettings();
408 | initAliases();
409 | }
410 |
411 | @Override
412 | public void destroy() {
413 | try {
414 | logger.info("Closing Elasticsearch Low Level client");
415 | if (lowLevelClient != null) {
416 | lowLevelClient.close();
417 | }
418 | } catch (final Exception e) {
419 | logger.error("Error closing Elasticsearch Low Level client: ", e);
420 | }
421 | }
422 |
423 | @Override
424 | public ElasticsearchClient getObject() {
425 | return client;
426 | }
427 |
428 | @Override
429 | public Class getObjectType() {
430 | return ElasticsearchClient.class;
431 | }
432 |
433 | @Override
434 | public boolean isSingleton() {
435 | return true;
436 | }
437 |
438 | /**
439 | * We use convention over configuration : see ...
440 | */
441 | static String[] computeIndexNames(boolean autoscan, String[] resources, String classpathRoot) {
442 | if (!autoscan) {
443 | logger.debug("Automatic discovery is disabled. Only static resources are used: {}", (Object) resources);
444 | return resources;
445 | }
446 | if (resources != null && resources.length > 0) {
447 | logger.debug("Resources are manually provided so we won't do any automatic discovery.");
448 | return resources;
449 | }
450 |
451 | if (logger.isDebugEnabled()) {
452 | logger.debug("Automatic discovery is activated. Looking for definition files in classpath under [{}].",
453 | classpathRoot);
454 | }
455 |
456 | try {
457 | // Let's scan our resources
458 | return findIndexNames(classpathRoot).toArray(new String[0]);
459 | } catch (IOException |URISyntaxException e) {
460 | logger.debug("Automatic discovery does not succeed for finding json files in classpath under " + classpathRoot + ".");
461 | logger.trace("", e);
462 | return null;
463 | }
464 | }
465 |
466 | static String[] discoverFromClasspath(boolean autoscan, String[] resources, String classpathRoot, String subdir) {
467 | if (!autoscan) {
468 | logger.debug("Automatic discovery is disabled. Only static resources are used: {}", (Object) resources);
469 | return resources;
470 | }
471 | if (resources != null && resources.length > 0) {
472 | logger.debug("Resources are manually provided so we won't do any automatic discovery.");
473 | return resources;
474 | }
475 |
476 | logger.debug("Automatic discovery is activated. Looking for resource files in classpath under [{}/{}].",
477 | classpathRoot, subdir);
478 | ArrayList autoResources = new ArrayList<>();
479 | try {
480 | // Let's scan our resources
481 | List scannedResources = ResourceList.getResourceNames(classpathRoot, subdir);
482 | autoResources.addAll(scannedResources);
483 |
484 | return autoResources.toArray(new String[0]);
485 | } catch (IOException|URISyntaxException e) {
486 | logger.debug("Automatic discovery does not succeed for finding json files in classpath under [{}/{}].", classpathRoot, subdir);
487 | logger.trace("", e);
488 | return resources;
489 | }
490 | }
491 |
492 | /**
493 | * Init index settings if needed.
494 | *
Note that you can force to reinit the index using {@link #setForceIndex(boolean)}
495 | */
496 | private void initSettings() throws Exception {
497 | logger.debug("Initializing indices");
498 | String[] indices = computeIndexNames(autoscan, this.indices, classpathRoot);
499 | // We extract indexes and mappings to manage from mappings definition
500 | if (indices != null) {
501 | // Let's initialize indexes and mappings if needed
502 | for (String index : indices) {
503 | logger.debug("Initializing index {}", index);
504 | createIndex(lowLevelClient, classpathRoot, index, forceIndex);
505 | if (mergeSettings) {
506 | updateSettings(lowLevelClient, classpathRoot, index);
507 | }
508 | }
509 |
510 | // Let's wait until the index is properly ready to be used
511 | client.cluster().health(hrb -> hrb.index(Arrays.stream(indices).toList()).waitForStatus(HealthStatus.Yellow));
512 | }
513 | }
514 |
515 | /**
516 | * It creates or updates:
517 | *
518 | *
component templates
519 | *
index templates
520 | *
521 | */
522 | private void initTemplates() throws Exception {
523 | logger.debug("Initializing component templates");
524 | String[] componentTemplates = discoverFromClasspath(autoscan, this.componentTemplates, classpathRoot, SettingsFinder.Defaults.ComponentTemplatesDir);
525 | if (componentTemplates != null) {
526 | for (String componentTemplate : componentTemplates) {
527 | logger.debug("Initializing component template {}", componentTemplate);
528 | Assert.hasText(componentTemplate, "Can not read component template in ["
529 | + componentTemplate
530 | + "]. Check that component template is not empty.");
531 | createComponentTemplate(lowLevelClient, classpathRoot, componentTemplate);
532 | }
533 | }
534 | logger.debug("Initializing index templates");
535 | String[] indexTemplates = discoverFromClasspath(autoscan, this.indexTemplates, classpathRoot, SettingsFinder.Defaults.IndexTemplatesDir);
536 | if (indexTemplates != null) {
537 | for (String indexTemplate : indexTemplates) {
538 | logger.debug("Initializing index template {}", indexTemplate);
539 | Assert.hasText(indexTemplate, "Can not read component template in ["
540 | + indexTemplate
541 | + "]. Check that component template is not empty.");
542 | createIndexTemplate(lowLevelClient, classpathRoot, indexTemplate);
543 | }
544 | }
545 | }
546 |
547 | /**
548 | * It creates or updates the index pipelines
549 | */
550 | private void initPipelines() throws Exception {
551 | logger.debug("Initializing ingest pipelines");
552 | String[] pipelines = discoverFromClasspath(autoscan, this.pipelines, classpathRoot, SettingsFinder.Defaults.PipelinesDir);
553 | if (pipelines != null) {
554 | for (String pipeline : pipelines) {
555 | logger.debug("Initializing pipeline {}", pipeline);
556 | Assert.hasText(pipeline, "Can not read pipeline in ["
557 | + pipeline
558 | + "]. Check that pipeline is not empty.");
559 | createPipeline(lowLevelClient, classpathRoot, pipeline);
560 | }
561 | }
562 | }
563 |
564 | /**
565 | * It creates or updates the index lifecycles
566 | */
567 | private void initLifecycles() throws Exception {
568 | logger.debug("Initializing lifecycle policies");
569 | String [] lifecycles = discoverFromClasspath(autoscan, this.lifecycles, classpathRoot, SettingsFinder.Defaults.IndexLifecyclesDir);
570 | if (lifecycles != null) {
571 | for (String lifecycle : lifecycles) {
572 | logger.debug("Initializing lifecycle {}", lifecycle);
573 | Assert.hasText(lifecycle, "Can not read lifecycle in ["
574 | + lifecycle
575 | + "]. Check that lifecycle is not empty.");
576 | createIndexLifecycle(lowLevelClient, classpathRoot, lifecycle);
577 | }
578 | }
579 | }
580 |
581 | /**
582 | * Init aliases if needed.
583 | */
584 | private void initAliases() throws Exception {
585 | logger.debug("Initializing aliases");
586 |
587 | if (!autoscan) {
588 | logger.debug("Automatic discovery is disabled. Only static resources are used: {}", (Object) aliases);
589 | } else {
590 | logger.debug("Automatic discovery is activated. Looking for aliases in classpath under [{}/{}{}].",
591 | classpathRoot, SettingsFinder.Defaults.AliasesFile, SettingsFinder.Defaults.JsonFileExtension);
592 | }
593 |
594 | if (aliases != null && aliases.length > 0) {
595 | logger.debug("Resources are manually provided so we won't do any automatic discovery.");
596 | String request = "{\"actions\":[";
597 | boolean first = true;
598 | for (String aliasIndex : aliases) {
599 | if (!first) {
600 | request += ",";
601 | }
602 | first = false;
603 | Tuple aliasIndexSplitted = computeAlias(aliasIndex);
604 | logger.debug("add alias {} on index {}", aliasIndexSplitted.v2(), aliasIndexSplitted.v1());
605 | request += "{\"add\":{\"index\":\"" + aliasIndexSplitted.v1() +"\",\"alias\":\"" + aliasIndexSplitted.v2() +"\"}}";
606 | }
607 | request += "]}";
608 | manageAliasesWithJsonInElasticsearch(lowLevelClient, request);
609 | } else {
610 | manageAliases(lowLevelClient, classpathRoot);
611 | }
612 | }
613 |
614 | static Tuple computeAlias(String aliasIndex) {
615 | String[] aliasIndexSplitted = aliasIndex.split(":");
616 | String alias = aliasIndexSplitted[0];
617 | String index = aliasIndexSplitted[1];
618 |
619 | if (index == null) throw new IllegalArgumentException("Can not read index in [" + aliasIndex +
620 | "]. Check that aliases contains only aliasname:indexname elements.");
621 | if (alias == null) throw new IllegalArgumentException("Can not read mapping in [" + aliasIndex +
622 | "]. Check that aliases contains only aliasname:indexname elements.");
623 |
624 | return new Tuple<>(index, alias);
625 | }
626 |
627 | private RestClient buildElasticsearchLowLevelClient() {
628 | RestClientBuilder rcb = RestClient.builder(esNodes.toArray(new HttpHost[]{}));
629 |
630 | // We need to check if we have a user security property
631 | if (username == null || password == null) {
632 | throw new IllegalArgumentException("From version 8, you MUST define a user and a password to access Elasticsearch.");
633 | }
634 |
635 | final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
636 | credentialsProvider.setCredentials(AuthScope.ANY,
637 | new UsernamePasswordCredentials(username, password));
638 |
639 | rcb.setHttpClientConfigCallback(hcb -> {
640 | hcb.setDefaultCredentialsProvider(credentialsProvider);
641 | if (sslContext != null) {
642 | hcb.setSSLContext(sslContext);
643 | }
644 | return hcb;
645 | });
646 |
647 | return rcb.build();
648 | }
649 | }
650 |
--------------------------------------------------------------------------------
/src/main/java/fr/pilato/spring/elasticsearch/SSLUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to Elasticsearch under one or more contributor
3 | * license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright
5 | * ownership. Elasticsearch licenses this file to you under
6 | * the Apache License, Version 2.0 (the "License"); you may
7 | * not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 |
20 | package fr.pilato.spring.elasticsearch;
21 |
22 | import org.apache.commons.io.IOUtils;
23 | import org.apache.http.ssl.SSLContextBuilder;
24 | import org.apache.http.ssl.SSLContexts;
25 | import org.slf4j.Logger;
26 | import org.slf4j.LoggerFactory;
27 |
28 | import javax.net.ssl.SSLContext;
29 | import javax.net.ssl.TrustManagerFactory;
30 | import javax.net.ssl.X509TrustManager;
31 | import java.io.ByteArrayInputStream;
32 | import java.io.IOException;
33 | import java.io.InputStream;
34 | import java.nio.file.Files;
35 | import java.nio.file.Path;
36 | import java.nio.file.Paths;
37 | import java.security.KeyManagementException;
38 | import java.security.KeyStore;
39 | import java.security.KeyStoreException;
40 | import java.security.NoSuchAlgorithmException;
41 | import java.security.cert.Certificate;
42 | import java.security.cert.CertificateException;
43 | import java.security.cert.CertificateFactory;
44 | import java.security.cert.X509Certificate;
45 |
46 | public class SSLUtils {
47 | private static final Logger logger = LoggerFactory.getLogger(SSLUtils.class);
48 | private static SSLContext yesCtx = null;
49 | private static SSLContext checkCertificatesSSLContext = null;
50 |
51 | /**
52 | * Returns an SSLContext that will accept any server certificate.
53 | * Use with great care and in limited situations, as it allows MITM attacks.
54 | */
55 | public static SSLContext yesSSLContext() {
56 | logger.warn("You disabled checking the https certificate. This could lead to " +
57 | "'Man in the middle' attacks. This setting is only intended for tests.");
58 |
59 | if (yesCtx == null) {
60 | X509TrustManager yesTm = new X509TrustManager() {
61 | @Override
62 | public void checkClientTrusted(X509Certificate[] certs, String authType) {
63 | // Accept anything
64 | }
65 |
66 | @Override
67 | public void checkServerTrusted(X509Certificate[] certs, String authType) {
68 | // Accept anything
69 | }
70 |
71 | @Override
72 | public X509Certificate[] getAcceptedIssuers() {
73 | return new X509Certificate[0];
74 | }
75 | };
76 |
77 | try {
78 | SSLContext ctx = SSLContext.getInstance("SSL");
79 | ctx.init(null, new X509TrustManager[] { yesTm }, null);
80 | yesCtx = ctx;
81 | } catch (Exception e) {
82 | // An exception here means SSL is not supported, which is unlikely
83 | throw new RuntimeException(e);
84 | }
85 | }
86 |
87 | return yesCtx;
88 | }
89 |
90 | /**
91 | *
92 | * @param trustStore
93 | * @param keyStoreType pkcs12
94 | * @return
95 | */
96 | public static SSLContext checkCertificatesSSLContext(String trustStore, String keyStoreType, String keyStorePass) {
97 | if (checkCertificatesSSLContext == null) {
98 | try {
99 | Path trustStorePath = Paths.get(trustStore);
100 | KeyStore truststore = KeyStore.getInstance(keyStoreType);
101 | try (InputStream is = Files.newInputStream(trustStorePath)) {
102 | truststore.load(is, keyStorePass.toCharArray());
103 | }
104 | SSLContextBuilder sslBuilder = SSLContexts.custom().loadTrustMaterial(truststore, null);
105 | checkCertificatesSSLContext = sslBuilder.build();
106 | } catch (IOException | CertificateException | NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {
107 | logger.error("Can not load the SSLContext for {}, {}", trustStore, keyStoreType);
108 | }
109 | }
110 | return checkCertificatesSSLContext;
111 | }
112 |
113 | /**
114 | * A SSL context based on the self signed CA, so that using this SSL Context allows to connect to the Elasticsearch service
115 | * @return a customized SSL Context
116 | */
117 | public SSLContext createSslContextFromCa(String certPath) {
118 | try {
119 | byte[] bytes = IOUtils.resourceToByteArray(certPath);
120 | CertificateFactory factory = CertificateFactory.getInstance("X.509");
121 | Certificate trustedCa = factory.generateCertificate(new ByteArrayInputStream(bytes));
122 | KeyStore trustStore = KeyStore.getInstance("pkcs12");
123 | trustStore.load(null, null);
124 | trustStore.setCertificateEntry("ca", trustedCa);
125 |
126 | final SSLContext sslContext = SSLContext.getInstance("TLSv1.3");
127 | TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
128 | tmfactory.init(trustStore);
129 | sslContext.init(null, tmfactory.getTrustManagers(), null);
130 | return sslContext;
131 | } catch (Exception e) {
132 | throw new RuntimeException(e);
133 | }
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/src/main/java/fr/pilato/spring/elasticsearch/Tuple.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to David Pilato (the "Author") under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. Author licenses this
6 | * file to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing,
13 | * software distributed under the License is distributed on an
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | * KIND, either express or implied. See the License for the
16 | * specific language governing permissions and limitations
17 | * under the License.
18 | */
19 |
20 | package fr.pilato.spring.elasticsearch;
21 |
22 | public class Tuple {
23 |
24 | public static Tuple tuple(V1 v1, V2 v2) {
25 | return new Tuple<>(v1, v2);
26 | }
27 |
28 | private final V1 v1;
29 | private final V2 v2;
30 |
31 | public Tuple(V1 v1, V2 v2) {
32 | this.v1 = v1;
33 | this.v2 = v2;
34 | }
35 |
36 | public V1 v1() {
37 | return v1;
38 | }
39 |
40 | public V2 v2() {
41 | return v2;
42 | }
43 |
44 | @Override
45 | public String toString() {
46 | return "Tuple [v1=" + v1 + ", v2=" + v2 + "]";
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/resources/org/apache/maven/plugin/announcement/announcement.vm:
--------------------------------------------------------------------------------
1 | ## Licensed to the Apache Software Foundation (ASF) under one
2 | ## or more contributor license agreements. See the NOTICE file
3 | ## distributed with this work for additional information
4 | ## regarding copyright ownership. The ASF licenses this file
5 | ## to you under the Apache License, Version 2.0 (the
6 | ## "License"); you may not use this file except in compliance
7 | ## with the License. You may obtain a copy of the License at
8 | ##
9 | ## http://www.apache.org/licenses/LICENSE-2.0
10 | ##
11 | ## Unless required by applicable law or agreed to in writing,
12 | ## software distributed under the License is distributed on an
13 | ## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | ## KIND, either express or implied. See the License for the
15 | ## specific language governing permissions and limitations
16 | ## under the License.
17 | The ${developmentTeam} is pleased to announce the **${finalName}** release!
18 |
19 | # ${introduction}
20 |
21 |
Usage
22 |
23 | Add this library to you project:
24 |
25 | ```
26 |
27 | ${project.groupId}
28 | ${project.artifactId}
29 | ${project.version}
30 |
31 | ```
32 |
33 | #if ($release.getActions().size() == 0)
34 | No changes defined in this version.
35 | #else
36 |
37 | #if ($release.getActions('add').size() !=0)
38 |