Create ExpiringSession which extends Session

This provides a better separation for consumers of the API. Most users are
likely not interested in checking to see if a session is expired so they
can focus on the Session API.

Fixes #28
This commit is contained in:
Rob Winch
2014-07-30 11:56:43 -05:00
parent f1fa380bdd
commit 903017285b
11 changed files with 73 additions and 59 deletions

View File

@@ -189,8 +189,8 @@ public class Config {
}
@Bean
public RedisTemplate<String,Session> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Session> template = new RedisTemplate<String, Session>();
public RedisTemplate<String,ExpiringSession> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, ExpiringSession> template = new RedisTemplate<String, ExpiringSession>();
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setConnectionFactory(connectionFactory);
@@ -198,7 +198,7 @@ public class Config {
}
@Bean
public RedisOperationsSessionRepository sessionRepository(RedisTemplate<String, Session> redisTemplate) {
public RedisOperationsSessionRepository sessionRepository(RedisTemplate<String, ExpiringSession> redisTemplate) {
return new RedisOperationsSessionRepository(redisTemplate);
}

View File

@@ -22,6 +22,7 @@ import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.session.ExpiringSession;
import org.springframework.session.Session;
import org.springframework.session.data.redis.RedisOperationsSessionRepository;
import org.springframework.session.web.http.SessionRepositoryFilter;
@@ -72,7 +73,7 @@ public class Config {
}
@Bean
public RedisOperationsSessionRepository sessionRepository(RedisTemplate<String, Session> redisTemplate) {
public RedisOperationsSessionRepository sessionRepository(RedisTemplate<String, ExpiringSession> redisTemplate) {
return new RedisOperationsSessionRepository(redisTemplate);
}

View File

@@ -18,6 +18,7 @@ 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.test.context.ContextConfiguration;
@@ -100,8 +101,8 @@ public class RedisOperationsSessionRepositoryITests {
}
@Bean
public RedisTemplate<String,Session> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Session> template = new RedisTemplate<String, Session>();
public RedisTemplate<String,ExpiringSession> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, ExpiringSession> template = new RedisTemplate<String, ExpiringSession>();
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setConnectionFactory(connectionFactory);
@@ -109,7 +110,7 @@ public class RedisOperationsSessionRepositoryITests {
}
@Bean
public RedisOperationsSessionRepository sessionRepository(RedisTemplate<String, Session> redisTemplate) {
public RedisOperationsSessionRepository sessionRepository(RedisTemplate<String, ExpiringSession> redisTemplate) {
return new RedisOperationsSessionRepository(redisTemplate);
}
}

View File

@@ -0,0 +1,39 @@
package org.springframework.session;
/**
* A {@link Session} that contains additional attributes that are useful for determining if a session is expired.
*
* @since 1.0
* @author Rob Winch
*/
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 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 setMaxInactiveInterval(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 getMaxInactiveInterval();
}

View File

@@ -40,7 +40,7 @@ import java.util.UUID;
* @since 1.0
* @author Rob Winch
*/
public final class MapSession implements Session {
public final class MapSession implements ExpiringSession {
/**
* Default {@link #setMaxInactiveInterval(int)} (30 minutes)
*/
@@ -67,7 +67,7 @@ public final class MapSession implements Session {
*
* @param session the {@link Session} to initialize this {@link Session} with. Cannot be null.
*/
public MapSession(Session session) {
public MapSession(ExpiringSession session) {
Assert.notNull(session, "session cannot be null");
this.id = session.getId();
this.sessionAttrs = new HashMap<String, Object>(session.getAttributeNames().size());

View File

@@ -28,14 +28,14 @@ import java.util.concurrent.ConcurrentHashMap;
* @author Rob Winch
* @since 1.0
*/
public class MapSessionRepository implements SessionRepository<Session> {
private final Map<String,Session> sessions;
public class MapSessionRepository implements SessionRepository<ExpiringSession> {
private final Map<String,ExpiringSession> sessions;
/**
* Creates an instance backed by a {@link java.util.concurrent.ConcurrentHashMap}
*/
public MapSessionRepository() {
this(new ConcurrentHashMap<String, Session>());
this(new ConcurrentHashMap<String, ExpiringSession>());
}
/**
@@ -43,17 +43,17 @@ public class MapSessionRepository implements SessionRepository<Session> {
*
* @param sessions the {@link java.util.Map} to use. Cannot be null.
*/
public MapSessionRepository(Map<String,Session> sessions) {
public MapSessionRepository(Map<String,ExpiringSession> sessions) {
Assert.notNull(sessions, "sessions cannot be null");
this.sessions = sessions;
}
public void save(Session session) {
public void save(ExpiringSession session) {
sessions.put(session.getId(), new MapSession(session));
}
public Session getSession(String id) {
Session saved = sessions.get(id);
public ExpiringSession getSession(String id) {
ExpiringSession saved = sessions.get(id);
if(saved == null) {
return null;
}
@@ -66,7 +66,7 @@ public class MapSessionRepository implements SessionRepository<Session> {
sessions.remove(id);
}
public Session createSession() {
public ExpiringSession createSession() {
return new MapSession();
}
}

View File

@@ -27,13 +27,6 @@ import java.util.Set;
*/
public interface 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 a unique string that identifies the {@link Session}
*
@@ -41,27 +34,6 @@ public interface Session {
*/
String getId();
/**
* 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 setMaxInactiveInterval(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 getMaxInactiveInterval();
/**
* Gets the Object associated with the specified name or null if no Object is associated to that name.
*

View File

@@ -17,6 +17,7 @@ package org.springframework.session.data.redis;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.session.ExpiringSession;
import org.springframework.session.MapSession;
import org.springframework.session.Session;
import org.springframework.session.SessionRepository;
@@ -99,17 +100,17 @@ public class RedisOperationsSessionRepository implements SessionRepository<Redis
static final String BOUNDED_HASH_KEY_PREFIX = "spring-security-sessions:";
/**
* The key in the Hash representing {@link org.springframework.session.Session#getCreationTime()}
* 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.Session#getMaxInactiveInterval()}
* The key in the Hash representing {@link org.springframework.session.ExpiringSession#getMaxInactiveInterval()}
*/
static final String MAX_INACTIVE_ATTR = "maxInactiveInterval";
/**
* The key in the Hash representing {@link org.springframework.session.Session#getLastAccessedTime()}
* The key in the Hash representing {@link org.springframework.session.ExpiringSession#getLastAccessedTime()}
*/
static final String LAST_ACCESSED_ATTR = "lastAccessedTime";
@@ -120,7 +121,7 @@ public class RedisOperationsSessionRepository implements SessionRepository<Redis
*/
static final String SESSION_ATTR_PREFIX = "sessionAttr:";
private final RedisOperations<String,Session> redisOperations;
private final RedisOperations<String,ExpiringSession> redisOperations;
/**
* If non-null, this value is used to override {@link RedisSession#setDefaultMaxInactiveInterval(int)}.
@@ -132,7 +133,7 @@ public class RedisOperationsSessionRepository implements SessionRepository<Redis
*
* @param redisOperations The {@link RedisOperations} to use. Cannot be null.
*/
public RedisOperationsSessionRepository(RedisOperations<String, Session> redisOperations) {
public RedisOperationsSessionRepository(RedisOperations<String, ExpiringSession> redisOperations) {
Assert.notNull(redisOperations, "RedisOperations cannot be null");
this.redisOperations = redisOperations;
}
@@ -232,7 +233,7 @@ public class RedisOperationsSessionRepository implements SessionRepository<Redis
* @since 1.0
* @author Rob Winch
*/
final class RedisSession implements Session {
final class RedisSession implements ExpiringSession {
private final MapSession cached;
private Map<String, Object> delta = new HashMap<String,Object>();

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.session.web.http;
import org.springframework.session.Session;
import org.springframework.session.ExpiringSession;
import org.springframework.session.SessionRepository;
import org.springframework.util.Assert;
@@ -43,15 +43,14 @@ import java.util.Set;
* <ul>
* <li>The session id is looked up using {@link HttpSessionStrategy#getRequestedSessionId(javax.servlet.http.HttpServletRequest)}.
* The default is to look in a cookie named SESSION.</li>
* <li>The session id of newly created {@link org.springframework.session.Session} is sent to the client using
* {@link HttpSessionStrategy#onNewSession(org.springframework.session.Session, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)} </li>
* <li>The session id of newly created {@link org.springframework.session.ExpiringSession} is sent to the client using
* <li>The client is notified that the session id is no longer valid with {@link HttpSessionStrategy#onInvalidateSession(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)}</li>
* </ul>
*
* @since 1.0
* @author Rob Winch
*/
public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFilter {
public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerRequestFilter {
private final SessionRepository<S> sessionRepository;
private HttpSessionStrategy httpSessionStrategy = new CookieHttpSessionStrategy();

View File

@@ -50,7 +50,7 @@ public class MapSessionTests {
assertThat(session.hashCode()).isEqualTo(session.getId().hashCode());
}
static class CustomSession implements Session {
static class CustomSession implements ExpiringSession {
@Override
public long getCreationTime() {

View File

@@ -17,6 +17,7 @@ import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.session.ExpiringSession;
import org.springframework.session.MapSession;
import org.springframework.session.Session;
import org.springframework.session.data.redis.RedisOperationsSessionRepository.RedisSession;
@@ -25,7 +26,7 @@ import org.springframework.session.data.redis.RedisOperationsSessionRepository.R
@RunWith(MockitoJUnitRunner.class)
public class RedisOperationsSessionRepositoryTests {
@Mock
RedisOperations<String,Session> redisOperations;
RedisOperations<String,ExpiringSession> redisOperations;
@Mock
BoundHashOperations<String, Object, Object> boundHashOperations;
@Captor
@@ -40,7 +41,7 @@ public class RedisOperationsSessionRepositoryTests {
@Test
public void createSessionDefaultMaxInactiveInterval() throws Exception {
Session session = redisRepository.createSession();
ExpiringSession session = redisRepository.createSession();
assertThat(session.getMaxInactiveInterval()).isEqualTo(new MapSession().getMaxInactiveInterval());
}
@@ -48,7 +49,7 @@ public class RedisOperationsSessionRepositoryTests {
public void createSessionCustomMaxInactiveInterval() throws Exception {
int interval = 1;
redisRepository.setDefaultMaxInactiveInterval(interval);
Session session = redisRepository.createSession();
ExpiringSession session = redisRepository.createSession();
assertThat(session.getMaxInactiveInterval()).isEqualTo(interval);
}