Polish "Add service connection support for Hazelcast"

See gh-42416
This commit is contained in:
Moritz Halbritter 2024-09-26 14:30:42 +02:00
parent cee7439dbe
commit 33def6d6b4
9 changed files with 85 additions and 42 deletions

View File

@ -17,17 +17,12 @@
package org.springframework.boot.autoconfigure.hazelcast; package org.springframework.boot.autoconfigure.hazelcast;
import com.hazelcast.client.HazelcastClient; import com.hazelcast.client.HazelcastClient;
import com.hazelcast.client.config.ClientConfig;
import com.hazelcast.core.HazelcastInstance; import com.hazelcast.core.HazelcastInstance;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.core.io.ResourceLoader;
/** /**
* Configuration for Hazelcast client. * Configuration for Hazelcast client.
@ -38,34 +33,9 @@ import org.springframework.core.io.ResourceLoader;
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass(HazelcastClient.class) @ConditionalOnClass(HazelcastClient.class)
@ConditionalOnMissingBean(HazelcastInstance.class) @ConditionalOnMissingBean(HazelcastInstance.class)
@Import(HazelcastClientInstanceConfiguration.class) @Import({ HazelcastConnectionDetailsConfiguration.class, HazelcastClientInstanceConfiguration.class })
class HazelcastClientConfiguration { class HazelcastClientConfiguration {
static final String CONFIG_SYSTEM_PROPERTY = "hazelcast.client.config"; static final String CONFIG_SYSTEM_PROPERTY = "hazelcast.client.config";
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean({ ClientConfig.class, HazelcastConnectionDetails.class })
@Conditional(HazelcastClientConfigAvailableCondition.class)
static class HazelcastClientConfigFileConfiguration {
@Bean
HazelcastConnectionDetails hazelcastConnectionDetails(HazelcastProperties properties,
ResourceLoader resourceLoader) {
return new PropertiesHazelcastConnectionDetails(properties, resourceLoader);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(HazelcastConnectionDetails.class)
@ConditionalOnSingleCandidate(ClientConfig.class)
static class HazelcastClientConfigConfiguration {
@Bean
HazelcastConnectionDetails hazelcastConnectionDetails(ClientConfig config) {
return () -> config;
}
}
} }

View File

@ -0,0 +1,62 @@
/*
* Copyright 2012-2024 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 org.springframework.boot.autoconfigure.hazelcast;
import com.hazelcast.client.config.ClientConfig;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader;
/**
* {@link Configuration} for providing {@link HazelcastConnectionDetails}.
*
* @author Dmytro Nosan
* @author Moritz Halbritter
*/
@Configuration(proxyBeanMethods = false)
class HazelcastConnectionDetailsConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean({ ClientConfig.class, HazelcastConnectionDetails.class })
@Conditional(HazelcastClientConfigAvailableCondition.class)
static class HazelcastClientConfigFileConfiguration {
@Bean
HazelcastConnectionDetails hazelcastConnectionDetails(HazelcastProperties properties,
ResourceLoader resourceLoader) {
return new PropertiesHazelcastConnectionDetails(properties, resourceLoader);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(HazelcastConnectionDetails.class)
@ConditionalOnSingleCandidate(ClientConfig.class)
static class HazelcastClientConfigConfiguration {
@Bean
HazelcastConnectionDetails hazelcastConnectionDetails(ClientConfig config) {
return () -> config;
}
}
}

View File

@ -19,7 +19,6 @@ dependencies {
dockerTestImplementation("org.junit.jupiter:junit-jupiter") dockerTestImplementation("org.junit.jupiter:junit-jupiter")
dockerTestImplementation("org.testcontainers:testcontainers") dockerTestImplementation("org.testcontainers:testcontainers")
dockerTestRuntimeOnly("com.microsoft.sqlserver:mssql-jdbc") dockerTestRuntimeOnly("com.microsoft.sqlserver:mssql-jdbc")
dockerTestRuntimeOnly("com.oracle.database.r2dbc:oracle-r2dbc") dockerTestRuntimeOnly("com.oracle.database.r2dbc:oracle-r2dbc")
dockerTestRuntimeOnly("io.r2dbc:r2dbc-mssql") dockerTestRuntimeOnly("io.r2dbc:r2dbc-mssql")
@ -31,11 +30,11 @@ dependencies {
optional(project(":spring-boot-project:spring-boot-autoconfigure")) optional(project(":spring-boot-project:spring-boot-autoconfigure"))
optional(project(":spring-boot-project:spring-boot-actuator-autoconfigure")) optional(project(":spring-boot-project:spring-boot-actuator-autoconfigure"))
optional("com.hazelcast:hazelcast")
optional("io.r2dbc:r2dbc-spi") optional("io.r2dbc:r2dbc-spi")
optional("org.mongodb:mongodb-driver-core") optional("org.mongodb:mongodb-driver-core")
optional("org.neo4j.driver:neo4j-java-driver") optional("org.neo4j.driver:neo4j-java-driver")
optional("org.springframework.data:spring-data-r2dbc") optional("org.springframework.data:spring-data-r2dbc")
optional("com.hazelcast:hazelcast")
testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support")) testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
testImplementation(project(":spring-boot-project:spring-boot-test")) testImplementation(project(":spring-boot-project:spring-boot-test"))

View File

@ -66,7 +66,9 @@ class HazelcastDockerComposeConnectionDetailsFactory
@Override @Override
public ClientConfig getClientConfig() { public ClientConfig getClientConfig() {
ClientConfig config = new ClientConfig(); ClientConfig config = new ClientConfig();
this.environment.getClusterName().ifPresent(config::setClusterName); if (this.environment.getClusterName() != null) {
config.setClusterName(this.environment.getClusterName());
}
config.getNetworkConfig().addAddress(this.host + ":" + this.port); config.getNetworkConfig().addAddress(this.host + ":" + this.port);
return config; return config;
} }

View File

@ -17,7 +17,6 @@
package org.springframework.boot.docker.compose.service.connection.hazelcast; package org.springframework.boot.docker.compose.service.connection.hazelcast;
import java.util.Map; import java.util.Map;
import java.util.Optional;
/** /**
* Hazelcast environment details. * Hazelcast environment details.
@ -32,8 +31,8 @@ class HazelcastEnvironment {
this.clusterName = env.get("HZ_CLUSTERNAME"); this.clusterName = env.get("HZ_CLUSTERNAME");
} }
Optional<String> getClusterName() { String getClusterName() {
return Optional.ofNullable(this.clusterName); return this.clusterName;
} }
} }

View File

@ -33,13 +33,13 @@ class HazelcastEnvironmentTests {
@Test @Test
void getClusterNameWhenHasNoHzClusterNameSet() { void getClusterNameWhenHasNoHzClusterNameSet() {
HazelcastEnvironment environment = new HazelcastEnvironment(Collections.emptyMap()); HazelcastEnvironment environment = new HazelcastEnvironment(Collections.emptyMap());
assertThat(environment.getClusterName()).isEmpty(); assertThat(environment.getClusterName()).isNull();
} }
@Test @Test
void getClusterNameWhenHzClusterNameSet() { void getClusterNameWhenHzClusterNameSet() {
HazelcastEnvironment environment = new HazelcastEnvironment(Map.of("HZ_CLUSTERNAME", "spring-boot")); HazelcastEnvironment environment = new HazelcastEnvironment(Map.of("HZ_CLUSTERNAME", "spring-boot"));
assertThat(environment.getClusterName()).isNotEmpty().hasValue("spring-boot"); assertThat(environment.getClusterName()).isEqualTo("spring-boot");
} }
} }

View File

@ -52,7 +52,7 @@ class CustomClusterNameHazelcastContainerConnectionDetailsFactoryIntegrationTest
@Container @Container
@ServiceConnection @ServiceConnection
static final HazelcastContainer hazelcast = TestImage.container(HazelcastContainer.class) static final HazelcastContainer hazelcast = TestImage.container(HazelcastContainer.class)
.withEnv("HZ_CLUSTERNAME", "spring-boot"); .withClusterName("spring-boot");
@Autowired(required = false) @Autowired(required = false)
private HazelcastConnectionDetails connectionDetails; private HazelcastConnectionDetails connectionDetails;

View File

@ -17,7 +17,6 @@
package org.springframework.boot.testcontainers.service.connection.hazelcast; package org.springframework.boot.testcontainers.service.connection.hazelcast;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import com.hazelcast.client.config.ClientConfig; import com.hazelcast.client.config.ClientConfig;
import org.testcontainers.containers.Container; import org.testcontainers.containers.Container;
@ -66,7 +65,10 @@ class HazelcastContainerConnectionDetailsFactory
ClientConfig config = new ClientConfig(); ClientConfig config = new ClientConfig();
Container<?> container = getContainer(); Container<?> container = getContainer();
Map<String, String> env = container.getEnvMap(); Map<String, String> env = container.getEnvMap();
Optional.ofNullable(env.get(CLUSTER_NAME_ENV)).ifPresent(config::setClusterName); String clusterName = env.get(CLUSTER_NAME_ENV);
if (clusterName != null) {
config.setClusterName(clusterName);
}
config.getNetworkConfig().addAddress(container.getHost() + ":" + container.getMappedPort(DEFAULT_PORT)); config.getNetworkConfig().addAddress(container.getHost() + ":" + container.getMappedPort(DEFAULT_PORT));
return config; return config;
} }

View File

@ -33,4 +33,13 @@ public final class HazelcastContainer extends GenericContainer<HazelcastContaine
addExposedPorts(DEFAULT_PORT); addExposedPorts(DEFAULT_PORT);
} }
/**
* Sets the cluster name.
* @param clusterName the cluster name
* @return this instance
*/
public HazelcastContainer withClusterName(String clusterName) {
return withEnv("HZ_CLUSTERNAME", clusterName);
}
} }