Add support to expose configuration as properties in the Spring Environment.

Edit Javadoc.

Resolves gh-14.
This commit is contained in:
John Blum
2018-11-25 18:26:36 -08:00
parent e036a1b512
commit f37010c5d7
6 changed files with 1096 additions and 111 deletions

View File

@@ -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";
}
};
}
}
}

View File

@@ -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) {

View File

@@ -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.
*/

View File

@@ -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

View File

@@ -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.
*

View File

@@ -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);