Add support to expose configuration as properties in the Spring Environment.
Edit Javadoc. Resolves gh-14.
This commit is contained in:
@@ -0,0 +1,413 @@
|
||||
/*
|
||||
* Copyright 2018 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
|
||||
*
|
||||
* http://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.session.data.gemfire.config.annotation.web.http;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.geode.cache.RegionShortcut;
|
||||
import org.apache.geode.cache.client.ClientRegionShortcut;
|
||||
import org.apache.geode.cache.client.Pool;
|
||||
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.data.gemfire.config.annotation.ClientCacheApplication;
|
||||
import org.springframework.data.gemfire.tests.mock.annotation.EnableGemFireMockObjects;
|
||||
import org.springframework.mock.env.MockPropertySource;
|
||||
import org.springframework.session.data.gemfire.AbstractGemFireIntegrationTests;
|
||||
import org.springframework.session.data.gemfire.config.annotation.web.http.support.SpringSessionGemFireConfigurer;
|
||||
import org.springframework.session.data.gemfire.expiration.SessionExpirationPolicy;
|
||||
import org.springframework.session.data.gemfire.serialization.SessionSerializer;
|
||||
|
||||
/**
|
||||
* The ExposingSpringSessionGemFireConfigurationIntegrationTests class...
|
||||
*
|
||||
* @author John Blum
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class ExposingSpringSessionGemFireConfigurationIntegrationTests extends AbstractGemFireIntegrationTests {
|
||||
|
||||
private ConfigurableApplicationContext applicationContext;
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
Optional.ofNullable(this.applicationContext).ifPresent(ConfigurableApplicationContext::close);
|
||||
}
|
||||
|
||||
private ConfigurableApplicationContext newApplicationContext(Class<?>... annotatedClasses) {
|
||||
return newApplicationContext(new MockPropertySource("TestProperties"), annotatedClasses);
|
||||
}
|
||||
|
||||
private ConfigurableApplicationContext newApplicationContext(PropertySource<?> testPropertySource,
|
||||
Class<?>... annotatedClasses) {
|
||||
|
||||
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
|
||||
|
||||
applicationContext.getEnvironment().getPropertySources().addFirst(testPropertySource);
|
||||
applicationContext.register(annotatedClasses);
|
||||
applicationContext.registerShutdownHook();
|
||||
applicationContext.refresh();
|
||||
|
||||
return applicationContext;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exposeAnnotationAttributesAsProperties() {
|
||||
|
||||
this.applicationContext = newApplicationContext(TestGemFireHttpSessionConfiguration.class);
|
||||
|
||||
Environment environment = this.applicationContext.getEnvironment();
|
||||
|
||||
assertThat(environment).isNotNull();
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.cache.client.region.shortcut"))
|
||||
.isEqualTo(ClientRegionShortcut.LOCAL.name());
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.session.configuration.expose"))
|
||||
.isEqualTo(Boolean.TRUE.toString());
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.session.attributes.indexed"))
|
||||
.isEqualTo("one,two");
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.session.expiration.max-inactive-interval-seconds"))
|
||||
.isEqualTo("600");
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.cache.client.pool.name"))
|
||||
.isEqualTo("Car");
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.session.region.name"))
|
||||
.isEqualTo("Sessions");
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.cache.server.region.shortcut"))
|
||||
.isEqualTo(RegionShortcut.REPLICATE.name());
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.session.expiration.bean-name"))
|
||||
.isEqualTo("AttributeSessionExpirationPolicy");
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.session.serializer.bean-name"))
|
||||
.isEqualTo("AttributeSessionSerializer");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exposePropertiesAsPropertiesOverridesAnnotationAttributes() {
|
||||
|
||||
MockPropertySource testPropertySource = new MockPropertySource("TestProperties")
|
||||
.withProperty("spring.session.data.gemfire.cache.client.region.shortcut", ClientRegionShortcut.LOCAL_PERSISTENT.name())
|
||||
.withProperty("spring.session.data.gemfire.session.configuration.expose", "true")
|
||||
.withProperty("spring.session.data.gemfire.session.attributes.indexed", "one, two, three")
|
||||
.withProperty("spring.session.data.gemfire.session.expiration.max-inactive-interval-seconds", "900")
|
||||
.withProperty("spring.session.data.gemfire.cache.client.pool.name", "Dead")
|
||||
.withProperty("spring.session.data.gemfire.session.region.name", "PropertySessions")
|
||||
.withProperty("spring.session.data.gemfire.cache.server.region.shortcut", RegionShortcut.REPLICATE_PERSISTENT.name())
|
||||
.withProperty("spring.session.data.gemfire.session.expiration.bean-name", "PropertySessionExpirationPolicy")
|
||||
.withProperty("spring.session.data.gemfire.session.serializer.bean-name", "PropertySessionSerializer");
|
||||
|
||||
this.applicationContext = newApplicationContext(testPropertySource, TestGemFireHttpSessionConfiguration.class);
|
||||
|
||||
Environment environment = this.applicationContext.getEnvironment();
|
||||
|
||||
assertThat(environment).isNotNull();
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.cache.client.region.shortcut"))
|
||||
.isEqualTo(ClientRegionShortcut.LOCAL_PERSISTENT.name());
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.session.configuration.expose"))
|
||||
.isEqualTo(Boolean.TRUE.toString());
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.session.attributes.indexed"))
|
||||
.isEqualTo("one,two,three");
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.session.expiration.max-inactive-interval-seconds"))
|
||||
.isEqualTo("900");
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.cache.client.pool.name"))
|
||||
.isEqualTo("Dead");
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.session.region.name"))
|
||||
.isEqualTo("PropertySessions");
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.cache.server.region.shortcut"))
|
||||
.isEqualTo(RegionShortcut.REPLICATE_PERSISTENT.name());
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.session.expiration.bean-name"))
|
||||
.isEqualTo("PropertySessionExpirationPolicy");
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.session.serializer.bean-name"))
|
||||
.isEqualTo("PropertySessionSerializer");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exposeConfigurerConfigurationAsPropertiesOverridesAnnotationAttributesAndProperties() {
|
||||
|
||||
MockPropertySource testPropertySource = new MockPropertySource("TestProperties")
|
||||
.withProperty("spring.session.data.gemfire.cache.client.region.shortcut", ClientRegionShortcut.LOCAL_PERSISTENT.name())
|
||||
.withProperty("spring.session.data.gemfire.session.configuration.expose", "false")
|
||||
.withProperty("spring.session.data.gemfire.session.attributes.indexed", "one, two, three")
|
||||
.withProperty("spring.session.data.gemfire.session.expiration.max-inactive-interval-seconds", "900")
|
||||
.withProperty("spring.session.data.gemfire.cache.client.pool.name", "Dead")
|
||||
.withProperty("spring.session.data.gemfire.session.region.name", "PropertySessions")
|
||||
.withProperty("spring.session.data.gemfire.cache.server.region.shortcut", RegionShortcut.REPLICATE_PERSISTENT.name())
|
||||
.withProperty("spring.session.data.gemfire.session.expiration.bean-name", "PropertySessionExpirationPolicy")
|
||||
.withProperty("spring.session.data.gemfire.session.serializer.bean-name", "PropertySessionSerializer");
|
||||
|
||||
this.applicationContext = newApplicationContext(testPropertySource, TestGemFireHttpSessionConfiguration.class,
|
||||
TestSpringSessionGemFireConfigurerConfiguration.class);
|
||||
|
||||
Environment environment = this.applicationContext.getEnvironment();
|
||||
|
||||
assertThat(environment).isNotNull();
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.cache.client.region.shortcut"))
|
||||
.isEqualTo(ClientRegionShortcut.CACHING_PROXY.name());
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.session.configuration.expose"))
|
||||
.isEqualTo(Boolean.TRUE.toString());
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.session.attributes.indexed"))
|
||||
.isEqualTo("two,four");
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.session.expiration.max-inactive-interval-seconds"))
|
||||
.isEqualTo("300");
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.cache.client.pool.name"))
|
||||
.isEqualTo("Swimming");
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.session.region.name"))
|
||||
.isEqualTo("ConfigurerSessions");
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.cache.server.region.shortcut"))
|
||||
.isEqualTo(RegionShortcut.PARTITION_REDUNDANT.name());
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.session.expiration.bean-name"))
|
||||
.isEqualTo("ConfigurerSessionExpirationPolicy");
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.session.serializer.bean-name"))
|
||||
.isEqualTo("ConfigurerSessionSerializer");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exposeConfigurationAsPropertiesUsesAnnotationAttributesConfigurerConfigurationAndProperties() {
|
||||
|
||||
MockPropertySource testPropertySource = new MockPropertySource("TestProperties")
|
||||
.withProperty("spring.session.data.gemfire.cache.client.region.shortcut", ClientRegionShortcut.LOCAL_PERSISTENT.name())
|
||||
.withProperty("spring.session.data.gemfire.session.expiration.max-inactive-interval-seconds", "300")
|
||||
.withProperty("spring.session.data.gemfire.cache.client.pool.name", "Dead")
|
||||
.withProperty("spring.session.data.gemfire.session.region.name", "PropertySessions");
|
||||
|
||||
this.applicationContext = newApplicationContext(testPropertySource, TestGemFireHttpSessionConfiguration.class,
|
||||
MockSpringSessionGemFirerConfigurerConfiguration.class);
|
||||
|
||||
Environment environment = this.applicationContext.getEnvironment();
|
||||
|
||||
assertThat(environment).isNotNull();
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.cache.client.region.shortcut"))
|
||||
.isEqualTo(ClientRegionShortcut.CACHING_PROXY.name());
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.session.configuration.expose"))
|
||||
.isEqualTo(Boolean.TRUE.toString());
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.session.attributes.indexed"))
|
||||
.isEqualTo("one,two");
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.session.expiration.max-inactive-interval-seconds"))
|
||||
.isEqualTo("300");
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.cache.client.pool.name"))
|
||||
.isEqualTo("Dead");
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.session.region.name"))
|
||||
.isEqualTo("PropertySessions");
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.cache.server.region.shortcut"))
|
||||
.isEqualTo(RegionShortcut.PARTITION_REDUNDANT.name());
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.session.expiration.bean-name"))
|
||||
.isEqualTo("AttributeSessionExpirationPolicy");
|
||||
|
||||
assertThat(environment.getRequiredProperty("spring.session.data.gemfire.session.serializer.bean-name"))
|
||||
.isEqualTo("ConfigurerSessionSerializer");
|
||||
}
|
||||
|
||||
@ClientCacheApplication
|
||||
@EnableGemFireMockObjects
|
||||
@EnableGemFireHttpSession(
|
||||
clientRegionShortcut = ClientRegionShortcut.LOCAL,
|
||||
exposeConfigurationAsProperties = true,
|
||||
indexableSessionAttributes = { "one", "two" },
|
||||
maxInactiveIntervalInSeconds = 600,
|
||||
poolName = "Car",
|
||||
regionName = "Sessions",
|
||||
serverRegionShortcut = RegionShortcut.REPLICATE,
|
||||
sessionExpirationPolicyBeanName = "AttributeSessionExpirationPolicy",
|
||||
sessionSerializerBeanName = "AttributeSessionSerializer"
|
||||
)
|
||||
@SuppressWarnings("unused")
|
||||
static class TestGemFireHttpSessionConfiguration {
|
||||
|
||||
@Bean("Car")
|
||||
Pool carPool() {
|
||||
return mock(Pool.class);
|
||||
}
|
||||
|
||||
@Bean("Dead")
|
||||
Pool deadPool() {
|
||||
return mock(Pool.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
SpringSessionGemFireConfigurer emptySpringSessionGemFireConfigurer() {
|
||||
return new SpringSessionGemFireConfigurer() { };
|
||||
}
|
||||
|
||||
@Bean("AttributeSessionExpirationPolicy")
|
||||
SessionExpirationPolicy attributeSessionExpirationPolicy() {
|
||||
return mock(SessionExpirationPolicy.class);
|
||||
}
|
||||
|
||||
@Bean("PropertySessionExpirationPolicy")
|
||||
SessionExpirationPolicy propertySessionExpirationPolicy() {
|
||||
return mock(SessionExpirationPolicy.class);
|
||||
}
|
||||
|
||||
@Bean("AttributeSessionSerializer")
|
||||
SessionSerializer attributeSessionSerializer() {
|
||||
return mock(SessionSerializer.class);
|
||||
}
|
||||
|
||||
@Bean("PropertySessionSerializer")
|
||||
SessionSerializer propertySessionSerializer() {
|
||||
return mock(SessionSerializer.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TestSpringSessionGemFireConfigurerConfiguration {
|
||||
|
||||
@Bean("Swimming")
|
||||
Pool swimmingPool() {
|
||||
return mock(Pool.class);
|
||||
}
|
||||
|
||||
@Bean("ConfigurerSessionExpirationPolicy")
|
||||
SessionExpirationPolicy configurerSessionExpirationPolicy() {
|
||||
return mock(SessionExpirationPolicy.class);
|
||||
}
|
||||
|
||||
@Bean("ConfigurerSessionSerializer")
|
||||
SessionSerializer configurerSessionSerializer() {
|
||||
return mock(SessionSerializer.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
SpringSessionGemFireConfigurer testSpringSessionGemFireConfigurer() {
|
||||
|
||||
return new SpringSessionGemFireConfigurer() {
|
||||
|
||||
@Override
|
||||
public ClientRegionShortcut getClientRegionShortcut() {
|
||||
return ClientRegionShortcut.CACHING_PROXY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getExposeConfigurationAsProperties() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getIndexableSessionAttributes() {
|
||||
return new String[] { "two", "four" };
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxInactiveIntervalInSeconds() {
|
||||
return 300;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPoolName() {
|
||||
return "Swimming";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRegionName() {
|
||||
return "ConfigurerSessions";
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegionShortcut getServerRegionShortcut() {
|
||||
return RegionShortcut.PARTITION_REDUNDANT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSessionExpirationPolicyBeanName() {
|
||||
return "ConfigurerSessionExpirationPolicy";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSessionSerializerBeanName() {
|
||||
return "ConfigurerSessionSerializer";
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class MockSpringSessionGemFirerConfigurerConfiguration {
|
||||
|
||||
@Bean("ConfigurerSessionSerializer")
|
||||
SessionSerializer configurerSessionSerializer() {
|
||||
return mock(SessionSerializer.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
SpringSessionGemFireConfigurer mockSpringSessionGemFireConfigurer() {
|
||||
|
||||
return new SpringSessionGemFireConfigurer() {
|
||||
|
||||
@Override
|
||||
public ClientRegionShortcut getClientRegionShortcut() {
|
||||
return ClientRegionShortcut.CACHING_PROXY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegionShortcut getServerRegionShortcut() {
|
||||
return RegionShortcut.PARTITION_REDUNDANT;
|
||||
}
|
||||
|
||||
@Bean("ConfigurerSessionSerializer")
|
||||
SessionSerializer configurerSessionSerializer() {
|
||||
return mock(SessionSerializer.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSessionSerializerBeanName() {
|
||||
return "ConfigurerSessionSerializer";
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,10 +43,10 @@ import org.slf4j.LoggerFactory;
|
||||
* @see java.lang.ClassLoader
|
||||
* @see org.springframework.beans.factory.BeanClassLoaderAware
|
||||
* @see org.springframework.beans.factory.config.ConfigurableBeanFactory
|
||||
* @see org.springframework.core.env.Environment
|
||||
* @see org.springframework.context.ApplicationContext
|
||||
* @see org.springframework.context.ConfigurableApplicationContext
|
||||
* @see org.springframework.context.EnvironmentAware
|
||||
* @see org.springframework.core.env.Environment
|
||||
* @see org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration
|
||||
* @since 2.0.4
|
||||
*/
|
||||
@@ -124,8 +124,9 @@ public abstract class AbstractGemFireHttpSessionConfiguration extends SpringHttp
|
||||
ApplicationContext applicationContext = getApplicationContext();
|
||||
|
||||
return Optional.ofNullable(applicationContext)
|
||||
.filter(it -> it instanceof ConfigurableApplicationContext)
|
||||
.map(it -> ((ConfigurableApplicationContext) it).getBeanFactory())
|
||||
.filter(ConfigurableApplicationContext.class::isInstance)
|
||||
.map(ConfigurableApplicationContext.class::cast)
|
||||
.map(ConfigurableApplicationContext::getBeanFactory)
|
||||
.orElseThrow(() -> newIllegalStateException("Unable to resolve a reference to a [%1$s] from a [%2$s]",
|
||||
ConfigurableBeanFactory.class.getName(), ObjectUtils.nullSafeClassName(applicationContext)));
|
||||
}
|
||||
@@ -161,28 +162,55 @@ public abstract class AbstractGemFireHttpSessionConfiguration extends SpringHttp
|
||||
return this.logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fully-qualified {@link String property name}.
|
||||
*
|
||||
* The fully qualified {@link String property name} consists of the {@link String base property name}
|
||||
* concatenated with the {@code propertyNameSuffix}.
|
||||
*
|
||||
* @param propertyNameSuffix {@link String} containing the property name suffix concatenated with
|
||||
* the {@link String base property name}.
|
||||
* @return the fully-qualified {@link String property name}.
|
||||
* @see java.lang.String
|
||||
*/
|
||||
private String propertyName(String propertyNameSuffix) {
|
||||
return String.format("%1$s%2$s", SPRING_SESSION_PROPERTY_PREFIX, propertyNameSuffix);
|
||||
}
|
||||
|
||||
private String cachePropertyName(String propertyNameSuffix) {
|
||||
return propertyName(String.format("cache.%s", propertyNameSuffix));
|
||||
}
|
||||
|
||||
private String sessionPropertyName(String propertyNameSuffix) {
|
||||
return propertyName(String.format("session.%s", propertyNameSuffix));
|
||||
}
|
||||
|
||||
protected String clientRegionShortcutPropertyName() {
|
||||
return propertyName("cache.client.region.shortcut");
|
||||
return cachePropertyName("client.region.shortcut");
|
||||
}
|
||||
|
||||
protected String exposeConfigurationAsPropertiesPropertyName() {
|
||||
return sessionPropertyName("configuration.expose");
|
||||
}
|
||||
|
||||
protected String indexableSessionAttributesPropertyName() {
|
||||
return sessionPropertyName("attributes.indexable");
|
||||
}
|
||||
|
||||
protected String indexedSessionAttributesPropertyName() {
|
||||
return sessionPropertyName("attributes.indexed");
|
||||
}
|
||||
|
||||
protected String maxInactiveIntervalInSecondsPropertyName() {
|
||||
return sessionPropertyName("expiration.max-inactive-interval-seconds");
|
||||
}
|
||||
|
||||
protected String poolNamePropertyName() {
|
||||
return propertyName("cache.client.pool.name");
|
||||
return cachePropertyName("client.pool.name");
|
||||
}
|
||||
|
||||
protected String serverRegionShortcutPropertyName() {
|
||||
return propertyName("cache.server.region.shortcut");
|
||||
}
|
||||
|
||||
protected String sessionPropertyName(String propertyNameSuffix) {
|
||||
return propertyName(String.format("session.%s", propertyNameSuffix));
|
||||
return cachePropertyName("server.region.shortcut");
|
||||
}
|
||||
|
||||
protected String sessionExpirationPolicyBeanNamePropertyName() {
|
||||
@@ -197,21 +225,6 @@ public abstract class AbstractGemFireHttpSessionConfiguration extends SpringHttp
|
||||
return sessionPropertyName("serializer.bean-name");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fully-qualified {@link String property name}.
|
||||
*
|
||||
* The fully qualified {@link String property name} consists of the {@link String base property name}
|
||||
* concatenated with the {@code propertyNameSuffix}.
|
||||
*
|
||||
* @param propertyNameSuffix {@link String} containing the property name suffix concatenated with
|
||||
* the {@link String base property name}.
|
||||
* @return the fully-qualified {@link String property name}.
|
||||
* @see java.lang.String
|
||||
*/
|
||||
protected String propertyName(String propertyNameSuffix) {
|
||||
return String.format("%1$s%2$s", SPRING_SESSION_PROPERTY_PREFIX, propertyNameSuffix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the value for the given property identified by {@link String name} from the Spring {@link Environment}
|
||||
* as an instance of the specified {@link Class type}.
|
||||
@@ -246,18 +259,32 @@ public abstract class AbstractGemFireHttpSessionConfiguration extends SpringHttp
|
||||
* @see java.lang.Enum
|
||||
*/
|
||||
protected <T extends Enum<T>> T resolveEnumeratedProperty(String propertyName, Class<T> targetType, T defaultValue) {
|
||||
|
||||
return resolveProperty(propertyName, targetType, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to resolve the property with the given {@link String name} from the Spring {@link Environment}
|
||||
* as an {@link Boolean}.
|
||||
*
|
||||
* @param propertyName {@link String name} of the property to resolve.
|
||||
* @param defaultValue default value to return if the property is not defined or not set.
|
||||
* @return the value of the property identified by {@link String name} or the default value
|
||||
* if the property is not defined or not set.
|
||||
* @see #resolveProperty(String, Class, Object)
|
||||
* @see java.lang.Boolean
|
||||
*/
|
||||
protected Boolean resolveProperty(String propertyName, Boolean defaultValue) {
|
||||
return resolveProperty(propertyName, Boolean.class, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to resolve the property with the given {@link String name} from the Spring {@link Environment}
|
||||
* as an {@link Integer}.
|
||||
*
|
||||
* @param propertyName {@link String name} of the property to resolve.
|
||||
* @param defaultValue default value to return if the property is not defined or not set.
|
||||
* @return the value of the property identified by {@link String name} or default value if the property
|
||||
* is not defined or not set.
|
||||
* @return the value of the property identified by {@link String name} or the default value
|
||||
* if the property is not defined or not set.
|
||||
* @see #resolveProperty(String, Class, Object)
|
||||
* @see java.lang.Integer
|
||||
*/
|
||||
@@ -271,8 +298,8 @@ public abstract class AbstractGemFireHttpSessionConfiguration extends SpringHttp
|
||||
*
|
||||
* @param propertyName {@link String name} of the property to resolve.
|
||||
* @param defaultValue default value to return if the property is not defined or not set.
|
||||
* @return the value of the property identified by {@link String name} or default value if the property
|
||||
* is not defined or not set.
|
||||
* @return the value of the property identified by {@link String name} or the default value
|
||||
* if the property is not defined or not set.
|
||||
* @see #resolveProperty(String, Class, Object)
|
||||
* @see java.lang.String
|
||||
*/
|
||||
@@ -286,8 +313,8 @@ public abstract class AbstractGemFireHttpSessionConfiguration extends SpringHttp
|
||||
*
|
||||
* @param propertyName {@link String name} of the property to resolve.
|
||||
* @param defaultValue default value to return if the property is not defined or not set.
|
||||
* @return the value of the property identified by {@link String name} or default value if the property
|
||||
* is not defined or not set.
|
||||
* @return the value of the property identified by {@link String name} or the default value
|
||||
* if the property is not defined or not set.
|
||||
* @see #resolveProperty(String, Class, Object)
|
||||
* @see java.lang.String
|
||||
*/
|
||||
@@ -298,11 +325,11 @@ public abstract class AbstractGemFireHttpSessionConfiguration extends SpringHttp
|
||||
/**
|
||||
* Attempts to resolve the property with the given {@link String name} from the Spring {@link Environment}.
|
||||
*
|
||||
* @param <T> {@link Class} type of the property value.
|
||||
* @param <T> {@link Class type} of the property value.
|
||||
* @param propertyName {@link String name} of the property to resolve.
|
||||
* @param targetType {@link Class} type of the property's value.
|
||||
* @return the value of the property identified by {@link String name} or {@literal null} if the property
|
||||
* is not defined or not set.
|
||||
* @param targetType {@link Class type} of the property's value.
|
||||
* @return the {@link Object value} of the property identified by {@link String name}
|
||||
* or {@literal null} if the property is not defined or not set.
|
||||
* @see #resolveProperty(String, Class, Object)
|
||||
*/
|
||||
protected <T> T resolveProperty(String propertyName, Class<T> targetType) {
|
||||
|
||||
@@ -16,11 +16,13 @@
|
||||
|
||||
package org.springframework.session.data.gemfire.config.annotation.web.http;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
@@ -33,62 +35,77 @@ import org.apache.geode.cache.client.Pool;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.data.gemfire.config.annotation.web.http.support.SpringSessionGemFireConfigurer;
|
||||
import org.springframework.session.data.gemfire.expiration.SessionExpirationPolicy;
|
||||
import org.springframework.session.data.gemfire.serialization.SessionSerializer;
|
||||
import org.springframework.session.web.http.SessionRepositoryFilter;
|
||||
|
||||
/**
|
||||
* Add this annotation to a Spring application defined {@code @Configuration} class exposing
|
||||
* the {@link SessionRepositoryFilter} as a bean named {@literal springSessionRepositoryFilter}
|
||||
* to back the {@link HttpSession} by Apache Geode or Pivotal GemFire.
|
||||
* Add this {@link Annotation annotation} to a Spring application defined {@code @Configuration} {@link Class}
|
||||
* exposing the {@link SessionRepositoryFilter} as a bean named {@literal springSessionRepositoryFilter}
|
||||
* to back the {@link HttpSession} with either Apache Geode or Pivotal GemFire.
|
||||
*
|
||||
* In order to use this annotation, a single Apache Geode / Pivotal GemFire {@link Cache} or {@link ClientCache}
|
||||
* instance must be provided.
|
||||
* In order to use this {@link Annotation annotation}, a single Apache Geode / Pivotal GemFire {@link ClientCache}
|
||||
* or {@link Cache Peer Cache} instance must be provided.
|
||||
*
|
||||
* The most common use case is to use Apache Geode or Pivotal GemFire's client/server topology, where your
|
||||
* Spring Session enabled application uses a {@link ClientCache} to manage {@link Session} state in a cluster
|
||||
* of dedicated Apache Geode or Pivotal GemFire servers.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* {@literal @ClientCacheApplication(subscriptionEnabled = true)}
|
||||
* {@literal @EnableGemFireHttpSession(poolName = "DEFAULT"}
|
||||
* public class ClientCacheHttpSessionConfiguration {
|
||||
*
|
||||
* }
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* Alternatively, though less common (and not recommended), you can use Spring Session with Apache Geode
|
||||
* or Pivotal GemFire in the embedded {@link Cache Peer Cache} scenario, where your Spring Session enabled application
|
||||
* is technically a {@literal peer} in the Apache Geode or Pivotal GemFire cluster.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* {@literal @Configuration}
|
||||
* {@literal @PeerCacheApplication}
|
||||
* {@literal @EnableGemFireHttpSession}
|
||||
* public class PeerCacheHttpSessionConfiguration {
|
||||
*
|
||||
* }
|
||||
* </code> </pre>
|
||||
*
|
||||
* Alternatively, Spring Session can be configured to use Apache Geode / Pivotal GemFire as a cache client
|
||||
* with a dedicated Apache Geode / Pivotal GemFire cluster.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* <code>
|
||||
* {@literal @Configuration}
|
||||
* {@literal @ClientCacheApplication}
|
||||
* {@literal @EnableGemFireHttpSession}
|
||||
* public class ClientCacheHttpSessionConfiguration {
|
||||
*
|
||||
* }
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* More advanced configurations can extend {@link GemFireHttpSessionConfiguration} instead.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.lang.annotation.Annotation
|
||||
* @see java.util.Properties
|
||||
* @see javax.servlet.http.HttpSession
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.apache.geode.cache.client.Pool
|
||||
* @see org.springframework.context.annotation.Configuration
|
||||
* @see org.springframework.context.annotation.Import
|
||||
* @see org.springframework.core.env.Environment
|
||||
* @see org.springframework.session.Session
|
||||
* @see org.springframework.session.config.annotation.web.http.EnableSpringHttpSession
|
||||
* @see org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration
|
||||
* @see org.springframework.session.data.gemfire.config.annotation.web.http.support.SpringSessionGemFireConfigurer
|
||||
* @see org.springframework.session.data.gemfire.expiration.SessionExpirationPolicy
|
||||
* @see org.springframework.session.data.gemfire.serialization.SessionSerializer
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Configuration
|
||||
@Import(GemFireHttpSessionConfiguration.class)
|
||||
public @interface EnableGemFireHttpSession {
|
||||
@@ -107,6 +124,33 @@ public @interface EnableGemFireHttpSession {
|
||||
*/
|
||||
ClientRegionShortcut clientRegionShortcut() default ClientRegionShortcut.PROXY;
|
||||
|
||||
/**
|
||||
* Determines whether the configuration for Spring Session using Apache Geode or Pivotal GemFire should be exposed
|
||||
* in the Spring {@link Environment} as {@link Properties}.
|
||||
*
|
||||
* Currently, users may configure Spring Session for Apache Geode or Pivotal GemFire using attributes on this
|
||||
* {@link Annotation}, using the well-known and documented {@link Properties}
|
||||
* (e.g. {@literal spring.session.data.gemfire.session.expiration.max-inactive-interval-seconds})
|
||||
* or using the {@link SpringSessionGemFireConfigurer} declared as a bean in the Spring application context.
|
||||
*
|
||||
* The {@link Properties} that are exposed will use the well-known property {@link String names} that are documented
|
||||
* in this {@link Annotation Annotation's} attributes.
|
||||
*
|
||||
* The values of the resulting {@link Properties} follows the precedence as outlined in the documentation:
|
||||
* first any {@link SpringSessionGemFireConfigurer} bean defined takes precedence, followed by explicit
|
||||
* {@link Properties} declared in Spring Boot {@literal application.properties} and finally, this
|
||||
* {@link Annotation Annotation's} attribute values.
|
||||
*
|
||||
* Defaults to {@literal false}.
|
||||
*
|
||||
* Use {@literal spring.session.data.gemfire.session.configuration.expose} in Spring Boot
|
||||
* {@literal application.properties}.
|
||||
*
|
||||
* @return a boolean value indicating whether to expose the configuration of Spring Session using Apache Geode
|
||||
* or Pivotal GemFire in the Spring {@link Environment} as {@link Properties}.
|
||||
*/
|
||||
boolean exposeConfigurationAsProperties() default GemFireHttpSessionConfiguration.DEFAULT_EXPOSE_CONFIGURATION_AS_PROPERTIES;
|
||||
|
||||
/**
|
||||
* Identifies the {@link Session} attributes by name that will be indexed for query operations.
|
||||
*
|
||||
@@ -115,8 +159,8 @@ public @interface EnableGemFireHttpSession {
|
||||
*
|
||||
* Defaults to empty {@link String} array.
|
||||
*
|
||||
* Use the {@literal spring.session.data.gemfire.session.attributes.indexable} in Spring Boot
|
||||
* {@literal application.properties}.
|
||||
* Use the {@literal spring.session.data.gemfire.session.attributes.indexed}
|
||||
* in Spring Boot {@literal application.properties}.
|
||||
*
|
||||
* @return an array of {@link String Strings} identifying the names of {@link Session} attributes to index.
|
||||
*/
|
||||
|
||||
@@ -18,10 +18,12 @@ package org.springframework.session.data.gemfire.config.annotation.web.http;
|
||||
|
||||
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
@@ -46,12 +48,17 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.ImportAware;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.PropertiesPropertySource;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.data.gemfire.CacheFactoryBean;
|
||||
import org.springframework.data.gemfire.GemfireOperations;
|
||||
@@ -133,6 +140,12 @@ import org.springframework.util.StringUtils;
|
||||
@SuppressWarnings("unused")
|
||||
public class GemFireHttpSessionConfiguration extends AbstractGemFireHttpSessionConfiguration implements ImportAware {
|
||||
|
||||
/**
|
||||
* Default expose Spring Session using Apache Geode or Pivotal GemFire configuration as {@link Properties}
|
||||
* in Spring's {@link Environment}.
|
||||
*/
|
||||
public static final boolean DEFAULT_EXPOSE_CONFIGURATION_AS_PROPERTIES = false;
|
||||
|
||||
/**
|
||||
* Default maximum interval in seconds in which a {@link Session} can remain inactive before it expires.
|
||||
*/
|
||||
@@ -162,6 +175,9 @@ public class GemFireHttpSessionConfiguration extends AbstractGemFireHttpSessionC
|
||||
public static final String CONFIGURER_GET_CLIENT_REGION_SHORTCUT_METHOD_NAME =
|
||||
findByMethodName(SpringSessionGemFireConfigurer.class, "getClientRegionShortcut");
|
||||
|
||||
public static final String CONFIGURER_GET_EXPOSE_CONFIGURATION_IN_PROPERTIES_METHOD_NAME =
|
||||
findByMethodName(SpringSessionGemFireConfigurer.class, "getExposeConfigurationAsProperties");
|
||||
|
||||
public static final String CONFIGURER_GET_INDEXABLE_SESSION_ATTRIBUTES_METHOD_NAME =
|
||||
findByMethodName(SpringSessionGemFireConfigurer.class, "getIndexableSessionAttributes");
|
||||
|
||||
@@ -208,11 +224,16 @@ public class GemFireHttpSessionConfiguration extends AbstractGemFireHttpSessionC
|
||||
|
||||
public static final String DEFAULT_SESSION_SERIALIZER_BEAN_NAME = SESSION_PDX_SERIALIZER_BEAN_NAME;
|
||||
|
||||
protected static final String SPRING_SESSION_GEMFIRE_PROPERTY_SOURCE =
|
||||
GemFireHttpSessionConfiguration.class.getName().concat(".PROPERTY_SOURCE");
|
||||
|
||||
/**
|
||||
* Defaults names of all {@link Session} attributes that will be indexed by Apache Geode.
|
||||
*/
|
||||
public static final String[] DEFAULT_INDEXABLE_SESSION_ATTRIBUTES = {};
|
||||
|
||||
private boolean exposeConfigurationAsProperties = DEFAULT_EXPOSE_CONFIGURATION_AS_PROPERTIES;
|
||||
|
||||
private int maxInactiveIntervalInSeconds = DEFAULT_MAX_INACTIVE_INTERVAL_IN_SECONDS;
|
||||
|
||||
private ClientRegionShortcut clientRegionShortcut = DEFAULT_CLIENT_REGION_SHORTCUT;
|
||||
@@ -229,7 +250,7 @@ public class GemFireHttpSessionConfiguration extends AbstractGemFireHttpSessionC
|
||||
|
||||
private String[] indexableSessionAttributes = DEFAULT_INDEXABLE_SESSION_ATTRIBUTES;
|
||||
|
||||
private static String findByMethodName(@NonNull Class<?> type, @NonNull String methodName) {
|
||||
private static @NonNull String findByMethodName(@NonNull Class<?> type, @NonNull String methodName) {
|
||||
|
||||
return Arrays.stream(type.getDeclaredMethods())
|
||||
.map(Method::getName)
|
||||
@@ -288,6 +309,48 @@ public class GemFireHttpSessionConfiguration extends AbstractGemFireHttpSessionC
|
||||
.orElse(DEFAULT_CLIENT_REGION_SHORTCUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to expose the configuration of Spring Session using Apache Geode or Pivotal GemFire
|
||||
* as {@link Properties} in the Spring {@link Environment}.
|
||||
*
|
||||
* @param exposeConfigurationAsProperties boolean indicating whether to expose the configuration
|
||||
* of Spring Session using Apache Geode or Pivotal GemFire as {@link Properties} in the Spring {@link Environment}.
|
||||
*
|
||||
* @see EnableGemFireHttpSession#exposeConfigurationAsProperties()
|
||||
*/
|
||||
public void setExposeConfigurationAsProperties(boolean exposeConfigurationAsProperties) {
|
||||
this.exposeConfigurationAsProperties = exposeConfigurationAsProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the configuration for Spring Session using Apache Geode or Pivotal GemFire should be exposed
|
||||
* in the Spring {@link org.springframework.core.env.Environment} as {@link Properties}.
|
||||
*
|
||||
* Currently, users may configure Spring Session for Apache Geode or Pivotal GemFire using attributes on this
|
||||
* {@link Annotation}, using the well-known and documented {@link Properties}
|
||||
* (e.g. {@literal spring.session.data.gemfire.session.expiration.max-inactive-interval-seconds})
|
||||
* or using the {@link SpringSessionGemFireConfigurer} declared as a bean in the Spring application context.
|
||||
*
|
||||
* The {@link Properties} that are exposed will use the well-known property {@link String names} that are documented
|
||||
* in this {@link Annotation Annotation's} attributes.
|
||||
*
|
||||
* The values of the resulting {@link Properties} follows the precedence as outlined in the documentation:
|
||||
* first any {@link SpringSessionGemFireConfigurer} bean defined takes precedence, followed by explicit
|
||||
* {@link Properties} declared in Spring Boot {@literal application.properties} and finally, this
|
||||
* {@link Annotation Annotation's} attribute values.
|
||||
*
|
||||
* Defaults to {@literal false}.
|
||||
*
|
||||
* Use {@literal spring.session.data.gemfire.session.configuration.expose} in Spring Boot
|
||||
* {@literal application.properties}.
|
||||
*
|
||||
* @return a boolean value indicating whether to expose the configuration of Spring Session using Apache Geode
|
||||
* or Pivotal GemFire in the Spring {@link org.springframework.core.env.Environment} as {@link Properties}.
|
||||
*/
|
||||
public boolean isExposeConfigurationAsProperties() {
|
||||
return this.exposeConfigurationAsProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the names of all {@link Session} attributes that will be indexed.
|
||||
*
|
||||
@@ -388,10 +451,24 @@ public class GemFireHttpSessionConfiguration extends AbstractGemFireHttpSessionC
|
||||
.orElse(DEFAULT_SERVER_REGION_SHORTCUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link String name} of the bean configured in the Spring application context implementing
|
||||
* the {@link SessionExpirationPolicy} for {@link Session} expiration.
|
||||
*
|
||||
* @param sessionExpirationPolicyBeanName {@link String} containing the name of the bean configured in
|
||||
* the Spring application context implementing the {@link SessionExpirationPolicy} for {@link Session} expiration.
|
||||
*/
|
||||
public void setSessionExpirationPolicyBeanName(String sessionExpirationPolicyBeanName) {
|
||||
this.sessionExpirationPolicyBeanName = sessionExpirationPolicyBeanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Optional} {@link String name} of the bean configured in the Spring application context
|
||||
* implementing the {@link SessionExpirationPolicy} for {@link Session} expiration.
|
||||
*
|
||||
* @return an {@link Optional} {@link String name} of the bean configured in the Spring application context
|
||||
* implementing the {@link SessionExpirationPolicy} for {@link Session} expiration.
|
||||
*/
|
||||
public Optional<String> getSessionExpirationPolicyBeanName() {
|
||||
|
||||
return Optional.ofNullable(this.sessionExpirationPolicyBeanName)
|
||||
@@ -477,11 +554,13 @@ public class GemFireHttpSessionConfiguration extends AbstractGemFireHttpSessionC
|
||||
* Callback with the {@link AnnotationMetadata} of the class containing {@link Import @Import} annotation
|
||||
* that imported this {@link Configuration @Configuration} class.
|
||||
*
|
||||
* The {@link Configuration @Configuration} class should have been annotated with {@link EnableGemFireHttpSession}.
|
||||
* The {@link Configuration @Configuration} class should also be annotated with {@link EnableGemFireHttpSession}.
|
||||
*
|
||||
* @param importMetadata {@link AnnotationMetadata} of the application class importing
|
||||
* this {@link Configuration} class.
|
||||
* @see org.springframework.core.type.AnnotationMetadata
|
||||
* @see #applySpringSessionGemFireConfigurer()
|
||||
* @see #exposeSpringSessionGemFireConfigurationAsProperties()
|
||||
*/
|
||||
public void setImportMetadata(AnnotationMetadata importMetadata) {
|
||||
|
||||
@@ -489,8 +568,11 @@ public class GemFireHttpSessionConfiguration extends AbstractGemFireHttpSessionC
|
||||
AnnotationAttributes.fromMap(importMetadata.getAnnotationAttributes(
|
||||
EnableGemFireHttpSession.class.getName()));
|
||||
|
||||
// Apply configuration from {@link EnableGemFireHttpSession} annotation
|
||||
// and well-known, documented {@link Properties}.
|
||||
configureClientRegionShortcut(enableGemFireHttpSessionAttributes);
|
||||
configureIndexableSessionAttributes(enableGemFireHttpSessionAttributes);
|
||||
configureExposeConfigurationAsProperties(enableGemFireHttpSessionAttributes);
|
||||
configureIndexedSessionAttributes(enableGemFireHttpSessionAttributes);
|
||||
configureMaxInactiveIntervalInSeconds(enableGemFireHttpSessionAttributes);
|
||||
configurePoolName(enableGemFireHttpSessionAttributes);
|
||||
configureServerRegionShortcut(enableGemFireHttpSessionAttributes);
|
||||
@@ -498,7 +580,12 @@ public class GemFireHttpSessionConfiguration extends AbstractGemFireHttpSessionC
|
||||
configureSessionRegionName(enableGemFireHttpSessionAttributes);
|
||||
configureSessionSerializerBeanName(enableGemFireHttpSessionAttributes);
|
||||
|
||||
// Apply configuration from {@link SpringSessionGemFireConfigurer}.
|
||||
applySpringSessionGemFireConfigurer();
|
||||
|
||||
// Expose configuration as {@link Properties} in the Spring {@link Environment}
|
||||
// if {@link EnableGemFireHttpSession#exposeConfigurationAsProperties} is set to {@literal true}.
|
||||
exposeSpringSessionGemFireConfigurationAsProperties();
|
||||
}
|
||||
|
||||
private void configureClientRegionShortcut(AnnotationAttributes enableGemFireHttpSessionAttributes) {
|
||||
@@ -510,13 +597,22 @@ public class GemFireHttpSessionConfiguration extends AbstractGemFireHttpSessionC
|
||||
ClientRegionShortcut.class, defaultClientRegionShortcut));
|
||||
}
|
||||
|
||||
private void configureIndexableSessionAttributes(AnnotationAttributes enableGemFireHttpSessionAttributes) {
|
||||
private void configureExposeConfigurationAsProperties(AnnotationAttributes enableGemFireHttpSessionAttributes) {
|
||||
|
||||
String[] defaultIndexableSessionAttributes =
|
||||
boolean defaultExposeConfigurationAsProperties = Boolean.TRUE
|
||||
.equals(enableGemFireHttpSessionAttributes.getBoolean("exposeConfigurationAsProperties"));
|
||||
|
||||
setExposeConfigurationAsProperties(resolveProperty(exposeConfigurationAsPropertiesPropertyName(),
|
||||
defaultExposeConfigurationAsProperties));
|
||||
}
|
||||
|
||||
private void configureIndexedSessionAttributes(AnnotationAttributes enableGemFireHttpSessionAttributes) {
|
||||
|
||||
String[] defaultIndexedSessionAttributes =
|
||||
enableGemFireHttpSessionAttributes.getStringArray("indexableSessionAttributes");
|
||||
|
||||
setIndexableSessionAttributes(resolveProperty(indexableSessionAttributesPropertyName(),
|
||||
defaultIndexableSessionAttributes));
|
||||
setIndexableSessionAttributes(resolveProperty(indexedSessionAttributesPropertyName(),
|
||||
resolveProperty(indexableSessionAttributesPropertyName(), defaultIndexedSessionAttributes)));
|
||||
}
|
||||
|
||||
private void configureMaxInactiveIntervalInSeconds(AnnotationAttributes enableGemFireHttpSessionAttributes) {
|
||||
@@ -569,10 +665,18 @@ public class GemFireHttpSessionConfiguration extends AbstractGemFireHttpSessionC
|
||||
defaultSessionSerializerBeanName));
|
||||
}
|
||||
|
||||
private void applySpringSessionGemFireConfigurer() {
|
||||
/**
|
||||
* Applies configuration from a single {@link SpringSessionGemFireConfigurer} bean
|
||||
* declared in the Spring {@link ApplicationContext}.
|
||||
*
|
||||
* @see org.springframework.session.data.gemfire.config.annotation.web.http.support.SpringSessionGemFireConfigurer
|
||||
* @see #resolveSpringSessionGemFireConfigurer()
|
||||
*/
|
||||
void applySpringSessionGemFireConfigurer() {
|
||||
|
||||
resolveSpringSessionGemFireConfigurer()
|
||||
.map(this::applyClientRegionShortcut)
|
||||
.map(this::applyExposeConfigurationAsProperties)
|
||||
.map(this::applyIndexableSessionAttributes)
|
||||
.map(this::applyMaxInactiveIntervalInSeconds)
|
||||
.map(this::applyPoolName)
|
||||
@@ -582,6 +686,25 @@ public class GemFireHttpSessionConfiguration extends AbstractGemFireHttpSessionC
|
||||
.map(this::applySessionSerializerBeanName);
|
||||
}
|
||||
|
||||
private Optional<SpringSessionGemFireConfigurer> resolveSpringSessionGemFireConfigurer() {
|
||||
|
||||
try {
|
||||
return Optional.of(getApplicationContext().getBean(SpringSessionGemFireConfigurer.class));
|
||||
}
|
||||
catch (BeansException cause) {
|
||||
|
||||
if (isCauseBecauseNoSpringSessionGemFireConfigurerPresent(cause)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
throw cause;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCauseBecauseNoSpringSessionGemFireConfigurerPresent(Exception cause) {
|
||||
return (!(cause instanceof NoUniqueBeanDefinitionException) && cause instanceof NoSuchBeanDefinitionException);
|
||||
}
|
||||
|
||||
private <T> SpringSessionGemFireConfigurer applySpringSessionGemFireConfigurerConfiguration(
|
||||
@Nullable SpringSessionGemFireConfigurer configurer, @NonNull String methodName,
|
||||
@NonNull Function<SpringSessionGemFireConfigurer, T> getter, @NonNull Consumer<T> setter) {
|
||||
@@ -601,6 +724,13 @@ public class GemFireHttpSessionConfiguration extends AbstractGemFireHttpSessionC
|
||||
SpringSessionGemFireConfigurer::getClientRegionShortcut, this::setClientRegionShortcut);
|
||||
}
|
||||
|
||||
private <T> SpringSessionGemFireConfigurer applyExposeConfigurationAsProperties(SpringSessionGemFireConfigurer configurer) {
|
||||
|
||||
return applySpringSessionGemFireConfigurerConfiguration(configurer,
|
||||
CONFIGURER_GET_EXPOSE_CONFIGURATION_IN_PROPERTIES_METHOD_NAME,
|
||||
SpringSessionGemFireConfigurer::getExposeConfigurationAsProperties, this::setExposeConfigurationAsProperties);
|
||||
}
|
||||
|
||||
private SpringSessionGemFireConfigurer applyIndexableSessionAttributes(SpringSessionGemFireConfigurer configurer) {
|
||||
|
||||
return applySpringSessionGemFireConfigurerConfiguration(configurer,
|
||||
@@ -650,23 +780,63 @@ public class GemFireHttpSessionConfiguration extends AbstractGemFireHttpSessionC
|
||||
SpringSessionGemFireConfigurer::getSessionSerializerBeanName, this::setSessionSerializerBeanName);
|
||||
}
|
||||
|
||||
private Optional<SpringSessionGemFireConfigurer> resolveSpringSessionGemFireConfigurer() {
|
||||
/**
|
||||
* Exposes the configuration of Spring Session using either Apache Geode or Pivotal GemFire as {@link Properties}
|
||||
* in the Spring {@link Environment}.
|
||||
*
|
||||
* @see #isExposeConfigurationAsProperties()
|
||||
*/
|
||||
void exposeSpringSessionGemFireConfigurationAsProperties() {
|
||||
|
||||
try {
|
||||
return Optional.of(getApplicationContext().getBean(SpringSessionGemFireConfigurer.class));
|
||||
if (isExposeConfigurationAsProperties()) {
|
||||
|
||||
Optional.ofNullable(getEnvironment())
|
||||
.filter(ConfigurableEnvironment.class::isInstance)
|
||||
.map(ConfigurableEnvironment.class::cast)
|
||||
.map(ConfigurableEnvironment::getPropertySources)
|
||||
.map(propertySources -> {
|
||||
|
||||
Properties springSessionGemFireProperties = new Properties();
|
||||
|
||||
PropertySource springSessionGemFirePropertySource =
|
||||
new PropertiesPropertySource(SPRING_SESSION_GEMFIRE_PROPERTY_SOURCE,
|
||||
springSessionGemFireProperties);
|
||||
|
||||
propertySources.addFirst(springSessionGemFirePropertySource);
|
||||
|
||||
return springSessionGemFireProperties;
|
||||
})
|
||||
.ifPresent(properties -> {
|
||||
|
||||
properties.setProperty(clientRegionShortcutPropertyName(),
|
||||
getClientRegionShortcut().name());
|
||||
|
||||
properties.setProperty(exposeConfigurationAsPropertiesPropertyName(),
|
||||
String.valueOf(isExposeConfigurationAsProperties()));
|
||||
|
||||
// TODO: deprecate and remove indexableSessionAttributes
|
||||
properties.setProperty(indexableSessionAttributesPropertyName(),
|
||||
StringUtils.arrayToCommaDelimitedString(getIndexableSessionAttributes()));
|
||||
|
||||
properties.setProperty(indexedSessionAttributesPropertyName(),
|
||||
StringUtils.arrayToCommaDelimitedString(getIndexableSessionAttributes()));
|
||||
|
||||
properties.setProperty(maxInactiveIntervalInSecondsPropertyName(),
|
||||
String.valueOf(getMaxInactiveIntervalInSeconds()));
|
||||
|
||||
properties.setProperty(poolNamePropertyName(), getPoolName());
|
||||
|
||||
properties.setProperty(sessionRegionNamePropertyName(), getSessionRegionName());
|
||||
|
||||
properties.setProperty(serverRegionShortcutPropertyName(),
|
||||
getServerRegionShortcut().name());
|
||||
|
||||
getSessionExpirationPolicyBeanName()
|
||||
.ifPresent(it -> properties.setProperty(sessionExpirationPolicyBeanNamePropertyName(), it));
|
||||
|
||||
properties.setProperty(sessionSerializerBeanNamePropertyName(), getSessionSerializerBeanName());
|
||||
});
|
||||
}
|
||||
catch (BeansException cause) {
|
||||
|
||||
if (isCauseBecauseNoSpringSessionGemFireConfigurerPresent(cause)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
throw cause;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCauseBecauseNoSpringSessionGemFireConfigurerPresent(Exception cause) {
|
||||
return (!(cause instanceof NoUniqueBeanDefinitionException) && cause instanceof NoSuchBeanDefinitionException);
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package org.springframework.session.data.gemfire.config.annotation.web.http.support;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.RegionShortcut;
|
||||
@@ -63,6 +66,35 @@ public interface SpringSessionGemFireConfigurer {
|
||||
return GemFireHttpSessionConfiguration.DEFAULT_CLIENT_REGION_SHORTCUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the configuration for Spring Session using Apache Geode or Pivotal GemFire should be exposed
|
||||
* in the Spring {@link org.springframework.core.env.Environment} as {@link Properties}.
|
||||
*
|
||||
* Currently, users may configure Spring Session for Apache Geode or Pivotal GemFire using attributes on this
|
||||
* {@link Annotation}, using the well-known and documented {@link Properties}
|
||||
* (e.g. {@literal spring.session.data.gemfire.session.expiration.max-inactive-interval-seconds})
|
||||
* or using the {@link SpringSessionGemFireConfigurer} declared as a bean in the Spring application context.
|
||||
*
|
||||
* The {@link Properties} that are exposed will use the well-known property {@link String names} that are documented
|
||||
* in this {@link Annotation Annotation's} attributes.
|
||||
*
|
||||
* The values of the resulting {@link Properties} follows the precedence as outlined in the documentation:
|
||||
* first any {@link SpringSessionGemFireConfigurer} bean defined takes precedence, followed by explicit
|
||||
* {@link Properties} declared in Spring Boot {@literal application.properties} and finally, this
|
||||
* {@link Annotation Annotation's} attribute values.
|
||||
*
|
||||
* Defaults to {@literal false}.
|
||||
*
|
||||
* Use {@literal spring.session.data.gemfire.session.configuration.expose} in Spring Boot
|
||||
* {@literal application.properties}.
|
||||
*
|
||||
* @return a boolean value indicating whether to expose the configuration of Spring Session using Apache Geode
|
||||
* or Pivotal GemFire in the Spring {@link org.springframework.core.env.Environment} as {@link Properties}.
|
||||
*/
|
||||
default boolean getExposeConfigurationAsProperties() {
|
||||
return GemFireHttpSessionConfiguration.DEFAULT_EXPOSE_CONFIGURATION_AS_PROPERTIES;
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies the {@link Session} attributes by name that will be indexed for query operations.
|
||||
*
|
||||
|
||||
@@ -17,9 +17,15 @@
|
||||
package org.springframework.session.data.gemfire.config.annotation.web.http;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
@@ -43,13 +49,19 @@ import org.apache.geode.cache.client.ClientCache;
|
||||
import org.apache.geode.cache.client.ClientRegionShortcut;
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.data.gemfire.GemfireOperations;
|
||||
import org.springframework.data.gemfire.GemfireTemplate;
|
||||
import org.springframework.data.gemfire.RegionAttributesFactoryBean;
|
||||
import org.springframework.data.gemfire.util.ArrayUtils;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.data.gemfire.GemFireOperationsSessionRepository;
|
||||
import org.springframework.session.data.gemfire.config.annotation.web.http.support.GemFireCacheTypeAwareRegionFactoryBean;
|
||||
@@ -83,10 +95,8 @@ import org.springframework.util.ReflectionUtils;
|
||||
*/
|
||||
public class GemFireHttpSessionConfigurationTests {
|
||||
|
||||
private GemFireHttpSessionConfiguration gemfireConfiguration;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T> T getField(Object obj, String fieldName) {
|
||||
private <T> T getField(Object obj, String fieldName) {
|
||||
|
||||
try {
|
||||
Field field = resolveField(obj, fieldName);
|
||||
@@ -118,20 +128,17 @@ public class GemFireHttpSessionConfigurationTests {
|
||||
return field;
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
private static <T> T[] toArray(T... array) {
|
||||
return array;
|
||||
}
|
||||
private GemFireHttpSessionConfiguration gemfireConfiguration;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
|
||||
this.gemfireConfiguration = new GemFireHttpSessionConfiguration();
|
||||
this.gemfireConfiguration = spy(new GemFireHttpSessionConfiguration());
|
||||
|
||||
ApplicationContext mockApplicationContext = mock(ApplicationContext.class);
|
||||
|
||||
when(mockApplicationContext.getBean(eq(SpringSessionGemFireConfigurer.class)))
|
||||
.thenThrow(new NoSuchBeanDefinitionException("No SpringSessionGemFireConfigurer bean available"));
|
||||
.thenThrow(new NoSuchBeanDefinitionException("No SpringSessionGemFireConfigurer bean present"));
|
||||
|
||||
this.gemfireConfiguration.setApplicationContext(mockApplicationContext);
|
||||
}
|
||||
@@ -169,6 +176,42 @@ public class GemFireHttpSessionConfigurationTests {
|
||||
GemFireHttpSessionConfiguration.DEFAULT_CLIENT_REGION_SHORTCUT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAndGetExposeConfigurationAsProperties() {
|
||||
|
||||
assertThat(this.gemfireConfiguration.isExposeConfigurationAsProperties()).isFalse();
|
||||
|
||||
this.gemfireConfiguration.setExposeConfigurationAsProperties(true);
|
||||
|
||||
assertThat(this.gemfireConfiguration.isExposeConfigurationAsProperties()).isTrue();
|
||||
|
||||
this.gemfireConfiguration.setExposeConfigurationAsProperties(false);
|
||||
|
||||
assertThat(this.gemfireConfiguration.isExposeConfigurationAsProperties()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAndGetIndexedSessionAttributes() {
|
||||
|
||||
assertThat(this.gemfireConfiguration.getIndexableSessionAttributes()).isEmpty();
|
||||
|
||||
this.gemfireConfiguration.setIndexableSessionAttributes(ArrayUtils.asArray("one", "two"));
|
||||
|
||||
assertThat(this.gemfireConfiguration.getIndexableSessionAttributes()).containsExactly("one", "two");
|
||||
|
||||
this.gemfireConfiguration.setIndexableSessionAttributes(new String[0]);
|
||||
|
||||
assertThat(this.gemfireConfiguration.getIndexableSessionAttributes()).isEmpty();
|
||||
|
||||
this.gemfireConfiguration.setIndexableSessionAttributes(ArrayUtils.asArray("two"));
|
||||
|
||||
assertThat(this.gemfireConfiguration.getIndexableSessionAttributes()).containsExactly("two");
|
||||
|
||||
this.gemfireConfiguration.setIndexableSessionAttributes(null);
|
||||
|
||||
assertThat(this.gemfireConfiguration.getIndexableSessionAttributes()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAndGetMaxInactiveIntervalInSeconds() {
|
||||
|
||||
@@ -235,6 +278,39 @@ public class GemFireHttpSessionConfigurationTests {
|
||||
GemFireHttpSessionConfiguration.DEFAULT_SERVER_REGION_SHORTCUT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAndGetSessionExpirationPolicyBeanName() {
|
||||
|
||||
assertThat(this.gemfireConfiguration.getSessionExpirationPolicyBeanName().orElse(null)).isNull();
|
||||
|
||||
this.gemfireConfiguration.setSessionExpirationPolicyBeanName("TestSessionExpirationPolicy");
|
||||
|
||||
assertThat(this.gemfireConfiguration.getSessionExpirationPolicyBeanName().orElse(null))
|
||||
.isEqualTo("TestSessionExpirationPolicy");
|
||||
|
||||
this.gemfireConfiguration.setSessionExpirationPolicyBeanName(" ");
|
||||
|
||||
assertThat(this.gemfireConfiguration.getSessionExpirationPolicyBeanName().orElse(null)).isNull();
|
||||
|
||||
this.gemfireConfiguration.setSessionExpirationPolicyBeanName("MockSessionExpirationPolicy");
|
||||
|
||||
assertThat(this.gemfireConfiguration.getSessionExpirationPolicyBeanName().orElse(null))
|
||||
.isEqualTo("MockSessionExpirationPolicy");
|
||||
|
||||
this.gemfireConfiguration.setSessionExpirationPolicyBeanName("");
|
||||
|
||||
assertThat(this.gemfireConfiguration.getSessionExpirationPolicyBeanName().orElse(null)).isNull();
|
||||
|
||||
this.gemfireConfiguration.setSessionExpirationPolicyBeanName("SessionExpirationPolicySpy");
|
||||
|
||||
assertThat(this.gemfireConfiguration.getSessionExpirationPolicyBeanName().orElse(null))
|
||||
.isEqualTo("SessionExpirationPolicySpy");
|
||||
|
||||
this.gemfireConfiguration.setSessionExpirationPolicyBeanName(null);
|
||||
|
||||
assertThat(this.gemfireConfiguration.getSessionExpirationPolicyBeanName().orElse(null)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAndGetSessionRegionName() {
|
||||
|
||||
@@ -286,7 +362,7 @@ public class GemFireHttpSessionConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isUsingDataSerializationIsFalse() {
|
||||
public void isUsingDataSerializationReturnsFalse() {
|
||||
|
||||
this.gemfireConfiguration.setSessionSerializerBeanName("test");
|
||||
|
||||
@@ -303,7 +379,7 @@ public class GemFireHttpSessionConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isUsingPdxSerializationIsTrue() {
|
||||
public void isUsingPdxSerializationReturnsTrue() {
|
||||
|
||||
assertThat(this.gemfireConfiguration.getSessionSerializerBeanName())
|
||||
.isEqualTo(GemFireHttpSessionConfiguration.SESSION_PDX_SERIALIZER_BEAN_NAME);
|
||||
@@ -324,7 +400,8 @@ public class GemFireHttpSessionConfigurationTests {
|
||||
Map<String, Object> annotationAttributes = new HashMap<>(4);
|
||||
|
||||
annotationAttributes.put("clientRegionShortcut", ClientRegionShortcut.CACHING_PROXY);
|
||||
annotationAttributes.put("indexableSessionAttributes", toArray("one", "two", "three"));
|
||||
annotationAttributes.put("exposeConfigurationAsProperties", Boolean.TRUE);
|
||||
annotationAttributes.put("indexableSessionAttributes", ArrayUtils.asArray("one", "two", "three"));
|
||||
annotationAttributes.put("maxInactiveIntervalInSeconds", 600);
|
||||
annotationAttributes.put("poolName", "TestPool");
|
||||
annotationAttributes.put("serverRegionShortcut", RegionShortcut.REPLICATE);
|
||||
@@ -332,13 +409,15 @@ public class GemFireHttpSessionConfigurationTests {
|
||||
annotationAttributes.put("sessionExpirationPolicyBeanName", "testSessionExpirationPolicy");
|
||||
annotationAttributes.put("sessionSerializerBeanName", "testSessionSerializer");
|
||||
|
||||
given(mockAnnotationMetadata.getAnnotationAttributes(eq(EnableGemFireHttpSession.class.getName())))
|
||||
.willReturn(annotationAttributes);
|
||||
when(mockAnnotationMetadata.getAnnotationAttributes(eq(EnableGemFireHttpSession.class.getName())))
|
||||
.thenReturn(annotationAttributes);
|
||||
|
||||
this.gemfireConfiguration.setImportMetadata(mockAnnotationMetadata);
|
||||
|
||||
assertThat(this.gemfireConfiguration.getClientRegionShortcut()).isEqualTo(ClientRegionShortcut.CACHING_PROXY);
|
||||
assertThat(this.gemfireConfiguration.getIndexableSessionAttributes()).isEqualTo(toArray("one", "two", "three"));
|
||||
assertThat(this.gemfireConfiguration.isExposeConfigurationAsProperties()).isTrue();
|
||||
assertThat(this.gemfireConfiguration.getIndexableSessionAttributes())
|
||||
.isEqualTo(ArrayUtils.asArray("one", "two", "three"));
|
||||
assertThat(this.gemfireConfiguration.getMaxInactiveIntervalInSeconds()).isEqualTo(600);
|
||||
assertThat(this.gemfireConfiguration.getPoolName()).isEqualTo("TestPool");
|
||||
assertThat(this.gemfireConfiguration.getServerRegionShortcut()).isEqualTo(RegionShortcut.REPLICATE);
|
||||
@@ -349,7 +428,227 @@ public class GemFireHttpSessionConfigurationTests {
|
||||
|
||||
verify(mockAnnotationMetadata, times(1))
|
||||
.getAnnotationAttributes(eq(EnableGemFireHttpSession.class.getName()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void applyConfigurationFromSpringSessionGemFireConfigurer() {
|
||||
|
||||
ApplicationContext mockApplicationContext = mock(ApplicationContext.class);
|
||||
|
||||
SpringSessionGemFireConfigurer mockConfigurer = mock(SpringSessionGemFireConfigurer.class);
|
||||
|
||||
when(mockApplicationContext.getBean(eq(SpringSessionGemFireConfigurer.class))).thenReturn(mockConfigurer);
|
||||
when(mockConfigurer.getClientRegionShortcut()).thenReturn(ClientRegionShortcut.CACHING_PROXY);
|
||||
when(mockConfigurer.getExposeConfigurationAsProperties()).thenReturn(true);
|
||||
when(mockConfigurer.getIndexableSessionAttributes()).thenReturn(new String[] { "one", "two" });
|
||||
when(mockConfigurer.getMaxInactiveIntervalInSeconds()).thenReturn(300);
|
||||
when(mockConfigurer.getPoolName()).thenReturn("DeadPool");
|
||||
when(mockConfigurer.getRegionName()).thenReturn("Sessions");
|
||||
when(mockConfigurer.getServerRegionShortcut()).thenReturn(RegionShortcut.PARTITION_REDUNDANT);
|
||||
when(mockConfigurer.getSessionExpirationPolicyBeanName()).thenReturn("TestSessionExpirationPolicy");
|
||||
when(mockConfigurer.getSessionSerializerBeanName()).thenReturn("TestSessionSerializer");
|
||||
|
||||
this.gemfireConfiguration.setApplicationContext(mockApplicationContext);
|
||||
this.gemfireConfiguration.applySpringSessionGemFireConfigurer();
|
||||
|
||||
assertThat(this.gemfireConfiguration.getClientRegionShortcut()).isEqualTo(ClientRegionShortcut.CACHING_PROXY);
|
||||
assertThat(this.gemfireConfiguration.isExposeConfigurationAsProperties()).isEqualTo(true);
|
||||
assertThat(this.gemfireConfiguration.getIndexableSessionAttributes()).containsExactly("one", "two");
|
||||
assertThat(this.gemfireConfiguration.getMaxInactiveIntervalInSeconds()).isEqualTo(300);
|
||||
assertThat(this.gemfireConfiguration.getPoolName()).isEqualTo("DeadPool");
|
||||
assertThat(this.gemfireConfiguration.getServerRegionShortcut()).isEqualTo(RegionShortcut.PARTITION_REDUNDANT);
|
||||
assertThat(this.gemfireConfiguration.getSessionRegionName()).isEqualTo("Sessions");
|
||||
assertThat(this.gemfireConfiguration.getSessionExpirationPolicyBeanName().orElse(null))
|
||||
.isEqualTo("TestSessionExpirationPolicy");
|
||||
assertThat(this.gemfireConfiguration.getSessionSerializerBeanName()).isEqualTo("TestSessionSerializer");
|
||||
|
||||
verify(mockConfigurer, times(1)).getClientRegionShortcut();
|
||||
verify(mockConfigurer, times(1)).getExposeConfigurationAsProperties();
|
||||
verify(mockConfigurer, times(1)).getIndexableSessionAttributes();
|
||||
verify(mockConfigurer, times(1)).getMaxInactiveIntervalInSeconds();
|
||||
verify(mockConfigurer, times(1)).getPoolName();
|
||||
verify(mockConfigurer, times(1)).getRegionName();
|
||||
verify(mockConfigurer, times(1)).getServerRegionShortcut();
|
||||
verify(mockConfigurer, times(1)).getSessionExpirationPolicyBeanName();
|
||||
verify(mockConfigurer, times(1)).getSessionSerializerBeanName();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void applyConfigurationFromNonExistingSpringSessionGemFireConfigurer() {
|
||||
|
||||
this.gemfireConfiguration.applySpringSessionGemFireConfigurer();
|
||||
|
||||
verify(this.gemfireConfiguration, never()).setClientRegionShortcut(any(ClientRegionShortcut.class));
|
||||
verify(this.gemfireConfiguration, never()).setExposeConfigurationAsProperties(anyBoolean());
|
||||
verify(this.gemfireConfiguration, never()).setIndexableSessionAttributes(any(String[].class));
|
||||
verify(this.gemfireConfiguration, never()).setMaxInactiveIntervalInSeconds(anyInt());
|
||||
verify(this.gemfireConfiguration, never()).setPoolName(anyString());
|
||||
verify(this.gemfireConfiguration, never()).setServerRegionShortcut(any(RegionShortcut.class));
|
||||
verify(this.gemfireConfiguration, never()).setSessionExpirationPolicyBeanName(anyString());
|
||||
verify(this.gemfireConfiguration, never()).setSessionRegionName(anyString());
|
||||
verify(this.gemfireConfiguration, never()).setSessionSerializerBeanName(anyString());
|
||||
}
|
||||
|
||||
@Test(expected = NoUniqueBeanDefinitionException.class)
|
||||
public void applyConfigurationFromMultipleSpringSessionGemFireConfigurersThrowsException() {
|
||||
|
||||
ApplicationContext mockApplicationContext = mock(ApplicationContext.class);
|
||||
|
||||
when(mockApplicationContext.getBean(eq(SpringSessionGemFireConfigurer.class)))
|
||||
.thenThrow(new NoUniqueBeanDefinitionException(SpringSessionGemFireConfigurer.class, 2, "TEST"));
|
||||
|
||||
this.gemfireConfiguration.setApplicationContext(mockApplicationContext);
|
||||
|
||||
try {
|
||||
this.gemfireConfiguration.applySpringSessionGemFireConfigurer();
|
||||
}
|
||||
catch (NoUniqueBeanDefinitionException expected) {
|
||||
|
||||
assertThat(expected).hasMessageContaining("TEST");
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
finally {
|
||||
verify(this.gemfireConfiguration, never()).setClientRegionShortcut(any(ClientRegionShortcut.class));
|
||||
verify(this.gemfireConfiguration, never()).setExposeConfigurationAsProperties(anyBoolean());
|
||||
verify(this.gemfireConfiguration, never()).setIndexableSessionAttributes(any(String[].class));
|
||||
verify(this.gemfireConfiguration, never()).setMaxInactiveIntervalInSeconds(anyInt());
|
||||
verify(this.gemfireConfiguration, never()).setPoolName(anyString());
|
||||
verify(this.gemfireConfiguration, never()).setServerRegionShortcut(any(RegionShortcut.class));
|
||||
verify(this.gemfireConfiguration, never()).setSessionExpirationPolicyBeanName(anyString());
|
||||
verify(this.gemfireConfiguration, never()).setSessionRegionName(anyString());
|
||||
verify(this.gemfireConfiguration, never()).setSessionSerializerBeanName(anyString());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exposeSpringSessionGemFireConfigurationAsPropertiesMutatesSpringEnvironment() {
|
||||
|
||||
ConfigurableEnvironment environment = new StandardEnvironment();
|
||||
|
||||
this.gemfireConfiguration.setClientRegionShortcut(ClientRegionShortcut.CACHING_PROXY);
|
||||
this.gemfireConfiguration.setEnvironment(environment);
|
||||
this.gemfireConfiguration.setExposeConfigurationAsProperties(true);
|
||||
this.gemfireConfiguration.setIndexableSessionAttributes(ArrayUtils.asArray("one", "two"));
|
||||
this.gemfireConfiguration.setMaxInactiveIntervalInSeconds(300);
|
||||
this.gemfireConfiguration.setPoolName("DeadPool");
|
||||
this.gemfireConfiguration.setServerRegionShortcut(RegionShortcut.PARTITION_REDUNDANT);
|
||||
this.gemfireConfiguration.setSessionExpirationPolicyBeanName("TestSessionExpirationPolicy");
|
||||
this.gemfireConfiguration.setSessionRegionName("Sessions");
|
||||
this.gemfireConfiguration.setSessionSerializerBeanName("TestSessionSerializer");
|
||||
this.gemfireConfiguration.setExposeConfigurationAsProperties(true);
|
||||
this.gemfireConfiguration.exposeSpringSessionGemFireConfigurationAsProperties();
|
||||
|
||||
PropertySource springSessionGemFirePropertySource = environment.getPropertySources()
|
||||
.get(GemFireHttpSessionConfiguration.SPRING_SESSION_GEMFIRE_PROPERTY_SOURCE);
|
||||
|
||||
assertThat(springSessionGemFirePropertySource).isNotNull();
|
||||
|
||||
assertThat(springSessionGemFirePropertySource.getProperty("spring.session.data.gemfire.cache.client.region.shortcut"))
|
||||
.isEqualTo(ClientRegionShortcut.CACHING_PROXY.name());
|
||||
|
||||
assertThat(springSessionGemFirePropertySource.getProperty("spring.session.data.gemfire.session.configuration.expose"))
|
||||
.isEqualTo(Boolean.TRUE.toString());
|
||||
|
||||
assertThat(springSessionGemFirePropertySource.getProperty("spring.session.data.gemfire.session.attributes.indexable"))
|
||||
.isEqualTo("one,two");
|
||||
|
||||
assertThat(springSessionGemFirePropertySource.getProperty("spring.session.data.gemfire.session.attributes.indexed"))
|
||||
.isEqualTo("one,two");
|
||||
|
||||
assertThat(springSessionGemFirePropertySource.getProperty("spring.session.data.gemfire.session.expiration.max-inactive-interval-seconds"))
|
||||
.isEqualTo("300");
|
||||
|
||||
assertThat(springSessionGemFirePropertySource.getProperty("spring.session.data.gemfire.cache.client.pool.name"))
|
||||
.isEqualTo("DeadPool");
|
||||
|
||||
assertThat(springSessionGemFirePropertySource.getProperty("spring.session.data.gemfire.cache.server.region.shortcut"))
|
||||
.isEqualTo(RegionShortcut.PARTITION_REDUNDANT.name());
|
||||
|
||||
assertThat(springSessionGemFirePropertySource.getProperty("spring.session.data.gemfire.session.expiration.bean-name"))
|
||||
.isEqualTo("TestSessionExpirationPolicy");
|
||||
|
||||
assertThat(springSessionGemFirePropertySource.getProperty("spring.session.data.gemfire.session.region.name"))
|
||||
.isEqualTo("Sessions");
|
||||
|
||||
assertThat(springSessionGemFirePropertySource.getProperty("spring.session.data.gemfire.session.serializer.bean-name"))
|
||||
.isEqualTo("TestSessionSerializer");
|
||||
|
||||
verify(this.gemfireConfiguration, times(1)).getClientRegionShortcut();
|
||||
verify(this.gemfireConfiguration, times(1)).getEnvironment();
|
||||
verify(this.gemfireConfiguration, times(2)).isExposeConfigurationAsProperties();
|
||||
verify(this.gemfireConfiguration, times(2)).getIndexableSessionAttributes();
|
||||
verify(this.gemfireConfiguration, times(1)).getMaxInactiveIntervalInSeconds();
|
||||
verify(this.gemfireConfiguration, times(1)).getPoolName();
|
||||
verify(this.gemfireConfiguration, times(1)).getSessionRegionName();
|
||||
verify(this.gemfireConfiguration, times(1)).getServerRegionShortcut();
|
||||
verify(this.gemfireConfiguration, times(1)).getSessionExpirationPolicyBeanName();
|
||||
verify(this.gemfireConfiguration, times(1)).getSessionSerializerBeanName();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("all")
|
||||
public void exposeSpringSessionGemFireConfigurationAsPropertiesIsNullSafe() {
|
||||
|
||||
this.gemfireConfiguration.setEnvironment(null);
|
||||
this.gemfireConfiguration.setExposeConfigurationAsProperties(true);
|
||||
this.gemfireConfiguration.exposeSpringSessionGemFireConfigurationAsProperties();
|
||||
|
||||
verify(this.gemfireConfiguration, never()).getClientRegionShortcut();
|
||||
verify(this.gemfireConfiguration, times(1)).getEnvironment();
|
||||
verify(this.gemfireConfiguration, times(1)).isExposeConfigurationAsProperties();
|
||||
verify(this.gemfireConfiguration, never()).getIndexableSessionAttributes();
|
||||
verify(this.gemfireConfiguration, never()).getMaxInactiveIntervalInSeconds();
|
||||
verify(this.gemfireConfiguration, never()).getPoolName();
|
||||
verify(this.gemfireConfiguration, never()).getSessionRegionName();
|
||||
verify(this.gemfireConfiguration, never()).getServerRegionShortcut();
|
||||
verify(this.gemfireConfiguration, never()).getSessionExpirationPolicyBeanName();
|
||||
verify(this.gemfireConfiguration, never()).getSessionSerializerBeanName();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exposeSpringSessionGemFireConfigurationAsPropertiesWhenExposureIsFalse() {
|
||||
|
||||
ConfigurableEnvironment mockEnvironment = mock(ConfigurableEnvironment.class);
|
||||
|
||||
this.gemfireConfiguration.setEnvironment(mockEnvironment);
|
||||
this.gemfireConfiguration.setExposeConfigurationAsProperties(false);
|
||||
this.gemfireConfiguration.exposeSpringSessionGemFireConfigurationAsProperties();
|
||||
|
||||
verify(this.gemfireConfiguration, never()).getClientRegionShortcut();
|
||||
verify(this.gemfireConfiguration, never()).getEnvironment();
|
||||
verify(this.gemfireConfiguration, times(1)).isExposeConfigurationAsProperties();
|
||||
verify(this.gemfireConfiguration, never()).getIndexableSessionAttributes();
|
||||
verify(this.gemfireConfiguration, never()).getMaxInactiveIntervalInSeconds();
|
||||
verify(this.gemfireConfiguration, never()).getPoolName();
|
||||
verify(this.gemfireConfiguration, never()).getSessionRegionName();
|
||||
verify(this.gemfireConfiguration, never()).getServerRegionShortcut();
|
||||
verify(this.gemfireConfiguration, never()).getSessionExpirationPolicyBeanName();
|
||||
verify(this.gemfireConfiguration, never()).getSessionSerializerBeanName();
|
||||
verifyZeroInteractions(mockEnvironment);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exposeSpringSessionGemFireConfigurationAsPropertiesWithNonConfigurableEnvironment() {
|
||||
|
||||
Environment mockEnvironment = mock(Environment.class);
|
||||
|
||||
this.gemfireConfiguration.setEnvironment(mockEnvironment);
|
||||
this.gemfireConfiguration.setExposeConfigurationAsProperties(true);
|
||||
this.gemfireConfiguration.exposeSpringSessionGemFireConfigurationAsProperties();
|
||||
|
||||
verify(this.gemfireConfiguration, never()).getClientRegionShortcut();
|
||||
verify(this.gemfireConfiguration, times(1)).getEnvironment();
|
||||
verify(this.gemfireConfiguration, times(1)).isExposeConfigurationAsProperties();
|
||||
verify(this.gemfireConfiguration, never()).getIndexableSessionAttributes();
|
||||
verify(this.gemfireConfiguration, never()).getMaxInactiveIntervalInSeconds();
|
||||
verify(this.gemfireConfiguration, never()).getPoolName();
|
||||
verify(this.gemfireConfiguration, never()).getSessionRegionName();
|
||||
verify(this.gemfireConfiguration, never()).getServerRegionShortcut();
|
||||
verify(this.gemfireConfiguration, never()).getSessionExpirationPolicyBeanName();
|
||||
verify(this.gemfireConfiguration, never()).getSessionSerializerBeanName();
|
||||
verifyZeroInteractions(mockEnvironment);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -382,8 +681,8 @@ public class GemFireHttpSessionConfigurationTests {
|
||||
|
||||
this.gemfireConfiguration.setMaxInactiveIntervalInSeconds(120);
|
||||
|
||||
GemFireOperationsSessionRepository sessionRepository = this.gemfireConfiguration.sessionRepository(
|
||||
mockGemfireOperations);
|
||||
GemFireOperationsSessionRepository sessionRepository =
|
||||
this.gemfireConfiguration.sessionRepository(mockGemfireOperations);
|
||||
|
||||
assertThat(sessionRepository).isNotNull();
|
||||
assertThat(sessionRepository.getTemplate()).isSameAs(mockGemfireOperations);
|
||||
@@ -421,7 +720,7 @@ public class GemFireHttpSessionConfigurationTests {
|
||||
|
||||
this.gemfireConfiguration.setClientRegionShortcut(ClientRegionShortcut.CACHING_PROXY);
|
||||
this.gemfireConfiguration.setPoolName("TestPool");
|
||||
this.gemfireConfiguration.setServerRegionShortcut(RegionShortcut.REPLICATE_PERSISTENT);
|
||||
this.gemfireConfiguration.setServerRegionShortcut(RegionShortcut.PARTITION_REDUNDANT);
|
||||
this.gemfireConfiguration.setSessionRegionName("TestRegion");
|
||||
|
||||
GemFireCacheTypeAwareRegionFactoryBean<Object, Session> sessionRegionFactoryBean =
|
||||
@@ -434,7 +733,7 @@ public class GemFireHttpSessionConfigurationTests {
|
||||
assertThat(this.<RegionAttributes<Object, Session>>getField(sessionRegionFactoryBean,
|
||||
"regionAttributes")).isEqualTo(mockRegionAttributes);
|
||||
assertThat(this.<String>getField(sessionRegionFactoryBean, "regionName")).isEqualTo("TestRegion");
|
||||
assertThat(sessionRegionFactoryBean.getServerRegionShortcut()).isEqualTo(RegionShortcut.REPLICATE_PERSISTENT);
|
||||
assertThat(sessionRegionFactoryBean.getServerRegionShortcut()).isEqualTo(RegionShortcut.PARTITION_REDUNDANT);
|
||||
|
||||
verifyZeroInteractions(mockGemFireCache);
|
||||
verifyZeroInteractions(mockRegionAttributes);
|
||||
@@ -459,10 +758,10 @@ public class GemFireHttpSessionConfigurationTests {
|
||||
RegionAttributes<Object, Session> sessionRegionAttributes = regionAttributesFactory.getObject();
|
||||
|
||||
assertThat(sessionRegionAttributes).isNotNull();
|
||||
assertThat(sessionRegionAttributes.getKeyConstraint()).isEqualTo(
|
||||
GemFireHttpSessionConfiguration.SESSION_REGION_KEY_CONSTRAINT);
|
||||
assertThat(sessionRegionAttributes.getValueConstraint()).isEqualTo(
|
||||
GemFireHttpSessionConfiguration.SESSION_REGION_VALUE_CONSTRAINT);
|
||||
assertThat(sessionRegionAttributes.getKeyConstraint())
|
||||
.isEqualTo(GemFireHttpSessionConfiguration.SESSION_REGION_KEY_CONSTRAINT);
|
||||
assertThat(sessionRegionAttributes.getValueConstraint())
|
||||
.isEqualTo(GemFireHttpSessionConfiguration.SESSION_REGION_VALUE_CONSTRAINT);
|
||||
|
||||
ExpirationAttributes entryIdleTimeoutExpiration = sessionRegionAttributes.getEntryIdleTimeout();
|
||||
|
||||
@@ -489,10 +788,10 @@ public class GemFireHttpSessionConfigurationTests {
|
||||
RegionAttributes<Object, Session> sessionRegionAttributes = regionAttributesFactory.getObject();
|
||||
|
||||
assertThat(sessionRegionAttributes).isNotNull();
|
||||
assertThat(sessionRegionAttributes.getKeyConstraint()).isEqualTo(
|
||||
GemFireHttpSessionConfiguration.SESSION_REGION_KEY_CONSTRAINT);
|
||||
assertThat(sessionRegionAttributes.getValueConstraint()).isEqualTo(
|
||||
GemFireHttpSessionConfiguration.SESSION_REGION_VALUE_CONSTRAINT);
|
||||
assertThat(sessionRegionAttributes.getKeyConstraint())
|
||||
.isEqualTo(GemFireHttpSessionConfiguration.SESSION_REGION_KEY_CONSTRAINT);
|
||||
assertThat(sessionRegionAttributes.getValueConstraint())
|
||||
.isEqualTo(GemFireHttpSessionConfiguration.SESSION_REGION_VALUE_CONSTRAINT);
|
||||
|
||||
ExpirationAttributes entryIdleTimeoutExpiration = sessionRegionAttributes.getEntryIdleTimeout();
|
||||
|
||||
@@ -500,8 +799,8 @@ public class GemFireHttpSessionConfigurationTests {
|
||||
assertThat(entryIdleTimeoutExpiration.getAction()).isEqualTo(ExpirationAction.INVALIDATE);
|
||||
assertThat(entryIdleTimeoutExpiration.getTimeout()).isEqualTo(0);
|
||||
}
|
||||
@Test
|
||||
|
||||
@Test
|
||||
public void clientExpirationIsAllowed() {
|
||||
|
||||
ClientCache mockClientCache = mock(ClientCache.class);
|
||||
|
||||
Reference in New Issue
Block a user