Add support to apply the 'spring.session.timeout' property or the 'server.servlet.session.timeout' property when the 'spring.session.timeout' property is not set.
Neither 'spring.session.timeout' nor 'server.servlet.session.timeout' are applied when the 'spring.session.data.gemfire.session.expiration.max-inactive-interval-seconds' property is set.
This commit is contained in:
@@ -19,18 +19,24 @@ package org.springframework.geode.boot.autoconfigure;
|
||||
import static org.springframework.data.gemfire.util.CollectionUtils.asSet;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.env.EnvironmentPostProcessor;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.PropertiesPropertySource;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.data.gemfire.config.annotation.web.http.EnableGemFireHttpSession;
|
||||
@@ -62,11 +68,56 @@ import org.springframework.util.StringUtils;
|
||||
@SuppressWarnings("unused")
|
||||
public class SpringSessionAutoConfiguration {
|
||||
|
||||
static final Set<String> SPRING_SESSION_STORE_TYPES = asSet("gemfire", "geode");
|
||||
protected static final Set<String> SPRING_SESSION_STORE_TYPES = asSet("gemfire", "geode");
|
||||
|
||||
static final String SPRING_SESSION_STORE_TYPE_PROPERTY = "spring.session.store-type";
|
||||
protected static final String SERVER_SERVLET_SESSION_TIMEOUT_PROPERTY = "server.servlet.session.timeout";
|
||||
protected static final String SPRING_SESSION_DATA_GEMFIRE_SESSION_EXPIRATION_TIMEOUT =
|
||||
"spring.session.data.gemfire.session.expiration.max-inactive-interval-seconds";
|
||||
protected static final String SPRING_SESSION_PROPERTY_SOURCE_NAME = "SpringSessionProperties";
|
||||
protected static final String SPRING_SESSION_STORE_TYPE_PROPERTY = "spring.session.store-type";
|
||||
protected static final String SPRING_SESSION_TIMEOUT_PROPERTY = "spring.session.timeout";
|
||||
|
||||
static class SpringSessionStoreTypeCondition implements Condition {
|
||||
public static class SpringSessionPropertiesEnvironmentPostProcessor implements EnvironmentPostProcessor {
|
||||
|
||||
@Override
|
||||
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
|
||||
|
||||
if (isNotSet(environment, SPRING_SESSION_DATA_GEMFIRE_SESSION_EXPIRATION_TIMEOUT)) {
|
||||
|
||||
Properties springSessionProperties = new Properties();
|
||||
|
||||
if (isSet(environment, SPRING_SESSION_TIMEOUT_PROPERTY)) {
|
||||
springSessionProperties.setProperty(SPRING_SESSION_DATA_GEMFIRE_SESSION_EXPIRATION_TIMEOUT,
|
||||
environment.getProperty(SPRING_SESSION_TIMEOUT_PROPERTY));
|
||||
}
|
||||
else if (isSet(environment, SERVER_SERVLET_SESSION_TIMEOUT_PROPERTY)) {
|
||||
springSessionProperties.setProperty(SPRING_SESSION_DATA_GEMFIRE_SESSION_EXPIRATION_TIMEOUT,
|
||||
environment.getProperty(SERVER_SERVLET_SESSION_TIMEOUT_PROPERTY));
|
||||
}
|
||||
|
||||
if (!springSessionProperties.isEmpty()) {
|
||||
environment.getPropertySources()
|
||||
.addFirst(newPropertySource(SPRING_SESSION_PROPERTY_SOURCE_NAME, springSessionProperties));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private PropertySource<?> newPropertySource(String name, Properties properties) {
|
||||
return new PropertiesPropertySource(name, properties);
|
||||
}
|
||||
}
|
||||
|
||||
protected static boolean isNotSet(ConfigurableEnvironment environment, String propertyName) {
|
||||
return !isSet(environment, propertyName);
|
||||
}
|
||||
|
||||
protected static boolean isSet(ConfigurableEnvironment environment, String propertyName) {
|
||||
|
||||
return environment.containsProperty(propertyName)
|
||||
&& StringUtils.hasText(environment.getProperty(propertyName));
|
||||
}
|
||||
|
||||
protected static class SpringSessionStoreTypeCondition implements Condition {
|
||||
|
||||
@Override @SuppressWarnings("all")
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
|
||||
@@ -14,4 +14,5 @@ org.springframework.geode.boot.autoconfigure.SslAutoConfiguration
|
||||
# Environment Post Processing
|
||||
org.springframework.boot.env.EnvironmentPostProcessor=\
|
||||
org.springframework.geode.boot.autoconfigure.ClientSecurityAutoConfiguration.AutoConfiguredCloudSecurityEnvironmentPostProcessor,\
|
||||
org.springframework.geode.boot.autoconfigure.SpringSessionAutoConfiguration.SpringSessionPropertiesEnvironmentPostProcessor,\
|
||||
org.springframework.geode.boot.autoconfigure.SslAutoConfiguration.SslEnvironmentPostProcessor
|
||||
|
||||
@@ -18,32 +18,32 @@ package org.springframework.geode.boot.autoconfigure.session;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.apache.geode.cache.RegionShortcut;
|
||||
import org.apache.geode.cache.client.ClientRegionShortcut;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.data.gemfire.tests.integration.SpringApplicationContextIntegrationTestsSupport;
|
||||
import org.springframework.data.gemfire.tests.integration.SpringBootApplicationIntegrationTestsSupport;
|
||||
import org.springframework.data.gemfire.tests.mock.GemFireMockObjectsSupport;
|
||||
import org.springframework.data.gemfire.tests.mock.annotation.EnableGemFireMockObjects;
|
||||
import org.springframework.geode.boot.autoconfigure.ContinuousQueryAutoConfiguration;
|
||||
import org.springframework.geode.core.util.ObjectUtils;
|
||||
import org.springframework.mock.env.MockPropertySource;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration;
|
||||
import org.springframework.session.data.gemfire.config.annotation.web.http.support.SpringSessionGemFireConfigurer;
|
||||
import org.springframework.session.data.gemfire.serialization.SessionSerializer;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Integration Test for the auto-configuration of Spring Session using either Apache Geode or Pivotal GemFire
|
||||
@@ -62,119 +62,184 @@ import org.springframework.util.ReflectionUtils;
|
||||
* @see org.springframework.context.annotation.Bean
|
||||
* @see org.springframework.context.annotation.Configuration
|
||||
* @see org.springframework.core.env.PropertySource
|
||||
* @see org.springframework.data.gemfire.tests.integration.SpringApplicationContextIntegrationTestsSupport
|
||||
* @see org.springframework.data.gemfire.tests.mock.annotation.EnableGemFireMockObjects
|
||||
* @see org.springframework.data.gemfire.tests.integration.SpringBootApplicationIntegrationTestsSupport
|
||||
* @see org.springframework.session.Session
|
||||
* @see org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration
|
||||
* @see org.springframework.session.data.gemfire.config.annotation.web.http.support.SpringSessionGemFireConfigurer
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class CustomConfiguredSessionCachingIntegrationTests extends SpringApplicationContextIntegrationTestsSupport {
|
||||
public class CustomConfiguredSessionCachingIntegrationTests extends SpringBootApplicationIntegrationTestsSupport {
|
||||
|
||||
private static final String SPRING_SESSION_DATA_GEMFIRE_PROPERTY = "spring.session.data.gemfire";
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T invoke(Object obj, String methodName) {
|
||||
private volatile Function<ConfigurableApplicationContext, ConfigurableApplicationContext> applicationContextFunction =
|
||||
Function.identity();
|
||||
|
||||
return (T) Optional.ofNullable(obj)
|
||||
.map(Object::getClass)
|
||||
.map(type -> ReflectionUtils.findMethod(type, methodName))
|
||||
.map(this::makeAccessible)
|
||||
.map(method -> ReflectionUtils.invokeMethod(method, obj))
|
||||
.orElseThrow(() -> newIllegalArgumentException("Method [%s] not found on Object of type [%s]",
|
||||
methodName, ObjectUtils.nullSafeClassName(obj)));
|
||||
private volatile Function<SpringApplicationBuilder, SpringApplicationBuilder> springApplicationBuilderFunction =
|
||||
Function.identity();
|
||||
|
||||
private static Properties singletonProperties(String propertyName, String propertyValue) {
|
||||
|
||||
Properties properties = new Properties();
|
||||
|
||||
properties.setProperty(propertyName, propertyValue);
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
private Method makeAccessible(Method method) {
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
return method;
|
||||
private Function<SpringApplicationBuilder, SpringApplicationBuilder> newSpringBootSessionPropertiesConfigurationFunction() {
|
||||
|
||||
return springApplicationBuilder ->
|
||||
springApplicationBuilder.properties(singletonProperties("spring.session.timeout", "300"));
|
||||
}
|
||||
|
||||
private PropertySource newSpringSessionGemFireProperties() {
|
||||
private Function<ConfigurableApplicationContext, ConfigurableApplicationContext> newSpringSessionGemFirePropertiesConfigurationFunction() {
|
||||
|
||||
return new MockPropertySource("TestSpringSessionGemFireProperties")
|
||||
.withProperty(springSessionPropertyName("cache.client.region.shortcut"), "LOCAL")
|
||||
.withProperty(springSessionPropertyName("session.attributes.indexable"), "one, two")
|
||||
.withProperty(springSessionPropertyName("session.expiration.max-inactive-interval-seconds"), "600")
|
||||
.withProperty(springSessionPropertyName("cache.client.pool.name"), "MockPool")
|
||||
.withProperty(springSessionPropertyName("session.region.name"), "MockRegion")
|
||||
.withProperty(springSessionPropertyName("cache.server.region.shortcut"), "REPLICATE")
|
||||
.withProperty(springSessionPropertyName("session.serializer.bean-name"), "MockSessionSerializer");
|
||||
return applicationContext -> {
|
||||
|
||||
PropertySource springSessionGemFireProperties = new MockPropertySource("TestSpringSessionGemFireProperties")
|
||||
.withProperty(springSessionPropertyName("cache.client.region.shortcut"), "LOCAL")
|
||||
.withProperty(springSessionPropertyName("session.attributes.indexable"), "one, two")
|
||||
.withProperty(springSessionPropertyName("session.expiration.max-inactive-interval-seconds"), "600")
|
||||
.withProperty(springSessionPropertyName("cache.client.pool.name"), "MockPool")
|
||||
.withProperty(springSessionPropertyName("session.region.name"), "MockRegion")
|
||||
.withProperty(springSessionPropertyName("cache.server.region.shortcut"), "REPLICATE")
|
||||
.withProperty(springSessionPropertyName("session.serializer.bean-name"), "MockSessionSerializer");
|
||||
|
||||
applicationContext.getEnvironment().getPropertySources().addFirst(springSessionGemFireProperties);
|
||||
|
||||
return applicationContext;
|
||||
};
|
||||
}
|
||||
|
||||
private Function<SpringApplicationBuilder, SpringApplicationBuilder> newWebServerSessionPropertiesConfigurationFunction() {
|
||||
|
||||
return springApplicationBuilder ->
|
||||
springApplicationBuilder.properties(singletonProperties("server.servlet.session.timeout", "3600"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SpringApplicationBuilder processBeforeBuild(SpringApplicationBuilder springApplicationBuilder) {
|
||||
return this.springApplicationBuilderFunction.apply(springApplicationBuilder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConfigurableApplicationContext processBeforeRefresh(ConfigurableApplicationContext applicationContext) {
|
||||
|
||||
applicationContext.getEnvironment().getPropertySources().addFirst(newSpringSessionGemFireProperties());
|
||||
|
||||
return applicationContext;
|
||||
return this.applicationContextFunction.apply(applicationContext);
|
||||
}
|
||||
|
||||
private String springSessionPropertyName(String propertyNameSuffix) {
|
||||
return String.format("%1$s.%2$s", SPRING_SESSION_DATA_GEMFIRE_PROPERTY, propertyNameSuffix);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
GemFireMockObjectsSupport.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void springSessionConfigurationCustomizedWithConfigurer() {
|
||||
|
||||
this.applicationContextFunction = newSpringSessionGemFirePropertiesConfigurationFunction();
|
||||
|
||||
this.springApplicationBuilderFunction = newSpringBootSessionPropertiesConfigurationFunction()
|
||||
.andThen(newWebServerSessionPropertiesConfigurationFunction());
|
||||
|
||||
newApplicationContext(TestConfiguration.class, SpringSessionGemFireConfigurerTestConfiguration.class);
|
||||
|
||||
GemFireHttpSessionConfiguration sessionConfiguration = getBean(GemFireHttpSessionConfiguration.class);
|
||||
|
||||
assertThat(sessionConfiguration).isNotNull();
|
||||
|
||||
assertThat(this.<ClientRegionShortcut>invoke(sessionConfiguration, "getClientRegionShortcut"))
|
||||
assertThat(ObjectUtils.<ClientRegionShortcut>invoke(sessionConfiguration, "getClientRegionShortcut"))
|
||||
.isEqualTo(ClientRegionShortcut.CACHING_PROXY);
|
||||
|
||||
assertThat(this.<String[]>invoke(sessionConfiguration, "getIndexableSessionAttributes"))
|
||||
assertThat(ObjectUtils.<String[]>invoke(sessionConfiguration, "getIndexableSessionAttributes"))
|
||||
.contains("two", "four");
|
||||
|
||||
assertThat(this.<Integer>invoke(sessionConfiguration, "getMaxInactiveIntervalInSeconds"))
|
||||
assertThat(ObjectUtils.<Integer>invoke(sessionConfiguration, "getMaxInactiveIntervalInSeconds"))
|
||||
.isEqualTo(900);
|
||||
|
||||
assertThat(this.<String>invoke(sessionConfiguration, "getPoolName")).isEqualTo("TestPool");
|
||||
assertThat(ObjectUtils.<String>invoke(sessionConfiguration, "getPoolName")).isEqualTo("TestPool");
|
||||
|
||||
assertThat(this.<RegionShortcut>invoke(sessionConfiguration, "getServerRegionShortcut"))
|
||||
assertThat(ObjectUtils.<RegionShortcut>invoke(sessionConfiguration, "getServerRegionShortcut"))
|
||||
.isEqualTo(RegionShortcut.PARTITION_REDUNDANT_PERSISTENT_OVERFLOW);
|
||||
|
||||
assertThat(this.<String>invoke(sessionConfiguration, "getSessionRegionName"))
|
||||
assertThat(ObjectUtils.<String>invoke(sessionConfiguration, "getSessionRegionName"))
|
||||
.isEqualTo("TestRegion");
|
||||
|
||||
assertThat(this.<String>invoke(sessionConfiguration, "getSessionSerializerBeanName"))
|
||||
assertThat(ObjectUtils.<String>invoke(sessionConfiguration, "getSessionSerializerBeanName"))
|
||||
.isEqualTo("TestSessionSerializer");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void springSessionConfigurationCustomizedWithProperties() {
|
||||
|
||||
this.applicationContextFunction = newSpringSessionGemFirePropertiesConfigurationFunction();
|
||||
|
||||
this.springApplicationBuilderFunction = newSpringBootSessionPropertiesConfigurationFunction()
|
||||
.andThen(newWebServerSessionPropertiesConfigurationFunction());
|
||||
|
||||
newApplicationContext(TestConfiguration.class);
|
||||
|
||||
GemFireHttpSessionConfiguration sessionConfiguration = getBean(GemFireHttpSessionConfiguration.class);
|
||||
|
||||
assertThat(sessionConfiguration).isNotNull();
|
||||
|
||||
assertThat(this.<ClientRegionShortcut>invoke(sessionConfiguration, "getClientRegionShortcut"))
|
||||
assertThat(ObjectUtils.<ClientRegionShortcut>invoke(sessionConfiguration, "getClientRegionShortcut"))
|
||||
.isEqualTo(ClientRegionShortcut.LOCAL);
|
||||
|
||||
assertThat(this.<String[]>invoke(sessionConfiguration, "getIndexableSessionAttributes"))
|
||||
assertThat(ObjectUtils.<String[]>invoke(sessionConfiguration, "getIndexableSessionAttributes"))
|
||||
.contains("one", "two");
|
||||
|
||||
assertThat(this.<Integer>invoke(sessionConfiguration, "getMaxInactiveIntervalInSeconds"))
|
||||
assertThat(ObjectUtils.<Integer>invoke(sessionConfiguration, "getMaxInactiveIntervalInSeconds"))
|
||||
.isEqualTo(600);
|
||||
|
||||
assertThat(this.<String>invoke(sessionConfiguration, "getPoolName")).isEqualTo("MockPool");
|
||||
assertThat(ObjectUtils.<String>invoke(sessionConfiguration, "getPoolName")).isEqualTo("MockPool");
|
||||
|
||||
assertThat(this.<RegionShortcut>invoke(sessionConfiguration, "getServerRegionShortcut"))
|
||||
assertThat(ObjectUtils.<RegionShortcut>invoke(sessionConfiguration, "getServerRegionShortcut"))
|
||||
.isEqualTo(RegionShortcut.REPLICATE);
|
||||
|
||||
assertThat(this.<String>invoke(sessionConfiguration, "getSessionRegionName"))
|
||||
assertThat(ObjectUtils.<String>invoke(sessionConfiguration, "getSessionRegionName"))
|
||||
.isEqualTo("MockRegion");
|
||||
|
||||
assertThat(this.<String>invoke(sessionConfiguration, "getSessionSerializerBeanName"))
|
||||
assertThat(ObjectUtils.<String>invoke(sessionConfiguration, "getSessionSerializerBeanName"))
|
||||
.isEqualTo("MockSessionSerializer");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void springSessionExpirationTimeoutConfiguredWithSpringBootProperties() {
|
||||
|
||||
this.springApplicationBuilderFunction = newSpringBootSessionPropertiesConfigurationFunction()
|
||||
.andThen(newWebServerSessionPropertiesConfigurationFunction());
|
||||
|
||||
newApplicationContext(TestConfiguration.class);
|
||||
|
||||
GemFireHttpSessionConfiguration sessionConfiguration = getBean(GemFireHttpSessionConfiguration.class);
|
||||
|
||||
assertThat(sessionConfiguration).isNotNull();
|
||||
|
||||
assertThat(ObjectUtils.<Integer>invoke(sessionConfiguration, "getMaxInactiveIntervalInSeconds"))
|
||||
.isEqualTo(300);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void springSessionExpirationTimeoutConfiguredWithWebContainerProperties() {
|
||||
|
||||
this.springApplicationBuilderFunction = newWebServerSessionPropertiesConfigurationFunction();
|
||||
|
||||
newApplicationContext(TestConfiguration.class);
|
||||
|
||||
GemFireHttpSessionConfiguration sessionConfiguration = getBean(GemFireHttpSessionConfiguration.class);
|
||||
|
||||
assertThat(sessionConfiguration).isNotNull();
|
||||
|
||||
assertThat(ObjectUtils.<Integer>invoke(sessionConfiguration, "getMaxInactiveIntervalInSeconds"))
|
||||
.isEqualTo(3600);
|
||||
}
|
||||
|
||||
@SpringBootConfiguration
|
||||
@EnableGemFireMockObjects
|
||||
@EnableAutoConfiguration(exclude = ContinuousQueryAutoConfiguration.class)
|
||||
|
||||
Reference in New Issue
Block a user