Spaces to tabs and license cleanup
This commit is contained in:
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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;
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
@@ -19,7 +34,6 @@ import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
@@ -32,148 +46,145 @@ import org.springframework.session.events.SessionDestroyedEvent;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import redis.clients.jedis.Protocol;
|
||||
import redis.embedded.RedisServer;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
public class RedisOperationsSessionRepositoryITests<S extends Session> {
|
||||
private RedisServer redisServer;
|
||||
@Autowired
|
||||
private SessionRepository<S> repository;
|
||||
|
||||
@Autowired
|
||||
private SessionRepository<S> repository;
|
||||
@Autowired
|
||||
private SessionDestroyedEventRegistry registry;
|
||||
|
||||
@Autowired
|
||||
private SessionDestroyedEventRegistry registry;
|
||||
private final Object lock = new Object();
|
||||
|
||||
private final Object lock = new Object();
|
||||
@Before
|
||||
public void setup() {
|
||||
registry.setLock(lock);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
registry.setLock(lock);
|
||||
}
|
||||
@Test
|
||||
public void saves() throws InterruptedException {
|
||||
S toSave = repository.createSession();
|
||||
toSave.setAttribute("a", "b");
|
||||
Authentication toSaveToken = new UsernamePasswordAuthenticationToken("user","password", AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
SecurityContext toSaveContext = SecurityContextHolder.createEmptyContext();
|
||||
toSaveContext.setAuthentication(toSaveToken);
|
||||
toSave.setAttribute("SPRING_SECURITY_CONTEXT", toSaveContext);
|
||||
|
||||
@Test
|
||||
public void saves() throws InterruptedException {
|
||||
S toSave = repository.createSession();
|
||||
toSave.setAttribute("a", "b");
|
||||
Authentication toSaveToken = new UsernamePasswordAuthenticationToken("user","password", AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
SecurityContext toSaveContext = SecurityContextHolder.createEmptyContext();
|
||||
toSaveContext.setAuthentication(toSaveToken);
|
||||
toSave.setAttribute("SPRING_SECURITY_CONTEXT", toSaveContext);
|
||||
repository.save(toSave);
|
||||
|
||||
repository.save(toSave);
|
||||
Session session = repository.getSession(toSave.getId());
|
||||
|
||||
Session session = repository.getSession(toSave.getId());
|
||||
assertThat(session.getId()).isEqualTo(toSave.getId());
|
||||
assertThat(session.getAttributeNames()).isEqualTo(session.getAttributeNames());
|
||||
assertThat(session.getAttribute("a")).isEqualTo(toSave.getAttribute("a"));
|
||||
|
||||
assertThat(session.getId()).isEqualTo(toSave.getId());
|
||||
assertThat(session.getAttributeNames()).isEqualTo(session.getAttributeNames());
|
||||
assertThat(session.getAttribute("a")).isEqualTo(toSave.getAttribute("a"));
|
||||
repository.delete(toSave.getId());
|
||||
|
||||
repository.delete(toSave.getId());
|
||||
assertThat(repository.getSession(toSave.getId())).isNull();
|
||||
synchronized (lock) {
|
||||
lock.wait(3000);
|
||||
}
|
||||
assertThat(registry.receivedEvent()).isTrue();
|
||||
}
|
||||
|
||||
assertThat(repository.getSession(toSave.getId())).isNull();
|
||||
synchronized (lock) {
|
||||
lock.wait(3000);
|
||||
}
|
||||
assertThat(registry.receivedEvent()).isTrue();
|
||||
}
|
||||
@Test
|
||||
public void putAllOnSingleAttrDoesNotRemoveOld() {
|
||||
S toSave = repository.createSession();
|
||||
toSave.setAttribute("a", "b");
|
||||
|
||||
@Test
|
||||
public void putAllOnSingleAttrDoesNotRemoveOld() {
|
||||
S toSave = repository.createSession();
|
||||
toSave.setAttribute("a", "b");
|
||||
repository.save(toSave);
|
||||
toSave = repository.getSession(toSave.getId());
|
||||
|
||||
repository.save(toSave);
|
||||
toSave = repository.getSession(toSave.getId());
|
||||
toSave.setAttribute("1", "2");
|
||||
|
||||
toSave.setAttribute("1", "2");
|
||||
repository.save(toSave);
|
||||
toSave = repository.getSession(toSave.getId());
|
||||
|
||||
repository.save(toSave);
|
||||
toSave = repository.getSession(toSave.getId());
|
||||
Session session = repository.getSession(toSave.getId());
|
||||
assertThat(session.getAttributeNames().size()).isEqualTo(2);
|
||||
assertThat(session.getAttribute("a")).isEqualTo("b");
|
||||
assertThat(session.getAttribute("1")).isEqualTo("2");
|
||||
}
|
||||
|
||||
Session session = repository.getSession(toSave.getId());
|
||||
assertThat(session.getAttributeNames().size()).isEqualTo(2);
|
||||
assertThat(session.getAttribute("a")).isEqualTo("b");
|
||||
assertThat(session.getAttribute("1")).isEqualTo("2");
|
||||
}
|
||||
static class SessionDestroyedEventRegistry implements ApplicationListener<SessionDestroyedEvent> {
|
||||
private boolean receivedEvent;
|
||||
private Object lock;
|
||||
|
||||
static class SessionDestroyedEventRegistry implements ApplicationListener<SessionDestroyedEvent> {
|
||||
private boolean receivedEvent;
|
||||
private Object lock;
|
||||
public void onApplicationEvent(SessionDestroyedEvent event) {
|
||||
receivedEvent = true;
|
||||
synchronized (lock) {
|
||||
lock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
public void onApplicationEvent(SessionDestroyedEvent event) {
|
||||
receivedEvent = true;
|
||||
synchronized (lock) {
|
||||
lock.notifyAll();
|
||||
}
|
||||
}
|
||||
public boolean receivedEvent() {
|
||||
return receivedEvent;
|
||||
}
|
||||
|
||||
public boolean receivedEvent() {
|
||||
return receivedEvent;
|
||||
}
|
||||
public void setLock(Object lock) {
|
||||
this.lock = lock;
|
||||
}
|
||||
}
|
||||
|
||||
public void setLock(Object lock) {
|
||||
this.lock = lock;
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
@EnableRedisHttpSession
|
||||
static class Config {
|
||||
@Bean
|
||||
public JedisConnectionFactory connectionFactory() throws Exception {
|
||||
JedisConnectionFactory factory = new JedisConnectionFactory();
|
||||
factory.setPort(getPort());
|
||||
factory.setUsePool(false);
|
||||
return factory;
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableRedisHttpSession
|
||||
static class Config {
|
||||
@Bean
|
||||
public JedisConnectionFactory connectionFactory() throws Exception {
|
||||
JedisConnectionFactory factory = new JedisConnectionFactory();
|
||||
factory.setPort(getPort());
|
||||
factory.setUsePool(false);
|
||||
return factory;
|
||||
}
|
||||
@Bean
|
||||
public static RedisServerBean redisServer() {
|
||||
return new RedisServerBean();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public static RedisServerBean redisServer() {
|
||||
return new RedisServerBean();
|
||||
}
|
||||
@Bean
|
||||
public SessionDestroyedEventRegistry sessionDestroyedEventRegistry() {
|
||||
return new SessionDestroyedEventRegistry();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SessionDestroyedEventRegistry sessionDestroyedEventRegistry() {
|
||||
return new SessionDestroyedEventRegistry();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements BeanDefinitionRegistryPostProcessor to ensure this Bean
|
||||
* is initialized before any other Beans. Specifically, we want to ensure
|
||||
* that the Redis Server is started before RedisHttpSessionConfiguration
|
||||
* attempts to enable Keyspace notifications.
|
||||
*/
|
||||
static class RedisServerBean implements InitializingBean, DisposableBean, BeanDefinitionRegistryPostProcessor {
|
||||
private RedisServer redisServer;
|
||||
/**
|
||||
* Implements BeanDefinitionRegistryPostProcessor to ensure this Bean
|
||||
* is initialized before any other Beans. Specifically, we want to ensure
|
||||
* that the Redis Server is started before RedisHttpSessionConfiguration
|
||||
* attempts to enable Keyspace notifications.
|
||||
*/
|
||||
static class RedisServerBean implements InitializingBean, DisposableBean, BeanDefinitionRegistryPostProcessor {
|
||||
private RedisServer redisServer;
|
||||
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
redisServer = new RedisServer(getPort());
|
||||
redisServer.start();
|
||||
}
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
redisServer = new RedisServer(getPort());
|
||||
redisServer.start();
|
||||
}
|
||||
|
||||
public void destroy() throws Exception {
|
||||
if(redisServer != null) {
|
||||
redisServer.stop();
|
||||
}
|
||||
}
|
||||
public void destroy() throws Exception {
|
||||
if(redisServer != null) {
|
||||
redisServer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {}
|
||||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {}
|
||||
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}
|
||||
}
|
||||
}
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}
|
||||
}
|
||||
}
|
||||
|
||||
private static Integer availablePort;
|
||||
private static Integer availablePort;
|
||||
|
||||
private static int getPort() throws IOException {
|
||||
if(availablePort == null) {
|
||||
ServerSocket socket = new ServerSocket(0);
|
||||
availablePort = socket.getLocalPort();
|
||||
socket.close();
|
||||
}
|
||||
return availablePort;
|
||||
}
|
||||
private static int getPort() throws IOException {
|
||||
if(availablePort == null) {
|
||||
ServerSocket socket = new ServerSocket(0);
|
||||
availablePort = socket.getLocalPort();
|
||||
socket.close();
|
||||
}
|
||||
return availablePort;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 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
|
||||
@@ -35,145 +35,139 @@ import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.session.ExpiringSession;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.SessionRepository;
|
||||
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
|
||||
import org.springframework.session.events.SessionDestroyedEvent;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import redis.clients.jedis.Protocol;
|
||||
import redis.embedded.RedisServer;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
public class EnableRedisHttpSessionExpireSessionDestroyedTests<S extends ExpiringSession> {
|
||||
private RedisServer redisServer;
|
||||
@Autowired
|
||||
private SessionRepository<S> repository;
|
||||
|
||||
@Autowired
|
||||
private SessionRepository<S> repository;
|
||||
@Autowired
|
||||
private SessionDestroyedEventRegistry registry;
|
||||
|
||||
@Autowired
|
||||
private SessionDestroyedEventRegistry registry;
|
||||
private final Object lock = new Object();
|
||||
|
||||
private final Object lock = new Object();
|
||||
@Before
|
||||
public void setup() {
|
||||
registry.setLock(lock);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
registry.setLock(lock);
|
||||
}
|
||||
@Test
|
||||
public void expireFiresSessionDestroyedEvent() throws InterruptedException {
|
||||
S toSave = repository.createSession();
|
||||
toSave.setAttribute("a", "b");
|
||||
Authentication toSaveToken = new UsernamePasswordAuthenticationToken("user","password", AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
SecurityContext toSaveContext = SecurityContextHolder.createEmptyContext();
|
||||
toSaveContext.setAuthentication(toSaveToken);
|
||||
toSave.setAttribute("SPRING_SECURITY_CONTEXT", toSaveContext);
|
||||
|
||||
@Test
|
||||
public void expireFiresSessionDestroyedEvent() throws InterruptedException {
|
||||
S toSave = repository.createSession();
|
||||
toSave.setAttribute("a", "b");
|
||||
Authentication toSaveToken = new UsernamePasswordAuthenticationToken("user","password", AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
SecurityContext toSaveContext = SecurityContextHolder.createEmptyContext();
|
||||
toSaveContext.setAuthentication(toSaveToken);
|
||||
toSave.setAttribute("SPRING_SECURITY_CONTEXT", toSaveContext);
|
||||
repository.save(toSave);
|
||||
|
||||
repository.save(toSave);
|
||||
synchronized (lock) {
|
||||
lock.wait((toSave.getMaxInactiveIntervalInSeconds() * 1000) + 1);
|
||||
}
|
||||
if(!registry.receivedEvent()) {
|
||||
// Redis makes no guarantees on when an expired event will be fired
|
||||
// we can ensure it gets fired by trying to get the session
|
||||
repository.getSession(toSave.getId());
|
||||
synchronized (lock) {
|
||||
if(!registry.receivedEvent()) {
|
||||
// wait at most second to process the event
|
||||
lock.wait(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
assertThat(registry.receivedEvent()).isTrue();
|
||||
}
|
||||
|
||||
synchronized (lock) {
|
||||
lock.wait((toSave.getMaxInactiveIntervalInSeconds() * 1000) + 1);
|
||||
}
|
||||
if(!registry.receivedEvent()) {
|
||||
// Redis makes no guarantees on when an expired event will be fired
|
||||
// we can ensure it gets fired by trying to get the session
|
||||
repository.getSession(toSave.getId());
|
||||
synchronized (lock) {
|
||||
if(!registry.receivedEvent()) {
|
||||
// wait at most second to process the event
|
||||
lock.wait(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
assertThat(registry.receivedEvent()).isTrue();
|
||||
}
|
||||
static class SessionDestroyedEventRegistry implements ApplicationListener<SessionDestroyedEvent> {
|
||||
private boolean receivedEvent;
|
||||
private Object lock;
|
||||
|
||||
static class SessionDestroyedEventRegistry implements ApplicationListener<SessionDestroyedEvent> {
|
||||
private boolean receivedEvent;
|
||||
private Object lock;
|
||||
public void onApplicationEvent(SessionDestroyedEvent event) {
|
||||
synchronized (lock) {
|
||||
receivedEvent = true;
|
||||
lock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
public void onApplicationEvent(SessionDestroyedEvent event) {
|
||||
synchronized (lock) {
|
||||
receivedEvent = true;
|
||||
lock.notifyAll();
|
||||
}
|
||||
}
|
||||
public boolean receivedEvent() {
|
||||
return receivedEvent;
|
||||
}
|
||||
|
||||
public boolean receivedEvent() {
|
||||
return receivedEvent;
|
||||
}
|
||||
public void setLock(Object lock) {
|
||||
this.lock = lock;
|
||||
}
|
||||
}
|
||||
|
||||
public void setLock(Object lock) {
|
||||
this.lock = lock;
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1)
|
||||
static class Config {
|
||||
@Bean
|
||||
public JedisConnectionFactory connectionFactory() throws Exception {
|
||||
JedisConnectionFactory factory = new JedisConnectionFactory();
|
||||
factory.setPort(getPort());
|
||||
factory.setUsePool(false);
|
||||
return factory;
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1)
|
||||
static class Config {
|
||||
@Bean
|
||||
public JedisConnectionFactory connectionFactory() throws Exception {
|
||||
JedisConnectionFactory factory = new JedisConnectionFactory();
|
||||
factory.setPort(getPort());
|
||||
factory.setUsePool(false);
|
||||
return factory;
|
||||
}
|
||||
@Bean
|
||||
public static RedisServerBean redisServer() {
|
||||
return new RedisServerBean();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public static RedisServerBean redisServer() {
|
||||
return new RedisServerBean();
|
||||
}
|
||||
@Bean
|
||||
public SessionDestroyedEventRegistry sessionDestroyedEventRegistry() {
|
||||
return new SessionDestroyedEventRegistry();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SessionDestroyedEventRegistry sessionDestroyedEventRegistry() {
|
||||
return new SessionDestroyedEventRegistry();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements BeanDefinitionRegistryPostProcessor to ensure this Bean
|
||||
* is initialized before any other Beans. Specifically, we want to ensure
|
||||
* that the Redis Server is started before RedisHttpSessionConfiguration
|
||||
* attempts to enable Keyspace notifications.
|
||||
*/
|
||||
static class RedisServerBean implements InitializingBean, DisposableBean, BeanDefinitionRegistryPostProcessor {
|
||||
private RedisServer redisServer;
|
||||
/**
|
||||
* Implements BeanDefinitionRegistryPostProcessor to ensure this Bean
|
||||
* is initialized before any other Beans. Specifically, we want to ensure
|
||||
* that the Redis Server is started before RedisHttpSessionConfiguration
|
||||
* attempts to enable Keyspace notifications.
|
||||
*/
|
||||
static class RedisServerBean implements InitializingBean, DisposableBean, BeanDefinitionRegistryPostProcessor {
|
||||
private RedisServer redisServer;
|
||||
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
redisServer = new RedisServer(getPort());
|
||||
redisServer.start();
|
||||
}
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
redisServer = new RedisServer(getPort());
|
||||
redisServer.start();
|
||||
}
|
||||
|
||||
public void destroy() throws Exception {
|
||||
if(redisServer != null) {
|
||||
redisServer.stop();
|
||||
}
|
||||
}
|
||||
public void destroy() throws Exception {
|
||||
if(redisServer != null) {
|
||||
redisServer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {}
|
||||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {}
|
||||
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}
|
||||
}
|
||||
}
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}
|
||||
}
|
||||
}
|
||||
|
||||
private static Integer availablePort;
|
||||
private static Integer availablePort;
|
||||
|
||||
private static int getPort() throws IOException {
|
||||
if(availablePort == null) {
|
||||
ServerSocket socket = new ServerSocket(0);
|
||||
availablePort = socket.getLocalPort();
|
||||
socket.close();
|
||||
}
|
||||
return availablePort;
|
||||
}
|
||||
private static int getPort() throws IOException {
|
||||
if(availablePort == null) {
|
||||
ServerSocket socket = new ServerSocket(0);
|
||||
availablePort = socket.getLocalPort();
|
||||
socket.close();
|
||||
}
|
||||
return availablePort;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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;
|
||||
|
||||
/**
|
||||
@@ -8,39 +23,39 @@ package org.springframework.session;
|
||||
*/
|
||||
public interface ExpiringSession extends Session {
|
||||
|
||||
/**
|
||||
* Gets the time when this session was created in milliseconds since midnight of 1/1/1970 GMT.
|
||||
*
|
||||
* @return the time when this session was created in milliseconds since midnight of 1/1/1970 GMT.
|
||||
*/
|
||||
long getCreationTime();
|
||||
/**
|
||||
* Gets the time when this session was created in milliseconds since midnight of 1/1/1970 GMT.
|
||||
*
|
||||
* @return the time when this session was created in milliseconds since midnight of 1/1/1970 GMT.
|
||||
*/
|
||||
long getCreationTime();
|
||||
|
||||
/**
|
||||
* Gets the last time this {@link Session} was accessed expressed in milliseconds since midnight of 1/1/1970 GMT
|
||||
*
|
||||
* @return the last time the client sent a request associated with the session expressed in milliseconds since midnight of 1/1/1970 GMT
|
||||
*/
|
||||
long getLastAccessedTime();
|
||||
/**
|
||||
* Gets the last time this {@link Session} was accessed expressed in milliseconds since midnight of 1/1/1970 GMT
|
||||
*
|
||||
* @return the last time the client sent a request associated with the session expressed in milliseconds since midnight of 1/1/1970 GMT
|
||||
*/
|
||||
long getLastAccessedTime();
|
||||
|
||||
/**
|
||||
* Sets the maximum inactive interval in seconds between requests before this session will be invalidated. A negative time indicates that the session will never timeout.
|
||||
*
|
||||
* @param interval the number of seconds that the {@link Session} should be kept alive between client requests.
|
||||
*/
|
||||
void setMaxInactiveIntervalInSeconds(int interval);
|
||||
/**
|
||||
* Sets the maximum inactive interval in seconds between requests before this session will be invalidated. A negative time indicates that the session will never timeout.
|
||||
*
|
||||
* @param interval the number of seconds that the {@link Session} should be kept alive between client requests.
|
||||
*/
|
||||
void setMaxInactiveIntervalInSeconds(int interval);
|
||||
|
||||
/**
|
||||
* Gets the maximum inactive interval in seconds between requests before this session will be invalidated. A negative time indicates that the session will never timeout.
|
||||
*
|
||||
* @return the maximum inactive interval in seconds between requests before this session will be invalidated. A negative time indicates that the session will never timeout.
|
||||
*/
|
||||
int getMaxInactiveIntervalInSeconds();
|
||||
/**
|
||||
* Gets the maximum inactive interval in seconds between requests before this session will be invalidated. A negative time indicates that the session will never timeout.
|
||||
*
|
||||
* @return the maximum inactive interval in seconds between requests before this session will be invalidated. A negative time indicates that the session will never timeout.
|
||||
*/
|
||||
int getMaxInactiveIntervalInSeconds();
|
||||
|
||||
/**
|
||||
* Returns true if the session is expired.
|
||||
*
|
||||
* @return true if the session is expired, else false.
|
||||
*/
|
||||
boolean isExpired();
|
||||
/**
|
||||
* Returns true if the session is expired.
|
||||
*
|
||||
* @return true if the session is expired, else false.
|
||||
*/
|
||||
boolean isExpired();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 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
|
||||
@@ -41,126 +41,126 @@ import java.util.concurrent.TimeUnit;
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public final class MapSession implements ExpiringSession, Serializable {
|
||||
/**
|
||||
* Default {@link #setMaxInactiveIntervalInSeconds(int)} (30 minutes)
|
||||
*/
|
||||
public static final int DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS = 1800;
|
||||
/**
|
||||
* Default {@link #setMaxInactiveIntervalInSeconds(int)} (30 minutes)
|
||||
*/
|
||||
public static final int DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS = 1800;
|
||||
|
||||
private String id = UUID.randomUUID().toString();
|
||||
private Map<String, Object> sessionAttrs = new HashMap<String, Object>();
|
||||
private long creationTime = System.currentTimeMillis();
|
||||
private long lastAccessedTime = creationTime;
|
||||
private String id = UUID.randomUUID().toString();
|
||||
private Map<String, Object> sessionAttrs = new HashMap<String, Object>();
|
||||
private long creationTime = System.currentTimeMillis();
|
||||
private long lastAccessedTime = creationTime;
|
||||
|
||||
/**
|
||||
* Defaults to 30 minutes
|
||||
*/
|
||||
private int maxInactiveInterval = DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS;
|
||||
/**
|
||||
* Defaults to 30 minutes
|
||||
*/
|
||||
private int maxInactiveInterval = DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*/
|
||||
public MapSession() {
|
||||
}
|
||||
/**
|
||||
* Creates a new instance
|
||||
*/
|
||||
public MapSession() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance from the provided {@link Session}
|
||||
*
|
||||
* @param session the {@link Session} to initialize this {@link Session} with. Cannot be null.
|
||||
*/
|
||||
public MapSession(ExpiringSession session) {
|
||||
if(session == null) {
|
||||
throw new IllegalArgumentException("session cannot be null");
|
||||
}
|
||||
this.id = session.getId();
|
||||
this.sessionAttrs = new HashMap<String, Object>(session.getAttributeNames().size());
|
||||
for (String attrName : session.getAttributeNames()) {
|
||||
Object attrValue = session.getAttribute(attrName);
|
||||
this.sessionAttrs.put(attrName, attrValue);
|
||||
}
|
||||
this.lastAccessedTime = session.getLastAccessedTime();
|
||||
this.creationTime = session.getCreationTime();
|
||||
this.maxInactiveInterval = session.getMaxInactiveIntervalInSeconds();
|
||||
}
|
||||
/**
|
||||
* Creates a new instance from the provided {@link Session}
|
||||
*
|
||||
* @param session the {@link Session} to initialize this {@link Session} with. Cannot be null.
|
||||
*/
|
||||
public MapSession(ExpiringSession session) {
|
||||
if(session == null) {
|
||||
throw new IllegalArgumentException("session cannot be null");
|
||||
}
|
||||
this.id = session.getId();
|
||||
this.sessionAttrs = new HashMap<String, Object>(session.getAttributeNames().size());
|
||||
for (String attrName : session.getAttributeNames()) {
|
||||
Object attrValue = session.getAttribute(attrName);
|
||||
this.sessionAttrs.put(attrName, attrValue);
|
||||
}
|
||||
this.lastAccessedTime = session.getLastAccessedTime();
|
||||
this.creationTime = session.getCreationTime();
|
||||
this.maxInactiveInterval = session.getMaxInactiveIntervalInSeconds();
|
||||
}
|
||||
|
||||
public void setLastAccessedTime(long lastAccessedTime) {
|
||||
this.lastAccessedTime = lastAccessedTime;
|
||||
}
|
||||
public void setLastAccessedTime(long lastAccessedTime) {
|
||||
this.lastAccessedTime = lastAccessedTime;
|
||||
}
|
||||
|
||||
public long getCreationTime() {
|
||||
return creationTime;
|
||||
}
|
||||
public long getCreationTime() {
|
||||
return creationTime;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public long getLastAccessedTime() {
|
||||
return lastAccessedTime;
|
||||
}
|
||||
public long getLastAccessedTime() {
|
||||
return lastAccessedTime;
|
||||
}
|
||||
|
||||
public void setMaxInactiveIntervalInSeconds(int interval) {
|
||||
this.maxInactiveInterval = interval;
|
||||
}
|
||||
public void setMaxInactiveIntervalInSeconds(int interval) {
|
||||
this.maxInactiveInterval = interval;
|
||||
}
|
||||
|
||||
public int getMaxInactiveIntervalInSeconds() {
|
||||
return maxInactiveInterval;
|
||||
}
|
||||
public int getMaxInactiveIntervalInSeconds() {
|
||||
return maxInactiveInterval;
|
||||
}
|
||||
|
||||
public boolean isExpired() {
|
||||
return isExpired(System.currentTimeMillis());
|
||||
}
|
||||
public boolean isExpired() {
|
||||
return isExpired(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
boolean isExpired(long now) {
|
||||
if(maxInactiveInterval < 0) {
|
||||
return false;
|
||||
}
|
||||
return now - TimeUnit.SECONDS.toMillis(maxInactiveInterval) >= lastAccessedTime;
|
||||
}
|
||||
boolean isExpired(long now) {
|
||||
if(maxInactiveInterval < 0) {
|
||||
return false;
|
||||
}
|
||||
return now - TimeUnit.SECONDS.toMillis(maxInactiveInterval) >= lastAccessedTime;
|
||||
}
|
||||
|
||||
public Object getAttribute(String attributeName) {
|
||||
return sessionAttrs.get(attributeName);
|
||||
}
|
||||
public Object getAttribute(String attributeName) {
|
||||
return sessionAttrs.get(attributeName);
|
||||
}
|
||||
|
||||
public Set<String> getAttributeNames() {
|
||||
return sessionAttrs.keySet();
|
||||
}
|
||||
public Set<String> getAttributeNames() {
|
||||
return sessionAttrs.keySet();
|
||||
}
|
||||
|
||||
public void setAttribute(String attributeName, Object attributeValue) {
|
||||
if (attributeValue == null) {
|
||||
removeAttribute(attributeName);
|
||||
} else {
|
||||
sessionAttrs.put(attributeName, attributeValue);
|
||||
}
|
||||
}
|
||||
public void setAttribute(String attributeName, Object attributeValue) {
|
||||
if (attributeValue == null) {
|
||||
removeAttribute(attributeName);
|
||||
} else {
|
||||
sessionAttrs.put(attributeName, attributeValue);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAttribute(String attributeName) {
|
||||
sessionAttrs.remove(attributeName);
|
||||
}
|
||||
public void removeAttribute(String attributeName) {
|
||||
sessionAttrs.remove(attributeName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time that this {@link Session} was created in milliseconds since midnight of 1/1/1970 GMT. The default is when the {@link Session} was instantiated.
|
||||
* @param creationTime the time that this {@link Session} was created in milliseconds since midnight of 1/1/1970 GMT.
|
||||
*/
|
||||
public void setCreationTime(long creationTime) {
|
||||
this.creationTime = creationTime;
|
||||
}
|
||||
/**
|
||||
* Sets the time that this {@link Session} was created in milliseconds since midnight of 1/1/1970 GMT. The default is when the {@link Session} was instantiated.
|
||||
* @param creationTime the time that this {@link Session} was created in milliseconds since midnight of 1/1/1970 GMT.
|
||||
*/
|
||||
public void setCreationTime(long creationTime) {
|
||||
this.creationTime = creationTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the identifier for this {@link Session}. The id should be a secure random generated value to prevent malicious users from guessing this value. The default is a secure random generated identifier.
|
||||
*
|
||||
* @param id the identifier for this session.
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
/**
|
||||
* Sets the identifier for this {@link Session}. The id should be a secure random generated value to prevent malicious users from guessing this value. The default is a secure random generated identifier.
|
||||
*
|
||||
* @param id the identifier for this session.
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof Session && id.equals(((Session) obj).getId());
|
||||
}
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof Session && id.equals(((Session) obj).getId());
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return id.hashCode();
|
||||
}
|
||||
public int hashCode() {
|
||||
return id.hashCode();
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 7160779239673823561L;
|
||||
private static final long serialVersionUID = 7160779239673823561L;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 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
|
||||
@@ -33,67 +33,67 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
* @since 1.0
|
||||
*/
|
||||
public class MapSessionRepository implements SessionRepository<ExpiringSession> {
|
||||
/**
|
||||
* If non-null, this value is used to override {@link ExpiringSession#setMaxInactiveIntervalInSeconds(int)}.
|
||||
*/
|
||||
private Integer defaultMaxInactiveInterval;
|
||||
/**
|
||||
* If non-null, this value is used to override {@link ExpiringSession#setMaxInactiveIntervalInSeconds(int)}.
|
||||
*/
|
||||
private Integer defaultMaxInactiveInterval;
|
||||
|
||||
private final Map<String,ExpiringSession> sessions;
|
||||
private final Map<String,ExpiringSession> sessions;
|
||||
|
||||
/**
|
||||
* Creates an instance backed by a {@link java.util.concurrent.ConcurrentHashMap}
|
||||
*/
|
||||
public MapSessionRepository() {
|
||||
this(new ConcurrentHashMap<String, ExpiringSession>());
|
||||
}
|
||||
/**
|
||||
* Creates an instance backed by a {@link java.util.concurrent.ConcurrentHashMap}
|
||||
*/
|
||||
public MapSessionRepository() {
|
||||
this(new ConcurrentHashMap<String, ExpiringSession>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance backed by the provided {@link java.util.Map}. This allows injecting a distributed {@link java.util.Map}.
|
||||
*
|
||||
* @param sessions the {@link java.util.Map} to use. Cannot be null.
|
||||
*/
|
||||
public MapSessionRepository(Map<String,ExpiringSession> sessions) {
|
||||
if(sessions == null) {
|
||||
throw new IllegalArgumentException("sessions cannot be null");
|
||||
}
|
||||
this.sessions = sessions;
|
||||
}
|
||||
/**
|
||||
* Creates a new instance backed by the provided {@link java.util.Map}. This allows injecting a distributed {@link java.util.Map}.
|
||||
*
|
||||
* @param sessions the {@link java.util.Map} to use. Cannot be null.
|
||||
*/
|
||||
public MapSessionRepository(Map<String,ExpiringSession> sessions) {
|
||||
if(sessions == null) {
|
||||
throw new IllegalArgumentException("sessions cannot be null");
|
||||
}
|
||||
this.sessions = sessions;
|
||||
}
|
||||
|
||||
/**
|
||||
* If non-null, this value is used to override {@link ExpiringSession#setMaxInactiveIntervalInSeconds(int)}.
|
||||
* @param defaultMaxInactiveInterval the number of seconds that the {@link Session} should be kept alive between client requests.
|
||||
*/
|
||||
public void setDefaultMaxInactiveInterval(int defaultMaxInactiveInterval) {
|
||||
this.defaultMaxInactiveInterval = Integer.valueOf(defaultMaxInactiveInterval);
|
||||
}
|
||||
/**
|
||||
* If non-null, this value is used to override {@link ExpiringSession#setMaxInactiveIntervalInSeconds(int)}.
|
||||
* @param defaultMaxInactiveInterval the number of seconds that the {@link Session} should be kept alive between client requests.
|
||||
*/
|
||||
public void setDefaultMaxInactiveInterval(int defaultMaxInactiveInterval) {
|
||||
this.defaultMaxInactiveInterval = Integer.valueOf(defaultMaxInactiveInterval);
|
||||
}
|
||||
|
||||
public void save(ExpiringSession session) {
|
||||
sessions.put(session.getId(), new MapSession(session));
|
||||
}
|
||||
public void save(ExpiringSession session) {
|
||||
sessions.put(session.getId(), new MapSession(session));
|
||||
}
|
||||
|
||||
public ExpiringSession getSession(String id) {
|
||||
ExpiringSession saved = sessions.get(id);
|
||||
if(saved == null) {
|
||||
return null;
|
||||
}
|
||||
if(saved.isExpired()) {
|
||||
delete(saved.getId());
|
||||
return null;
|
||||
}
|
||||
MapSession result = new MapSession(saved);
|
||||
result.setLastAccessedTime(System.currentTimeMillis());
|
||||
return result;
|
||||
}
|
||||
public ExpiringSession getSession(String id) {
|
||||
ExpiringSession saved = sessions.get(id);
|
||||
if(saved == null) {
|
||||
return null;
|
||||
}
|
||||
if(saved.isExpired()) {
|
||||
delete(saved.getId());
|
||||
return null;
|
||||
}
|
||||
MapSession result = new MapSession(saved);
|
||||
result.setLastAccessedTime(System.currentTimeMillis());
|
||||
return result;
|
||||
}
|
||||
|
||||
public void delete(String id) {
|
||||
sessions.remove(id);
|
||||
}
|
||||
public void delete(String id) {
|
||||
sessions.remove(id);
|
||||
}
|
||||
|
||||
public ExpiringSession createSession() {
|
||||
ExpiringSession result = new MapSession();
|
||||
if(defaultMaxInactiveInterval != null) {
|
||||
result.setMaxInactiveIntervalInSeconds(defaultMaxInactiveInterval);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public ExpiringSession createSession() {
|
||||
ExpiringSession result = new MapSession();
|
||||
if(defaultMaxInactiveInterval != null) {
|
||||
result.setMaxInactiveIntervalInSeconds(defaultMaxInactiveInterval);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 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
|
||||
@@ -26,41 +26,41 @@ import java.util.Set;
|
||||
*/
|
||||
public interface Session {
|
||||
|
||||
/**
|
||||
* Gets a unique string that identifies the {@link Session}
|
||||
*
|
||||
* @return a unique string that identifies the {@link Session}
|
||||
*/
|
||||
String getId();
|
||||
/**
|
||||
* Gets a unique string that identifies the {@link Session}
|
||||
*
|
||||
* @return a unique string that identifies the {@link Session}
|
||||
*/
|
||||
String getId();
|
||||
|
||||
/**
|
||||
* Gets the Object associated with the specified name or null if no Object is associated to that name.
|
||||
*
|
||||
* @param attributeName the name of the attribute to get
|
||||
* @return the Object associated with the specified name or null if no Object is associated to that name
|
||||
* @param <T> The return type of the attribute
|
||||
*/
|
||||
<T> T getAttribute(String attributeName);
|
||||
/**
|
||||
* Gets the Object associated with the specified name or null if no Object is associated to that name.
|
||||
*
|
||||
* @param attributeName the name of the attribute to get
|
||||
* @return the Object associated with the specified name or null if no Object is associated to that name
|
||||
* @param <T> The return type of the attribute
|
||||
*/
|
||||
<T> T getAttribute(String attributeName);
|
||||
|
||||
/**
|
||||
* Gets the attribute names that have a value associated with it. Each value can be passed into {@link org.springframework.session.Session#getAttribute(String)} to obtain the attribute value.
|
||||
*
|
||||
* @return the attribute names that have a value associated with it.
|
||||
* @see #getAttribute(String)
|
||||
*/
|
||||
Set<String> getAttributeNames();
|
||||
/**
|
||||
* Gets the attribute names that have a value associated with it. Each value can be passed into {@link org.springframework.session.Session#getAttribute(String)} to obtain the attribute value.
|
||||
*
|
||||
* @return the attribute names that have a value associated with it.
|
||||
* @see #getAttribute(String)
|
||||
*/
|
||||
Set<String> getAttributeNames();
|
||||
|
||||
/**
|
||||
* Sets the attribute value for the provided attribute name. If the attributeValue is null, it has the same result as removing the attribute with {@link org.springframework.session.Session#removeAttribute(String)} .
|
||||
*
|
||||
* @param attributeName the attribute name to set
|
||||
* @param attributeValue the value of the attribute to set. If null, the attribute will be removed.
|
||||
*/
|
||||
void setAttribute(String attributeName, Object attributeValue);
|
||||
/**
|
||||
* Sets the attribute value for the provided attribute name. If the attributeValue is null, it has the same result as removing the attribute with {@link org.springframework.session.Session#removeAttribute(String)} .
|
||||
*
|
||||
* @param attributeName the attribute name to set
|
||||
* @param attributeValue the value of the attribute to set. If null, the attribute will be removed.
|
||||
*/
|
||||
void setAttribute(String attributeName, Object attributeValue);
|
||||
|
||||
/**
|
||||
* Removes the attribute with the provided attribute name
|
||||
* @param attributeName the name of the attribute to remove
|
||||
*/
|
||||
void removeAttribute(String attributeName);
|
||||
/**
|
||||
* Removes the attribute with the provided attribute name
|
||||
* @param attributeName the name of the attribute to remove
|
||||
*/
|
||||
void removeAttribute(String attributeName);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 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
|
||||
@@ -23,46 +23,46 @@ package org.springframework.session;
|
||||
*/
|
||||
public interface SessionRepository<S extends Session> {
|
||||
|
||||
/**
|
||||
* Creates a new {@link Session} that is capable of being persisted by this {@link SessionRepository}.
|
||||
*
|
||||
* <p>This allows optimizations and customizations in how the {@link Session} is persisted. For example, the
|
||||
* implementation returned might keep track of the changes ensuring that only the delta needs to be persisted on
|
||||
* a save.</p>
|
||||
*
|
||||
* @return a new {@link Session} that is capable of being persisted by this {@link SessionRepository}
|
||||
*/
|
||||
S createSession();
|
||||
/**
|
||||
* Creates a new {@link Session} that is capable of being persisted by this {@link SessionRepository}.
|
||||
*
|
||||
* <p>This allows optimizations and customizations in how the {@link Session} is persisted. For example, the
|
||||
* implementation returned might keep track of the changes ensuring that only the delta needs to be persisted on
|
||||
* a save.</p>
|
||||
*
|
||||
* @return a new {@link Session} that is capable of being persisted by this {@link SessionRepository}
|
||||
*/
|
||||
S createSession();
|
||||
|
||||
/**
|
||||
* Ensures the {@link Session} created by {@link org.springframework.session.SessionRepository#createSession()} is saved.
|
||||
*
|
||||
* <p>
|
||||
* Some implementations may choose to save as the {@link Session} is updated by returning a {@link Session} that
|
||||
* immediately persists any changes. In this case, this method may not actually do anything.
|
||||
* </p>
|
||||
*
|
||||
* @param session the {@link Session} to save
|
||||
*/
|
||||
void save(S session);
|
||||
/**
|
||||
* Ensures the {@link Session} created by {@link org.springframework.session.SessionRepository#createSession()} is saved.
|
||||
*
|
||||
* <p>
|
||||
* Some implementations may choose to save as the {@link Session} is updated by returning a {@link Session} that
|
||||
* immediately persists any changes. In this case, this method may not actually do anything.
|
||||
* </p>
|
||||
*
|
||||
* @param session the {@link Session} to save
|
||||
*/
|
||||
void save(S session);
|
||||
|
||||
/**
|
||||
* Gets the {@link Session} by the {@link Session#getId()} or null if no {@link Session} is found.
|
||||
*
|
||||
* <p>
|
||||
* If the {@link Session} extends {@link ExpiringSession}, then {@link ExpiringSession#getLastAccessedTime()} will be
|
||||
* updated on the returned object. In order to persist this change, {@link #save(Session)} must be invoked on the returned
|
||||
* instance.
|
||||
* </p>
|
||||
*
|
||||
* @param id the {@link org.springframework.session.Session#getId()} to lookup
|
||||
* @return the {@link Session} by the {@link Session#getId()} or null if no {@link Session} is found.
|
||||
*/
|
||||
S getSession(String id);
|
||||
/**
|
||||
* Gets the {@link Session} by the {@link Session#getId()} or null if no {@link Session} is found.
|
||||
*
|
||||
* <p>
|
||||
* If the {@link Session} extends {@link ExpiringSession}, then {@link ExpiringSession#getLastAccessedTime()} will be
|
||||
* updated on the returned object. In order to persist this change, {@link #save(Session)} must be invoked on the returned
|
||||
* instance.
|
||||
* </p>
|
||||
*
|
||||
* @param id the {@link org.springframework.session.Session#getId()} to lookup
|
||||
* @return the {@link Session} by the {@link Session#getId()} or null if no {@link Session} is found.
|
||||
*/
|
||||
S getSession(String id);
|
||||
|
||||
/**
|
||||
* Deletes the {@link Session} with the given {@link Session#getId()} or does nothing if the {@link Session} is not found.
|
||||
* @param id the {@link org.springframework.session.Session#getId()} to delete
|
||||
*/
|
||||
void delete(String id);
|
||||
/**
|
||||
* Deletes the {@link Session} with the given {@link Session#getId()} or does nothing if the {@link Session} is not found.
|
||||
* @param id the {@link org.springframework.session.Session#getId()} to delete
|
||||
*/
|
||||
void delete(String id);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 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
|
||||
@@ -139,277 +139,277 @@ import org.springframework.util.Assert;
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class RedisOperationsSessionRepository implements SessionRepository<RedisOperationsSessionRepository.RedisSession> {
|
||||
/**
|
||||
* The prefix for each key of the Redis Hash representing a single session. The suffix is the unique session id.
|
||||
*/
|
||||
static final String BOUNDED_HASH_KEY_PREFIX = "spring:session:sessions:";
|
||||
/**
|
||||
* The prefix for each key of the Redis Hash representing a single session. The suffix is the unique session id.
|
||||
*/
|
||||
static final String BOUNDED_HASH_KEY_PREFIX = "spring:session:sessions:";
|
||||
|
||||
/**
|
||||
* The key in the Hash representing {@link org.springframework.session.ExpiringSession#getCreationTime()}
|
||||
*/
|
||||
static final String CREATION_TIME_ATTR = "creationTime";
|
||||
/**
|
||||
* The key in the Hash representing {@link org.springframework.session.ExpiringSession#getCreationTime()}
|
||||
*/
|
||||
static final String CREATION_TIME_ATTR = "creationTime";
|
||||
|
||||
/**
|
||||
* The key in the Hash representing {@link org.springframework.session.ExpiringSession#getMaxInactiveIntervalInSeconds()}
|
||||
*/
|
||||
static final String MAX_INACTIVE_ATTR = "maxInactiveInterval";
|
||||
/**
|
||||
* The key in the Hash representing {@link org.springframework.session.ExpiringSession#getMaxInactiveIntervalInSeconds()}
|
||||
*/
|
||||
static final String MAX_INACTIVE_ATTR = "maxInactiveInterval";
|
||||
|
||||
/**
|
||||
* The key in the Hash representing {@link org.springframework.session.ExpiringSession#getLastAccessedTime()}
|
||||
*/
|
||||
static final String LAST_ACCESSED_ATTR = "lastAccessedTime";
|
||||
/**
|
||||
* The key in the Hash representing {@link org.springframework.session.ExpiringSession#getLastAccessedTime()}
|
||||
*/
|
||||
static final String LAST_ACCESSED_ATTR = "lastAccessedTime";
|
||||
|
||||
/**
|
||||
* The prefix of the key for used for session attributes. The suffix is the name of the session attribute. For
|
||||
* example, if the session contained an attribute named attributeName, then there would be an entry in the hash named
|
||||
* sessionAttr:attributeName that mapped to its value.
|
||||
*/
|
||||
static final String SESSION_ATTR_PREFIX = "sessionAttr:";
|
||||
/**
|
||||
* The prefix of the key for used for session attributes. The suffix is the name of the session attribute. For
|
||||
* example, if the session contained an attribute named attributeName, then there would be an entry in the hash named
|
||||
* sessionAttr:attributeName that mapped to its value.
|
||||
*/
|
||||
static final String SESSION_ATTR_PREFIX = "sessionAttr:";
|
||||
|
||||
private final RedisOperations<String,ExpiringSession> sessionRedisOperations;
|
||||
private final RedisOperations<String,ExpiringSession> sessionRedisOperations;
|
||||
|
||||
private final RedisSessionExpirationPolicy expirationPolicy;
|
||||
private final RedisSessionExpirationPolicy expirationPolicy;
|
||||
|
||||
/**
|
||||
* If non-null, this value is used to override the default value for {@link RedisSession#setMaxInactiveIntervalInSeconds(int)}.
|
||||
*/
|
||||
private Integer defaultMaxInactiveInterval;
|
||||
/**
|
||||
* If non-null, this value is used to override the default value for {@link RedisSession#setMaxInactiveIntervalInSeconds(int)}.
|
||||
*/
|
||||
private Integer defaultMaxInactiveInterval;
|
||||
|
||||
/**
|
||||
* Allows creating an instance and uses a default {@link RedisOperations} for both managing the session and the expirations.
|
||||
*
|
||||
* @param redisConnectionFactory the {@link RedisConnectionFactory} to use.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public RedisOperationsSessionRepository(RedisConnectionFactory redisConnectionFactory) {
|
||||
this(createDefaultTemplate(redisConnectionFactory));
|
||||
}
|
||||
/**
|
||||
* Allows creating an instance and uses a default {@link RedisOperations} for both managing the session and the expirations.
|
||||
*
|
||||
* @param redisConnectionFactory the {@link RedisConnectionFactory} to use.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public RedisOperationsSessionRepository(RedisConnectionFactory redisConnectionFactory) {
|
||||
this(createDefaultTemplate(redisConnectionFactory));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance. For an example, refer to the class level javadoc.
|
||||
*
|
||||
* @param sessionRedisOperations The {@link RedisOperations} to use for managing the sessions. Cannot be null.
|
||||
*/
|
||||
public RedisOperationsSessionRepository(RedisOperations<String, ExpiringSession> sessionRedisOperations) {
|
||||
Assert.notNull(sessionRedisOperations, "sessionRedisOperations cannot be null");
|
||||
this.sessionRedisOperations = sessionRedisOperations;
|
||||
this.expirationPolicy = new RedisSessionExpirationPolicy(sessionRedisOperations);
|
||||
}
|
||||
/**
|
||||
* Creates a new instance. For an example, refer to the class level javadoc.
|
||||
*
|
||||
* @param sessionRedisOperations The {@link RedisOperations} to use for managing the sessions. Cannot be null.
|
||||
*/
|
||||
public RedisOperationsSessionRepository(RedisOperations<String, ExpiringSession> sessionRedisOperations) {
|
||||
Assert.notNull(sessionRedisOperations, "sessionRedisOperations cannot be null");
|
||||
this.sessionRedisOperations = sessionRedisOperations;
|
||||
this.expirationPolicy = new RedisSessionExpirationPolicy(sessionRedisOperations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum inactive interval in seconds between requests before newly created sessions will be
|
||||
* invalidated. A negative time indicates that the session will never timeout. The default is 1800 (30 minutes).
|
||||
*
|
||||
* @param defaultMaxInactiveInterval the number of seconds that the {@link Session} should be kept alive between
|
||||
* client requests.
|
||||
*/
|
||||
public void setDefaultMaxInactiveInterval(int defaultMaxInactiveInterval) {
|
||||
this.defaultMaxInactiveInterval = defaultMaxInactiveInterval;
|
||||
}
|
||||
/**
|
||||
* Sets the maximum inactive interval in seconds between requests before newly created sessions will be
|
||||
* invalidated. A negative time indicates that the session will never timeout. The default is 1800 (30 minutes).
|
||||
*
|
||||
* @param defaultMaxInactiveInterval the number of seconds that the {@link Session} should be kept alive between
|
||||
* client requests.
|
||||
*/
|
||||
public void setDefaultMaxInactiveInterval(int defaultMaxInactiveInterval) {
|
||||
this.defaultMaxInactiveInterval = defaultMaxInactiveInterval;
|
||||
}
|
||||
|
||||
public void save(RedisSession session) {
|
||||
session.saveDelta();
|
||||
}
|
||||
public void save(RedisSession session) {
|
||||
session.saveDelta();
|
||||
}
|
||||
|
||||
@Scheduled(cron="0 * * * * *")
|
||||
public void cleanupExpiredSessions() {
|
||||
this.expirationPolicy.cleanExpiredSessions();
|
||||
}
|
||||
@Scheduled(cron="0 * * * * *")
|
||||
public void cleanupExpiredSessions() {
|
||||
this.expirationPolicy.cleanExpiredSessions();
|
||||
}
|
||||
|
||||
public RedisSession getSession(String id) {
|
||||
return getSession(id, false);
|
||||
}
|
||||
public RedisSession getSession(String id) {
|
||||
return getSession(id, false);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param id the session id
|
||||
* @param allowExpired
|
||||
* if true, will also include expired sessions that have not been
|
||||
* deleted. If false, will ensure expired sessions are not
|
||||
* returned.
|
||||
* @return
|
||||
*/
|
||||
private RedisSession getSession(String id, boolean allowExpired) {
|
||||
Map<Object, Object> entries = getSessionBoundHashOperations(id).entries();
|
||||
if(entries.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
MapSession loaded = new MapSession();
|
||||
loaded.setId(id);
|
||||
for(Map.Entry<Object,Object> entry : entries.entrySet()) {
|
||||
String key = (String) entry.getKey();
|
||||
if(CREATION_TIME_ATTR.equals(key)) {
|
||||
loaded.setCreationTime((Long) entry.getValue());
|
||||
} else if(MAX_INACTIVE_ATTR.equals(key)) {
|
||||
loaded.setMaxInactiveIntervalInSeconds((Integer) entry.getValue());
|
||||
} else if(LAST_ACCESSED_ATTR.equals(key)) {
|
||||
loaded.setLastAccessedTime((Long) entry.getValue());
|
||||
} else if(key.startsWith(SESSION_ATTR_PREFIX)) {
|
||||
loaded.setAttribute(key.substring(SESSION_ATTR_PREFIX.length()), entry.getValue());
|
||||
}
|
||||
}
|
||||
if(!allowExpired && loaded.isExpired()) {
|
||||
return null;
|
||||
}
|
||||
RedisSession result = new RedisSession(loaded);
|
||||
result.originalLastAccessTime = loaded.getLastAccessedTime() + TimeUnit.SECONDS.toMillis(loaded.getMaxInactiveIntervalInSeconds());
|
||||
result.setLastAccessedTime(System.currentTimeMillis());
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param id the session id
|
||||
* @param allowExpired
|
||||
* if true, will also include expired sessions that have not been
|
||||
* deleted. If false, will ensure expired sessions are not
|
||||
* returned.
|
||||
* @return
|
||||
*/
|
||||
private RedisSession getSession(String id, boolean allowExpired) {
|
||||
Map<Object, Object> entries = getSessionBoundHashOperations(id).entries();
|
||||
if(entries.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
MapSession loaded = new MapSession();
|
||||
loaded.setId(id);
|
||||
for(Map.Entry<Object,Object> entry : entries.entrySet()) {
|
||||
String key = (String) entry.getKey();
|
||||
if(CREATION_TIME_ATTR.equals(key)) {
|
||||
loaded.setCreationTime((Long) entry.getValue());
|
||||
} else if(MAX_INACTIVE_ATTR.equals(key)) {
|
||||
loaded.setMaxInactiveIntervalInSeconds((Integer) entry.getValue());
|
||||
} else if(LAST_ACCESSED_ATTR.equals(key)) {
|
||||
loaded.setLastAccessedTime((Long) entry.getValue());
|
||||
} else if(key.startsWith(SESSION_ATTR_PREFIX)) {
|
||||
loaded.setAttribute(key.substring(SESSION_ATTR_PREFIX.length()), entry.getValue());
|
||||
}
|
||||
}
|
||||
if(!allowExpired && loaded.isExpired()) {
|
||||
return null;
|
||||
}
|
||||
RedisSession result = new RedisSession(loaded);
|
||||
result.originalLastAccessTime = loaded.getLastAccessedTime() + TimeUnit.SECONDS.toMillis(loaded.getMaxInactiveIntervalInSeconds());
|
||||
result.setLastAccessedTime(System.currentTimeMillis());
|
||||
return result;
|
||||
}
|
||||
|
||||
public void delete(String sessionId) {
|
||||
ExpiringSession session = getSession(sessionId, true);
|
||||
if(session == null) {
|
||||
return;
|
||||
}
|
||||
public void delete(String sessionId) {
|
||||
ExpiringSession session = getSession(sessionId, true);
|
||||
if(session == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String key = getKey(sessionId);
|
||||
expirationPolicy.onDelete(session);
|
||||
String key = getKey(sessionId);
|
||||
expirationPolicy.onDelete(session);
|
||||
|
||||
// always delete they key since session may be null if just expired
|
||||
this.sessionRedisOperations.delete(key);
|
||||
}
|
||||
// always delete they key since session may be null if just expired
|
||||
this.sessionRedisOperations.delete(key);
|
||||
}
|
||||
|
||||
public RedisSession createSession() {
|
||||
RedisSession redisSession = new RedisSession();
|
||||
if(defaultMaxInactiveInterval != null) {
|
||||
redisSession.setMaxInactiveIntervalInSeconds(defaultMaxInactiveInterval);
|
||||
}
|
||||
return redisSession;
|
||||
}
|
||||
public RedisSession createSession() {
|
||||
RedisSession redisSession = new RedisSession();
|
||||
if(defaultMaxInactiveInterval != null) {
|
||||
redisSession.setMaxInactiveIntervalInSeconds(defaultMaxInactiveInterval);
|
||||
}
|
||||
return redisSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Hash key for this session by prefixing it appropriately.
|
||||
*
|
||||
* @param sessionId the session id
|
||||
* @return the Hash key for this session by prefixing it appropriately.
|
||||
*/
|
||||
static String getKey(String sessionId) {
|
||||
return BOUNDED_HASH_KEY_PREFIX + sessionId;
|
||||
}
|
||||
/**
|
||||
* Gets the Hash key for this session by prefixing it appropriately.
|
||||
*
|
||||
* @param sessionId the session id
|
||||
* @return the Hash key for this session by prefixing it appropriately.
|
||||
*/
|
||||
static String getKey(String sessionId) {
|
||||
return BOUNDED_HASH_KEY_PREFIX + sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the key for the specified session attribute
|
||||
*
|
||||
* @param attributeName
|
||||
* @return
|
||||
*/
|
||||
static String getSessionAttrNameKey(String attributeName) {
|
||||
return SESSION_ATTR_PREFIX + attributeName;
|
||||
}
|
||||
/**
|
||||
* Gets the key for the specified session attribute
|
||||
*
|
||||
* @param attributeName
|
||||
* @return
|
||||
*/
|
||||
static String getSessionAttrNameKey(String attributeName) {
|
||||
return SESSION_ATTR_PREFIX + attributeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link BoundHashOperations} to operate on a {@link Session}
|
||||
* @param sessionId the id of the {@link Session} to work with
|
||||
* @return the {@link BoundHashOperations} to operate on a {@link Session}
|
||||
*/
|
||||
private BoundHashOperations<String, Object, Object> getSessionBoundHashOperations(String sessionId) {
|
||||
String key = getKey(sessionId);
|
||||
return this.sessionRedisOperations.boundHashOps(key);
|
||||
}
|
||||
/**
|
||||
* Gets the {@link BoundHashOperations} to operate on a {@link Session}
|
||||
* @param sessionId the id of the {@link Session} to work with
|
||||
* @return the {@link BoundHashOperations} to operate on a {@link Session}
|
||||
*/
|
||||
private BoundHashOperations<String, Object, Object> getSessionBoundHashOperations(String sessionId) {
|
||||
String key = getKey(sessionId);
|
||||
return this.sessionRedisOperations.boundHashOps(key);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static RedisTemplate createDefaultTemplate(RedisConnectionFactory connectionFactory) {
|
||||
Assert.notNull(connectionFactory,"connectionFactory cannot be null");
|
||||
RedisTemplate<String, ExpiringSession> template = new RedisTemplate<String, ExpiringSession>();
|
||||
template.setKeySerializer(new StringRedisSerializer());
|
||||
template.setHashKeySerializer(new StringRedisSerializer());
|
||||
template.setConnectionFactory(connectionFactory);
|
||||
template.afterPropertiesSet();
|
||||
return template;
|
||||
}
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static RedisTemplate createDefaultTemplate(RedisConnectionFactory connectionFactory) {
|
||||
Assert.notNull(connectionFactory,"connectionFactory cannot be null");
|
||||
RedisTemplate<String, ExpiringSession> template = new RedisTemplate<String, ExpiringSession>();
|
||||
template.setKeySerializer(new StringRedisSerializer());
|
||||
template.setHashKeySerializer(new StringRedisSerializer());
|
||||
template.setConnectionFactory(connectionFactory);
|
||||
template.afterPropertiesSet();
|
||||
return template;
|
||||
}
|
||||
|
||||
/**
|
||||
* A custom implementation of {@link Session} that uses a {@link MapSession} as the basis for its mapping. It keeps
|
||||
* track of any attributes that have changed. When
|
||||
* {@link org.springframework.session.data.redis.RedisOperationsSessionRepository.RedisSession#saveDelta()} is invoked
|
||||
* all the attributes that have been changed will be persisted.
|
||||
*
|
||||
* @since 1.0
|
||||
* @author Rob Winch
|
||||
*/
|
||||
final class RedisSession implements ExpiringSession {
|
||||
private final MapSession cached;
|
||||
private Long originalLastAccessTime;
|
||||
private Map<String, Object> delta = new HashMap<String,Object>();
|
||||
/**
|
||||
* A custom implementation of {@link Session} that uses a {@link MapSession} as the basis for its mapping. It keeps
|
||||
* track of any attributes that have changed. When
|
||||
* {@link org.springframework.session.data.redis.RedisOperationsSessionRepository.RedisSession#saveDelta()} is invoked
|
||||
* all the attributes that have been changed will be persisted.
|
||||
*
|
||||
* @since 1.0
|
||||
* @author Rob Winch
|
||||
*/
|
||||
final class RedisSession implements ExpiringSession {
|
||||
private final MapSession cached;
|
||||
private Long originalLastAccessTime;
|
||||
private Map<String, Object> delta = new HashMap<String,Object>();
|
||||
|
||||
/**
|
||||
* Creates a new instance ensuring to mark all of the new attributes to be persisted in the next save operation.
|
||||
*/
|
||||
RedisSession() {
|
||||
this(new MapSession());
|
||||
delta.put(CREATION_TIME_ATTR, getCreationTime());
|
||||
delta.put(MAX_INACTIVE_ATTR, getMaxInactiveIntervalInSeconds());
|
||||
delta.put(LAST_ACCESSED_ATTR, getLastAccessedTime());
|
||||
}
|
||||
/**
|
||||
* Creates a new instance ensuring to mark all of the new attributes to be persisted in the next save operation.
|
||||
*/
|
||||
RedisSession() {
|
||||
this(new MapSession());
|
||||
delta.put(CREATION_TIME_ATTR, getCreationTime());
|
||||
delta.put(MAX_INACTIVE_ATTR, getMaxInactiveIntervalInSeconds());
|
||||
delta.put(LAST_ACCESSED_ATTR, getLastAccessedTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance from the provided {@link MapSession}
|
||||
*
|
||||
* @param cached the {@MapSession} that represents the persisted session that was retrieved. Cannot be null.
|
||||
*/
|
||||
RedisSession(MapSession cached) {
|
||||
Assert.notNull("MapSession cannot be null");
|
||||
this.cached = cached;
|
||||
}
|
||||
/**
|
||||
* Creates a new instance from the provided {@link MapSession}
|
||||
*
|
||||
* @param cached the {@MapSession} that represents the persisted session that was retrieved. Cannot be null.
|
||||
*/
|
||||
RedisSession(MapSession cached) {
|
||||
Assert.notNull("MapSession cannot be null");
|
||||
this.cached = cached;
|
||||
}
|
||||
|
||||
public void setLastAccessedTime(long lastAccessedTime) {
|
||||
cached.setLastAccessedTime(lastAccessedTime);
|
||||
delta.put(LAST_ACCESSED_ATTR, getLastAccessedTime());
|
||||
}
|
||||
public void setLastAccessedTime(long lastAccessedTime) {
|
||||
cached.setLastAccessedTime(lastAccessedTime);
|
||||
delta.put(LAST_ACCESSED_ATTR, getLastAccessedTime());
|
||||
}
|
||||
|
||||
public boolean isExpired() {
|
||||
return cached.isExpired();
|
||||
}
|
||||
public boolean isExpired() {
|
||||
return cached.isExpired();
|
||||
}
|
||||
|
||||
public long getCreationTime() {
|
||||
return cached.getCreationTime();
|
||||
}
|
||||
public long getCreationTime() {
|
||||
return cached.getCreationTime();
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return cached.getId();
|
||||
}
|
||||
public String getId() {
|
||||
return cached.getId();
|
||||
}
|
||||
|
||||
public long getLastAccessedTime() {
|
||||
return cached.getLastAccessedTime();
|
||||
}
|
||||
public long getLastAccessedTime() {
|
||||
return cached.getLastAccessedTime();
|
||||
}
|
||||
|
||||
public void setMaxInactiveIntervalInSeconds(int interval) {
|
||||
cached.setMaxInactiveIntervalInSeconds(interval);
|
||||
delta.put(MAX_INACTIVE_ATTR, getMaxInactiveIntervalInSeconds());
|
||||
}
|
||||
public void setMaxInactiveIntervalInSeconds(int interval) {
|
||||
cached.setMaxInactiveIntervalInSeconds(interval);
|
||||
delta.put(MAX_INACTIVE_ATTR, getMaxInactiveIntervalInSeconds());
|
||||
}
|
||||
|
||||
public int getMaxInactiveIntervalInSeconds() {
|
||||
return cached.getMaxInactiveIntervalInSeconds();
|
||||
}
|
||||
public int getMaxInactiveIntervalInSeconds() {
|
||||
return cached.getMaxInactiveIntervalInSeconds();
|
||||
}
|
||||
|
||||
public Object getAttribute(String attributeName) {
|
||||
return cached.getAttribute(attributeName);
|
||||
}
|
||||
public Object getAttribute(String attributeName) {
|
||||
return cached.getAttribute(attributeName);
|
||||
}
|
||||
|
||||
public Set<String> getAttributeNames() {
|
||||
return cached.getAttributeNames();
|
||||
}
|
||||
public Set<String> getAttributeNames() {
|
||||
return cached.getAttributeNames();
|
||||
}
|
||||
|
||||
public void setAttribute(String attributeName, Object attributeValue) {
|
||||
cached.setAttribute(attributeName, attributeValue);
|
||||
delta.put(getSessionAttrNameKey(attributeName), attributeValue);
|
||||
}
|
||||
public void setAttribute(String attributeName, Object attributeValue) {
|
||||
cached.setAttribute(attributeName, attributeValue);
|
||||
delta.put(getSessionAttrNameKey(attributeName), attributeValue);
|
||||
}
|
||||
|
||||
public void removeAttribute(String attributeName) {
|
||||
cached.removeAttribute(attributeName);
|
||||
delta.put(getSessionAttrNameKey(attributeName), null);
|
||||
}
|
||||
public void removeAttribute(String attributeName) {
|
||||
cached.removeAttribute(attributeName);
|
||||
delta.put(getSessionAttrNameKey(attributeName), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves any attributes that have been changed and updates the expiration of this session.
|
||||
*/
|
||||
private void saveDelta() {
|
||||
String sessionId = getId();
|
||||
getSessionBoundHashOperations(sessionId).putAll(delta);
|
||||
delta = new HashMap<String,Object>(delta.size());
|
||||
/**
|
||||
* Saves any attributes that have been changed and updates the expiration of this session.
|
||||
*/
|
||||
private void saveDelta() {
|
||||
String sessionId = getId();
|
||||
getSessionBoundHashOperations(sessionId).putAll(delta);
|
||||
delta = new HashMap<String,Object>(delta.size());
|
||||
|
||||
expirationPolicy.onExpirationUpdated(originalLastAccessTime, this);
|
||||
}
|
||||
}
|
||||
expirationPolicy.onExpirationUpdated(originalLastAccessTime, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -17,7 +17,6 @@ package org.springframework.session.data.redis;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -46,101 +45,102 @@ import org.springframework.session.data.redis.RedisOperationsSessionRepository.R
|
||||
*/
|
||||
final class RedisSessionExpirationPolicy {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(RedisOperationsSessionRepository.class);
|
||||
private static final Log logger = LogFactory.getLog(RedisOperationsSessionRepository.class);
|
||||
|
||||
/**
|
||||
* The prefix for each key of the Redis Hash representing a single session. The suffix is the unique session id.
|
||||
*/
|
||||
static final String EXPIRATION_BOUNDED_HASH_KEY_PREFIX = "spring:session:expirations:";
|
||||
/**
|
||||
* The prefix for each key of the Redis Hash representing a single session. The suffix is the unique session id.
|
||||
*/
|
||||
static final String EXPIRATION_BOUNDED_HASH_KEY_PREFIX = "spring:session:expirations:";
|
||||
|
||||
private final RedisOperations<String,ExpiringSession> sessionRedisOperations;
|
||||
private final RedisOperations<String,ExpiringSession> sessionRedisOperations;
|
||||
|
||||
private final RedisOperations<String,String> expirationRedisOperations;
|
||||
private final RedisOperations<String,String> expirationRedisOperations;
|
||||
|
||||
public RedisSessionExpirationPolicy(
|
||||
RedisOperations sessionRedisOperations) {
|
||||
super();
|
||||
this.sessionRedisOperations = sessionRedisOperations;
|
||||
this.expirationRedisOperations = sessionRedisOperations;
|
||||
}
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public RedisSessionExpirationPolicy(
|
||||
RedisOperations sessionRedisOperations) {
|
||||
super();
|
||||
this.sessionRedisOperations = sessionRedisOperations;
|
||||
this.expirationRedisOperations = sessionRedisOperations;
|
||||
}
|
||||
|
||||
public void onDelete(ExpiringSession session) {
|
||||
long lastAccessedTime = session.getLastAccessedTime();
|
||||
int maxInactiveInterval = session.getMaxInactiveIntervalInSeconds();
|
||||
public void onDelete(ExpiringSession session) {
|
||||
long lastAccessedTime = session.getLastAccessedTime();
|
||||
int maxInactiveInterval = session.getMaxInactiveIntervalInSeconds();
|
||||
|
||||
long toExpire = roundUpToNextMinute(lastAccessedTime, maxInactiveInterval);
|
||||
String expireKey = getExpirationKey(toExpire);
|
||||
expirationRedisOperations.boundSetOps(expireKey).remove(session.getId());
|
||||
}
|
||||
long toExpire = roundUpToNextMinute(lastAccessedTime, maxInactiveInterval);
|
||||
String expireKey = getExpirationKey(toExpire);
|
||||
expirationRedisOperations.boundSetOps(expireKey).remove(session.getId());
|
||||
}
|
||||
|
||||
public void onExpirationUpdated(Long originalExpirationTime, ExpiringSession session) {
|
||||
if(originalExpirationTime != null) {
|
||||
String expireKey = getExpirationKey(originalExpirationTime);
|
||||
expirationRedisOperations.boundSetOps(expireKey).remove(session.getId());
|
||||
}
|
||||
public void onExpirationUpdated(Long originalExpirationTime, ExpiringSession session) {
|
||||
if(originalExpirationTime != null) {
|
||||
String expireKey = getExpirationKey(originalExpirationTime);
|
||||
expirationRedisOperations.boundSetOps(expireKey).remove(session.getId());
|
||||
}
|
||||
|
||||
long toExpire = roundUpToNextMinute(session.getLastAccessedTime(), session.getMaxInactiveIntervalInSeconds());
|
||||
long toExpire = roundUpToNextMinute(session.getLastAccessedTime(), session.getMaxInactiveIntervalInSeconds());
|
||||
|
||||
String expireKey = getExpirationKey(toExpire);
|
||||
expirationRedisOperations.boundSetOps(expireKey).add(session.getId());
|
||||
String expireKey = getExpirationKey(toExpire);
|
||||
expirationRedisOperations.boundSetOps(expireKey).add(session.getId());
|
||||
|
||||
long redisExpirationInSeconds = session.getMaxInactiveIntervalInSeconds();
|
||||
String sessionKey = getSessionKey(session.getId());
|
||||
expirationRedisOperations.boundSetOps(expireKey).expire(redisExpirationInSeconds, TimeUnit.SECONDS);
|
||||
sessionRedisOperations.boundHashOps(sessionKey).expire(redisExpirationInSeconds, TimeUnit.SECONDS);
|
||||
}
|
||||
long redisExpirationInSeconds = session.getMaxInactiveIntervalInSeconds();
|
||||
String sessionKey = getSessionKey(session.getId());
|
||||
expirationRedisOperations.boundSetOps(expireKey).expire(redisExpirationInSeconds, TimeUnit.SECONDS);
|
||||
sessionRedisOperations.boundHashOps(sessionKey).expire(redisExpirationInSeconds, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private String getExpirationKey(long expires) {
|
||||
return EXPIRATION_BOUNDED_HASH_KEY_PREFIX + expires;
|
||||
}
|
||||
private String getExpirationKey(long expires) {
|
||||
return EXPIRATION_BOUNDED_HASH_KEY_PREFIX + expires;
|
||||
}
|
||||
|
||||
private String getSessionKey(String sessionId) {
|
||||
return RedisOperationsSessionRepository.BOUNDED_HASH_KEY_PREFIX + sessionId;
|
||||
}
|
||||
private String getSessionKey(String sessionId) {
|
||||
return RedisOperationsSessionRepository.BOUNDED_HASH_KEY_PREFIX + sessionId;
|
||||
}
|
||||
|
||||
public void cleanExpiredSessions() {
|
||||
long now = System.currentTimeMillis();
|
||||
long prevMin = roundDownMinute(now);
|
||||
public void cleanExpiredSessions() {
|
||||
long now = System.currentTimeMillis();
|
||||
long prevMin = roundDownMinute(now);
|
||||
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("Cleaning up sessions expiring at "+ new Date(prevMin));
|
||||
}
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("Cleaning up sessions expiring at "+ new Date(prevMin));
|
||||
}
|
||||
|
||||
String expirationKey = getExpirationKey(prevMin);
|
||||
Set<String> sessionsToExpire = expirationRedisOperations.boundSetOps(expirationKey).members();
|
||||
touch(expirationKey);
|
||||
for(String session : sessionsToExpire) {
|
||||
String sessionKey = getSessionKey(session);
|
||||
touch(sessionKey);
|
||||
}
|
||||
}
|
||||
String expirationKey = getExpirationKey(prevMin);
|
||||
Set<String> sessionsToExpire = expirationRedisOperations.boundSetOps(expirationKey).members();
|
||||
touch(expirationKey);
|
||||
for(String session : sessionsToExpire) {
|
||||
String sessionKey = getSessionKey(session);
|
||||
touch(sessionKey);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* By trying to access the session we only trigger a deletion if it the TTL is expired. This is done to handle
|
||||
* https://github.com/spring-projects/spring-session/issues/93
|
||||
*
|
||||
* @param key
|
||||
*/
|
||||
private void touch(String key) {
|
||||
sessionRedisOperations.hasKey(key);
|
||||
}
|
||||
/**
|
||||
* By trying to access the session we only trigger a deletion if it the TTL is expired. This is done to handle
|
||||
* https://github.com/spring-projects/spring-session/issues/93
|
||||
*
|
||||
* @param key
|
||||
*/
|
||||
private void touch(String key) {
|
||||
sessionRedisOperations.hasKey(key);
|
||||
}
|
||||
|
||||
private long roundUpToNextMinute(long timeInMs, int inactiveIntervalInSec) {
|
||||
private long roundUpToNextMinute(long timeInMs, int inactiveIntervalInSec) {
|
||||
|
||||
Calendar date = Calendar.getInstance();
|
||||
date.setTimeInMillis(timeInMs + TimeUnit.SECONDS.toMillis(inactiveIntervalInSec));
|
||||
date.add(Calendar.MINUTE, 1);
|
||||
date.clear(Calendar.SECOND);
|
||||
date.clear(Calendar.MILLISECOND);
|
||||
return date.getTimeInMillis();
|
||||
}
|
||||
Calendar date = Calendar.getInstance();
|
||||
date.setTimeInMillis(timeInMs + TimeUnit.SECONDS.toMillis(inactiveIntervalInSec));
|
||||
date.add(Calendar.MINUTE, 1);
|
||||
date.clear(Calendar.SECOND);
|
||||
date.clear(Calendar.MILLISECOND);
|
||||
return date.getTimeInMillis();
|
||||
}
|
||||
|
||||
private long roundDownMinute(long timeInMs) {
|
||||
Calendar date = Calendar.getInstance();
|
||||
date.setTimeInMillis(timeInMs);
|
||||
date.add(Calendar.MINUTE, -1);
|
||||
date.clear(Calendar.SECOND);
|
||||
date.clear(Calendar.MILLISECOND);
|
||||
return date.getTimeInMillis();
|
||||
}
|
||||
private long roundDownMinute(long timeInMs) {
|
||||
Calendar date = Calendar.getInstance();
|
||||
date.setTimeInMillis(timeInMs);
|
||||
date.add(Calendar.MINUTE, -1);
|
||||
date.clear(Calendar.SECOND);
|
||||
date.clear(Calendar.MILLISECOND);
|
||||
return date.getTimeInMillis();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -32,53 +32,53 @@ import org.springframework.util.Assert;
|
||||
* @since 1.0
|
||||
*/
|
||||
public class SessionMessageListener implements MessageListener {
|
||||
private static final Log logger = LogFactory.getLog(SessionMessageListener.class);
|
||||
private static final Log logger = LogFactory.getLog(SessionMessageListener.class);
|
||||
|
||||
private final ApplicationEventPublisher eventPublisher;
|
||||
private final ApplicationEventPublisher eventPublisher;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param eventPublisher the {@link ApplicationEventPublisher} to use. Cannot be null.
|
||||
*/
|
||||
public SessionMessageListener(ApplicationEventPublisher eventPublisher) {
|
||||
Assert.notNull(eventPublisher, "eventPublisher cannot be null");
|
||||
this.eventPublisher = eventPublisher;
|
||||
}
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param eventPublisher the {@link ApplicationEventPublisher} to use. Cannot be null.
|
||||
*/
|
||||
public SessionMessageListener(ApplicationEventPublisher eventPublisher) {
|
||||
Assert.notNull(eventPublisher, "eventPublisher cannot be null");
|
||||
this.eventPublisher = eventPublisher;
|
||||
}
|
||||
|
||||
public void onMessage(Message message, byte[] pattern) {
|
||||
byte[] messageChannel = message.getChannel();
|
||||
byte[] messageBody = message.getBody();
|
||||
if(messageChannel == null || messageBody == null) {
|
||||
return;
|
||||
}
|
||||
String channel = new String(messageChannel);
|
||||
if(!(channel.endsWith(":del") || channel.endsWith(":expired"))) {
|
||||
return;
|
||||
}
|
||||
String body = new String(messageBody);
|
||||
if(!body.startsWith("spring:session:sessions:")) {
|
||||
return;
|
||||
}
|
||||
public void onMessage(Message message, byte[] pattern) {
|
||||
byte[] messageChannel = message.getChannel();
|
||||
byte[] messageBody = message.getBody();
|
||||
if(messageChannel == null || messageBody == null) {
|
||||
return;
|
||||
}
|
||||
String channel = new String(messageChannel);
|
||||
if(!(channel.endsWith(":del") || channel.endsWith(":expired"))) {
|
||||
return;
|
||||
}
|
||||
String body = new String(messageBody);
|
||||
if(!body.startsWith("spring:session:sessions:")) {
|
||||
return;
|
||||
}
|
||||
|
||||
int beginIndex = body.lastIndexOf(":") + 1;
|
||||
int endIndex = body.length();
|
||||
String sessionId = body.substring(beginIndex, endIndex);
|
||||
int beginIndex = body.lastIndexOf(":") + 1;
|
||||
int endIndex = body.length();
|
||||
String sessionId = body.substring(beginIndex, endIndex);
|
||||
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("Publishing SessionDestroyedEvent for session " + sessionId);
|
||||
}
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("Publishing SessionDestroyedEvent for session " + sessionId);
|
||||
}
|
||||
|
||||
publishEvent(new SessionDestroyedEvent(this, sessionId));
|
||||
}
|
||||
publishEvent(new SessionDestroyedEvent(this, sessionId));
|
||||
}
|
||||
|
||||
private void publishEvent(ApplicationEvent event) {
|
||||
try {
|
||||
this.eventPublisher.publishEvent(event);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.error("Error publishing " + event + ".", ex);
|
||||
}
|
||||
}
|
||||
private void publishEvent(ApplicationEvent event) {
|
||||
try {
|
||||
this.eventPublisher.publishEvent(event);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.error("Error publishing " + event + ".", ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -53,5 +53,5 @@ import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
@Import(RedisHttpSessionConfiguration.class)
|
||||
@Configuration
|
||||
public @interface EnableRedisHttpSession {
|
||||
int maxInactiveIntervalInSeconds() default 1800;
|
||||
int maxInactiveIntervalInSeconds() default 1800;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -22,7 +22,6 @@ import java.util.Map;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
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.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -59,132 +58,132 @@ import org.springframework.util.ClassUtils;
|
||||
@EnableScheduling
|
||||
public class RedisHttpSessionConfiguration implements ImportAware, BeanClassLoaderAware {
|
||||
|
||||
private ClassLoader beanClassLoader;
|
||||
private ClassLoader beanClassLoader;
|
||||
|
||||
private Integer maxInactiveIntervalInSeconds;
|
||||
private Integer maxInactiveIntervalInSeconds;
|
||||
|
||||
private HttpSessionStrategy httpSessionStrategy;
|
||||
private HttpSessionStrategy httpSessionStrategy;
|
||||
|
||||
@Autowired
|
||||
private ApplicationEventPublisher eventPublisher;
|
||||
@Autowired
|
||||
private ApplicationEventPublisher eventPublisher;
|
||||
|
||||
@Bean
|
||||
public RedisMessageListenerContainer redisMessageListenerContainer(
|
||||
RedisConnectionFactory connectionFactory) {
|
||||
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
|
||||
container.setConnectionFactory(connectionFactory);
|
||||
container.addMessageListener(redisSessionMessageListener(),
|
||||
Arrays.asList(new PatternTopic("__keyevent@*:del"),new PatternTopic("__keyevent@*:expired")));
|
||||
return container;
|
||||
}
|
||||
@Bean
|
||||
public RedisMessageListenerContainer redisMessageListenerContainer(
|
||||
RedisConnectionFactory connectionFactory) {
|
||||
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
|
||||
container.setConnectionFactory(connectionFactory);
|
||||
container.addMessageListener(redisSessionMessageListener(),
|
||||
Arrays.asList(new PatternTopic("__keyevent@*:del"),new PatternTopic("__keyevent@*:expired")));
|
||||
return container;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SessionMessageListener redisSessionMessageListener() {
|
||||
return new SessionMessageListener(eventPublisher);
|
||||
}
|
||||
@Bean
|
||||
public SessionMessageListener redisSessionMessageListener() {
|
||||
return new SessionMessageListener(eventPublisher);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RedisTemplate<String,ExpiringSession> sessionRedisTemplate(RedisConnectionFactory connectionFactory) {
|
||||
RedisTemplate<String, ExpiringSession> template = new RedisTemplate<String, ExpiringSession>();
|
||||
template.setKeySerializer(new StringRedisSerializer());
|
||||
template.setHashKeySerializer(new StringRedisSerializer());
|
||||
template.setConnectionFactory(connectionFactory);
|
||||
return template;
|
||||
}
|
||||
@Bean
|
||||
public RedisTemplate<String,ExpiringSession> sessionRedisTemplate(RedisConnectionFactory connectionFactory) {
|
||||
RedisTemplate<String, ExpiringSession> template = new RedisTemplate<String, ExpiringSession>();
|
||||
template.setKeySerializer(new StringRedisSerializer());
|
||||
template.setHashKeySerializer(new StringRedisSerializer());
|
||||
template.setConnectionFactory(connectionFactory);
|
||||
return template;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RedisOperationsSessionRepository sessionRepository(RedisTemplate<String, ExpiringSession> sessionRedisTemplate) {
|
||||
RedisOperationsSessionRepository sessionRepository = new RedisOperationsSessionRepository(sessionRedisTemplate);
|
||||
sessionRepository.setDefaultMaxInactiveInterval(maxInactiveIntervalInSeconds);
|
||||
return sessionRepository;
|
||||
}
|
||||
@Bean
|
||||
public RedisOperationsSessionRepository sessionRepository(RedisTemplate<String, ExpiringSession> sessionRedisTemplate) {
|
||||
RedisOperationsSessionRepository sessionRepository = new RedisOperationsSessionRepository(sessionRedisTemplate);
|
||||
sessionRepository.setDefaultMaxInactiveInterval(maxInactiveIntervalInSeconds);
|
||||
return sessionRepository;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public <S extends ExpiringSession> SessionRepositoryFilter<? extends ExpiringSession> springSessionRepositoryFilter(SessionRepository<S> sessionRepository) {
|
||||
SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter<S>(sessionRepository);
|
||||
if(httpSessionStrategy != null) {
|
||||
sessionRepositoryFilter.setHttpSessionStrategy(httpSessionStrategy);
|
||||
}
|
||||
return sessionRepositoryFilter;
|
||||
}
|
||||
@Bean
|
||||
public <S extends ExpiringSession> SessionRepositoryFilter<? extends ExpiringSession> springSessionRepositoryFilter(SessionRepository<S> sessionRepository) {
|
||||
SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter<S>(sessionRepository);
|
||||
if(httpSessionStrategy != null) {
|
||||
sessionRepositoryFilter.setHttpSessionStrategy(httpSessionStrategy);
|
||||
}
|
||||
return sessionRepositoryFilter;
|
||||
}
|
||||
|
||||
public void setImportMetadata(AnnotationMetadata importMetadata) {
|
||||
public void setImportMetadata(AnnotationMetadata importMetadata) {
|
||||
|
||||
Map<String, Object> enableAttrMap = importMetadata.getAnnotationAttributes(EnableRedisHttpSession.class.getName());
|
||||
AnnotationAttributes enableAttrs = AnnotationAttributes.fromMap(enableAttrMap);
|
||||
if(enableAttrs == null) {
|
||||
// search parent classes
|
||||
Class<?> currentClass = ClassUtils.resolveClassName(importMetadata.getClassName(), beanClassLoader);
|
||||
for(Class<?> classToInspect = currentClass ;classToInspect != null; classToInspect = classToInspect.getSuperclass()) {
|
||||
EnableRedisHttpSession enableWebSecurityAnnotation = AnnotationUtils.findAnnotation(classToInspect, EnableRedisHttpSession.class);
|
||||
if(enableWebSecurityAnnotation == null) {
|
||||
continue;
|
||||
}
|
||||
enableAttrMap = AnnotationUtils
|
||||
.getAnnotationAttributes(enableWebSecurityAnnotation);
|
||||
enableAttrs = AnnotationAttributes.fromMap(enableAttrMap);
|
||||
}
|
||||
}
|
||||
maxInactiveIntervalInSeconds = enableAttrs.getNumber("maxInactiveIntervalInSeconds");
|
||||
}
|
||||
Map<String, Object> enableAttrMap = importMetadata.getAnnotationAttributes(EnableRedisHttpSession.class.getName());
|
||||
AnnotationAttributes enableAttrs = AnnotationAttributes.fromMap(enableAttrMap);
|
||||
if(enableAttrs == null) {
|
||||
// search parent classes
|
||||
Class<?> currentClass = ClassUtils.resolveClassName(importMetadata.getClassName(), beanClassLoader);
|
||||
for(Class<?> classToInspect = currentClass ;classToInspect != null; classToInspect = classToInspect.getSuperclass()) {
|
||||
EnableRedisHttpSession enableWebSecurityAnnotation = AnnotationUtils.findAnnotation(classToInspect, EnableRedisHttpSession.class);
|
||||
if(enableWebSecurityAnnotation == null) {
|
||||
continue;
|
||||
}
|
||||
enableAttrMap = AnnotationUtils
|
||||
.getAnnotationAttributes(enableWebSecurityAnnotation);
|
||||
enableAttrs = AnnotationAttributes.fromMap(enableAttrMap);
|
||||
}
|
||||
}
|
||||
maxInactiveIntervalInSeconds = enableAttrs.getNumber("maxInactiveIntervalInSeconds");
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setHttpSessionStrategy(HttpSessionStrategy httpSessionStrategy) {
|
||||
this.httpSessionStrategy = httpSessionStrategy;
|
||||
}
|
||||
@Autowired(required = false)
|
||||
public void setHttpSessionStrategy(HttpSessionStrategy httpSessionStrategy) {
|
||||
this.httpSessionStrategy = httpSessionStrategy;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public EnableRedisKeyspaceNotificationsInitializer enableRedisKeyspaceNotificationsInitializer(RedisConnectionFactory connectionFactory) {
|
||||
return new EnableRedisKeyspaceNotificationsInitializer(connectionFactory);
|
||||
}
|
||||
@Bean
|
||||
public EnableRedisKeyspaceNotificationsInitializer enableRedisKeyspaceNotificationsInitializer(RedisConnectionFactory connectionFactory) {
|
||||
return new EnableRedisKeyspaceNotificationsInitializer(connectionFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that Redis is configured to send keyspace notifications. This is important to ensure that expiration and
|
||||
* deletion of sessions trigger SessionDestroyedEvents. Without the SessionDestroyedEvent resources may not get
|
||||
* cleaned up properly. For example, the mapping of the Session to WebSocket connections may not get cleaned up.
|
||||
*/
|
||||
static class EnableRedisKeyspaceNotificationsInitializer implements InitializingBean {
|
||||
static final String CONFIG_NOTIFY_KEYSPACE_EVENTS = "notify-keyspace-events";
|
||||
/**
|
||||
* Ensures that Redis is configured to send keyspace notifications. This is important to ensure that expiration and
|
||||
* deletion of sessions trigger SessionDestroyedEvents. Without the SessionDestroyedEvent resources may not get
|
||||
* cleaned up properly. For example, the mapping of the Session to WebSocket connections may not get cleaned up.
|
||||
*/
|
||||
static class EnableRedisKeyspaceNotificationsInitializer implements InitializingBean {
|
||||
static final String CONFIG_NOTIFY_KEYSPACE_EVENTS = "notify-keyspace-events";
|
||||
|
||||
private final RedisConnectionFactory connectionFactory;
|
||||
private final RedisConnectionFactory connectionFactory;
|
||||
|
||||
EnableRedisKeyspaceNotificationsInitializer(RedisConnectionFactory connectionFactory) {
|
||||
this.connectionFactory = connectionFactory;
|
||||
}
|
||||
EnableRedisKeyspaceNotificationsInitializer(RedisConnectionFactory connectionFactory) {
|
||||
this.connectionFactory = connectionFactory;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
RedisConnection connection = connectionFactory.getConnection();
|
||||
String notifyOptions = getNotifyOptions(connection);
|
||||
String customizedNotifyOptions = notifyOptions;
|
||||
if(!customizedNotifyOptions.contains("E")) {
|
||||
customizedNotifyOptions += "E";
|
||||
}
|
||||
boolean A = customizedNotifyOptions.contains("A");
|
||||
if(!(A || customizedNotifyOptions.contains("g"))) {
|
||||
customizedNotifyOptions += "g";
|
||||
}
|
||||
if(!(A || customizedNotifyOptions.contains("x"))) {
|
||||
customizedNotifyOptions += "x";
|
||||
}
|
||||
if(!notifyOptions.equals(customizedNotifyOptions)) {
|
||||
connection.setConfig(CONFIG_NOTIFY_KEYSPACE_EVENTS, customizedNotifyOptions);
|
||||
}
|
||||
}
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
RedisConnection connection = connectionFactory.getConnection();
|
||||
String notifyOptions = getNotifyOptions(connection);
|
||||
String customizedNotifyOptions = notifyOptions;
|
||||
if(!customizedNotifyOptions.contains("E")) {
|
||||
customizedNotifyOptions += "E";
|
||||
}
|
||||
boolean A = customizedNotifyOptions.contains("A");
|
||||
if(!(A || customizedNotifyOptions.contains("g"))) {
|
||||
customizedNotifyOptions += "g";
|
||||
}
|
||||
if(!(A || customizedNotifyOptions.contains("x"))) {
|
||||
customizedNotifyOptions += "x";
|
||||
}
|
||||
if(!notifyOptions.equals(customizedNotifyOptions)) {
|
||||
connection.setConfig(CONFIG_NOTIFY_KEYSPACE_EVENTS, customizedNotifyOptions);
|
||||
}
|
||||
}
|
||||
|
||||
private String getNotifyOptions(RedisConnection connection) {
|
||||
List<String> config = connection.getConfig(CONFIG_NOTIFY_KEYSPACE_EVENTS);
|
||||
if(config.size() < 2) {
|
||||
return "";
|
||||
}
|
||||
return config.get(1);
|
||||
}
|
||||
}
|
||||
private String getNotifyOptions(RedisConnection connection) {
|
||||
List<String> config = connection.getConfig(CONFIG_NOTIFY_KEYSPACE_EVENTS);
|
||||
if(config.size() < 2) {
|
||||
return "";
|
||||
}
|
||||
return config.get(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader(java.lang.ClassLoader)
|
||||
*/
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader(java.lang.ClassLoader)
|
||||
*/
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -30,14 +30,14 @@ import org.springframework.session.SessionRepository;
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class SessionDestroyedEvent extends ApplicationEvent {
|
||||
private final String sessionId;
|
||||
private final String sessionId;
|
||||
|
||||
public SessionDestroyedEvent(Object source, String sessionId) {
|
||||
super(source);
|
||||
this.sessionId = sessionId;
|
||||
}
|
||||
public SessionDestroyedEvent(Object source, String sessionId) {
|
||||
super(source);
|
||||
this.sessionId = sessionId;
|
||||
}
|
||||
|
||||
public String getSessionId() {
|
||||
return sessionId;
|
||||
}
|
||||
public String getSessionId() {
|
||||
return sessionId;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -73,210 +73,210 @@ import org.springframework.web.filter.DelegatingFilterProxy;
|
||||
@Order(100)
|
||||
public abstract class AbstractHttpSessionApplicationInitializer implements WebApplicationInitializer {
|
||||
|
||||
private static final String SERVLET_CONTEXT_PREFIX = "org.springframework.web.servlet.FrameworkServlet.CONTEXT.";
|
||||
private static final String SERVLET_CONTEXT_PREFIX = "org.springframework.web.servlet.FrameworkServlet.CONTEXT.";
|
||||
|
||||
public static final String DEFAULT_FILTER_NAME = "springSessionRepositoryFilter";
|
||||
public static final String DEFAULT_FILTER_NAME = "springSessionRepositoryFilter";
|
||||
|
||||
private final Class<?>[] configurationClasses;
|
||||
private final Class<?>[] configurationClasses;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance that assumes the Spring Session configuration is
|
||||
* loaded by some other means than this class. For example, a user might
|
||||
* create a {@link ContextLoaderListener} using a subclass of
|
||||
* {@link AbstractContextLoaderInitializer}.
|
||||
*
|
||||
* @see ContextLoaderListener
|
||||
*/
|
||||
protected AbstractHttpSessionApplicationInitializer() {
|
||||
this.configurationClasses = null;
|
||||
}
|
||||
/**
|
||||
* Creates a new instance that assumes the Spring Session configuration is
|
||||
* loaded by some other means than this class. For example, a user might
|
||||
* create a {@link ContextLoaderListener} using a subclass of
|
||||
* {@link AbstractContextLoaderInitializer}.
|
||||
*
|
||||
* @see ContextLoaderListener
|
||||
*/
|
||||
protected AbstractHttpSessionApplicationInitializer() {
|
||||
this.configurationClasses = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance that will instantiate the
|
||||
* {@link ContextLoaderListener} with the specified classes.
|
||||
*
|
||||
* @param configurationClasses {@code @Configuration} classes that will be used to configure the context
|
||||
*/
|
||||
protected AbstractHttpSessionApplicationInitializer(Class<?>... configurationClasses) {
|
||||
this.configurationClasses = configurationClasses;
|
||||
}
|
||||
/**
|
||||
* Creates a new instance that will instantiate the
|
||||
* {@link ContextLoaderListener} with the specified classes.
|
||||
*
|
||||
* @param configurationClasses {@code @Configuration} classes that will be used to configure the context
|
||||
*/
|
||||
protected AbstractHttpSessionApplicationInitializer(Class<?>... configurationClasses) {
|
||||
this.configurationClasses = configurationClasses;
|
||||
}
|
||||
|
||||
public void onStartup(ServletContext servletContext)
|
||||
throws ServletException {
|
||||
beforeSessionRepositoryFilter(servletContext);
|
||||
if(configurationClasses != null) {
|
||||
AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext();
|
||||
rootAppContext.register(configurationClasses);
|
||||
servletContext.addListener(new ContextLoaderListener(rootAppContext));
|
||||
}
|
||||
insertSessionRepositoryFilter(servletContext);
|
||||
afterSessionRepositoryFilter(servletContext);
|
||||
}
|
||||
public void onStartup(ServletContext servletContext)
|
||||
throws ServletException {
|
||||
beforeSessionRepositoryFilter(servletContext);
|
||||
if(configurationClasses != null) {
|
||||
AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext();
|
||||
rootAppContext.register(configurationClasses);
|
||||
servletContext.addListener(new ContextLoaderListener(rootAppContext));
|
||||
}
|
||||
insertSessionRepositoryFilter(servletContext);
|
||||
afterSessionRepositoryFilter(servletContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the springSessionRepositoryFilter
|
||||
* @param servletContext the {@link ServletContext}
|
||||
*/
|
||||
private void insertSessionRepositoryFilter(ServletContext servletContext) {
|
||||
String filterName = DEFAULT_FILTER_NAME;
|
||||
DelegatingFilterProxy springSessionRepositoryFilter = new DelegatingFilterProxy(filterName);
|
||||
String contextAttribute = getWebApplicationContextAttribute();
|
||||
if(contextAttribute != null) {
|
||||
springSessionRepositoryFilter.setContextAttribute(contextAttribute);
|
||||
}
|
||||
registerFilter(servletContext, true, filterName, springSessionRepositoryFilter);
|
||||
}
|
||||
/**
|
||||
* Registers the springSessionRepositoryFilter
|
||||
* @param servletContext the {@link ServletContext}
|
||||
*/
|
||||
private void insertSessionRepositoryFilter(ServletContext servletContext) {
|
||||
String filterName = DEFAULT_FILTER_NAME;
|
||||
DelegatingFilterProxy springSessionRepositoryFilter = new DelegatingFilterProxy(filterName);
|
||||
String contextAttribute = getWebApplicationContextAttribute();
|
||||
if(contextAttribute != null) {
|
||||
springSessionRepositoryFilter.setContextAttribute(contextAttribute);
|
||||
}
|
||||
registerFilter(servletContext, true, filterName, springSessionRepositoryFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the provided {@link Filter}s before existing {@link Filter}s
|
||||
* using default generated names, {@link #getSessionDispatcherTypes()}, and
|
||||
* {@link #isAsyncSessionSupported()}.
|
||||
*
|
||||
* @param servletContext
|
||||
* the {@link ServletContext} to use
|
||||
* @param filters
|
||||
* the {@link Filter}s to register
|
||||
*/
|
||||
protected final void insertFilters(ServletContext servletContext,Filter... filters) {
|
||||
registerFilters(servletContext, true, filters);
|
||||
}
|
||||
/**
|
||||
* Inserts the provided {@link Filter}s before existing {@link Filter}s
|
||||
* using default generated names, {@link #getSessionDispatcherTypes()}, and
|
||||
* {@link #isAsyncSessionSupported()}.
|
||||
*
|
||||
* @param servletContext
|
||||
* the {@link ServletContext} to use
|
||||
* @param filters
|
||||
* the {@link Filter}s to register
|
||||
*/
|
||||
protected final void insertFilters(ServletContext servletContext,Filter... filters) {
|
||||
registerFilters(servletContext, true, filters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the provided {@link Filter}s after existing {@link Filter}s
|
||||
* using default generated names, {@link #getSessionDispatcherTypes()}, and
|
||||
* {@link #isAsyncSessionSupported()}.
|
||||
*
|
||||
* @param servletContext
|
||||
* the {@link ServletContext} to use
|
||||
* @param filters
|
||||
* the {@link Filter}s to register
|
||||
*/
|
||||
protected final void appendFilters(ServletContext servletContext,Filter... filters) {
|
||||
registerFilters(servletContext, false, filters);
|
||||
}
|
||||
/**
|
||||
* Inserts the provided {@link Filter}s after existing {@link Filter}s
|
||||
* using default generated names, {@link #getSessionDispatcherTypes()}, and
|
||||
* {@link #isAsyncSessionSupported()}.
|
||||
*
|
||||
* @param servletContext
|
||||
* the {@link ServletContext} to use
|
||||
* @param filters
|
||||
* the {@link Filter}s to register
|
||||
*/
|
||||
protected final void appendFilters(ServletContext servletContext,Filter... filters) {
|
||||
registerFilters(servletContext, false, filters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the provided {@link Filter}s using default generated names,
|
||||
* {@link #getSessionDispatcherTypes()}, and
|
||||
* {@link #isAsyncSessionSupported()}.
|
||||
*
|
||||
* @param servletContext
|
||||
* the {@link ServletContext} to use
|
||||
* @param insertBeforeOtherFilters
|
||||
* if true, will insert the provided {@link Filter}s before other
|
||||
* {@link Filter}s. Otherwise, will insert the {@link Filter}s
|
||||
* after other {@link Filter}s.
|
||||
* @param filters
|
||||
* the {@link Filter}s to register
|
||||
*/
|
||||
private void registerFilters(ServletContext servletContext, boolean insertBeforeOtherFilters, Filter... filters) {
|
||||
Assert.notEmpty(filters, "filters cannot be null or empty");
|
||||
/**
|
||||
* Registers the provided {@link Filter}s using default generated names,
|
||||
* {@link #getSessionDispatcherTypes()}, and
|
||||
* {@link #isAsyncSessionSupported()}.
|
||||
*
|
||||
* @param servletContext
|
||||
* the {@link ServletContext} to use
|
||||
* @param insertBeforeOtherFilters
|
||||
* if true, will insert the provided {@link Filter}s before other
|
||||
* {@link Filter}s. Otherwise, will insert the {@link Filter}s
|
||||
* after other {@link Filter}s.
|
||||
* @param filters
|
||||
* the {@link Filter}s to register
|
||||
*/
|
||||
private void registerFilters(ServletContext servletContext, boolean insertBeforeOtherFilters, Filter... filters) {
|
||||
Assert.notEmpty(filters, "filters cannot be null or empty");
|
||||
|
||||
for(Filter filter : filters) {
|
||||
if(filter == null) {
|
||||
throw new IllegalArgumentException("filters cannot contain null values. Got " + Arrays.asList(filters));
|
||||
}
|
||||
String filterName = Conventions.getVariableName(filter);
|
||||
registerFilter(servletContext, insertBeforeOtherFilters, filterName, filter);
|
||||
}
|
||||
}
|
||||
for(Filter filter : filters) {
|
||||
if(filter == null) {
|
||||
throw new IllegalArgumentException("filters cannot contain null values. Got " + Arrays.asList(filters));
|
||||
}
|
||||
String filterName = Conventions.getVariableName(filter);
|
||||
registerFilter(servletContext, insertBeforeOtherFilters, filterName, filter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the provided filter using the {@link #isAsyncSessionSupported()} and {@link #getSessionDispatcherTypes()}.
|
||||
*
|
||||
* @param servletContext
|
||||
* @param insertBeforeOtherFilters should this Filter be inserted before or after other {@link Filter}
|
||||
* @param filterName
|
||||
* @param filter
|
||||
*/
|
||||
private final void registerFilter(ServletContext servletContext, boolean insertBeforeOtherFilters, String filterName, Filter filter) {
|
||||
Dynamic registration = servletContext.addFilter(filterName, filter);
|
||||
if(registration == null) {
|
||||
throw new IllegalStateException("Duplicate Filter registration for '" + filterName +"'. Check to ensure the Filter is only configured once.");
|
||||
}
|
||||
registration.setAsyncSupported(isAsyncSessionSupported());
|
||||
EnumSet<DispatcherType> dispatcherTypes = getSessionDispatcherTypes();
|
||||
registration.addMappingForUrlPatterns(dispatcherTypes, !insertBeforeOtherFilters, "/*");
|
||||
}
|
||||
/**
|
||||
* Registers the provided filter using the {@link #isAsyncSessionSupported()} and {@link #getSessionDispatcherTypes()}.
|
||||
*
|
||||
* @param servletContext
|
||||
* @param insertBeforeOtherFilters should this Filter be inserted before or after other {@link Filter}
|
||||
* @param filterName
|
||||
* @param filter
|
||||
*/
|
||||
private final void registerFilter(ServletContext servletContext, boolean insertBeforeOtherFilters, String filterName, Filter filter) {
|
||||
Dynamic registration = servletContext.addFilter(filterName, filter);
|
||||
if(registration == null) {
|
||||
throw new IllegalStateException("Duplicate Filter registration for '" + filterName +"'. Check to ensure the Filter is only configured once.");
|
||||
}
|
||||
registration.setAsyncSupported(isAsyncSessionSupported());
|
||||
EnumSet<DispatcherType> dispatcherTypes = getSessionDispatcherTypes();
|
||||
registration.addMappingForUrlPatterns(dispatcherTypes, !insertBeforeOtherFilters, "/*");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link DelegatingFilterProxy#getContextAttribute()} or null
|
||||
* if the parent {@link ApplicationContext} should be used. The default
|
||||
* behavior is to use the parent {@link ApplicationContext}.
|
||||
*
|
||||
* <p>
|
||||
* If {@link #getDispatcherWebApplicationContextSuffix()} is non-null the
|
||||
* {@link WebApplicationContext} for the Dispatcher will be used. This means
|
||||
* the child {@link ApplicationContext} is used to look up the
|
||||
* springSessionRepositoryFilter bean.
|
||||
* </p>
|
||||
*
|
||||
* @return the {@link DelegatingFilterProxy#getContextAttribute()} or null
|
||||
* if the parent {@link ApplicationContext} should be used
|
||||
*/
|
||||
private String getWebApplicationContextAttribute() {
|
||||
String dispatcherServletName = getDispatcherWebApplicationContextSuffix();
|
||||
if(dispatcherServletName == null) {
|
||||
return null;
|
||||
}
|
||||
return SERVLET_CONTEXT_PREFIX + dispatcherServletName;
|
||||
}
|
||||
/**
|
||||
* Returns the {@link DelegatingFilterProxy#getContextAttribute()} or null
|
||||
* if the parent {@link ApplicationContext} should be used. The default
|
||||
* behavior is to use the parent {@link ApplicationContext}.
|
||||
*
|
||||
* <p>
|
||||
* If {@link #getDispatcherWebApplicationContextSuffix()} is non-null the
|
||||
* {@link WebApplicationContext} for the Dispatcher will be used. This means
|
||||
* the child {@link ApplicationContext} is used to look up the
|
||||
* springSessionRepositoryFilter bean.
|
||||
* </p>
|
||||
*
|
||||
* @return the {@link DelegatingFilterProxy#getContextAttribute()} or null
|
||||
* if the parent {@link ApplicationContext} should be used
|
||||
*/
|
||||
private String getWebApplicationContextAttribute() {
|
||||
String dispatcherServletName = getDispatcherWebApplicationContextSuffix();
|
||||
if(dispatcherServletName == null) {
|
||||
return null;
|
||||
}
|
||||
return SERVLET_CONTEXT_PREFIX + dispatcherServletName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Return the {@code <servlet-name>} to use the DispatcherServlet's
|
||||
* {@link WebApplicationContext} to find the {@link DelegatingFilterProxy}
|
||||
* or null to use the parent {@link ApplicationContext}.
|
||||
*
|
||||
* <p>
|
||||
* For example, if you are using AbstractDispatcherServletInitializer or
|
||||
* AbstractAnnotationConfigDispatcherServletInitializer and using the
|
||||
* provided Servlet name, you can return "dispatcher" from this method to
|
||||
* use the DispatcherServlet's {@link WebApplicationContext}.
|
||||
* </p>
|
||||
*
|
||||
* @return the {@code <servlet-name>} of the DispatcherServlet to use its
|
||||
* {@link WebApplicationContext} or null (default) to use the parent
|
||||
* {@link ApplicationContext}.
|
||||
*/
|
||||
protected String getDispatcherWebApplicationContextSuffix() {
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Return the {@code <servlet-name>} to use the DispatcherServlet's
|
||||
* {@link WebApplicationContext} to find the {@link DelegatingFilterProxy}
|
||||
* or null to use the parent {@link ApplicationContext}.
|
||||
*
|
||||
* <p>
|
||||
* For example, if you are using AbstractDispatcherServletInitializer or
|
||||
* AbstractAnnotationConfigDispatcherServletInitializer and using the
|
||||
* provided Servlet name, you can return "dispatcher" from this method to
|
||||
* use the DispatcherServlet's {@link WebApplicationContext}.
|
||||
* </p>
|
||||
*
|
||||
* @return the {@code <servlet-name>} of the DispatcherServlet to use its
|
||||
* {@link WebApplicationContext} or null (default) to use the parent
|
||||
* {@link ApplicationContext}.
|
||||
*/
|
||||
protected String getDispatcherWebApplicationContextSuffix() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked before the springSessionRepositoryFilter is added.
|
||||
* @param servletContext the {@link ServletContext}
|
||||
*/
|
||||
protected void beforeSessionRepositoryFilter(ServletContext servletContext) {
|
||||
/**
|
||||
* Invoked before the springSessionRepositoryFilter is added.
|
||||
* @param servletContext the {@link ServletContext}
|
||||
*/
|
||||
protected void beforeSessionRepositoryFilter(ServletContext servletContext) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked after the springSessionRepositoryFilter is added.
|
||||
* @param servletContext the {@link ServletContext}
|
||||
*/
|
||||
protected void afterSessionRepositoryFilter(ServletContext servletContext) {
|
||||
/**
|
||||
* Invoked after the springSessionRepositoryFilter is added.
|
||||
* @param servletContext the {@link ServletContext}
|
||||
*/
|
||||
protected void afterSessionRepositoryFilter(ServletContext servletContext) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link DispatcherType} for the springSessionRepositoryFilter.
|
||||
* @return the {@link DispatcherType} for the filter
|
||||
*/
|
||||
protected EnumSet<DispatcherType> getSessionDispatcherTypes() {
|
||||
return EnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR, DispatcherType.ASYNC);
|
||||
}
|
||||
/**
|
||||
* Get the {@link DispatcherType} for the springSessionRepositoryFilter.
|
||||
* @return the {@link DispatcherType} for the filter
|
||||
*/
|
||||
protected EnumSet<DispatcherType> getSessionDispatcherTypes() {
|
||||
return EnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR, DispatcherType.ASYNC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the springSessionRepositoryFilter should be marked as supporting
|
||||
* asynch. Default is true.
|
||||
*
|
||||
* @return true if springSessionRepositoryFilter should be marked as supporting
|
||||
* asynch
|
||||
*/
|
||||
protected boolean isAsyncSessionSupported() {
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Determine if the springSessionRepositoryFilter should be marked as supporting
|
||||
* asynch. Default is true.
|
||||
*
|
||||
* @return true if springSessionRepositoryFilter should be marked as supporting
|
||||
* asynch
|
||||
*/
|
||||
protected boolean isAsyncSessionSupported() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 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
|
||||
@@ -151,240 +151,240 @@ import org.springframework.session.Session;
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public final class CookieHttpSessionStrategy implements MultiHttpSessionStrategy, HttpSessionManager {
|
||||
static final String DEFAULT_ALIAS = "0";
|
||||
static final String DEFAULT_ALIAS = "0";
|
||||
|
||||
static final String DEFAULT_SESSION_ALIAS_PARAM_NAME = "_s";
|
||||
static final String DEFAULT_SESSION_ALIAS_PARAM_NAME = "_s";
|
||||
|
||||
private Pattern ALIAS_PATTERN = Pattern.compile("^[\\w-]{1,50}$");
|
||||
private Pattern ALIAS_PATTERN = Pattern.compile("^[\\w-]{1,50}$");
|
||||
|
||||
private String cookieName = "SESSION";
|
||||
private String cookieName = "SESSION";
|
||||
|
||||
private String sessionParam = DEFAULT_SESSION_ALIAS_PARAM_NAME;
|
||||
private String sessionParam = DEFAULT_SESSION_ALIAS_PARAM_NAME;
|
||||
|
||||
public String getRequestedSessionId(HttpServletRequest request) {
|
||||
Map<String,String> sessionIds = getSessionIds(request);
|
||||
String sessionAlias = getCurrentSessionAlias(request);
|
||||
return sessionIds.get(sessionAlias);
|
||||
}
|
||||
public String getRequestedSessionId(HttpServletRequest request) {
|
||||
Map<String,String> sessionIds = getSessionIds(request);
|
||||
String sessionAlias = getCurrentSessionAlias(request);
|
||||
return sessionIds.get(sessionAlias);
|
||||
}
|
||||
|
||||
public String getCurrentSessionAlias(HttpServletRequest request) {
|
||||
if(sessionParam == null) {
|
||||
return DEFAULT_ALIAS;
|
||||
}
|
||||
String u = request.getParameter(sessionParam);
|
||||
if(u == null) {
|
||||
return DEFAULT_ALIAS;
|
||||
}
|
||||
if(!ALIAS_PATTERN.matcher(u).matches()) {
|
||||
return DEFAULT_ALIAS;
|
||||
}
|
||||
return u;
|
||||
}
|
||||
public String getCurrentSessionAlias(HttpServletRequest request) {
|
||||
if(sessionParam == null) {
|
||||
return DEFAULT_ALIAS;
|
||||
}
|
||||
String u = request.getParameter(sessionParam);
|
||||
if(u == null) {
|
||||
return DEFAULT_ALIAS;
|
||||
}
|
||||
if(!ALIAS_PATTERN.matcher(u).matches()) {
|
||||
return DEFAULT_ALIAS;
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
public String getNewSessionAlias(HttpServletRequest request) {
|
||||
Set<String> sessionAliases = getSessionIds(request).keySet();
|
||||
if(sessionAliases.isEmpty()) {
|
||||
return DEFAULT_ALIAS;
|
||||
}
|
||||
long lastAlias = Long.decode(DEFAULT_ALIAS);
|
||||
for(String alias : sessionAliases) {
|
||||
long selectedAlias = safeParse(alias);
|
||||
if(selectedAlias > lastAlias) {
|
||||
lastAlias = selectedAlias;
|
||||
}
|
||||
}
|
||||
return Long.toHexString(lastAlias + 1);
|
||||
}
|
||||
public String getNewSessionAlias(HttpServletRequest request) {
|
||||
Set<String> sessionAliases = getSessionIds(request).keySet();
|
||||
if(sessionAliases.isEmpty()) {
|
||||
return DEFAULT_ALIAS;
|
||||
}
|
||||
long lastAlias = Long.decode(DEFAULT_ALIAS);
|
||||
for(String alias : sessionAliases) {
|
||||
long selectedAlias = safeParse(alias);
|
||||
if(selectedAlias > lastAlias) {
|
||||
lastAlias = selectedAlias;
|
||||
}
|
||||
}
|
||||
return Long.toHexString(lastAlias + 1);
|
||||
}
|
||||
|
||||
private long safeParse(String hex) {
|
||||
try {
|
||||
return Long.decode("0x" + hex);
|
||||
} catch(NumberFormatException notNumber) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
private long safeParse(String hex) {
|
||||
try {
|
||||
return Long.decode("0x" + hex);
|
||||
} catch(NumberFormatException notNumber) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void onNewSession(Session session, HttpServletRequest request, HttpServletResponse response) {
|
||||
Map<String,String> sessionIds = getSessionIds(request);
|
||||
String sessionAlias = getCurrentSessionAlias(request);
|
||||
sessionIds.put(sessionAlias, session.getId());
|
||||
Cookie sessionCookie = createSessionCookie(request, sessionIds);
|
||||
response.addCookie(sessionCookie);
|
||||
}
|
||||
public void onNewSession(Session session, HttpServletRequest request, HttpServletResponse response) {
|
||||
Map<String,String> sessionIds = getSessionIds(request);
|
||||
String sessionAlias = getCurrentSessionAlias(request);
|
||||
sessionIds.put(sessionAlias, session.getId());
|
||||
Cookie sessionCookie = createSessionCookie(request, sessionIds);
|
||||
response.addCookie(sessionCookie);
|
||||
}
|
||||
|
||||
private Cookie createSessionCookie(HttpServletRequest request,
|
||||
Map<String, String> sessionIds) {
|
||||
Cookie sessionCookie = new Cookie(cookieName,"");
|
||||
sessionCookie.setHttpOnly(true);
|
||||
sessionCookie.setSecure(request.isSecure());
|
||||
sessionCookie.setPath(cookiePath(request));
|
||||
// TODO set domain?
|
||||
private Cookie createSessionCookie(HttpServletRequest request,
|
||||
Map<String, String> sessionIds) {
|
||||
Cookie sessionCookie = new Cookie(cookieName,"");
|
||||
sessionCookie.setHttpOnly(true);
|
||||
sessionCookie.setSecure(request.isSecure());
|
||||
sessionCookie.setPath(cookiePath(request));
|
||||
// TODO set domain?
|
||||
|
||||
if(sessionIds.isEmpty()) {
|
||||
sessionCookie.setMaxAge(0);
|
||||
return sessionCookie;
|
||||
}
|
||||
if(sessionIds.isEmpty()) {
|
||||
sessionCookie.setMaxAge(0);
|
||||
return sessionCookie;
|
||||
}
|
||||
|
||||
if(sessionIds.size() == 1) {
|
||||
String cookieValue = sessionIds.values().iterator().next();
|
||||
sessionCookie.setValue(cookieValue);
|
||||
return sessionCookie;
|
||||
}
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
for(Map.Entry<String,String> entry : sessionIds.entrySet()) {
|
||||
String alias = entry.getKey();
|
||||
String id = entry.getValue();
|
||||
if(sessionIds.size() == 1) {
|
||||
String cookieValue = sessionIds.values().iterator().next();
|
||||
sessionCookie.setValue(cookieValue);
|
||||
return sessionCookie;
|
||||
}
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
for(Map.Entry<String,String> entry : sessionIds.entrySet()) {
|
||||
String alias = entry.getKey();
|
||||
String id = entry.getValue();
|
||||
|
||||
buffer.append(alias);
|
||||
buffer.append(" ");
|
||||
buffer.append(id);
|
||||
buffer.append(" ");
|
||||
}
|
||||
buffer.deleteCharAt(buffer.length()-1);
|
||||
buffer.append(alias);
|
||||
buffer.append(" ");
|
||||
buffer.append(id);
|
||||
buffer.append(" ");
|
||||
}
|
||||
buffer.deleteCharAt(buffer.length()-1);
|
||||
|
||||
sessionCookie.setValue(buffer.toString());
|
||||
return sessionCookie;
|
||||
}
|
||||
sessionCookie.setValue(buffer.toString());
|
||||
return sessionCookie;
|
||||
}
|
||||
|
||||
public void onInvalidateSession(HttpServletRequest request, HttpServletResponse response) {
|
||||
Map<String,String> sessionIds = getSessionIds(request);
|
||||
String requestedAlias = getCurrentSessionAlias(request);
|
||||
sessionIds.remove(requestedAlias);
|
||||
public void onInvalidateSession(HttpServletRequest request, HttpServletResponse response) {
|
||||
Map<String,String> sessionIds = getSessionIds(request);
|
||||
String requestedAlias = getCurrentSessionAlias(request);
|
||||
sessionIds.remove(requestedAlias);
|
||||
|
||||
Cookie sessionCookie = createSessionCookie(request, sessionIds);
|
||||
response.addCookie(sessionCookie);
|
||||
}
|
||||
Cookie sessionCookie = createSessionCookie(request, sessionIds);
|
||||
response.addCookie(sessionCookie);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the HTTP parameter that is used to specify the session
|
||||
* alias. If the value is null, then only a single session is supported per
|
||||
* browser.
|
||||
*
|
||||
* @param sessionAliasParamName
|
||||
* the name of the HTTP parameter used to specify the session
|
||||
* alias. If null, then ony a single session is supported per
|
||||
* browser.
|
||||
*/
|
||||
public void setSessionAliasParamName(String sessionAliasParamName) {
|
||||
this.sessionParam = sessionAliasParamName;
|
||||
}
|
||||
/**
|
||||
* Sets the name of the HTTP parameter that is used to specify the session
|
||||
* alias. If the value is null, then only a single session is supported per
|
||||
* browser.
|
||||
*
|
||||
* @param sessionAliasParamName
|
||||
* the name of the HTTP parameter used to specify the session
|
||||
* alias. If null, then ony a single session is supported per
|
||||
* browser.
|
||||
*/
|
||||
public void setSessionAliasParamName(String sessionAliasParamName) {
|
||||
this.sessionParam = sessionAliasParamName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the cookie to be used
|
||||
* @param cookieName the name of the cookie to be used
|
||||
*/
|
||||
public void setCookieName(String cookieName) {
|
||||
if(cookieName == null) {
|
||||
throw new IllegalArgumentException("cookieName cannot be null");
|
||||
}
|
||||
this.cookieName = cookieName;
|
||||
}
|
||||
/**
|
||||
* Sets the name of the cookie to be used
|
||||
* @param cookieName the name of the cookie to be used
|
||||
*/
|
||||
public void setCookieName(String cookieName) {
|
||||
if(cookieName == null) {
|
||||
throw new IllegalArgumentException("cookieName cannot be null");
|
||||
}
|
||||
this.cookieName = cookieName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the first cookie with the given name. Note that multiple
|
||||
* cookies can have the same name but different paths or domains.
|
||||
* @param request current servlet request
|
||||
* @param name cookie name
|
||||
* @return the first cookie with the given name, or {@code null} if none is found
|
||||
*/
|
||||
private static Cookie getCookie(HttpServletRequest request, String name) {
|
||||
if(request == null) {
|
||||
throw new IllegalArgumentException("request cannot be null");
|
||||
}
|
||||
Cookie cookies[] = request.getCookies();
|
||||
if (cookies != null) {
|
||||
for (Cookie cookie : cookies) {
|
||||
if (name.equals(cookie.getName())) {
|
||||
return cookie;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Retrieve the first cookie with the given name. Note that multiple
|
||||
* cookies can have the same name but different paths or domains.
|
||||
* @param request current servlet request
|
||||
* @param name cookie name
|
||||
* @return the first cookie with the given name, or {@code null} if none is found
|
||||
*/
|
||||
private static Cookie getCookie(HttpServletRequest request, String name) {
|
||||
if(request == null) {
|
||||
throw new IllegalArgumentException("request cannot be null");
|
||||
}
|
||||
Cookie cookies[] = request.getCookies();
|
||||
if (cookies != null) {
|
||||
for (Cookie cookie : cookies) {
|
||||
if (name.equals(cookie.getName())) {
|
||||
return cookie;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String cookiePath(HttpServletRequest request) {
|
||||
return request.getContextPath() + "/";
|
||||
}
|
||||
private static String cookiePath(HttpServletRequest request) {
|
||||
return request.getContextPath() + "/";
|
||||
}
|
||||
|
||||
public Map<String,String> getSessionIds(HttpServletRequest request) {
|
||||
Cookie session = getCookie(request, cookieName);
|
||||
String sessionCookieValue = session == null ? "" : session.getValue();
|
||||
Map<String,String> result = new LinkedHashMap<String,String>();
|
||||
StringTokenizer tokens = new StringTokenizer(sessionCookieValue, " ");
|
||||
if(tokens.countTokens() == 1) {
|
||||
result.put(DEFAULT_ALIAS, tokens.nextToken());
|
||||
return result;
|
||||
}
|
||||
while(tokens.hasMoreTokens()) {
|
||||
String alias = tokens.nextToken();
|
||||
if(!tokens.hasMoreTokens()) {
|
||||
break;
|
||||
}
|
||||
String id = tokens.nextToken();
|
||||
result.put(alias, id);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public Map<String,String> getSessionIds(HttpServletRequest request) {
|
||||
Cookie session = getCookie(request, cookieName);
|
||||
String sessionCookieValue = session == null ? "" : session.getValue();
|
||||
Map<String,String> result = new LinkedHashMap<String,String>();
|
||||
StringTokenizer tokens = new StringTokenizer(sessionCookieValue, " ");
|
||||
if(tokens.countTokens() == 1) {
|
||||
result.put(DEFAULT_ALIAS, tokens.nextToken());
|
||||
return result;
|
||||
}
|
||||
while(tokens.hasMoreTokens()) {
|
||||
String alias = tokens.nextToken();
|
||||
if(!tokens.hasMoreTokens()) {
|
||||
break;
|
||||
}
|
||||
String id = tokens.nextToken();
|
||||
result.put(alias, id);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public HttpServletRequest wrapRequest(HttpServletRequest request, HttpServletResponse response) {
|
||||
request.setAttribute(HttpSessionManager.class.getName(), this);
|
||||
return request;
|
||||
}
|
||||
public HttpServletRequest wrapRequest(HttpServletRequest request, HttpServletResponse response) {
|
||||
request.setAttribute(HttpSessionManager.class.getName(), this);
|
||||
return request;
|
||||
}
|
||||
|
||||
public HttpServletResponse wrapResponse(HttpServletRequest request, HttpServletResponse response) {
|
||||
return new MultiSessionHttpServletResponse(response, request);
|
||||
}
|
||||
public HttpServletResponse wrapResponse(HttpServletRequest request, HttpServletResponse response) {
|
||||
return new MultiSessionHttpServletResponse(response, request);
|
||||
}
|
||||
|
||||
class MultiSessionHttpServletResponse extends HttpServletResponseWrapper {
|
||||
private final HttpServletRequest request;
|
||||
class MultiSessionHttpServletResponse extends HttpServletResponseWrapper {
|
||||
private final HttpServletRequest request;
|
||||
|
||||
public MultiSessionHttpServletResponse(HttpServletResponse response, HttpServletRequest request) {
|
||||
super(response);
|
||||
this.request = request;
|
||||
}
|
||||
public MultiSessionHttpServletResponse(HttpServletResponse response, HttpServletRequest request) {
|
||||
super(response);
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String encodeRedirectURL(String url) {
|
||||
url = super.encodeRedirectURL(url);
|
||||
return CookieHttpSessionStrategy.this.encodeURL(url, getCurrentSessionAlias(request));
|
||||
}
|
||||
@Override
|
||||
public String encodeRedirectURL(String url) {
|
||||
url = super.encodeRedirectURL(url);
|
||||
return CookieHttpSessionStrategy.this.encodeURL(url, getCurrentSessionAlias(request));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String encodeURL(String url) {
|
||||
url = super.encodeURL(url);
|
||||
@Override
|
||||
public String encodeURL(String url) {
|
||||
url = super.encodeURL(url);
|
||||
|
||||
String alias = getCurrentSessionAlias(request);
|
||||
return CookieHttpSessionStrategy.this.encodeURL(url, alias);
|
||||
}
|
||||
}
|
||||
String alias = getCurrentSessionAlias(request);
|
||||
return CookieHttpSessionStrategy.this.encodeURL(url, alias);
|
||||
}
|
||||
}
|
||||
|
||||
public String encodeURL(String url, String sessionAlias) {
|
||||
String encodedSessionAlias = urlEncode(sessionAlias);
|
||||
int queryStart = url.indexOf("?");
|
||||
boolean isDefaultAlias = DEFAULT_ALIAS.equals(encodedSessionAlias);
|
||||
if(queryStart < 0) {
|
||||
return isDefaultAlias ? url : url + "?" + sessionParam + "=" + encodedSessionAlias;
|
||||
}
|
||||
String path = url.substring(0, queryStart);
|
||||
String query = url.substring(queryStart + 1, url.length());
|
||||
String replacement = isDefaultAlias ? "" : "$1"+encodedSessionAlias;
|
||||
query = query.replaceFirst( "((^|&)" + sessionParam + "=)([^&]+)?", replacement);
|
||||
if(!isDefaultAlias && url.endsWith(query)) {
|
||||
// no existing alias
|
||||
if(!(query.endsWith("&") || query.length() == 0)) {
|
||||
query += "&";
|
||||
}
|
||||
query += sessionParam + "=" + encodedSessionAlias;
|
||||
}
|
||||
public String encodeURL(String url, String sessionAlias) {
|
||||
String encodedSessionAlias = urlEncode(sessionAlias);
|
||||
int queryStart = url.indexOf("?");
|
||||
boolean isDefaultAlias = DEFAULT_ALIAS.equals(encodedSessionAlias);
|
||||
if(queryStart < 0) {
|
||||
return isDefaultAlias ? url : url + "?" + sessionParam + "=" + encodedSessionAlias;
|
||||
}
|
||||
String path = url.substring(0, queryStart);
|
||||
String query = url.substring(queryStart + 1, url.length());
|
||||
String replacement = isDefaultAlias ? "" : "$1"+encodedSessionAlias;
|
||||
query = query.replaceFirst( "((^|&)" + sessionParam + "=)([^&]+)?", replacement);
|
||||
if(!isDefaultAlias && url.endsWith(query)) {
|
||||
// no existing alias
|
||||
if(!(query.endsWith("&") || query.length() == 0)) {
|
||||
query += "&";
|
||||
}
|
||||
query += sessionParam + "=" + encodedSessionAlias;
|
||||
}
|
||||
|
||||
return path + "?" + query;
|
||||
}
|
||||
return path + "?" + query;
|
||||
}
|
||||
|
||||
private String urlEncode(String value) {
|
||||
try {
|
||||
return URLEncoder.encode(value, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
private String urlEncode(String value) {
|
||||
try {
|
||||
return URLEncoder.encode(value, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 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
|
||||
@@ -51,27 +51,27 @@ import javax.servlet.http.HttpServletResponse;
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class HeaderHttpSessionStrategy implements HttpSessionStrategy {
|
||||
private String headerName = "x-auth-token";
|
||||
private String headerName = "x-auth-token";
|
||||
|
||||
public String getRequestedSessionId(HttpServletRequest request) {
|
||||
return request.getHeader(headerName);
|
||||
}
|
||||
public String getRequestedSessionId(HttpServletRequest request) {
|
||||
return request.getHeader(headerName);
|
||||
}
|
||||
|
||||
public void onNewSession(Session session, HttpServletRequest request, HttpServletResponse response) {
|
||||
response.setHeader(headerName, session.getId());
|
||||
}
|
||||
public void onNewSession(Session session, HttpServletRequest request, HttpServletResponse response) {
|
||||
response.setHeader(headerName, session.getId());
|
||||
}
|
||||
|
||||
public void onInvalidateSession(HttpServletRequest request, HttpServletResponse response) {
|
||||
response.setHeader(headerName, "");
|
||||
}
|
||||
public void onInvalidateSession(HttpServletRequest request, HttpServletResponse response) {
|
||||
response.setHeader(headerName, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the header to obtain the session id from. Default is "x-auth-token".
|
||||
*
|
||||
* @param headerName the name of the header to obtain the session id from.
|
||||
*/
|
||||
public void setHeaderName(String headerName) {
|
||||
Assert.notNull(headerName, "headerName cannot be null");
|
||||
this.headerName = headerName;
|
||||
}
|
||||
/**
|
||||
* The name of the header to obtain the session id from. Default is "x-auth-token".
|
||||
*
|
||||
* @param headerName the name of the header to obtain the session id from.
|
||||
*/
|
||||
public void setHeaderName(String headerName) {
|
||||
Assert.notNull(headerName, "headerName cannot be null");
|
||||
this.headerName = headerName;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -29,44 +29,44 @@ import javax.servlet.http.HttpServletRequest;
|
||||
*/
|
||||
public interface HttpSessionManager {
|
||||
|
||||
/**
|
||||
* Gets the current session's alias from the {@link HttpServletRequest}.
|
||||
*
|
||||
* @param request the {@link HttpServletRequest} to obtain the current session's alias from.
|
||||
* @return the current sessions' alias. Cannot be null.
|
||||
*/
|
||||
String getCurrentSessionAlias(HttpServletRequest request);
|
||||
/**
|
||||
* Gets the current session's alias from the {@link HttpServletRequest}.
|
||||
*
|
||||
* @param request the {@link HttpServletRequest} to obtain the current session's alias from.
|
||||
* @return the current sessions' alias. Cannot be null.
|
||||
*/
|
||||
String getCurrentSessionAlias(HttpServletRequest request);
|
||||
|
||||
/**
|
||||
* Gets a mapping of the session alias to the session id from the
|
||||
* {@link HttpServletRequest}
|
||||
*
|
||||
* @param request the {@link HttpServletRequest} to obtain the mapping from. Cannot be null.
|
||||
* @return a mapping of the session alias to the session id from the
|
||||
* {@link HttpServletRequest}. Cannot be null.
|
||||
*/
|
||||
Map<String, String> getSessionIds(HttpServletRequest request);
|
||||
/**
|
||||
* Gets a mapping of the session alias to the session id from the
|
||||
* {@link HttpServletRequest}
|
||||
*
|
||||
* @param request the {@link HttpServletRequest} to obtain the mapping from. Cannot be null.
|
||||
* @return a mapping of the session alias to the session id from the
|
||||
* {@link HttpServletRequest}. Cannot be null.
|
||||
*/
|
||||
Map<String, String> getSessionIds(HttpServletRequest request);
|
||||
|
||||
/**
|
||||
* Provides the ability to encode the URL for a given session alias.
|
||||
*
|
||||
* @param url the url to encode.
|
||||
* @param sessionAlias the session alias to encode.
|
||||
* @return the encoded URL
|
||||
*/
|
||||
String encodeURL(String url, String sessionAlias);
|
||||
/**
|
||||
* Provides the ability to encode the URL for a given session alias.
|
||||
*
|
||||
* @param url the url to encode.
|
||||
* @param sessionAlias the session alias to encode.
|
||||
* @return the encoded URL
|
||||
*/
|
||||
String encodeURL(String url, String sessionAlias);
|
||||
|
||||
/**
|
||||
* Gets a new and unique Session alias. Typically this will be called to pass into
|
||||
* {@code HttpSessionManager#encodeURL(java.lang.String)}. For example:
|
||||
*
|
||||
* <code>
|
||||
* String newAlias = httpSessionManager.getNewSessionAlias(request);
|
||||
* String addAccountUrl = httpSessionManager.encodeURL("./", newAlias);
|
||||
* </code>
|
||||
*
|
||||
* @param request the {@link HttpServletRequest} to get a new alias from
|
||||
* @return
|
||||
*/
|
||||
String getNewSessionAlias(HttpServletRequest request);
|
||||
/**
|
||||
* Gets a new and unique Session alias. Typically this will be called to pass into
|
||||
* {@code HttpSessionManager#encodeURL(java.lang.String)}. For example:
|
||||
*
|
||||
* <code>
|
||||
* String newAlias = httpSessionManager.getNewSessionAlias(request);
|
||||
* String addAccountUrl = httpSessionManager.encodeURL("./", newAlias);
|
||||
* </code>
|
||||
*
|
||||
* @param request the {@link HttpServletRequest} to get a new alias from
|
||||
* @return
|
||||
*/
|
||||
String getNewSessionAlias(HttpServletRequest request);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 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
|
||||
@@ -28,36 +28,36 @@ import javax.servlet.http.HttpServletResponse;
|
||||
*/
|
||||
public interface HttpSessionStrategy {
|
||||
|
||||
/**
|
||||
* Obtains the requested session id from the provided {@link javax.servlet.http.HttpServletRequest}. For example,
|
||||
* the session id might come from a cookie or a request header.
|
||||
*
|
||||
* @param request the {@link javax.servlet.http.HttpServletRequest} to obtain the session id from. Cannot be null.
|
||||
* @return the {@link javax.servlet.http.HttpServletRequest} to obtain the session id from.
|
||||
*/
|
||||
String getRequestedSessionId(HttpServletRequest request);
|
||||
/**
|
||||
* Obtains the requested session id from the provided {@link javax.servlet.http.HttpServletRequest}. For example,
|
||||
* the session id might come from a cookie or a request header.
|
||||
*
|
||||
* @param request the {@link javax.servlet.http.HttpServletRequest} to obtain the session id from. Cannot be null.
|
||||
* @return the {@link javax.servlet.http.HttpServletRequest} to obtain the session id from.
|
||||
*/
|
||||
String getRequestedSessionId(HttpServletRequest request);
|
||||
|
||||
/**
|
||||
* This method is invoked when a new session is created and should inform a client what the new session id is. For
|
||||
* example, it might create a new cookie with the session id in it or set an HTTP response header with the value of
|
||||
* the new session id.
|
||||
*
|
||||
* Some implementations may wish to associate additional information to the {@link Session} at this time. For example, they
|
||||
* may wish to add the IP Address, browser headers, the username, etc to the {@link org.springframework.session.Session}.
|
||||
*
|
||||
* @param session the {@link org.springframework.session.Session} that is being sent to the client. Cannot be null.
|
||||
* @param request the {@link javax.servlet.http.HttpServletRequest} that create the new {@link org.springframework.session.Session} Cannot be null.
|
||||
* @param response the {@link javax.servlet.http.HttpServletResponse} that is associated with the {@link javax.servlet.http.HttpServletRequest} that created the new {@link org.springframework.session.Session} Cannot be null.
|
||||
*/
|
||||
void onNewSession(Session session, HttpServletRequest request, HttpServletResponse response);
|
||||
/**
|
||||
* This method is invoked when a new session is created and should inform a client what the new session id is. For
|
||||
* example, it might create a new cookie with the session id in it or set an HTTP response header with the value of
|
||||
* the new session id.
|
||||
*
|
||||
* Some implementations may wish to associate additional information to the {@link Session} at this time. For example, they
|
||||
* may wish to add the IP Address, browser headers, the username, etc to the {@link org.springframework.session.Session}.
|
||||
*
|
||||
* @param session the {@link org.springframework.session.Session} that is being sent to the client. Cannot be null.
|
||||
* @param request the {@link javax.servlet.http.HttpServletRequest} that create the new {@link org.springframework.session.Session} Cannot be null.
|
||||
* @param response the {@link javax.servlet.http.HttpServletResponse} that is associated with the {@link javax.servlet.http.HttpServletRequest} that created the new {@link org.springframework.session.Session} Cannot be null.
|
||||
*/
|
||||
void onNewSession(Session session, HttpServletRequest request, HttpServletResponse response);
|
||||
|
||||
/**
|
||||
* This method is invoked when a session is invalidated and should inform a client that the session id is no longer valid. For
|
||||
* example, it might remove a cookie with the session id in it or set an HTTP response header with an empty value indicating
|
||||
* to the client to no longer submit that session id.
|
||||
*
|
||||
* @param request the {@link javax.servlet.http.HttpServletRequest} that invalidated the {@link org.springframework.session.Session} Cannot be null.
|
||||
* @param response the {@link javax.servlet.http.HttpServletResponse} that is associated with the {@link javax.servlet.http.HttpServletRequest} that invalidated the {@link org.springframework.session.Session} Cannot be null.
|
||||
*/
|
||||
void onInvalidateSession(HttpServletRequest request, HttpServletResponse response);
|
||||
/**
|
||||
* This method is invoked when a session is invalidated and should inform a client that the session id is no longer valid. For
|
||||
* example, it might remove a cookie with the session id in it or set an HTTP response header with an empty value indicating
|
||||
* to the client to no longer submit that session id.
|
||||
*
|
||||
* @param request the {@link javax.servlet.http.HttpServletRequest} that invalidated the {@link org.springframework.session.Session} Cannot be null.
|
||||
* @param response the {@link javax.servlet.http.HttpServletResponse} that is associated with the {@link javax.servlet.http.HttpServletRequest} that invalidated the {@link org.springframework.session.Session} Cannot be null.
|
||||
*/
|
||||
void onInvalidateSession(HttpServletRequest request, HttpServletResponse response);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 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
|
||||
@@ -28,62 +28,62 @@ import java.io.IOException;
|
||||
* @author Rob Winch
|
||||
*/
|
||||
abstract class OncePerRequestFilter implements Filter {
|
||||
/**
|
||||
* Suffix that gets appended to the filter name for the
|
||||
* "already filtered" request attribute.
|
||||
*/
|
||||
public static final String ALREADY_FILTERED_SUFFIX = ".FILTERED";
|
||||
/**
|
||||
* Suffix that gets appended to the filter name for the
|
||||
* "already filtered" request attribute.
|
||||
*/
|
||||
public static final String ALREADY_FILTERED_SUFFIX = ".FILTERED";
|
||||
|
||||
private String alreadyFilteredAttributeName = getClass().getName().concat(ALREADY_FILTERED_SUFFIX);
|
||||
private String alreadyFilteredAttributeName = getClass().getName().concat(ALREADY_FILTERED_SUFFIX);
|
||||
|
||||
|
||||
/**
|
||||
* This {@code doFilter} implementation stores a request attribute for
|
||||
* "already filtered", proceeding without filtering again if the
|
||||
* attribute is already there.
|
||||
*/
|
||||
public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
/**
|
||||
* This {@code doFilter} implementation stores a request attribute for
|
||||
* "already filtered", proceeding without filtering again if the
|
||||
* attribute is already there.
|
||||
*/
|
||||
public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
|
||||
throw new ServletException("OncePerRequestFilter just supports HTTP requests");
|
||||
}
|
||||
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
||||
boolean hasAlreadyFilteredAttribute = request.getAttribute(alreadyFilteredAttributeName) != null;
|
||||
if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
|
||||
throw new ServletException("OncePerRequestFilter just supports HTTP requests");
|
||||
}
|
||||
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
||||
boolean hasAlreadyFilteredAttribute = request.getAttribute(alreadyFilteredAttributeName) != null;
|
||||
|
||||
|
||||
if (hasAlreadyFilteredAttribute) {
|
||||
if (hasAlreadyFilteredAttribute) {
|
||||
|
||||
// Proceed without invoking this filter...
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
else {
|
||||
// Do invoke this filter...
|
||||
request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);
|
||||
try {
|
||||
doFilterInternal(httpRequest, httpResponse, filterChain);
|
||||
}
|
||||
finally {
|
||||
// Remove the "already filtered" request attribute for this request.
|
||||
request.removeAttribute(alreadyFilteredAttributeName);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Proceed without invoking this filter...
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
else {
|
||||
// Do invoke this filter...
|
||||
request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);
|
||||
try {
|
||||
doFilterInternal(httpRequest, httpResponse, filterChain);
|
||||
}
|
||||
finally {
|
||||
// Remove the "already filtered" request attribute for this request.
|
||||
request.removeAttribute(alreadyFilteredAttributeName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Same contract as for {@code doFilter}, but guaranteed to be
|
||||
* just invoked once per request within a single request thread.
|
||||
* <p>Provides HttpServletRequest and HttpServletResponse arguments instead of the
|
||||
* default ServletRequest and ServletResponse ones.
|
||||
* @see Filter#doFilter
|
||||
*/
|
||||
protected abstract void doFilterInternal(
|
||||
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException;
|
||||
/**
|
||||
* Same contract as for {@code doFilter}, but guaranteed to be
|
||||
* just invoked once per request within a single request thread.
|
||||
* <p>Provides HttpServletRequest and HttpServletResponse arguments instead of the
|
||||
* default ServletRequest and ServletResponse ones.
|
||||
* @see Filter#doFilter
|
||||
*/
|
||||
protected abstract void doFilterInternal(
|
||||
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException;
|
||||
|
||||
public void init(FilterConfig config) {}
|
||||
public void init(FilterConfig config) {}
|
||||
|
||||
public void destroy() {}
|
||||
public void destroy() {}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -27,33 +27,33 @@ import javax.servlet.http.HttpServletResponse;
|
||||
*/
|
||||
public interface RequestResponsePostProcessor {
|
||||
|
||||
/**
|
||||
* Allows customizing the {@link HttpServletRequest}.
|
||||
*
|
||||
* @param request
|
||||
* the original {@link HttpServletRequest}. Cannot be null.
|
||||
* @param response
|
||||
* the original {@link HttpServletResponse}. This is NOT the
|
||||
* result of
|
||||
* {@link #wrapResponse(HttpServletRequest, HttpServletResponse)}
|
||||
* Cannot be null. .
|
||||
* @return a non-null {@link HttpServletRequest}
|
||||
*/
|
||||
HttpServletRequest wrapRequest(HttpServletRequest request,
|
||||
HttpServletResponse response);
|
||||
/**
|
||||
* Allows customizing the {@link HttpServletRequest}.
|
||||
*
|
||||
* @param request
|
||||
* the original {@link HttpServletRequest}. Cannot be null.
|
||||
* @param response
|
||||
* the original {@link HttpServletResponse}. This is NOT the
|
||||
* result of
|
||||
* {@link #wrapResponse(HttpServletRequest, HttpServletResponse)}
|
||||
* Cannot be null. .
|
||||
* @return a non-null {@link HttpServletRequest}
|
||||
*/
|
||||
HttpServletRequest wrapRequest(HttpServletRequest request,
|
||||
HttpServletResponse response);
|
||||
|
||||
/**
|
||||
* Allows customizing the {@link HttpServletResponse}.
|
||||
*
|
||||
* @param request
|
||||
* the original {@link HttpServletRequest}. This is NOT the
|
||||
* result of
|
||||
* {@link #wrapRequest(HttpServletRequest, HttpServletResponse)}.
|
||||
* Cannot be null.
|
||||
* @param response
|
||||
* the original {@link HttpServletResponse}. Cannot be null.
|
||||
* @return a non-null {@link HttpServletResponse}
|
||||
*/
|
||||
HttpServletResponse wrapResponse(HttpServletRequest request,
|
||||
HttpServletResponse response);
|
||||
/**
|
||||
* Allows customizing the {@link HttpServletResponse}.
|
||||
*
|
||||
* @param request
|
||||
* the original {@link HttpServletRequest}. This is NOT the
|
||||
* result of
|
||||
* {@link #wrapRequest(HttpServletRequest, HttpServletResponse)}.
|
||||
* Cannot be null.
|
||||
* @param response
|
||||
* the original {@link HttpServletResponse}. Cannot be null.
|
||||
* @return a non-null {@link HttpServletResponse}
|
||||
*/
|
||||
HttpServletResponse wrapResponse(HttpServletRequest request,
|
||||
HttpServletResponse response);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 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
|
||||
@@ -54,342 +54,342 @@ import java.util.Set;
|
||||
*/
|
||||
@Order(SessionRepositoryFilter.DEFAULT_ORDER)
|
||||
public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerRequestFilter {
|
||||
public static final String SESSION_REPOSITORY_ATTR = SessionRepository.class.getName();
|
||||
public static final String SESSION_REPOSITORY_ATTR = SessionRepository.class.getName();
|
||||
|
||||
public static final int DEFAULT_ORDER = Integer.MIN_VALUE + 50;
|
||||
public static final int DEFAULT_ORDER = Integer.MIN_VALUE + 50;
|
||||
|
||||
private final SessionRepository<S> sessionRepository;
|
||||
private final SessionRepository<S> sessionRepository;
|
||||
|
||||
private MultiHttpSessionStrategy httpSessionStrategy = new CookieHttpSessionStrategy();
|
||||
private MultiHttpSessionStrategy httpSessionStrategy = new CookieHttpSessionStrategy();
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param sessionRepository the <code>SessionRepository</code> to use. Cannot be null.
|
||||
*/
|
||||
public SessionRepositoryFilter(SessionRepository<S> sessionRepository) {
|
||||
if(sessionRepository == null) {
|
||||
throw new IllegalArgumentException("SessionRepository cannot be null");
|
||||
}
|
||||
this.sessionRepository = sessionRepository;
|
||||
}
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param sessionRepository the <code>SessionRepository</code> to use. Cannot be null.
|
||||
*/
|
||||
public SessionRepositoryFilter(SessionRepository<S> sessionRepository) {
|
||||
if(sessionRepository == null) {
|
||||
throw new IllegalArgumentException("SessionRepository cannot be null");
|
||||
}
|
||||
this.sessionRepository = sessionRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link HttpSessionStrategy} to be used. The default is a {@link CookieHttpSessionStrategy}.
|
||||
*
|
||||
* @param httpSessionStrategy the {@link HttpSessionStrategy} to use. Cannot be null.
|
||||
*/
|
||||
public void setHttpSessionStrategy(HttpSessionStrategy httpSessionStrategy) {
|
||||
if(sessionRepository == null) {
|
||||
throw new IllegalArgumentException("httpSessionIdStrategy cannot be null");
|
||||
}
|
||||
this.httpSessionStrategy = new MultiHttpSessionStrategyAdapter(httpSessionStrategy);
|
||||
}
|
||||
/**
|
||||
* Sets the {@link HttpSessionStrategy} to be used. The default is a {@link CookieHttpSessionStrategy}.
|
||||
*
|
||||
* @param httpSessionStrategy the {@link HttpSessionStrategy} to use. Cannot be null.
|
||||
*/
|
||||
public void setHttpSessionStrategy(HttpSessionStrategy httpSessionStrategy) {
|
||||
if(sessionRepository == null) {
|
||||
throw new IllegalArgumentException("httpSessionIdStrategy cannot be null");
|
||||
}
|
||||
this.httpSessionStrategy = new MultiHttpSessionStrategyAdapter(httpSessionStrategy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link MultiHttpSessionStrategy} to be used. The default is a {@link CookieHttpSessionStrategy}.
|
||||
*
|
||||
* @param httpSessionStrategy the {@link MultiHttpSessionStrategy} to use. Cannot be null.
|
||||
*/
|
||||
public void setHttpSessionStrategy(MultiHttpSessionStrategy httpSessionStrategy) {
|
||||
if(sessionRepository == null) {
|
||||
throw new IllegalArgumentException("httpSessionIdStrategy cannot be null");
|
||||
}
|
||||
this.httpSessionStrategy = httpSessionStrategy;
|
||||
}
|
||||
/**
|
||||
* Sets the {@link MultiHttpSessionStrategy} to be used. The default is a {@link CookieHttpSessionStrategy}.
|
||||
*
|
||||
* @param httpSessionStrategy the {@link MultiHttpSessionStrategy} to use. Cannot be null.
|
||||
*/
|
||||
public void setHttpSessionStrategy(MultiHttpSessionStrategy httpSessionStrategy) {
|
||||
if(sessionRepository == null) {
|
||||
throw new IllegalArgumentException("httpSessionIdStrategy cannot be null");
|
||||
}
|
||||
this.httpSessionStrategy = httpSessionStrategy;
|
||||
}
|
||||
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||
request.setAttribute(SESSION_REPOSITORY_ATTR, sessionRepository);
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||
request.setAttribute(SESSION_REPOSITORY_ATTR, sessionRepository);
|
||||
|
||||
SessionRepositoryRequestWrapper wrappedRequest = new SessionRepositoryRequestWrapper(request, response);
|
||||
SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryResponseWrapper(wrappedRequest,response);
|
||||
SessionRepositoryRequestWrapper wrappedRequest = new SessionRepositoryRequestWrapper(request, response);
|
||||
SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryResponseWrapper(wrappedRequest,response);
|
||||
|
||||
HttpServletRequest strategyRequest = httpSessionStrategy.wrapRequest(wrappedRequest, wrappedResponse);
|
||||
HttpServletResponse strategyResponse = httpSessionStrategy.wrapResponse(wrappedRequest, wrappedResponse);
|
||||
HttpServletRequest strategyRequest = httpSessionStrategy.wrapRequest(wrappedRequest, wrappedResponse);
|
||||
HttpServletResponse strategyResponse = httpSessionStrategy.wrapResponse(wrappedRequest, wrappedResponse);
|
||||
|
||||
try {
|
||||
filterChain.doFilter(strategyRequest, strategyResponse);
|
||||
} finally {
|
||||
wrappedRequest.commitSession();
|
||||
}
|
||||
}
|
||||
try {
|
||||
filterChain.doFilter(strategyRequest, strategyResponse);
|
||||
} finally {
|
||||
wrappedRequest.commitSession();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows ensuring that the session is saved if the response is committed.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 1.0
|
||||
*/
|
||||
private final class SessionRepositoryResponseWrapper extends OnCommittedResponseWrapper {
|
||||
/**
|
||||
* Allows ensuring that the session is saved if the response is committed.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 1.0
|
||||
*/
|
||||
private final class SessionRepositoryResponseWrapper extends OnCommittedResponseWrapper {
|
||||
|
||||
private final SessionRepositoryRequestWrapper request;
|
||||
private final SessionRepositoryRequestWrapper request;
|
||||
|
||||
/**
|
||||
* @param response the response to be wrapped
|
||||
*/
|
||||
public SessionRepositoryResponseWrapper(SessionRepositoryRequestWrapper request, HttpServletResponse response) {
|
||||
super(response);
|
||||
if(request == null) {
|
||||
throw new IllegalArgumentException("request cannot be null");
|
||||
}
|
||||
this.request = request;
|
||||
}
|
||||
/**
|
||||
* @param response the response to be wrapped
|
||||
*/
|
||||
public SessionRepositoryResponseWrapper(SessionRepositoryRequestWrapper request, HttpServletResponse response) {
|
||||
super(response);
|
||||
if(request == null) {
|
||||
throw new IllegalArgumentException("request cannot be null");
|
||||
}
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResponseCommitted() {
|
||||
request.commitSession();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void onResponseCommitted() {
|
||||
request.commitSession();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link javax.servlet.http.HttpServletRequest} that retrieves the {@link javax.servlet.http.HttpSession} using a
|
||||
* {@link org.springframework.session.SessionRepository}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 1.0
|
||||
*/
|
||||
private final class SessionRepositoryRequestWrapper extends HttpServletRequestWrapper {
|
||||
private HttpSessionWrapper currentSession;
|
||||
private Boolean requestedSessionIdValid;
|
||||
private final HttpServletResponse response;
|
||||
/**
|
||||
* A {@link javax.servlet.http.HttpServletRequest} that retrieves the {@link javax.servlet.http.HttpSession} using a
|
||||
* {@link org.springframework.session.SessionRepository}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 1.0
|
||||
*/
|
||||
private final class SessionRepositoryRequestWrapper extends HttpServletRequestWrapper {
|
||||
private HttpSessionWrapper currentSession;
|
||||
private Boolean requestedSessionIdValid;
|
||||
private final HttpServletResponse response;
|
||||
|
||||
private SessionRepositoryRequestWrapper(HttpServletRequest request, HttpServletResponse response) {
|
||||
super(request);
|
||||
this.response = response;
|
||||
}
|
||||
private SessionRepositoryRequestWrapper(HttpServletRequest request, HttpServletResponse response) {
|
||||
super(request);
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the HttpSessionStrategy to write the session id tot he response and persist the Session.
|
||||
*/
|
||||
private void commitSession() {
|
||||
HttpSessionWrapper wrappedSession = currentSession;
|
||||
if(wrappedSession == null) {
|
||||
if(isInvalidateClientSession()) {
|
||||
httpSessionStrategy.onInvalidateSession(this, response);
|
||||
}
|
||||
} else {
|
||||
S session = wrappedSession.session;
|
||||
sessionRepository.save(session);
|
||||
if(!isRequestedSessionIdValid() || !session.getId().equals(getRequestedSessionId())) {
|
||||
httpSessionStrategy.onNewSession(session, this, response);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Uses the HttpSessionStrategy to write the session id tot he response and persist the Session.
|
||||
*/
|
||||
private void commitSession() {
|
||||
HttpSessionWrapper wrappedSession = currentSession;
|
||||
if(wrappedSession == null) {
|
||||
if(isInvalidateClientSession()) {
|
||||
httpSessionStrategy.onInvalidateSession(this, response);
|
||||
}
|
||||
} else {
|
||||
S session = wrappedSession.session;
|
||||
sessionRepository.save(session);
|
||||
if(!isRequestedSessionIdValid() || !session.getId().equals(getRequestedSessionId())) {
|
||||
httpSessionStrategy.onNewSession(session, this, response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRequestedSessionIdValid() {
|
||||
if(requestedSessionIdValid == null) {
|
||||
String sessionId = getRequestedSessionId();
|
||||
S session = sessionId == null ? null : sessionRepository.getSession(sessionId);
|
||||
return isRequestedSessionIdValid(session);
|
||||
}
|
||||
public boolean isRequestedSessionIdValid() {
|
||||
if(requestedSessionIdValid == null) {
|
||||
String sessionId = getRequestedSessionId();
|
||||
S session = sessionId == null ? null : sessionRepository.getSession(sessionId);
|
||||
return isRequestedSessionIdValid(session);
|
||||
}
|
||||
|
||||
return requestedSessionIdValid;
|
||||
}
|
||||
return requestedSessionIdValid;
|
||||
}
|
||||
|
||||
private boolean isRequestedSessionIdValid(S session) {
|
||||
if(requestedSessionIdValid == null) {
|
||||
requestedSessionIdValid = session != null;
|
||||
}
|
||||
return requestedSessionIdValid;
|
||||
}
|
||||
private boolean isRequestedSessionIdValid(S session) {
|
||||
if(requestedSessionIdValid == null) {
|
||||
requestedSessionIdValid = session != null;
|
||||
}
|
||||
return requestedSessionIdValid;
|
||||
}
|
||||
|
||||
private boolean isInvalidateClientSession() {
|
||||
return currentSession == null && isRequestedSessionIdValid();
|
||||
}
|
||||
private boolean isInvalidateClientSession() {
|
||||
return currentSession == null && isRequestedSessionIdValid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpSession getSession(boolean create) {
|
||||
if(currentSession != null) {
|
||||
return currentSession;
|
||||
}
|
||||
String requestedSessionId = getRequestedSessionId();
|
||||
if(requestedSessionId != null) {
|
||||
S session = sessionRepository.getSession(requestedSessionId);
|
||||
if(session != null) {
|
||||
this.requestedSessionIdValid = true;
|
||||
currentSession = new HttpSessionWrapper(session, getServletContext());
|
||||
currentSession.setNew(false);
|
||||
return currentSession;
|
||||
}
|
||||
}
|
||||
if(!create) {
|
||||
return null;
|
||||
}
|
||||
S session = sessionRepository.createSession();
|
||||
currentSession = new HttpSessionWrapper(session, getServletContext());
|
||||
return currentSession;
|
||||
}
|
||||
@Override
|
||||
public HttpSession getSession(boolean create) {
|
||||
if(currentSession != null) {
|
||||
return currentSession;
|
||||
}
|
||||
String requestedSessionId = getRequestedSessionId();
|
||||
if(requestedSessionId != null) {
|
||||
S session = sessionRepository.getSession(requestedSessionId);
|
||||
if(session != null) {
|
||||
this.requestedSessionIdValid = true;
|
||||
currentSession = new HttpSessionWrapper(session, getServletContext());
|
||||
currentSession.setNew(false);
|
||||
return currentSession;
|
||||
}
|
||||
}
|
||||
if(!create) {
|
||||
return null;
|
||||
}
|
||||
S session = sessionRepository.createSession();
|
||||
currentSession = new HttpSessionWrapper(session, getServletContext());
|
||||
return currentSession;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpSession getSession() {
|
||||
return getSession(true);
|
||||
}
|
||||
@Override
|
||||
public HttpSession getSession() {
|
||||
return getSession(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRequestedSessionId() {
|
||||
return httpSessionStrategy.getRequestedSessionId(this);
|
||||
}
|
||||
@Override
|
||||
public String getRequestedSessionId() {
|
||||
return httpSessionStrategy.getRequestedSessionId(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows creating an HttpSession from a Session instance.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 1.0
|
||||
*/
|
||||
private final class HttpSessionWrapper implements HttpSession {
|
||||
private final S session;
|
||||
private final ServletContext servletContext;
|
||||
private boolean invalidated;
|
||||
private boolean old;
|
||||
/**
|
||||
* Allows creating an HttpSession from a Session instance.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 1.0
|
||||
*/
|
||||
private final class HttpSessionWrapper implements HttpSession {
|
||||
private final S session;
|
||||
private final ServletContext servletContext;
|
||||
private boolean invalidated;
|
||||
private boolean old;
|
||||
|
||||
public HttpSessionWrapper(S session, ServletContext servletContext) {
|
||||
this.session = session;
|
||||
this.servletContext = servletContext;
|
||||
}
|
||||
public HttpSessionWrapper(S session, ServletContext servletContext) {
|
||||
this.session = session;
|
||||
this.servletContext = servletContext;
|
||||
}
|
||||
|
||||
public long getCreationTime() {
|
||||
checkState();
|
||||
return session.getCreationTime();
|
||||
}
|
||||
public long getCreationTime() {
|
||||
checkState();
|
||||
return session.getCreationTime();
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return session.getId();
|
||||
}
|
||||
public String getId() {
|
||||
return session.getId();
|
||||
}
|
||||
|
||||
public long getLastAccessedTime() {
|
||||
checkState();
|
||||
return session.getLastAccessedTime();
|
||||
}
|
||||
public long getLastAccessedTime() {
|
||||
checkState();
|
||||
return session.getLastAccessedTime();
|
||||
}
|
||||
|
||||
public ServletContext getServletContext() {
|
||||
return servletContext;
|
||||
}
|
||||
public ServletContext getServletContext() {
|
||||
return servletContext;
|
||||
}
|
||||
|
||||
public void setMaxInactiveInterval(int interval) {
|
||||
session.setMaxInactiveIntervalInSeconds(interval);
|
||||
}
|
||||
public void setMaxInactiveInterval(int interval) {
|
||||
session.setMaxInactiveIntervalInSeconds(interval);
|
||||
}
|
||||
|
||||
public int getMaxInactiveInterval() {
|
||||
return session.getMaxInactiveIntervalInSeconds();
|
||||
}
|
||||
public int getMaxInactiveInterval() {
|
||||
return session.getMaxInactiveIntervalInSeconds();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public HttpSessionContext getSessionContext() {
|
||||
return NOOP_SESSION_CONTEXT;
|
||||
}
|
||||
@SuppressWarnings("deprecation")
|
||||
public HttpSessionContext getSessionContext() {
|
||||
return NOOP_SESSION_CONTEXT;
|
||||
}
|
||||
|
||||
public Object getAttribute(String name) {
|
||||
checkState();
|
||||
return session.getAttribute(name);
|
||||
}
|
||||
public Object getAttribute(String name) {
|
||||
checkState();
|
||||
return session.getAttribute(name);
|
||||
}
|
||||
|
||||
public Object getValue(String name) {
|
||||
return getAttribute(name);
|
||||
}
|
||||
public Object getValue(String name) {
|
||||
return getAttribute(name);
|
||||
}
|
||||
|
||||
public Enumeration<String> getAttributeNames() {
|
||||
checkState();
|
||||
return Collections.enumeration(session.getAttributeNames());
|
||||
}
|
||||
public Enumeration<String> getAttributeNames() {
|
||||
checkState();
|
||||
return Collections.enumeration(session.getAttributeNames());
|
||||
}
|
||||
|
||||
public String[] getValueNames() {
|
||||
checkState();
|
||||
Set<String> attrs = session.getAttributeNames();
|
||||
return attrs.toArray(new String[0]);
|
||||
}
|
||||
public String[] getValueNames() {
|
||||
checkState();
|
||||
Set<String> attrs = session.getAttributeNames();
|
||||
return attrs.toArray(new String[0]);
|
||||
}
|
||||
|
||||
public void setAttribute(String name, Object value) {
|
||||
checkState();
|
||||
session.setAttribute(name, value);
|
||||
}
|
||||
public void setAttribute(String name, Object value) {
|
||||
checkState();
|
||||
session.setAttribute(name, value);
|
||||
}
|
||||
|
||||
public void putValue(String name, Object value) {
|
||||
setAttribute(name, value);
|
||||
}
|
||||
public void putValue(String name, Object value) {
|
||||
setAttribute(name, value);
|
||||
}
|
||||
|
||||
public void removeAttribute(String name) {
|
||||
checkState();
|
||||
session.removeAttribute(name);
|
||||
}
|
||||
public void removeAttribute(String name) {
|
||||
checkState();
|
||||
session.removeAttribute(name);
|
||||
}
|
||||
|
||||
public void removeValue(String name) {
|
||||
removeAttribute(name);
|
||||
}
|
||||
public void removeValue(String name) {
|
||||
removeAttribute(name);
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
checkState();
|
||||
this.invalidated = true;
|
||||
currentSession = null;
|
||||
sessionRepository.delete(getId());
|
||||
}
|
||||
public void invalidate() {
|
||||
checkState();
|
||||
this.invalidated = true;
|
||||
currentSession = null;
|
||||
sessionRepository.delete(getId());
|
||||
}
|
||||
|
||||
public void setNew(boolean isNew) {
|
||||
this.old = !isNew;
|
||||
}
|
||||
public void setNew(boolean isNew) {
|
||||
this.old = !isNew;
|
||||
}
|
||||
|
||||
public boolean isNew() {
|
||||
checkState();
|
||||
return !old;
|
||||
}
|
||||
public boolean isNew() {
|
||||
checkState();
|
||||
return !old;
|
||||
}
|
||||
|
||||
private void checkState() {
|
||||
if(invalidated) {
|
||||
throw new IllegalStateException("The HttpSession has already be invalidated.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private void checkState() {
|
||||
if(invalidated) {
|
||||
throw new IllegalStateException("The HttpSession has already be invalidated.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private static final HttpSessionContext NOOP_SESSION_CONTEXT = new HttpSessionContext() {
|
||||
public HttpSession getSession(String sessionId) {
|
||||
return null;
|
||||
}
|
||||
@SuppressWarnings("deprecation")
|
||||
private static final HttpSessionContext NOOP_SESSION_CONTEXT = new HttpSessionContext() {
|
||||
public HttpSession getSession(String sessionId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Enumeration<String> getIds() {
|
||||
return EMPTY_ENUMERATION;
|
||||
}
|
||||
};
|
||||
public Enumeration<String> getIds() {
|
||||
return EMPTY_ENUMERATION;
|
||||
}
|
||||
};
|
||||
|
||||
private static final Enumeration<String> EMPTY_ENUMERATION = new Enumeration<String>() {
|
||||
public boolean hasMoreElements() {
|
||||
return false;
|
||||
}
|
||||
private static final Enumeration<String> EMPTY_ENUMERATION = new Enumeration<String>() {
|
||||
public boolean hasMoreElements() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String nextElement() {
|
||||
throw new NoSuchElementException("a");
|
||||
}
|
||||
};
|
||||
public String nextElement() {
|
||||
throw new NoSuchElementException("a");
|
||||
}
|
||||
};
|
||||
|
||||
static class MultiHttpSessionStrategyAdapter implements MultiHttpSessionStrategy {
|
||||
private HttpSessionStrategy delegate;
|
||||
static class MultiHttpSessionStrategyAdapter implements MultiHttpSessionStrategy {
|
||||
private HttpSessionStrategy delegate;
|
||||
|
||||
public MultiHttpSessionStrategyAdapter(HttpSessionStrategy delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
public MultiHttpSessionStrategyAdapter(HttpSessionStrategy delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public String getRequestedSessionId(HttpServletRequest request) {
|
||||
return delegate.getRequestedSessionId(request);
|
||||
}
|
||||
public String getRequestedSessionId(HttpServletRequest request) {
|
||||
return delegate.getRequestedSessionId(request);
|
||||
}
|
||||
|
||||
public void onNewSession(Session session, HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
delegate.onNewSession(session, request, response);
|
||||
}
|
||||
public void onNewSession(Session session, HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
delegate.onNewSession(session, request, response);
|
||||
}
|
||||
|
||||
public void onInvalidateSession(HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
delegate.onInvalidateSession(request, response);
|
||||
}
|
||||
public void onInvalidateSession(HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
delegate.onInvalidateSession(request, response);
|
||||
}
|
||||
|
||||
public HttpServletRequest wrapRequest(HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
return request;
|
||||
}
|
||||
public HttpServletRequest wrapRequest(HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
return request;
|
||||
}
|
||||
|
||||
public HttpServletResponse wrapResponse(HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
return response;
|
||||
}
|
||||
}
|
||||
public HttpServletResponse wrapResponse(HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -74,71 +74,71 @@ import org.springframework.web.socket.server.HandshakeInterceptor;
|
||||
*/
|
||||
public abstract class AbstractSessionWebSocketMessageBrokerConfigurer<S extends ExpiringSession> extends AbstractWebSocketMessageBrokerConfigurer {
|
||||
|
||||
@Autowired
|
||||
@SuppressWarnings("rawtypes")
|
||||
private SessionRepository sessionRepository;
|
||||
@Autowired
|
||||
@SuppressWarnings("rawtypes")
|
||||
private SessionRepository sessionRepository;
|
||||
|
||||
@Autowired
|
||||
private ApplicationEventPublisher eventPublisher;
|
||||
@Autowired
|
||||
private ApplicationEventPublisher eventPublisher;
|
||||
|
||||
@Override
|
||||
public void configureClientInboundChannel(ChannelRegistration registration) {
|
||||
registration.setInterceptors(sessionRepositoryInterceptor());
|
||||
}
|
||||
@Override
|
||||
public void configureClientInboundChannel(ChannelRegistration registration) {
|
||||
registration.setInterceptors(sessionRepositoryInterceptor());
|
||||
}
|
||||
|
||||
public final void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||
configureStompEndpoints(new SessionStompEndpointRegistry(registry, sessionRepositoryInterceptor()));
|
||||
}
|
||||
public final void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||
configureStompEndpoints(new SessionStompEndpointRegistry(registry, sessionRepositoryInterceptor()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register STOMP endpoints mapping each to a specific URL and (optionally)
|
||||
* enabling and configuring SockJS fallback options with a
|
||||
* {@link SessionRepositoryMessageInterceptor} automatically added as an
|
||||
* interceptor.
|
||||
*
|
||||
* @param registry
|
||||
* the {@link StompEndpointRegistry} which automatically has a
|
||||
* {@link SessionRepositoryMessageInterceptor} added to it.
|
||||
*/
|
||||
protected abstract void configureStompEndpoints(StompEndpointRegistry registry);
|
||||
/**
|
||||
* Register STOMP endpoints mapping each to a specific URL and (optionally)
|
||||
* enabling and configuring SockJS fallback options with a
|
||||
* {@link SessionRepositoryMessageInterceptor} automatically added as an
|
||||
* interceptor.
|
||||
*
|
||||
* @param registry
|
||||
* the {@link StompEndpointRegistry} which automatically has a
|
||||
* {@link SessionRepositoryMessageInterceptor} added to it.
|
||||
*/
|
||||
protected abstract void configureStompEndpoints(StompEndpointRegistry registry);
|
||||
|
||||
@Override
|
||||
public void configureWebSocketTransport(
|
||||
WebSocketTransportRegistration registration) {
|
||||
registration.addDecoratorFactory(wsConnectHandlerDecoratorFactory());
|
||||
}
|
||||
@Override
|
||||
public void configureWebSocketTransport(
|
||||
WebSocketTransportRegistration registration) {
|
||||
registration.addDecoratorFactory(wsConnectHandlerDecoratorFactory());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public WebSocketRegistryListener webSocketRegistryListener() {
|
||||
return new WebSocketRegistryListener();
|
||||
}
|
||||
@Bean
|
||||
public WebSocketRegistryListener webSocketRegistryListener() {
|
||||
return new WebSocketRegistryListener();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public WebSocketConnectHandlerDecoratorFactory wsConnectHandlerDecoratorFactory() {
|
||||
return new WebSocketConnectHandlerDecoratorFactory(eventPublisher);
|
||||
}
|
||||
@Bean
|
||||
public WebSocketConnectHandlerDecoratorFactory wsConnectHandlerDecoratorFactory() {
|
||||
return new WebSocketConnectHandlerDecoratorFactory(eventPublisher);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("unchecked")
|
||||
public SessionRepositoryMessageInterceptor<S> sessionRepositoryInterceptor() {
|
||||
return new SessionRepositoryMessageInterceptor<S>(sessionRepository);
|
||||
}
|
||||
@Bean
|
||||
@SuppressWarnings("unchecked")
|
||||
public SessionRepositoryMessageInterceptor<S> sessionRepositoryInterceptor() {
|
||||
return new SessionRepositoryMessageInterceptor<S>(sessionRepository);
|
||||
}
|
||||
|
||||
static class SessionStompEndpointRegistry implements StompEndpointRegistry {
|
||||
private final StompEndpointRegistry registry;
|
||||
private final HandshakeInterceptor interceptor;
|
||||
static class SessionStompEndpointRegistry implements StompEndpointRegistry {
|
||||
private final StompEndpointRegistry registry;
|
||||
private final HandshakeInterceptor interceptor;
|
||||
|
||||
public SessionStompEndpointRegistry(StompEndpointRegistry registry,
|
||||
HandshakeInterceptor interceptor) {
|
||||
this.registry = registry;
|
||||
this.interceptor = interceptor;
|
||||
}
|
||||
public SessionStompEndpointRegistry(StompEndpointRegistry registry,
|
||||
HandshakeInterceptor interceptor) {
|
||||
this.registry = registry;
|
||||
this.interceptor = interceptor;
|
||||
}
|
||||
|
||||
public StompWebSocketEndpointRegistration addEndpoint(String... paths) {
|
||||
StompWebSocketEndpointRegistration endpoints = registry.addEndpoint(paths);
|
||||
endpoints.addInterceptors(interceptor);
|
||||
return endpoints;
|
||||
}
|
||||
}
|
||||
public StompWebSocketEndpointRegistration addEndpoint(String... paths) {
|
||||
StompWebSocketEndpointRegistration endpoints = registry.addEndpoint(paths);
|
||||
endpoints.addInterceptors(interceptor);
|
||||
return endpoints;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -34,14 +34,14 @@ import org.springframework.web.socket.WebSocketSession;
|
||||
@SuppressWarnings("serial")
|
||||
public class SessionConnectEvent extends ApplicationEvent {
|
||||
|
||||
private final WebSocketSession webSocketSession;
|
||||
private final WebSocketSession webSocketSession;
|
||||
|
||||
public SessionConnectEvent(Object source, WebSocketSession webSocketSession) {
|
||||
super(source);
|
||||
this.webSocketSession = webSocketSession;
|
||||
}
|
||||
public SessionConnectEvent(Object source, WebSocketSession webSocketSession) {
|
||||
super(source);
|
||||
this.webSocketSession = webSocketSession;
|
||||
}
|
||||
|
||||
public WebSocketSession getWebSocketSession() {
|
||||
return webSocketSession;
|
||||
}
|
||||
public WebSocketSession getWebSocketSession() {
|
||||
return webSocketSession;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -42,46 +42,46 @@ import org.springframework.web.socket.handler.WebSocketHandlerDecoratorFactory;
|
||||
*/
|
||||
public final class WebSocketConnectHandlerDecoratorFactory implements WebSocketHandlerDecoratorFactory {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(WebSocketConnectHandlerDecoratorFactory.class);
|
||||
private static final Log logger = LogFactory.getLog(WebSocketConnectHandlerDecoratorFactory.class);
|
||||
|
||||
private final ApplicationEventPublisher eventPublisher;
|
||||
private final ApplicationEventPublisher eventPublisher;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param eventPublisher the {@link ApplicationEventPublisher} to use. Cannot be null.
|
||||
*/
|
||||
public WebSocketConnectHandlerDecoratorFactory(
|
||||
ApplicationEventPublisher eventPublisher) {
|
||||
Assert.notNull(eventPublisher, "eventPublisher cannot be null");
|
||||
this.eventPublisher = eventPublisher;
|
||||
}
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param eventPublisher the {@link ApplicationEventPublisher} to use. Cannot be null.
|
||||
*/
|
||||
public WebSocketConnectHandlerDecoratorFactory(
|
||||
ApplicationEventPublisher eventPublisher) {
|
||||
Assert.notNull(eventPublisher, "eventPublisher cannot be null");
|
||||
this.eventPublisher = eventPublisher;
|
||||
}
|
||||
|
||||
public WebSocketHandler decorate(WebSocketHandler handler) {
|
||||
return new SessionWebSocketHandler(handler);
|
||||
}
|
||||
public WebSocketHandler decorate(WebSocketHandler handler) {
|
||||
return new SessionWebSocketHandler(handler);
|
||||
}
|
||||
|
||||
private final class SessionWebSocketHandler extends WebSocketHandlerDecorator {
|
||||
private final class SessionWebSocketHandler extends WebSocketHandlerDecorator {
|
||||
|
||||
public SessionWebSocketHandler(WebSocketHandler delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
public SessionWebSocketHandler(WebSocketHandler delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterConnectionEstablished(WebSocketSession wsSession)
|
||||
throws Exception {
|
||||
super.afterConnectionEstablished(wsSession);
|
||||
@Override
|
||||
public void afterConnectionEstablished(WebSocketSession wsSession)
|
||||
throws Exception {
|
||||
super.afterConnectionEstablished(wsSession);
|
||||
|
||||
publishEvent(new SessionConnectEvent(this,wsSession));
|
||||
}
|
||||
publishEvent(new SessionConnectEvent(this,wsSession));
|
||||
}
|
||||
|
||||
private void publishEvent(ApplicationEvent event) {
|
||||
try {
|
||||
eventPublisher.publishEvent(event);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.error("Error publishing " + event + ".", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
private void publishEvent(ApplicationEvent event) {
|
||||
try {
|
||||
eventPublisher.publishEvent(event);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.error("Error publishing " + event + ".", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -45,88 +45,88 @@ import org.springframework.web.socket.messaging.SessionDisconnectEvent;
|
||||
*/
|
||||
public final class WebSocketRegistryListener implements ApplicationListener<ApplicationEvent> {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(WebSocketRegistryListener.class);
|
||||
private static final Log logger = LogFactory.getLog(WebSocketRegistryListener.class);
|
||||
|
||||
static final CloseStatus SESSION_EXPIRED_STATUS = new CloseStatus(CloseStatus.POLICY_VIOLATION.getCode(),
|
||||
"This connection was established under an authenticated HTTP Session that has expired");
|
||||
static final CloseStatus SESSION_EXPIRED_STATUS = new CloseStatus(CloseStatus.POLICY_VIOLATION.getCode(),
|
||||
"This connection was established under an authenticated HTTP Session that has expired");
|
||||
|
||||
private final ConcurrentHashMap<String,Map<String,WebSocketSession>> httpSessionIdToWsSessions = new ConcurrentHashMap<String,Map<String,WebSocketSession>>();
|
||||
private final ConcurrentHashMap<String,Map<String,WebSocketSession>> httpSessionIdToWsSessions = new ConcurrentHashMap<String,Map<String,WebSocketSession>>();
|
||||
|
||||
public void onApplicationEvent(ApplicationEvent event) {
|
||||
if(event instanceof SessionDestroyedEvent) {
|
||||
SessionDestroyedEvent e = (SessionDestroyedEvent) event;
|
||||
closeWsSessions(e.getSessionId());
|
||||
} else if(event instanceof SessionConnectEvent) {
|
||||
SessionConnectEvent e = (SessionConnectEvent) event;
|
||||
afterConnectionEstablished(e.getWebSocketSession());
|
||||
} else if(event instanceof SessionDisconnectEvent) {
|
||||
SessionDisconnectEvent e = (SessionDisconnectEvent) event;
|
||||
Map<String, Object> sessionAttributes = SimpMessageHeaderAccessor.getSessionAttributes(e.getMessage().getHeaders());
|
||||
String httpSessionId = sessionAttributes == null ? null : SessionRepositoryMessageInterceptor.getSessionId(sessionAttributes);
|
||||
afterConnectionClosed(httpSessionId, e.getSessionId());
|
||||
}
|
||||
}
|
||||
public void onApplicationEvent(ApplicationEvent event) {
|
||||
if(event instanceof SessionDestroyedEvent) {
|
||||
SessionDestroyedEvent e = (SessionDestroyedEvent) event;
|
||||
closeWsSessions(e.getSessionId());
|
||||
} else if(event instanceof SessionConnectEvent) {
|
||||
SessionConnectEvent e = (SessionConnectEvent) event;
|
||||
afterConnectionEstablished(e.getWebSocketSession());
|
||||
} else if(event instanceof SessionDisconnectEvent) {
|
||||
SessionDisconnectEvent e = (SessionDisconnectEvent) event;
|
||||
Map<String, Object> sessionAttributes = SimpMessageHeaderAccessor.getSessionAttributes(e.getMessage().getHeaders());
|
||||
String httpSessionId = sessionAttributes == null ? null : SessionRepositoryMessageInterceptor.getSessionId(sessionAttributes);
|
||||
afterConnectionClosed(httpSessionId, e.getSessionId());
|
||||
}
|
||||
}
|
||||
|
||||
private void afterConnectionEstablished(WebSocketSession wsSession) {
|
||||
Principal principal = wsSession.getPrincipal();
|
||||
if(principal == null) {
|
||||
return;
|
||||
}
|
||||
private void afterConnectionEstablished(WebSocketSession wsSession) {
|
||||
Principal principal = wsSession.getPrincipal();
|
||||
if(principal == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String httpSessionId = getHttpSessionId(wsSession);
|
||||
registerWsSession(httpSessionId, wsSession);
|
||||
}
|
||||
String httpSessionId = getHttpSessionId(wsSession);
|
||||
registerWsSession(httpSessionId, wsSession);
|
||||
}
|
||||
|
||||
private String getHttpSessionId(WebSocketSession wsSession) {
|
||||
Map<String, Object> attributes = wsSession.getAttributes();
|
||||
return SessionRepositoryMessageInterceptor.getSessionId(attributes);
|
||||
}
|
||||
private String getHttpSessionId(WebSocketSession wsSession) {
|
||||
Map<String, Object> attributes = wsSession.getAttributes();
|
||||
return SessionRepositoryMessageInterceptor.getSessionId(attributes);
|
||||
}
|
||||
|
||||
private void afterConnectionClosed(String httpSessionId, String wsSessionId) {
|
||||
if(httpSessionId == null) {
|
||||
return;
|
||||
}
|
||||
private void afterConnectionClosed(String httpSessionId, String wsSessionId) {
|
||||
if(httpSessionId == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String,WebSocketSession> sessions = httpSessionIdToWsSessions.get(httpSessionId);
|
||||
if(sessions != null) {
|
||||
boolean result = sessions.remove(wsSessionId) != null;
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("Removal of " + wsSessionId + " was " + result);
|
||||
}
|
||||
if(sessions.isEmpty()) {
|
||||
httpSessionIdToWsSessions.remove(httpSessionId);
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("Removed the corresponding HTTP Session for " + wsSessionId + " since it contained no WebSocket mappings");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Map<String,WebSocketSession> sessions = httpSessionIdToWsSessions.get(httpSessionId);
|
||||
if(sessions != null) {
|
||||
boolean result = sessions.remove(wsSessionId) != null;
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("Removal of " + wsSessionId + " was " + result);
|
||||
}
|
||||
if(sessions.isEmpty()) {
|
||||
httpSessionIdToWsSessions.remove(httpSessionId);
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("Removed the corresponding HTTP Session for " + wsSessionId + " since it contained no WebSocket mappings");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void registerWsSession(String httpSessionId, WebSocketSession wsSession) {
|
||||
Map<String,WebSocketSession> sessions = httpSessionIdToWsSessions.get(httpSessionId);
|
||||
if(sessions == null) {
|
||||
sessions =
|
||||
new ConcurrentHashMap<String,WebSocketSession>();
|
||||
httpSessionIdToWsSessions.putIfAbsent(httpSessionId, sessions);
|
||||
sessions = httpSessionIdToWsSessions.get(httpSessionId);
|
||||
}
|
||||
sessions.put(wsSession.getId(), wsSession);
|
||||
}
|
||||
private void registerWsSession(String httpSessionId, WebSocketSession wsSession) {
|
||||
Map<String,WebSocketSession> sessions = httpSessionIdToWsSessions.get(httpSessionId);
|
||||
if(sessions == null) {
|
||||
sessions =
|
||||
new ConcurrentHashMap<String,WebSocketSession>();
|
||||
httpSessionIdToWsSessions.putIfAbsent(httpSessionId, sessions);
|
||||
sessions = httpSessionIdToWsSessions.get(httpSessionId);
|
||||
}
|
||||
sessions.put(wsSession.getId(), wsSession);
|
||||
}
|
||||
|
||||
private void closeWsSessions(String httpSessionId) {
|
||||
Map<String,WebSocketSession> sessionsToClose = httpSessionIdToWsSessions.remove(httpSessionId);
|
||||
if(sessionsToClose == null) {
|
||||
return;
|
||||
}
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("Closing WebSocket connections associated to expired HTTP Session " + httpSessionId);
|
||||
}
|
||||
for(WebSocketSession toClose : sessionsToClose.values()) {
|
||||
try {
|
||||
toClose.close(SESSION_EXPIRED_STATUS);
|
||||
} catch (IOException e) {
|
||||
logger.debug("Failed to close WebSocketSession (this is nothing to worry about but for debugging only)",e);
|
||||
}
|
||||
}
|
||||
}
|
||||
private void closeWsSessions(String httpSessionId) {
|
||||
Map<String,WebSocketSession> sessionsToClose = httpSessionIdToWsSessions.remove(httpSessionId);
|
||||
if(sessionsToClose == null) {
|
||||
return;
|
||||
}
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("Closing WebSocket connections associated to expired HTTP Session " + httpSessionId);
|
||||
}
|
||||
for(WebSocketSession toClose : sessionsToClose.values()) {
|
||||
try {
|
||||
toClose.close(SESSION_EXPIRED_STATUS);
|
||||
} catch (IOException e) {
|
||||
logger.debug("Failed to close WebSocketSession (this is nothing to worry about but for debugging only)",e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -66,93 +66,93 @@ import org.springframework.web.socket.server.HandshakeInterceptor;
|
||||
* @since 1.0
|
||||
*/
|
||||
public final class SessionRepositoryMessageInterceptor<S extends ExpiringSession> extends ChannelInterceptorAdapter
|
||||
implements HandshakeInterceptor {
|
||||
implements HandshakeInterceptor {
|
||||
|
||||
private static final String SPRING_SESSION_ID_ATTR_NAME = "SPRING.SESSION.ID";
|
||||
private static final String SPRING_SESSION_ID_ATTR_NAME = "SPRING.SESSION.ID";
|
||||
|
||||
private final SessionRepository<S> sessionRepository;
|
||||
private final SessionRepository<S> sessionRepository;
|
||||
|
||||
private Set<SimpMessageType> matchingMessageTypes;
|
||||
private Set<SimpMessageType> matchingMessageTypes;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param sessionRepository the {@link SessionRepository} to use. Cannot be null.
|
||||
*/
|
||||
public SessionRepositoryMessageInterceptor(SessionRepository<S> sessionRepository) {
|
||||
Assert.notNull(sessionRepository, "sessionRepository cannot be null");
|
||||
this.sessionRepository = sessionRepository;
|
||||
this.matchingMessageTypes = EnumSet.of(SimpMessageType.CONNECT, SimpMessageType.MESSAGE, SimpMessageType.SUBSCRIBE, SimpMessageType.UNSUBSCRIBE);
|
||||
}
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param sessionRepository the {@link SessionRepository} to use. Cannot be null.
|
||||
*/
|
||||
public SessionRepositoryMessageInterceptor(SessionRepository<S> sessionRepository) {
|
||||
Assert.notNull(sessionRepository, "sessionRepository cannot be null");
|
||||
this.sessionRepository = sessionRepository;
|
||||
this.matchingMessageTypes = EnumSet.of(SimpMessageType.CONNECT, SimpMessageType.MESSAGE, SimpMessageType.SUBSCRIBE, SimpMessageType.UNSUBSCRIBE);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Sets the {@link SimpMessageType} to match on. If the {@link Message}
|
||||
* matches, then {@link #preSend(Message, MessageChannel)} ensures the
|
||||
* {@link Session} is not expired and updates the
|
||||
* {@link ExpiringSession#getLastAccessedTime()}
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The default is: SimpMessageType.CONNECT, SimpMessageType.MESSAGE,
|
||||
* SimpMessageType.SUBSCRIBE, SimpMessageType.UNSUBSCRIBE.
|
||||
* </p>
|
||||
*
|
||||
* @param matchingMessageTypes
|
||||
* the {@link SimpMessageType} to match on in
|
||||
* {@link #preSend(Message, MessageChannel)}, else the
|
||||
* {@link Message} is continued without accessing or updating the
|
||||
* {@link Session}
|
||||
*/
|
||||
public void setMatchingMessageTypes(Set<SimpMessageType> matchingMessageTypes) {
|
||||
Assert.notEmpty(matchingMessageTypes,"matchingMessageTypes cannot be null or empty");
|
||||
this.matchingMessageTypes = matchingMessageTypes;
|
||||
}
|
||||
/**
|
||||
* <p>
|
||||
* Sets the {@link SimpMessageType} to match on. If the {@link Message}
|
||||
* matches, then {@link #preSend(Message, MessageChannel)} ensures the
|
||||
* {@link Session} is not expired and updates the
|
||||
* {@link ExpiringSession#getLastAccessedTime()}
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The default is: SimpMessageType.CONNECT, SimpMessageType.MESSAGE,
|
||||
* SimpMessageType.SUBSCRIBE, SimpMessageType.UNSUBSCRIBE.
|
||||
* </p>
|
||||
*
|
||||
* @param matchingMessageTypes
|
||||
* the {@link SimpMessageType} to match on in
|
||||
* {@link #preSend(Message, MessageChannel)}, else the
|
||||
* {@link Message} is continued without accessing or updating the
|
||||
* {@link Session}
|
||||
*/
|
||||
public void setMatchingMessageTypes(Set<SimpMessageType> matchingMessageTypes) {
|
||||
Assert.notEmpty(matchingMessageTypes,"matchingMessageTypes cannot be null or empty");
|
||||
this.matchingMessageTypes = matchingMessageTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message<?> preSend(Message<?> message, MessageChannel channel) {
|
||||
if(message == null) {
|
||||
return message;
|
||||
}
|
||||
SimpMessageType messageType = SimpMessageHeaderAccessor.getMessageType(message.getHeaders());
|
||||
if(!this.matchingMessageTypes.contains(messageType)) {
|
||||
return super.preSend(message, channel);
|
||||
}
|
||||
Map<String, Object> sessionHeaders = SimpMessageHeaderAccessor.getSessionAttributes(message.getHeaders());
|
||||
String sessionId = sessionHeaders == null ? null : (String) sessionHeaders.get(SPRING_SESSION_ID_ATTR_NAME);
|
||||
if (sessionId != null) {
|
||||
S session = sessionRepository.getSession(sessionId);
|
||||
if (session != null) {
|
||||
// update the last accessed time
|
||||
sessionRepository.save(session);
|
||||
}
|
||||
}
|
||||
return super.preSend(message, channel);
|
||||
}
|
||||
@Override
|
||||
public Message<?> preSend(Message<?> message, MessageChannel channel) {
|
||||
if(message == null) {
|
||||
return message;
|
||||
}
|
||||
SimpMessageType messageType = SimpMessageHeaderAccessor.getMessageType(message.getHeaders());
|
||||
if(!this.matchingMessageTypes.contains(messageType)) {
|
||||
return super.preSend(message, channel);
|
||||
}
|
||||
Map<String, Object> sessionHeaders = SimpMessageHeaderAccessor.getSessionAttributes(message.getHeaders());
|
||||
String sessionId = sessionHeaders == null ? null : (String) sessionHeaders.get(SPRING_SESSION_ID_ATTR_NAME);
|
||||
if (sessionId != null) {
|
||||
S session = sessionRepository.getSession(sessionId);
|
||||
if (session != null) {
|
||||
// update the last accessed time
|
||||
sessionRepository.save(session);
|
||||
}
|
||||
}
|
||||
return super.preSend(message, channel);
|
||||
}
|
||||
|
||||
public boolean beforeHandshake(ServerHttpRequest request,
|
||||
ServerHttpResponse response, WebSocketHandler wsHandler,
|
||||
Map<String, Object> attributes) throws Exception {
|
||||
if (request instanceof ServletServerHttpRequest) {
|
||||
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
|
||||
HttpSession session = servletRequest.getServletRequest().getSession(false);
|
||||
if (session != null) {
|
||||
setSessionId(attributes, session.getId());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public boolean beforeHandshake(ServerHttpRequest request,
|
||||
ServerHttpResponse response, WebSocketHandler wsHandler,
|
||||
Map<String, Object> attributes) throws Exception {
|
||||
if (request instanceof ServletServerHttpRequest) {
|
||||
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
|
||||
HttpSession session = servletRequest.getServletRequest().getSession(false);
|
||||
if (session != null) {
|
||||
setSessionId(attributes, session.getId());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void afterHandshake(ServerHttpRequest request,
|
||||
ServerHttpResponse response, WebSocketHandler wsHandler,
|
||||
Exception exception) {
|
||||
}
|
||||
public void afterHandshake(ServerHttpRequest request,
|
||||
ServerHttpResponse response, WebSocketHandler wsHandler,
|
||||
Exception exception) {
|
||||
}
|
||||
|
||||
public static String getSessionId(Map<String, Object> attributes) {
|
||||
return (String) attributes.get(SPRING_SESSION_ID_ATTR_NAME);
|
||||
}
|
||||
public static String getSessionId(Map<String, Object> attributes) {
|
||||
return (String) attributes.get(SPRING_SESSION_ID_ATTR_NAME);
|
||||
}
|
||||
|
||||
public static void setSessionId(Map<String, Object> attributes, String sessionId) {
|
||||
attributes.put(SPRING_SESSION_ID_ATTR_NAME, sessionId);
|
||||
}
|
||||
public static void setSessionId(Map<String, Object> attributes, String sessionId) {
|
||||
attributes.put(SPRING_SESSION_ID_ATTR_NAME, sessionId);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -23,40 +23,40 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class MapSessionRepositoryTests {
|
||||
MapSessionRepository repository;
|
||||
MapSessionRepository repository;
|
||||
|
||||
MapSession session;
|
||||
MapSession session;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
repository = new MapSessionRepository();
|
||||
session = new MapSession();
|
||||
}
|
||||
@Before
|
||||
public void setup() {
|
||||
repository = new MapSessionRepository();
|
||||
session = new MapSession();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSessionExpired() {
|
||||
session.setMaxInactiveIntervalInSeconds(1);
|
||||
session.setLastAccessedTime(System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(5));
|
||||
repository.save(session);
|
||||
@Test
|
||||
public void getSessionExpired() {
|
||||
session.setMaxInactiveIntervalInSeconds(1);
|
||||
session.setLastAccessedTime(System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(5));
|
||||
repository.save(session);
|
||||
|
||||
assertThat(repository.getSession(session.getId())).isNull();
|
||||
}
|
||||
assertThat(repository.getSession(session.getId())).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createSessionDefaultExpiration() {
|
||||
ExpiringSession session = repository.createSession();
|
||||
@Test
|
||||
public void createSessionDefaultExpiration() {
|
||||
ExpiringSession session = repository.createSession();
|
||||
|
||||
assertThat(session).isInstanceOf(MapSession.class);
|
||||
assertThat(session.getMaxInactiveIntervalInSeconds()).isEqualTo(new MapSession().getMaxInactiveIntervalInSeconds());
|
||||
}
|
||||
assertThat(session).isInstanceOf(MapSession.class);
|
||||
assertThat(session.getMaxInactiveIntervalInSeconds()).isEqualTo(new MapSession().getMaxInactiveIntervalInSeconds());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createSessionCustomDefaultExpiration() {
|
||||
final int expectedMaxInterval = new MapSession().getMaxInactiveIntervalInSeconds() + 10;
|
||||
repository.setDefaultMaxInactiveInterval(expectedMaxInterval);
|
||||
@Test
|
||||
public void createSessionCustomDefaultExpiration() {
|
||||
final int expectedMaxInterval = new MapSession().getMaxInactiveIntervalInSeconds() + 10;
|
||||
repository.setDefaultMaxInactiveInterval(expectedMaxInterval);
|
||||
|
||||
ExpiringSession session = repository.createSession();
|
||||
ExpiringSession session = repository.createSession();
|
||||
|
||||
assertThat(session.getMaxInactiveIntervalInSeconds()).isEqualTo(expectedMaxInterval);
|
||||
}
|
||||
assertThat(session.getMaxInactiveIntervalInSeconds()).isEqualTo(expectedMaxInterval);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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;
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
@@ -9,107 +24,107 @@ import org.junit.Test;
|
||||
|
||||
public class MapSessionTests {
|
||||
|
||||
private MapSession session;
|
||||
private MapSession session;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
session = new MapSession();
|
||||
session.setLastAccessedTime(1413258262962L);
|
||||
}
|
||||
@Before
|
||||
public void setup() {
|
||||
session = new MapSession();
|
||||
session.setLastAccessedTime(1413258262962L);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructorNullSession() {
|
||||
new MapSession(null);
|
||||
}
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructorNullSession() {
|
||||
new MapSession(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure conforms to the javadoc of {@link Session}
|
||||
*/
|
||||
@Test
|
||||
public void setAttributeNullObjectRemoves() {
|
||||
String attr = "attr";
|
||||
session.setAttribute(attr, new Object());
|
||||
session.setAttribute(attr, null);
|
||||
assertThat(session.getAttributeNames()).isEmpty();
|
||||
}
|
||||
/**
|
||||
* Ensure conforms to the javadoc of {@link Session}
|
||||
*/
|
||||
@Test
|
||||
public void setAttributeNullObjectRemoves() {
|
||||
String attr = "attr";
|
||||
session.setAttribute(attr, new Object());
|
||||
session.setAttribute(attr, null);
|
||||
assertThat(session.getAttributeNames()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalsNonSessionFalse() {
|
||||
assertThat(session.equals(new Object())).isFalse();
|
||||
}
|
||||
@Test
|
||||
public void equalsNonSessionFalse() {
|
||||
assertThat(session.equals(new Object())).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalsCustomSession() {
|
||||
CustomSession other = new CustomSession();
|
||||
session.setId(other.getId());
|
||||
assertThat(session.equals(other)).isTrue();
|
||||
}
|
||||
@Test
|
||||
public void equalsCustomSession() {
|
||||
CustomSession other = new CustomSession();
|
||||
session.setId(other.getId());
|
||||
assertThat(session.equals(other)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hashCodeEqualsIdHashCode() {
|
||||
session.setId("constantId");
|
||||
assertThat(session.hashCode()).isEqualTo(session.getId().hashCode());
|
||||
}
|
||||
@Test
|
||||
public void hashCodeEqualsIdHashCode() {
|
||||
session.setId("constantId");
|
||||
assertThat(session.hashCode()).isEqualTo(session.getId().hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isExpiredExact() {
|
||||
long now = 1413260062962L;
|
||||
assertThat(session.isExpired(now)).isTrue();
|
||||
}
|
||||
@Test
|
||||
public void isExpiredExact() {
|
||||
long now = 1413260062962L;
|
||||
assertThat(session.isExpired(now)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isExpiredOneMsTooSoon() {
|
||||
long now = 1413260062961L;
|
||||
assertThat(session.isExpired(now)).isFalse();
|
||||
}
|
||||
@Test
|
||||
public void isExpiredOneMsTooSoon() {
|
||||
long now = 1413260062961L;
|
||||
assertThat(session.isExpired(now)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isExpiredOneMsAfter() {
|
||||
long now = 1413260062963L;
|
||||
assertThat(session.isExpired(now)).isTrue();
|
||||
}
|
||||
@Test
|
||||
public void isExpiredOneMsAfter() {
|
||||
long now = 1413260062963L;
|
||||
assertThat(session.isExpired(now)).isTrue();
|
||||
}
|
||||
|
||||
static class CustomSession implements ExpiringSession {
|
||||
static class CustomSession implements ExpiringSession {
|
||||
|
||||
public long getCreationTime() {
|
||||
return 0;
|
||||
}
|
||||
public long getCreationTime() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return "id";
|
||||
}
|
||||
public String getId() {
|
||||
return "id";
|
||||
}
|
||||
|
||||
public long getLastAccessedTime() {
|
||||
return 0;
|
||||
}
|
||||
public long getLastAccessedTime() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setMaxInactiveIntervalInSeconds(int interval) {
|
||||
public void setMaxInactiveIntervalInSeconds(int interval) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public int getMaxInactiveIntervalInSeconds() {
|
||||
return 0;
|
||||
}
|
||||
public int getMaxInactiveIntervalInSeconds() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Object getAttribute(String attributeName) {
|
||||
return null;
|
||||
}
|
||||
public Object getAttribute(String attributeName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Set<String> getAttributeNames() {
|
||||
return null;
|
||||
}
|
||||
public Set<String> getAttributeNames() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setAttribute(String attributeName, Object attributeValue) {
|
||||
public void setAttribute(String attributeName, Object attributeValue) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAttribute(String attributeName) {
|
||||
public void removeAttribute(String attributeName) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isExpired() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public boolean isExpired() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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;
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
@@ -34,234 +49,231 @@ import org.springframework.session.data.redis.RedisOperationsSessionRepository.R
|
||||
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
@SuppressWarnings({"unchecked","rawtypes"})
|
||||
public class RedisOperationsSessionRepositoryTests {
|
||||
@Mock
|
||||
RedisConnectionFactory factory;
|
||||
@Mock
|
||||
RedisConnection connection;
|
||||
@Mock
|
||||
RedisOperations redisOperations;
|
||||
@Mock
|
||||
BoundHashOperations<String, Object, Object> boundHashOperations;
|
||||
@Mock
|
||||
BoundSetOperations<String, String> boundSetOperations;
|
||||
@Captor
|
||||
ArgumentCaptor<Map<String,Object>> delta;
|
||||
@Mock
|
||||
RedisConnectionFactory factory;
|
||||
@Mock
|
||||
RedisConnection connection;
|
||||
@Mock
|
||||
RedisOperations redisOperations;
|
||||
@Mock
|
||||
BoundHashOperations<String, Object, Object> boundHashOperations;
|
||||
@Mock
|
||||
BoundSetOperations<String, String> boundSetOperations;
|
||||
@Captor
|
||||
ArgumentCaptor<Map<String,Object>> delta;
|
||||
|
||||
private RedisOperationsSessionRepository redisRepository;
|
||||
private RedisOperationsSessionRepository redisRepository;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.redisRepository = new RedisOperationsSessionRepository(redisOperations);
|
||||
}
|
||||
@Before
|
||||
public void setup() {
|
||||
this.redisRepository = new RedisOperationsSessionRepository(redisOperations);
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void constructorNullConnectionFactory() {
|
||||
new RedisOperationsSessionRepository((RedisConnectionFactory)null);
|
||||
}
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void constructorNullConnectionFactory() {
|
||||
new RedisOperationsSessionRepository((RedisConnectionFactory)null);
|
||||
}
|
||||
|
||||
// gh-61
|
||||
@Test
|
||||
public void constructorConnectionFactory() {
|
||||
redisRepository = new RedisOperationsSessionRepository(factory);
|
||||
RedisSession session = redisRepository.createSession();
|
||||
// gh-61
|
||||
@Test
|
||||
public void constructorConnectionFactory() {
|
||||
redisRepository = new RedisOperationsSessionRepository(factory);
|
||||
RedisSession session = redisRepository.createSession();
|
||||
|
||||
when(factory.getConnection()).thenReturn(connection);
|
||||
when(factory.getConnection()).thenReturn(connection);
|
||||
|
||||
redisRepository.save(session);
|
||||
}
|
||||
redisRepository.save(session);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createSessionDefaultMaxInactiveInterval() throws Exception {
|
||||
ExpiringSession session = redisRepository.createSession();
|
||||
assertThat(session.getMaxInactiveIntervalInSeconds()).isEqualTo(new MapSession().getMaxInactiveIntervalInSeconds());
|
||||
}
|
||||
@Test
|
||||
public void createSessionDefaultMaxInactiveInterval() throws Exception {
|
||||
ExpiringSession session = redisRepository.createSession();
|
||||
assertThat(session.getMaxInactiveIntervalInSeconds()).isEqualTo(new MapSession().getMaxInactiveIntervalInSeconds());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createSessionCustomMaxInactiveInterval() throws Exception {
|
||||
int interval = 1;
|
||||
redisRepository.setDefaultMaxInactiveInterval(interval);
|
||||
ExpiringSession session = redisRepository.createSession();
|
||||
assertThat(session.getMaxInactiveIntervalInSeconds()).isEqualTo(interval);
|
||||
}
|
||||
@Test
|
||||
public void createSessionCustomMaxInactiveInterval() throws Exception {
|
||||
int interval = 1;
|
||||
redisRepository.setDefaultMaxInactiveInterval(interval);
|
||||
ExpiringSession session = redisRepository.createSession();
|
||||
assertThat(session.getMaxInactiveIntervalInSeconds()).isEqualTo(interval);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveNewSession() {
|
||||
RedisSession session = redisRepository.createSession();
|
||||
when(redisOperations.boundHashOps(getKey(session.getId()))).thenReturn(boundHashOperations);
|
||||
when(redisOperations.boundSetOps(anyString())).thenReturn(boundSetOperations);
|
||||
@Test
|
||||
public void saveNewSession() {
|
||||
RedisSession session = redisRepository.createSession();
|
||||
when(redisOperations.boundHashOps(getKey(session.getId()))).thenReturn(boundHashOperations);
|
||||
when(redisOperations.boundSetOps(anyString())).thenReturn(boundSetOperations);
|
||||
|
||||
redisRepository.save(session);
|
||||
redisRepository.save(session);
|
||||
|
||||
Map<String,Object> delta = getDelta();
|
||||
assertThat(delta.size()).isEqualTo(3);
|
||||
Object creationTime = delta.get(CREATION_TIME_ATTR);
|
||||
assertThat(creationTime).isInstanceOf(Long.class);
|
||||
assertThat(delta.get(MAX_INACTIVE_ATTR)).isEqualTo(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
|
||||
assertThat(delta.get(LAST_ACCESSED_ATTR)).isEqualTo(creationTime);
|
||||
}
|
||||
Map<String,Object> delta = getDelta();
|
||||
assertThat(delta.size()).isEqualTo(3);
|
||||
Object creationTime = delta.get(CREATION_TIME_ATTR);
|
||||
assertThat(creationTime).isInstanceOf(Long.class);
|
||||
assertThat(delta.get(MAX_INACTIVE_ATTR)).isEqualTo(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
|
||||
assertThat(delta.get(LAST_ACCESSED_ATTR)).isEqualTo(creationTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveLastAccessChanged() {
|
||||
RedisSession session = redisRepository.new RedisSession(new MapSession());
|
||||
session.setLastAccessedTime(12345678L);
|
||||
when(redisOperations.boundHashOps(getKey(session.getId()))).thenReturn(boundHashOperations);
|
||||
when(redisOperations.boundSetOps(anyString())).thenReturn(boundSetOperations);
|
||||
@Test
|
||||
public void saveLastAccessChanged() {
|
||||
RedisSession session = redisRepository.new RedisSession(new MapSession());
|
||||
session.setLastAccessedTime(12345678L);
|
||||
when(redisOperations.boundHashOps(getKey(session.getId()))).thenReturn(boundHashOperations);
|
||||
when(redisOperations.boundSetOps(anyString())).thenReturn(boundSetOperations);
|
||||
|
||||
redisRepository.save(session);
|
||||
redisRepository.save(session);
|
||||
|
||||
assertThat(getDelta()).isEqualTo(map(LAST_ACCESSED_ATTR, session.getLastAccessedTime()));
|
||||
}
|
||||
assertThat(getDelta()).isEqualTo(map(LAST_ACCESSED_ATTR, session.getLastAccessedTime()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveSetAttribute() {
|
||||
String attrName = "attrName";
|
||||
RedisSession session = redisRepository.new RedisSession(new MapSession());
|
||||
session.setAttribute(attrName, "attrValue");
|
||||
when(redisOperations.boundHashOps(getKey(session.getId()))).thenReturn(boundHashOperations);
|
||||
when(redisOperations.boundSetOps(anyString())).thenReturn(boundSetOperations);
|
||||
@Test
|
||||
public void saveSetAttribute() {
|
||||
String attrName = "attrName";
|
||||
RedisSession session = redisRepository.new RedisSession(new MapSession());
|
||||
session.setAttribute(attrName, "attrValue");
|
||||
when(redisOperations.boundHashOps(getKey(session.getId()))).thenReturn(boundHashOperations);
|
||||
when(redisOperations.boundSetOps(anyString())).thenReturn(boundSetOperations);
|
||||
|
||||
redisRepository.save(session);
|
||||
redisRepository.save(session);
|
||||
|
||||
assertThat(getDelta()).isEqualTo(map(getSessionAttrNameKey(attrName), session.getAttribute(attrName)));
|
||||
}
|
||||
assertThat(getDelta()).isEqualTo(map(getSessionAttrNameKey(attrName), session.getAttribute(attrName)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveRemoveAttribute() {
|
||||
String attrName = "attrName";
|
||||
RedisSession session = redisRepository.new RedisSession(new MapSession());
|
||||
session.removeAttribute(attrName);
|
||||
when(redisOperations.boundHashOps(getKey(session.getId()))).thenReturn(boundHashOperations);
|
||||
when(redisOperations.boundSetOps(anyString())).thenReturn(boundSetOperations);
|
||||
@Test
|
||||
public void saveRemoveAttribute() {
|
||||
String attrName = "attrName";
|
||||
RedisSession session = redisRepository.new RedisSession(new MapSession());
|
||||
session.removeAttribute(attrName);
|
||||
when(redisOperations.boundHashOps(getKey(session.getId()))).thenReturn(boundHashOperations);
|
||||
when(redisOperations.boundSetOps(anyString())).thenReturn(boundSetOperations);
|
||||
|
||||
redisRepository.save(session);
|
||||
redisRepository.save(session);
|
||||
|
||||
assertThat(getDelta()).isEqualTo(map(getSessionAttrNameKey(attrName), null));
|
||||
}
|
||||
assertThat(getDelta()).isEqualTo(map(getSessionAttrNameKey(attrName), null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void redisSessionGetAttributes() {
|
||||
String attrName = "attrName";
|
||||
RedisSession session = redisRepository.new RedisSession(new MapSession());
|
||||
assertThat(session.getAttributeNames()).isEmpty();
|
||||
session.setAttribute(attrName, "attrValue");
|
||||
assertThat(session.getAttributeNames()).containsOnly(attrName);
|
||||
session.removeAttribute(attrName);
|
||||
assertThat(session.getAttributeNames()).isEmpty();
|
||||
}
|
||||
@Test
|
||||
public void redisSessionGetAttributes() {
|
||||
String attrName = "attrName";
|
||||
RedisSession session = redisRepository.new RedisSession(new MapSession());
|
||||
assertThat(session.getAttributeNames()).isEmpty();
|
||||
session.setAttribute(attrName, "attrValue");
|
||||
assertThat(session.getAttributeNames()).containsOnly(attrName);
|
||||
session.removeAttribute(attrName);
|
||||
assertThat(session.getAttributeNames()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void delete() {
|
||||
String attrName = "attrName";
|
||||
MapSession expected = new MapSession();
|
||||
expected.setLastAccessedTime(System.currentTimeMillis() - 60000);
|
||||
expected.setAttribute(attrName, "attrValue");
|
||||
when(redisOperations.boundHashOps(getKey(expected.getId()))).thenReturn(boundHashOperations);
|
||||
Map map = map(
|
||||
getSessionAttrNameKey(attrName), expected.getAttribute(attrName),
|
||||
CREATION_TIME_ATTR, expected.getCreationTime(),
|
||||
MAX_INACTIVE_ATTR, expected.getMaxInactiveIntervalInSeconds(),
|
||||
LAST_ACCESSED_ATTR, expected.getLastAccessedTime());
|
||||
when(boundHashOperations.entries()).thenReturn(map);
|
||||
when(redisOperations.boundSetOps(anyString())).thenReturn(boundSetOperations);
|
||||
@Test
|
||||
public void delete() {
|
||||
String attrName = "attrName";
|
||||
MapSession expected = new MapSession();
|
||||
expected.setLastAccessedTime(System.currentTimeMillis() - 60000);
|
||||
expected.setAttribute(attrName, "attrValue");
|
||||
when(redisOperations.boundHashOps(getKey(expected.getId()))).thenReturn(boundHashOperations);
|
||||
Map map = map(
|
||||
getSessionAttrNameKey(attrName), expected.getAttribute(attrName),
|
||||
CREATION_TIME_ATTR, expected.getCreationTime(),
|
||||
MAX_INACTIVE_ATTR, expected.getMaxInactiveIntervalInSeconds(),
|
||||
LAST_ACCESSED_ATTR, expected.getLastAccessedTime());
|
||||
when(boundHashOperations.entries()).thenReturn(map);
|
||||
when(redisOperations.boundSetOps(anyString())).thenReturn(boundSetOperations);
|
||||
|
||||
String id = expected.getId();
|
||||
redisRepository.delete(id);
|
||||
verify(redisOperations).delete(getKey(id));
|
||||
}
|
||||
String id = expected.getId();
|
||||
redisRepository.delete(id);
|
||||
verify(redisOperations).delete(getKey(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteNullSession() {
|
||||
when(redisOperations.boundSetOps(anyString())).thenReturn(boundSetOperations);
|
||||
when(redisOperations.boundHashOps(anyString())).thenReturn(boundHashOperations);
|
||||
@Test
|
||||
public void deleteNullSession() {
|
||||
when(redisOperations.boundSetOps(anyString())).thenReturn(boundSetOperations);
|
||||
when(redisOperations.boundHashOps(anyString())).thenReturn(boundHashOperations);
|
||||
|
||||
String id = "abc";
|
||||
redisRepository.delete(id);
|
||||
verify(redisOperations,times(0)).delete(anyString());
|
||||
verify(redisOperations,times(0)).delete(anyString());
|
||||
}
|
||||
String id = "abc";
|
||||
redisRepository.delete(id);
|
||||
verify(redisOperations,times(0)).delete(anyString());
|
||||
verify(redisOperations,times(0)).delete(anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void getSessionNotFound() {
|
||||
String id = "abc";
|
||||
when(redisOperations.boundHashOps(getKey(id))).thenReturn(boundHashOperations);
|
||||
when(boundHashOperations.entries()).thenReturn(map());
|
||||
@Test
|
||||
public void getSessionNotFound() {
|
||||
String id = "abc";
|
||||
when(redisOperations.boundHashOps(getKey(id))).thenReturn(boundHashOperations);
|
||||
when(boundHashOperations.entries()).thenReturn(map());
|
||||
|
||||
assertThat(redisRepository.getSession(id)).isNull();
|
||||
}
|
||||
assertThat(redisRepository.getSession(id)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public void getSessionFound() {
|
||||
String attrName = "attrName";
|
||||
MapSession expected = new MapSession();
|
||||
expected.setLastAccessedTime(System.currentTimeMillis() - 60000);
|
||||
expected.setAttribute(attrName, "attrValue");
|
||||
when(redisOperations.boundHashOps(getKey(expected.getId()))).thenReturn(boundHashOperations);
|
||||
Map map = map(
|
||||
getSessionAttrNameKey(attrName), expected.getAttribute(attrName),
|
||||
CREATION_TIME_ATTR, expected.getCreationTime(),
|
||||
MAX_INACTIVE_ATTR, expected.getMaxInactiveIntervalInSeconds(),
|
||||
LAST_ACCESSED_ATTR, expected.getLastAccessedTime());
|
||||
when(boundHashOperations.entries()).thenReturn(map);
|
||||
@Test
|
||||
public void getSessionFound() {
|
||||
String attrName = "attrName";
|
||||
MapSession expected = new MapSession();
|
||||
expected.setLastAccessedTime(System.currentTimeMillis() - 60000);
|
||||
expected.setAttribute(attrName, "attrValue");
|
||||
when(redisOperations.boundHashOps(getKey(expected.getId()))).thenReturn(boundHashOperations);
|
||||
Map map = map(
|
||||
getSessionAttrNameKey(attrName), expected.getAttribute(attrName),
|
||||
CREATION_TIME_ATTR, expected.getCreationTime(),
|
||||
MAX_INACTIVE_ATTR, expected.getMaxInactiveIntervalInSeconds(),
|
||||
LAST_ACCESSED_ATTR, expected.getLastAccessedTime());
|
||||
when(boundHashOperations.entries()).thenReturn(map);
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
RedisSession session = redisRepository.getSession(expected.getId());
|
||||
assertThat(session.getId()).isEqualTo(expected.getId());
|
||||
assertThat(session.getAttributeNames()).isEqualTo(expected.getAttributeNames());
|
||||
assertThat(session.getAttribute(attrName)).isEqualTo(expected.getAttribute(attrName));
|
||||
assertThat(session.getCreationTime()).isEqualTo(expected.getCreationTime());
|
||||
assertThat(session.getMaxInactiveIntervalInSeconds()).isEqualTo(expected.getMaxInactiveIntervalInSeconds());
|
||||
assertThat(session.getLastAccessedTime()).isGreaterThanOrEqualTo(now);
|
||||
long now = System.currentTimeMillis();
|
||||
RedisSession session = redisRepository.getSession(expected.getId());
|
||||
assertThat(session.getId()).isEqualTo(expected.getId());
|
||||
assertThat(session.getAttributeNames()).isEqualTo(expected.getAttributeNames());
|
||||
assertThat(session.getAttribute(attrName)).isEqualTo(expected.getAttribute(attrName));
|
||||
assertThat(session.getCreationTime()).isEqualTo(expected.getCreationTime());
|
||||
assertThat(session.getMaxInactiveIntervalInSeconds()).isEqualTo(expected.getMaxInactiveIntervalInSeconds());
|
||||
assertThat(session.getLastAccessedTime()).isGreaterThanOrEqualTo(now);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public void getSessionExpired() {
|
||||
String expiredId = "expired-id";
|
||||
when(redisOperations.boundHashOps(getKey(expiredId))).thenReturn(boundHashOperations);
|
||||
Map map = map(
|
||||
MAX_INACTIVE_ATTR, 1,
|
||||
LAST_ACCESSED_ATTR, System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(5));
|
||||
when(boundHashOperations.entries()).thenReturn(map);
|
||||
@Test
|
||||
public void getSessionExpired() {
|
||||
String expiredId = "expired-id";
|
||||
when(redisOperations.boundHashOps(getKey(expiredId))).thenReturn(boundHashOperations);
|
||||
Map map = map(
|
||||
MAX_INACTIVE_ATTR, 1,
|
||||
LAST_ACCESSED_ATTR, System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(5));
|
||||
when(boundHashOperations.entries()).thenReturn(map);
|
||||
|
||||
assertThat(redisRepository.getSession(expiredId)).isNull();
|
||||
}
|
||||
assertThat(redisRepository.getSession(expiredId)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cleanupExpiredSessions() {
|
||||
String expiredId = "expired-id";
|
||||
when(redisOperations.boundHashOps(getKey(expiredId))).thenReturn(boundHashOperations);
|
||||
when(redisOperations.boundSetOps(anyString())).thenReturn(boundSetOperations);
|
||||
@Test
|
||||
public void cleanupExpiredSessions() {
|
||||
String expiredId = "expired-id";
|
||||
when(redisOperations.boundHashOps(getKey(expiredId))).thenReturn(boundHashOperations);
|
||||
when(redisOperations.boundSetOps(anyString())).thenReturn(boundSetOperations);
|
||||
|
||||
Set<String> expiredIds = new HashSet<String>(Arrays.asList("expired-key1","expired-key2"));
|
||||
when(boundSetOperations.members()).thenReturn(expiredIds);
|
||||
Set<String> expiredIds = new HashSet<String>(Arrays.asList("expired-key1","expired-key2"));
|
||||
when(boundSetOperations.members()).thenReturn(expiredIds);
|
||||
|
||||
redisRepository.cleanupExpiredSessions();
|
||||
redisRepository.cleanupExpiredSessions();
|
||||
|
||||
for(String id : expiredIds) {
|
||||
String expiredKey = RedisOperationsSessionRepository.BOUNDED_HASH_KEY_PREFIX + id;
|
||||
// https://github.com/spring-projects/spring-session/issues/93
|
||||
verify(redisOperations).hasKey(expiredKey);
|
||||
}
|
||||
}
|
||||
for(String id : expiredIds) {
|
||||
String expiredKey = RedisOperationsSessionRepository.BOUNDED_HASH_KEY_PREFIX + id;
|
||||
// https://github.com/spring-projects/spring-session/issues/93
|
||||
verify(redisOperations).hasKey(expiredKey);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private Map map(Object...objects) {
|
||||
Map<String,Object> result = new HashMap<String,Object>();
|
||||
if(objects == null) {
|
||||
return result;
|
||||
}
|
||||
for(int i = 0; i < objects.length; i += 2) {
|
||||
result.put((String)objects[i], objects[i+1]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private Map map(Object...objects) {
|
||||
Map<String,Object> result = new HashMap<String,Object>();
|
||||
if(objects == null) {
|
||||
return result;
|
||||
}
|
||||
for(int i = 0; i < objects.length; i += 2) {
|
||||
result.put((String)objects[i], objects[i+1]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Map<String,Object> getDelta() {
|
||||
verify(boundHashOperations).putAll(delta.capture());
|
||||
return delta.getValue();
|
||||
}
|
||||
private Map<String,Object> getDelta() {
|
||||
verify(boundHashOperations).putAll(delta.capture());
|
||||
return delta.getValue();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -40,109 +40,109 @@ import org.springframework.session.events.SessionDestroyedEvent;
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class SessionMessageListenerTests {
|
||||
@Mock
|
||||
ApplicationEventPublisher eventPublisher;
|
||||
@Mock
|
||||
ApplicationEventPublisher eventPublisher;
|
||||
|
||||
@Mock
|
||||
Message message;
|
||||
@Mock
|
||||
Message message;
|
||||
|
||||
@Captor
|
||||
ArgumentCaptor<SessionDestroyedEvent> event;
|
||||
@Captor
|
||||
ArgumentCaptor<SessionDestroyedEvent> event;
|
||||
|
||||
byte[] pattern;
|
||||
byte[] pattern;
|
||||
|
||||
SessionMessageListener listener;
|
||||
SessionMessageListener listener;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
listener = new SessionMessageListener(eventPublisher);
|
||||
}
|
||||
@Before
|
||||
public void setup() {
|
||||
listener = new SessionMessageListener(eventPublisher);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructorNullEventPublisher() {
|
||||
new SessionMessageListener(null);
|
||||
}
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructorNullEventPublisher() {
|
||||
new SessionMessageListener(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onMessageNullBody() throws Exception {
|
||||
listener.onMessage(message, pattern);
|
||||
@Test
|
||||
public void onMessageNullBody() throws Exception {
|
||||
listener.onMessage(message, pattern);
|
||||
|
||||
verifyZeroInteractions(eventPublisher);
|
||||
}
|
||||
verifyZeroInteractions(eventPublisher);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onMessageDel() throws Exception {
|
||||
mockMessage("__keyevent@0__:del", "spring:session:sessions:123");
|
||||
@Test
|
||||
public void onMessageDel() throws Exception {
|
||||
mockMessage("__keyevent@0__:del", "spring:session:sessions:123");
|
||||
|
||||
listener.onMessage(message, pattern);
|
||||
listener.onMessage(message, pattern);
|
||||
|
||||
verify(eventPublisher).publishEvent(event.capture());
|
||||
assertThat(event.getValue().getSessionId()).isEqualTo("123");
|
||||
}
|
||||
verify(eventPublisher).publishEvent(event.capture());
|
||||
assertThat(event.getValue().getSessionId()).isEqualTo("123");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onMessageSource() throws Exception {
|
||||
mockMessage("__keyevent@0__:del","spring:session:sessions:123");
|
||||
@Test
|
||||
public void onMessageSource() throws Exception {
|
||||
mockMessage("__keyevent@0__:del","spring:session:sessions:123");
|
||||
|
||||
listener.onMessage(message, pattern);
|
||||
listener.onMessage(message, pattern);
|
||||
|
||||
verify(eventPublisher).publishEvent(event.capture());
|
||||
assertThat(event.getValue().getSource()).isEqualTo(listener);
|
||||
}
|
||||
verify(eventPublisher).publishEvent(event.capture());
|
||||
assertThat(event.getValue().getSource()).isEqualTo(listener);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onMessageExpired() throws Exception {
|
||||
mockMessage("__keyevent@0__:expired","spring:session:sessions:543");
|
||||
@Test
|
||||
public void onMessageExpired() throws Exception {
|
||||
mockMessage("__keyevent@0__:expired","spring:session:sessions:543");
|
||||
|
||||
listener.onMessage(message, pattern);
|
||||
listener.onMessage(message, pattern);
|
||||
|
||||
verify(eventPublisher).publishEvent(event.capture());
|
||||
assertThat(event.getValue().getSessionId()).isEqualTo("543");
|
||||
}
|
||||
verify(eventPublisher).publishEvent(event.capture());
|
||||
assertThat(event.getValue().getSessionId()).isEqualTo("543");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onMessageHset() throws Exception {
|
||||
mockMessage("__keyevent@0__:hset","spring:session:sessions:123");
|
||||
@Test
|
||||
public void onMessageHset() throws Exception {
|
||||
mockMessage("__keyevent@0__:hset","spring:session:sessions:123");
|
||||
|
||||
listener.onMessage(message, pattern);
|
||||
listener.onMessage(message, pattern);
|
||||
|
||||
verifyZeroInteractions(eventPublisher);
|
||||
}
|
||||
verifyZeroInteractions(eventPublisher);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onMessageWrongKeyPrefix() throws Exception {
|
||||
mockMessage("__keyevent@0__:del","spring:session:sessionsNo:123");
|
||||
@Test
|
||||
public void onMessageWrongKeyPrefix() throws Exception {
|
||||
mockMessage("__keyevent@0__:del","spring:session:sessionsNo:123");
|
||||
|
||||
listener.onMessage(message, pattern);
|
||||
listener.onMessage(message, pattern);
|
||||
|
||||
verifyZeroInteractions(eventPublisher);
|
||||
}
|
||||
verifyZeroInteractions(eventPublisher);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onMessageRename() throws Exception {
|
||||
mockMessage("__keyevent@0__:rename","spring:session:sessions:123");
|
||||
@Test
|
||||
public void onMessageRename() throws Exception {
|
||||
mockMessage("__keyevent@0__:rename","spring:session:sessions:123");
|
||||
|
||||
listener.onMessage(message, pattern);
|
||||
listener.onMessage(message, pattern);
|
||||
|
||||
verifyZeroInteractions(eventPublisher);
|
||||
}
|
||||
verifyZeroInteractions(eventPublisher);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onMessageEventPublisherErrorCaught() throws Exception {
|
||||
mockMessage("__keyevent@0__:del","spring:session:sessions:123");
|
||||
doThrow(new IllegalStateException("Test Exceptions are caught")).when(eventPublisher).publishEvent(any(ApplicationEvent.class));
|
||||
@Test
|
||||
public void onMessageEventPublisherErrorCaught() throws Exception {
|
||||
mockMessage("__keyevent@0__:del","spring:session:sessions:123");
|
||||
doThrow(new IllegalStateException("Test Exceptions are caught")).when(eventPublisher).publishEvent(any(ApplicationEvent.class));
|
||||
|
||||
listener.onMessage(message, pattern);
|
||||
listener.onMessage(message, pattern);
|
||||
|
||||
verify(eventPublisher).publishEvent(any(ApplicationEvent.class));
|
||||
}
|
||||
verify(eventPublisher).publishEvent(any(ApplicationEvent.class));
|
||||
}
|
||||
|
||||
private void mockMessage(String channel, String body) throws UnsupportedEncodingException {
|
||||
when(message.getBody()).thenReturn(bytes(body));
|
||||
when(message.getChannel()).thenReturn(bytes(channel));
|
||||
}
|
||||
private void mockMessage(String channel, String body) throws UnsupportedEncodingException {
|
||||
when(message.getBody()).thenReturn(bytes(body));
|
||||
when(message.getChannel()).thenReturn(bytes(channel));
|
||||
}
|
||||
|
||||
private static byte[] bytes(String s) throws UnsupportedEncodingException {
|
||||
return s.getBytes("UTF-8");
|
||||
}
|
||||
private static byte[] bytes(String s) throws UnsupportedEncodingException {
|
||||
return s.getBytes("UTF-8");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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 static org.fest.assertions.Assertions.assertThat;
|
||||
@@ -20,132 +35,132 @@ import java.util.Arrays;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class EnableRedisKeyspaceNotificationsInitializerTests {
|
||||
static final String CONFIG_NOTIFY_KEYSPACE_EVENTS = "notify-keyspace-events";
|
||||
static final String CONFIG_NOTIFY_KEYSPACE_EVENTS = "notify-keyspace-events";
|
||||
|
||||
@Mock
|
||||
RedisConnectionFactory connectionFactory;
|
||||
@Mock
|
||||
RedisConnection connection;
|
||||
@Captor
|
||||
ArgumentCaptor<String> options;
|
||||
@Mock
|
||||
RedisConnectionFactory connectionFactory;
|
||||
@Mock
|
||||
RedisConnection connection;
|
||||
@Captor
|
||||
ArgumentCaptor<String> options;
|
||||
|
||||
EnableRedisKeyspaceNotificationsInitializer initializer;
|
||||
EnableRedisKeyspaceNotificationsInitializer initializer;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
when(connectionFactory.getConnection()).thenReturn(connection);
|
||||
@Before
|
||||
public void setup() {
|
||||
when(connectionFactory.getConnection()).thenReturn(connection);
|
||||
|
||||
initializer = new EnableRedisKeyspaceNotificationsInitializer(connectionFactory);
|
||||
}
|
||||
initializer = new EnableRedisKeyspaceNotificationsInitializer(connectionFactory);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterPropertiesSetUnset() throws Exception {
|
||||
setConfigNotification("");
|
||||
@Test
|
||||
public void afterPropertiesSetUnset() throws Exception {
|
||||
setConfigNotification("");
|
||||
|
||||
initializer.afterPropertiesSet();
|
||||
initializer.afterPropertiesSet();
|
||||
|
||||
assertOptionsContains("E","g","x");
|
||||
}
|
||||
assertOptionsContains("E","g","x");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterPropertiesSetA() throws Exception {
|
||||
setConfigNotification("A");
|
||||
@Test
|
||||
public void afterPropertiesSetA() throws Exception {
|
||||
setConfigNotification("A");
|
||||
|
||||
initializer.afterPropertiesSet();
|
||||
initializer.afterPropertiesSet();
|
||||
|
||||
assertOptionsContains("A", "E");
|
||||
}
|
||||
assertOptionsContains("A", "E");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterPropertiesSetE() throws Exception {
|
||||
setConfigNotification("E");
|
||||
@Test
|
||||
public void afterPropertiesSetE() throws Exception {
|
||||
setConfigNotification("E");
|
||||
|
||||
initializer.afterPropertiesSet();
|
||||
initializer.afterPropertiesSet();
|
||||
|
||||
assertOptionsContains("E", "g", "x");
|
||||
}
|
||||
assertOptionsContains("E", "g", "x");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterPropertiesSetK() throws Exception {
|
||||
setConfigNotification("K");
|
||||
@Test
|
||||
public void afterPropertiesSetK() throws Exception {
|
||||
setConfigNotification("K");
|
||||
|
||||
initializer.afterPropertiesSet();
|
||||
initializer.afterPropertiesSet();
|
||||
|
||||
assertOptionsContains("K", "E", "g", "x");
|
||||
}
|
||||
assertOptionsContains("K", "E", "g", "x");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterPropertiesSetAE() throws Exception {
|
||||
setConfigNotification("AE");
|
||||
@Test
|
||||
public void afterPropertiesSetAE() throws Exception {
|
||||
setConfigNotification("AE");
|
||||
|
||||
initializer.afterPropertiesSet();
|
||||
initializer.afterPropertiesSet();
|
||||
|
||||
verify(connection, never()).setConfig(anyString(), anyString());
|
||||
}
|
||||
verify(connection, never()).setConfig(anyString(), anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterPropertiesSetAK() throws Exception {
|
||||
setConfigNotification("AK");
|
||||
@Test
|
||||
public void afterPropertiesSetAK() throws Exception {
|
||||
setConfigNotification("AK");
|
||||
|
||||
initializer.afterPropertiesSet();
|
||||
initializer.afterPropertiesSet();
|
||||
|
||||
assertOptionsContains("A", "K", "E");
|
||||
}
|
||||
assertOptionsContains("A", "K", "E");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterPropertiesSetEK() throws Exception {
|
||||
setConfigNotification("EK");
|
||||
@Test
|
||||
public void afterPropertiesSetEK() throws Exception {
|
||||
setConfigNotification("EK");
|
||||
|
||||
initializer.afterPropertiesSet();
|
||||
initializer.afterPropertiesSet();
|
||||
|
||||
assertOptionsContains("E", "K", "g", "x");
|
||||
}
|
||||
assertOptionsContains("E", "K", "g", "x");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterPropertiesSetEg() throws Exception {
|
||||
setConfigNotification("Eg");
|
||||
@Test
|
||||
public void afterPropertiesSetEg() throws Exception {
|
||||
setConfigNotification("Eg");
|
||||
|
||||
initializer.afterPropertiesSet();
|
||||
initializer.afterPropertiesSet();
|
||||
|
||||
assertOptionsContains("E", "g", "x");
|
||||
}
|
||||
assertOptionsContains("E", "g", "x");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterPropertiesSetE$() throws Exception {
|
||||
setConfigNotification("E$");
|
||||
@Test
|
||||
public void afterPropertiesSetE$() throws Exception {
|
||||
setConfigNotification("E$");
|
||||
|
||||
initializer.afterPropertiesSet();
|
||||
initializer.afterPropertiesSet();
|
||||
|
||||
assertOptionsContains("E", "$", "g", "x");
|
||||
}
|
||||
assertOptionsContains("E", "$", "g", "x");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterPropertiesSetKg() throws Exception {
|
||||
setConfigNotification("Kg");
|
||||
@Test
|
||||
public void afterPropertiesSetKg() throws Exception {
|
||||
setConfigNotification("Kg");
|
||||
|
||||
initializer.afterPropertiesSet();
|
||||
initializer.afterPropertiesSet();
|
||||
|
||||
assertOptionsContains("K", "g", "E", "x");
|
||||
}
|
||||
assertOptionsContains("K", "g", "E", "x");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterPropertiesSetAEK() throws Exception {
|
||||
setConfigNotification("AEK");
|
||||
@Test
|
||||
public void afterPropertiesSetAEK() throws Exception {
|
||||
setConfigNotification("AEK");
|
||||
|
||||
initializer.afterPropertiesSet();
|
||||
initializer.afterPropertiesSet();
|
||||
|
||||
verify(connection, never()).setConfig(anyString(), anyString());
|
||||
}
|
||||
verify(connection, never()).setConfig(anyString(), anyString());
|
||||
}
|
||||
|
||||
private void assertOptionsContains(String... expectedValues) {
|
||||
verify(connection).setConfig(eq(CONFIG_NOTIFY_KEYSPACE_EVENTS), options.capture());
|
||||
for(String expectedValue : expectedValues) {
|
||||
assertThat(options.getValue()).contains(expectedValue);
|
||||
}
|
||||
assertThat(options.getValue().length()).isEqualTo(expectedValues.length);
|
||||
}
|
||||
private void assertOptionsContains(String... expectedValues) {
|
||||
verify(connection).setConfig(eq(CONFIG_NOTIFY_KEYSPACE_EVENTS), options.capture());
|
||||
for(String expectedValue : expectedValues) {
|
||||
assertThat(options.getValue()).contains(expectedValue);
|
||||
}
|
||||
assertThat(options.getValue().length()).isEqualTo(expectedValues.length);
|
||||
}
|
||||
|
||||
private void setConfigNotification(String value) {
|
||||
when(connection.getConfig(CONFIG_NOTIFY_KEYSPACE_EVENTS)).thenReturn(Arrays.asList(CONFIG_NOTIFY_KEYSPACE_EVENTS, value));
|
||||
}
|
||||
private void setConfigNotification(String value) {
|
||||
when(connection.getConfig(CONFIG_NOTIFY_KEYSPACE_EVENTS)).thenReturn(Arrays.asList(CONFIG_NOTIFY_KEYSPACE_EVENTS, value));
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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.web.http;
|
||||
|
||||
import static org.fest.assertions.Assertions.*;
|
||||
@@ -13,405 +28,405 @@ import javax.servlet.http.Cookie;
|
||||
import java.util.Map;
|
||||
|
||||
public class CookieHttpSessionStrategyTests {
|
||||
private MockHttpServletRequest request;
|
||||
private MockHttpServletResponse response;
|
||||
|
||||
private CookieHttpSessionStrategy strategy;
|
||||
private String cookieName;
|
||||
private Session session;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
cookieName = "SESSION";
|
||||
session = new MapSession();
|
||||
request = new MockHttpServletRequest();
|
||||
response = new MockHttpServletResponse();
|
||||
strategy = new CookieHttpSessionStrategy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRequestedSessionIdNull() throws Exception {
|
||||
assertThat(strategy.getRequestedSessionId(request)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRequestedSessionIdNotNull() throws Exception {
|
||||
setSessionCookie(session.getId());
|
||||
assertThat(strategy.getRequestedSessionId(request)).isEqualTo(session.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRequestedSessionIdNotNullCustomCookieName() throws Exception {
|
||||
setCookieName("CUSTOM");
|
||||
setSessionCookie(session.getId());
|
||||
assertThat(strategy.getRequestedSessionId(request)).isEqualTo(session.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onNewSession() throws Exception {
|
||||
strategy.onNewSession(session, request, response);
|
||||
assertThat(getSessionId()).isEqualTo(session.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onNewSessionExistingSessionSameAlias() throws Exception {
|
||||
Session existing = new MapSession();
|
||||
setSessionCookie(existing.getId());
|
||||
strategy.onNewSession(session, request, response);
|
||||
assertThat(getSessionId()).isEqualTo(session.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onNewSessionExistingSessionNewAlias() throws Exception {
|
||||
Session existing = new MapSession();
|
||||
setSessionCookie(existing.getId());
|
||||
request.setParameter(CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "new");
|
||||
strategy.onNewSession(session, request, response);
|
||||
assertThat(getSessionId()).isEqualTo("0 " + existing.getId() + " new " + session.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onNewSessionCookiePath() throws Exception {
|
||||
request.setContextPath("/somethingunique");
|
||||
strategy.onNewSession(session, request, response);
|
||||
|
||||
Cookie sessionCookie = response.getCookie(cookieName);
|
||||
assertThat(sessionCookie.getPath()).isEqualTo(request.getContextPath() + "/");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onNewSessionCustomCookieName() throws Exception {
|
||||
setCookieName("CUSTOM");
|
||||
strategy.onNewSession(session, request, response);
|
||||
assertThat(getSessionId()).isEqualTo(session.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeleteSession() throws Exception {
|
||||
strategy.onInvalidateSession(request, response);
|
||||
assertThat(getSessionId()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeleteSessionCookiePath() throws Exception {
|
||||
request.setContextPath("/somethingunique");
|
||||
strategy.onInvalidateSession(request, response);
|
||||
|
||||
Cookie sessionCookie = response.getCookie(cookieName);
|
||||
assertThat(sessionCookie.getPath()).isEqualTo(request.getContextPath() + "/");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeleteSessionCustomCookieName() throws Exception {
|
||||
setCookieName("CUSTOM");
|
||||
strategy.onInvalidateSession(request, response);
|
||||
assertThat(getSessionId()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeleteSessionExistingSessionSameAlias() throws Exception {
|
||||
Session existing = new MapSession();
|
||||
setSessionCookie("0 " + existing.getId() + " new " + session.getId());
|
||||
strategy.onInvalidateSession(request, response);
|
||||
assertThat(getSessionId()).isEqualTo(session.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeleteSessionExistingSessionNewAlias() throws Exception {
|
||||
Session existing = new MapSession();
|
||||
setSessionCookie("0 " + existing.getId() + " new " + session.getId());
|
||||
request.setParameter(CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "new");
|
||||
strategy.onInvalidateSession(request, response);
|
||||
assertThat(getSessionId()).isEqualTo(existing.getId());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void setCookieNameNull() throws Exception {
|
||||
strategy.setCookieName(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeURLNoExistingQuery() {
|
||||
assertThat(strategy.encodeURL("/url", "2")).isEqualTo("/url?_s=2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeURLNoExistingQueryEmpty() {
|
||||
assertThat(strategy.encodeURL("/url?", "2")).isEqualTo("/url?_s=2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeURLExistingQueryNoAlias() {
|
||||
assertThat(strategy.encodeURL("/url?a=b", "2")).isEqualTo("/url?a=b&_s=2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeURLExistingQueryExistingAliasStart() {
|
||||
assertThat(strategy.encodeURL("/url?_s=1&y=z", "2")).isEqualTo("/url?_s=2&y=z");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeURLExistingQueryExistingAliasMiddle() {
|
||||
assertThat(strategy.encodeURL("/url?a=b&_s=1&y=z", "2")).isEqualTo("/url?a=b&_s=2&y=z");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeURLExistingQueryExistingAliasEnd() {
|
||||
assertThat(strategy.encodeURL("/url?a=b&_s=1", "2")).isEqualTo("/url?a=b&_s=2");
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@Test
|
||||
public void encodeURLExistingQueryParamEndsWithActualParamStart() {
|
||||
assertThat(strategy.encodeURL("/url?x_s=1&y=z", "2")).isEqualTo("/url?x_s=1&y=z&_s=2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeURLExistingQueryParamEndsWithActualParamMiddle() {
|
||||
assertThat(strategy.encodeURL("/url?a=b&x_s=1&y=z", "2")).isEqualTo("/url?a=b&x_s=1&y=z&_s=2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeURLExistingQueryParamEndsWithActualParamEnd() {
|
||||
assertThat(strategy.encodeURL("/url?a=b&x_s=1", "2")).isEqualTo("/url?a=b&x_s=1&_s=2");
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@Test
|
||||
public void encodeURLNoExistingQueryDefaultAlias() {
|
||||
assertThat(strategy.encodeURL("/url", "0")).isEqualTo("/url");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeURLNoExistingQueryEmptyDefaultAlias() {
|
||||
assertThat(strategy.encodeURL("/url?", "0")).isEqualTo("/url?");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeURLExistingQueryNoAliasDefaultAlias() {
|
||||
assertThat(strategy.encodeURL("/url?a=b", "0")).isEqualTo("/url?a=b");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeURLExistingQueryExistingAliasStartDefaultAlias() {
|
||||
// relaxed constraint as result /url?&y=z does not hurt anything (ideally should remove the &)
|
||||
assertThat(strategy.encodeURL("/url?_s=1&y=z", "0")).doesNotContain("_s=0&_s=1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeURLExistingQueryExistingAliasMiddleDefaultAlias() {
|
||||
assertThat(strategy.encodeURL("/url?a=b&_s=1&y=z", "0")).isEqualTo("/url?a=b&y=z");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeURLExistingQueryExistingAliasEndDefaultAlias() {
|
||||
assertThat(strategy.encodeURL("/url?a=b&_s=1", "0")).isEqualTo("/url?a=b");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeURLMaliciousAlias() {
|
||||
assertThat(strategy.encodeURL("/url?a=b&_s=1", "\"> <script>alert('hi')</script>")).isEqualTo("/url?a=b&_s=%22%3E+%3Cscript%3Ealert%28%27hi%27%29%3C%2Fscript%3E");
|
||||
}
|
||||
|
||||
// --- getCurrentSessionAlias
|
||||
|
||||
@Test
|
||||
public void getCurrentSessionAliasNull() {
|
||||
assertThat(strategy.getCurrentSessionAlias(request)).isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCurrentSessionAliasNullParamName() {
|
||||
strategy.setSessionAliasParamName(null);
|
||||
request.setParameter(CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "NOT USED");
|
||||
|
||||
assertThat(strategy.getCurrentSessionAlias(request)).isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS);
|
||||
}
|
||||
|
||||
// protect against malicious users
|
||||
@Test
|
||||
public void getCurrentSessionAliasContainsQuote() {
|
||||
request.setParameter(CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "here\"this");
|
||||
private MockHttpServletRequest request;
|
||||
private MockHttpServletResponse response;
|
||||
|
||||
private CookieHttpSessionStrategy strategy;
|
||||
private String cookieName;
|
||||
private Session session;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
cookieName = "SESSION";
|
||||
session = new MapSession();
|
||||
request = new MockHttpServletRequest();
|
||||
response = new MockHttpServletResponse();
|
||||
strategy = new CookieHttpSessionStrategy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRequestedSessionIdNull() throws Exception {
|
||||
assertThat(strategy.getRequestedSessionId(request)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRequestedSessionIdNotNull() throws Exception {
|
||||
setSessionCookie(session.getId());
|
||||
assertThat(strategy.getRequestedSessionId(request)).isEqualTo(session.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRequestedSessionIdNotNullCustomCookieName() throws Exception {
|
||||
setCookieName("CUSTOM");
|
||||
setSessionCookie(session.getId());
|
||||
assertThat(strategy.getRequestedSessionId(request)).isEqualTo(session.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onNewSession() throws Exception {
|
||||
strategy.onNewSession(session, request, response);
|
||||
assertThat(getSessionId()).isEqualTo(session.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onNewSessionExistingSessionSameAlias() throws Exception {
|
||||
Session existing = new MapSession();
|
||||
setSessionCookie(existing.getId());
|
||||
strategy.onNewSession(session, request, response);
|
||||
assertThat(getSessionId()).isEqualTo(session.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onNewSessionExistingSessionNewAlias() throws Exception {
|
||||
Session existing = new MapSession();
|
||||
setSessionCookie(existing.getId());
|
||||
request.setParameter(CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "new");
|
||||
strategy.onNewSession(session, request, response);
|
||||
assertThat(getSessionId()).isEqualTo("0 " + existing.getId() + " new " + session.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onNewSessionCookiePath() throws Exception {
|
||||
request.setContextPath("/somethingunique");
|
||||
strategy.onNewSession(session, request, response);
|
||||
|
||||
Cookie sessionCookie = response.getCookie(cookieName);
|
||||
assertThat(sessionCookie.getPath()).isEqualTo(request.getContextPath() + "/");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onNewSessionCustomCookieName() throws Exception {
|
||||
setCookieName("CUSTOM");
|
||||
strategy.onNewSession(session, request, response);
|
||||
assertThat(getSessionId()).isEqualTo(session.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeleteSession() throws Exception {
|
||||
strategy.onInvalidateSession(request, response);
|
||||
assertThat(getSessionId()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeleteSessionCookiePath() throws Exception {
|
||||
request.setContextPath("/somethingunique");
|
||||
strategy.onInvalidateSession(request, response);
|
||||
|
||||
Cookie sessionCookie = response.getCookie(cookieName);
|
||||
assertThat(sessionCookie.getPath()).isEqualTo(request.getContextPath() + "/");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeleteSessionCustomCookieName() throws Exception {
|
||||
setCookieName("CUSTOM");
|
||||
strategy.onInvalidateSession(request, response);
|
||||
assertThat(getSessionId()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeleteSessionExistingSessionSameAlias() throws Exception {
|
||||
Session existing = new MapSession();
|
||||
setSessionCookie("0 " + existing.getId() + " new " + session.getId());
|
||||
strategy.onInvalidateSession(request, response);
|
||||
assertThat(getSessionId()).isEqualTo(session.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeleteSessionExistingSessionNewAlias() throws Exception {
|
||||
Session existing = new MapSession();
|
||||
setSessionCookie("0 " + existing.getId() + " new " + session.getId());
|
||||
request.setParameter(CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "new");
|
||||
strategy.onInvalidateSession(request, response);
|
||||
assertThat(getSessionId()).isEqualTo(existing.getId());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void setCookieNameNull() throws Exception {
|
||||
strategy.setCookieName(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeURLNoExistingQuery() {
|
||||
assertThat(strategy.encodeURL("/url", "2")).isEqualTo("/url?_s=2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeURLNoExistingQueryEmpty() {
|
||||
assertThat(strategy.encodeURL("/url?", "2")).isEqualTo("/url?_s=2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeURLExistingQueryNoAlias() {
|
||||
assertThat(strategy.encodeURL("/url?a=b", "2")).isEqualTo("/url?a=b&_s=2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeURLExistingQueryExistingAliasStart() {
|
||||
assertThat(strategy.encodeURL("/url?_s=1&y=z", "2")).isEqualTo("/url?_s=2&y=z");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeURLExistingQueryExistingAliasMiddle() {
|
||||
assertThat(strategy.encodeURL("/url?a=b&_s=1&y=z", "2")).isEqualTo("/url?a=b&_s=2&y=z");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeURLExistingQueryExistingAliasEnd() {
|
||||
assertThat(strategy.encodeURL("/url?a=b&_s=1", "2")).isEqualTo("/url?a=b&_s=2");
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@Test
|
||||
public void encodeURLExistingQueryParamEndsWithActualParamStart() {
|
||||
assertThat(strategy.encodeURL("/url?x_s=1&y=z", "2")).isEqualTo("/url?x_s=1&y=z&_s=2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeURLExistingQueryParamEndsWithActualParamMiddle() {
|
||||
assertThat(strategy.encodeURL("/url?a=b&x_s=1&y=z", "2")).isEqualTo("/url?a=b&x_s=1&y=z&_s=2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeURLExistingQueryParamEndsWithActualParamEnd() {
|
||||
assertThat(strategy.encodeURL("/url?a=b&x_s=1", "2")).isEqualTo("/url?a=b&x_s=1&_s=2");
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@Test
|
||||
public void encodeURLNoExistingQueryDefaultAlias() {
|
||||
assertThat(strategy.encodeURL("/url", "0")).isEqualTo("/url");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeURLNoExistingQueryEmptyDefaultAlias() {
|
||||
assertThat(strategy.encodeURL("/url?", "0")).isEqualTo("/url?");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeURLExistingQueryNoAliasDefaultAlias() {
|
||||
assertThat(strategy.encodeURL("/url?a=b", "0")).isEqualTo("/url?a=b");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeURLExistingQueryExistingAliasStartDefaultAlias() {
|
||||
// relaxed constraint as result /url?&y=z does not hurt anything (ideally should remove the &)
|
||||
assertThat(strategy.encodeURL("/url?_s=1&y=z", "0")).doesNotContain("_s=0&_s=1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeURLExistingQueryExistingAliasMiddleDefaultAlias() {
|
||||
assertThat(strategy.encodeURL("/url?a=b&_s=1&y=z", "0")).isEqualTo("/url?a=b&y=z");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeURLExistingQueryExistingAliasEndDefaultAlias() {
|
||||
assertThat(strategy.encodeURL("/url?a=b&_s=1", "0")).isEqualTo("/url?a=b");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodeURLMaliciousAlias() {
|
||||
assertThat(strategy.encodeURL("/url?a=b&_s=1", "\"> <script>alert('hi')</script>")).isEqualTo("/url?a=b&_s=%22%3E+%3Cscript%3Ealert%28%27hi%27%29%3C%2Fscript%3E");
|
||||
}
|
||||
|
||||
// --- getCurrentSessionAlias
|
||||
|
||||
@Test
|
||||
public void getCurrentSessionAliasNull() {
|
||||
assertThat(strategy.getCurrentSessionAlias(request)).isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCurrentSessionAliasNullParamName() {
|
||||
strategy.setSessionAliasParamName(null);
|
||||
request.setParameter(CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "NOT USED");
|
||||
|
||||
assertThat(strategy.getCurrentSessionAlias(request)).isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS);
|
||||
}
|
||||
|
||||
// protect against malicious users
|
||||
@Test
|
||||
public void getCurrentSessionAliasContainsQuote() {
|
||||
request.setParameter(CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "here\"this");
|
||||
|
||||
assertThat(strategy.getCurrentSessionAlias(request)).isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS);
|
||||
}
|
||||
assertThat(strategy.getCurrentSessionAlias(request)).isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCurrentSessionAliasContainsSingleQuote() {
|
||||
request.setParameter(CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "here'this");
|
||||
@Test
|
||||
public void getCurrentSessionAliasContainsSingleQuote() {
|
||||
request.setParameter(CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "here'this");
|
||||
|
||||
assertThat(strategy.getCurrentSessionAlias(request)).isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS);
|
||||
}
|
||||
assertThat(strategy.getCurrentSessionAlias(request)).isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCurrentSessionAliasContainsSpace() {
|
||||
request.setParameter(CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "here this");
|
||||
@Test
|
||||
public void getCurrentSessionAliasContainsSpace() {
|
||||
request.setParameter(CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "here this");
|
||||
|
||||
assertThat(strategy.getCurrentSessionAlias(request)).isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS);
|
||||
}
|
||||
assertThat(strategy.getCurrentSessionAlias(request)).isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCurrentSessionAliasContainsLt() {
|
||||
request.setParameter(CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "here<this");
|
||||
@Test
|
||||
public void getCurrentSessionAliasContainsLt() {
|
||||
request.setParameter(CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "here<this");
|
||||
|
||||
assertThat(strategy.getCurrentSessionAlias(request)).isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS);
|
||||
}
|
||||
assertThat(strategy.getCurrentSessionAlias(request)).isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCurrentSessionAliasContainsGt() {
|
||||
strategy.setSessionAliasParamName(null);
|
||||
request.setParameter(CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "here>this");
|
||||
|
||||
assertThat(strategy.getCurrentSessionAlias(request)).isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS);
|
||||
}
|
||||
@Test
|
||||
public void getCurrentSessionAliasContainsGt() {
|
||||
strategy.setSessionAliasParamName(null);
|
||||
request.setParameter(CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "here>this");
|
||||
|
||||
assertThat(strategy.getCurrentSessionAlias(request)).isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCurrentSessionAliasTooLong() {
|
||||
request.setParameter(CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "012345678901234567890123456789012345678901234567890");
|
||||
@Test
|
||||
public void getCurrentSessionAliasTooLong() {
|
||||
request.setParameter(CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "012345678901234567890123456789012345678901234567890");
|
||||
|
||||
assertThat(strategy.getCurrentSessionAlias(request)).isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS);
|
||||
}
|
||||
|
||||
// We want some sort of length restrictions, but want to ensure some sort of length Technically no hard limit, but chose 50
|
||||
@Test
|
||||
public void getCurrentSessionAliasAllows50() {
|
||||
request.setParameter(CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "01234567890123456789012345678901234567890123456789");
|
||||
assertThat(strategy.getCurrentSessionAlias(request)).isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS);
|
||||
}
|
||||
|
||||
// We want some sort of length restrictions, but want to ensure some sort of length Technically no hard limit, but chose 50
|
||||
@Test
|
||||
public void getCurrentSessionAliasAllows50() {
|
||||
request.setParameter(CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "01234567890123456789012345678901234567890123456789");
|
||||
|
||||
assertThat(strategy.getCurrentSessionAlias(request)).isEqualTo("01234567890123456789012345678901234567890123456789");
|
||||
}
|
||||
assertThat(strategy.getCurrentSessionAlias(request)).isEqualTo("01234567890123456789012345678901234567890123456789");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCurrentSession() {
|
||||
String expectedAlias = "1";
|
||||
request.setParameter(CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, expectedAlias);
|
||||
assertThat(strategy.getCurrentSessionAlias(request)).isEqualTo(expectedAlias);
|
||||
}
|
||||
@Test
|
||||
public void getCurrentSession() {
|
||||
String expectedAlias = "1";
|
||||
request.setParameter(CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, expectedAlias);
|
||||
assertThat(strategy.getCurrentSessionAlias(request)).isEqualTo(expectedAlias);
|
||||
}
|
||||
|
||||
// --- getNewSessionAlias
|
||||
// --- getNewSessionAlias
|
||||
|
||||
@Test
|
||||
public void getNewSessionAliasNoSessions() {
|
||||
assertThat(strategy.getNewSessionAlias(request)).isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNewSessionAliasSingleSession() {
|
||||
setSessionCookie("abc");
|
||||
@Test
|
||||
public void getNewSessionAliasNoSessions() {
|
||||
assertThat(strategy.getNewSessionAlias(request)).isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNewSessionAliasSingleSession() {
|
||||
setSessionCookie("abc");
|
||||
|
||||
assertThat(strategy.getNewSessionAlias(request)).isEqualTo("1");
|
||||
}
|
||||
assertThat(strategy.getNewSessionAlias(request)).isEqualTo("1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNewSessionAlias2Sessions() {
|
||||
setCookieWithNSessions(2);
|
||||
@Test
|
||||
public void getNewSessionAlias2Sessions() {
|
||||
setCookieWithNSessions(2);
|
||||
|
||||
assertThat(strategy.getNewSessionAlias(request)).isEqualTo("2");
|
||||
}
|
||||
assertThat(strategy.getNewSessionAlias(request)).isEqualTo("2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNewSessionAlias9Sessions() {
|
||||
setCookieWithNSessions(9);
|
||||
@Test
|
||||
public void getNewSessionAlias9Sessions() {
|
||||
setCookieWithNSessions(9);
|
||||
|
||||
assertThat(strategy.getNewSessionAlias(request)).isEqualToIgnoringCase("9");
|
||||
}
|
||||
assertThat(strategy.getNewSessionAlias(request)).isEqualToIgnoringCase("9");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNewSessionAlias10Sessions() {
|
||||
setCookieWithNSessions(10);
|
||||
@Test
|
||||
public void getNewSessionAlias10Sessions() {
|
||||
setCookieWithNSessions(10);
|
||||
|
||||
assertThat(strategy.getNewSessionAlias(request)).isEqualToIgnoringCase("a");
|
||||
}
|
||||
assertThat(strategy.getNewSessionAlias(request)).isEqualToIgnoringCase("a");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNewSessionAlias16Sessions() {
|
||||
setCookieWithNSessions(16);
|
||||
@Test
|
||||
public void getNewSessionAlias16Sessions() {
|
||||
setCookieWithNSessions(16);
|
||||
|
||||
assertThat(strategy.getNewSessionAlias(request)).isEqualToIgnoringCase("10");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNewSessionAliasInvalidAlias() {
|
||||
setSessionCookie("0 1 $ b");
|
||||
assertThat(strategy.getNewSessionAlias(request)).isEqualToIgnoringCase("10");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNewSessionAliasInvalidAlias() {
|
||||
setSessionCookie("0 1 $ b");
|
||||
|
||||
assertThat(strategy.getNewSessionAlias(request)).isEqualToIgnoringCase("1");
|
||||
}
|
||||
assertThat(strategy.getNewSessionAlias(request)).isEqualToIgnoringCase("1");
|
||||
}
|
||||
|
||||
// --- getSessionIds
|
||||
// --- getSessionIds
|
||||
|
||||
@Test
|
||||
public void getSessionIdsNone() {
|
||||
assertThat(strategy.getSessionIds(request)).isEmpty();
|
||||
}
|
||||
@Test
|
||||
public void getSessionIdsNone() {
|
||||
assertThat(strategy.getSessionIds(request)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSessionIdsSingle() {
|
||||
String expectedId = "a";
|
||||
setSessionCookie(expectedId);
|
||||
|
||||
Map<String, String> sessionIds = strategy.getSessionIds(request);
|
||||
assertThat(sessionIds.size()).isEqualTo(1);
|
||||
assertThat(sessionIds.get("0")).isEqualTo(expectedId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSessionIdsMulti() {
|
||||
setSessionCookie("0 a 1 b");
|
||||
|
||||
Map<String, String> sessionIds = strategy.getSessionIds(request);
|
||||
assertThat(sessionIds.size()).isEqualTo(2);
|
||||
assertThat(sessionIds.get("0")).isEqualTo("a");
|
||||
assertThat(sessionIds.get("1")).isEqualTo("b");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSessionIdsDangling() {
|
||||
setSessionCookie("0 a 1 b noValue");
|
||||
|
||||
Map<String, String> sessionIds = strategy.getSessionIds(request);
|
||||
assertThat(sessionIds.size()).isEqualTo(2);
|
||||
assertThat(sessionIds.get("0")).isEqualTo("a");
|
||||
assertThat(sessionIds.get("1")).isEqualTo("b");
|
||||
}
|
||||
|
||||
// --- helper
|
||||
|
||||
@Test
|
||||
public void createSessionCookieValue() {
|
||||
assertThat(createSessionCookieValue(17)).isEqualToIgnoringCase("0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 a 10 b 11 c 12 d 13 e 14 f 15 10 16");
|
||||
}
|
||||
|
||||
private void setCookieWithNSessions(long size) {
|
||||
setSessionCookie(createSessionCookieValue(size));
|
||||
}
|
||||
|
||||
private String createSessionCookieValue(long size) {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
@Test
|
||||
public void getSessionIdsSingle() {
|
||||
String expectedId = "a";
|
||||
setSessionCookie(expectedId);
|
||||
|
||||
Map<String, String> sessionIds = strategy.getSessionIds(request);
|
||||
assertThat(sessionIds.size()).isEqualTo(1);
|
||||
assertThat(sessionIds.get("0")).isEqualTo(expectedId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSessionIdsMulti() {
|
||||
setSessionCookie("0 a 1 b");
|
||||
|
||||
Map<String, String> sessionIds = strategy.getSessionIds(request);
|
||||
assertThat(sessionIds.size()).isEqualTo(2);
|
||||
assertThat(sessionIds.get("0")).isEqualTo("a");
|
||||
assertThat(sessionIds.get("1")).isEqualTo("b");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSessionIdsDangling() {
|
||||
setSessionCookie("0 a 1 b noValue");
|
||||
|
||||
Map<String, String> sessionIds = strategy.getSessionIds(request);
|
||||
assertThat(sessionIds.size()).isEqualTo(2);
|
||||
assertThat(sessionIds.get("0")).isEqualTo("a");
|
||||
assertThat(sessionIds.get("1")).isEqualTo("b");
|
||||
}
|
||||
|
||||
// --- helper
|
||||
|
||||
@Test
|
||||
public void createSessionCookieValue() {
|
||||
assertThat(createSessionCookieValue(17)).isEqualToIgnoringCase("0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 a 10 b 11 c 12 d 13 e 14 f 15 10 16");
|
||||
}
|
||||
|
||||
private void setCookieWithNSessions(long size) {
|
||||
setSessionCookie(createSessionCookieValue(size));
|
||||
}
|
||||
|
||||
private String createSessionCookieValue(long size) {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
||||
for(long i=0;i < size; i++) {
|
||||
String hex = Long.toHexString(i);
|
||||
buffer.append(hex);
|
||||
buffer.append(" ");
|
||||
buffer.append(i);
|
||||
if(i < size - 1) {
|
||||
buffer.append(" ");
|
||||
}
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public void setCookieName(String cookieName) {
|
||||
strategy.setCookieName(cookieName);
|
||||
this.cookieName = cookieName;
|
||||
}
|
||||
|
||||
public void setSessionCookie(String value) {
|
||||
request.setCookies(new Cookie(cookieName, value));
|
||||
}
|
||||
|
||||
public String getSessionId() {
|
||||
return response.getCookie(cookieName).getValue();
|
||||
}
|
||||
for(long i=0;i < size; i++) {
|
||||
String hex = Long.toHexString(i);
|
||||
buffer.append(hex);
|
||||
buffer.append(" ");
|
||||
buffer.append(i);
|
||||
if(i < size - 1) {
|
||||
buffer.append(" ");
|
||||
}
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public void setCookieName(String cookieName) {
|
||||
strategy.setCookieName(cookieName);
|
||||
this.cookieName = cookieName;
|
||||
}
|
||||
|
||||
public void setSessionCookie(String value) {
|
||||
request.setCookies(new Cookie(cookieName, value));
|
||||
}
|
||||
|
||||
public String getSessionId() {
|
||||
return response.getCookie(cookieName).getValue();
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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.web.http;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -11,102 +26,102 @@ import org.springframework.session.web.http.HeaderHttpSessionStrategy;
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
|
||||
public class HeaderSessionStrategyTests {
|
||||
private MockHttpServletRequest request;
|
||||
private MockHttpServletResponse response;
|
||||
private MockHttpServletRequest request;
|
||||
private MockHttpServletResponse response;
|
||||
|
||||
private HeaderHttpSessionStrategy strategy;
|
||||
private String headerName;
|
||||
private Session session;
|
||||
private HeaderHttpSessionStrategy strategy;
|
||||
private String headerName;
|
||||
private Session session;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
headerName = "x-auth-token";
|
||||
session = new MapSession();
|
||||
request = new MockHttpServletRequest();
|
||||
response = new MockHttpServletResponse();
|
||||
strategy = new HeaderHttpSessionStrategy();
|
||||
}
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
headerName = "x-auth-token";
|
||||
session = new MapSession();
|
||||
request = new MockHttpServletRequest();
|
||||
response = new MockHttpServletResponse();
|
||||
strategy = new HeaderHttpSessionStrategy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRequestedSessionIdNull() throws Exception {
|
||||
assertThat(strategy.getRequestedSessionId(request)).isNull();
|
||||
}
|
||||
@Test
|
||||
public void getRequestedSessionIdNull() throws Exception {
|
||||
assertThat(strategy.getRequestedSessionId(request)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRequestedSessionIdNotNull() throws Exception {
|
||||
setSessionId(session.getId());
|
||||
assertThat(strategy.getRequestedSessionId(request)).isEqualTo(session.getId());
|
||||
}
|
||||
@Test
|
||||
public void getRequestedSessionIdNotNull() throws Exception {
|
||||
setSessionId(session.getId());
|
||||
assertThat(strategy.getRequestedSessionId(request)).isEqualTo(session.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRequestedSessionIdNotNullCustomHeaderName() throws Exception {
|
||||
setHeaderName("CUSTOM");
|
||||
setSessionId(session.getId());
|
||||
assertThat(strategy.getRequestedSessionId(request)).isEqualTo(session.getId());
|
||||
}
|
||||
@Test
|
||||
public void getRequestedSessionIdNotNullCustomHeaderName() throws Exception {
|
||||
setHeaderName("CUSTOM");
|
||||
setSessionId(session.getId());
|
||||
assertThat(strategy.getRequestedSessionId(request)).isEqualTo(session.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onNewSession() throws Exception {
|
||||
strategy.onNewSession(session, request, response);
|
||||
assertThat(getSessionId()).isEqualTo(session.getId());
|
||||
}
|
||||
@Test
|
||||
public void onNewSession() throws Exception {
|
||||
strategy.onNewSession(session, request, response);
|
||||
assertThat(getSessionId()).isEqualTo(session.getId());
|
||||
}
|
||||
|
||||
// the header is set as apposed to added
|
||||
@Test
|
||||
public void onNewSessionMulti() throws Exception {
|
||||
strategy.onNewSession(session, request, response);
|
||||
strategy.onNewSession(session, request, response);
|
||||
// the header is set as apposed to added
|
||||
@Test
|
||||
public void onNewSessionMulti() throws Exception {
|
||||
strategy.onNewSession(session, request, response);
|
||||
strategy.onNewSession(session, request, response);
|
||||
|
||||
assertThat(response.getHeaders(headerName).size()).isEqualTo(1);
|
||||
assertThat(response.getHeaders(headerName)).containsOnly(session.getId());
|
||||
}
|
||||
assertThat(response.getHeaders(headerName).size()).isEqualTo(1);
|
||||
assertThat(response.getHeaders(headerName)).containsOnly(session.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onNewSessionCustomHeaderName() throws Exception {
|
||||
setHeaderName("CUSTOM");
|
||||
strategy.onNewSession(session, request, response);
|
||||
assertThat(getSessionId()).isEqualTo(session.getId());
|
||||
}
|
||||
@Test
|
||||
public void onNewSessionCustomHeaderName() throws Exception {
|
||||
setHeaderName("CUSTOM");
|
||||
strategy.onNewSession(session, request, response);
|
||||
assertThat(getSessionId()).isEqualTo(session.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeleteSession() throws Exception {
|
||||
strategy.onInvalidateSession(request, response);
|
||||
assertThat(getSessionId()).isEmpty();
|
||||
}
|
||||
@Test
|
||||
public void onDeleteSession() throws Exception {
|
||||
strategy.onInvalidateSession(request, response);
|
||||
assertThat(getSessionId()).isEmpty();
|
||||
}
|
||||
|
||||
|
||||
// the header is set as apposed to added
|
||||
@Test
|
||||
public void onDeleteSessionMulti() throws Exception {
|
||||
strategy.onInvalidateSession(request, response);
|
||||
strategy.onInvalidateSession(request, response);
|
||||
// the header is set as apposed to added
|
||||
@Test
|
||||
public void onDeleteSessionMulti() throws Exception {
|
||||
strategy.onInvalidateSession(request, response);
|
||||
strategy.onInvalidateSession(request, response);
|
||||
|
||||
assertThat(response.getHeaders(headerName).size()).isEqualTo(1);
|
||||
assertThat(getSessionId()).isEmpty();
|
||||
}
|
||||
assertThat(response.getHeaders(headerName).size()).isEqualTo(1);
|
||||
assertThat(getSessionId()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeleteSessionCustomHeaderName() throws Exception {
|
||||
setHeaderName("CUSTOM");
|
||||
strategy.onInvalidateSession(request, response);
|
||||
assertThat(getSessionId()).isEmpty();
|
||||
}
|
||||
@Test
|
||||
public void onDeleteSessionCustomHeaderName() throws Exception {
|
||||
setHeaderName("CUSTOM");
|
||||
strategy.onInvalidateSession(request, response);
|
||||
assertThat(getSessionId()).isEmpty();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void setHeaderNameNull() throws Exception {
|
||||
strategy.setHeaderName(null);
|
||||
}
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void setHeaderNameNull() throws Exception {
|
||||
strategy.setHeaderName(null);
|
||||
}
|
||||
|
||||
public void setHeaderName(String headerName) {
|
||||
strategy.setHeaderName(headerName);
|
||||
this.headerName = headerName;
|
||||
}
|
||||
public void setHeaderName(String headerName) {
|
||||
strategy.setHeaderName(headerName);
|
||||
this.headerName = headerName;
|
||||
}
|
||||
|
||||
public void setSessionId(String id) {
|
||||
request.addHeader(headerName, id);
|
||||
}
|
||||
public void setSessionId(String id) {
|
||||
request.addHeader(headerName, id);
|
||||
}
|
||||
|
||||
public String getSessionId() {
|
||||
return response.getHeader(headerName);
|
||||
}
|
||||
public String getSessionId() {
|
||||
return response.getHeader(headerName);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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.web.http;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -20,57 +35,57 @@ import java.util.List;
|
||||
import static org.fest.assertions.Assertions.*;
|
||||
|
||||
public class OncePerRequestFilterTests {
|
||||
private MockHttpServletRequest request;
|
||||
private MockHttpServletResponse response;
|
||||
private MockFilterChain chain;
|
||||
private OncePerRequestFilter filter;
|
||||
private HttpServlet servlet;
|
||||
private MockHttpServletRequest request;
|
||||
private MockHttpServletResponse response;
|
||||
private MockFilterChain chain;
|
||||
private OncePerRequestFilter filter;
|
||||
private HttpServlet servlet;
|
||||
|
||||
|
||||
private List<OncePerRequestFilter> invocations;
|
||||
private List<OncePerRequestFilter> invocations;
|
||||
|
||||
@Before
|
||||
@SuppressWarnings("serial")
|
||||
public void setup() {
|
||||
servlet = new HttpServlet() {};
|
||||
request = new MockHttpServletRequest();
|
||||
response = new MockHttpServletResponse();
|
||||
chain = new MockFilterChain();
|
||||
invocations = new ArrayList<OncePerRequestFilter>();
|
||||
filter = new OncePerRequestFilter() {
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||
invocations.add(this);
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
};
|
||||
}
|
||||
@Before
|
||||
@SuppressWarnings("serial")
|
||||
public void setup() {
|
||||
servlet = new HttpServlet() {};
|
||||
request = new MockHttpServletRequest();
|
||||
response = new MockHttpServletResponse();
|
||||
chain = new MockFilterChain();
|
||||
invocations = new ArrayList<OncePerRequestFilter>();
|
||||
filter = new OncePerRequestFilter() {
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||
invocations.add(this);
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterOnce() throws ServletException, IOException {
|
||||
filter.doFilter(request, response, chain);
|
||||
@Test
|
||||
public void doFilterOnce() throws ServletException, IOException {
|
||||
filter.doFilter(request, response, chain);
|
||||
|
||||
assertThat(invocations).containsOnly(filter);
|
||||
}
|
||||
assertThat(invocations).containsOnly(filter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterMultiOnlyIvokesOnce() throws ServletException, IOException {
|
||||
filter.doFilter(request, response, new MockFilterChain(servlet, filter));
|
||||
@Test
|
||||
public void doFilterMultiOnlyIvokesOnce() throws ServletException, IOException {
|
||||
filter.doFilter(request, response, new MockFilterChain(servlet, filter));
|
||||
|
||||
assertThat(invocations).containsOnly(filter);
|
||||
}
|
||||
assertThat(invocations).containsOnly(filter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterOtherSubclassInvoked() throws ServletException, IOException {
|
||||
OncePerRequestFilter filter2 = new OncePerRequestFilter() {
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||
invocations.add(this);
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
};
|
||||
filter.doFilter(request, response, new MockFilterChain(servlet, filter2));
|
||||
@Test
|
||||
public void doFilterOtherSubclassInvoked() throws ServletException, IOException {
|
||||
OncePerRequestFilter filter2 = new OncePerRequestFilter() {
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||
invocations.add(this);
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
};
|
||||
filter.doFilter(request, response, new MockFilterChain(servlet, filter2));
|
||||
|
||||
assertThat(invocations).containsOnly(filter, filter2);
|
||||
}
|
||||
assertThat(invocations).containsOnly(filter, filter2);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -33,44 +33,44 @@ import org.springframework.web.socket.WebSocketSession;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class WebSocketConnectHandlerDecoratorFactoryTests {
|
||||
@Mock
|
||||
ApplicationEventPublisher eventPublisher;
|
||||
@Mock
|
||||
WebSocketHandler delegate;
|
||||
@Mock
|
||||
WebSocketSession session;
|
||||
@Captor
|
||||
ArgumentCaptor<SessionConnectEvent> event;
|
||||
@Mock
|
||||
ApplicationEventPublisher eventPublisher;
|
||||
@Mock
|
||||
WebSocketHandler delegate;
|
||||
@Mock
|
||||
WebSocketSession session;
|
||||
@Captor
|
||||
ArgumentCaptor<SessionConnectEvent> event;
|
||||
|
||||
WebSocketConnectHandlerDecoratorFactory factory;
|
||||
WebSocketConnectHandlerDecoratorFactory factory;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
factory = new WebSocketConnectHandlerDecoratorFactory(eventPublisher);
|
||||
}
|
||||
@Before
|
||||
public void setup() {
|
||||
factory = new WebSocketConnectHandlerDecoratorFactory(eventPublisher);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructorNullEventPublisher() {
|
||||
new WebSocketConnectHandlerDecoratorFactory(null);
|
||||
}
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructorNullEventPublisher() {
|
||||
new WebSocketConnectHandlerDecoratorFactory(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decorateAfterConnectionEstablished() throws Exception {
|
||||
WebSocketHandler decorated = factory.decorate(delegate);
|
||||
@Test
|
||||
public void decorateAfterConnectionEstablished() throws Exception {
|
||||
WebSocketHandler decorated = factory.decorate(delegate);
|
||||
|
||||
decorated.afterConnectionEstablished(session);
|
||||
decorated.afterConnectionEstablished(session);
|
||||
|
||||
verify(eventPublisher).publishEvent(event.capture());
|
||||
assertThat(event.getValue().getWebSocketSession()).isSameAs(session);
|
||||
}
|
||||
verify(eventPublisher).publishEvent(event.capture());
|
||||
assertThat(event.getValue().getWebSocketSession()).isSameAs(session);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decorateAfterConnectionEstablishedEventError() throws Exception {
|
||||
WebSocketHandler decorated = factory.decorate(delegate);
|
||||
doThrow(new IllegalStateException("Test throw on publishEvent")).when(eventPublisher).publishEvent(any(ApplicationEvent.class));
|
||||
@Test
|
||||
public void decorateAfterConnectionEstablishedEventError() throws Exception {
|
||||
WebSocketHandler decorated = factory.decorate(delegate);
|
||||
doThrow(new IllegalStateException("Test throw on publishEvent")).when(eventPublisher).publishEvent(any(ApplicationEvent.class));
|
||||
|
||||
decorated.afterConnectionEstablished(session);
|
||||
decorated.afterConnectionEstablished(session);
|
||||
|
||||
verify(eventPublisher).publishEvent(any(SessionConnectEvent.class));
|
||||
}
|
||||
verify(eventPublisher).publishEvent(any(SessionConnectEvent.class));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -16,7 +16,10 @@
|
||||
package org.springframework.session.web.socket.handler;
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.HashMap;
|
||||
@@ -26,7 +29,6 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.internal.util.reflection.Whitebox;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
@@ -41,115 +43,116 @@ import org.springframework.web.socket.messaging.SessionDisconnectEvent;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class WebSocketRegistryListenerTests {
|
||||
@Mock
|
||||
WebSocketSession wsSession;
|
||||
@Mock
|
||||
WebSocketSession wsSession2;
|
||||
@Mock
|
||||
Message<byte[]> message;
|
||||
@Mock
|
||||
Principal principal;
|
||||
@Mock
|
||||
WebSocketSession wsSession;
|
||||
@Mock
|
||||
WebSocketSession wsSession2;
|
||||
@Mock
|
||||
Message<byte[]> message;
|
||||
@Mock
|
||||
Principal principal;
|
||||
|
||||
SessionConnectEvent connect;
|
||||
SessionConnectEvent connect;
|
||||
|
||||
SessionConnectEvent connect2;
|
||||
SessionConnectEvent connect2;
|
||||
|
||||
SessionDisconnectEvent disconnect;
|
||||
SessionDisconnectEvent disconnect;
|
||||
|
||||
SessionDestroyedEvent destroyed;
|
||||
SessionDestroyedEvent destroyed;
|
||||
|
||||
Map<String, Object> attributes;
|
||||
Map<String, Object> attributes;
|
||||
|
||||
String sessionId;
|
||||
String sessionId;
|
||||
|
||||
WebSocketRegistryListener listener;
|
||||
WebSocketRegistryListener listener;
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
sessionId = "session-id";
|
||||
attributes = new HashMap<String,Object>();
|
||||
SessionRepositoryMessageInterceptor.setSessionId(attributes, sessionId);
|
||||
@Before
|
||||
public void setup() {
|
||||
sessionId = "session-id";
|
||||
attributes = new HashMap<String,Object>();
|
||||
SessionRepositoryMessageInterceptor.setSessionId(attributes, sessionId);
|
||||
|
||||
when(wsSession.getAttributes()).thenReturn(attributes);
|
||||
when(wsSession.getPrincipal()).thenReturn(principal);
|
||||
when(wsSession.getId()).thenReturn("wsSession-id");
|
||||
when(wsSession.getAttributes()).thenReturn(attributes);
|
||||
when(wsSession.getPrincipal()).thenReturn(principal);
|
||||
when(wsSession.getId()).thenReturn("wsSession-id");
|
||||
|
||||
when(wsSession2.getAttributes()).thenReturn(attributes);
|
||||
when(wsSession2.getPrincipal()).thenReturn(principal);
|
||||
when(wsSession2.getId()).thenReturn("wsSession-id2");
|
||||
when(wsSession2.getAttributes()).thenReturn(attributes);
|
||||
when(wsSession2.getPrincipal()).thenReturn(principal);
|
||||
when(wsSession2.getId()).thenReturn("wsSession-id2");
|
||||
|
||||
Map<String,Object> headers = new HashMap<String,Object>();
|
||||
headers.put(SimpMessageHeaderAccessor.SESSION_ATTRIBUTES, attributes);
|
||||
when(message.getHeaders()).thenReturn(new MessageHeaders(headers));
|
||||
Map<String,Object> headers = new HashMap<String,Object>();
|
||||
headers.put(SimpMessageHeaderAccessor.SESSION_ATTRIBUTES, attributes);
|
||||
when(message.getHeaders()).thenReturn(new MessageHeaders(headers));
|
||||
|
||||
listener = new WebSocketRegistryListener();
|
||||
connect = new SessionConnectEvent(listener,wsSession);
|
||||
connect2 = new SessionConnectEvent(listener,wsSession2);
|
||||
disconnect = new SessionDisconnectEvent(listener, message, wsSession.getId(), CloseStatus.NORMAL);
|
||||
destroyed = new SessionDestroyedEvent(listener, sessionId);
|
||||
}
|
||||
listener = new WebSocketRegistryListener();
|
||||
connect = new SessionConnectEvent(listener,wsSession);
|
||||
connect2 = new SessionConnectEvent(listener,wsSession2);
|
||||
disconnect = new SessionDisconnectEvent(listener, message, wsSession.getId(), CloseStatus.NORMAL);
|
||||
destroyed = new SessionDestroyedEvent(listener, sessionId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onApplicationEventConnectSessionDestroyed() throws Exception {
|
||||
listener.onApplicationEvent(connect);
|
||||
@Test
|
||||
public void onApplicationEventConnectSessionDestroyed() throws Exception {
|
||||
listener.onApplicationEvent(connect);
|
||||
|
||||
listener.onApplicationEvent(destroyed);
|
||||
listener.onApplicationEvent(destroyed);
|
||||
|
||||
verify(wsSession).close(WebSocketRegistryListener.SESSION_EXPIRED_STATUS);
|
||||
}
|
||||
verify(wsSession).close(WebSocketRegistryListener.SESSION_EXPIRED_STATUS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onApplicationEventConnectSessionDestroyedNullPrincipal() throws Exception {
|
||||
when(wsSession.getPrincipal()).thenReturn(null);
|
||||
listener.onApplicationEvent(connect);
|
||||
@Test
|
||||
public void onApplicationEventConnectSessionDestroyedNullPrincipal() throws Exception {
|
||||
when(wsSession.getPrincipal()).thenReturn(null);
|
||||
listener.onApplicationEvent(connect);
|
||||
|
||||
listener.onApplicationEvent(destroyed);
|
||||
listener.onApplicationEvent(destroyed);
|
||||
|
||||
verify(wsSession,times(0)).close(any(CloseStatus.class));
|
||||
}
|
||||
verify(wsSession,times(0)).close(any(CloseStatus.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onApplicationEventConnectDisconnect() throws Exception {
|
||||
listener.onApplicationEvent(connect);
|
||||
listener.onApplicationEvent(disconnect);
|
||||
@Test
|
||||
public void onApplicationEventConnectDisconnect() throws Exception {
|
||||
listener.onApplicationEvent(connect);
|
||||
listener.onApplicationEvent(disconnect);
|
||||
|
||||
listener.onApplicationEvent(destroyed);
|
||||
listener.onApplicationEvent(destroyed);
|
||||
|
||||
verify(wsSession,times(0)).close(any(CloseStatus.class));
|
||||
}
|
||||
verify(wsSession,times(0)).close(any(CloseStatus.class));
|
||||
}
|
||||
|
||||
// gh-76
|
||||
@Test
|
||||
public void onApplicationEventConnectDisconnectCleanup() {
|
||||
listener.onApplicationEvent(connect);
|
||||
// gh-76
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void onApplicationEventConnectDisconnectCleanup() {
|
||||
listener.onApplicationEvent(connect);
|
||||
|
||||
listener.onApplicationEvent(disconnect);
|
||||
listener.onApplicationEvent(disconnect);
|
||||
|
||||
Map<String,Map<String,WebSocketSession>> httpSessionIdToWsSessions =
|
||||
(Map<String, Map<String, WebSocketSession>>) ReflectionTestUtils.getField(listener, "httpSessionIdToWsSessions");
|
||||
assertThat(httpSessionIdToWsSessions).isEmpty();
|
||||
}
|
||||
Map<String,Map<String,WebSocketSession>> httpSessionIdToWsSessions =
|
||||
(Map<String, Map<String, WebSocketSession>>) ReflectionTestUtils.getField(listener, "httpSessionIdToWsSessions");
|
||||
assertThat(httpSessionIdToWsSessions).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onApplicationEventConnectDisconnectNullSession() throws Exception {
|
||||
listener.onApplicationEvent(connect);
|
||||
attributes.clear();
|
||||
@Test
|
||||
public void onApplicationEventConnectDisconnectNullSession() throws Exception {
|
||||
listener.onApplicationEvent(connect);
|
||||
attributes.clear();
|
||||
|
||||
listener.onApplicationEvent(disconnect);
|
||||
listener.onApplicationEvent(disconnect);
|
||||
|
||||
// no exception
|
||||
}
|
||||
// no exception
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onApplicationEventConnectConnectDisonnect() throws Exception {
|
||||
listener.onApplicationEvent(connect);
|
||||
listener.onApplicationEvent(connect2);
|
||||
listener.onApplicationEvent(disconnect);
|
||||
@Test
|
||||
public void onApplicationEventConnectConnectDisonnect() throws Exception {
|
||||
listener.onApplicationEvent(connect);
|
||||
listener.onApplicationEvent(connect2);
|
||||
listener.onApplicationEvent(disconnect);
|
||||
|
||||
listener.onApplicationEvent(destroyed);
|
||||
listener.onApplicationEvent(destroyed);
|
||||
|
||||
verify(wsSession2).close(WebSocketRegistryListener.SESSION_EXPIRED_STATUS);
|
||||
verify(wsSession,times(0)).close(any(CloseStatus.class));
|
||||
}
|
||||
verify(wsSession2).close(WebSocketRegistryListener.SESSION_EXPIRED_STATUS);
|
||||
verify(wsSession,times(0)).close(any(CloseStatus.class));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -43,214 +43,214 @@ import org.springframework.session.SessionRepository;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class SessionRepositoryMessageInterceptorTests {
|
||||
@Mock
|
||||
SessionRepository<ExpiringSession> sessionRepository;
|
||||
@Mock
|
||||
MessageChannel channel;
|
||||
@Mock
|
||||
ExpiringSession session;
|
||||
@Mock
|
||||
SessionRepository<ExpiringSession> sessionRepository;
|
||||
@Mock
|
||||
MessageChannel channel;
|
||||
@Mock
|
||||
ExpiringSession session;
|
||||
|
||||
Message<?> createMessage;
|
||||
Message<?> createMessage;
|
||||
|
||||
SimpMessageHeaderAccessor headers;
|
||||
SimpMessageHeaderAccessor headers;
|
||||
|
||||
SessionRepositoryMessageInterceptor<ExpiringSession> interceptor;
|
||||
SessionRepositoryMessageInterceptor<ExpiringSession> interceptor;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
interceptor = new SessionRepositoryMessageInterceptor<ExpiringSession>(sessionRepository);
|
||||
headers = SimpMessageHeaderAccessor.create();
|
||||
headers.setSessionId("session");
|
||||
headers.setSessionAttributes(new HashMap<String,Object>());
|
||||
setMessageType(SimpMessageType.MESSAGE);
|
||||
String sessionId = "http-session";
|
||||
setSessionId(sessionId);
|
||||
when(sessionRepository.getSession(sessionId)).thenReturn(session);
|
||||
}
|
||||
@Before
|
||||
public void setup() {
|
||||
interceptor = new SessionRepositoryMessageInterceptor<ExpiringSession>(sessionRepository);
|
||||
headers = SimpMessageHeaderAccessor.create();
|
||||
headers.setSessionId("session");
|
||||
headers.setSessionAttributes(new HashMap<String,Object>());
|
||||
setMessageType(SimpMessageType.MESSAGE);
|
||||
String sessionId = "http-session";
|
||||
setSessionId(sessionId);
|
||||
when(sessionRepository.getSession(sessionId)).thenReturn(session);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void preSendconstructorNullRepository() {
|
||||
new SessionRepositoryMessageInterceptor<ExpiringSession>(null);
|
||||
}
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void preSendconstructorNullRepository() {
|
||||
new SessionRepositoryMessageInterceptor<ExpiringSession>(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preSendNullMessage() {
|
||||
assertThat(interceptor.preSend(null, channel)).isNull();
|
||||
}
|
||||
@Test
|
||||
public void preSendNullMessage() {
|
||||
assertThat(interceptor.preSend(null, channel)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preSendConnectAckDoesNotInvokeSessionRepository() {
|
||||
setMessageType(SimpMessageType.CONNECT_ACK);
|
||||
@Test
|
||||
public void preSendConnectAckDoesNotInvokeSessionRepository() {
|
||||
setMessageType(SimpMessageType.CONNECT_ACK);
|
||||
|
||||
assertThat(interceptor.preSend(createMessage(), channel)).isSameAs(createMessage);
|
||||
assertThat(interceptor.preSend(createMessage(), channel)).isSameAs(createMessage);
|
||||
|
||||
verifyZeroInteractions(sessionRepository);
|
||||
}
|
||||
verifyZeroInteractions(sessionRepository);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preSendHeartbeatDoesNotInvokeSessionRepository() {
|
||||
setMessageType(SimpMessageType.HEARTBEAT);
|
||||
@Test
|
||||
public void preSendHeartbeatDoesNotInvokeSessionRepository() {
|
||||
setMessageType(SimpMessageType.HEARTBEAT);
|
||||
|
||||
assertThat(interceptor.preSend(createMessage(), channel)).isSameAs(createMessage);
|
||||
assertThat(interceptor.preSend(createMessage(), channel)).isSameAs(createMessage);
|
||||
|
||||
verifyZeroInteractions(sessionRepository);
|
||||
}
|
||||
verifyZeroInteractions(sessionRepository);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preSendDisconnectDoesNotInvokeSessionRepository() {
|
||||
setMessageType(SimpMessageType.DISCONNECT);
|
||||
@Test
|
||||
public void preSendDisconnectDoesNotInvokeSessionRepository() {
|
||||
setMessageType(SimpMessageType.DISCONNECT);
|
||||
|
||||
assertThat(interceptor.preSend(createMessage(), channel)).isSameAs(createMessage);
|
||||
assertThat(interceptor.preSend(createMessage(), channel)).isSameAs(createMessage);
|
||||
|
||||
verifyZeroInteractions(sessionRepository);
|
||||
}
|
||||
verifyZeroInteractions(sessionRepository);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preSendOtherDoesNotInvokeSessionRepository() {
|
||||
setMessageType(SimpMessageType.OTHER);
|
||||
@Test
|
||||
public void preSendOtherDoesNotInvokeSessionRepository() {
|
||||
setMessageType(SimpMessageType.OTHER);
|
||||
|
||||
assertThat(interceptor.preSend(createMessage(), channel)).isSameAs(createMessage);
|
||||
assertThat(interceptor.preSend(createMessage(), channel)).isSameAs(createMessage);
|
||||
|
||||
verifyZeroInteractions(sessionRepository);
|
||||
}
|
||||
verifyZeroInteractions(sessionRepository);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void setMatchingMessageTypesNull() {
|
||||
interceptor.setMatchingMessageTypes(null);
|
||||
}
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void setMatchingMessageTypesNull() {
|
||||
interceptor.setMatchingMessageTypes(null);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void setMatchingMessageTypesEmpty() {
|
||||
interceptor.setMatchingMessageTypes(Collections.<SimpMessageType>emptySet());
|
||||
}
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void setMatchingMessageTypesEmpty() {
|
||||
interceptor.setMatchingMessageTypes(Collections.<SimpMessageType>emptySet());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preSendSetMatchingMessageTypes() {
|
||||
interceptor.setMatchingMessageTypes(EnumSet.of(SimpMessageType.DISCONNECT));
|
||||
setMessageType(SimpMessageType.DISCONNECT);
|
||||
@Test
|
||||
public void preSendSetMatchingMessageTypes() {
|
||||
interceptor.setMatchingMessageTypes(EnumSet.of(SimpMessageType.DISCONNECT));
|
||||
setMessageType(SimpMessageType.DISCONNECT);
|
||||
|
||||
assertThat(interceptor.preSend(createMessage(), channel)).isSameAs(createMessage);
|
||||
assertThat(interceptor.preSend(createMessage(), channel)).isSameAs(createMessage);
|
||||
|
||||
verify(sessionRepository).getSession(anyString());
|
||||
verify(sessionRepository).save(session);
|
||||
}
|
||||
verify(sessionRepository).getSession(anyString());
|
||||
verify(sessionRepository).save(session);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preSendConnectUpdatesLastUpdateTime() {
|
||||
setMessageType(SimpMessageType.CONNECT);
|
||||
@Test
|
||||
public void preSendConnectUpdatesLastUpdateTime() {
|
||||
setMessageType(SimpMessageType.CONNECT);
|
||||
|
||||
assertThat(interceptor.preSend(createMessage(), channel)).isSameAs(createMessage);
|
||||
assertThat(interceptor.preSend(createMessage(), channel)).isSameAs(createMessage);
|
||||
|
||||
verify(sessionRepository).getSession(anyString());
|
||||
verify(sessionRepository).save(session);
|
||||
}
|
||||
verify(sessionRepository).getSession(anyString());
|
||||
verify(sessionRepository).save(session);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preSendMessageUpdatesLastUpdateTime() {
|
||||
setMessageType(SimpMessageType.MESSAGE);
|
||||
@Test
|
||||
public void preSendMessageUpdatesLastUpdateTime() {
|
||||
setMessageType(SimpMessageType.MESSAGE);
|
||||
|
||||
assertThat(interceptor.preSend(createMessage(), channel)).isSameAs(createMessage);
|
||||
assertThat(interceptor.preSend(createMessage(), channel)).isSameAs(createMessage);
|
||||
|
||||
verify(sessionRepository).getSession(anyString());
|
||||
verify(sessionRepository).save(session);
|
||||
}
|
||||
verify(sessionRepository).getSession(anyString());
|
||||
verify(sessionRepository).save(session);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preSendSubscribeUpdatesLastUpdateTime() {
|
||||
setMessageType(SimpMessageType.SUBSCRIBE);
|
||||
@Test
|
||||
public void preSendSubscribeUpdatesLastUpdateTime() {
|
||||
setMessageType(SimpMessageType.SUBSCRIBE);
|
||||
|
||||
assertThat(interceptor.preSend(createMessage(), channel)).isSameAs(createMessage);
|
||||
assertThat(interceptor.preSend(createMessage(), channel)).isSameAs(createMessage);
|
||||
|
||||
verify(sessionRepository).getSession(anyString());
|
||||
verify(sessionRepository).save(session);
|
||||
}
|
||||
verify(sessionRepository).getSession(anyString());
|
||||
verify(sessionRepository).save(session);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preSendUnsubscribeUpdatesLastUpdateTime() {
|
||||
setMessageType(SimpMessageType.UNSUBSCRIBE);
|
||||
@Test
|
||||
public void preSendUnsubscribeUpdatesLastUpdateTime() {
|
||||
setMessageType(SimpMessageType.UNSUBSCRIBE);
|
||||
|
||||
assertThat(interceptor.preSend(createMessage(), channel)).isSameAs(createMessage);
|
||||
assertThat(interceptor.preSend(createMessage(), channel)).isSameAs(createMessage);
|
||||
|
||||
verify(sessionRepository).getSession(anyString());
|
||||
verify(sessionRepository).save(session);
|
||||
}
|
||||
verify(sessionRepository).getSession(anyString());
|
||||
verify(sessionRepository).save(session);
|
||||
}
|
||||
|
||||
// This will updated when SPR-12288 is resolved
|
||||
@Test
|
||||
public void preSendExpiredSession() {
|
||||
setSessionId("expired");
|
||||
// This will updated when SPR-12288 is resolved
|
||||
@Test
|
||||
public void preSendExpiredSession() {
|
||||
setSessionId("expired");
|
||||
|
||||
interceptor.preSend(createMessage(), channel);
|
||||
interceptor.preSend(createMessage(), channel);
|
||||
|
||||
verify(sessionRepository,times(0)).save(any(ExpiringSession.class));
|
||||
}
|
||||
verify(sessionRepository,times(0)).save(any(ExpiringSession.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preSendNullSessionId() {
|
||||
setSessionId(null);
|
||||
@Test
|
||||
public void preSendNullSessionId() {
|
||||
setSessionId(null);
|
||||
|
||||
assertThat(interceptor.preSend(createMessage(), channel)).isSameAs(createMessage);
|
||||
assertThat(interceptor.preSend(createMessage(), channel)).isSameAs(createMessage);
|
||||
|
||||
verifyZeroInteractions(sessionRepository);
|
||||
}
|
||||
verifyZeroInteractions(sessionRepository);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preSendNullSessionAttributes() {
|
||||
headers.setSessionAttributes(null);
|
||||
@Test
|
||||
public void preSendNullSessionAttributes() {
|
||||
headers.setSessionAttributes(null);
|
||||
|
||||
assertThat(interceptor.preSend(createMessage(), channel)).isSameAs(createMessage);
|
||||
assertThat(interceptor.preSend(createMessage(), channel)).isSameAs(createMessage);
|
||||
|
||||
verifyZeroInteractions(sessionRepository);
|
||||
}
|
||||
verifyZeroInteractions(sessionRepository);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beforeHandshakeNotServletServerHttpRequest() throws Exception {
|
||||
assertThat(interceptor.beforeHandshake(null,null,null,null)).isTrue();
|
||||
@Test
|
||||
public void beforeHandshakeNotServletServerHttpRequest() throws Exception {
|
||||
assertThat(interceptor.beforeHandshake(null,null,null,null)).isTrue();
|
||||
|
||||
verifyZeroInteractions(sessionRepository);
|
||||
}
|
||||
verifyZeroInteractions(sessionRepository);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beforeHandshakeNullSession() throws Exception {
|
||||
ServletServerHttpRequest request = new ServletServerHttpRequest(new MockHttpServletRequest());
|
||||
assertThat(interceptor.beforeHandshake(request,null,null,null)).isTrue();
|
||||
@Test
|
||||
public void beforeHandshakeNullSession() throws Exception {
|
||||
ServletServerHttpRequest request = new ServletServerHttpRequest(new MockHttpServletRequest());
|
||||
assertThat(interceptor.beforeHandshake(request,null,null,null)).isTrue();
|
||||
|
||||
verifyZeroInteractions(sessionRepository);
|
||||
}
|
||||
verifyZeroInteractions(sessionRepository);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beforeHandshakeSession() throws Exception {
|
||||
MockHttpServletRequest httpRequest = new MockHttpServletRequest();
|
||||
HttpSession httpSession = httpRequest.getSession();
|
||||
ServletServerHttpRequest request = new ServletServerHttpRequest(httpRequest);
|
||||
Map<String,Object> attributes = new HashMap<String,Object>();
|
||||
@Test
|
||||
public void beforeHandshakeSession() throws Exception {
|
||||
MockHttpServletRequest httpRequest = new MockHttpServletRequest();
|
||||
HttpSession httpSession = httpRequest.getSession();
|
||||
ServletServerHttpRequest request = new ServletServerHttpRequest(httpRequest);
|
||||
Map<String,Object> attributes = new HashMap<String,Object>();
|
||||
|
||||
assertThat(interceptor.beforeHandshake(request,null,null,attributes)).isTrue();
|
||||
assertThat(interceptor.beforeHandshake(request,null,null,attributes)).isTrue();
|
||||
|
||||
assertThat(attributes.size()).isEqualTo(1);
|
||||
assertThat(SessionRepositoryMessageInterceptor.getSessionId(attributes)).isEqualTo(httpSession.getId());
|
||||
}
|
||||
assertThat(attributes.size()).isEqualTo(1);
|
||||
assertThat(SessionRepositoryMessageInterceptor.getSessionId(attributes)).isEqualTo(httpSession.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* At the moment there is no need for afterHandshake to do anything.
|
||||
*/
|
||||
@Test
|
||||
public void afterHandshakeDoesNothing() {
|
||||
interceptor.afterHandshake(null,null,null,null);
|
||||
/**
|
||||
* At the moment there is no need for afterHandshake to do anything.
|
||||
*/
|
||||
@Test
|
||||
public void afterHandshakeDoesNothing() {
|
||||
interceptor.afterHandshake(null,null,null,null);
|
||||
|
||||
verifyZeroInteractions(sessionRepository);
|
||||
}
|
||||
verifyZeroInteractions(sessionRepository);
|
||||
}
|
||||
|
||||
private void setSessionId(String id) {
|
||||
SessionRepositoryMessageInterceptor.setSessionId(headers.getSessionAttributes(), id);
|
||||
}
|
||||
private void setSessionId(String id) {
|
||||
SessionRepositoryMessageInterceptor.setSessionId(headers.getSessionAttributes(), id);
|
||||
}
|
||||
|
||||
private Message<?> createMessage() {
|
||||
createMessage = MessageBuilder.createMessage("", headers.getMessageHeaders());
|
||||
return createMessage;
|
||||
}
|
||||
private Message<?> createMessage() {
|
||||
createMessage = MessageBuilder.createMessage("", headers.getMessageHeaders());
|
||||
return createMessage;
|
||||
}
|
||||
|
||||
private void setMessageType(SimpMessageType type) {
|
||||
headers.setHeader(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER, type);
|
||||
}
|
||||
private void setMessageType(SimpMessageType type) {
|
||||
headers.setHeader(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER, type);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user