From 05e5a7503762de3e357e391e92bc0f8c3bfbd844 Mon Sep 17 00:00:00 2001 From: John Blum Date: Fri, 11 Dec 2020 12:53:24 -0800 Subject: [PATCH] Refactor the @EnableClusterAware configuration and conditional logic to determine whether an Apache Geode based cluster is available or not. Applied Spring's @NonNull and @Nullable annotations to the API. Added a NotKubernetesEnvironmentCondition class to the ClusterNotAvailableConfiguration class. Added a @Conditional on the NotKubernetesEnvironmentCondition class annotated IsNotKubernetesEnvironmentCondition class to the ClusterNotAvailableConfiguration.AllClusterNotAvailableConditions class. Removed all @ConditionalOnCloudPlatform annotated Condition classes in the ClusterAvailableConfiguration.AnyClusterAvailableCondition class, for both CloudFoundry and Kubernetes. Edit Javadoc. Resolves gh-99. --- .../ClusterAvailableConfiguration.java | 11 +++-- .../annotation/ClusterAwareConfiguration.java | 46 +++++++++++++------ .../ClusterNotAvailableConfiguration.java | 33 +++++++++---- 3 files changed, 62 insertions(+), 28 deletions(-) diff --git a/spring-geode/src/main/java/org/springframework/geode/config/annotation/ClusterAvailableConfiguration.java b/spring-geode/src/main/java/org/springframework/geode/config/annotation/ClusterAvailableConfiguration.java index a7cbed40..947f82df 100644 --- a/spring-geode/src/main/java/org/springframework/geode/config/annotation/ClusterAvailableConfiguration.java +++ b/spring-geode/src/main/java/org/springframework/geode/config/annotation/ClusterAvailableConfiguration.java @@ -16,8 +16,6 @@ package org.springframework.geode.config.annotation; import org.springframework.boot.autoconfigure.condition.AnyNestedCondition; -import org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform; -import org.springframework.boot.cloud.CloudPlatform; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.data.gemfire.config.annotation.EnableClusterConfiguration; @@ -47,11 +45,16 @@ public class ClusterAvailableConfiguration { super(ConfigurationPhase.PARSE_CONFIGURATION); } + @Conditional(ClusterAvailableCondition.class) + static class IsClusterAvailableCondition { } + + /* @ConditionalOnCloudPlatform(CloudPlatform.CLOUD_FOUNDRY) static class IsCloudFoundryEnvironmentCondition { } - @Conditional(ClusterAvailableCondition.class) - static class IsClusterAvailableCondition { } + @ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES) + static class IsKubernetesEnvironmentCondition { } + */ } diff --git a/spring-geode/src/main/java/org/springframework/geode/config/annotation/ClusterAwareConfiguration.java b/spring-geode/src/main/java/org/springframework/geode/config/annotation/ClusterAwareConfiguration.java index 54a4cdee..61465769 100644 --- a/spring-geode/src/main/java/org/springframework/geode/config/annotation/ClusterAwareConfiguration.java +++ b/spring-geode/src/main/java/org/springframework/geode/config/annotation/ClusterAwareConfiguration.java @@ -49,6 +49,8 @@ import org.springframework.data.gemfire.support.ConnectionEndpoint; import org.springframework.data.gemfire.support.ConnectionEndpointList; import org.springframework.data.gemfire.util.ArrayUtils; import org.springframework.geode.core.util.ObjectUtils; +import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; import org.slf4j.Logger; @@ -74,6 +76,7 @@ import org.slf4j.LoggerFactory; * @see org.springframework.context.annotation.Import * @see org.springframework.context.event.ContextClosedEvent * @see org.springframework.core.env.ConfigurableEnvironment + * @see org.springframework.core.env.EnumerablePropertySource * @see org.springframework.core.env.Environment * @see org.springframework.core.env.PropertySource * @see org.springframework.core.type.AnnotatedTypeMetadata @@ -125,8 +128,11 @@ public class ClusterAwareConfiguration extends AbstractAnnotationConfigSupport { clusterAvailable.set(null); } + /** + * @inheritDoc + */ @Override - public synchronized boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { + public synchronized boolean matches(@NonNull ConditionContext context, @NonNull AnnotatedTypeMetadata metadata) { if (clusterAvailable.get() == null) { registerApplicationListener(context); @@ -136,7 +142,7 @@ public class ClusterAwareConfiguration extends AbstractAnnotationConfigSupport { return isMatch(context); } - ConditionContext registerApplicationListener(ConditionContext conditionContext) { + @NonNull ConditionContext registerApplicationListener(@NonNull ConditionContext conditionContext) { Optional.ofNullable(conditionContext) .map(ConditionContext::getResourceLoader) @@ -148,7 +154,7 @@ public class ClusterAwareConfiguration extends AbstractAnnotationConfigSupport { return conditionContext; } - boolean isMatch(ConditionContext context) { + boolean isMatch(@NonNull ConditionContext context) { Environment environment = context.getEnvironment(); @@ -157,7 +163,16 @@ public class ClusterAwareConfiguration extends AbstractAnnotationConfigSupport { Boolean.class, false)); } - ConditionContext doMatch(ConditionContext conditionContext) { + /** + * Performs the actual conditional match to determine whether this Spring Boot for Apache Geode application + * can connect to an available Apache Geode cluster available in any environment (e.g. Standalone or Cloud). + * + * @param conditionContext Spring {@link ConditionContext} which captures the context in which the condition(s) + * are evaluated; must not be {@literal null}. + * @return the given {@link ConditionContext}. + * @see org.springframework.context.annotation.ConditionContext + */ + @NonNull ConditionContext doMatch(@NonNull ConditionContext conditionContext) { Environment environment = conditionContext.getEnvironment(); @@ -174,7 +189,7 @@ public class ClusterAwareConfiguration extends AbstractAnnotationConfigSupport { return conditionContext; } - Logger getLogger() { + @NonNull Logger getLogger() { return logger; } @@ -186,7 +201,7 @@ public class ClusterAwareConfiguration extends AbstractAnnotationConfigSupport { ); } - List getConfiguredConnectionEndpoints(Environment environment) { + List getConfiguredConnectionEndpoints(@NonNull Environment environment) { List connectionEndpoints = new ArrayList<>(); @@ -209,6 +224,7 @@ public class ClusterAwareConfiguration extends AbstractAnnotationConfigSupport { String[] propertyNames = enumerablePropertySource.getPropertyNames(); Arrays.stream(ArrayUtils.nullSafeArray(propertyNames, String.class)) + .filter(StringUtils::hasText) .filter(propertyName-> pattern.matcher(propertyName).find()) .forEach(propertyName -> { @@ -216,7 +232,7 @@ public class ClusterAwareConfiguration extends AbstractAnnotationConfigSupport { if (StringUtils.hasText(propertyValue)) { - int defaultPort = propertyName.contains("servers") + int defaultPort = propertyName.toLowerCase().contains("servers") ? DEFAULT_CACHE_SERVER_PORT : DEFAULT_LOCATOR_PORT; @@ -236,7 +252,7 @@ public class ClusterAwareConfiguration extends AbstractAnnotationConfigSupport { return connectionEndpoints; } - int countConnections(ConnectionEndpointList connectionEndpoints) { + int countConnections(@NonNull ConnectionEndpointList connectionEndpoints) { int count = 0; @@ -245,7 +261,9 @@ public class ClusterAwareConfiguration extends AbstractAnnotationConfigSupport { Socket socket = null; try { + socket = connect(connectionEndpoint); + count++; if (getLogger().isInfoEnabled()) { @@ -270,7 +288,7 @@ public class ClusterAwareConfiguration extends AbstractAnnotationConfigSupport { return count; } - Socket connect(ConnectionEndpoint connectionEndpoint) throws IOException { + @NonNull Socket connect(@NonNull ConnectionEndpoint connectionEndpoint) throws IOException { SocketAddress socketAddress = new InetSocketAddress(connectionEndpoint.getHost(), connectionEndpoint.getPort()); @@ -282,7 +300,7 @@ public class ClusterAwareConfiguration extends AbstractAnnotationConfigSupport { return socket; } - boolean close(Socket socket) { + boolean close(@Nullable Socket socket) { return ObjectUtils.doOperationSafely(() -> { @@ -296,7 +314,7 @@ public class ClusterAwareConfiguration extends AbstractAnnotationConfigSupport { }, cause -> false); } - void configureTopology(Environment environment, ConnectionEndpointList connectionEndpoints, + void configureTopology(@NonNull Environment environment, @NonNull ConnectionEndpointList connectionEndpoints, int connectionCount) { if (connectionCount < 1) { @@ -306,12 +324,12 @@ public class ClusterAwareConfiguration extends AbstractAnnotationConfigSupport { } if (getLogger().isInfoEnabled()) { - getLogger().info("No cluster found; Spring Boot application will run in LOCAL-only mode"); + getLogger().info("No cluster found; Spring Boot application will run in standalone (LOCAL) mode"); } } else { if (getLogger().isInfoEnabled()) { - getLogger().info("Cluster was found; auto-configuration made [{}] successful connections;" + getLogger().info("Cluster was found; Auto-configuration made [{}] successful connection(s);" + " Spring Boot application will run in a client/server topology", connectionCount); } @@ -332,7 +350,7 @@ public class ClusterAwareConfiguration extends AbstractAnnotationConfigSupport { } } - boolean isMatch(ConnectionEndpointList connectionEndpoints, int connectionCount) { + boolean isMatch(@NonNull ConnectionEndpointList connectionEndpoints, int connectionCount) { return connectionCount > 0; } } diff --git a/spring-geode/src/main/java/org/springframework/geode/config/annotation/ClusterNotAvailableConfiguration.java b/spring-geode/src/main/java/org/springframework/geode/config/annotation/ClusterNotAvailableConfiguration.java index 815d7628..02611657 100644 --- a/spring-geode/src/main/java/org/springframework/geode/config/annotation/ClusterNotAvailableConfiguration.java +++ b/spring-geode/src/main/java/org/springframework/geode/config/annotation/ClusterNotAvailableConfiguration.java @@ -35,6 +35,7 @@ import org.springframework.data.gemfire.GemfireUtils; import org.springframework.data.gemfire.client.ClientRegionFactoryBean; import org.springframework.data.gemfire.config.annotation.RegionConfigurer; import org.springframework.data.gemfire.config.annotation.support.CacheTypeAwareRegionFactoryBean; +import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; /** @@ -60,7 +61,7 @@ import org.springframework.lang.Nullable; public class ClusterNotAvailableConfiguration { @Bean - BeanPostProcessor localClientRegionBeanPostProcessor(Environment environment) { + BeanPostProcessor localClientRegionBeanPostProcessor(@NonNull Environment environment) { return new BeanPostProcessor() { @@ -78,7 +79,7 @@ public class ClusterNotAvailableConfiguration { @Bean @SuppressWarnings("unused") - RegionConfigurer localClientRegionConfigurer(Environment environment) { + RegionConfigurer localClientRegionConfigurer(@NonNull Environment environment) { return new RegionConfigurer() { @@ -89,19 +90,20 @@ public class ClusterNotAvailableConfiguration { }; } - protected boolean isClientRegion(Object bean) { + protected boolean isClientRegion(@Nullable Object bean) { return bean instanceof CacheTypeAwareRegionFactoryBean || bean instanceof ClientRegionFactoryBean; } - protected Object configureAsLocalClientRegion(Environment environment, Object clientRegion) { + protected @NonNull Object configureAsLocalClientRegion(@NonNull Environment environment, + @NonNull Object clientRegion) { return clientRegion instanceof ClientRegionFactoryBean ? configureAsLocalClientRegion(environment, (ClientRegionFactoryBean) clientRegion) : configureAsLocalClientRegion(environment, (CacheTypeAwareRegionFactoryBean) clientRegion); } - protected CacheTypeAwareRegionFactoryBean configureAsLocalClientRegion(Environment environment, - CacheTypeAwareRegionFactoryBean clientRegion) { + protected @NonNull CacheTypeAwareRegionFactoryBean configureAsLocalClientRegion( + @NonNull Environment environment, @NonNull CacheTypeAwareRegionFactoryBean clientRegion) { ClientRegionShortcut shortcut = environment.getProperty(SPRING_DATA_GEMFIRE_CACHE_CLIENT_REGION_SHORTCUT_PROPERTY, @@ -113,8 +115,8 @@ public class ClusterNotAvailableConfiguration { return clientRegion; } - protected ClientRegionFactoryBean configureAsLocalClientRegion(Environment environment, - ClientRegionFactoryBean clientRegion) { + protected @NonNull ClientRegionFactoryBean configureAsLocalClientRegion( + @NonNull Environment environment, @NonNull ClientRegionFactoryBean clientRegion) { ClientRegionShortcut shortcut = environment.getProperty(SPRING_DATA_GEMFIRE_CACHE_CLIENT_REGION_SHORTCUT_PROPERTY, @@ -138,12 +140,15 @@ public class ClusterNotAvailableConfiguration { @Conditional(NotCloudFoundryEnvironmentCondition.class) static class IsNotCloudFoundryEnvironmentCondition { } + @Conditional(NotKubernetesEnvironmentCondition.class) + static class IsNotKubernetesEnvironmentCondition { } + } public static final class ClusterNotAvailableCondition extends ClusterAwareConfiguration.ClusterAwareCondition { @Override - public synchronized boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { + public synchronized boolean matches(@NonNull ConditionContext context, @NonNull AnnotatedTypeMetadata metadata) { return !super.matches(context, metadata); } } @@ -151,8 +156,16 @@ public class ClusterNotAvailableConfiguration { public static final class NotCloudFoundryEnvironmentCondition implements Condition { @Override - public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { + public boolean matches(@NonNull ConditionContext context, @NonNull AnnotatedTypeMetadata metadata) { return !CloudPlatform.CLOUD_FOUNDRY.isActive(context.getEnvironment()); } } + + public static final class NotKubernetesEnvironmentCondition implements Condition { + + @Override + public boolean matches(@NonNull ConditionContext context, @NonNull AnnotatedTypeMetadata metadata) { + return !CloudPlatform.KUBERNETES.isActive(context.getEnvironment()); + } + } }