Add SSL service connection support for ElasticSearch

See gh-41137
This commit is contained in:
Moritz Halbritter 2025-02-11 10:23:21 +01:00
parent 7cf9cc74a2
commit 789d30deab
13 changed files with 583 additions and 11 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -21,6 +21,7 @@ import java.net.URISyntaxException;
import java.util.List;
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
import org.springframework.boot.ssl.SslBundle;
/**
* Details required to establish a connection to an Elasticsearch service.
@ -63,6 +64,15 @@ public interface ElasticsearchConnectionDetails extends ConnectionDetails {
return null;
}
/**
* SSL bundle to use.
* @return the SSL bundle to use
* @since 3.5.0
*/
default SslBundle getSslBundle() {
return null;
}
/**
* An Elasticsearch node.
*

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -44,12 +44,14 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchConnectionDetails.Node;
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchConnectionDetails.Node.Protocol;
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchProperties.Restclient.Ssl;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.boot.ssl.SslBundle;
import org.springframework.boot.ssl.SslBundles;
import org.springframework.boot.ssl.SslOptions;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
@ -75,8 +77,8 @@ class ElasticsearchRestClientConfigurations {
@Bean
@ConditionalOnMissingBean(ElasticsearchConnectionDetails.class)
PropertiesElasticsearchConnectionDetails elasticsearchConnectionDetails() {
return new PropertiesElasticsearchConnectionDetails(this.properties);
PropertiesElasticsearchConnectionDetails elasticsearchConnectionDetails(ObjectProvider<SslBundles> sslBundles) {
return new PropertiesElasticsearchConnectionDetails(this.properties, sslBundles.getIfAvailable());
}
@Bean
@ -87,16 +89,16 @@ class ElasticsearchRestClientConfigurations {
@Bean
RestClientBuilder elasticsearchRestClientBuilder(ElasticsearchConnectionDetails connectionDetails,
ObjectProvider<RestClientBuilderCustomizer> builderCustomizers, ObjectProvider<SslBundles> sslBundles) {
ObjectProvider<RestClientBuilderCustomizer> builderCustomizers) {
RestClientBuilder builder = RestClient.builder(connectionDetails.getNodes()
.stream()
.map((node) -> new HttpHost(node.hostname(), node.port(), node.protocol().getScheme()))
.toArray(HttpHost[]::new));
builder.setHttpClientConfigCallback((httpClientBuilder) -> {
builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(httpClientBuilder));
String sslBundleName = this.properties.getRestclient().getSsl().getBundle();
if (StringUtils.hasText(sslBundleName)) {
configureSsl(httpClientBuilder, sslBundles.getObject().getBundle(sslBundleName));
SslBundle sslBundle = connectionDetails.getSslBundle();
if (sslBundle != null) {
configureSsl(httpClientBuilder, sslBundle);
}
return httpClientBuilder;
});
@ -236,8 +238,11 @@ class ElasticsearchRestClientConfigurations {
private final ElasticsearchProperties properties;
PropertiesElasticsearchConnectionDetails(ElasticsearchProperties properties) {
private final SslBundles sslBundles;
PropertiesElasticsearchConnectionDetails(ElasticsearchProperties properties, SslBundles sslBundles) {
this.properties = properties;
this.sslBundles = sslBundles;
}
@Override
@ -260,6 +265,16 @@ class ElasticsearchRestClientConfigurations {
return this.properties.getPathPrefix();
}
@Override
public SslBundle getSslBundle() {
Ssl ssl = this.properties.getRestclient().getSsl();
if (StringUtils.hasLength(ssl.getBundle())) {
Assert.notNull(this.sslBundles, "SSL bundle name has been set but no SSL bundles found in context");
return this.sslBundles.getBundle(ssl.getBundle());
}
return null;
}
private Node createNode(String uri) {
if (!(uri.startsWith("http://") || uri.startsWith("https://"))) {
uri = "http://" + uri;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,15 +16,26 @@
package org.springframework.boot.testcontainers.service.connection.elasticsearch;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.List;
import org.testcontainers.elasticsearch.ElasticsearchContainer;
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchConnectionDetails;
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchConnectionDetails.Node.Protocol;
import org.springframework.boot.ssl.SslBundle;
import org.springframework.boot.ssl.SslStoreBundle;
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.boot.testcontainers.service.connection.Ssl;
/**
* {@link ContainerConnectionDetailsFactory} to create
@ -53,15 +64,83 @@ class ElasticsearchContainerConnectionDetailsFactory
private static final class ElasticsearchContainerConnectionDetails
extends ContainerConnectionDetails<ElasticsearchContainer> implements ElasticsearchConnectionDetails {
private volatile SslBundle sslBundle;
private ElasticsearchContainerConnectionDetails(ContainerConnectionSource<ElasticsearchContainer> source) {
super(source);
}
@Override
public String getUsername() {
return "elastic";
}
@Override
public String getPassword() {
return getContainer().getEnvMap().get("ELASTIC_PASSWORD");
}
@Override
public List<Node> getNodes() {
String host = getContainer().getHost();
Integer port = getContainer().getMappedPort(DEFAULT_PORT);
return List.of(new Node(host, port, Protocol.HTTP, null, null));
return List.of(new Node(host, port, (getSslBundle() != null) ? Protocol.HTTPS : Protocol.HTTP,
getUsername(), getPassword()));
}
@Override
public SslBundle getSslBundle() {
if (this.sslBundle != null) {
return this.sslBundle;
}
SslBundle sslBundle = super.getSslBundle();
if (sslBundle != null) {
this.sslBundle = sslBundle;
return sslBundle;
}
if (hasAnnotation(Ssl.class)) {
byte[] caCertificate = getContainer().caCertAsBytes().orElse(null);
if (caCertificate != null) {
KeyStore trustStore = createTrustStore(caCertificate);
sslBundle = createSslBundleWithTrustStore(trustStore);
this.sslBundle = sslBundle;
return sslBundle;
}
}
return null;
}
private SslBundle createSslBundleWithTrustStore(KeyStore trustStore) {
return SslBundle.of(new SslStoreBundle() {
@Override
public KeyStore getKeyStore() {
return null;
}
@Override
public String getKeyStorePassword() {
return null;
}
@Override
public KeyStore getTrustStore() {
return trustStore;
}
});
}
private KeyStore createTrustStore(byte[] caCertificate) {
try {
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
Certificate certificate = certFactory.generateCertificate(new ByteArrayInputStream(caCertificate));
keyStore.setCertificateEntry("ca", certificate);
return keyStore;
}
catch (KeyStoreException | CertificateException | IOException | NoSuchAlgorithmException ex) {
throw new IllegalStateException("Failed to create keystore from CA certificate", ex);
}
}
}

View File

@ -0,0 +1,22 @@
plugins {
id "java"
id "org.springframework.boot.conventions"
id "org.springframework.boot.docker-test"
}
description = "Spring Boot Data ElasticSearch smoke test"
dependencies {
dockerTestImplementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-test"))
dockerTestImplementation(project(":spring-boot-project:spring-boot-test"))
dockerTestImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support-docker"))
dockerTestImplementation(project(":spring-boot-project:spring-boot-testcontainers"))
dockerTestImplementation("org.junit.jupiter:junit-jupiter")
dockerTestImplementation("org.junit.platform:junit-platform-engine")
dockerTestImplementation("org.junit.platform:junit-platform-launcher")
dockerTestImplementation("org.testcontainers:junit-jupiter")
dockerTestImplementation("org.testcontainers:elasticsearch")
dockerTestImplementation("org.testcontainers:testcontainers")
implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-data-elasticsearch"))
}

View File

@ -0,0 +1,70 @@
/*
* Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package smoketest.data.elasticsearch;
import java.util.UUID;
import org.junit.jupiter.api.Test;
import org.testcontainers.elasticsearch.ElasticsearchContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.elasticsearch.DataElasticsearchTest;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.boot.testcontainers.service.connection.Ssl;
import org.springframework.boot.testsupport.container.TestImage;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Smoke tests for Elasticsearch 8.
*
* @author Moritz Halbritter
*/
@Testcontainers(disabledWithoutDocker = true)
@DataElasticsearchTest
class SampleElasticSearch8ApplicationTests {
@Container
@ServiceConnection
@Ssl
static final ElasticsearchContainer elasticSearch = new ElasticsearchContainer(TestImage.ELASTICSEARCH_8.toString())
.withPassword("my-custom-password");
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@Autowired
private SampleRepository exampleRepository;
@Test
void testRepository() {
SampleDocument document = new SampleDocument();
document.setText("Look, new @DataElasticsearchTest!");
String id = UUID.randomUUID().toString();
document.setId(id);
SampleDocument savedDocument = this.exampleRepository.save(document);
SampleDocument getDocument = this.elasticsearchTemplate.get(id, SampleDocument.class);
assertThat(getDocument).isNotNull();
assertThat(getDocument.getId()).isNotNull();
assertThat(getDocument.getId()).isEqualTo(savedDocument.getId());
this.exampleRepository.deleteAll();
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package smoketest.data.elasticsearch;
import java.util.UUID;
import org.junit.jupiter.api.Test;
import org.testcontainers.elasticsearch.ElasticsearchContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.elasticsearch.DataElasticsearchTest;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.boot.testsupport.container.TestImage;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Smoke tests for Elasticsearch.
*
* @author Moritz Halbritter
*/
@Testcontainers(disabledWithoutDocker = true)
@DataElasticsearchTest
class SampleElasticSearchApplicationTests {
@Container
@ServiceConnection
static final ElasticsearchContainer elasticSearch = TestImage.container(ElasticsearchContainer.class);
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@Autowired
private SampleRepository exampleRepository;
@Test
void testRepository() {
SampleDocument document = new SampleDocument();
document.setText("Look, new @DataElasticsearchTest!");
String id = UUID.randomUUID().toString();
document.setId(id);
SampleDocument savedDocument = this.exampleRepository.save(document);
SampleDocument getDocument = this.elasticsearchTemplate.get(id, SampleDocument.class);
assertThat(getDocument).isNotNull();
assertThat(getDocument.getId()).isNotNull();
assertThat(getDocument.getId()).isEqualTo(savedDocument.getId());
this.exampleRepository.deleteAll();
}
}

View File

@ -0,0 +1,70 @@
/*
* Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package smoketest.data.elasticsearch;
import java.util.UUID;
import org.junit.jupiter.api.Test;
import org.testcontainers.elasticsearch.ElasticsearchContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.elasticsearch.DataElasticsearchTest;
import org.springframework.boot.testcontainers.service.connection.PemTrustStore;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.boot.testsupport.container.TestImage;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Smoke tests for Elasticsearch with SSL.
*
* @author Moritz Halbritter
*/
@Testcontainers(disabledWithoutDocker = true)
@DataElasticsearchTest(
properties = { "spring.elasticsearch.connection-timeout=120s", "spring.elasticsearch.socket-timeout=120s" })
class SampleElasticSearchSslApplicationTests {
@Container
@ServiceConnection
@PemTrustStore(certificate = "classpath:ssl.crt")
static final ElasticsearchContainer elasticSearch = TestImage.container(SecureElasticsearchContainer.class);
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@Autowired
private SampleRepository exampleRepository;
@Test
void testRepository() {
SampleDocument document = new SampleDocument();
document.setText("Look, new @DataElasticsearchTest!");
String id = UUID.randomUUID().toString();
document.setId(id);
SampleDocument savedDocument = this.exampleRepository.save(document);
SampleDocument getDocument = this.elasticsearchTemplate.get(id, SampleDocument.class);
assertThat(getDocument).isNotNull();
assertThat(getDocument.getId()).isNotNull();
assertThat(getDocument.getId()).isEqualTo(savedDocument.getId());
this.exampleRepository.deleteAll();
}
}

View File

@ -0,0 +1,52 @@
/*
* Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package smoketest.data.elasticsearch;
import java.util.Map;
import org.testcontainers.elasticsearch.ElasticsearchContainer;
import org.testcontainers.utility.DockerImageName;
import org.testcontainers.utility.MountableFile;
/**
* A {@link ElasticsearchContainer} for Elasticsearch with SSL configuration.
*
* @author Moritz Halbritter
*/
class SecureElasticsearchContainer extends ElasticsearchContainer {
SecureElasticsearchContainer(DockerImageName dockerImageName) {
super(dockerImageName);
}
@Override
public void configure() {
// See
// https://www.elastic.co/guide/en/elastic-stack-get-started/7.5/get-started-docker.html#get-started-docker-tls
withEnv(Map.of("xpack.security.http.ssl.enabled", "true", "xpack.security.http.ssl.key",
"/usr/share/elasticsearch/config/ssl.key", "xpack.security.http.ssl.certificate",
"/usr/share/elasticsearch/config/ssl.crt", "xpack.security.transport.ssl.enabled", "true",
"xpack.security.transport.ssl.verification_mode", "certificate", "xpack.security.transport.ssl.key",
"/usr/share/elasticsearch/config/ssl.key", "xpack.security.transport.ssl.certificate",
"/usr/share/elasticsearch/config/ssl.crt"));
withCopyFileToContainer(MountableFile.forClasspathResource("/ssl.crt"),
"/usr/share/elasticsearch/config/ssl.crt");
withCopyFileToContainer(MountableFile.forClasspathResource("/ssl.key"),
"/usr/share/elasticsearch/config/ssl.key");
}
}

View File

@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICpjCCAY6gAwIBAgIUd1pIGeth3t+uXRwJqQgBkX6RqVwwDQYJKoZIhvcNAQEL
BQAwDDEKMAgGA1UEAwwBKjAgFw0yNDA4MjMwOTI5MjBaGA8yMTI0MDgyMzA5Mjky
MFowDDEKMAgGA1UEAwwBKjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AMvuy3afu6umnCgEBElfgboa2M1O7RWwuvA0OIWdEzxYYQmc9QUihd2l68pIu9jT
hR+2CENL4iY2HNtELJ8kFSGgUGPGrsjLj/qqULG1/r2f18tPavMD7Hxo0AGA+yyX
nECCfHGPJ7P88fWwoMfdp8Y4s/BW7QcC7vB9kQGjUOb4V/WUWI7c27Yxj6/nCPRr
Gkb5YkEvsw6TPeBfZbx7kjWaYtd8eKjVHf40lu0AhXGK+lFuaLrY9VYBYoiMRtIZ
3/EKf2gKQiIIR7tN3DUa5zi6vYvQNaUaK14yomfyynUzGPbIcMq8V+c6j3gI7jqf
ITqaaBn5NIM0W7ox6hhr+UUCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEApgal5rth
5y94hnwgNt0/+PuVj5vwxUIi0WgV6b1GE+3033h+l57hKcIRem4l3xEQnAs3NyLK
BnbBgnnUfSOgPZhiP8s3VHSvGeJda7z2IQhCBe+cUnx6UHs8wgN4Nh1rkbEUzBvZ
xm98B/bcbTsiSnIRTHBvIYhySDuCmyYOZwH8HC6rct6U3PODmJ6OjtWC43kjO0jT
4/T/1PBJnVnN0r1Xu/P+GNDgDnzifIYr5ofY0zGsOC1GhRWyqbiIfe5hgZ//q81U
1tFbSlLNvoi3C4jf2Fj9lYo8Ylkxk7QE5dFbRmBDffCo2sD8g6wyZN3PhaIyckG5
E0uZHTBFFpFKjQ==
-----END CERTIFICATE-----

View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDL7st2n7urppwo
BARJX4G6GtjNTu0VsLrwNDiFnRM8WGEJnPUFIoXdpevKSLvY04UftghDS+ImNhzb
RCyfJBUhoFBjxq7Iy4/6qlCxtf69n9fLT2rzA+x8aNABgPssl5xAgnxxjyez/PH1
sKDH3afGOLPwVu0HAu7wfZEBo1Dm+Ff1lFiO3Nu2MY+v5wj0axpG+WJBL7MOkz3g
X2W8e5I1mmLXfHio1R3+NJbtAIVxivpRbmi62PVWAWKIjEbSGd/xCn9oCkIiCEe7
Tdw1Guc4ur2L0DWlGiteMqJn8sp1Mxj2yHDKvFfnOo94CO46nyE6mmgZ+TSDNFu6
MeoYa/lFAgMBAAECggEAHdNp/Ip2Fy/B7PRRcC3AumhMxxJBCIgVfyYUEi6b7pp6
br5+82ZOL9Ghf69NkfO1p6Km6LjDdZU6eTMqV4gecxGQUFdxnrpu71lTffpBLJih
JgISgUJUpwlpSp8DnUz7NFAhRTaLtv5KoQVZLoITlKEcaA0+k2Txb0jeGWA6Z90t
ocHJb9MTeWU7SSaVttNshoJPj272CXExuOCSi+NziSiuCnZbKSZDQKDEe9+jMVhL
OqvXYyp+FWoL60DuLb2BgKet5UcsVaYZNfETRY7vn5LThFpRJnOpZ6Um8JydP60+
3gtuKpsZ8kVKcif4cawAfzpGobra9BBFOc6IqbZMrQKBgQDmVkd1LHdLGOOAd5C+
pwHqxftsh1qyJQ2PAQn6VwAPGkl6c9P/hC3eS6gWMXAf++QlqNUrQR8SvPXlOcXH
LirqVLd/+gLAD4aRhGTKPjBK07NryGvMQO2pRCPd1n5xnd4Xpp9gt10JJlwZUaIY
dItvGcV+5TXUMqnEl+GaNKs35wKBgQDip2iUZCwpG1mGn4Pbvs+hLTZQD3+oXPMh
NYpe9vaStv5YxkFBXM9M+XWH2MDKSMTBZxuTV8GY4pipQwBB32UOtlVVWhOJh1go
Qh7NQOt8yPWb+ynu/i30THfgYMARrqRXXB4o/l9R0J7gW3yjyQDBSuBz5xUIQlpt
adhg+fmv8wKBgQDjZv75YcMMsy+4H1MZxswPuxK0XRVfl1FBg+cT7lyyjGNKr5v3
Qcn/E3aJIpnuGcNuoraCE7LXzxJ9EoJ+WMgpvSXFBVE9yJY0iB7xxF/tIACdQqua
Zee9GvbGBwOirBceBnSHCcCiTerTXFLKDhWyxCDFXQm9y57r5n7mvWTktQKBgQCW
sJ7DKeaCXgCjlKJiEvaQPjMB/4vsMAAlcCdTA/bjjG6GLylrf30DvEb7zow+8Sp/
O0IGMC4yq1S8FCOzqAbURT1uxbh/k1B1U6CO7j6idCl3TwGON8ftyHla4HhSST5S
JpiWwKg3CPDYUXsImba6zEF2TYiaOSNN4zVNJGVxKQKBgB2aOa93jTHxx4BWCqz1
q8EWxbSItNHoTLfe4PgRhu3Ow2I2zi+XAfpW5XIrkNfQ09iDeZLsovaZ35fRcwMB
LWwDlujb5OkJZ4eLgYQqHEwJaYsoR5O6OfpW4IW79t1pzYbGkR0hqY5bcGcI/Tm5
ZZg8ZonNdwagmoihBFAZ+wpB
-----END PRIVATE KEY-----

View File

@ -0,0 +1,56 @@
/*
* Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package smoketest.data.elasticsearch;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
/**
* Sample document.
*
* @author Moritz Halbritter
*/
@Document(indexName = "examples")
public class SampleDocument {
@Id
private String id;
private String text;
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
public String getText() {
return this.text;
}
public void setText(String text) {
this.text = text;
}
@Override
public String toString() {
return "SampleDocument{" + "id='" + this.id + '\'' + ", text='" + this.text + '\'' + '}';
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package smoketest.data.elasticsearch;
import java.util.UUID;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
/**
* Sample application.
*
* @author Moritz Halbritter
*/
@SpringBootApplication
public class SampleElasticsearchApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SampleElasticsearchApplication.class, args);
SampleRepository repository = context.getBean(SampleRepository.class);
createDocument(repository);
listDocuments(repository);
repository.deleteAll();
context.close();
}
private static void listDocuments(SampleRepository repository) {
System.out.println("Documents:");
for (SampleDocument foundDocument : repository.findAll()) {
System.out.println(" " + foundDocument);
}
}
private static void createDocument(SampleRepository repository) {
SampleDocument document = new SampleDocument();
document.setText("Look, new @DataElasticsearchTest!");
String id = UUID.randomUUID().toString();
document.setId(id);
SampleDocument savedDocument = repository.save(document);
System.out.println("Saved document " + savedDocument);
}
}

View File

@ -0,0 +1,28 @@
/*
* Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package smoketest.data.elasticsearch;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
/**
* Sample repository.
*
* @author Moritz Halbritter
*/
interface SampleRepository extends ElasticsearchRepository<SampleDocument, String> {
}