diff --git a/spring-session/src/main/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfiguration.java b/spring-session/src/main/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfiguration.java index 1c612da0..14e8db90 100644 --- a/spring-session/src/main/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfiguration.java +++ b/spring-session/src/main/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfiguration.java @@ -26,6 +26,7 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.EmbeddedValueResolverAware; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.ImportAware; @@ -49,6 +50,7 @@ import org.springframework.session.data.redis.config.ConfigureRedisAction; import org.springframework.session.web.http.SessionRepositoryFilter; import org.springframework.util.Assert; import org.springframework.util.StringUtils; +import org.springframework.util.StringValueResolver; /** * Exposes the {@link SessionRepositoryFilter} as a bean named @@ -56,14 +58,14 @@ import org.springframework.util.StringUtils; * {@link RedisConnectionFactory} must be exposed as a Bean. * * @author Rob Winch - * @since 1.0 - * + * @author Eddú Meléndez * @see EnableRedisHttpSession + * @since 1.0 */ @Configuration @EnableScheduling public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguration - implements ImportAware { + implements EmbeddedValueResolverAware, ImportAware { private Integer maxInactiveIntervalInSeconds = 1800; @@ -79,6 +81,8 @@ public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguratio private Executor redisSubscriptionExecutor; + private StringValueResolver embeddedValueResolver; + @Bean public RedisMessageListenerContainer redisMessageListenerContainer( RedisConnectionFactory connectionFactory, @@ -162,7 +166,10 @@ public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguratio AnnotationAttributes enableAttrs = AnnotationAttributes.fromMap(enableAttrMap); this.maxInactiveIntervalInSeconds = enableAttrs .getNumber("maxInactiveIntervalInSeconds"); - this.redisNamespace = enableAttrs.getString("redisNamespace"); + String redisNamespaceValue = enableAttrs.getString("redisNamespace"); + if (StringUtils.hasText(redisNamespaceValue)) { + this.redisNamespace = this.embeddedValueResolver.resolveStringValue(redisNamespaceValue); + } this.redisFlushMode = enableAttrs.getEnum("redisFlushMode"); } @@ -177,7 +184,7 @@ public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguratio * Sets the action to perform for configuring Redis. * * @param configureRedisAction the configureRedis to set. The default is - * {@link ConfigureNotifyKeyspaceEventsAction}. + * {@link ConfigureNotifyKeyspaceEventsAction}. */ @Autowired(required = false) public void setConfigureRedisAction(ConfigureRedisAction configureRedisAction) { @@ -203,6 +210,10 @@ public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguratio this.redisSubscriptionExecutor = redisSubscriptionExecutor; } + public void setEmbeddedValueResolver(StringValueResolver resolver) { + this.embeddedValueResolver = resolver; + } + /** * Property placeholder to process the @Scheduled annotation. * @return the {@link PropertySourcesPlaceholderConfigurer} to use diff --git a/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationMockTests.java b/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationMockTests.java new file mode 100644 index 00000000..35038a92 --- /dev/null +++ b/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationMockTests.java @@ -0,0 +1,90 @@ +/* + * Copyright 2014-2016 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.redis.config.annotation.web.http; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import org.springframework.data.redis.connection.RedisConnection; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.session.data.redis.config.ConfigureRedisAction; +import org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration.EnableRedisKeyspaceNotificationsInitializer; + +import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.willThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; + +@RunWith(MockitoJUnitRunner.class) +public class RedisHttpSessionConfigurationMockTests { + @Mock + RedisConnectionFactory factory; + @Mock + RedisConnection connection; + + @Before + public void setup() { + given(this.factory.getConnection()).willReturn(this.connection); + } + + @Test + public void enableRedisKeyspaceNotificationsInitializerAfterPropertiesSetWhenNoOpThenNoInteractionWithConnectionFactory() + throws Exception { + EnableRedisKeyspaceNotificationsInitializer init = new EnableRedisKeyspaceNotificationsInitializer( + this.factory, ConfigureRedisAction.NO_OP); + + init.afterPropertiesSet(); + + verifyZeroInteractions(this.factory); + } + + @Test + public void enableRedisKeyspaceNotificationsInitializerAfterPropertiesSetWhenExceptionThenCloseConnection() + throws Exception { + ConfigureRedisAction action = mock(ConfigureRedisAction.class); + willThrow(new RuntimeException()).given(action).configure(this.connection); + + EnableRedisKeyspaceNotificationsInitializer init = new EnableRedisKeyspaceNotificationsInitializer( + this.factory, action); + + try { + init.afterPropertiesSet(); + failBecauseExceptionWasNotThrown(Throwable.class); + } + catch (Throwable success) { + } + + verify(this.connection).close(); + } + + @Test + public void enableRedisKeyspaceNotificationsInitializerAfterPropertiesSetWhenNoExceptionThenCloseConnection() + throws Exception { + ConfigureRedisAction action = mock(ConfigureRedisAction.class); + + EnableRedisKeyspaceNotificationsInitializer init = new EnableRedisKeyspaceNotificationsInitializer( + this.factory, action); + + init.afterPropertiesSet(); + + verify(this.connection).close(); + } +} diff --git a/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationTests.java b/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationTests.java index 7f7dc8a5..ba72159e 100644 --- a/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationTests.java +++ b/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationTests.java @@ -13,78 +13,97 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.session.data.redis.config.annotation.web.http; +import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.session.data.redis.config.ConfigureRedisAction; -import org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration.EnableRedisKeyspaceNotificationsInitializer; +import org.springframework.mock.env.MockEnvironment; +import org.springframework.test.util.ReflectionTestUtils; -import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.given; -import static org.mockito.BDDMockito.willThrow; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -@RunWith(MockitoJUnitRunner.class) +/** + * @author Eddú Meléndez + */ public class RedisHttpSessionConfigurationTests { - @Mock - RedisConnectionFactory factory; - @Mock - RedisConnection connection; + + private AnnotationConfigApplicationContext context; @Before - public void setup() { - given(this.factory.getConnection()).willReturn(this.connection); + public void before() { + this.context = new AnnotationConfigApplicationContext(); } - @Test - public void enableRedisKeyspaceNotificationsInitializerAfterPropertiesSetWhenNoOpThenNoInteractionWithConnectionFactory() - throws Exception { - EnableRedisKeyspaceNotificationsInitializer init = new EnableRedisKeyspaceNotificationsInitializer( - this.factory, ConfigureRedisAction.NO_OP); - - init.afterPropertiesSet(); - - verifyZeroInteractions(this.factory); - } - - @Test - public void enableRedisKeyspaceNotificationsInitializerAfterPropertiesSetWhenExceptionThenCloseConnection() - throws Exception { - ConfigureRedisAction action = mock(ConfigureRedisAction.class); - willThrow(new RuntimeException()).given(action).configure(this.connection); - - EnableRedisKeyspaceNotificationsInitializer init = new EnableRedisKeyspaceNotificationsInitializer( - this.factory, action); - - try { - init.afterPropertiesSet(); - failBecauseExceptionWasNotThrown(Throwable.class); + @After + public void after() { + if (this.context != null) { + this.context.close(); } - catch (Throwable success) { + } + + @Test + public void resolveValue() { + registerAndRefresh(RedisConfig.class, CustomRedisHttpSessionConfiguration.class); + RedisHttpSessionConfiguration configuration = this.context.getBean(RedisHttpSessionConfiguration.class); + assertThat(ReflectionTestUtils.getField(configuration, "redisNamespace")).isEqualTo("myRedisNamespace"); + } + + @Test + public void resolveValueByPlaceholder() { + this.context.setEnvironment(new MockEnvironment().withProperty("session.redis.namespace", "customRedisNamespace")); + registerAndRefresh(RedisConfig.class, PropertySourceConfiguration.class, CustomRedisHttpSessionConfiguration2.class); + RedisHttpSessionConfiguration configuration = this.context.getBean(RedisHttpSessionConfiguration.class); + assertThat(ReflectionTestUtils.getField(configuration, "redisNamespace")).isEqualTo("customRedisNamespace"); + } + + private void registerAndRefresh(Class... annotatedClasses) { + this.context.register(annotatedClasses); + this.context.refresh(); + } + + @Configuration + static class PropertySourceConfiguration { + + @Bean + public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { + return new PropertySourcesPlaceholderConfigurer(); } - verify(this.connection).close(); } - @Test - public void enableRedisKeyspaceNotificationsInitializerAfterPropertiesSetWhenNoExceptionThenCloseConnection() - throws Exception { - ConfigureRedisAction action = mock(ConfigureRedisAction.class); + @Configuration + static class RedisConfig { - EnableRedisKeyspaceNotificationsInitializer init = new EnableRedisKeyspaceNotificationsInitializer( - this.factory, action); + @Bean + public RedisConnectionFactory redisConnectionFactory() { + RedisConnectionFactory connectionFactory = mock(RedisConnectionFactory.class); + given(connectionFactory.getConnection()).willReturn(mock(RedisConnection.class)); + return connectionFactory; + } - init.afterPropertiesSet(); - - verify(this.connection).close(); } + + @Configuration + @EnableRedisHttpSession(redisNamespace = "myRedisNamespace") + static class CustomRedisHttpSessionConfiguration { + + } + + @Configuration + @EnableRedisHttpSession(redisNamespace = "${session.redis.namespace}") + static class CustomRedisHttpSessionConfiguration2 { + + } + }