Additional Checkstyle Fixes

Issue gh-393
This commit is contained in:
Rob Winch
2016-03-07 15:32:03 -06:00
parent 7f3302253b
commit f0200696ef
189 changed files with 4591 additions and 3201 deletions

View File

@@ -48,8 +48,8 @@ import org.springframework.session.events.AbstractSessionEvent;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
/** /**
* AbstractGemFireIntegrationTests is an abstract base class encapsulating common operations for writing * AbstractGemFireIntegrationTests is an abstract base class encapsulating common
* Spring Session GemFire integration tests. * operations for writing Spring Session GemFire integration tests.
* *
* @author John Blum * @author John Blum
* @since 1.1.0 * @since 1.1.0
@@ -64,24 +64,25 @@ import static org.assertj.core.api.Assertions.assertThat;
* @see com.gemstone.gemfire.cache.server.CacheServer * @see com.gemstone.gemfire.cache.server.CacheServer
*/ */
public class AbstractGemFireIntegrationTests { public class AbstractGemFireIntegrationTests {
public static final String GEMFIRE_LOG_LEVEL = System.getProperty( public static final String GEMFIRE_LOG_LEVEL = System
"spring.session.data.gemfire.log-level", "warning"); .getProperty("spring.session.data.gemfire.log-level", "warning");
protected static final boolean DEFAULT_ENABLE_QUERY_DEBUGGING = false; protected static final boolean DEFAULT_ENABLE_QUERY_DEBUGGING = false;
protected static final boolean GEMFIRE_QUERY_DEBUG = Boolean.getBoolean("spring.session.data.gemfire.query.debug"); protected static final boolean GEMFIRE_QUERY_DEBUG = Boolean
.getBoolean("spring.session.data.gemfire.query.debug");
protected static final int DEFAULT_GEMFIRE_SERVER_PORT = CacheServer.DEFAULT_PORT; protected static final int DEFAULT_GEMFIRE_SERVER_PORT = CacheServer.DEFAULT_PORT;
protected static final long DEFAULT_WAIT_DURATION = TimeUnit.SECONDS.toMillis(20); protected static final long DEFAULT_WAIT_DURATION = TimeUnit.SECONDS.toMillis(20);
protected static final long DEFAULT_WAIT_INTERVAL = 500L; protected static final long DEFAULT_WAIT_INTERVAL = 500L;
protected static final File WORKING_DIRECTORY = new File(System.getProperty("user.dir")); protected static final File WORKING_DIRECTORY = new File(
System.getProperty("user.dir"));
protected static final String DEFAULT_PROCESS_CONTROL_FILENAME = "process.ctl"; protected static final String DEFAULT_PROCESS_CONTROL_FILENAME = "process.ctl";
protected static final String GEMFIRE_LOG_FILE_NAME = System.getProperty( protected static final String GEMFIRE_LOG_FILE_NAME = System
"spring.session.data.gemfire.log-file", "server.log"); .getProperty("spring.session.data.gemfire.log-file", "server.log");
@Autowired @Autowired
protected Cache gemfireCache; protected Cache gemfireCache;
@@ -91,15 +92,17 @@ public class AbstractGemFireIntegrationTests {
@Before @Before
public void setup() { public void setup() {
System.setProperty("gemfire.Query.VERBOSE", String.valueOf(isQueryDebuggingEnabled())); System.setProperty("gemfire.Query.VERBOSE",
String.valueOf(isQueryDebuggingEnabled()));
} }
/* (non-Javadoc) */ /* (non-Javadoc) */
protected static File createDirectory(String pathname) { protected static File createDirectory(String pathname) {
File directory = new File(WORKING_DIRECTORY, pathname); File directory = new File(WORKING_DIRECTORY, pathname);
assertThat(directory.isDirectory() || directory.mkdirs()).as( assertThat(directory.isDirectory() || directory.mkdirs())
String.format("Failed to create directory (%1$s)", directory)).isTrue(); .as(String.format("Failed to create directory (%1$s)", directory))
.isTrue();
directory.deleteOnExit(); directory.deleteOnExit();
@@ -107,7 +110,8 @@ public class AbstractGemFireIntegrationTests {
} }
/* (non-Javadoc) */ /* (non-Javadoc) */
protected static List<String> createJavaProcessCommandLine(Class<?> type, String... args) { protected static List<String> createJavaProcessCommandLine(Class<?> type,
String... args) {
List<String> commandLine = new ArrayList<String>(); List<String> commandLine = new ArrayList<String>();
String javaHome = System.getProperty("java.home"); String javaHome = System.getProperty("java.home");
@@ -118,7 +122,8 @@ public class AbstractGemFireIntegrationTests {
commandLine.add("-ea"); commandLine.add("-ea");
commandLine.add(String.format("-Dgemfire.log-file=%1$s", GEMFIRE_LOG_FILE_NAME)); commandLine.add(String.format("-Dgemfire.log-file=%1$s", GEMFIRE_LOG_FILE_NAME));
commandLine.add(String.format("-Dgemfire.log-level=%1$s", GEMFIRE_LOG_LEVEL)); commandLine.add(String.format("-Dgemfire.log-level=%1$s", GEMFIRE_LOG_LEVEL));
commandLine.add(String.format("-Dgemfire.Query.VERBOSE=%1$s", GEMFIRE_QUERY_DEBUG)); commandLine
.add(String.format("-Dgemfire.Query.VERBOSE=%1$s", GEMFIRE_QUERY_DEBUG));
commandLine.addAll(extractJvmArguments(args)); commandLine.addAll(extractJvmArguments(args));
commandLine.add("-classpath"); commandLine.add("-classpath");
commandLine.add(System.getProperty("java.class.path")); commandLine.add(System.getProperty("java.class.path"));
@@ -157,11 +162,10 @@ public class AbstractGemFireIntegrationTests {
} }
/* (non-Javadoc) */ /* (non-Javadoc) */
protected static Process run(Class<?> type, File directory, String... args) throws IOException { protected static Process run(Class<?> type, File directory, String... args)
return new ProcessBuilder() throws IOException {
.command(createJavaProcessCommandLine(type, args)) return new ProcessBuilder().command(createJavaProcessCommandLine(type, args))
.directory(directory) .directory(directory).start();
.start();
} }
/* (non-Javadoc) */ /* (non-Javadoc) */
@@ -170,8 +174,10 @@ public class AbstractGemFireIntegrationTests {
} }
/* (non-Javadoc) */ /* (non-Javadoc) */
protected static boolean waitForCacheServerToStart(CacheServer cacheServer, long duration) { protected static boolean waitForCacheServerToStart(CacheServer cacheServer,
return waitForCacheServerToStart(cacheServer.getBindAddress(), cacheServer.getPort(), duration); long duration) {
return waitForCacheServerToStart(cacheServer.getBindAddress(),
cacheServer.getPort(), duration);
} }
/* (non-Javadoc) */ /* (non-Javadoc) */
@@ -180,7 +186,8 @@ public class AbstractGemFireIntegrationTests {
} }
/* (non-Javadoc) */ /* (non-Javadoc) */
protected static boolean waitForCacheServerToStart(final String host, final int port, long duration) { protected static boolean waitForCacheServerToStart(final String host, final int port,
long duration) {
return waitOnCondition(new Condition() { return waitOnCondition(new Condition() {
AtomicBoolean connected = new AtomicBoolean(false); AtomicBoolean connected = new AtomicBoolean(false);
@@ -204,7 +211,8 @@ public class AbstractGemFireIntegrationTests {
}, duration); }, duration);
} }
// NOTE this method would not be necessary except Spring Sessions' build does not fork the test JVM // NOTE this method would not be necessary except Spring Sessions' build does not fork
// the test JVM
// for every test class. // for every test class.
/* (non-Javadoc) */ /* (non-Javadoc) */
protected static boolean waitForClientCacheToClose() { protected static boolean waitForClientCacheToClose() {
@@ -239,7 +247,8 @@ public class AbstractGemFireIntegrationTests {
/* (non-Javadoc) */ /* (non-Javadoc) */
@SuppressWarnings("all") @SuppressWarnings("all")
protected static boolean waitForProcessToStart(Process process, File directory, long duration) { protected static boolean waitForProcessToStart(Process process, File directory,
long duration) {
final File processControl = new File(directory, DEFAULT_PROCESS_CONTROL_FILENAME); final File processControl = new File(directory, DEFAULT_PROCESS_CONTROL_FILENAME);
waitOnCondition(new Condition() { waitOnCondition(new Condition() {
@@ -257,7 +266,8 @@ public class AbstractGemFireIntegrationTests {
} }
/* (non-Javadoc) */ /* (non-Javadoc) */
protected static int waitForProcessToStop(Process process, File directory, long duration) { protected static int waitForProcessToStop(Process process, File directory,
long duration) {
final long timeout = (System.currentTimeMillis() + duration); final long timeout = (System.currentTimeMillis() + duration);
try { try {
@@ -312,24 +322,30 @@ public class AbstractGemFireIntegrationTests {
} }
/* (non-Javadoc) */ /* (non-Javadoc) */
protected void assertRegion(Region<?, ?> actualRegion, String expectedName, DataPolicy expectedDataPolicy) { protected void assertRegion(Region<?, ?> actualRegion, String expectedName,
DataPolicy expectedDataPolicy) {
assertThat(actualRegion).isNotNull(); assertThat(actualRegion).isNotNull();
assertThat(actualRegion.getName()).isEqualTo(expectedName); assertThat(actualRegion.getName()).isEqualTo(expectedName);
assertThat(actualRegion.getFullPath()).isEqualTo(GemFireUtils.toRegionPath(expectedName)); assertThat(actualRegion.getFullPath())
.isEqualTo(GemFireUtils.toRegionPath(expectedName));
assertThat(actualRegion.getAttributes()).isNotNull(); assertThat(actualRegion.getAttributes()).isNotNull();
assertThat(actualRegion.getAttributes().getDataPolicy()).isEqualTo(expectedDataPolicy); assertThat(actualRegion.getAttributes().getDataPolicy())
.isEqualTo(expectedDataPolicy);
} }
/* (non-Javadoc) */ /* (non-Javadoc) */
protected void assertIndex(Index index, String expectedExpression, String expectedFromClause) { protected void assertIndex(Index index, String expectedExpression,
String expectedFromClause) {
assertThat(index).isNotNull(); assertThat(index).isNotNull();
assertThat(index.getIndexedExpression()).isEqualTo(expectedExpression); assertThat(index.getIndexedExpression()).isEqualTo(expectedExpression);
assertThat(index.getFromClause()).isEqualTo(expectedFromClause); assertThat(index.getFromClause()).isEqualTo(expectedFromClause);
} }
/* (non-Javadoc) */ /* (non-Javadoc) */
protected void assertEntryIdleTimeout(Region<?, ?> region, ExpirationAction expectedAction, int expectedTimeout) { protected void assertEntryIdleTimeout(Region<?, ?> region,
assertEntryIdleTimeout(region.getAttributes().getEntryIdleTimeout(), expectedAction, expectedTimeout); ExpirationAction expectedAction, int expectedTimeout) {
assertEntryIdleTimeout(region.getAttributes().getEntryIdleTimeout(),
expectedAction, expectedTimeout);
} }
/* (non-Javadoc) */ /* (non-Javadoc) */
@@ -404,13 +420,14 @@ public class AbstractGemFireIntegrationTests {
} }
/** /**
* The SessionEventListener class is a Spring {@link ApplicationListener} listening for Spring HTTP Session * The SessionEventListener class is a Spring {@link ApplicationListener} listening
* application events. * for Spring HTTP Session application events.
* *
* @see org.springframework.context.ApplicationListener * @see org.springframework.context.ApplicationListener
* @see org.springframework.session.events.AbstractSessionEvent * @see org.springframework.session.events.AbstractSessionEvent
*/ */
public static class SessionEventListener implements ApplicationListener<AbstractSessionEvent> { public static class SessionEventListener
implements ApplicationListener<AbstractSessionEvent> {
private volatile AbstractSessionEvent sessionEvent; private volatile AbstractSessionEvent sessionEvent;
@@ -440,7 +457,8 @@ public class AbstractGemFireIntegrationTests {
} }
/** /**
* The Condition interface defines a logical condition that must be satisfied before it is safe to proceed. * The Condition interface defines a logical condition that must be satisfied before
* it is safe to proceed.
*/ */
protected interface Condition { protected interface Condition {
boolean evaluate(); boolean evaluate();

View File

@@ -60,7 +60,8 @@ public class HttpSessionGemFireIndexingITests extends AbstractGemFireIntegration
sessionRepository.save(session); sessionRepository.save(session);
// tag::findbyindexname-get[] // tag::findbyindexname-get[]
Map<String, ExpiringSession> idToSessions = sessionRepository.findByIndexNameAndIndexValue(indexName, username); Map<String, ExpiringSession> idToSessions = sessionRepository
.findByIndexNameAndIndexValue(indexName, username);
// end::findbyindexname-get[] // end::findbyindexname-get[]
assertThat(idToSessions.keySet()).containsOnly(session.getId()); assertThat(idToSessions.keySet()).containsOnly(session.getId());
@@ -78,12 +79,15 @@ public class HttpSessionGemFireIndexingITests extends AbstractGemFireIntegration
Authentication authentication = context.getAuthentication(); Authentication authentication = context.getAuthentication();
// end::findbyspringsecurityindexname-context[] // end::findbyspringsecurityindexname-context[]
session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, context); session.setAttribute(
HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY,
context);
sessionRepository.save(session); sessionRepository.save(session);
// tag::findbyspringsecurityindexname-get[] // tag::findbyspringsecurityindexname-get[]
String indexName = FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME; String indexName = FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME;
Map<String, ExpiringSession> idToSessions = sessionRepository.findByIndexNameAndIndexValue(indexName, authentication.getName()); Map<String, ExpiringSession> idToSessions = sessionRepository
.findByIndexNameAndIndexValue(indexName, authentication.getName());
// end::findbyspringsecurityindexname-get[] // end::findbyspringsecurityindexname-get[]
assertThat(idToSessions.keySet()).containsOnly(session.getId()); assertThat(idToSessions.keySet()).containsOnly(session.getId());

View File

@@ -39,7 +39,8 @@ public class GemFireHttpSessionConfig {
gemfireProperties.setProperty("name", GemFireHttpSessionConfig.class.getName()); gemfireProperties.setProperty("name", GemFireHttpSessionConfig.class.getName());
gemfireProperties.setProperty("mcast-port", "0"); gemfireProperties.setProperty("mcast-port", "0");
gemfireProperties.setProperty("log-level", AbstractGemFireIntegrationTests.GEMFIRE_LOG_LEVEL); gemfireProperties.setProperty("log-level",
AbstractGemFireIntegrationTests.GEMFIRE_LOG_LEVEL);
return gemfireProperties; return gemfireProperties;
} }

View File

@@ -34,7 +34,8 @@ import static org.assertj.core.api.Assertions.assertThat;
*/ */
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = GemFireHttpSessionConfig.class) @ContextConfiguration(classes = GemFireHttpSessionConfig.class)
public class HttpSessionGemFireIndexingCustomITests extends AbstractGemFireIntegrationTests { public class HttpSessionGemFireIndexingCustomITests
extends AbstractGemFireIntegrationTests {
@Test @Test
public void findByIndexName() { public void findByIndexName() {
@@ -49,7 +50,8 @@ public class HttpSessionGemFireIndexingCustomITests extends AbstractGemFireInteg
sessionRepository.save(session); sessionRepository.save(session);
// tag::findbyindexname-get[] // tag::findbyindexname-get[]
Map<String, ExpiringSession> idToSessions = sessionRepository.findByIndexNameAndIndexValue(indexName, attrValue); Map<String, ExpiringSession> idToSessions = sessionRepository
.findByIndexNameAndIndexValue(indexName, attrValue);
// end::findbyindexname-get[] // end::findbyindexname-get[]
assertThat(idToSessions.keySet()).containsOnly(session.getId()); assertThat(idToSessions.keySet()).containsOnly(session.getId());

View File

@@ -41,7 +41,8 @@ public class FindByIndexNameSessionRepositoryTests {
public void setUsername() { public void setUsername() {
// tag::set-username[] // tag::set-username[]
String username = "username"; String username = "username";
this.session.setAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, username); this.session.setAttribute(
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, username);
// end::set-username[] // end::set-username[]
} }
@@ -50,8 +51,10 @@ public class FindByIndexNameSessionRepositoryTests {
public void findByUsername() { public void findByUsername() {
// tag::findby-username[] // tag::findby-username[]
String username = "username"; String username = "username";
Map<String, Session> sessionIdToSession = Map<String, Session> sessionIdToSession = this.sessionRepository
this.sessionRepository.findByIndexNameAndIndexValue(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, username); .findByIndexNameAndIndexValue(
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME,
username);
// end::findby-username[] // end::findby-username[]
} }
} }

View File

@@ -45,7 +45,6 @@ public class HttpSessionConfigurationNoOpConfigureRedisActionXmlTests {
assertThat(this.filter).isNotNull(); assertThat(this.filter).isNotNull();
} }
static RedisConnectionFactory connectionFactory() { static RedisConnectionFactory connectionFactory() {
return mock(RedisConnectionFactory.class); return mock(RedisConnectionFactory.class);
} }

View File

@@ -68,7 +68,6 @@ public class IndexDocTests {
} }
// end::repository-demo[] // end::repository-demo[]
@Test @Test
public void expireRepositoryDemo() { public void expireRepositoryDemo() {
ExpiringRepositoryDemo<ExpiringSession> demo = new ExpiringRepositoryDemo<ExpiringSession>(); ExpiringRepositoryDemo<ExpiringSession> demo = new ExpiringRepositoryDemo<ExpiringSession>();
@@ -102,8 +101,8 @@ public class IndexDocTests {
public void newRedisOperationsSessionRepository() { public void newRedisOperationsSessionRepository() {
// tag::new-redisoperationssessionrepository[] // tag::new-redisoperationssessionrepository[]
JedisConnectionFactory factory = new JedisConnectionFactory(); JedisConnectionFactory factory = new JedisConnectionFactory();
SessionRepository<? extends ExpiringSession> repository = SessionRepository<? extends ExpiringSession> repository = new RedisOperationsSessionRepository(
new RedisOperationsSessionRepository(factory); factory);
// end::new-redisoperationssessionrepository[] // end::new-redisoperationssessionrepository[]
} }

View File

@@ -51,7 +51,9 @@ public abstract class AbstractHttpSessionListenerTests {
public void springSessionDestroyedTranslatedToSpringSecurityDestroyed() { public void springSessionDestroyedTranslatedToSpringSecurityDestroyed() {
Session session = new MapSession(); Session session = new MapSession();
this.publisher.publishEvent(new org.springframework.session.events.SessionDestroyedEvent(this, session)); this.publisher.publishEvent(
new org.springframework.session.events.SessionDestroyedEvent(this,
session));
assertThat(this.listener.getEvent().getId()).isEqualTo(session.getId()); assertThat(this.listener.getEvent().getId()).isEqualTo(session.getId());
} }
@@ -64,12 +66,16 @@ public abstract class AbstractHttpSessionListenerTests {
return factory; return factory;
} }
static class SecuritySessionDestroyedListener implements ApplicationListener<SessionDestroyedEvent> { static class SecuritySessionDestroyedListener
implements ApplicationListener<SessionDestroyedEvent> {
private SessionDestroyedEvent event; private SessionDestroyedEvent event;
/* (non-Javadoc) /*
* @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) * (non-Javadoc)
*
* @see org.springframework.context.ApplicationListener#onApplicationEvent(org.
* springframework.context.ApplicationEvent)
*/ */
public void onApplicationEvent(SessionDestroyedEvent event) { public void onApplicationEvent(SessionDestroyedEvent event) {
this.event = event; this.event = event;

View File

@@ -30,12 +30,10 @@ import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
@Configuration @Configuration
@EnableScheduling @EnableScheduling
@EnableWebSocketMessageBroker @EnableWebSocketMessageBroker
public class WebSocketConfig public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
extends AbstractWebSocketMessageBrokerConfigurer {
public void registerStompEndpoints(StompEndpointRegistry registry) { public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/messages") registry.addEndpoint("/messages").withSockJS();
.withSockJS();
} }
@Override @Override

View File

@@ -18,8 +18,8 @@ package sample.config;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
// tag::class[] // tag::class[]
@EnableRedisHttpSession // <1> @EnableRedisHttpSession // <1>
public class HttpSessionConfig { } public class HttpSessionConfig {
}
// end::class[] // end::class[]

View File

@@ -29,8 +29,6 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired @Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
} }
} }

View File

@@ -22,7 +22,6 @@ import org.springframework.session.data.redis.config.annotation.web.http.EnableR
import org.springframework.session.web.http.CookieSerializer; import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.DefaultCookieSerializer; import org.springframework.session.web.http.DefaultCookieSerializer;
@EnableRedisHttpSession @EnableRedisHttpSession
public class Config { public class Config {

View File

@@ -19,8 +19,7 @@ package sample;
import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer; import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer;
// tag::class[] // tag::class[]
public class Initializer public class Initializer extends AbstractHttpSessionApplicationInitializer { // <1>
extends AbstractHttpSessionApplicationInitializer { // <1>
public Initializer() { public Initializer() {
super(Config.class); // <2> super(Config.class); // <2>

View File

@@ -29,7 +29,8 @@ import javax.servlet.http.HttpServletResponse;
public class SessionServlet extends HttpServlet { public class SessionServlet extends HttpServlet {
@Override @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String attributeName = req.getParameter("attributeName"); String attributeName = req.getParameter("attributeName");
String attributeValue = req.getParameter("attributeValue"); String attributeValue = req.getParameter("attributeValue");
req.getSession().setAttribute(attributeName, attributeValue); req.getSession().setAttribute(attributeName, attributeValue);

View File

@@ -33,7 +33,9 @@ import org.springframework.context.annotation.Configuration;
public class GeoConfig { public class GeoConfig {
@Bean @Bean
public DatabaseReader geoDatabaseReader(@Value("classpath:GeoLite2-City.mmdb") InputStream geoInputStream) throws Exception { public DatabaseReader geoDatabaseReader(
@Value("classpath:GeoLite2-City.mmdb") InputStream geoInputStream)
throws Exception {
return new DatabaseReader.Builder(geoInputStream).build(); return new DatabaseReader.Builder(geoInputStream).build();
} }

View File

@@ -25,5 +25,6 @@ import org.springframework.session.data.redis.config.annotation.web.http.EnableR
*/ */
// tag::class[] // tag::class[]
@EnableRedisHttpSession // <1> @EnableRedisHttpSession // <1>
public class HttpSessionConfig { } public class HttpSessionConfig {
}
// end::class[] // end::class[]

View File

@@ -31,24 +31,14 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
// tag::config[] // tag::config[]
@Override @Override
protected void configure(HttpSecurity http) throws Exception { protected void configure(HttpSecurity http) throws Exception {
http http.formLogin().loginPage("/login").permitAll().and().authorizeRequests()
.formLogin() .antMatchers("/resources/**").permitAll().anyRequest().authenticated()
.loginPage("/login") .and().logout().permitAll();
.permitAll()
.and()
.authorizeRequests()
.antMatchers("/resources/**").permitAll()
.anyRequest().authenticated()
.and()
.logout()
.permitAll();
} }
// end::config[] // end::config[]
@Autowired @Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
} }
} }

View File

@@ -43,17 +43,21 @@ public class IndexController {
@RequestMapping("/") @RequestMapping("/")
public String index(Principal principal, Model model) { public String index(Principal principal, Model model) {
Collection<? extends ExpiringSession> usersSessions = Collection<? extends ExpiringSession> usersSessions = this.sessions
this.sessions.findByIndexNameAndIndexValue(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, .findByIndexNameAndIndexValue(
principal.getName()).values(); FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME,
principal.getName())
.values();
model.addAttribute("sessions", usersSessions); model.addAttribute("sessions", usersSessions);
return "index"; return "index";
} }
// end::findbyusername[] // end::findbyusername[]
@RequestMapping(value = "/sessions/{sessionIdToDelete}", method = RequestMethod.DELETE) @RequestMapping(value = "/sessions/{sessionIdToDelete}", method = RequestMethod.DELETE)
public String removeSession(Principal principal, @PathVariable String sessionIdToDelete) { public String removeSession(Principal principal,
Set<String> usersSessionIds = this.sessions.findByIndexNameAndIndexValue(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, @PathVariable String sessionIdToDelete) {
Set<String> usersSessionIds = this.sessions.findByIndexNameAndIndexValue(
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME,
principal.getName()).keySet(); principal.getName()).keySet();
if (usersSessionIds.contains(sessionIdToDelete)) { if (usersSessionIds.contains(sessionIdToDelete)) {
this.sessions.delete(sessionIdToDelete); this.sessions.delete(sessionIdToDelete);

View File

@@ -35,10 +35,10 @@ import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.filter.OncePerRequestFilter;
/** /**
* Inserts the session details into the session for every request. Some users * Inserts the session details into the session for every request. Some users may prefer
* may prefer to insert session details only after authentication. This is fine, * to insert session details only after authentication. This is fine, but it may be
* but it may be valuable to the most up to date information so that if someone * valuable to the most up to date information so that if someone stole the user's session
* stole the user's session id it can be observed. * id it can be observed.
* *
* @author Rob Winch * @author Rob Winch
* *
@@ -57,8 +57,8 @@ public class SessionDetailsFilter extends OncePerRequestFilter {
} }
// tag::dofilterinternal[] // tag::dofilterinternal[]
public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) public void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
throws IOException, ServletException { FilterChain chain) throws IOException, ServletException {
chain.doFilter(request, response); chain.doFilter(request, response);
HttpSession session = request.getSession(false); HttpSession session = request.getSession(false);
@@ -109,4 +109,3 @@ public class SessionDetailsFilter extends OncePerRequestFilter {
} }
} }
// end::class[] // end::class[]

View File

@@ -48,16 +48,19 @@ public class SessionDetailsFilterTests {
@Test @Test
public void getGeoLocationHanldesInvalidIp() { public void getGeoLocationHanldesInvalidIp() {
assertThat(this.filter.getGeoLocation("a")).isEqualTo(SessionDetailsFilter.UNKNOWN); assertThat(this.filter.getGeoLocation("a"))
.isEqualTo(SessionDetailsFilter.UNKNOWN);
} }
@Test @Test
public void getGeoLocationNullCity() { public void getGeoLocationNullCity() {
assertThat(this.filter.getGeoLocation("22.231.113.64")).isEqualTo("United States"); assertThat(this.filter.getGeoLocation("22.231.113.64"))
.isEqualTo("United States");
} }
@Test @Test
public void getGeoLocationBoth() { public void getGeoLocationBoth() {
assertThat(this.filter.getGeoLocation("184.154.83.119")).isEqualTo("Chicago, United States"); assertThat(this.filter.getGeoLocation("184.154.83.119"))
.isEqualTo("Chicago, United States");
} }
} }

View File

@@ -38,8 +38,8 @@ public class Config {
netConfig.setPort(SocketUtils.findAvailableTcpPort()); netConfig.setPort(SocketUtils.findAvailableTcpPort());
System.out.println("Hazelcast port #: " + netConfig.getPort()); System.out.println("Hazelcast port #: " + netConfig.getPort());
cfg.setNetworkConfig(netConfig); cfg.setNetworkConfig(netConfig);
SerializerConfig serializer = new SerializerConfig().setTypeClass( SerializerConfig serializer = new SerializerConfig().setTypeClass(Object.class)
Object.class).setImplementation(new ObjectStreamSerializer()); .setImplementation(new ObjectStreamSerializer());
cfg.getSerializationConfig().addSerializerConfig(serializer); cfg.getSerializationConfig().addSerializerConfig(serializer);
return Hazelcast.newHazelcastInstance(cfg); return Hazelcast.newHazelcastInstance(cfg);

View File

@@ -27,11 +27,10 @@ import com.hazelcast.nio.ObjectDataOutput;
import com.hazelcast.nio.serialization.StreamSerializer; import com.hazelcast.nio.serialization.StreamSerializer;
/** /**
* A {@link StreamSerializer} that uses Java serialization to persist the * A {@link StreamSerializer} that uses Java serialization to persist the session. This is
* session. This is certainly not the most efficient way to persist sessions, * certainly not the most efficient way to persist sessions, but the example is intended
* but the example is intended to demonstrate using minimal dependencies. For * to demonstrate using minimal dependencies. For better serialization methods try using
* better serialization methods try using <a * <a href="https://github.com/EsotericSoftware/kryo">Kryo</a>.
* href="https://github.com/EsotericSoftware/kryo">Kryo</a>.
* *
* @author Rob Winch * @author Rob Winch
* *
@@ -48,8 +47,7 @@ public class ObjectStreamSerializer implements StreamSerializer<Object> {
out.flush(); out.flush();
} }
public Object read(ObjectDataInput objectDataInput) public Object read(ObjectDataInput objectDataInput) throws IOException {
throws IOException {
ObjectInputStream in = new ObjectInputStream((InputStream) objectDataInput); ObjectInputStream in = new ObjectInputStream((InputStream) objectDataInput);
try { try {
return in.readObject(); return in.readObject();

View File

@@ -28,8 +28,6 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
public class SecurityConfig { public class SecurityConfig {
@Autowired @Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
} }
} }

View File

@@ -19,8 +19,7 @@ package sample;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
// tag::class[] // tag::class[]
public class SecurityInitializer extends public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
AbstractSecurityWebApplicationInitializer {
public SecurityInitializer() { public SecurityInitializer() {
super(SecurityConfig.class, Config.class); super(SecurityConfig.class, Config.class);

View File

@@ -28,7 +28,8 @@ import javax.servlet.http.HttpServletResponse;
public class SessionServlet extends HttpServlet { public class SessionServlet extends HttpServlet {
@Override @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String attributeName = req.getParameter("attributeName"); String attributeName = req.getParameter("attributeName");
String attributeValue = req.getParameter("attributeValue"); String attributeValue = req.getParameter("attributeValue");
req.getSession().setAttribute(attributeName, attributeValue); req.getSession().setAttribute(attributeName, attributeValue);

View File

@@ -53,8 +53,7 @@ public class Initializer implements ServletContextListener {
NetworkConfig netConfig = new NetworkConfig(); NetworkConfig netConfig = new NetworkConfig();
netConfig.setPort(getAvailablePort()); netConfig.setPort(getAvailablePort());
cfg.setNetworkConfig(netConfig); cfg.setNetworkConfig(netConfig);
SerializerConfig serializer = new SerializerConfig() SerializerConfig serializer = new SerializerConfig().setTypeClass(Object.class)
.setTypeClass(Object.class)
.setImplementation(new ObjectStreamSerializer()); .setImplementation(new ObjectStreamSerializer());
cfg.getSerializationConfig().addSerializerConfig(serializer); cfg.getSerializationConfig().addSerializerConfig(serializer);
MapConfig mc = new MapConfig(); MapConfig mc = new MapConfig();
@@ -65,10 +64,10 @@ public class Initializer implements ServletContextListener {
this.instance = Hazelcast.newHazelcastInstance(cfg); this.instance = Hazelcast.newHazelcastInstance(cfg);
Map<String, ExpiringSession> sessions = this.instance.getMap(sessionMapName); Map<String, ExpiringSession> sessions = this.instance.getMap(sessionMapName);
SessionRepository<ExpiringSession> sessionRepository = SessionRepository<ExpiringSession> sessionRepository = new MapSessionRepository(
new MapSessionRepository(sessions); sessions);
SessionRepositoryFilter<ExpiringSession> filter = SessionRepositoryFilter<ExpiringSession> filter = new SessionRepositoryFilter<ExpiringSession>(
new SessionRepositoryFilter<ExpiringSession>(sessionRepository); sessionRepository);
Dynamic fr = sc.addFilter("springSessionFilter", filter); Dynamic fr = sc.addFilter("springSessionFilter", filter);
fr.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*"); fr.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
} }

View File

@@ -27,11 +27,10 @@ import com.hazelcast.nio.ObjectDataOutput;
import com.hazelcast.nio.serialization.StreamSerializer; import com.hazelcast.nio.serialization.StreamSerializer;
/** /**
* A {@link StreamSerializer} that uses Java serialization to persist the * A {@link StreamSerializer} that uses Java serialization to persist the session. This is
* session. This is certainly not the most efficient way to persist sessions, * certainly not the most efficient way to persist sessions, but the example is intended
* but the example is intended to demonstrate using minimal dependencies. For * to demonstrate using minimal dependencies. For better serialization methods try using
* better serialization methods try using <a * <a href="https://github.com/EsotericSoftware/kryo">Kryo</a>.
* href="https://github.com/EsotericSoftware/kryo">Kryo</a>.
* *
* @author Rob Winch * @author Rob Winch
* *
@@ -48,8 +47,7 @@ public class ObjectStreamSerializer implements StreamSerializer<Object> {
out.flush(); out.flush();
} }
public Object read(ObjectDataInput objectDataInput) public Object read(ObjectDataInput objectDataInput) throws IOException {
throws IOException {
ObjectInputStream in = new ObjectInputStream((InputStream) objectDataInput); ObjectInputStream in = new ObjectInputStream((InputStream) objectDataInput);
try { try {
return in.readObject(); return in.readObject();

View File

@@ -31,7 +31,8 @@ import javax.servlet.http.HttpServletResponse;
public class SessionServlet extends HttpServlet { public class SessionServlet extends HttpServlet {
@Override @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String attributeName = req.getParameter("attributeName"); String attributeName = req.getParameter("attributeName");
String attributeValue = req.getParameter("attributeValue"); String attributeValue = req.getParameter("attributeValue");
req.getSession().setAttribute(attributeName, attributeValue); req.getSession().setAttribute(attributeName, attributeValue);

View File

@@ -27,7 +27,8 @@ import org.springframework.context.annotation.ImportResource;
public class Application { public class Application {
public static void main(final String[] args) { public static void main(final String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Application.class); AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
Application.class);
context.registerShutdownHook(); context.registerShutdownHook();
} }
} }

View File

@@ -51,7 +51,8 @@ public class GemFireCacheServerReadyBeanPostProcessor implements BeanPostProcess
// tag::class[] // tag::class[]
static { static {
ClientMembership.registerClientMembershipListener(new ClientMembershipListenerAdapter() { ClientMembership
.registerClientMembershipListener(new ClientMembershipListenerAdapter() {
public void memberJoined(final ClientMembershipEvent event) { public void memberJoined(final ClientMembershipEvent event) {
if (!event.isClient()) { if (!event.isClient()) {
latch.countDown(); latch.countDown();
@@ -64,17 +65,21 @@ public class GemFireCacheServerReadyBeanPostProcessor implements BeanPostProcess
@Resource(name = "applicationProperties") @Resource(name = "applicationProperties")
private Properties applicationProperties; private Properties applicationProperties;
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof PoolFactoryBean || bean instanceof Pool) { if (bean instanceof PoolFactoryBean || bean instanceof Pool) {
String host = getServerHost(DEFAULT_SERVER_HOST); String host = getServerHost(DEFAULT_SERVER_HOST);
Assert.isTrue(waitForCacheServerToStart(host, this.port), String.format( Assert.isTrue(waitForCacheServerToStart(host, this.port),
"GemFire Server failed to start [host: '%1$s', port: %2$d]%n", host, this.port)); String.format(
"GemFire Server failed to start [host: '%1$s', port: %2$d]%n",
host, this.port));
} }
return bean; return bean;
} }
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof PoolFactoryBean || bean instanceof Pool) { if (bean instanceof PoolFactoryBean || bean instanceof Pool) {
try { try {
latch.await(DEFAULT_WAIT_DURATION, TimeUnit.MILLISECONDS); latch.await(DEFAULT_WAIT_DURATION, TimeUnit.MILLISECONDS);
@@ -93,7 +98,8 @@ public class GemFireCacheServerReadyBeanPostProcessor implements BeanPostProcess
} }
String getServerHost(String defaultServerHost) { String getServerHost(String defaultServerHost) {
return this.applicationProperties.getProperty("application.gemfire.client-server.host", defaultServerHost); return this.applicationProperties
.getProperty("application.gemfire.client-server.host", defaultServerHost);
} }
boolean waitForCacheServerToStart(String host, int port) { boolean waitForCacheServerToStart(String host, int port) {
@@ -109,8 +115,10 @@ public class GemFireCacheServerReadyBeanPostProcessor implements BeanPostProcess
Socket socket = null; Socket socket = null;
try { try {
// NOTE: this code is not intended to be an atomic, compound action (a possible race condition); // NOTE: this code is not intended to be an atomic, compound action (a
// opening another connection (at the expense of using system resources) after connectivity // possible race condition);
// opening another connection (at the expense of using system
// resources) after connectivity
// has already been established is not detrimental in this use case // has already been established is not detrimental in this use case
if (!connected.get()) { if (!connected.get()) {
socket = new Socket(host, port); socket = new Socket(host, port);

View File

@@ -55,8 +55,8 @@ public class ClientConfig {
System.setProperty("gemfire.log-level", System.setProperty("gemfire.log-level",
System.getProperty("sample.httpsession.gemfire.log-level", "warning")); System.getProperty("sample.httpsession.gemfire.log-level", "warning"));
ClientMembership.registerClientMembershipListener( ClientMembership
new ClientMembershipListenerAdapter() { .registerClientMembershipListener(new ClientMembershipListenerAdapter() {
public void memberJoined(ClientMembershipEvent event) { public void memberJoined(ClientMembershipEvent event) {
if (!event.isClient()) { if (!event.isClient()) {
latch.countDown(); latch.countDown();
@@ -77,7 +77,8 @@ public class ClientConfig {
@Bean(name = GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME) @Bean(name = GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME)
PoolFactoryBean gemfirePool(// <3> PoolFactoryBean gemfirePool(// <3>
@Value("${spring.session.data.gemfire.port:" + ServerConfig.SERVER_PORT + "}") int port) { @Value("${spring.session.data.gemfire.port:" + ServerConfig.SERVER_PORT
+ "}") int port) {
PoolFactoryBean poolFactory = new PoolFactoryBean(); PoolFactoryBean poolFactory = new PoolFactoryBean();
@@ -91,8 +92,8 @@ public class ClientConfig {
poolFactory.setSubscriptionEnabled(true); poolFactory.setSubscriptionEnabled(true);
poolFactory.setThreadLocalConnections(false); poolFactory.setThreadLocalConnections(false);
poolFactory.setServerEndpoints(Collections.singletonList(new ConnectionEndpoint( poolFactory.setServerEndpoints(Collections.singletonList(
ServerConfig.SERVER_HOSTNAME, port))); new ConnectionEndpoint(ServerConfig.SERVER_HOSTNAME, port)));
return poolFactory; return poolFactory;
} }
@@ -111,27 +112,29 @@ public class ClientConfig {
@Bean @Bean
BeanPostProcessor gemfireCacheServerReadyBeanPostProcessor(// <5> BeanPostProcessor gemfireCacheServerReadyBeanPostProcessor(// <5>
@Value("${spring.session.data.gemfire.port:" + ServerConfig.SERVER_PORT + "}") final int port) { @Value("${spring.session.data.gemfire.port:" + ServerConfig.SERVER_PORT
+ "}") final int port) {
return new BeanPostProcessor() { return new BeanPostProcessor() {
public Object postProcessBeforeInitialization( public Object postProcessBeforeInitialization(Object bean, String beanName)
Object bean, String beanName) throws BeansException { throws BeansException {
if (bean instanceof PoolFactoryBean || bean instanceof Pool) { if (bean instanceof PoolFactoryBean || bean instanceof Pool) {
Assert.isTrue(waitForCacheServerToStart(ServerConfig.SERVER_HOSTNAME, port), Assert.isTrue(
String.format("GemFire Server failed to start [hostname: %1$s, port: %2$d]", waitForCacheServerToStart(ServerConfig.SERVER_HOSTNAME, port),
String.format(
"GemFire Server failed to start [hostname: %1$s, port: %2$d]",
ServerConfig.SERVER_HOSTNAME, port)); ServerConfig.SERVER_HOSTNAME, port));
} }
return bean; return bean;
} }
public Object postProcessAfterInitialization( public Object postProcessAfterInitialization(Object bean, String beanName)
Object bean, String beanName) throws BeansException { throws BeansException {
if (bean instanceof PoolFactoryBean || bean instanceof Pool) { if (bean instanceof PoolFactoryBean || bean instanceof Pool) {
try { try {
latch.await(DEFAULT_WAIT_DURATION, latch.await(DEFAULT_WAIT_DURATION, TimeUnit.MILLISECONDS);
TimeUnit.MILLISECONDS);
} }
catch (InterruptedException e) { catch (InterruptedException e) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
@@ -161,8 +164,10 @@ public class ClientConfig {
Socket socket = null; Socket socket = null;
try { try {
// NOTE: this code is not intended to be an atomic, compound action (a possible race condition); // NOTE: this code is not intended to be an atomic, compound action (a
// opening another connection (at the expense of using system resources) after connectivity // possible race condition);
// opening another connection (at the expense of using system
// resources) after connectivity
// has already been established is not detrimental in this use case // has already been established is not detrimental in this use case
if (!connected.get()) { if (!connected.get()) {
socket = new Socket(host, port); socket = new Socket(host, port);

View File

@@ -19,8 +19,7 @@ package sample;
import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer; import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer;
// tag::class[] // tag::class[]
public class Initializer public class Initializer extends AbstractHttpSessionApplicationInitializer { // <1>
extends AbstractHttpSessionApplicationInitializer { // <1>
public Initializer() { public Initializer() {
super(ClientConfig.class); // <2> super(ClientConfig.class); // <2>

View File

@@ -84,8 +84,7 @@ public class ServerConfig {
@SuppressWarnings("resource") @SuppressWarnings("resource")
public static void main(final String[] args) throws IOException { // <5> public static void main(final String[] args) throws IOException { // <5>
new AnnotationConfigApplicationContext(ServerConfig.class) new AnnotationConfigApplicationContext(ServerConfig.class).registerShutdownHook();
.registerShutdownHook();
} }
} }
// end::class[] // end::class[]

View File

@@ -19,8 +19,7 @@ package sample;
import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer; import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer;
// tag::class[] // tag::class[]
public class Initializer public class Initializer extends AbstractHttpSessionApplicationInitializer { // <1>
extends AbstractHttpSessionApplicationInitializer { // <1>
public Initializer() { public Initializer() {
super(Config.class); // <2> super(Config.class); // <2>

View File

@@ -15,15 +15,19 @@
*/ */
package sample; package sample;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException; import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
// tag::class[] // tag::class[]
public class SessionServlet extends HttpServlet { public class SessionServlet extends HttpServlet {
@Override @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String attributeName = req.getParameter("attributeName"); String attributeName = req.getParameter("attributeName");
String attributeValue = req.getParameter("attributeValue"); String attributeValue = req.getParameter("attributeValue");
req.getSession().setAttribute(attributeName, attributeValue); req.getSession().setAttribute(attributeName, attributeValue);

View File

@@ -34,8 +34,7 @@ public class Config {
public EmbeddedDatabase dataSource() { public EmbeddedDatabase dataSource() {
return new EmbeddedDatabaseBuilder() // <2> return new EmbeddedDatabaseBuilder() // <2>
.setType(EmbeddedDatabaseType.H2) .setType(EmbeddedDatabaseType.H2)
.addScript("org/springframework/session/jdbc/schema-h2.sql") .addScript("org/springframework/session/jdbc/schema-h2.sql").build();
.build();
} }
@Bean @Bean

View File

@@ -18,8 +18,7 @@ package sample;
import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer; import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer;
// tag::class[] // tag::class[]
public class Initializer public class Initializer extends AbstractHttpSessionApplicationInitializer { // <1>
extends AbstractHttpSessionApplicationInitializer { // <1>
public Initializer() { public Initializer() {
super(Config.class); // <2> super(Config.class); // <2>

View File

@@ -15,17 +15,21 @@
*/ */
package sample; package sample;
import javax.servlet.*;
import javax.servlet.annotation.*;
import javax.servlet.http.*;
import java.io.IOException; import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
// tag::class[] // tag::class[]
@WebServlet("/session") @WebServlet("/session")
public class SessionServlet extends HttpServlet { public class SessionServlet extends HttpServlet {
@Override @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String attributeName = req.getParameter("attributeName"); String attributeName = req.getParameter("attributeName");
String attributeValue = req.getParameter("attributeValue"); String attributeValue = req.getParameter("attributeValue");
req.getSession().setAttribute(attributeName, attributeValue); req.getSession().setAttribute(attributeName, attributeValue);

View File

@@ -27,7 +27,8 @@ import javax.servlet.http.HttpServletResponse;
public class SessionServlet extends HttpServlet { public class SessionServlet extends HttpServlet {
@Override @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String attributeName = req.getParameter("attributeName"); String attributeName = req.getParameter("attributeName");
String attributeValue = req.getParameter("attributeValue"); String attributeValue = req.getParameter("attributeValue");
req.getSession().setAttribute(attributeName, attributeValue); req.getSession().setAttribute(attributeName, attributeValue);

View File

@@ -19,8 +19,7 @@ package sample;
import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer; import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer;
// tag::class[] // tag::class[]
public class Initializer public class Initializer extends AbstractHttpSessionApplicationInitializer { // <1>
extends AbstractHttpSessionApplicationInitializer { // <1>
public Initializer() { public Initializer() {
super(Config.class); // <2> super(Config.class); // <2>

View File

@@ -29,7 +29,8 @@ import javax.servlet.http.HttpServletResponse;
public class SessionServlet extends HttpServlet { public class SessionServlet extends HttpServlet {
@Override @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String attributeName = req.getParameter("attributeName"); String attributeName = req.getParameter("attributeName");
String attributeValue = req.getParameter("attributeValue"); String attributeValue = req.getParameter("attributeValue");
req.getSession().setAttribute(attributeName, attributeValue); req.getSession().setAttribute(attributeName, attributeValue);

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2015 the original author or authors. * Copyright 2014-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -16,16 +16,15 @@
package sample package sample
import geb.spock.* import geb.spock.*
import org.springframework.beans.factory.annotation.Value import pages.*
import org.springframework.boot.test.IntegrationTest
import org.springframework.boot.test.SpringApplicationConfiguration
import org.springframework.boot.test.SpringApplicationContextLoader
import org.springframework.test.context.ContextConfiguration
import org.springframework.test.context.web.WebAppConfiguration
import sample.pages.HomePage import sample.pages.HomePage
import sample.pages.LoginPage import sample.pages.LoginPage
import spock.lang.Stepwise import spock.lang.Stepwise
import pages.*
import org.springframework.boot.test.IntegrationTest
import org.springframework.boot.test.SpringApplicationContextLoader
import org.springframework.test.context.ContextConfiguration
import org.springframework.test.context.web.WebAppConfiguration
/** /**
* Tests the demo that supports multiple sessions * Tests the demo that supports multiple sessions

View File

@@ -1,17 +1,17 @@
/* /*
* Copyright 2002-2015 the original author or authors. * Copyright 2014-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not * Licensed under the Apache License, Version 2.0 (the "License");
* use this file except in compliance with the License. You may obtain a copy of * you may not use this file except in compliance with the License.
* the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * distributed under the License is distributed on an "AS IS" BASIS,
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* License for the specific language governing permissions and limitations under * See the License for the specific language governing permissions and
* the License. * limitations under the License.
*/ */
package sample; package sample;

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2015 the original author or authors. * Copyright 2014-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -17,8 +17,8 @@ package sample.config;
import org.springframework.session.data.mongo.config.annotation.web.http.EnableMongoHttpSession; import org.springframework.session.data.mongo.config.annotation.web.http.EnableMongoHttpSession;
// tag::class[] // tag::class[]
@EnableMongoHttpSession // <1> @EnableMongoHttpSession // <1>
public class HttpSessionConfig { } public class HttpSessionConfig {
}
// end::class[] // end::class[]

View File

@@ -1,17 +1,17 @@
/* /*
* Copyright 2002-2015 the original author or authors. * Copyright 2014-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not * Licensed under the Apache License, Version 2.0 (the "License");
* use this file except in compliance with the License. You may obtain a copy of * you may not use this file except in compliance with the License.
* the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * distributed under the License is distributed on an "AS IS" BASIS,
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* License for the specific language governing permissions and limitations under * See the License for the specific language governing permissions and
* the License. * limitations under the License.
*/ */
package sample.config; package sample.config;
@@ -28,8 +28,6 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired @Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
} }
} }

View File

@@ -1,17 +1,17 @@
/* /*
* Copyright 2002-2015 the original author or authors. * Copyright 2014-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not * Licensed under the Apache License, Version 2.0 (the "License");
* use this file except in compliance with the License. You may obtain a copy of * you may not use this file except in compliance with the License.
* the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * distributed under the License is distributed on an "AS IS" BASIS,
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* License for the specific language governing permissions and limitations under * See the License for the specific language governing permissions and
* the License. * limitations under the License.
*/ */
package sample.mvc; package sample.mvc;

View File

@@ -43,9 +43,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {HttpSessionConfig.class, SecurityConfig.class, MvcConfig.class}) @ContextConfiguration(classes = { HttpSessionConfig.class, SecurityConfig.class,
MvcConfig.class })
@WebAppConfiguration @WebAppConfiguration
public class RestMockMvcTests { public class RestMockMvcTests {
@@ -59,25 +59,20 @@ public class RestMockMvcTests {
@Before @Before
public void setup() { public void setup() {
this.mvc = MockMvcBuilders.webAppContextSetup(this.context) this.mvc = MockMvcBuilders.webAppContextSetup(this.context).alwaysDo(print())
.alwaysDo(print()) .addFilters(this.sessionRepositoryFilter).apply(springSecurity()).build();
.addFilters(this.sessionRepositoryFilter)
.apply(springSecurity())
.build();
} }
@Test @Test
public void noSessionOnNoCredentials() throws Exception { public void noSessionOnNoCredentials() throws Exception {
this.mvc.perform(get("/")) this.mvc.perform(get("/")).andExpect(header().doesNotExist("x-auth-token"))
.andExpect(header().doesNotExist("x-auth-token"))
.andExpect(status().isUnauthorized()); .andExpect(status().isUnauthorized());
} }
@WithMockUser @WithMockUser
@Test @Test
public void autheticatedAnnotation() throws Exception { public void autheticatedAnnotation() throws Exception {
this.mvc.perform(get("/")) this.mvc.perform(get("/")).andExpect(content().string("{\"username\":\"user\"}"));
.andExpect(content().string("{\"username\":\"user\"}"));
} }

View File

@@ -21,7 +21,6 @@ import org.springframework.security.web.context.AbstractSecurityWebApplicationIn
/** /**
* @author Rob Winch * @author Rob Winch
*/ */
public class SecurityInitializer extends public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
AbstractSecurityWebApplicationInitializer {
} }

View File

@@ -28,8 +28,6 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
public class SecurityConfig { public class SecurityConfig {
@Autowired @Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
} }
} }

View File

@@ -19,8 +19,7 @@ package sample;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
// tag::class[] // tag::class[]
public class SecurityInitializer extends public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
AbstractSecurityWebApplicationInitializer {
public SecurityInitializer() { public SecurityInitializer() {
super(SecurityConfig.class, Config.class); super(SecurityConfig.class, Config.class);

View File

@@ -28,7 +28,8 @@ import javax.servlet.http.HttpServletResponse;
public class SessionServlet extends HttpServlet { public class SessionServlet extends HttpServlet {
@Override @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String attributeName = req.getParameter("attributeName"); String attributeName = req.getParameter("attributeName");
String attributeValue = req.getParameter("attributeValue"); String attributeValue = req.getParameter("attributeValue");
req.getSession().setAttribute(attributeName, attributeValue); req.getSession().setAttribute(attributeName, attributeValue);

View File

@@ -44,11 +44,11 @@ public class UserAccountsFilter implements Filter {
HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletRequest httpRequest = (HttpServletRequest) request;
// tag::HttpSessionManager[] // tag::HttpSessionManager[]
HttpSessionManager sessionManager = HttpSessionManager sessionManager = (HttpSessionManager) httpRequest
(HttpSessionManager) httpRequest.getAttribute(HttpSessionManager.class.getName()); .getAttribute(HttpSessionManager.class.getName());
// end::HttpSessionManager[] // end::HttpSessionManager[]
SessionRepository<Session> repo = SessionRepository<Session> repo = (SessionRepository<Session>) httpRequest
(SessionRepository<Session>) httpRequest.getAttribute(SessionRepository.class.getName()); .getAttribute(SessionRepository.class.getName());
String currentSessionAlias = sessionManager.getCurrentSessionAlias(httpRequest); String currentSessionAlias = sessionManager.getCurrentSessionAlias(httpRequest);
Map<String, String> sessionIds = sessionManager.getSessionIds(httpRequest); Map<String, String> sessionIds = sessionManager.getSessionIds(httpRequest);
@@ -85,7 +85,8 @@ public class UserAccountsFilter implements Filter {
// tag::addAccountUrl[] // tag::addAccountUrl[]
String addAlias = unauthenticatedAlias == null ? // <1> String addAlias = unauthenticatedAlias == null ? // <1>
sessionManager.getNewSessionAlias(httpRequest) : // <2> sessionManager.getNewSessionAlias(httpRequest)
: // <2>
unauthenticatedAlias; // <3> unauthenticatedAlias; // <3>
String addAccountUrl = sessionManager.encodeURL(contextPath, addAlias); // <4> String addAccountUrl = sessionManager.encodeURL(contextPath, addAlias); // <4>
// end::addAccountUrl[] // end::addAccountUrl[]

View File

@@ -23,8 +23,8 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
/** /**
* Initializes the H2 {@link WebServlet} so we can access our in memory database * Initializes the H2 {@link WebServlet} so we can access our in memory database from the
* from the URL "/h2". * URL "/h2".
* *
* @author Rob Winch * @author Rob Winch
*/ */

View File

@@ -34,8 +34,7 @@ import org.springframework.session.data.redis.config.annotation.web.http.EnableR
@EnableGlobalMethodSecurity(prePostEnabled = true) @EnableGlobalMethodSecurity(prePostEnabled = true)
// tag::enable-redis-httpsession[] // tag::enable-redis-httpsession[]
@EnableRedisHttpSession // (maxInactiveIntervalInSeconds = 60) @EnableRedisHttpSession // (maxInactiveIntervalInSeconds = 60)
public class WebSecurityConfig public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
extends WebSecurityConfigurerAdapter {
// end::enable-redis-httpsession[] // end::enable-redis-httpsession[]
// @formatter:off // @formatter:off

View File

@@ -32,8 +32,7 @@ public class WebSocketConfig
extends AbstractSessionWebSocketMessageBrokerConfigurer<ExpiringSession> { // <1> extends AbstractSessionWebSocketMessageBrokerConfigurer<ExpiringSession> { // <1>
protected void configureStompEndpoints(StompEndpointRegistry registry) { // <2> protected void configureStompEndpoints(StompEndpointRegistry registry) { // <2>
registry.addEndpoint("/messages") registry.addEndpoint("/messages").withSockJS();
.withSockJS();
} }
public void configureMessageBroker(MessageBrokerRegistry registry) { public void configureMessageBroker(MessageBrokerRegistry registry) {

View File

@@ -24,8 +24,10 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.SimpMessageSendingOperations; import org.springframework.messaging.simp.SimpMessageSendingOperations;
import org.springframework.session.ExpiringSession; import org.springframework.session.ExpiringSession;
/** /**
* These handlers are separated from WebSocketConfig because they are specific to this application and do not demonstrate a typical Spring Session setup. * These handlers are separated from WebSocketConfig because they are specific to this
* application and do not demonstrate a typical Spring Session setup.
* *
* @author Rob Winch * @author Rob Winch
*/ */
@@ -33,12 +35,16 @@ import org.springframework.session.ExpiringSession;
public class WebSocketHandlersConfig<S extends ExpiringSession> { public class WebSocketHandlersConfig<S extends ExpiringSession> {
@Bean @Bean
public WebSocketConnectHandler<S> webSocketConnectHandler(SimpMessageSendingOperations messagingTemplate, ActiveWebSocketUserRepository repository) { public WebSocketConnectHandler<S> webSocketConnectHandler(
SimpMessageSendingOperations messagingTemplate,
ActiveWebSocketUserRepository repository) {
return new WebSocketConnectHandler<S>(messagingTemplate, repository); return new WebSocketConnectHandler<S>(messagingTemplate, repository);
} }
@Bean @Bean
public WebSocketDisconnectHandler<S> webSocketDisconnectHandler(SimpMessageSendingOperations messagingTemplate, ActiveWebSocketUserRepository repository) { public WebSocketDisconnectHandler<S> webSocketDisconnectHandler(
SimpMessageSendingOperations messagingTemplate,
ActiveWebSocketUserRepository repository) {
return new WebSocketDisconnectHandler<S>(messagingTemplate, repository); return new WebSocketDisconnectHandler<S>(messagingTemplate, repository);
} }
} }

View File

@@ -24,7 +24,8 @@ import org.springframework.security.config.annotation.web.socket.AbstractSecurit
* @author Rob Winch * @author Rob Winch
*/ */
@Configuration @Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer { public class WebSocketSecurityConfig
extends AbstractSecurityWebSocketMessageBrokerConfigurer {
// @formatter:off // @formatter:off
@Override @Override

View File

@@ -56,5 +56,4 @@ public class ActiveWebSocketUser {
this.connectionTime = connectionTime; this.connectionTime = connectionTime;
} }
} }

View File

@@ -21,7 +21,8 @@ import java.util.List;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;
public interface ActiveWebSocketUserRepository extends CrudRepository<ActiveWebSocketUser, String> { public interface ActiveWebSocketUserRepository
extends CrudRepository<ActiveWebSocketUser, String> {
@Query("select DISTINCT(u.username) from ActiveWebSocketUser u where u.username != ?#{principal?.username}") @Query("select DISTINCT(u.username) from ActiveWebSocketUser u where u.username != ?#{principal?.username}")
List<String> findAllActiveUsers(); List<String> findAllActiveUsers();

View File

@@ -59,6 +59,4 @@ public class InstantMessage {
this.created = created; this.created = created;
} }
} }

View File

@@ -44,7 +44,8 @@ public class MessageController {
private ActiveWebSocketUserRepository activeUserRepository; private ActiveWebSocketUserRepository activeUserRepository;
@Autowired @Autowired
public MessageController(ActiveWebSocketUserRepository activeUserRepository, SimpMessageSendingOperations messagingTemplate) { public MessageController(ActiveWebSocketUserRepository activeUserRepository,
SimpMessageSendingOperations messagingTemplate) {
this.activeUserRepository = activeUserRepository; this.activeUserRepository = activeUserRepository;
this.messagingTemplate = messagingTemplate; this.messagingTemplate = messagingTemplate;
} }

View File

@@ -27,16 +27,14 @@ import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
/** /**
* Annotate Spring MVC method arguments with this annotation to indicate you * Annotate Spring MVC method arguments with this annotation to indicate you wish to
* wish to specify the argument with the value of the current * specify the argument with the value of the current
* {@link Authentication#getPrincipal()} found on the * {@link Authentication#getPrincipal()} found on the {@link SecurityContextHolder}.
* {@link SecurityContextHolder}.
* *
* <p> * <p>
* Creating your own annotation that uses {@link AuthenticationPrincipal} as a * Creating your own annotation that uses {@link AuthenticationPrincipal} as a meta
* meta annotation creates a layer of indirection between your code and Spring * annotation creates a layer of indirection between your code and Spring Security's. For
* Security's. For simplicity, you could instead use the * simplicity, you could instead use the {@link AuthenticationPrincipal} directly.
* {@link AuthenticationPrincipal} directly.
* </p> * </p>
* *
* @author Rob Winch * @author Rob Winch

View File

@@ -42,8 +42,12 @@ public class UserRepositoryUserDetailsService implements UserDetailsService {
this.userRepository = userRepository; this.userRepository = userRepository;
} }
/* (non-Javadoc) /*
* @see org.springframework.security.core.userdetails.UserDetailsService#loadUserByUsername(java.lang.String) * (non-Javadoc)
*
* @see
* org.springframework.security.core.userdetails.UserDetailsService#loadUserByUsername
* (java.lang.String)
*/ */
public UserDetails loadUserByUsername(String username) public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException { throws UsernameNotFoundException {

View File

@@ -29,11 +29,13 @@ import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
import org.springframework.messaging.simp.SimpMessageSendingOperations; import org.springframework.messaging.simp.SimpMessageSendingOperations;
import org.springframework.web.socket.messaging.SessionConnectEvent; import org.springframework.web.socket.messaging.SessionConnectEvent;
public class WebSocketConnectHandler<S> implements ApplicationListener<SessionConnectEvent> { public class WebSocketConnectHandler<S>
implements ApplicationListener<SessionConnectEvent> {
private ActiveWebSocketUserRepository repository; private ActiveWebSocketUserRepository repository;
private SimpMessageSendingOperations messagingTemplate; private SimpMessageSendingOperations messagingTemplate;
public WebSocketConnectHandler(SimpMessageSendingOperations messagingTemplate, ActiveWebSocketUserRepository repository) { public WebSocketConnectHandler(SimpMessageSendingOperations messagingTemplate,
ActiveWebSocketUserRepository repository) {
super(); super();
this.messagingTemplate = messagingTemplate; this.messagingTemplate = messagingTemplate;
this.repository = repository; this.repository = repository;
@@ -46,7 +48,9 @@ public class WebSocketConnectHandler<S> implements ApplicationListener<SessionCo
return; return;
} }
String id = SimpMessageHeaderAccessor.getSessionId(headers); String id = SimpMessageHeaderAccessor.getSessionId(headers);
this.repository.save(new ActiveWebSocketUser(id, user.getName(), Calendar.getInstance())); this.repository.save(
this.messagingTemplate.convertAndSend("/topic/friends/signin", Arrays.asList(user.getName())); new ActiveWebSocketUser(id, user.getName(), Calendar.getInstance()));
this.messagingTemplate.convertAndSend("/topic/friends/signin",
Arrays.asList(user.getName()));
} }
} }

View File

@@ -25,11 +25,13 @@ import org.springframework.context.ApplicationListener;
import org.springframework.messaging.simp.SimpMessageSendingOperations; import org.springframework.messaging.simp.SimpMessageSendingOperations;
import org.springframework.web.socket.messaging.SessionDisconnectEvent; import org.springframework.web.socket.messaging.SessionDisconnectEvent;
public class WebSocketDisconnectHandler<S> implements ApplicationListener<SessionDisconnectEvent> { public class WebSocketDisconnectHandler<S>
implements ApplicationListener<SessionDisconnectEvent> {
private ActiveWebSocketUserRepository repository; private ActiveWebSocketUserRepository repository;
private SimpMessageSendingOperations messagingTemplate; private SimpMessageSendingOperations messagingTemplate;
public WebSocketDisconnectHandler(SimpMessageSendingOperations messagingTemplate, ActiveWebSocketUserRepository repository) { public WebSocketDisconnectHandler(SimpMessageSendingOperations messagingTemplate,
ActiveWebSocketUserRepository repository) {
super(); super();
this.messagingTemplate = messagingTemplate; this.messagingTemplate = messagingTemplate;
this.repository = repository; this.repository = repository;
@@ -46,7 +48,8 @@ public class WebSocketDisconnectHandler<S> implements ApplicationListener<Sessio
} }
this.repository.delete(id); this.repository.delete(id);
this.messagingTemplate.convertAndSend("/topic/friends/signout", Arrays.asList(user.getUsername())); this.messagingTemplate.convertAndSend("/topic/friends/signout",
Arrays.asList(user.getUsername()));
} }
} }

View File

@@ -1,7 +1,25 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data; package org.springframework.session.data;
import java.util.UUID;
import org.junit.Before; import org.junit.Before;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.authority.AuthorityUtils;
@@ -10,8 +28,6 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.context.web.WebAppConfiguration;
import java.util.UUID;
/** /**
* Base class for repositories integration tests * Base class for repositories integration tests
* *
@@ -30,14 +46,18 @@ public abstract class AbstractITests {
@Before @Before
public void setup() { public void setup() {
if (registry != null) { if (this.registry != null) {
registry.clear(); this.registry.clear();
} }
context = SecurityContextHolder.createEmptyContext(); this.context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(new UsernamePasswordAuthenticationToken("username-" + UUID.randomUUID(), "na", AuthorityUtils.createAuthorityList("ROLE_USER"))); this.context.setAuthentication(
new UsernamePasswordAuthenticationToken("username-" + UUID.randomUUID(),
"na", AuthorityUtils.createAuthorityList("ROLE_USER")));
changedContext = SecurityContextHolder.createEmptyContext(); this.changedContext = SecurityContextHolder.createEmptyContext();
changedContext.setAuthentication(new UsernamePasswordAuthenticationToken("changedContext-" + UUID.randomUUID(), "na", AuthorityUtils.createAuthorityList("ROLE_USER"))); this.changedContext.setAuthentication(new UsernamePasswordAuthenticationToken(
"changedContext-" + UUID.randomUUID(), "na",
AuthorityUtils.createAuthorityList("ROLE_USER")));
} }
} }

View File

@@ -45,12 +45,14 @@ public class SessionEventRegistry implements ApplicationListener<AbstractSession
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <E extends AbstractSessionEvent> E getEvent(String sessionId) throws InterruptedException { public <E extends AbstractSessionEvent> E getEvent(String sessionId)
throws InterruptedException {
return (E) waitForEvent(sessionId); return (E) waitForEvent(sessionId);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private <E extends AbstractSessionEvent> E waitForEvent(String sessionId) throws InterruptedException { private <E extends AbstractSessionEvent> E waitForEvent(String sessionId)
throws InterruptedException {
Object lock = getLock(sessionId); Object lock = getLock(sessionId);
synchronized (lock) { synchronized (lock) {
if (!this.events.containsKey(sessionId)) { if (!this.events.containsKey(sessionId)) {

View File

@@ -47,8 +47,8 @@ import org.springframework.session.events.AbstractSessionEvent;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
/** /**
* AbstractGemFireIntegrationTests is an abstract base class encapsulating common operations for writing * AbstractGemFireIntegrationTests is an abstract base class encapsulating common
* Spring Session GemFire integration tests. * operations for writing Spring Session GemFire integration tests.
* *
* @author John Blum * @author John Blum
* @since 1.1.0 * @since 1.1.0
@@ -65,22 +65,24 @@ import static org.assertj.core.api.Assertions.assertThat;
public abstract class AbstractGemFireIntegrationTests { public abstract class AbstractGemFireIntegrationTests {
protected static final boolean DEFAULT_ENABLE_QUERY_DEBUGGING = false; protected static final boolean DEFAULT_ENABLE_QUERY_DEBUGGING = false;
protected static final boolean GEMFIRE_QUERY_DEBUG = Boolean.getBoolean("spring.session.data.gemfire.query.debug"); protected static final boolean GEMFIRE_QUERY_DEBUG = Boolean
.getBoolean("spring.session.data.gemfire.query.debug");
protected static final int DEFAULT_GEMFIRE_SERVER_PORT = CacheServer.DEFAULT_PORT; protected static final int DEFAULT_GEMFIRE_SERVER_PORT = CacheServer.DEFAULT_PORT;
protected static final long DEFAULT_WAIT_DURATION = TimeUnit.SECONDS.toMillis(20); protected static final long DEFAULT_WAIT_DURATION = TimeUnit.SECONDS.toMillis(20);
protected static final long DEFAULT_WAIT_INTERVAL = 500L; protected static final long DEFAULT_WAIT_INTERVAL = 500L;
protected static final File WORKING_DIRECTORY = new File(System.getProperty("user.dir")); protected static final File WORKING_DIRECTORY = new File(
System.getProperty("user.dir"));
protected static final String DEFAULT_PROCESS_CONTROL_FILENAME = "process.ctl"; protected static final String DEFAULT_PROCESS_CONTROL_FILENAME = "process.ctl";
protected static final String GEMFIRE_LOG_FILE_NAME = System.getProperty( protected static final String GEMFIRE_LOG_FILE_NAME = System
"spring.session.data.gemfire.log-file", "server.log"); .getProperty("spring.session.data.gemfire.log-file", "server.log");
protected static final String GEMFIRE_LOG_LEVEL = System.getProperty( protected static final String GEMFIRE_LOG_LEVEL = System
"spring.session.data.gemfire.log-level", "warning"); .getProperty("spring.session.data.gemfire.log-level", "warning");
@Autowired @Autowired
protected Cache gemfireCache; protected Cache gemfireCache;
@@ -90,15 +92,17 @@ public abstract class AbstractGemFireIntegrationTests {
@Before @Before
public void setup() { public void setup() {
System.setProperty("gemfire.Query.VERBOSE", String.valueOf(isQueryDebuggingEnabled())); System.setProperty("gemfire.Query.VERBOSE",
String.valueOf(isQueryDebuggingEnabled()));
} }
/* (non-Javadoc) */ /* (non-Javadoc) */
protected static File createDirectory(String pathname) { protected static File createDirectory(String pathname) {
File directory = new File(WORKING_DIRECTORY, pathname); File directory = new File(WORKING_DIRECTORY, pathname);
assertThat(directory.isDirectory() || directory.mkdirs()).as( assertThat(directory.isDirectory() || directory.mkdirs())
String.format("Failed to create directory (%1$s)", directory)).isTrue(); .as(String.format("Failed to create directory (%1$s)", directory))
.isTrue();
directory.deleteOnExit(); directory.deleteOnExit();
@@ -106,7 +110,8 @@ public abstract class AbstractGemFireIntegrationTests {
} }
/* (non-Javadoc) */ /* (non-Javadoc) */
protected static List<String> createJavaProcessCommandLine(Class<?> type, String... args) { protected static List<String> createJavaProcessCommandLine(Class<?> type,
String... args) {
List<String> commandLine = new ArrayList<String>(); List<String> commandLine = new ArrayList<String>();
String javaHome = System.getProperty("java.home"); String javaHome = System.getProperty("java.home");
@@ -117,7 +122,8 @@ public abstract class AbstractGemFireIntegrationTests {
commandLine.add("-ea"); commandLine.add("-ea");
commandLine.add(String.format("-Dgemfire.log-file=%1$s", GEMFIRE_LOG_FILE_NAME)); commandLine.add(String.format("-Dgemfire.log-file=%1$s", GEMFIRE_LOG_FILE_NAME));
commandLine.add(String.format("-Dgemfire.log-level=%1$s", GEMFIRE_LOG_LEVEL)); commandLine.add(String.format("-Dgemfire.log-level=%1$s", GEMFIRE_LOG_LEVEL));
commandLine.add(String.format("-Dgemfire.Query.VERBOSE=%1$s", GEMFIRE_QUERY_DEBUG)); commandLine
.add(String.format("-Dgemfire.Query.VERBOSE=%1$s", GEMFIRE_QUERY_DEBUG));
commandLine.addAll(extractJvmArguments(args)); commandLine.addAll(extractJvmArguments(args));
commandLine.add("-classpath"); commandLine.add("-classpath");
commandLine.add(System.getProperty("java.class.path")); commandLine.add(System.getProperty("java.class.path"));
@@ -156,11 +162,10 @@ public abstract class AbstractGemFireIntegrationTests {
} }
/* (non-Javadoc) */ /* (non-Javadoc) */
protected static Process run(Class<?> type, File directory, String... args) throws IOException { protected static Process run(Class<?> type, File directory, String... args)
return new ProcessBuilder() throws IOException {
.command(createJavaProcessCommandLine(type, args)) return new ProcessBuilder().command(createJavaProcessCommandLine(type, args))
.directory(directory) .directory(directory).start();
.start();
} }
/* (non-Javadoc) */ /* (non-Javadoc) */
@@ -169,8 +174,10 @@ public abstract class AbstractGemFireIntegrationTests {
} }
/* (non-Javadoc) */ /* (non-Javadoc) */
protected static boolean waitForCacheServerToStart(CacheServer cacheServer, long duration) { protected static boolean waitForCacheServerToStart(CacheServer cacheServer,
return waitForCacheServerToStart(cacheServer.getBindAddress(), cacheServer.getPort(), duration); long duration) {
return waitForCacheServerToStart(cacheServer.getBindAddress(),
cacheServer.getPort(), duration);
} }
/* (non-Javadoc) */ /* (non-Javadoc) */
@@ -179,7 +186,8 @@ public abstract class AbstractGemFireIntegrationTests {
} }
/* (non-Javadoc) */ /* (non-Javadoc) */
protected static boolean waitForCacheServerToStart(final String host, final int port, long duration) { protected static boolean waitForCacheServerToStart(final String host, final int port,
long duration) {
return waitOnCondition(new Condition() { return waitOnCondition(new Condition() {
AtomicBoolean connected = new AtomicBoolean(false); AtomicBoolean connected = new AtomicBoolean(false);
@@ -203,7 +211,8 @@ public abstract class AbstractGemFireIntegrationTests {
}, duration); }, duration);
} }
// NOTE this method would not be necessary except Spring Sessions' build does not fork the test JVM // NOTE this method would not be necessary except Spring Sessions' build does not fork
// the test JVM
// for every test class. // for every test class.
/* (non-Javadoc) */ /* (non-Javadoc) */
protected static boolean waitForClientCacheToClose() { protected static boolean waitForClientCacheToClose() {
@@ -238,7 +247,8 @@ public abstract class AbstractGemFireIntegrationTests {
/* (non-Javadoc) */ /* (non-Javadoc) */
@SuppressWarnings("all") @SuppressWarnings("all")
protected static boolean waitForProcessToStart(Process process, File directory, long duration) { protected static boolean waitForProcessToStart(Process process, File directory,
long duration) {
final File processControl = new File(directory, DEFAULT_PROCESS_CONTROL_FILENAME); final File processControl = new File(directory, DEFAULT_PROCESS_CONTROL_FILENAME);
waitOnCondition(new Condition() { waitOnCondition(new Condition() {
@@ -256,7 +266,8 @@ public abstract class AbstractGemFireIntegrationTests {
} }
/* (non-Javadoc) */ /* (non-Javadoc) */
protected static int waitForProcessToStop(Process process, File directory, long duration) { protected static int waitForProcessToStop(Process process, File directory,
long duration) {
final long timeout = (System.currentTimeMillis() + duration); final long timeout = (System.currentTimeMillis() + duration);
try { try {
@@ -311,24 +322,30 @@ public abstract class AbstractGemFireIntegrationTests {
} }
/* (non-Javadoc) */ /* (non-Javadoc) */
protected void assertRegion(Region<?, ?> actualRegion, String expectedName, DataPolicy expectedDataPolicy) { protected void assertRegion(Region<?, ?> actualRegion, String expectedName,
DataPolicy expectedDataPolicy) {
assertThat(actualRegion).isNotNull(); assertThat(actualRegion).isNotNull();
assertThat(actualRegion.getName()).isEqualTo(expectedName); assertThat(actualRegion.getName()).isEqualTo(expectedName);
assertThat(actualRegion.getFullPath()).isEqualTo(GemFireUtils.toRegionPath(expectedName)); assertThat(actualRegion.getFullPath())
.isEqualTo(GemFireUtils.toRegionPath(expectedName));
assertThat(actualRegion.getAttributes()).isNotNull(); assertThat(actualRegion.getAttributes()).isNotNull();
assertThat(actualRegion.getAttributes().getDataPolicy()).isEqualTo(expectedDataPolicy); assertThat(actualRegion.getAttributes().getDataPolicy())
.isEqualTo(expectedDataPolicy);
} }
/* (non-Javadoc) */ /* (non-Javadoc) */
protected void assertIndex(Index index, String expectedExpression, String expectedFromClause) { protected void assertIndex(Index index, String expectedExpression,
String expectedFromClause) {
assertThat(index).isNotNull(); assertThat(index).isNotNull();
assertThat(index.getIndexedExpression()).isEqualTo(expectedExpression); assertThat(index.getIndexedExpression()).isEqualTo(expectedExpression);
assertThat(index.getFromClause()).isEqualTo(expectedFromClause); assertThat(index.getFromClause()).isEqualTo(expectedFromClause);
} }
/* (non-Javadoc) */ /* (non-Javadoc) */
protected void assertEntryIdleTimeout(Region<?, ?> region, ExpirationAction expectedAction, int expectedTimeout) { protected void assertEntryIdleTimeout(Region<?, ?> region,
assertEntryIdleTimeout(region.getAttributes().getEntryIdleTimeout(), expectedAction, expectedTimeout); ExpirationAction expectedAction, int expectedTimeout) {
assertEntryIdleTimeout(region.getAttributes().getEntryIdleTimeout(),
expectedAction, expectedTimeout);
} }
/* (non-Javadoc) */ /* (non-Javadoc) */
@@ -403,13 +420,14 @@ public abstract class AbstractGemFireIntegrationTests {
} }
/** /**
* The SessionEventListener class is a Spring {@link ApplicationListener} listening for Spring HTTP Session * The SessionEventListener class is a Spring {@link ApplicationListener} listening
* application events. * for Spring HTTP Session application events.
* *
* @see org.springframework.context.ApplicationListener * @see org.springframework.context.ApplicationListener
* @see org.springframework.session.events.AbstractSessionEvent * @see org.springframework.session.events.AbstractSessionEvent
*/ */
public static class SessionEventListener implements ApplicationListener<AbstractSessionEvent> { public static class SessionEventListener
implements ApplicationListener<AbstractSessionEvent> {
private volatile AbstractSessionEvent sessionEvent; private volatile AbstractSessionEvent sessionEvent;
@@ -439,7 +457,8 @@ public abstract class AbstractGemFireIntegrationTests {
} }
/** /**
* The Condition interface defines a logical condition that must be satisfied before it is safe to proceed. * The Condition interface defines a logical condition that must be satisfied before
* it is safe to proceed.
*/ */
protected interface Condition { protected interface Condition {
boolean evaluate(); boolean evaluate();

View File

@@ -69,16 +69,19 @@ import org.springframework.util.SocketUtils;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
/** /**
* The ClientServerGemFireOperationsSessionRepositoryIntegrationTests class is a test suite of test cases testing * The ClientServerGemFireOperationsSessionRepositoryIntegrationTests class is a test
* the functionality of GemFire-backed Spring Sessions using a GemFire client-server topology. * suite of test cases testing the functionality of GemFire-backed Spring Sessions using a
* GemFire client-server topology.
* *
* @author John Blum * @author John Blum
* @since 1.1.0 * @since 1.1.0
* @see org.junit.Test * @see org.junit.Test
* @see org.junit.runner.RunWith * @see org.junit.runner.RunWith
* @see org.springframework.session.data.gemfire.AbstractGemFireIntegrationTests * @see org.springframework.session.data.gemfire.AbstractGemFireIntegrationTests
* @see org.springframework.session.data.gemfire.config.annotation.web.http.EnableGemFireHttpSession * @see org.springframework.session.data.gemfire.config.annotation.web.http.
* @see org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration * EnableGemFireHttpSession
* @see org.springframework.session.data.gemfire.config.annotation.web.http.
* GemFireHttpSessionConfiguration
* @see org.springframework.test.annotation.DirtiesContext * @see org.springframework.test.annotation.DirtiesContext
* @see org.springframework.test.context.ContextConfiguration * @see org.springframework.test.context.ContextConfiguration
* @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner * @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner
@@ -89,15 +92,16 @@ import static org.assertj.core.api.Assertions.assertThat;
* @see com.gemstone.gemfire.cache.server.CacheServer * @see com.gemstone.gemfire.cache.server.CacheServer
*/ */
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = @ContextConfiguration(classes = ClientServerGemFireOperationsSessionRepositoryIntegrationTests.SpringSessionGemFireClientConfiguration.class)
ClientServerGemFireOperationsSessionRepositoryIntegrationTests.SpringSessionGemFireClientConfiguration.class)
@DirtiesContext @DirtiesContext
@WebAppConfiguration @WebAppConfiguration
public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests extends AbstractGemFireIntegrationTests { public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests
extends AbstractGemFireIntegrationTests {
private static final int MAX_INACTIVE_INTERVAL_IN_SECONDS = 1; private static final int MAX_INACTIVE_INTERVAL_IN_SECONDS = 1;
private static final DateFormat TIMESTAMP = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); private static final DateFormat TIMESTAMP = new SimpleDateFormat(
"yyyy-MM-dd-HH-mm-ss");
private static File processWorkingDirectory; private static File processWorkingDirectory;
@@ -114,21 +118,25 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests exte
final int port = SocketUtils.findAvailableTcpPort(); final int port = SocketUtils.findAvailableTcpPort();
System.err.printf("Starting GemFire Server running on [%1$s] listening on port [%2$d]%n", System.err.printf(
"Starting GemFire Server running on [%1$s] listening on port [%2$d]%n",
InetAddress.getLocalHost().getHostName(), port); InetAddress.getLocalHost().getHostName(), port);
System.setProperty("spring.session.data.gemfire.port", String.valueOf(port)); System.setProperty("spring.session.data.gemfire.port", String.valueOf(port));
String processWorkingDirectoryPathname = String.format("gemfire-client-server-tests-%1$s", String processWorkingDirectoryPathname = String
TIMESTAMP.format(new Date())); .format("gemfire-client-server-tests-%1$s", TIMESTAMP.format(new Date()));
processWorkingDirectory = createDirectory(processWorkingDirectoryPathname); processWorkingDirectory = createDirectory(processWorkingDirectoryPathname);
gemfireServer = run(SpringSessionGemFireServerConfiguration.class, processWorkingDirectory, gemfireServer = run(SpringSessionGemFireServerConfiguration.class,
processWorkingDirectory,
String.format("-Dspring.session.data.gemfire.port=%1$d", port)); String.format("-Dspring.session.data.gemfire.port=%1$d", port));
assertThat(waitForCacheServerToStart(SpringSessionGemFireServerConfiguration.SERVER_HOSTNAME, port)).isTrue(); assertThat(waitForCacheServerToStart(
SpringSessionGemFireServerConfiguration.SERVER_HOSTNAME, port)).isTrue();
System.err.printf("GemFire Server [startup time = %1$d ms]%n", System.currentTimeMillis() - t0); System.err.printf("GemFire Server [startup time = %1$d ms]%n",
System.currentTimeMillis() - t0);
} }
@AfterClass @AfterClass
@@ -139,7 +147,8 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests exte
waitForProcessToStop(gemfireServer, processWorkingDirectory)); waitForProcessToStop(gemfireServer, processWorkingDirectory));
} }
if (Boolean.valueOf(System.getProperty("spring.session.data.gemfire.fork.clean", Boolean.TRUE.toString()))) { if (Boolean.valueOf(System.getProperty("spring.session.data.gemfire.fork.clean",
Boolean.TRUE.toString()))) {
FileSystemUtils.deleteRecursively(processWorkingDirectory); FileSystemUtils.deleteRecursively(processWorkingDirectory);
} }
@@ -150,16 +159,17 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests exte
public void setup() { public void setup() {
assertThat(GemFireUtils.isClient(gemfireCache)).isTrue(); assertThat(GemFireUtils.isClient(gemfireCache)).isTrue();
Region<Object, ExpiringSession> springSessionGemFireRegion = gemfireCache.getRegion( Region<Object, ExpiringSession> springSessionGemFireRegion = gemfireCache
SPRING_SESSION_GEMFIRE_REGION_NAME); .getRegion(SPRING_SESSION_GEMFIRE_REGION_NAME);
assertThat(springSessionGemFireRegion).isNotNull(); assertThat(springSessionGemFireRegion).isNotNull();
RegionAttributes<Object, ExpiringSession> springSessionGemFireRegionAttributes = RegionAttributes<Object, ExpiringSession> springSessionGemFireRegionAttributes = springSessionGemFireRegion
springSessionGemFireRegion.getAttributes(); .getAttributes();
assertThat(springSessionGemFireRegionAttributes).isNotNull(); assertThat(springSessionGemFireRegionAttributes).isNotNull();
assertThat(springSessionGemFireRegionAttributes.getDataPolicy()).isEqualTo(DataPolicy.EMPTY); assertThat(springSessionGemFireRegionAttributes.getDataPolicy())
.isEqualTo(DataPolicy.EMPTY);
} }
@After @After
@@ -173,7 +183,8 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests exte
ExpiringSession expectedSession = save(createSession()); ExpiringSession expectedSession = save(createSession());
AbstractSessionEvent sessionEvent = this.sessionEventListener.waitForSessionEvent(500); AbstractSessionEvent sessionEvent = this.sessionEventListener
.waitForSessionEvent(500);
assertThat(sessionEvent).isInstanceOf(SessionCreatedEvent.class); assertThat(sessionEvent).isInstanceOf(SessionCreatedEvent.class);
@@ -181,9 +192,12 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests exte
assertThat(createdSession).isEqualTo(expectedSession); assertThat(createdSession).isEqualTo(expectedSession);
assertThat(createdSession.getId()).isNotNull(); assertThat(createdSession.getId()).isNotNull();
assertThat(createdSession.getCreationTime()).isGreaterThanOrEqualTo(beforeOrAtCreationTime); assertThat(createdSession.getCreationTime())
assertThat(createdSession.getLastAccessedTime()).isEqualTo(createdSession.getCreationTime()); .isGreaterThanOrEqualTo(beforeOrAtCreationTime);
assertThat(createdSession.getMaxInactiveIntervalInSeconds()).isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS); assertThat(createdSession.getLastAccessedTime())
.isEqualTo(createdSession.getCreationTime());
assertThat(createdSession.getMaxInactiveIntervalInSeconds())
.isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
this.gemfireSessionRepository.delete(expectedSession.getId()); this.gemfireSessionRepository.delete(expectedSession.getId());
} }
@@ -192,28 +206,32 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests exte
public void getExistingNonExpiredSessionBeforeAndAfterExpiration() { public void getExistingNonExpiredSessionBeforeAndAfterExpiration() {
ExpiringSession expectedSession = save(touch(createSession())); ExpiringSession expectedSession = save(touch(createSession()));
AbstractSessionEvent sessionEvent = this.sessionEventListener.waitForSessionEvent(500); AbstractSessionEvent sessionEvent = this.sessionEventListener
.waitForSessionEvent(500);
assertThat(sessionEvent).isInstanceOf(SessionCreatedEvent.class); assertThat(sessionEvent).isInstanceOf(SessionCreatedEvent.class);
assertThat(sessionEvent.<ExpiringSession>getSession()).isEqualTo(expectedSession); assertThat(sessionEvent.<ExpiringSession>getSession()).isEqualTo(expectedSession);
assertThat(this.sessionEventListener.getSessionEvent()).isNull(); assertThat(this.sessionEventListener.getSessionEvent()).isNull();
ExpiringSession savedSession = this.gemfireSessionRepository.getSession(expectedSession.getId()); ExpiringSession savedSession = this.gemfireSessionRepository
.getSession(expectedSession.getId());
assertThat(savedSession).isEqualTo(expectedSession); assertThat(savedSession).isEqualTo(expectedSession);
// NOTE for some reason or another, performing a GemFire (Client)Cache Region.get(key) // NOTE for some reason or another, performing a GemFire (Client)Cache
// Region.get(key)
// causes a Region CREATE event... o.O // causes a Region CREATE event... o.O
// calling sessionEventListener.getSessionEvent() here to clear the event // calling sessionEventListener.getSessionEvent() here to clear the event
this.sessionEventListener.getSessionEvent(); this.sessionEventListener.getSessionEvent();
sessionEvent = this.sessionEventListener.waitForSessionEvent(TimeUnit.SECONDS.toMillis( sessionEvent = this.sessionEventListener.waitForSessionEvent(
MAX_INACTIVE_INTERVAL_IN_SECONDS + 1)); TimeUnit.SECONDS.toMillis(MAX_INACTIVE_INTERVAL_IN_SECONDS + 1));
assertThat(sessionEvent).isInstanceOf(SessionExpiredEvent.class); assertThat(sessionEvent).isInstanceOf(SessionExpiredEvent.class);
assertThat(sessionEvent.getSessionId()).isEqualTo(expectedSession.getId()); assertThat(sessionEvent.getSessionId()).isEqualTo(expectedSession.getId());
ExpiringSession expiredSession = this.gemfireSessionRepository.getSession(expectedSession.getId()); ExpiringSession expiredSession = this.gemfireSessionRepository
.getSession(expectedSession.getId());
assertThat(expiredSession).isNull(); assertThat(expiredSession).isNull();
} }
@@ -222,7 +240,8 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests exte
public void deleteExistingNonExpiredSessionFiresSessionDeletedEventAndReturnsNullOnGet() { public void deleteExistingNonExpiredSessionFiresSessionDeletedEventAndReturnsNullOnGet() {
ExpiringSession expectedSession = save(touch(createSession())); ExpiringSession expectedSession = save(touch(createSession()));
AbstractSessionEvent sessionEvent = this.sessionEventListener.waitForSessionEvent(500); AbstractSessionEvent sessionEvent = this.sessionEventListener
.waitForSessionEvent(500);
assertThat(sessionEvent).isInstanceOf(SessionCreatedEvent.class); assertThat(sessionEvent).isInstanceOf(SessionCreatedEvent.class);
assertThat(sessionEvent.<ExpiringSession>getSession()).isEqualTo(expectedSession); assertThat(sessionEvent.<ExpiringSession>getSession()).isEqualTo(expectedSession);
@@ -234,13 +253,13 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests exte
assertThat(sessionEvent).isInstanceOf(SessionDeletedEvent.class); assertThat(sessionEvent).isInstanceOf(SessionDeletedEvent.class);
assertThat(sessionEvent.getSessionId()).isEqualTo(expectedSession.getId()); assertThat(sessionEvent.getSessionId()).isEqualTo(expectedSession.getId());
ExpiringSession deletedSession = this.gemfireSessionRepository.getSession(expectedSession.getId()); ExpiringSession deletedSession = this.gemfireSessionRepository
.getSession(expectedSession.getId());
assertThat(deletedSession).isNull(); assertThat(deletedSession).isNull();
} }
@EnableGemFireHttpSession(regionName = SPRING_SESSION_GEMFIRE_REGION_NAME, @EnableGemFireHttpSession(regionName = SPRING_SESSION_GEMFIRE_REGION_NAME, maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS)
maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS)
static class SpringSessionGemFireClientConfiguration { static class SpringSessionGemFireClientConfiguration {
@Bean @Bean
@@ -251,13 +270,16 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests exte
@Bean @Bean
Properties gemfireProperties() { Properties gemfireProperties() {
Properties gemfireProperties = new Properties(); Properties gemfireProperties = new Properties();
gemfireProperties.setProperty("name", ClientServerGemFireOperationsSessionRepositoryIntegrationTests.class.getName()); gemfireProperties.setProperty("name",
ClientServerGemFireOperationsSessionRepositoryIntegrationTests.class
.getName());
gemfireProperties.setProperty("log-level", GEMFIRE_LOG_LEVEL); gemfireProperties.setProperty("log-level", GEMFIRE_LOG_LEVEL);
return gemfireProperties; return gemfireProperties;
} }
@Bean(name = GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME) @Bean(name = GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME)
PoolFactoryBean gemfirePool(@Value("${spring.session.data.gemfire.port:" + DEFAULT_GEMFIRE_SERVER_PORT + "}") int port) { PoolFactoryBean gemfirePool(@Value("${spring.session.data.gemfire.port:"
+ DEFAULT_GEMFIRE_SERVER_PORT + "}") int port) {
PoolFactoryBean poolFactory = new PoolFactoryBean() { PoolFactoryBean poolFactory = new PoolFactoryBean() {
@Override @Override
protected Properties resolveGemfireProperties() { protected Properties resolveGemfireProperties() {
@@ -268,15 +290,18 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests exte
poolFactory.setName(GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME); poolFactory.setName(GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME);
poolFactory.setFreeConnectionTimeout(5000); // 5 seconds poolFactory.setFreeConnectionTimeout(5000); // 5 seconds
poolFactory.setKeepAlive(false); poolFactory.setKeepAlive(false);
poolFactory.setMaxConnections(SpringSessionGemFireServerConfiguration.MAX_CONNECTIONS); poolFactory.setMaxConnections(
SpringSessionGemFireServerConfiguration.MAX_CONNECTIONS);
poolFactory.setPingInterval(TimeUnit.SECONDS.toMillis(5)); poolFactory.setPingInterval(TimeUnit.SECONDS.toMillis(5));
poolFactory.setReadTimeout(2000); // 2 seconds poolFactory.setReadTimeout(2000); // 2 seconds
poolFactory.setRetryAttempts(2); poolFactory.setRetryAttempts(2);
poolFactory.setSubscriptionEnabled(true); poolFactory.setSubscriptionEnabled(true);
poolFactory.setThreadLocalConnections(false); poolFactory.setThreadLocalConnections(false);
poolFactory.setServerEndpoints(Collections.singletonList(new ConnectionEndpoint( poolFactory
SpringSessionGemFireServerConfiguration.SERVER_HOSTNAME, port))); .setServerEndpoints(Collections.singletonList(new ConnectionEndpoint(
SpringSessionGemFireServerConfiguration.SERVER_HOSTNAME,
port)));
return poolFactory; return poolFactory;
} }
@@ -315,8 +340,7 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests exte
} }
} }
@EnableGemFireHttpSession(regionName = SPRING_SESSION_GEMFIRE_REGION_NAME, @EnableGemFireHttpSession(regionName = SPRING_SESSION_GEMFIRE_REGION_NAME, maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS)
maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS)
static class SpringSessionGemFireServerConfiguration { static class SpringSessionGemFireServerConfiguration {
static final int MAX_CONNECTIONS = 50; static final int MAX_CONNECTIONS = 50;
@@ -331,7 +355,8 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests exte
Properties gemfireProperties() { Properties gemfireProperties() {
Properties gemfireProperties = new Properties(); Properties gemfireProperties = new Properties();
gemfireProperties.setProperty("name", SpringSessionGemFireServerConfiguration.class.getName()); gemfireProperties.setProperty("name",
SpringSessionGemFireServerConfiguration.class.getName());
gemfireProperties.setProperty("mcast-port", "0"); gemfireProperties.setProperty("mcast-port", "0");
gemfireProperties.setProperty("log-file", "server.log"); gemfireProperties.setProperty("log-file", "server.log");
gemfireProperties.setProperty("log-level", GEMFIRE_LOG_LEVEL); gemfireProperties.setProperty("log-level", GEMFIRE_LOG_LEVEL);
@@ -351,7 +376,8 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests exte
@Bean @Bean
CacheServerFactoryBean gemfireCacheServer(Cache gemfireCache, CacheServerFactoryBean gemfireCacheServer(Cache gemfireCache,
@Value("${spring.session.data.gemfire.port:" + DEFAULT_GEMFIRE_SERVER_PORT + "}") int port) { @Value("${spring.session.data.gemfire.port:" + DEFAULT_GEMFIRE_SERVER_PORT
+ "}") int port) {
CacheServerFactoryBean cacheServerFactory = new CacheServerFactoryBean(); CacheServerFactoryBean cacheServerFactory = new CacheServerFactoryBean();
@@ -366,7 +392,8 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests exte
@SuppressWarnings("resource") @SuppressWarnings("resource")
public static void main(final String[] args) throws IOException { public static void main(final String[] args) throws IOException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringSessionGemFireServerConfiguration.class); AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
SpringSessionGemFireServerConfiguration.class);
context.registerShutdownHook(); context.registerShutdownHook();
writeProcessControlFile(WORKING_DIRECTORY); writeProcessControlFile(WORKING_DIRECTORY);
} }

View File

@@ -55,8 +55,9 @@ import org.springframework.util.ObjectUtils;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
/** /**
* The GemFireOperationsSessionRepositoryIntegrationTests class is a test suite of test cases testing * The GemFireOperationsSessionRepositoryIntegrationTests class is a test suite of test
* the findByPrincipalName query method on the GemFireOpeationsSessionRepository class. * cases testing the findByPrincipalName query method on the
* GemFireOpeationsSessionRepository class.
* *
* @author John Blum * @author John Blum
* @since 1.1.0 * @since 1.1.0
@@ -75,7 +76,8 @@ import static org.assertj.core.api.Assertions.assertThat;
@ContextConfiguration @ContextConfiguration
@DirtiesContext @DirtiesContext
@WebAppConfiguration @WebAppConfiguration
public class GemFireOperationsSessionRepositoryIntegrationTests extends AbstractGemFireIntegrationTests { public class GemFireOperationsSessionRepositoryIntegrationTests
extends AbstractGemFireIntegrationTests {
private static final int MAX_INACTIVE_INTERVAL_IN_SECONDS = 300; private static final int MAX_INACTIVE_INTERVAL_IN_SECONDS = 300;
@@ -90,48 +92,63 @@ public class GemFireOperationsSessionRepositoryIntegrationTests extends Abstract
@Before @Before
public void setup() { public void setup() {
this.context = SecurityContextHolder.createEmptyContext(); this.context = SecurityContextHolder.createEmptyContext();
this.context.setAuthentication(new UsernamePasswordAuthenticationToken("username-" + UUID.randomUUID(), "na", AuthorityUtils.createAuthorityList("ROLE_USER"))); this.context.setAuthentication(
new UsernamePasswordAuthenticationToken("username-" + UUID.randomUUID(),
"na", AuthorityUtils.createAuthorityList("ROLE_USER")));
this.changedContext = SecurityContextHolder.createEmptyContext(); this.changedContext = SecurityContextHolder.createEmptyContext();
this.changedContext.setAuthentication(new UsernamePasswordAuthenticationToken("changedContext-" + UUID.randomUUID(), "na", AuthorityUtils.createAuthorityList("ROLE_USER"))); this.changedContext.setAuthentication(new UsernamePasswordAuthenticationToken(
"changedContext-" + UUID.randomUUID(), "na",
AuthorityUtils.createAuthorityList("ROLE_USER")));
assertThat(this.gemfireCache).isNotNull(); assertThat(this.gemfireCache).isNotNull();
assertThat(this.gemfireSessionRepository).isNotNull(); assertThat(this.gemfireSessionRepository).isNotNull();
assertThat(this.gemfireSessionRepository.getMaxInactiveIntervalInSeconds()).isEqualTo( assertThat(this.gemfireSessionRepository.getMaxInactiveIntervalInSeconds())
.isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
Region<Object, ExpiringSession> sessionRegion = this.gemfireCache
.getRegion(SPRING_SESSION_GEMFIRE_REGION_NAME);
assertRegion(sessionRegion, SPRING_SESSION_GEMFIRE_REGION_NAME,
DataPolicy.PARTITION);
assertEntryIdleTimeout(sessionRegion, ExpirationAction.INVALIDATE,
MAX_INACTIVE_INTERVAL_IN_SECONDS); MAX_INACTIVE_INTERVAL_IN_SECONDS);
Region<Object, ExpiringSession> sessionRegion = this.gemfireCache.getRegion(SPRING_SESSION_GEMFIRE_REGION_NAME);
assertRegion(sessionRegion, SPRING_SESSION_GEMFIRE_REGION_NAME, DataPolicy.PARTITION);
assertEntryIdleTimeout(sessionRegion, ExpirationAction.INVALIDATE, MAX_INACTIVE_INTERVAL_IN_SECONDS);
} }
protected Map<String, ExpiringSession> doFindByIndexNameAndIndexValue(String indexName, String indexValue) { protected Map<String, ExpiringSession> doFindByIndexNameAndIndexValue(
return this.gemfireSessionRepository.findByIndexNameAndIndexValue(indexName, indexValue); String indexName, String indexValue) {
return this.gemfireSessionRepository.findByIndexNameAndIndexValue(indexName,
indexValue);
} }
protected Map<String, ExpiringSession> doFindByPrincipalName(String principalName) { protected Map<String, ExpiringSession> doFindByPrincipalName(String principalName) {
return doFindByIndexNameAndIndexValue(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, principalName); return doFindByIndexNameAndIndexValue(
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME,
principalName);
} }
@SuppressWarnings({ "unchecked" }) @SuppressWarnings({ "unchecked" })
protected Map<String, ExpiringSession> doFindByPrincipalName(String regionName, String principalName) { protected Map<String, ExpiringSession> doFindByPrincipalName(String regionName,
String principalName) {
try { try {
Region<String, ExpiringSession> region = this.gemfireCache.getRegion(regionName); Region<String, ExpiringSession> region = this.gemfireCache
.getRegion(regionName);
assertThat(region).isNotNull(); assertThat(region).isNotNull();
QueryService queryService = region.getRegionService().getQueryService(); QueryService queryService = region.getRegionService().getQueryService();
String queryString = String.format(GemFireOperationsSessionRepository.FIND_SESSIONS_BY_PRINCIPAL_NAME_QUERY, String queryString = String.format(
GemFireOperationsSessionRepository.FIND_SESSIONS_BY_PRINCIPAL_NAME_QUERY,
region.getFullPath()); region.getFullPath());
Query query = queryService.newQuery(queryString); Query query = queryService.newQuery(queryString);
SelectResults<ExpiringSession> results = (SelectResults<ExpiringSession>) query.execute( SelectResults<ExpiringSession> results = (SelectResults<ExpiringSession>) query
new Object[] { principalName }); .execute(new Object[] { principalName });
Map<String, ExpiringSession> sessions = new HashMap<String, ExpiringSession>(results.size()); Map<String, ExpiringSession> sessions = new HashMap<String, ExpiringSession>(
results.size());
for (ExpiringSession session : results.asList()) { for (ExpiringSession session : results.asList()) {
sessions.put(session.getId(), session); sessions.put(session.getId(), session);
@@ -149,17 +166,22 @@ public class GemFireOperationsSessionRepositoryIntegrationTests extends Abstract
return true; return true;
} }
protected ExpiringSession setAttribute(ExpiringSession session, String attributeName, Object attributeValue) { protected ExpiringSession setAttribute(ExpiringSession session, String attributeName,
Object attributeValue) {
session.setAttribute(attributeName, attributeValue); session.setAttribute(attributeName, attributeValue);
return session; return session;
} }
@Test @Test
public void findSessionsByIndexedSessionAttributeNameValues() { public void findSessionsByIndexedSessionAttributeNameValues() {
ExpiringSession johnBlumSession = save(touch(setAttribute(createSession("johnBlum"), "vip", "yes"))); ExpiringSession johnBlumSession = save(
ExpiringSession robWinchSession = save(touch(setAttribute(createSession("robWinch"), "vip", "yes"))); touch(setAttribute(createSession("johnBlum"), "vip", "yes")));
ExpiringSession jonDoeSession = save(touch(setAttribute(createSession("jonDoe"), "vip", "no"))); ExpiringSession robWinchSession = save(
ExpiringSession pieDoeSession = save(touch(setAttribute(createSession("pieDoe"), "viper", "true"))); touch(setAttribute(createSession("robWinch"), "vip", "yes")));
ExpiringSession jonDoeSession = save(
touch(setAttribute(createSession("jonDoe"), "vip", "no")));
ExpiringSession pieDoeSession = save(
touch(setAttribute(createSession("pieDoe"), "viper", "true")));
ExpiringSession sourDoeSession = save(touch(createSession("sourDoe"))); ExpiringSession sourDoeSession = save(touch(createSession("sourDoe")));
assertThat(get(johnBlumSession.getId())).isEqualTo(johnBlumSession); assertThat(get(johnBlumSession.getId())).isEqualTo(johnBlumSession);
@@ -173,7 +195,8 @@ public class GemFireOperationsSessionRepositoryIntegrationTests extends Abstract
assertThat(get(sourDoeSession.getId())).isEqualTo(sourDoeSession); assertThat(get(sourDoeSession.getId())).isEqualTo(sourDoeSession);
assertThat(sourDoeSession.getAttributeNames().contains("vip")).isFalse(); assertThat(sourDoeSession.getAttributeNames().contains("vip")).isFalse();
Map<String, ExpiringSession> vipSessions = doFindByIndexNameAndIndexValue("vip", "yes"); Map<String, ExpiringSession> vipSessions = doFindByIndexNameAndIndexValue("vip",
"yes");
assertThat(vipSessions).isNotNull(); assertThat(vipSessions).isNotNull();
assertThat(vipSessions.size()).isEqualTo(2); assertThat(vipSessions.size()).isEqualTo(2);
@@ -183,7 +206,8 @@ public class GemFireOperationsSessionRepositoryIntegrationTests extends Abstract
assertThat(vipSessions.containsKey(pieDoeSession.getId())); assertThat(vipSessions.containsKey(pieDoeSession.getId()));
assertThat(vipSessions.containsKey(sourDoeSession.getId())); assertThat(vipSessions.containsKey(sourDoeSession.getId()));
Map<String, ExpiringSession> nonVipSessions = doFindByIndexNameAndIndexValue("vip", "no"); Map<String, ExpiringSession> nonVipSessions = doFindByIndexNameAndIndexValue(
"vip", "no");
assertThat(nonVipSessions).isNotNull(); assertThat(nonVipSessions).isNotNull();
assertThat(nonVipSessions.size()).isEqualTo(1); assertThat(nonVipSessions.size()).isEqualTo(1);
@@ -193,7 +217,8 @@ public class GemFireOperationsSessionRepositoryIntegrationTests extends Abstract
assertThat(nonVipSessions.containsKey(pieDoeSession.getId())); assertThat(nonVipSessions.containsKey(pieDoeSession.getId()));
assertThat(nonVipSessions.containsKey(sourDoeSession.getId())); assertThat(nonVipSessions.containsKey(sourDoeSession.getId()));
Map<String, ExpiringSession> noSessions = doFindByIndexNameAndIndexValue("nonExistingAttribute", "test"); Map<String, ExpiringSession> noSessions = doFindByIndexNameAndIndexValue(
"nonExistingAttribute", "test");
assertThat(noSessions).isNotNull(); assertThat(noSessions).isNotNull();
assertThat(noSessions.isEmpty()).isTrue(); assertThat(noSessions.isEmpty()).isTrue();
@@ -241,7 +266,8 @@ public class GemFireOperationsSessionRepositoryIntegrationTests extends Abstract
save(toSave); save(toSave);
Map<String, ExpiringSession> findByPrincipalName = doFindByPrincipalName(getSecurityName()); Map<String, ExpiringSession> findByPrincipalName = doFindByPrincipalName(
getSecurityName());
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
} }
@@ -255,7 +281,8 @@ public class GemFireOperationsSessionRepositoryIntegrationTests extends Abstract
toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.changedContext); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.changedContext);
save(toSave); save(toSave);
Map<String, ExpiringSession> findByPrincipalName = doFindByPrincipalName(getSecurityName()); Map<String, ExpiringSession> findByPrincipalName = doFindByPrincipalName(
getSecurityName());
assertThat(findByPrincipalName).isEmpty(); assertThat(findByPrincipalName).isEmpty();
findByPrincipalName = doFindByPrincipalName(getChangedSecurityName()); findByPrincipalName = doFindByPrincipalName(getChangedSecurityName());
@@ -264,7 +291,8 @@ public class GemFireOperationsSessionRepositoryIntegrationTests extends Abstract
@Test @Test
public void findsNoSessionsByNonExistingPrincipal() { public void findsNoSessionsByNonExistingPrincipal() {
Map<String, ExpiringSession> nonExistingPrincipalSessions = doFindByPrincipalName("nonExistingPrincipalName"); Map<String, ExpiringSession> nonExistingPrincipalSessions = doFindByPrincipalName(
"nonExistingPrincipalName");
assertThat(nonExistingPrincipalSessions).isNotNull(); assertThat(nonExistingPrincipalSessions).isNotNull();
assertThat(nonExistingPrincipalSessions.isEmpty()).isTrue(); assertThat(nonExistingPrincipalSessions.isEmpty()).isTrue();
@@ -274,10 +302,12 @@ public class GemFireOperationsSessionRepositoryIntegrationTests extends Abstract
public void findsNoSessionsAfterPrincipalIsRemoved() { public void findsNoSessionsAfterPrincipalIsRemoved() {
String username = "doesNotFindAfterPrincipalRemoved"; String username = "doesNotFindAfterPrincipalRemoved";
ExpiringSession session = save(touch(createSession(username))); ExpiringSession session = save(touch(createSession(username)));
session.setAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, null); session.setAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME,
null);
save(session); save(session);
Map<String, ExpiringSession> nonExistingPrincipalSessions = doFindByPrincipalName(username); Map<String, ExpiringSession> nonExistingPrincipalSessions = doFindByPrincipalName(
username);
assertThat(nonExistingPrincipalSessions).isNotNull(); assertThat(nonExistingPrincipalSessions).isNotNull();
assertThat(nonExistingPrincipalSessions.isEmpty()).isTrue(); assertThat(nonExistingPrincipalSessions.isEmpty()).isTrue();
@@ -287,12 +317,14 @@ public class GemFireOperationsSessionRepositoryIntegrationTests extends Abstract
public void saveAndReadSessionWithAttributes() { public void saveAndReadSessionWithAttributes() {
ExpiringSession expectedSession = this.gemfireSessionRepository.createSession(); ExpiringSession expectedSession = this.gemfireSessionRepository.createSession();
assertThat(expectedSession).isInstanceOf(AbstractGemFireOperationsSessionRepository.GemFireSession.class); assertThat(expectedSession).isInstanceOf(
AbstractGemFireOperationsSessionRepository.GemFireSession.class);
((AbstractGemFireOperationsSessionRepository.GemFireSession) expectedSession).setPrincipalName("jblum"); ((AbstractGemFireOperationsSessionRepository.GemFireSession) expectedSession)
.setPrincipalName("jblum");
List<String> expectedAttributeNames = Arrays.asList( List<String> expectedAttributeNames = Arrays.asList("booleanAttribute",
"booleanAttribute", "numericAttribute", "stringAttribute", "personAttribute"); "numericAttribute", "stringAttribute", "personAttribute");
Person jonDoe = new Person("Jon", "Doe"); Person jonDoe = new Person("Jon", "Doe");
@@ -303,21 +335,32 @@ public class GemFireOperationsSessionRepositoryIntegrationTests extends Abstract
this.gemfireSessionRepository.save(touch(expectedSession)); this.gemfireSessionRepository.save(touch(expectedSession));
ExpiringSession savedSession = this.gemfireSessionRepository.getSession(expectedSession.getId()); ExpiringSession savedSession = this.gemfireSessionRepository
.getSession(expectedSession.getId());
assertThat(savedSession).isEqualTo(expectedSession); assertThat(savedSession).isEqualTo(expectedSession);
assertThat(savedSession).isInstanceOf(AbstractGemFireOperationsSessionRepository.GemFireSession.class); assertThat(savedSession).isInstanceOf(
assertThat(((AbstractGemFireOperationsSessionRepository.GemFireSession) savedSession).getPrincipalName()).isEqualTo("jblum"); AbstractGemFireOperationsSessionRepository.GemFireSession.class);
assertThat(
((AbstractGemFireOperationsSessionRepository.GemFireSession) savedSession)
.getPrincipalName()).isEqualTo("jblum");
assertThat(savedSession.getAttributeNames().containsAll(expectedAttributeNames)).as( assertThat(savedSession.getAttributeNames().containsAll(expectedAttributeNames))
String.format("Expected (%1$s); but was (%2$s)", expectedAttributeNames, savedSession.getAttributeNames())) .as(String.format("Expected (%1$s); but was (%2$s)",
expectedAttributeNames, savedSession.getAttributeNames()))
.isTrue(); .isTrue();
assertThat(Boolean.valueOf(String.valueOf(savedSession.getAttribute(expectedAttributeNames.get(0))))).isTrue(); assertThat(Boolean.valueOf(
assertThat(Double.valueOf(String.valueOf(savedSession.getAttribute(expectedAttributeNames.get(1))))) String.valueOf(savedSession.getAttribute(expectedAttributeNames.get(0)))))
.isTrue();
assertThat(Double.valueOf(
String.valueOf(savedSession.getAttribute(expectedAttributeNames.get(1)))))
.isEqualTo(Math.PI); .isEqualTo(Math.PI);
assertThat(String.valueOf(savedSession.getAttribute(expectedAttributeNames.get(2)))).isEqualTo("test"); assertThat(
assertThat(savedSession.getAttribute(expectedAttributeNames.get(3))).isEqualTo(jonDoe); String.valueOf(savedSession.getAttribute(expectedAttributeNames.get(2))))
.isEqualTo("test");
assertThat(savedSession.getAttribute(expectedAttributeNames.get(3)))
.isEqualTo(jonDoe);
} }
private String getSecurityName() { private String getSecurityName() {
@@ -328,15 +371,15 @@ public class GemFireOperationsSessionRepositoryIntegrationTests extends Abstract
return this.changedContext.getAuthentication().getName(); return this.changedContext.getAuthentication().getName();
} }
@EnableGemFireHttpSession(regionName = SPRING_SESSION_GEMFIRE_REGION_NAME, @EnableGemFireHttpSession(regionName = SPRING_SESSION_GEMFIRE_REGION_NAME, maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS)
maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS)
static class SpringSessionGemFireConfiguration { static class SpringSessionGemFireConfiguration {
@Bean @Bean
Properties gemfireProperties() { Properties gemfireProperties() {
Properties gemfireProperties = new Properties(); Properties gemfireProperties = new Properties();
gemfireProperties.setProperty("name", GemFireOperationsSessionRepositoryIntegrationTests.class.getName()); gemfireProperties.setProperty("name",
GemFireOperationsSessionRepositoryIntegrationTests.class.getName());
gemfireProperties.setProperty("mcast-port", "0"); gemfireProperties.setProperty("mcast-port", "0");
gemfireProperties.setProperty("log-level", GEMFIRE_LOG_LEVEL); gemfireProperties.setProperty("log-level", GEMFIRE_LOG_LEVEL);
@@ -370,7 +413,8 @@ public class GemFireOperationsSessionRepositoryIntegrationTests extends Abstract
} }
private String validate(String value) { private String validate(String value) {
Assert.hasText(value, String.format("The String value (%1$s) must be specified!", value)); Assert.hasText(value,
String.format("The String value (%1$s) must be specified!", value));
return value; return value;
} }
@@ -399,7 +443,8 @@ public class GemFireOperationsSessionRepositoryIntegrationTests extends Abstract
@SuppressWarnings("all") @SuppressWarnings("all")
public int compareTo(final Person person) { public int compareTo(final Person person) {
int compareValue = getLastName().compareTo(person.getLastName()); int compareValue = getLastName().compareTo(person.getLastName());
return (compareValue != 0 ? compareValue : getFirstName().compareTo(person.getFirstName())); return (compareValue != 0 ? compareValue
: getFirstName().compareTo(person.getFirstName()));
} }
@Override @Override

View File

@@ -47,8 +47,9 @@ import org.springframework.test.context.web.WebAppConfiguration;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
/** /**
* The EnableGemFireHttpSessionEventsIntegrationTests class is a test suite of test cases testing the Session Event * The EnableGemFireHttpSessionEventsIntegrationTests class is a test suite of test cases
* functionality and behavior of the GemFireOperationsSessionRepository and GemFire's configuration. * testing the Session Event functionality and behavior of the
* GemFireOperationsSessionRepository and GemFire's configuration.
* *
* @author John Blum * @author John Blum
* @since 1.1.0 * @since 1.1.0
@@ -70,7 +71,8 @@ import static org.assertj.core.api.Assertions.assertThat;
@ContextConfiguration @ContextConfiguration
@DirtiesContext @DirtiesContext
@WebAppConfiguration @WebAppConfiguration
public class EnableGemFireHttpSessionEventsIntegrationTests extends AbstractGemFireIntegrationTests { public class EnableGemFireHttpSessionEventsIntegrationTests
extends AbstractGemFireIntegrationTests {
private static final int MAX_INACTIVE_INTERVAL_IN_SECONDS = 1; private static final int MAX_INACTIVE_INTERVAL_IN_SECONDS = 1;
@@ -84,14 +86,17 @@ public class EnableGemFireHttpSessionEventsIntegrationTests extends AbstractGemF
public void setup() { public void setup() {
assertThat(GemFireUtils.isPeer(this.gemfireCache)).isTrue(); assertThat(GemFireUtils.isPeer(this.gemfireCache)).isTrue();
assertThat(this.gemfireSessionRepository).isNotNull(); assertThat(this.gemfireSessionRepository).isNotNull();
assertThat(this.gemfireSessionRepository.getMaxInactiveIntervalInSeconds()).isEqualTo( assertThat(this.gemfireSessionRepository.getMaxInactiveIntervalInSeconds())
MAX_INACTIVE_INTERVAL_IN_SECONDS); .isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
assertThat(this.sessionEventListener).isNotNull(); assertThat(this.sessionEventListener).isNotNull();
Region<Object, ExpiringSession> sessionRegion = this.gemfireCache.getRegion(SPRING_SESSION_GEMFIRE_REGION_NAME); Region<Object, ExpiringSession> sessionRegion = this.gemfireCache
.getRegion(SPRING_SESSION_GEMFIRE_REGION_NAME);
assertRegion(sessionRegion, SPRING_SESSION_GEMFIRE_REGION_NAME, DataPolicy.REPLICATE); assertRegion(sessionRegion, SPRING_SESSION_GEMFIRE_REGION_NAME,
assertEntryIdleTimeout(sessionRegion, ExpirationAction.INVALIDATE, MAX_INACTIVE_INTERVAL_IN_SECONDS); DataPolicy.REPLICATE);
assertEntryIdleTimeout(sessionRegion, ExpirationAction.INVALIDATE,
MAX_INACTIVE_INTERVAL_IN_SECONDS);
} }
@After @After
@@ -113,9 +118,12 @@ public class EnableGemFireHttpSessionEventsIntegrationTests extends AbstractGemF
assertThat(createdSession).isEqualTo(expectedSession); assertThat(createdSession).isEqualTo(expectedSession);
assertThat(createdSession.getId()).isNotNull(); assertThat(createdSession.getId()).isNotNull();
assertThat(createdSession.getCreationTime()).isGreaterThanOrEqualTo(beforeOrAtCreationTime); assertThat(createdSession.getCreationTime())
assertThat(createdSession.getLastAccessedTime()).isEqualTo(createdSession.getCreationTime()); .isGreaterThanOrEqualTo(beforeOrAtCreationTime);
assertThat(createdSession.getMaxInactiveIntervalInSeconds()).isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS); assertThat(createdSession.getLastAccessedTime())
.isEqualTo(createdSession.getCreationTime());
assertThat(createdSession.getMaxInactiveIntervalInSeconds())
.isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
assertThat(createdSession.isExpired()).isFalse(); assertThat(createdSession.isExpired()).isFalse();
} }
@@ -126,7 +134,8 @@ public class EnableGemFireHttpSessionEventsIntegrationTests extends AbstractGemF
assertThat(expectedSession.isExpired()).isFalse(); assertThat(expectedSession.isExpired()).isFalse();
// NOTE though unlikely, a possible race condition exists between save and get... // NOTE though unlikely, a possible race condition exists between save and get...
ExpiringSession savedSession = this.gemfireSessionRepository.getSession(expectedSession.getId()); ExpiringSession savedSession = this.gemfireSessionRepository
.getSession(expectedSession.getId());
assertThat(savedSession).isEqualTo(expectedSession); assertThat(savedSession).isEqualTo(expectedSession);
} }
@@ -143,18 +152,21 @@ public class EnableGemFireHttpSessionEventsIntegrationTests extends AbstractGemF
assertThat(createdSession).isEqualTo(expectedSession); assertThat(createdSession).isEqualTo(expectedSession);
assertThat(createdSession.isExpired()).isTrue(); assertThat(createdSession.isExpired()).isTrue();
assertThat(this.gemfireSessionRepository.getSession(createdSession.getId())).isNull(); assertThat(this.gemfireSessionRepository.getSession(createdSession.getId()))
.isNull();
} }
@Test @Test
public void getNonExistingSession() { public void getNonExistingSession() {
assertThat(this.gemfireSessionRepository.getSession(UUID.randomUUID().toString())).isNull(); assertThat(this.gemfireSessionRepository.getSession(UUID.randomUUID().toString()))
.isNull();
} }
@Test @Test
public void deleteExistingNonExpiredSession() { public void deleteExistingNonExpiredSession() {
ExpiringSession expectedSession = save(touch(createSession())); ExpiringSession expectedSession = save(touch(createSession()));
ExpiringSession savedSession = this.gemfireSessionRepository.getSession(expectedSession.getId()); ExpiringSession savedSession = this.gemfireSessionRepository
.getSession(expectedSession.getId());
assertThat(savedSession).isEqualTo(expectedSession); assertThat(savedSession).isEqualTo(expectedSession);
assertThat(savedSession.isExpired()).isFalse(); assertThat(savedSession.isExpired()).isFalse();
@@ -169,7 +181,8 @@ public class EnableGemFireHttpSessionEventsIntegrationTests extends AbstractGemF
ExpiringSession deletedSession = sessionEvent.getSession(); ExpiringSession deletedSession = sessionEvent.getSession();
assertThat(deletedSession).isEqualTo(savedSession); assertThat(deletedSession).isEqualTo(savedSession);
assertThat(this.gemfireSessionRepository.getSession(deletedSession.getId())).isNull(); assertThat(this.gemfireSessionRepository.getSession(deletedSession.getId()))
.isNull();
} }
@Test @Test
@@ -184,8 +197,9 @@ public class EnableGemFireHttpSessionEventsIntegrationTests extends AbstractGemF
assertThat(createdSession).isEqualTo(expectedSession); assertThat(createdSession).isEqualTo(expectedSession);
sessionEvent = this.sessionEventListener.waitForSessionEvent(TimeUnit.SECONDS.toMillis( sessionEvent = this.sessionEventListener.waitForSessionEvent(TimeUnit.SECONDS
this.gemfireSessionRepository.getMaxInactiveIntervalInSeconds() + 1)); .toMillis(this.gemfireSessionRepository.getMaxInactiveIntervalInSeconds()
+ 1));
assertThat(sessionEvent).isInstanceOf(SessionExpiredEvent.class); assertThat(sessionEvent).isInstanceOf(SessionExpiredEvent.class);
@@ -201,7 +215,8 @@ public class EnableGemFireHttpSessionEventsIntegrationTests extends AbstractGemF
assertThat(sessionEvent).isInstanceOf(SessionDeletedEvent.class); assertThat(sessionEvent).isInstanceOf(SessionDeletedEvent.class);
assertThat(sessionEvent.getSession()).isNull(); assertThat(sessionEvent.getSession()).isNull();
assertThat(sessionEvent.getSessionId()).isEqualTo(expiredSession.getId()); assertThat(sessionEvent.getSessionId()).isEqualTo(expiredSession.getId());
assertThat(this.gemfireSessionRepository.getSession(sessionEvent.getSessionId())).isNull(); assertThat(this.gemfireSessionRepository.getSession(sessionEvent.getSessionId()))
.isNull();
} }
@Test @Test
@@ -219,16 +234,15 @@ public class EnableGemFireHttpSessionEventsIntegrationTests extends AbstractGemF
assertThat(sessionEvent.getSessionId()).isEqualTo(expectedSessionId); assertThat(sessionEvent.getSessionId()).isEqualTo(expectedSessionId);
} }
@EnableGemFireHttpSession(regionName = SPRING_SESSION_GEMFIRE_REGION_NAME, @EnableGemFireHttpSession(regionName = SPRING_SESSION_GEMFIRE_REGION_NAME, maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS, serverRegionShortcut = RegionShortcut.REPLICATE)
maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS,
serverRegionShortcut = RegionShortcut.REPLICATE)
static class SpringSessionGemFireConfiguration { static class SpringSessionGemFireConfiguration {
@Bean @Bean
Properties gemfireProperties() { Properties gemfireProperties() {
Properties gemfireProperties = new Properties(); Properties gemfireProperties = new Properties();
gemfireProperties.setProperty("name", EnableGemFireHttpSessionEventsIntegrationTests.class.getName()); gemfireProperties.setProperty("name",
EnableGemFireHttpSessionEventsIntegrationTests.class.getName());
gemfireProperties.setProperty("mcast-port", "0"); gemfireProperties.setProperty("mcast-port", "0");
gemfireProperties.setProperty("log-level", GEMFIRE_LOG_LEVEL); gemfireProperties.setProperty("log-level", GEMFIRE_LOG_LEVEL);

View File

@@ -42,8 +42,9 @@ import org.springframework.test.context.web.WebAppConfiguration;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
/** /**
* The GemFireHttpSessionJavaConfigurationTests class is a test suite of test cases testing the configuration of * The GemFireHttpSessionJavaConfigurationTests class is a test suite of test cases
* Spring Session backed by GemFire using Java-based configuration meta-data. * testing the configuration of Spring Session backed by GemFire using Java-based
* configuration meta-data.
* *
* @author John Blum * @author John Blum
* @since 1.1.0 * @since 1.1.0
@@ -61,12 +62,14 @@ import static org.assertj.core.api.Assertions.assertThat;
@ContextConfiguration @ContextConfiguration
@DirtiesContext @DirtiesContext
@WebAppConfiguration @WebAppConfiguration
public class GemFireHttpSessionJavaConfigurationTests extends AbstractGemFireIntegrationTests { public class GemFireHttpSessionJavaConfigurationTests
extends AbstractGemFireIntegrationTests {
@Autowired @Autowired
private Cache gemfireCache; private Cache gemfireCache;
protected <K, V> Region<K, V> assertCacheAndRegion(Cache gemfireCache, String regionName, DataPolicy dataPolicy) { protected <K, V> Region<K, V> assertCacheAndRegion(Cache gemfireCache,
String regionName, DataPolicy dataPolicy) {
assertThat(GemFireUtils.isPeer(gemfireCache)).isTrue(); assertThat(GemFireUtils.isPeer(gemfireCache)).isTrue();
Region<K, V> region = gemfireCache.getRegion(regionName); Region<K, V> region = gemfireCache.getRegion(regionName);
@@ -78,16 +81,16 @@ public class GemFireHttpSessionJavaConfigurationTests extends AbstractGemFireInt
@Test @Test
public void gemfireCacheConfigurationIsValid() { public void gemfireCacheConfigurationIsValid() {
Region<Object, ExpiringSession> example = assertCacheAndRegion(this.gemfireCache, "JavaExample", Region<Object, ExpiringSession> example = assertCacheAndRegion(this.gemfireCache,
DataPolicy.REPLICATE); "JavaExample", DataPolicy.REPLICATE);
assertEntryIdleTimeout(example, ExpirationAction.INVALIDATE, 900); assertEntryIdleTimeout(example, ExpirationAction.INVALIDATE, 900);
} }
@Test @Test
public void verifyGemFireExampleCacheRegionPrincipalNameIndexWasCreatedSuccessfully() { public void verifyGemFireExampleCacheRegionPrincipalNameIndexWasCreatedSuccessfully() {
Region<Object, ExpiringSession> example = assertCacheAndRegion(this.gemfireCache, "JavaExample", Region<Object, ExpiringSession> example = assertCacheAndRegion(this.gemfireCache,
DataPolicy.REPLICATE); "JavaExample", DataPolicy.REPLICATE);
QueryService queryService = example.getRegionService().getQueryService(); QueryService queryService = example.getRegionService().getQueryService();
@@ -100,26 +103,27 @@ public class GemFireHttpSessionJavaConfigurationTests extends AbstractGemFireInt
@Test @Test
public void verifyGemFireExampleCacheRegionSessionAttributesIndexWasNotCreated() { public void verifyGemFireExampleCacheRegionSessionAttributesIndexWasNotCreated() {
Region<Object, ExpiringSession> example = assertCacheAndRegion(this.gemfireCache, "JavaExample", Region<Object, ExpiringSession> example = assertCacheAndRegion(this.gemfireCache,
DataPolicy.REPLICATE); "JavaExample", DataPolicy.REPLICATE);
QueryService queryService = example.getRegionService().getQueryService(); QueryService queryService = example.getRegionService().getQueryService();
assertThat(queryService).isNotNull(); assertThat(queryService).isNotNull();
Index sessionAttributesIndex = queryService.getIndex(example, "sessionAttributesIndex"); Index sessionAttributesIndex = queryService.getIndex(example,
"sessionAttributesIndex");
assertThat(sessionAttributesIndex).isNull(); assertThat(sessionAttributesIndex).isNull();
} }
@EnableGemFireHttpSession(indexableSessionAttributes = {}, maxInactiveIntervalInSeconds = 900, @EnableGemFireHttpSession(indexableSessionAttributes = {}, maxInactiveIntervalInSeconds = 900, regionName = "JavaExample", serverRegionShortcut = RegionShortcut.REPLICATE)
regionName = "JavaExample", serverRegionShortcut = RegionShortcut.REPLICATE)
public static class GemFireConfiguration { public static class GemFireConfiguration {
@Bean @Bean
Properties gemfireProperties() { Properties gemfireProperties() {
Properties gemfireProperties = new Properties(); Properties gemfireProperties = new Properties();
gemfireProperties.setProperty("name", GemFireHttpSessionJavaConfigurationTests.class.getName()); gemfireProperties.setProperty("name",
GemFireHttpSessionJavaConfigurationTests.class.getName());
gemfireProperties.setProperty("mcast-port", "0"); gemfireProperties.setProperty("mcast-port", "0");
gemfireProperties.setProperty("log-level", "warning"); gemfireProperties.setProperty("log-level", "warning");
return gemfireProperties; return gemfireProperties;

View File

@@ -37,8 +37,9 @@ import org.springframework.test.context.web.WebAppConfiguration;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
/** /**
* The GemFireHttpSessionXmlConfigurationTests class is a test suite of test cases testing the configuration of * The GemFireHttpSessionXmlConfigurationTests class is a test suite of test cases testing
* Spring Session backed by GemFire using XML configuration meta-data. * the configuration of Spring Session backed by GemFire using XML configuration
* meta-data.
* *
* @author John Blum * @author John Blum
* @since 1.1.0 * @since 1.1.0
@@ -56,12 +57,14 @@ import static org.assertj.core.api.Assertions.assertThat;
@ContextConfiguration @ContextConfiguration
@DirtiesContext @DirtiesContext
@WebAppConfiguration @WebAppConfiguration
public class GemFireHttpSessionXmlConfigurationTests extends AbstractGemFireIntegrationTests { public class GemFireHttpSessionXmlConfigurationTests
extends AbstractGemFireIntegrationTests {
@Autowired @Autowired
private Cache gemfireCache; private Cache gemfireCache;
protected <K, V> Region<K, V> assertCacheAndRegion(Cache gemfireCache, String regionName, DataPolicy dataPolicy) { protected <K, V> Region<K, V> assertCacheAndRegion(Cache gemfireCache,
String regionName, DataPolicy dataPolicy) {
assertThat(GemFireUtils.isPeer(gemfireCache)).isTrue(); assertThat(GemFireUtils.isPeer(gemfireCache)).isTrue();
Region<K, V> region = gemfireCache.getRegion(regionName); Region<K, V> region = gemfireCache.getRegion(regionName);
@@ -73,14 +76,16 @@ public class GemFireHttpSessionXmlConfigurationTests extends AbstractGemFireInte
@Test @Test
public void gemfireCacheConfigurationIsValid() { public void gemfireCacheConfigurationIsValid() {
Region<Object, ExpiringSession> example = assertCacheAndRegion(this.gemfireCache, "XmlExample", DataPolicy.NORMAL); Region<Object, ExpiringSession> example = assertCacheAndRegion(this.gemfireCache,
"XmlExample", DataPolicy.NORMAL);
assertEntryIdleTimeout(example, ExpirationAction.INVALIDATE, 3600); assertEntryIdleTimeout(example, ExpirationAction.INVALIDATE, 3600);
} }
@Test @Test
public void verifyGemFireExampleCacheRegionPrincipalNameIndexWasCreatedSuccessfully() { public void verifyGemFireExampleCacheRegionPrincipalNameIndexWasCreatedSuccessfully() {
Region<Object, ExpiringSession> example = assertCacheAndRegion(this.gemfireCache, "XmlExample", DataPolicy.NORMAL); Region<Object, ExpiringSession> example = assertCacheAndRegion(this.gemfireCache,
"XmlExample", DataPolicy.NORMAL);
QueryService queryService = example.getRegionService().getQueryService(); QueryService queryService = example.getRegionService().getQueryService();
@@ -93,13 +98,15 @@ public class GemFireHttpSessionXmlConfigurationTests extends AbstractGemFireInte
@Test @Test
public void verifyGemFireExampleCacheRegionSessionAttributesIndexWasCreatedSuccessfully() { public void verifyGemFireExampleCacheRegionSessionAttributesIndexWasCreatedSuccessfully() {
Region<Object, ExpiringSession> example = assertCacheAndRegion(this.gemfireCache, "XmlExample", DataPolicy.NORMAL); Region<Object, ExpiringSession> example = assertCacheAndRegion(this.gemfireCache,
"XmlExample", DataPolicy.NORMAL);
QueryService queryService = example.getRegionService().getQueryService(); QueryService queryService = example.getRegionService().getQueryService();
assertThat(queryService).isNotNull(); assertThat(queryService).isNotNull();
Index sessionAttributesIndex = queryService.getIndex(example, "sessionAttributesIndex"); Index sessionAttributesIndex = queryService.getIndex(example,
"sessionAttributesIndex");
assertIndex(sessionAttributesIndex, "s.attributes['one', 'two', 'three']", assertIndex(sessionAttributesIndex, "s.attributes['one', 'two', 'three']",
String.format("%1$s s", example.getFullPath())); String.format("%1$s s", example.getFullPath()));

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2016 the original author or authors. * Copyright 2014-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -15,8 +15,14 @@
*/ */
package org.springframework.session.data.mongo; package org.springframework.session.data.mongo;
import java.net.UnknownHostException;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import com.mongodb.MongoClient; import com.mongodb.MongoClient;
import org.junit.Test; import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@@ -33,11 +39,6 @@ import org.springframework.session.data.AbstractITests;
import org.springframework.session.data.mongo.config.annotation.web.http.EnableMongoHttpSession; import org.springframework.session.data.mongo.config.annotation.web.http.EnableMongoHttpSession;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import java.net.UnknownHostException;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
/** /**
@@ -57,69 +58,71 @@ public class MongoRepositoryITests extends AbstractITests {
public void saves() throws InterruptedException { public void saves() throws InterruptedException {
String username = "saves-" + System.currentTimeMillis(); String username = "saves-" + System.currentTimeMillis();
MongoExpiringSession toSave = repository.createSession(); MongoExpiringSession toSave = this.repository.createSession();
String expectedAttributeName = "a"; String expectedAttributeName = "a";
String expectedAttributeValue = "b"; String expectedAttributeValue = "b";
toSave.setAttribute(expectedAttributeName, expectedAttributeValue); toSave.setAttribute(expectedAttributeName, expectedAttributeValue);
Authentication toSaveToken = new UsernamePasswordAuthenticationToken(username, "password", Authentication toSaveToken = new UsernamePasswordAuthenticationToken(username,
AuthorityUtils.createAuthorityList("ROLE_USER")); "password", AuthorityUtils.createAuthorityList("ROLE_USER"));
SecurityContext toSaveContext = SecurityContextHolder.createEmptyContext(); SecurityContext toSaveContext = SecurityContextHolder.createEmptyContext();
toSaveContext.setAuthentication(toSaveToken); toSaveContext.setAuthentication(toSaveToken);
toSave.setAttribute(SPRING_SECURITY_CONTEXT, toSaveContext); toSave.setAttribute(SPRING_SECURITY_CONTEXT, toSaveContext);
toSave.setAttribute(INDEX_NAME, username); toSave.setAttribute(INDEX_NAME, username);
repository.save(toSave); this.repository.save(toSave);
Session session = repository.getSession(toSave.getId()); Session session = this.repository.getSession(toSave.getId());
assertThat(session.getId()).isEqualTo(toSave.getId()); assertThat(session.getId()).isEqualTo(toSave.getId());
assertThat(session.getAttributeNames()).isEqualTo(toSave.getAttributeNames()); assertThat(session.getAttributeNames()).isEqualTo(toSave.getAttributeNames());
assertThat(session.getAttribute(expectedAttributeName)).isEqualTo(toSave.getAttribute(expectedAttributeName)); assertThat(session.getAttribute(expectedAttributeName))
.isEqualTo(toSave.getAttribute(expectedAttributeName));
repository.delete(toSave.getId()); this.repository.delete(toSave.getId());
String id = toSave.getId(); String id = toSave.getId();
assertThat(repository.getSession(id)).isNull(); assertThat(this.repository.getSession(id)).isNull();
} }
@Test @Test
public void putAllOnSingleAttrDoesNotRemoveOld() { public void putAllOnSingleAttrDoesNotRemoveOld() {
MongoExpiringSession toSave = repository.createSession(); MongoExpiringSession toSave = this.repository.createSession();
toSave.setAttribute("a", "b"); toSave.setAttribute("a", "b");
repository.save(toSave); this.repository.save(toSave);
toSave = repository.getSession(toSave.getId()); toSave = this.repository.getSession(toSave.getId());
toSave.setAttribute("1", "2"); toSave.setAttribute("1", "2");
repository.save(toSave); this.repository.save(toSave);
toSave = repository.getSession(toSave.getId()); toSave = this.repository.getSession(toSave.getId());
Session session = repository.getSession(toSave.getId()); Session session = this.repository.getSession(toSave.getId());
assertThat(session.getAttributeNames().size()).isEqualTo(2); assertThat(session.getAttributeNames().size()).isEqualTo(2);
assertThat(session.getAttribute("a")).isEqualTo("b"); assertThat(session.getAttribute("a")).isEqualTo("b");
assertThat(session.getAttribute("1")).isEqualTo("2"); assertThat(session.getAttribute("1")).isEqualTo("2");
repository.delete(toSave.getId()); this.repository.delete(toSave.getId());
} }
@Test @Test
public void findByPrincipalName() throws Exception { public void findByPrincipalName() throws Exception {
String principalName = "findByPrincipalName" + UUID.randomUUID(); String principalName = "findByPrincipalName" + UUID.randomUUID();
MongoExpiringSession toSave = repository.createSession(); MongoExpiringSession toSave = this.repository.createSession();
toSave.setAttribute(INDEX_NAME, principalName); toSave.setAttribute(INDEX_NAME, principalName);
repository.save(toSave); this.repository.save(toSave);
Map<String, MongoExpiringSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, MongoExpiringSession> findByPrincipalName = this.repository
principalName); .findByIndexNameAndIndexValue(INDEX_NAME, principalName);
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
repository.delete(toSave.getId()); this.repository.delete(toSave.getId());
findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, principalName); findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME,
principalName);
assertThat(findByPrincipalName).hasSize(0); assertThat(findByPrincipalName).hasSize(0);
assertThat(findByPrincipalName.keySet()).doesNotContain(toSave.getId()); assertThat(findByPrincipalName.keySet()).doesNotContain(toSave.getId());
@@ -127,17 +130,18 @@ public class MongoRepositoryITests extends AbstractITests {
@Test @Test
public void findByPrincipalNameNoPrincipalNameChange() throws Exception { public void findByPrincipalNameNoPrincipalNameChange() throws Exception {
String principalName = "findByPrincipalNameNoPrincipalNameChange" + UUID.randomUUID(); String principalName = "findByPrincipalNameNoPrincipalNameChange"
MongoExpiringSession toSave = repository.createSession(); + UUID.randomUUID();
MongoExpiringSession toSave = this.repository.createSession();
toSave.setAttribute(INDEX_NAME, principalName); toSave.setAttribute(INDEX_NAME, principalName);
repository.save(toSave); this.repository.save(toSave);
toSave.setAttribute("other", "value"); toSave.setAttribute("other", "value");
repository.save(toSave); this.repository.save(toSave);
Map<String, MongoExpiringSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, MongoExpiringSession> findByPrincipalName = this.repository
principalName); .findByIndexNameAndIndexValue(INDEX_NAME, principalName);
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
@@ -145,19 +149,20 @@ public class MongoRepositoryITests extends AbstractITests {
@Test @Test
public void findByPrincipalNameNoPrincipalNameChangeReload() throws Exception { public void findByPrincipalNameNoPrincipalNameChangeReload() throws Exception {
String principalName = "findByPrincipalNameNoPrincipalNameChangeReload" + UUID.randomUUID(); String principalName = "findByPrincipalNameNoPrincipalNameChangeReload"
MongoExpiringSession toSave = repository.createSession(); + UUID.randomUUID();
MongoExpiringSession toSave = this.repository.createSession();
toSave.setAttribute(INDEX_NAME, principalName); toSave.setAttribute(INDEX_NAME, principalName);
repository.save(toSave); this.repository.save(toSave);
toSave = repository.getSession(toSave.getId()); toSave = this.repository.getSession(toSave.getId());
toSave.setAttribute("other", "value"); toSave.setAttribute("other", "value");
repository.save(toSave); this.repository.save(toSave);
Map<String, MongoExpiringSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, MongoExpiringSession> findByPrincipalName = this.repository
principalName); .findByIndexNameAndIndexValue(INDEX_NAME, principalName);
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
@@ -166,16 +171,16 @@ public class MongoRepositoryITests extends AbstractITests {
@Test @Test
public void findByDeletedPrincipalName() throws Exception { public void findByDeletedPrincipalName() throws Exception {
String principalName = "findByDeletedPrincipalName" + UUID.randomUUID(); String principalName = "findByDeletedPrincipalName" + UUID.randomUUID();
MongoExpiringSession toSave = repository.createSession(); MongoExpiringSession toSave = this.repository.createSession();
toSave.setAttribute(INDEX_NAME, principalName); toSave.setAttribute(INDEX_NAME, principalName);
repository.save(toSave); this.repository.save(toSave);
toSave.setAttribute(INDEX_NAME, null); toSave.setAttribute(INDEX_NAME, null);
repository.save(toSave); this.repository.save(toSave);
Map<String, MongoExpiringSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, MongoExpiringSession> findByPrincipalName = this.repository
principalName); .findByIndexNameAndIndexValue(INDEX_NAME, principalName);
assertThat(findByPrincipalName).isEmpty(); assertThat(findByPrincipalName).isEmpty();
} }
@@ -184,19 +189,20 @@ public class MongoRepositoryITests extends AbstractITests {
public void findByChangedPrincipalName() throws Exception { public void findByChangedPrincipalName() throws Exception {
String principalName = "findByChangedPrincipalName" + UUID.randomUUID(); String principalName = "findByChangedPrincipalName" + UUID.randomUUID();
String principalNameChanged = "findByChangedPrincipalName" + UUID.randomUUID(); String principalNameChanged = "findByChangedPrincipalName" + UUID.randomUUID();
MongoExpiringSession toSave = repository.createSession(); MongoExpiringSession toSave = this.repository.createSession();
toSave.setAttribute(INDEX_NAME, principalName); toSave.setAttribute(INDEX_NAME, principalName);
repository.save(toSave); this.repository.save(toSave);
toSave.setAttribute(INDEX_NAME, principalNameChanged); toSave.setAttribute(INDEX_NAME, principalNameChanged);
repository.save(toSave); this.repository.save(toSave);
Map<String, MongoExpiringSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, MongoExpiringSession> findByPrincipalName = this.repository
principalName); .findByIndexNameAndIndexValue(INDEX_NAME, principalName);
assertThat(findByPrincipalName).isEmpty(); assertThat(findByPrincipalName).isEmpty();
findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, principalNameChanged); findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME,
principalNameChanged);
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
@@ -205,17 +211,17 @@ public class MongoRepositoryITests extends AbstractITests {
@Test @Test
public void findByDeletedPrincipalNameReload() throws Exception { public void findByDeletedPrincipalNameReload() throws Exception {
String principalName = "findByDeletedPrincipalName" + UUID.randomUUID(); String principalName = "findByDeletedPrincipalName" + UUID.randomUUID();
MongoExpiringSession toSave = repository.createSession(); MongoExpiringSession toSave = this.repository.createSession();
toSave.setAttribute(INDEX_NAME, principalName); toSave.setAttribute(INDEX_NAME, principalName);
repository.save(toSave); this.repository.save(toSave);
MongoExpiringSession getSession = repository.getSession(toSave.getId()); MongoExpiringSession getSession = this.repository.getSession(toSave.getId());
getSession.setAttribute(INDEX_NAME, null); getSession.setAttribute(INDEX_NAME, null);
repository.save(getSession); this.repository.save(getSession);
Map<String, MongoExpiringSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, MongoExpiringSession> findByPrincipalName = this.repository
principalName); .findByIndexNameAndIndexValue(INDEX_NAME, principalName);
assertThat(findByPrincipalName).isEmpty(); assertThat(findByPrincipalName).isEmpty();
} }
@@ -224,21 +230,22 @@ public class MongoRepositoryITests extends AbstractITests {
public void findByChangedPrincipalNameReload() throws Exception { public void findByChangedPrincipalNameReload() throws Exception {
String principalName = "findByChangedPrincipalName" + UUID.randomUUID(); String principalName = "findByChangedPrincipalName" + UUID.randomUUID();
String principalNameChanged = "findByChangedPrincipalName" + UUID.randomUUID(); String principalNameChanged = "findByChangedPrincipalName" + UUID.randomUUID();
MongoExpiringSession toSave = repository.createSession(); MongoExpiringSession toSave = this.repository.createSession();
toSave.setAttribute(INDEX_NAME, principalName); toSave.setAttribute(INDEX_NAME, principalName);
repository.save(toSave); this.repository.save(toSave);
MongoExpiringSession getSession = repository.getSession(toSave.getId()); MongoExpiringSession getSession = this.repository.getSession(toSave.getId());
getSession.setAttribute(INDEX_NAME, principalNameChanged); getSession.setAttribute(INDEX_NAME, principalNameChanged);
repository.save(getSession); this.repository.save(getSession);
Map<String, MongoExpiringSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, MongoExpiringSession> findByPrincipalName = this.repository
principalName); .findByIndexNameAndIndexValue(INDEX_NAME, principalName);
assertThat(findByPrincipalName).isEmpty(); assertThat(findByPrincipalName).isEmpty();
findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, principalNameChanged); findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME,
principalNameChanged);
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
@@ -246,20 +253,21 @@ public class MongoRepositoryITests extends AbstractITests {
@Test @Test
public void findBySecurityPrincipalName() throws Exception { public void findBySecurityPrincipalName() throws Exception {
MongoExpiringSession toSave = repository.createSession(); MongoExpiringSession toSave = this.repository.createSession();
toSave.setAttribute(SPRING_SECURITY_CONTEXT, context); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context);
repository.save(toSave); this.repository.save(toSave);
Map<String, MongoExpiringSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, MongoExpiringSession> findByPrincipalName = this.repository
getSecurityName()); .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName());
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
repository.delete(toSave.getId()); this.repository.delete(toSave.getId());
findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName()); findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME,
getSecurityName());
assertThat(findByPrincipalName).hasSize(0); assertThat(findByPrincipalName).hasSize(0);
assertThat(findByPrincipalName.keySet()).doesNotContain(toSave.getId()); assertThat(findByPrincipalName.keySet()).doesNotContain(toSave.getId());
@@ -267,35 +275,36 @@ public class MongoRepositoryITests extends AbstractITests {
@Test @Test
public void findByPrincipalNameNoSecurityPrincipalNameChange() throws Exception { public void findByPrincipalNameNoSecurityPrincipalNameChange() throws Exception {
MongoExpiringSession toSave = repository.createSession(); MongoExpiringSession toSave = this.repository.createSession();
toSave.setAttribute(SPRING_SECURITY_CONTEXT, context); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context);
repository.save(toSave); this.repository.save(toSave);
toSave.setAttribute("other", "value"); toSave.setAttribute("other", "value");
repository.save(toSave); this.repository.save(toSave);
Map<String, MongoExpiringSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, MongoExpiringSession> findByPrincipalName = this.repository
getSecurityName()); .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName());
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
} }
@Test @Test
public void findByPrincipalNameNoSecurityPrincipalNameChangeReload() throws Exception { public void findByPrincipalNameNoSecurityPrincipalNameChangeReload()
MongoExpiringSession toSave = repository.createSession(); throws Exception {
toSave.setAttribute(SPRING_SECURITY_CONTEXT, context); MongoExpiringSession toSave = this.repository.createSession();
toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context);
repository.save(toSave); this.repository.save(toSave);
toSave = repository.getSession(toSave.getId()); toSave = this.repository.getSession(toSave.getId());
toSave.setAttribute("other", "value"); toSave.setAttribute("other", "value");
repository.save(toSave); this.repository.save(toSave);
Map<String, MongoExpiringSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, MongoExpiringSession> findByPrincipalName = this.repository
getSecurityName()); .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName());
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
@@ -303,35 +312,36 @@ public class MongoRepositoryITests extends AbstractITests {
@Test @Test
public void findByDeletedSecurityPrincipalName() throws Exception { public void findByDeletedSecurityPrincipalName() throws Exception {
MongoExpiringSession toSave = repository.createSession(); MongoExpiringSession toSave = this.repository.createSession();
toSave.setAttribute(SPRING_SECURITY_CONTEXT, context); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context);
repository.save(toSave); this.repository.save(toSave);
toSave.setAttribute(SPRING_SECURITY_CONTEXT, null); toSave.setAttribute(SPRING_SECURITY_CONTEXT, null);
repository.save(toSave); this.repository.save(toSave);
Map<String, MongoExpiringSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, MongoExpiringSession> findByPrincipalName = this.repository
getSecurityName()); .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName());
assertThat(findByPrincipalName).isEmpty(); assertThat(findByPrincipalName).isEmpty();
} }
@Test @Test
public void findByChangedSecurityPrincipalName() throws Exception { public void findByChangedSecurityPrincipalName() throws Exception {
MongoExpiringSession toSave = repository.createSession(); MongoExpiringSession toSave = this.repository.createSession();
toSave.setAttribute(SPRING_SECURITY_CONTEXT, context); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context);
repository.save(toSave); this.repository.save(toSave);
toSave.setAttribute(SPRING_SECURITY_CONTEXT, changedContext); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.changedContext);
repository.save(toSave); this.repository.save(toSave);
Map<String, MongoExpiringSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, MongoExpiringSession> findByPrincipalName = this.repository
getSecurityName()); .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName());
assertThat(findByPrincipalName).isEmpty(); assertThat(findByPrincipalName).isEmpty();
findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, getChangedSecurityName()); findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME,
getChangedSecurityName());
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
@@ -339,38 +349,39 @@ public class MongoRepositoryITests extends AbstractITests {
@Test @Test
public void findByDeletedSecurityPrincipalNameReload() throws Exception { public void findByDeletedSecurityPrincipalNameReload() throws Exception {
MongoExpiringSession toSave = repository.createSession(); MongoExpiringSession toSave = this.repository.createSession();
toSave.setAttribute(SPRING_SECURITY_CONTEXT, context); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context);
repository.save(toSave); this.repository.save(toSave);
MongoExpiringSession getSession = repository.getSession(toSave.getId()); MongoExpiringSession getSession = this.repository.getSession(toSave.getId());
getSession.setAttribute(INDEX_NAME, null); getSession.setAttribute(INDEX_NAME, null);
repository.save(getSession); this.repository.save(getSession);
Map<String, MongoExpiringSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, MongoExpiringSession> findByPrincipalName = this.repository
getChangedSecurityName()); .findByIndexNameAndIndexValue(INDEX_NAME, getChangedSecurityName());
assertThat(findByPrincipalName).isEmpty(); assertThat(findByPrincipalName).isEmpty();
} }
@Test @Test
public void findByChangedSecurityPrincipalNameReload() throws Exception { public void findByChangedSecurityPrincipalNameReload() throws Exception {
MongoExpiringSession toSave = repository.createSession(); MongoExpiringSession toSave = this.repository.createSession();
toSave.setAttribute(SPRING_SECURITY_CONTEXT, context); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context);
repository.save(toSave); this.repository.save(toSave);
MongoExpiringSession getSession = repository.getSession(toSave.getId()); MongoExpiringSession getSession = this.repository.getSession(toSave.getId());
getSession.setAttribute(SPRING_SECURITY_CONTEXT, changedContext); getSession.setAttribute(SPRING_SECURITY_CONTEXT, this.changedContext);
repository.save(getSession); this.repository.save(getSession);
Map<String, MongoExpiringSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, MongoExpiringSession> findByPrincipalName = this.repository
getSecurityName()); .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName());
assertThat(findByPrincipalName).isEmpty(); assertThat(findByPrincipalName).isEmpty();
findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, getChangedSecurityName()); findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME,
getChangedSecurityName());
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
@@ -379,22 +390,24 @@ public class MongoRepositoryITests extends AbstractITests {
@Test @Test
public void loadExpiredSession() throws Exception { public void loadExpiredSession() throws Exception {
// given // given
MongoExpiringSession expiredSession = repository.createSession(); MongoExpiringSession expiredSession = this.repository.createSession();
long thirtyOneMinutesAgo = System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(31); long thirtyOneMinutesAgo = System.currentTimeMillis()
- TimeUnit.MINUTES.toMillis(31);
expiredSession.setLastAccessedTime(thirtyOneMinutesAgo); expiredSession.setLastAccessedTime(thirtyOneMinutesAgo);
repository.save(expiredSession); this.repository.save(expiredSession);
// then // then
MongoExpiringSession expiredSessionFromDb = repository.getSession(expiredSession.getId()); MongoExpiringSession expiredSessionFromDb = this.repository
.getSession(expiredSession.getId());
assertThat(expiredSessionFromDb).isNull(); assertThat(expiredSessionFromDb).isNull();
} }
private String getSecurityName() { private String getSecurityName() {
return context.getAuthentication().getName(); return this.context.getAuthentication().getName();
} }
private String getChangedSecurityName() { private String getChangedSecurityName() {
return changedContext.getAuthentication().getName(); return this.changedContext.getAuthentication().getName();
} }
@Configuration @Configuration

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2015 the original author or authors. * Copyright 2014-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -15,12 +15,11 @@
*/ */
package org.springframework.session.data.redis; package org.springframework.session.data.redis;
import static org.assertj.core.api.Assertions.*;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import org.junit.Test; import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@@ -42,6 +41,8 @@ import org.springframework.session.events.SessionCreatedEvent;
import org.springframework.session.events.SessionDestroyedEvent; import org.springframework.session.events.SessionDestroyedEvent;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import static org.assertj.core.api.Assertions.assertThat;
@ContextConfiguration @ContextConfiguration
public class RedisOperationsSessionRepositoryITests extends AbstractITests { public class RedisOperationsSessionRepositoryITests extends AbstractITests {
private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT"; private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT";
@@ -58,86 +59,90 @@ public class RedisOperationsSessionRepositoryITests extends AbstractITests {
public void saves() throws InterruptedException { public void saves() throws InterruptedException {
String username = "saves-" + System.currentTimeMillis(); String username = "saves-" + System.currentTimeMillis();
String usernameSessionKey = "spring:session:RedisOperationsSessionRepositoryITests:index:" + INDEX_NAME + ":" String usernameSessionKey = "spring:session:RedisOperationsSessionRepositoryITests:index:"
+ username; + INDEX_NAME + ":" + username;
RedisSession toSave = repository.createSession(); RedisSession toSave = this.repository.createSession();
String expectedAttributeName = "a"; String expectedAttributeName = "a";
String expectedAttributeValue = "b"; String expectedAttributeValue = "b";
toSave.setAttribute(expectedAttributeName, expectedAttributeValue); toSave.setAttribute(expectedAttributeName, expectedAttributeValue);
Authentication toSaveToken = new UsernamePasswordAuthenticationToken(username, "password", Authentication toSaveToken = new UsernamePasswordAuthenticationToken(username,
AuthorityUtils.createAuthorityList("ROLE_USER")); "password", AuthorityUtils.createAuthorityList("ROLE_USER"));
SecurityContext toSaveContext = SecurityContextHolder.createEmptyContext(); SecurityContext toSaveContext = SecurityContextHolder.createEmptyContext();
toSaveContext.setAuthentication(toSaveToken); toSaveContext.setAuthentication(toSaveToken);
toSave.setAttribute(SPRING_SECURITY_CONTEXT, toSaveContext); toSave.setAttribute(SPRING_SECURITY_CONTEXT, toSaveContext);
toSave.setAttribute(INDEX_NAME, username); toSave.setAttribute(INDEX_NAME, username);
registry.clear(); this.registry.clear();
repository.save(toSave); this.repository.save(toSave);
assertThat(registry.receivedEvent(toSave.getId())).isTrue(); assertThat(this.registry.receivedEvent(toSave.getId())).isTrue();
assertThat(registry.getEvent(toSave.getId())).isInstanceOf(SessionCreatedEvent.class); assertThat(this.registry.getEvent(toSave.getId()))
assertThat(redis.boundSetOps(usernameSessionKey).members()).contains(toSave.getId()); .isInstanceOf(SessionCreatedEvent.class);
assertThat(this.redis.boundSetOps(usernameSessionKey).members())
.contains(toSave.getId());
Session session = repository.getSession(toSave.getId()); Session session = this.repository.getSession(toSave.getId());
assertThat(session.getId()).isEqualTo(toSave.getId()); assertThat(session.getId()).isEqualTo(toSave.getId());
assertThat(session.getAttributeNames()).isEqualTo(toSave.getAttributeNames()); assertThat(session.getAttributeNames()).isEqualTo(toSave.getAttributeNames());
assertThat(session.getAttribute(expectedAttributeName)).isEqualTo(toSave.getAttribute(expectedAttributeName)); assertThat(session.getAttribute(expectedAttributeName))
.isEqualTo(toSave.getAttribute(expectedAttributeName));
registry.clear(); this.registry.clear();
repository.delete(toSave.getId()); this.repository.delete(toSave.getId());
assertThat(repository.getSession(toSave.getId())).isNull(); assertThat(this.repository.getSession(toSave.getId())).isNull();
assertThat(registry.getEvent(toSave.getId())).isInstanceOf(SessionDestroyedEvent.class); assertThat(this.registry.getEvent(toSave.getId()))
assertThat(redis.boundSetOps(usernameSessionKey).members()).doesNotContain(toSave.getId()); .isInstanceOf(SessionDestroyedEvent.class);
assertThat(this.redis.boundSetOps(usernameSessionKey).members())
.doesNotContain(toSave.getId());
assertThat(registry.getEvent(toSave.getId()).getSession().getAttribute(expectedAttributeName)) assertThat(this.registry.getEvent(toSave.getId()).getSession()
.isEqualTo(expectedAttributeValue); .getAttribute(expectedAttributeName)).isEqualTo(expectedAttributeValue);
} }
@Test @Test
public void putAllOnSingleAttrDoesNotRemoveOld() { public void putAllOnSingleAttrDoesNotRemoveOld() {
RedisSession toSave = repository.createSession(); RedisSession toSave = this.repository.createSession();
toSave.setAttribute("a", "b"); toSave.setAttribute("a", "b");
repository.save(toSave); this.repository.save(toSave);
toSave = repository.getSession(toSave.getId()); toSave = this.repository.getSession(toSave.getId());
toSave.setAttribute("1", "2"); toSave.setAttribute("1", "2");
repository.save(toSave); this.repository.save(toSave);
toSave = repository.getSession(toSave.getId()); toSave = this.repository.getSession(toSave.getId());
Session session = repository.getSession(toSave.getId()); Session session = this.repository.getSession(toSave.getId());
assertThat(session.getAttributeNames().size()).isEqualTo(2); assertThat(session.getAttributeNames().size()).isEqualTo(2);
assertThat(session.getAttribute("a")).isEqualTo("b"); assertThat(session.getAttribute("a")).isEqualTo("b");
assertThat(session.getAttribute("1")).isEqualTo("2"); assertThat(session.getAttribute("1")).isEqualTo("2");
repository.delete(toSave.getId()); this.repository.delete(toSave.getId());
} }
@Test @Test
public void findByPrincipalName() throws Exception { public void findByPrincipalName() throws Exception {
String principalName = "findByPrincipalName" + UUID.randomUUID(); String principalName = "findByPrincipalName" + UUID.randomUUID();
RedisSession toSave = repository.createSession(); RedisSession toSave = this.repository.createSession();
toSave.setAttribute(INDEX_NAME, principalName); toSave.setAttribute(INDEX_NAME, principalName);
repository.save(toSave); this.repository.save(toSave);
Map<String, RedisSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, RedisSession> findByPrincipalName = this.repository
principalName); .findByIndexNameAndIndexValue(INDEX_NAME, principalName);
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
repository.delete(toSave.getId()); this.repository.delete(toSave.getId());
assertThat(registry.receivedEvent(toSave.getId())).isTrue(); assertThat(this.registry.receivedEvent(toSave.getId())).isTrue();
findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, principalName); findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME,
principalName);
assertThat(findByPrincipalName).hasSize(0); assertThat(findByPrincipalName).hasSize(0);
assertThat(findByPrincipalName.keySet()).doesNotContain(toSave.getId()); assertThat(findByPrincipalName.keySet()).doesNotContain(toSave.getId());
@@ -145,20 +150,23 @@ public class RedisOperationsSessionRepositoryITests extends AbstractITests {
@Test @Test
public void findByPrincipalNameExpireRemovesIndex() throws Exception { public void findByPrincipalNameExpireRemovesIndex() throws Exception {
String principalName = "findByPrincipalNameExpireRemovesIndex" + UUID.randomUUID(); String principalName = "findByPrincipalNameExpireRemovesIndex"
RedisSession toSave = repository.createSession(); + UUID.randomUUID();
RedisSession toSave = this.repository.createSession();
toSave.setAttribute(INDEX_NAME, principalName); toSave.setAttribute(INDEX_NAME, principalName);
repository.save(toSave); this.repository.save(toSave);
String body = "spring:session:RedisOperationsSessionRepositoryITests:sessions:expires:" + toSave.getId(); String body = "spring:session:RedisOperationsSessionRepositoryITests:sessions:expires:"
+ toSave.getId();
String channel = ":expired"; String channel = ":expired";
DefaultMessage message = new DefaultMessage(channel.getBytes("UTF-8"), body.getBytes("UTF-8")); DefaultMessage message = new DefaultMessage(channel.getBytes("UTF-8"),
body.getBytes("UTF-8"));
byte[] pattern = new byte[] {}; byte[] pattern = new byte[] {};
repository.onMessage(message, pattern); this.repository.onMessage(message, pattern);
Map<String, RedisSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, RedisSession> findByPrincipalName = this.repository
principalName); .findByIndexNameAndIndexValue(INDEX_NAME, principalName);
assertThat(findByPrincipalName).hasSize(0); assertThat(findByPrincipalName).hasSize(0);
assertThat(findByPrincipalName.keySet()).doesNotContain(toSave.getId()); assertThat(findByPrincipalName.keySet()).doesNotContain(toSave.getId());
@@ -166,17 +174,18 @@ public class RedisOperationsSessionRepositoryITests extends AbstractITests {
@Test @Test
public void findByPrincipalNameNoPrincipalNameChange() throws Exception { public void findByPrincipalNameNoPrincipalNameChange() throws Exception {
String principalName = "findByPrincipalNameNoPrincipalNameChange" + UUID.randomUUID(); String principalName = "findByPrincipalNameNoPrincipalNameChange"
RedisSession toSave = repository.createSession(); + UUID.randomUUID();
RedisSession toSave = this.repository.createSession();
toSave.setAttribute(INDEX_NAME, principalName); toSave.setAttribute(INDEX_NAME, principalName);
repository.save(toSave); this.repository.save(toSave);
toSave.setAttribute("other", "value"); toSave.setAttribute("other", "value");
repository.save(toSave); this.repository.save(toSave);
Map<String, RedisSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, RedisSession> findByPrincipalName = this.repository
principalName); .findByIndexNameAndIndexValue(INDEX_NAME, principalName);
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
@@ -184,19 +193,20 @@ public class RedisOperationsSessionRepositoryITests extends AbstractITests {
@Test @Test
public void findByPrincipalNameNoPrincipalNameChangeReload() throws Exception { public void findByPrincipalNameNoPrincipalNameChangeReload() throws Exception {
String principalName = "findByPrincipalNameNoPrincipalNameChangeReload" + UUID.randomUUID(); String principalName = "findByPrincipalNameNoPrincipalNameChangeReload"
RedisSession toSave = repository.createSession(); + UUID.randomUUID();
RedisSession toSave = this.repository.createSession();
toSave.setAttribute(INDEX_NAME, principalName); toSave.setAttribute(INDEX_NAME, principalName);
repository.save(toSave); this.repository.save(toSave);
toSave = repository.getSession(toSave.getId()); toSave = this.repository.getSession(toSave.getId());
toSave.setAttribute("other", "value"); toSave.setAttribute("other", "value");
repository.save(toSave); this.repository.save(toSave);
Map<String, RedisSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, RedisSession> findByPrincipalName = this.repository
principalName); .findByIndexNameAndIndexValue(INDEX_NAME, principalName);
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
@@ -205,16 +215,16 @@ public class RedisOperationsSessionRepositoryITests extends AbstractITests {
@Test @Test
public void findByDeletedPrincipalName() throws Exception { public void findByDeletedPrincipalName() throws Exception {
String principalName = "findByDeletedPrincipalName" + UUID.randomUUID(); String principalName = "findByDeletedPrincipalName" + UUID.randomUUID();
RedisSession toSave = repository.createSession(); RedisSession toSave = this.repository.createSession();
toSave.setAttribute(INDEX_NAME, principalName); toSave.setAttribute(INDEX_NAME, principalName);
repository.save(toSave); this.repository.save(toSave);
toSave.setAttribute(INDEX_NAME, null); toSave.setAttribute(INDEX_NAME, null);
repository.save(toSave); this.repository.save(toSave);
Map<String, RedisSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, RedisSession> findByPrincipalName = this.repository
principalName); .findByIndexNameAndIndexValue(INDEX_NAME, principalName);
assertThat(findByPrincipalName).isEmpty(); assertThat(findByPrincipalName).isEmpty();
} }
@@ -223,19 +233,20 @@ public class RedisOperationsSessionRepositoryITests extends AbstractITests {
public void findByChangedPrincipalName() throws Exception { public void findByChangedPrincipalName() throws Exception {
String principalName = "findByChangedPrincipalName" + UUID.randomUUID(); String principalName = "findByChangedPrincipalName" + UUID.randomUUID();
String principalNameChanged = "findByChangedPrincipalName" + UUID.randomUUID(); String principalNameChanged = "findByChangedPrincipalName" + UUID.randomUUID();
RedisSession toSave = repository.createSession(); RedisSession toSave = this.repository.createSession();
toSave.setAttribute(INDEX_NAME, principalName); toSave.setAttribute(INDEX_NAME, principalName);
repository.save(toSave); this.repository.save(toSave);
toSave.setAttribute(INDEX_NAME, principalNameChanged); toSave.setAttribute(INDEX_NAME, principalNameChanged);
repository.save(toSave); this.repository.save(toSave);
Map<String, RedisSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, RedisSession> findByPrincipalName = this.repository
principalName); .findByIndexNameAndIndexValue(INDEX_NAME, principalName);
assertThat(findByPrincipalName).isEmpty(); assertThat(findByPrincipalName).isEmpty();
findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, principalNameChanged); findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME,
principalNameChanged);
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
@@ -244,17 +255,17 @@ public class RedisOperationsSessionRepositoryITests extends AbstractITests {
@Test @Test
public void findByDeletedPrincipalNameReload() throws Exception { public void findByDeletedPrincipalNameReload() throws Exception {
String principalName = "findByDeletedPrincipalName" + UUID.randomUUID(); String principalName = "findByDeletedPrincipalName" + UUID.randomUUID();
RedisSession toSave = repository.createSession(); RedisSession toSave = this.repository.createSession();
toSave.setAttribute(INDEX_NAME, principalName); toSave.setAttribute(INDEX_NAME, principalName);
repository.save(toSave); this.repository.save(toSave);
RedisSession getSession = repository.getSession(toSave.getId()); RedisSession getSession = this.repository.getSession(toSave.getId());
getSession.setAttribute(INDEX_NAME, null); getSession.setAttribute(INDEX_NAME, null);
repository.save(getSession); this.repository.save(getSession);
Map<String, RedisSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, RedisSession> findByPrincipalName = this.repository
principalName); .findByIndexNameAndIndexValue(INDEX_NAME, principalName);
assertThat(findByPrincipalName).isEmpty(); assertThat(findByPrincipalName).isEmpty();
} }
@@ -263,21 +274,22 @@ public class RedisOperationsSessionRepositoryITests extends AbstractITests {
public void findByChangedPrincipalNameReload() throws Exception { public void findByChangedPrincipalNameReload() throws Exception {
String principalName = "findByChangedPrincipalName" + UUID.randomUUID(); String principalName = "findByChangedPrincipalName" + UUID.randomUUID();
String principalNameChanged = "findByChangedPrincipalName" + UUID.randomUUID(); String principalNameChanged = "findByChangedPrincipalName" + UUID.randomUUID();
RedisSession toSave = repository.createSession(); RedisSession toSave = this.repository.createSession();
toSave.setAttribute(INDEX_NAME, principalName); toSave.setAttribute(INDEX_NAME, principalName);
repository.save(toSave); this.repository.save(toSave);
RedisSession getSession = repository.getSession(toSave.getId()); RedisSession getSession = this.repository.getSession(toSave.getId());
getSession.setAttribute(INDEX_NAME, principalNameChanged); getSession.setAttribute(INDEX_NAME, principalNameChanged);
repository.save(getSession); this.repository.save(getSession);
Map<String, RedisSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, RedisSession> findByPrincipalName = this.repository
principalName); .findByIndexNameAndIndexValue(INDEX_NAME, principalName);
assertThat(findByPrincipalName).isEmpty(); assertThat(findByPrincipalName).isEmpty();
findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, principalNameChanged); findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME,
principalNameChanged);
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
@@ -285,21 +297,22 @@ public class RedisOperationsSessionRepositoryITests extends AbstractITests {
@Test @Test
public void findBySecurityPrincipalName() throws Exception { public void findBySecurityPrincipalName() throws Exception {
RedisSession toSave = repository.createSession(); RedisSession toSave = this.repository.createSession();
toSave.setAttribute(SPRING_SECURITY_CONTEXT, context); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context);
repository.save(toSave); this.repository.save(toSave);
Map<String, RedisSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, RedisSession> findByPrincipalName = this.repository
getSecurityName()); .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName());
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
repository.delete(toSave.getId()); this.repository.delete(toSave.getId());
assertThat(registry.receivedEvent(toSave.getId())).isTrue(); assertThat(this.registry.receivedEvent(toSave.getId())).isTrue();
findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName()); findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME,
getSecurityName());
assertThat(findByPrincipalName).hasSize(0); assertThat(findByPrincipalName).hasSize(0);
assertThat(findByPrincipalName.keySet()).doesNotContain(toSave.getId()); assertThat(findByPrincipalName.keySet()).doesNotContain(toSave.getId());
@@ -307,19 +320,21 @@ public class RedisOperationsSessionRepositoryITests extends AbstractITests {
@Test @Test
public void findBySecurityPrincipalNameExpireRemovesIndex() throws Exception { public void findBySecurityPrincipalNameExpireRemovesIndex() throws Exception {
RedisSession toSave = repository.createSession(); RedisSession toSave = this.repository.createSession();
toSave.setAttribute(SPRING_SECURITY_CONTEXT, context); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context);
repository.save(toSave); this.repository.save(toSave);
String body = "spring:session:RedisOperationsSessionRepositoryITests:sessions:expires:" + toSave.getId(); String body = "spring:session:RedisOperationsSessionRepositoryITests:sessions:expires:"
+ toSave.getId();
String channel = ":expired"; String channel = ":expired";
DefaultMessage message = new DefaultMessage(channel.getBytes("UTF-8"), body.getBytes("UTF-8")); DefaultMessage message = new DefaultMessage(channel.getBytes("UTF-8"),
body.getBytes("UTF-8"));
byte[] pattern = new byte[] {}; byte[] pattern = new byte[] {};
repository.onMessage(message, pattern); this.repository.onMessage(message, pattern);
Map<String, RedisSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, RedisSession> findByPrincipalName = this.repository
getSecurityName()); .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName());
assertThat(findByPrincipalName).hasSize(0); assertThat(findByPrincipalName).hasSize(0);
assertThat(findByPrincipalName.keySet()).doesNotContain(toSave.getId()); assertThat(findByPrincipalName.keySet()).doesNotContain(toSave.getId());
@@ -327,35 +342,36 @@ public class RedisOperationsSessionRepositoryITests extends AbstractITests {
@Test @Test
public void findByPrincipalNameNoSecurityPrincipalNameChange() throws Exception { public void findByPrincipalNameNoSecurityPrincipalNameChange() throws Exception {
RedisSession toSave = repository.createSession(); RedisSession toSave = this.repository.createSession();
toSave.setAttribute(SPRING_SECURITY_CONTEXT, context); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context);
repository.save(toSave); this.repository.save(toSave);
toSave.setAttribute("other", "value"); toSave.setAttribute("other", "value");
repository.save(toSave); this.repository.save(toSave);
Map<String, RedisSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, RedisSession> findByPrincipalName = this.repository
getSecurityName()); .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName());
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
} }
@Test @Test
public void findByPrincipalNameNoSecurityPrincipalNameChangeReload() throws Exception { public void findByPrincipalNameNoSecurityPrincipalNameChangeReload()
RedisSession toSave = repository.createSession(); throws Exception {
toSave.setAttribute(SPRING_SECURITY_CONTEXT, context); RedisSession toSave = this.repository.createSession();
toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context);
repository.save(toSave); this.repository.save(toSave);
toSave = repository.getSession(toSave.getId()); toSave = this.repository.getSession(toSave.getId());
toSave.setAttribute("other", "value"); toSave.setAttribute("other", "value");
repository.save(toSave); this.repository.save(toSave);
Map<String, RedisSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, RedisSession> findByPrincipalName = this.repository
getSecurityName()); .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName());
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
@@ -363,35 +379,36 @@ public class RedisOperationsSessionRepositoryITests extends AbstractITests {
@Test @Test
public void findByDeletedSecurityPrincipalName() throws Exception { public void findByDeletedSecurityPrincipalName() throws Exception {
RedisSession toSave = repository.createSession(); RedisSession toSave = this.repository.createSession();
toSave.setAttribute(SPRING_SECURITY_CONTEXT, context); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context);
repository.save(toSave); this.repository.save(toSave);
toSave.setAttribute(SPRING_SECURITY_CONTEXT, null); toSave.setAttribute(SPRING_SECURITY_CONTEXT, null);
repository.save(toSave); this.repository.save(toSave);
Map<String, RedisSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, RedisSession> findByPrincipalName = this.repository
getSecurityName()); .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName());
assertThat(findByPrincipalName).isEmpty(); assertThat(findByPrincipalName).isEmpty();
} }
@Test @Test
public void findByChangedSecurityPrincipalName() throws Exception { public void findByChangedSecurityPrincipalName() throws Exception {
RedisSession toSave = repository.createSession(); RedisSession toSave = this.repository.createSession();
toSave.setAttribute(SPRING_SECURITY_CONTEXT, context); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context);
repository.save(toSave); this.repository.save(toSave);
toSave.setAttribute(SPRING_SECURITY_CONTEXT, changedContext); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.changedContext);
repository.save(toSave); this.repository.save(toSave);
Map<String, RedisSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, RedisSession> findByPrincipalName = this.repository
getSecurityName()); .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName());
assertThat(findByPrincipalName).isEmpty(); assertThat(findByPrincipalName).isEmpty();
findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, getChangedSecurityName()); findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME,
getChangedSecurityName());
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
@@ -399,49 +416,50 @@ public class RedisOperationsSessionRepositoryITests extends AbstractITests {
@Test @Test
public void findByDeletedSecurityPrincipalNameReload() throws Exception { public void findByDeletedSecurityPrincipalNameReload() throws Exception {
RedisSession toSave = repository.createSession(); RedisSession toSave = this.repository.createSession();
toSave.setAttribute(SPRING_SECURITY_CONTEXT, context); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context);
repository.save(toSave); this.repository.save(toSave);
RedisSession getSession = repository.getSession(toSave.getId()); RedisSession getSession = this.repository.getSession(toSave.getId());
getSession.setAttribute(INDEX_NAME, null); getSession.setAttribute(INDEX_NAME, null);
repository.save(getSession); this.repository.save(getSession);
Map<String, RedisSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, RedisSession> findByPrincipalName = this.repository
getChangedSecurityName()); .findByIndexNameAndIndexValue(INDEX_NAME, getChangedSecurityName());
assertThat(findByPrincipalName).isEmpty(); assertThat(findByPrincipalName).isEmpty();
} }
@Test @Test
public void findByChangedSecurityPrincipalNameReload() throws Exception { public void findByChangedSecurityPrincipalNameReload() throws Exception {
RedisSession toSave = repository.createSession(); RedisSession toSave = this.repository.createSession();
toSave.setAttribute(SPRING_SECURITY_CONTEXT, context); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context);
repository.save(toSave); this.repository.save(toSave);
RedisSession getSession = repository.getSession(toSave.getId()); RedisSession getSession = this.repository.getSession(toSave.getId());
getSession.setAttribute(SPRING_SECURITY_CONTEXT, changedContext); getSession.setAttribute(SPRING_SECURITY_CONTEXT, this.changedContext);
repository.save(getSession); this.repository.save(getSession);
Map<String, RedisSession> findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, Map<String, RedisSession> findByPrincipalName = this.repository
getSecurityName()); .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName());
assertThat(findByPrincipalName).isEmpty(); assertThat(findByPrincipalName).isEmpty();
findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, getChangedSecurityName()); findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME,
getChangedSecurityName());
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
} }
private String getSecurityName() { private String getSecurityName() {
return context.getAuthentication().getName(); return this.context.getAuthentication().getName();
} }
private String getChangedSecurityName() { private String getChangedSecurityName() {
return changedContext.getAuthentication().getName(); return this.changedContext.getAuthentication().getName();
} }
@Configuration @Configuration

View File

@@ -62,7 +62,8 @@ public class EnableRedisHttpSessionExpireSessionDestroyedTests<S extends Expirin
public void expireFiresSessionExpiredEvent() throws InterruptedException { public void expireFiresSessionExpiredEvent() throws InterruptedException {
S toSave = this.repository.createSession(); S toSave = this.repository.createSession();
toSave.setAttribute("a", "b"); toSave.setAttribute("a", "b");
Authentication toSaveToken = new UsernamePasswordAuthenticationToken("user", "password", AuthorityUtils.createAuthorityList("ROLE_USER")); Authentication toSaveToken = new UsernamePasswordAuthenticationToken("user",
"password", AuthorityUtils.createAuthorityList("ROLE_USER"));
SecurityContext toSaveContext = SecurityContextHolder.createEmptyContext(); SecurityContext toSaveContext = SecurityContextHolder.createEmptyContext();
toSaveContext.setAuthentication(toSaveToken); toSaveContext.setAuthentication(toSaveToken);
toSave.setAttribute("SPRING_SECURITY_CONTEXT", toSaveContext); toSave.setAttribute("SPRING_SECURITY_CONTEXT", toSaveContext);
@@ -86,7 +87,8 @@ public class EnableRedisHttpSessionExpireSessionDestroyedTests<S extends Expirin
assertThat(this.registry.receivedEvent()).isTrue(); assertThat(this.registry.receivedEvent()).isTrue();
} }
static class SessionExpiredEventRegistry implements ApplicationListener<SessionExpiredEvent> { static class SessionExpiredEventRegistry
implements ApplicationListener<SessionExpiredEvent> {
private boolean receivedEvent; private boolean receivedEvent;
private Object lock; private Object lock;

View File

@@ -53,9 +53,10 @@ public class RedisListenerContainerTaskExecutorITests {
RedisOperations<Object, Object> redis; RedisOperations<Object, Object> redis;
@Test @Test
public void testRedisDelEventsAreDispatchedInSessionTaskExecutor() throws InterruptedException { public void testRedisDelEventsAreDispatchedInSessionTaskExecutor()
BoundSetOperations<Object, Object> ops = this.redis throws InterruptedException {
.boundSetOps("spring:session:RedisListenerContainerTaskExecutorITests:expirations:dummy"); BoundSetOperations<Object, Object> ops = this.redis.boundSetOps(
"spring:session:RedisListenerContainerTaskExecutorITests:expirations:dummy");
ops.add("value"); ops.add("value");
ops.remove("value"); ops.remove("value");
assertThat(this.executor.taskDispatched()).isTrue(); assertThat(this.executor.taskDispatched()).isTrue();

View File

@@ -33,8 +33,8 @@ import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.util.SocketUtils; import org.springframework.util.SocketUtils;
/** /**
* Integration tests that check the underlying data source - in this case * Integration tests that check the underlying data source - in this case Hazelcast
* Hazelcast Client. * Client.
* *
* @author Vedran Pavic * @author Vedran Pavic
* @author Artem Bilan * @author Artem Bilan
@@ -50,7 +50,6 @@ public class HazelcastClientRepositoryITests<S extends ExpiringSession>
private static HazelcastInstance hazelcastInstance; private static HazelcastInstance hazelcastInstance;
@BeforeClass @BeforeClass
public static void setup() { public static void setup() {
hazelcastInstance = HazelcastITestUtils.embeddedHazelcastServer(PORT); hazelcastInstance = HazelcastITestUtils.embeddedHazelcastServer(PORT);
@@ -70,8 +69,7 @@ public class HazelcastClientRepositoryITests<S extends ExpiringSession>
@Bean @Bean
public HazelcastInstance embeddedHazelcastClient() { public HazelcastInstance embeddedHazelcastClient() {
ClientConfig clientConfig = new ClientConfig(); ClientConfig clientConfig = new ClientConfig();
clientConfig.getNetworkConfig() clientConfig.getNetworkConfig().addAddress("127.0.0.1:" + PORT);
.addAddress("127.0.0.1:" + PORT);
return HazelcastClient.newHazelcastClient(clientConfig); return HazelcastClient.newHazelcastClient(clientConfig);
} }

View File

@@ -39,8 +39,7 @@ public final class HazelcastITestUtils {
*/ */
public static HazelcastInstance embeddedHazelcastServer(int port) { public static HazelcastInstance embeddedHazelcastServer(int port) {
Config config = new Config(); Config config = new Config();
config.getNetworkConfig() config.getNetworkConfig().setPort(port);
.setPort(port);
return Hazelcast.newHazelcastInstance(config); return Hazelcast.newHazelcastInstance(config);
} }

View File

@@ -28,8 +28,8 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.context.web.WebAppConfiguration;
/** /**
* Integration tests that check the underlying data source - in this case * Integration tests that check the underlying data source - in this case Hazelcast
* Hazelcast Server. * Server.
* *
* @author Tommy Ludwig * @author Tommy Ludwig
* @author Vedran Pavic * @author Vedran Pavic

View File

@@ -45,9 +45,9 @@ import org.springframework.test.context.web.WebAppConfiguration;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
/** /**
* Ensure that the appropriate SessionEvents are fired at the expected times. * Ensure that the appropriate SessionEvents are fired at the expected times. Additionally
* Additionally ensure that the interactions with the {@link SessionRepository} * ensure that the interactions with the {@link SessionRepository} abstraction behave as
* abstraction behave as expected after each SessionEvent. * expected after each SessionEvent.
* *
* @author Tommy Ludwig * @author Tommy Ludwig
*/ */
@@ -78,22 +78,27 @@ public class EnableHazelcastHttpSessionEventsTests<S extends ExpiringSession> {
String expectedAttributeName = "a"; String expectedAttributeName = "a";
String expectedAttributeValue = "b"; String expectedAttributeValue = "b";
sessionToSave.setAttribute(expectedAttributeName, expectedAttributeValue); sessionToSave.setAttribute(expectedAttributeName, expectedAttributeValue);
Authentication toSaveToken = new UsernamePasswordAuthenticationToken(username, "password", AuthorityUtils.createAuthorityList("ROLE_USER")); Authentication toSaveToken = new UsernamePasswordAuthenticationToken(username,
"password", AuthorityUtils.createAuthorityList("ROLE_USER"));
SecurityContext toSaveContext = SecurityContextHolder.createEmptyContext(); SecurityContext toSaveContext = SecurityContextHolder.createEmptyContext();
toSaveContext.setAuthentication(toSaveToken); toSaveContext.setAuthentication(toSaveToken);
sessionToSave.setAttribute("SPRING_SECURITY_CONTEXT", toSaveContext); sessionToSave.setAttribute("SPRING_SECURITY_CONTEXT", toSaveContext);
sessionToSave.setAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, username); sessionToSave.setAttribute(
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, username);
this.repository.save(sessionToSave); this.repository.save(sessionToSave);
assertThat(this.registry.receivedEvent(sessionToSave.getId())).isTrue(); assertThat(this.registry.receivedEvent(sessionToSave.getId())).isTrue();
assertThat(this.registry.getEvent(sessionToSave.getId())).isInstanceOf(SessionCreatedEvent.class); assertThat(this.registry.getEvent(sessionToSave.getId()))
.isInstanceOf(SessionCreatedEvent.class);
Session session = this.repository.getSession(sessionToSave.getId()); Session session = this.repository.getSession(sessionToSave.getId());
assertThat(session.getId()).isEqualTo(sessionToSave.getId()); assertThat(session.getId()).isEqualTo(sessionToSave.getId());
assertThat(session.getAttributeNames()).isEqualTo(sessionToSave.getAttributeNames()); assertThat(session.getAttributeNames())
assertThat(session.getAttribute(expectedAttributeName)).isEqualTo(sessionToSave.getAttribute(expectedAttributeName)); .isEqualTo(sessionToSave.getAttributeNames());
assertThat(session.getAttribute(expectedAttributeName))
.isEqualTo(sessionToSave.getAttribute(expectedAttributeName));
} }
@Test @Test
@@ -103,13 +108,16 @@ public class EnableHazelcastHttpSessionEventsTests<S extends ExpiringSession> {
this.repository.save(sessionToSave); this.repository.save(sessionToSave);
assertThat(this.registry.receivedEvent(sessionToSave.getId())).isTrue(); assertThat(this.registry.receivedEvent(sessionToSave.getId())).isTrue();
assertThat(this.registry.getEvent(sessionToSave.getId())).isInstanceOf(SessionCreatedEvent.class); assertThat(this.registry.getEvent(sessionToSave.getId()))
.isInstanceOf(SessionCreatedEvent.class);
this.registry.clear(); this.registry.clear();
assertThat(sessionToSave.getMaxInactiveIntervalInSeconds()).isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS); assertThat(sessionToSave.getMaxInactiveIntervalInSeconds())
.isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
assertThat(this.registry.receivedEvent(sessionToSave.getId())).isTrue(); assertThat(this.registry.receivedEvent(sessionToSave.getId())).isTrue();
assertThat(this.registry.getEvent(sessionToSave.getId())).isInstanceOf(SessionExpiredEvent.class); assertThat(this.registry.getEvent(sessionToSave.getId()))
.isInstanceOf(SessionExpiredEvent.class);
assertThat(this.repository.getSession(sessionToSave.getId())).isNull(); assertThat(this.repository.getSession(sessionToSave.getId())).isNull();
} }
@@ -121,13 +129,15 @@ public class EnableHazelcastHttpSessionEventsTests<S extends ExpiringSession> {
this.repository.save(sessionToSave); this.repository.save(sessionToSave);
assertThat(this.registry.receivedEvent(sessionToSave.getId())).isTrue(); assertThat(this.registry.receivedEvent(sessionToSave.getId())).isTrue();
assertThat(this.registry.getEvent(sessionToSave.getId())).isInstanceOf(SessionCreatedEvent.class); assertThat(this.registry.getEvent(sessionToSave.getId()))
.isInstanceOf(SessionCreatedEvent.class);
this.registry.clear(); this.registry.clear();
this.repository.delete(sessionToSave.getId()); this.repository.delete(sessionToSave.getId());
assertThat(this.registry.receivedEvent(sessionToSave.getId())).isTrue(); assertThat(this.registry.receivedEvent(sessionToSave.getId())).isTrue();
assertThat(this.registry.getEvent(sessionToSave.getId())).isInstanceOf(SessionDeletedEvent.class); assertThat(this.registry.getEvent(sessionToSave.getId()))
.isInstanceOf(SessionDeletedEvent.class);
assertThat(this.repository.getSession(sessionToSave.getId())).isNull(); assertThat(this.repository.getSession(sessionToSave.getId())).isNull();
} }

View File

@@ -37,8 +37,8 @@ import org.springframework.util.SocketUtils;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
/** /**
* Test the different configuration options for the * Test the different configuration options for the {@link EnableHazelcastHttpSession}
* {@link EnableHazelcastHttpSession} annotation. * annotation.
* *
* @author Tommy Ludwig * @author Tommy Ludwig
*/ */

View File

@@ -73,24 +73,27 @@ public class JdbcOperationsSessionRepositoryITests {
@Before @Before
public void setup() throws Exception { public void setup() throws Exception {
this.context = SecurityContextHolder.createEmptyContext(); this.context = SecurityContextHolder.createEmptyContext();
this.context.setAuthentication(new UsernamePasswordAuthenticationToken( this.context.setAuthentication(
"username-" + UUID.randomUUID(), "na", AuthorityUtils.createAuthorityList("ROLE_USER"))); new UsernamePasswordAuthenticationToken("username-" + UUID.randomUUID(),
"na", AuthorityUtils.createAuthorityList("ROLE_USER")));
this.changedContext = SecurityContextHolder.createEmptyContext(); this.changedContext = SecurityContextHolder.createEmptyContext();
this.changedContext.setAuthentication(new UsernamePasswordAuthenticationToken( this.changedContext.setAuthentication(new UsernamePasswordAuthenticationToken(
"changedContext-" + UUID.randomUUID(), "na", AuthorityUtils.createAuthorityList("ROLE_USER"))); "changedContext-" + UUID.randomUUID(), "na",
AuthorityUtils.createAuthorityList("ROLE_USER")));
} }
@Test @Test
public void saves() throws InterruptedException { public void saves() throws InterruptedException {
String username = "saves-" + System.currentTimeMillis(); String username = "saves-" + System.currentTimeMillis();
JdbcOperationsSessionRepository.JdbcSession toSave = this.repository.createSession(); JdbcOperationsSessionRepository.JdbcSession toSave = this.repository
.createSession();
String expectedAttributeName = "a"; String expectedAttributeName = "a";
String expectedAttributeValue = "b"; String expectedAttributeValue = "b";
toSave.setAttribute(expectedAttributeName, expectedAttributeValue); toSave.setAttribute(expectedAttributeName, expectedAttributeValue);
Authentication toSaveToken = new UsernamePasswordAuthenticationToken(username, "password", Authentication toSaveToken = new UsernamePasswordAuthenticationToken(username,
AuthorityUtils.createAuthorityList("ROLE_USER")); "password", AuthorityUtils.createAuthorityList("ROLE_USER"));
SecurityContext toSaveContext = SecurityContextHolder.createEmptyContext(); SecurityContext toSaveContext = SecurityContextHolder.createEmptyContext();
toSaveContext.setAuthentication(toSaveToken); toSaveContext.setAuthentication(toSaveToken);
toSave.setAttribute(SPRING_SECURITY_CONTEXT, toSaveContext); toSave.setAttribute(SPRING_SECURITY_CONTEXT, toSaveContext);
@@ -102,7 +105,8 @@ public class JdbcOperationsSessionRepositoryITests {
assertThat(session.getId()).isEqualTo(toSave.getId()); assertThat(session.getId()).isEqualTo(toSave.getId());
assertThat(session.getAttributeNames()).isEqualTo(toSave.getAttributeNames()); assertThat(session.getAttributeNames()).isEqualTo(toSave.getAttributeNames());
assertThat(session.getAttribute(expectedAttributeName)).isEqualTo(toSave.getAttribute(expectedAttributeName)); assertThat(session.getAttribute(expectedAttributeName))
.isEqualTo(toSave.getAttribute(expectedAttributeName));
this.repository.delete(toSave.getId()); this.repository.delete(toSave.getId());
@@ -111,7 +115,8 @@ public class JdbcOperationsSessionRepositoryITests {
@Test @Test
public void putAllOnSingleAttrDoesNotRemoveOld() { public void putAllOnSingleAttrDoesNotRemoveOld() {
JdbcOperationsSessionRepository.JdbcSession toSave = this.repository.createSession(); JdbcOperationsSessionRepository.JdbcSession toSave = this.repository
.createSession();
toSave.setAttribute("a", "b"); toSave.setAttribute("a", "b");
this.repository.save(toSave); this.repository.save(toSave);
@@ -133,20 +138,22 @@ public class JdbcOperationsSessionRepositoryITests {
@Test @Test
public void findByPrincipalName() throws Exception { public void findByPrincipalName() throws Exception {
String principalName = "findByPrincipalName" + UUID.randomUUID(); String principalName = "findByPrincipalName" + UUID.randomUUID();
JdbcOperationsSessionRepository.JdbcSession toSave = this.repository.createSession(); JdbcOperationsSessionRepository.JdbcSession toSave = this.repository
.createSession();
toSave.setAttribute(INDEX_NAME, principalName); toSave.setAttribute(INDEX_NAME, principalName);
this.repository.save(toSave); this.repository.save(toSave);
Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = this.repository
this.repository.findByIndexNameAndIndexValue(INDEX_NAME, principalName); .findByIndexNameAndIndexValue(INDEX_NAME, principalName);
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
this.repository.delete(toSave.getId()); this.repository.delete(toSave.getId());
findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME, principalName); findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME,
principalName);
assertThat(findByPrincipalName).hasSize(0); assertThat(findByPrincipalName).hasSize(0);
assertThat(findByPrincipalName.keySet()).doesNotContain(toSave.getId()); assertThat(findByPrincipalName.keySet()).doesNotContain(toSave.getId());
@@ -154,17 +161,19 @@ public class JdbcOperationsSessionRepositoryITests {
@Test @Test
public void findByPrincipalNameExpireRemovesIndex() throws Exception { public void findByPrincipalNameExpireRemovesIndex() throws Exception {
String principalName = "findByPrincipalNameExpireRemovesIndex" + UUID.randomUUID(); String principalName = "findByPrincipalNameExpireRemovesIndex"
JdbcOperationsSessionRepository.JdbcSession toSave = this.repository.createSession(); + UUID.randomUUID();
JdbcOperationsSessionRepository.JdbcSession toSave = this.repository
.createSession();
toSave.setAttribute(INDEX_NAME, principalName); toSave.setAttribute(INDEX_NAME, principalName);
toSave.setLastAccessedTime(System.currentTimeMillis() - toSave.setLastAccessedTime(System.currentTimeMillis()
(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS * 1000 + 1000)); - (MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS * 1000 + 1000));
this.repository.save(toSave); this.repository.save(toSave);
this.repository.cleanUpExpiredSessions(); this.repository.cleanUpExpiredSessions();
Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = this.repository
this.repository.findByIndexNameAndIndexValue(INDEX_NAME, principalName); .findByIndexNameAndIndexValue(INDEX_NAME, principalName);
assertThat(findByPrincipalName).hasSize(0); assertThat(findByPrincipalName).hasSize(0);
assertThat(findByPrincipalName.keySet()).doesNotContain(toSave.getId()); assertThat(findByPrincipalName.keySet()).doesNotContain(toSave.getId());
@@ -172,8 +181,10 @@ public class JdbcOperationsSessionRepositoryITests {
@Test @Test
public void findByPrincipalNameNoPrincipalNameChange() throws Exception { public void findByPrincipalNameNoPrincipalNameChange() throws Exception {
String principalName = "findByPrincipalNameNoPrincipalNameChange" + UUID.randomUUID(); String principalName = "findByPrincipalNameNoPrincipalNameChange"
JdbcOperationsSessionRepository.JdbcSession toSave = this.repository.createSession(); + UUID.randomUUID();
JdbcOperationsSessionRepository.JdbcSession toSave = this.repository
.createSession();
toSave.setAttribute(INDEX_NAME, principalName); toSave.setAttribute(INDEX_NAME, principalName);
this.repository.save(toSave); this.repository.save(toSave);
@@ -181,8 +192,8 @@ public class JdbcOperationsSessionRepositoryITests {
toSave.setAttribute("other", "value"); toSave.setAttribute("other", "value");
this.repository.save(toSave); this.repository.save(toSave);
Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = this.repository
this.repository.findByIndexNameAndIndexValue(INDEX_NAME, principalName); .findByIndexNameAndIndexValue(INDEX_NAME, principalName);
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
@@ -190,8 +201,10 @@ public class JdbcOperationsSessionRepositoryITests {
@Test @Test
public void findByPrincipalNameNoPrincipalNameChangeReload() throws Exception { public void findByPrincipalNameNoPrincipalNameChangeReload() throws Exception {
String principalName = "findByPrincipalNameNoPrincipalNameChangeReload" + UUID.randomUUID(); String principalName = "findByPrincipalNameNoPrincipalNameChangeReload"
JdbcOperationsSessionRepository.JdbcSession toSave = this.repository.createSession(); + UUID.randomUUID();
JdbcOperationsSessionRepository.JdbcSession toSave = this.repository
.createSession();
toSave.setAttribute(INDEX_NAME, principalName); toSave.setAttribute(INDEX_NAME, principalName);
this.repository.save(toSave); this.repository.save(toSave);
@@ -201,8 +214,8 @@ public class JdbcOperationsSessionRepositoryITests {
toSave.setAttribute("other", "value"); toSave.setAttribute("other", "value");
this.repository.save(toSave); this.repository.save(toSave);
Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = this.repository
this.repository.findByIndexNameAndIndexValue(INDEX_NAME, principalName); .findByIndexNameAndIndexValue(INDEX_NAME, principalName);
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
@@ -211,7 +224,8 @@ public class JdbcOperationsSessionRepositoryITests {
@Test @Test
public void findByDeletedPrincipalName() throws Exception { public void findByDeletedPrincipalName() throws Exception {
String principalName = "findByDeletedPrincipalName" + UUID.randomUUID(); String principalName = "findByDeletedPrincipalName" + UUID.randomUUID();
JdbcOperationsSessionRepository.JdbcSession toSave = this.repository.createSession(); JdbcOperationsSessionRepository.JdbcSession toSave = this.repository
.createSession();
toSave.setAttribute(INDEX_NAME, principalName); toSave.setAttribute(INDEX_NAME, principalName);
this.repository.save(toSave); this.repository.save(toSave);
@@ -219,8 +233,8 @@ public class JdbcOperationsSessionRepositoryITests {
toSave.setAttribute(INDEX_NAME, null); toSave.setAttribute(INDEX_NAME, null);
this.repository.save(toSave); this.repository.save(toSave);
Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = this.repository
this.repository.findByIndexNameAndIndexValue(INDEX_NAME, principalName); .findByIndexNameAndIndexValue(INDEX_NAME, principalName);
assertThat(findByPrincipalName).isEmpty(); assertThat(findByPrincipalName).isEmpty();
} }
@@ -229,7 +243,8 @@ public class JdbcOperationsSessionRepositoryITests {
public void findByChangedPrincipalName() throws Exception { public void findByChangedPrincipalName() throws Exception {
String principalName = "findByChangedPrincipalName" + UUID.randomUUID(); String principalName = "findByChangedPrincipalName" + UUID.randomUUID();
String principalNameChanged = "findByChangedPrincipalName" + UUID.randomUUID(); String principalNameChanged = "findByChangedPrincipalName" + UUID.randomUUID();
JdbcOperationsSessionRepository.JdbcSession toSave = this.repository.createSession(); JdbcOperationsSessionRepository.JdbcSession toSave = this.repository
.createSession();
toSave.setAttribute(INDEX_NAME, principalName); toSave.setAttribute(INDEX_NAME, principalName);
this.repository.save(toSave); this.repository.save(toSave);
@@ -237,11 +252,12 @@ public class JdbcOperationsSessionRepositoryITests {
toSave.setAttribute(INDEX_NAME, principalNameChanged); toSave.setAttribute(INDEX_NAME, principalNameChanged);
this.repository.save(toSave); this.repository.save(toSave);
Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = this.repository
this.repository.findByIndexNameAndIndexValue(INDEX_NAME, principalName); .findByIndexNameAndIndexValue(INDEX_NAME, principalName);
assertThat(findByPrincipalName).isEmpty(); assertThat(findByPrincipalName).isEmpty();
findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME, principalNameChanged); findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME,
principalNameChanged);
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
@@ -250,17 +266,19 @@ public class JdbcOperationsSessionRepositoryITests {
@Test @Test
public void findByDeletedPrincipalNameReload() throws Exception { public void findByDeletedPrincipalNameReload() throws Exception {
String principalName = "findByDeletedPrincipalName" + UUID.randomUUID(); String principalName = "findByDeletedPrincipalName" + UUID.randomUUID();
JdbcOperationsSessionRepository.JdbcSession toSave = this.repository.createSession(); JdbcOperationsSessionRepository.JdbcSession toSave = this.repository
.createSession();
toSave.setAttribute(INDEX_NAME, principalName); toSave.setAttribute(INDEX_NAME, principalName);
this.repository.save(toSave); this.repository.save(toSave);
JdbcOperationsSessionRepository.JdbcSession getSession = this.repository.getSession(toSave.getId()); JdbcOperationsSessionRepository.JdbcSession getSession = this.repository
.getSession(toSave.getId());
getSession.setAttribute(INDEX_NAME, null); getSession.setAttribute(INDEX_NAME, null);
this.repository.save(getSession); this.repository.save(getSession);
Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = this.repository
this.repository.findByIndexNameAndIndexValue(INDEX_NAME, principalName); .findByIndexNameAndIndexValue(INDEX_NAME, principalName);
assertThat(findByPrincipalName).isEmpty(); assertThat(findByPrincipalName).isEmpty();
} }
@@ -269,21 +287,24 @@ public class JdbcOperationsSessionRepositoryITests {
public void findByChangedPrincipalNameReload() throws Exception { public void findByChangedPrincipalNameReload() throws Exception {
String principalName = "findByChangedPrincipalName" + UUID.randomUUID(); String principalName = "findByChangedPrincipalName" + UUID.randomUUID();
String principalNameChanged = "findByChangedPrincipalName" + UUID.randomUUID(); String principalNameChanged = "findByChangedPrincipalName" + UUID.randomUUID();
JdbcOperationsSessionRepository.JdbcSession toSave = this.repository.createSession(); JdbcOperationsSessionRepository.JdbcSession toSave = this.repository
.createSession();
toSave.setAttribute(INDEX_NAME, principalName); toSave.setAttribute(INDEX_NAME, principalName);
this.repository.save(toSave); this.repository.save(toSave);
JdbcOperationsSessionRepository.JdbcSession getSession = this.repository.getSession(toSave.getId()); JdbcOperationsSessionRepository.JdbcSession getSession = this.repository
.getSession(toSave.getId());
getSession.setAttribute(INDEX_NAME, principalNameChanged); getSession.setAttribute(INDEX_NAME, principalNameChanged);
this.repository.save(getSession); this.repository.save(getSession);
Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = this.repository
this.repository.findByIndexNameAndIndexValue(INDEX_NAME, principalName); .findByIndexNameAndIndexValue(INDEX_NAME, principalName);
assertThat(findByPrincipalName).isEmpty(); assertThat(findByPrincipalName).isEmpty();
findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME, principalNameChanged); findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME,
principalNameChanged);
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
@@ -291,20 +312,22 @@ public class JdbcOperationsSessionRepositoryITests {
@Test @Test
public void findBySecurityPrincipalName() throws Exception { public void findBySecurityPrincipalName() throws Exception {
JdbcOperationsSessionRepository.JdbcSession toSave = this.repository.createSession(); JdbcOperationsSessionRepository.JdbcSession toSave = this.repository
.createSession();
toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context);
this.repository.save(toSave); this.repository.save(toSave);
Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = this.repository
this.repository.findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName()); .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName());
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
this.repository.delete(toSave.getId()); this.repository.delete(toSave.getId());
findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName()); findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME,
getSecurityName());
assertThat(findByPrincipalName).hasSize(0); assertThat(findByPrincipalName).hasSize(0);
assertThat(findByPrincipalName.keySet()).doesNotContain(toSave.getId()); assertThat(findByPrincipalName.keySet()).doesNotContain(toSave.getId());
@@ -312,16 +335,17 @@ public class JdbcOperationsSessionRepositoryITests {
@Test @Test
public void findBySecurityPrincipalNameExpireRemovesIndex() throws Exception { public void findBySecurityPrincipalNameExpireRemovesIndex() throws Exception {
JdbcOperationsSessionRepository.JdbcSession toSave = this.repository.createSession(); JdbcOperationsSessionRepository.JdbcSession toSave = this.repository
.createSession();
toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context);
toSave.setLastAccessedTime(System.currentTimeMillis() - toSave.setLastAccessedTime(System.currentTimeMillis()
(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS * 1000 + 1000)); - (MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS * 1000 + 1000));
this.repository.save(toSave); this.repository.save(toSave);
this.repository.cleanUpExpiredSessions(); this.repository.cleanUpExpiredSessions();
Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = this.repository
this.repository.findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName()); .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName());
assertThat(findByPrincipalName).hasSize(0); assertThat(findByPrincipalName).hasSize(0);
assertThat(findByPrincipalName.keySet()).doesNotContain(toSave.getId()); assertThat(findByPrincipalName.keySet()).doesNotContain(toSave.getId());
@@ -329,7 +353,8 @@ public class JdbcOperationsSessionRepositoryITests {
@Test @Test
public void findByPrincipalNameNoSecurityPrincipalNameChange() throws Exception { public void findByPrincipalNameNoSecurityPrincipalNameChange() throws Exception {
JdbcOperationsSessionRepository.JdbcSession toSave = this.repository.createSession(); JdbcOperationsSessionRepository.JdbcSession toSave = this.repository
.createSession();
toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context);
this.repository.save(toSave); this.repository.save(toSave);
@@ -337,16 +362,18 @@ public class JdbcOperationsSessionRepositoryITests {
toSave.setAttribute("other", "value"); toSave.setAttribute("other", "value");
this.repository.save(toSave); this.repository.save(toSave);
Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = this.repository
this.repository.findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName()); .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName());
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
} }
@Test @Test
public void findByPrincipalNameNoSecurityPrincipalNameChangeReload() throws Exception { public void findByPrincipalNameNoSecurityPrincipalNameChangeReload()
JdbcOperationsSessionRepository.JdbcSession toSave = this.repository.createSession(); throws Exception {
JdbcOperationsSessionRepository.JdbcSession toSave = this.repository
.createSession();
toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context);
this.repository.save(toSave); this.repository.save(toSave);
@@ -356,8 +383,8 @@ public class JdbcOperationsSessionRepositoryITests {
toSave.setAttribute("other", "value"); toSave.setAttribute("other", "value");
this.repository.save(toSave); this.repository.save(toSave);
Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = this.repository
this.repository.findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName()); .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName());
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
@@ -365,7 +392,8 @@ public class JdbcOperationsSessionRepositoryITests {
@Test @Test
public void findByDeletedSecurityPrincipalName() throws Exception { public void findByDeletedSecurityPrincipalName() throws Exception {
JdbcOperationsSessionRepository.JdbcSession toSave = this.repository.createSession(); JdbcOperationsSessionRepository.JdbcSession toSave = this.repository
.createSession();
toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context);
this.repository.save(toSave); this.repository.save(toSave);
@@ -373,15 +401,16 @@ public class JdbcOperationsSessionRepositoryITests {
toSave.setAttribute(SPRING_SECURITY_CONTEXT, null); toSave.setAttribute(SPRING_SECURITY_CONTEXT, null);
this.repository.save(toSave); this.repository.save(toSave);
Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = this.repository
this.repository.findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName()); .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName());
assertThat(findByPrincipalName).isEmpty(); assertThat(findByPrincipalName).isEmpty();
} }
@Test @Test
public void findByChangedSecurityPrincipalName() throws Exception { public void findByChangedSecurityPrincipalName() throws Exception {
JdbcOperationsSessionRepository.JdbcSession toSave = this.repository.createSession(); JdbcOperationsSessionRepository.JdbcSession toSave = this.repository
.createSession();
toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context);
this.repository.save(toSave); this.repository.save(toSave);
@@ -389,11 +418,12 @@ public class JdbcOperationsSessionRepositoryITests {
toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.changedContext); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.changedContext);
this.repository.save(toSave); this.repository.save(toSave);
Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = this.repository
this.repository.findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName()); .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName());
assertThat(findByPrincipalName).isEmpty(); assertThat(findByPrincipalName).isEmpty();
findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME, getChangedSecurityName()); findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME,
getChangedSecurityName());
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
@@ -401,38 +431,43 @@ public class JdbcOperationsSessionRepositoryITests {
@Test @Test
public void findByDeletedSecurityPrincipalNameReload() throws Exception { public void findByDeletedSecurityPrincipalNameReload() throws Exception {
JdbcOperationsSessionRepository.JdbcSession toSave = this.repository.createSession(); JdbcOperationsSessionRepository.JdbcSession toSave = this.repository
.createSession();
toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context);
this.repository.save(toSave); this.repository.save(toSave);
JdbcOperationsSessionRepository.JdbcSession getSession = this.repository.getSession(toSave.getId()); JdbcOperationsSessionRepository.JdbcSession getSession = this.repository
.getSession(toSave.getId());
getSession.setAttribute(INDEX_NAME, null); getSession.setAttribute(INDEX_NAME, null);
this.repository.save(getSession); this.repository.save(getSession);
Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = this.repository
this.repository.findByIndexNameAndIndexValue(INDEX_NAME, getChangedSecurityName()); .findByIndexNameAndIndexValue(INDEX_NAME, getChangedSecurityName());
assertThat(findByPrincipalName).isEmpty(); assertThat(findByPrincipalName).isEmpty();
} }
@Test @Test
public void findByChangedSecurityPrincipalNameReload() throws Exception { public void findByChangedSecurityPrincipalNameReload() throws Exception {
JdbcOperationsSessionRepository.JdbcSession toSave = this.repository.createSession(); JdbcOperationsSessionRepository.JdbcSession toSave = this.repository
.createSession();
toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context);
this.repository.save(toSave); this.repository.save(toSave);
JdbcOperationsSessionRepository.JdbcSession getSession = this.repository.getSession(toSave.getId()); JdbcOperationsSessionRepository.JdbcSession getSession = this.repository
.getSession(toSave.getId());
getSession.setAttribute(SPRING_SECURITY_CONTEXT, this.changedContext); getSession.setAttribute(SPRING_SECURITY_CONTEXT, this.changedContext);
repository.save(getSession); this.repository.save(getSession);
Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = Map<String, JdbcOperationsSessionRepository.JdbcSession> findByPrincipalName = this.repository
this.repository.findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName()); .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName());
assertThat(findByPrincipalName).isEmpty(); assertThat(findByPrincipalName).isEmpty();
findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME, getChangedSecurityName()); findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME,
getChangedSecurityName());
assertThat(findByPrincipalName).hasSize(1); assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
@@ -452,10 +487,8 @@ public class JdbcOperationsSessionRepositoryITests {
@Bean @Bean
public EmbeddedDatabase dataSource() { public EmbeddedDatabase dataSource() {
return new EmbeddedDatabaseBuilder() return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2)
.setType(EmbeddedDatabaseType.H2) .addScript("org/springframework/session/jdbc/schema-h2.sql").build();
.addScript("org/springframework/session/jdbc/schema-h2.sql")
.build();
} }
@Bean @Bean

View File

@@ -17,7 +17,8 @@
package org.springframework.session; package org.springframework.session;
/** /**
* A {@link Session} that contains additional attributes that are useful for determining if a session is expired. * A {@link Session} that contains additional attributes that are useful for determining
* if a session is expired.
* *
* @author Rob Winch * @author Rob Winch
* @since 1.0 * @since 1.0
@@ -25,37 +26,47 @@ package org.springframework.session;
public interface ExpiringSession extends Session { public interface ExpiringSession extends Session {
/** /**
* Gets the time when this session was created in milliseconds since midnight of 1/1/1970 GMT. * 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. * @return the time when this session was created in milliseconds since midnight of
* 1/1/1970 GMT.
*/ */
long getCreationTime(); long getCreationTime();
/** /**
* Sets the last accessed time in milliseconds since midnight of 1/1/1970 GMT. * Sets the last accessed time in milliseconds since midnight of 1/1/1970 GMT.
* *
* @param lastAccessedTime the last accessed time in milliseconds since midnight of 1/1/1970 GMT * @param lastAccessedTime the last accessed time in milliseconds since midnight of
* 1/1/1970 GMT
*/ */
void setLastAccessedTime(long lastAccessedTime); void setLastAccessedTime(long lastAccessedTime);
/** /**
* Gets the last time this {@link Session} was accessed expressed in milliseconds since midnight of 1/1/1970 GMT. * 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 * @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(); 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. * 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. * @param interval the number of seconds that the {@link Session} should be kept alive
* between client requests.
*/ */
void setMaxInactiveIntervalInSeconds(int interval); 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. * 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. * @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(); int getMaxInactiveIntervalInSeconds();

View File

@@ -19,16 +19,16 @@ package org.springframework.session;
import java.util.Map; import java.util.Map;
/** /**
* Extends a basic {@link SessionRepository} to allow finding a session id by * Extends a basic {@link SessionRepository} to allow finding a session id by the
* the principal name. The principal name is defined by the {@link Session} * principal name. The principal name is defined by the {@link Session} attribute with the
* attribute with the name {@link FindByIndexNameSessionRepository#PRINCIPAL_NAME_INDEX_NAME}. * name {@link FindByIndexNameSessionRepository#PRINCIPAL_NAME_INDEX_NAME}.
* *
* @param <S> * @param <S> the type of Session being managed by this
* the type of Session being managed by this
* {@link FindByIndexNameSessionRepository} * {@link FindByIndexNameSessionRepository}
* @author Rob Winch * @author Rob Winch
*/ */
public interface FindByIndexNameSessionRepository<S extends Session> extends SessionRepository<S> { public interface FindByIndexNameSessionRepository<S extends Session>
extends SessionRepository<S> {
/** /**
* <p> * <p>
@@ -37,28 +37,27 @@ public interface FindByIndexNameSessionRepository<S extends Session> extends Ses
* </p> * </p>
* *
* <p> * <p>
* It is the responsibility of the developer to ensure the attribute * It is the responsibility of the developer to ensure the attribute is populated
* is populated since Spring Session is not aware of the authentication * since Spring Session is not aware of the authentication mechanism being used.
* mechanism being used.
* </p> * </p>
* *
* @since 1.1 * @since 1.1
*/ */
String PRINCIPAL_NAME_INDEX_NAME = FindByIndexNameSessionRepository.class.getName().concat(".PRINCIPAL_NAME_INDEX_NAME"); String PRINCIPAL_NAME_INDEX_NAME = FindByIndexNameSessionRepository.class.getName()
.concat(".PRINCIPAL_NAME_INDEX_NAME");
/** /**
* Find a Map of the session id to the {@link Session} of all sessions that * Find a Map of the session id to the {@link Session} of all sessions that contain
* contain the session attribute with the name * the session attribute with the name
* {@link FindByIndexNameSessionRepository#PRINCIPAL_NAME_INDEX_NAME} and * {@link FindByIndexNameSessionRepository#PRINCIPAL_NAME_INDEX_NAME} and the value of
* the value of the specified principal name. * the specified principal name.
* *
* @param indexName * @param indexName the name if the index (i.e.
* the name if the index (i.e. {@link FindByIndexNameSessionRepository#PRINCIPAL_NAME_INDEX_NAME}) * {@link FindByIndexNameSessionRepository#PRINCIPAL_NAME_INDEX_NAME})
* @param indexValue the value of the index to search for. * @param indexValue the value of the index to search for.
* @return a Map (never null) of the session id to the {@link Session} of * @return a Map (never null) of the session id to the {@link Session} of all sessions
* all sessions that contain the session specified index name and * that contain the session specified index name and the value of the specified index
* the value of the specified index name. If no results are found, * name. If no results are found, an empty Map is returned.
* an empty Map is returned.
*/ */
Map<String, S> findByIndexNameAndIndexValue(String indexName, String indexValue); Map<String, S> findByIndexNameAndIndexValue(String indexName, String indexValue);
} }

View File

@@ -25,7 +25,8 @@ import java.util.concurrent.TimeUnit;
/** /**
* <p> * <p>
* A {@link Session} implementation that is backed by a {@link java.util.Map}. The defaults for the properties are: * A {@link Session} implementation that is backed by a {@link java.util.Map}. The
* defaults for the properties are:
* </p> * </p>
* <ul> * <ul>
* <li>id - a secure random generated id</li> * <li>id - a secure random generated id</li>
@@ -35,7 +36,8 @@ import java.util.concurrent.TimeUnit;
* </ul> * </ul>
* *
* <p> * <p>
* This implementation has no synchronization, so it is best to use the copy constructor when working on multiple threads. * This implementation has no synchronization, so it is best to use the copy constructor
* when working on multiple threads.
* </p> * </p>
* *
* @author Rob Winch * @author Rob Winch
@@ -65,9 +67,9 @@ public final class MapSession implements ExpiringSession, Serializable {
} }
/** /**
* Creates a new instance with the specified id. This is preferred to the * Creates a new instance with the specified id. This is preferred to the default
* default constructor when the id is known to prevent unnecessary consumption on * constructor when the id is known to prevent unnecessary consumption on entropy
* entropy which can be slow. * which can be slow.
* *
* @param id the identifier to use * @param id the identifier to use
*/ */
@@ -78,14 +80,16 @@ public final class MapSession implements ExpiringSession, Serializable {
/** /**
* Creates a new instance from the provided {@link Session}. * Creates a new instance from the provided {@link Session}.
* *
* @param session the {@link Session} to initialize this {@link Session} with. Cannot be null. * @param session the {@link Session} to initialize this {@link Session} with. Cannot
* be null.
*/ */
public MapSession(ExpiringSession session) { public MapSession(ExpiringSession session) {
if (session == null) { if (session == null) {
throw new IllegalArgumentException("session cannot be null"); throw new IllegalArgumentException("session cannot be null");
} }
this.id = session.getId(); this.id = session.getId();
this.sessionAttrs = new HashMap<String, Object>(session.getAttributeNames().size()); this.sessionAttrs = new HashMap<String, Object>(
session.getAttributeNames().size());
for (String attrName : session.getAttributeNames()) { for (String attrName : session.getAttributeNames()) {
Object attrValue = session.getAttribute(attrName); Object attrValue = session.getAttribute(attrName);
this.sessionAttrs.put(attrName, attrValue); this.sessionAttrs.put(attrName, attrValue);
@@ -127,7 +131,8 @@ public final class MapSession implements ExpiringSession, Serializable {
if (this.maxInactiveInterval < 0) { if (this.maxInactiveInterval < 0) {
return false; return false;
} }
return now - TimeUnit.SECONDS.toMillis(this.maxInactiveInterval) >= this.lastAccessedTime; return now - TimeUnit.SECONDS
.toMillis(this.maxInactiveInterval) >= this.lastAccessedTime;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -153,15 +158,19 @@ public final class MapSession implements ExpiringSession, Serializable {
} }
/** /**
* 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. * Sets the time that this {@link Session} was created in milliseconds since midnight
* @param creationTime the time that this {@link Session} was created in milliseconds since midnight of 1/1/1970 GMT. * 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) { public void setCreationTime(long creationTime) {
this.creationTime = 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. * 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. * @param id the identifier for this session.
*/ */

View File

@@ -23,12 +23,14 @@ import org.springframework.session.events.SessionDeletedEvent;
import org.springframework.session.events.SessionExpiredEvent; import org.springframework.session.events.SessionExpiredEvent;
/** /**
* A {@link SessionRepository} backed by a {@link java.util.Map} and that uses a {@link MapSession}. By default a * A {@link SessionRepository} backed by a {@link java.util.Map} and that uses a
* {@link java.util.concurrent.ConcurrentHashMap} is used, but a custom {@link java.util.Map} can be injected to use * {@link MapSession}. By default a {@link java.util.concurrent.ConcurrentHashMap} is
* distributed maps provided by NoSQL stores like Redis and Hazelcast. * used, but a custom {@link java.util.Map} can be injected to use distributed maps
* provided by NoSQL stores like Redis and Hazelcast.
* *
* <p> * <p>
* The implementation does NOT support firing {@link SessionDeletedEvent} or {@link SessionExpiredEvent}. * The implementation does NOT support firing {@link SessionDeletedEvent} or
* {@link SessionExpiredEvent}.
* </p> * </p>
* *
* @author Rob Winch * @author Rob Winch
@@ -36,7 +38,8 @@ import org.springframework.session.events.SessionExpiredEvent;
*/ */
public class MapSessionRepository implements SessionRepository<ExpiringSession> { public class MapSessionRepository implements SessionRepository<ExpiringSession> {
/** /**
* If non-null, this value is used to override {@link ExpiringSession#setMaxInactiveIntervalInSeconds(int)}. * If non-null, this value is used to override
* {@link ExpiringSession#setMaxInactiveIntervalInSeconds(int)}.
*/ */
private Integer defaultMaxInactiveInterval; private Integer defaultMaxInactiveInterval;
@@ -50,7 +53,8 @@ public class MapSessionRepository implements SessionRepository<ExpiringSession>
} }
/** /**
* Creates a new instance backed by the provided {@link java.util.Map}. This allows injecting a distributed {@link java.util.Map}. * 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. * @param sessions the {@link java.util.Map} to use. Cannot be null.
*/ */
@@ -62,8 +66,10 @@ public class MapSessionRepository implements SessionRepository<ExpiringSession>
} }
/** /**
* If non-null, this value is used to override {@link ExpiringSession#setMaxInactiveIntervalInSeconds(int)}. * If non-null, this value is used to override
* @param defaultMaxInactiveInterval the number of seconds that the {@link Session} should be kept alive between client requests. * {@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) { public void setDefaultMaxInactiveInterval(int defaultMaxInactiveInterval) {
this.defaultMaxInactiveInterval = Integer.valueOf(defaultMaxInactiveInterval); this.defaultMaxInactiveInterval = Integer.valueOf(defaultMaxInactiveInterval);

View File

@@ -19,8 +19,8 @@ package org.springframework.session;
import java.util.Set; import java.util.Set;
/** /**
* Provides a way to identify a user in an agnostic way. This allows the session to be used by an HttpSession, WebSocket * Provides a way to identify a user in an agnostic way. This allows the session to be
* Session, or even non web related sessions. * used by an HttpSession, WebSocket Session, or even non web related sessions.
* *
* @author Rob Winch * @author Rob Winch
* @since 1.0 * @since 1.0
@@ -35,16 +35,20 @@ public interface Session {
String getId(); String getId();
/** /**
* Gets the Object associated with the specified name or null if no Object is associated to that name. * 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 * @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 * @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 * @param <T> The return type of the attribute
*/ */
<T> T getAttribute(String attributeName); <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. * 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. * @return the attribute names that have a value associated with it.
* @see #getAttribute(String) * @see #getAttribute(String)
@@ -52,10 +56,13 @@ public interface Session {
Set<String> getAttributeNames(); 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)} . * 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 attributeName the attribute name to set
* @param attributeValue the value of the attribute to set. If null, the attribute will be removed. * @param attributeValue the value of the attribute to set. If null, the attribute
* will be removed.
*/ */
void setAttribute(String attributeName, Object attributeValue); void setAttribute(String attributeName, Object attributeValue);

View File

@@ -26,22 +26,28 @@ package org.springframework.session;
public interface SessionRepository<S extends Session> { public interface SessionRepository<S extends Session> {
/** /**
* Creates a new {@link Session} that is capable of being persisted by this {@link SessionRepository}. * 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 * <p>
* implementation returned might keep track of the changes ensuring that only the delta needs to be persisted on * This allows optimizations and customizations in how the {@link Session} is
* a save.</p> * 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} * @return a new {@link Session} that is capable of being persisted by this
* {@link SessionRepository}
*/ */
S createSession(); S createSession();
/** /**
* Ensures the {@link Session} created by {@link org.springframework.session.SessionRepository#createSession()} is saved. * Ensures the {@link Session} created by
* {@link org.springframework.session.SessionRepository#createSession()} is saved.
* *
* <p> * <p>
* Some implementations may choose to save as the {@link Session} is updated by returning a {@link Session} that * Some implementations may choose to save as the {@link Session} is updated by
* immediately persists any changes. In this case, this method may not actually do anything. * returning a {@link Session} that immediately persists any changes. In this case,
* this method may not actually do anything.
* </p> * </p>
* *
* @param session the {@link Session} to save * @param session the {@link Session} to save
@@ -49,15 +55,18 @@ public interface SessionRepository<S extends Session> {
void save(S session); void save(S session);
/** /**
* Gets the {@link Session} by the {@link Session#getId()} or null if no {@link Session} is found. * Gets the {@link Session} by the {@link Session#getId()} or null if no
* {@link Session} is found.
* *
* @param id the {@link org.springframework.session.Session#getId()} to lookup * @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. * @return the {@link Session} by the {@link Session#getId()} or null if no
* {@link Session} is found.
*/ */
S getSession(String id); S getSession(String id);
/** /**
* Deletes the {@link Session} with the given {@link Session#getId()} or does nothing if the {@link Session} is not found. * 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 * @param id the {@link org.springframework.session.Session#getId()} to delete
*/ */
void delete(String id); void delete(String id);

View File

@@ -28,10 +28,9 @@ import org.springframework.session.events.SessionDestroyedEvent;
/** /**
* Add this annotation to an {@code @Configuration} class to expose the * Add this annotation to an {@code @Configuration} class to expose the
* SessionRepositoryFilter as a bean named "springSessionRepositoryFilter" and * SessionRepositoryFilter as a bean named "springSessionRepositoryFilter" and backed by a
* backed by a user provided implementation of {@link SessionRepository}. In * user provided implementation of {@link SessionRepository}. In order to leverage the
* order to leverage the annotation, a single {@link SessionRepository} bean * annotation, a single {@link SessionRepository} bean must be provided. For example:
* must be provided. For example:
* *
* <pre> * <pre>
* <code> * <code>
@@ -45,15 +44,13 @@ import org.springframework.session.events.SessionDestroyedEvent;
* } * }
* *
* } * }
* </code> * </code> </pre>
* </pre>
* *
* <p> * <p>
* It is important to note that no infrastructure for session expirations is * It is important to note that no infrastructure for session expirations is configured
* configured for you out of the box. This is because things like session * for you out of the box. This is because things like session expiration are highly
* expiration are highly implementation dependent. This means if you require * implementation dependent. This means if you require cleaning up expired sessions, you
* cleaning up expired sessions, you are responsible for cleaning up the expired * are responsible for cleaning up the expired sessions.
* sessions.
* </p> * </p>
* *
* <p> * <p>
@@ -61,13 +58,12 @@ import org.springframework.session.events.SessionDestroyedEvent;
* </p> * </p>
* *
* <ul> * <ul>
* <li>SessionRepositoryFilter - is responsible for wrapping the * <li>SessionRepositoryFilter - is responsible for wrapping the HttpServletRequest with
* HttpServletRequest with an implementation of HttpSession that is backed by a * an implementation of HttpSession that is backed by a SessionRepository</li>
* SessionRepository</li> * <li>SessionEventHttpSessionListenerAdapter - is responsible for translating Spring
* <li>SessionEventHttpSessionListenerAdapter - is responsible for translating * Session events into HttpSessionEvent. In order for it to work, the implementation of
* Spring Session events into HttpSessionEvent. In order for it to work, the * SessionRepository you provide must support {@link SessionCreatedEvent} and
* implementation of SessionRepository you provide must support * {@link SessionDestroyedEvent}.</li>
* {@link SessionCreatedEvent} and {@link SessionDestroyedEvent}.</li>
* <li> * <li>
* </ul> * </ul>
* *

View File

@@ -37,8 +37,8 @@ import org.springframework.session.web.http.SessionEventHttpSessionListenerAdapt
import org.springframework.session.web.http.SessionRepositoryFilter; import org.springframework.session.web.http.SessionRepositoryFilter;
/** /**
* Configures the basics for setting up Spring Session in a web environment. In * Configures the basics for setting up Spring Session in a web environment. In order to
* order to use it, you must provide a {@link SessionRepository}. For example: * use it, you must provide a {@link SessionRepository}. For example:
* *
* <pre> * <pre>
* {@literal @Configuration} * {@literal @Configuration}
@@ -54,11 +54,10 @@ import org.springframework.session.web.http.SessionRepositoryFilter;
* </pre> * </pre>
* *
* <p> * <p>
* It is important to note that no infrastructure for session expirations is * It is important to note that no infrastructure for session expirations is configured
* configured for you out of the box. This is because things like session * for you out of the box. This is because things like session expiration are highly
* expiration are highly implementation dependent. This means if you require * implementation dependent. This means if you require cleaning up expired sessions, you
* cleaning up expired sessions, you are responsible for cleaning up the expired * are responsible for cleaning up the expired sessions.
* sessions.
* </p> * </p>
* *
* <p> * <p>
@@ -66,13 +65,12 @@ import org.springframework.session.web.http.SessionRepositoryFilter;
* </p> * </p>
* *
* <ul> * <ul>
* <li>SessionRepositoryFilter - is responsible for wrapping the * <li>SessionRepositoryFilter - is responsible for wrapping the HttpServletRequest with
* HttpServletRequest with an implementation of HttpSession that is backed by a * an implementation of HttpSession that is backed by a SessionRepository</li>
* SessionRepository</li> * <li>SessionEventHttpSessionListenerAdapter - is responsible for translating Spring
* <li>SessionEventHttpSessionListenerAdapter - is responsible for translating * Session events into HttpSessionEvent. In order for it to work, the implementation of
* Spring Session events into HttpSessionEvent. In order for it to work, the * SessionRepository you provide must support {@link SessionCreatedEvent} and
* implementation of SessionRepository you provide must support * {@link SessionDestroyedEvent}.</li>
* {@link SessionCreatedEvent} and {@link SessionDestroyedEvent}.</li>
* <li> * <li>
* </ul> * </ul>
* *
@@ -98,11 +96,14 @@ public class SpringHttpSessionConfiguration {
} }
@Bean @Bean
public <S extends ExpiringSession> SessionRepositoryFilter<? extends ExpiringSession> springSessionRepositoryFilter(SessionRepository<S> sessionRepository) { public <S extends ExpiringSession> SessionRepositoryFilter<? extends ExpiringSession> springSessionRepositoryFilter(
SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter<S>(sessionRepository); SessionRepository<S> sessionRepository) {
SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter<S>(
sessionRepository);
sessionRepositoryFilter.setServletContext(this.servletContext); sessionRepositoryFilter.setServletContext(this.servletContext);
if (this.httpSessionStrategy instanceof MultiHttpSessionStrategy) { if (this.httpSessionStrategy instanceof MultiHttpSessionStrategy) {
sessionRepositoryFilter.setHttpSessionStrategy((MultiHttpSessionStrategy) this.httpSessionStrategy); sessionRepositoryFilter.setHttpSessionStrategy(
(MultiHttpSessionStrategy) this.httpSessionStrategy);
} }
else { else {
sessionRepositoryFilter.setHttpSessionStrategy(this.httpSessionStrategy); sessionRepositoryFilter.setHttpSessionStrategy(this.httpSessionStrategy);

View File

@@ -64,8 +64,9 @@ import org.springframework.util.Assert;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
* AbstractGemFireOperationsSessionRepository is an abstract base class encapsulating functionality common * AbstractGemFireOperationsSessionRepository is an abstract base class encapsulating
* to all implementations that support SessionRepository operations backed by GemFire. * functionality common to all implementations that support SessionRepository operations
* backed by GemFire.
* *
* @author John Blum * @author John Blum
* @since 1.1.0 * @since 1.1.0
@@ -77,11 +78,13 @@ import org.springframework.util.StringUtils;
* @see org.springframework.session.ExpiringSession * @see org.springframework.session.ExpiringSession
* @see org.springframework.session.FindByIndexNameSessionRepository * @see org.springframework.session.FindByIndexNameSessionRepository
* @see org.springframework.session.Session * @see org.springframework.session.Session
* @see org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration * @see org.springframework.session.data.gemfire.config.annotation.web.http.
* GemFireHttpSessionConfiguration
* @see com.gemstone.gemfire.cache.Region * @see com.gemstone.gemfire.cache.Region
* @see com.gemstone.gemfire.cache.util.CacheListenerAdapter * @see com.gemstone.gemfire.cache.util.CacheListenerAdapter
*/ */
public abstract class AbstractGemFireOperationsSessionRepository extends CacheListenerAdapter<Object, ExpiringSession> public abstract class AbstractGemFireOperationsSessionRepository
extends CacheListenerAdapter<Object, ExpiringSession>
implements InitializingBean, FindByIndexNameSessionRepository<ExpiringSession>, implements InitializingBean, FindByIndexNameSessionRepository<ExpiringSession>,
ApplicationEventPublisherAware { ApplicationEventPublisherAware {
@@ -90,6 +93,7 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
private ApplicationEventPublisher applicationEventPublisher = new ApplicationEventPublisher() { private ApplicationEventPublisher applicationEventPublisher = new ApplicationEventPublisher() {
public void publishEvent(ApplicationEvent event) { public void publishEvent(ApplicationEvent event) {
} }
public void publishEvent(Object event) { public void publishEvent(Object event) {
} }
}; };
@@ -101,8 +105,9 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
private String fullyQualifiedRegionName; private String fullyQualifiedRegionName;
/** /**
* Constructs an instance of AbstractGemFireOperationsSessionRepository with a required GemfireOperations instance * Constructs an instance of AbstractGemFireOperationsSessionRepository with a
* used to perform GemFire data access operations and interactions supporting the SessionRepository operations. * required GemfireOperations instance used to perform GemFire data access operations
* and interactions supporting the SessionRepository operations.
* *
* @param template the GemfireOperations instance used to interact with GemFire. * @param template the GemfireOperations instance used to interact with GemFire.
* @see org.springframework.data.gemfire.GemfireOperations * @see org.springframework.data.gemfire.GemfireOperations
@@ -123,18 +128,23 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
} }
/** /**
* Sets the ApplicationEventPublisher used to publish Session events corresponding to GemFire cache events. * Sets the ApplicationEventPublisher used to publish Session events corresponding to
* GemFire cache events.
* *
* @param applicationEventPublisher the Spring ApplicationEventPublisher used to publish Session-based events. * @param applicationEventPublisher the Spring ApplicationEventPublisher used to
* publish Session-based events.
* @see org.springframework.context.ApplicationEventPublisher * @see org.springframework.context.ApplicationEventPublisher
*/ */
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { public void setApplicationEventPublisher(
Assert.notNull(applicationEventPublisher, "ApplicationEventPublisher must not be null"); ApplicationEventPublisher applicationEventPublisher) {
Assert.notNull(applicationEventPublisher,
"ApplicationEventPublisher must not be null");
this.applicationEventPublisher = applicationEventPublisher; this.applicationEventPublisher = applicationEventPublisher;
} }
/** /**
* Gets the ApplicationEventPublisher used to publish Session events corresponding to GemFire cache events. * Gets the ApplicationEventPublisher used to publish Session events corresponding to
* GemFire cache events.
* *
* @return the Spring ApplicationEventPublisher used to publish Session-based events. * @return the Spring ApplicationEventPublisher used to publish Session-based events.
* @see org.springframework.context.ApplicationEventPublisher * @see org.springframework.context.ApplicationEventPublisher
@@ -144,38 +154,43 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
} }
/** /**
* Gets the fully-qualified name of the GemFire cache {@link Region} used to store and manage Session data. * Gets the fully-qualified name of the GemFire cache {@link Region} used to store and
* manage Session data.
* *
* @return a String indicating the fully qualified name of the GemFire cache {@link Region} used to store * @return a String indicating the fully qualified name of the GemFire cache
* and manage Session data. * {@link Region} used to store and manage Session data.
*/ */
protected String getFullyQualifiedRegionName() { protected String getFullyQualifiedRegionName() {
return this.fullyQualifiedRegionName; return this.fullyQualifiedRegionName;
} }
/** /**
* Sets the maximum interval in seconds in which a Session can remain inactive before it is considered expired. * Sets the maximum interval in seconds in which a Session can remain inactive before
* it is considered expired.
* *
* @param maxInactiveIntervalInSeconds an integer value specifying the maximum interval in seconds that a Session * @param maxInactiveIntervalInSeconds an integer value specifying the maximum
* can remain inactive before it is considered expired. * interval in seconds that a Session can remain inactive before it is considered
* expired.
*/ */
public void setMaxInactiveIntervalInSeconds(int maxInactiveIntervalInSeconds) { public void setMaxInactiveIntervalInSeconds(int maxInactiveIntervalInSeconds) {
this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds; this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds;
} }
/** /**
* Gets the maximum interval in seconds in which a Session can remain inactive before it is considered expired. * Gets the maximum interval in seconds in which a Session can remain inactive before
* it is considered expired.
* *
* @return an integer value specifying the maximum interval in seconds that a Session can remain inactive * @return an integer value specifying the maximum interval in seconds that a Session
* before it is considered expired. * can remain inactive before it is considered expired.
*/ */
public int getMaxInactiveIntervalInSeconds() { public int getMaxInactiveIntervalInSeconds() {
return this.maxInactiveIntervalInSeconds; return this.maxInactiveIntervalInSeconds;
} }
/** /**
* Gets a reference to the GemfireOperations (template) used to perform data access operations * Gets a reference to the GemfireOperations (template) used to perform data access
* and other interactions on the GemFire cache {@link Region} backing this SessionRepository. * operations and other interactions on the GemFire cache {@link Region} backing this
* SessionRepository.
* *
* @return a reference to the GemfireOperations used to interact with GemFire. * @return a reference to the GemfireOperations used to interact with GemFire.
* @see org.springframework.data.gemfire.GemfireOperations * @see org.springframework.data.gemfire.GemfireOperations
@@ -185,9 +200,10 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
} }
/** /**
* Callback method during Spring bean initialization that will capture the fully-qualified name * Callback method during Spring bean initialization that will capture the
* of the GemFire cache {@link Region} used to manage Session state and register this SessionRepository * fully-qualified name of the GemFire cache {@link Region} used to manage Session
* as a GemFire {@link com.gemstone.gemfire.cache.CacheListener}. * state and register this SessionRepository as a GemFire
* {@link com.gemstone.gemfire.cache.CacheListener}.
* *
* @throws Exception if an error occurs during the initialization process. * @throws Exception if an error occurs during the initialization process.
*/ */
@@ -213,7 +229,8 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
} }
/** /**
* Callback method triggered when an entry is created in the GemFire cache {@link Region}. * Callback method triggered when an entry is created in the GemFire cache
* {@link Region}.
* *
* @param event an EntryEvent containing the details of the cache operation. * @param event an EntryEvent containing the details of the cache operation.
* @see com.gemstone.gemfire.cache.EntryEvent * @see com.gemstone.gemfire.cache.EntryEvent
@@ -222,12 +239,14 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
@Override @Override
public void afterCreate(EntryEvent<Object, ExpiringSession> event) { public void afterCreate(EntryEvent<Object, ExpiringSession> event) {
if (isExpiringSessionOrNull(event.getNewValue())) { if (isExpiringSessionOrNull(event.getNewValue())) {
handleCreated(event.getKey().toString(), toExpiringSession(event.getNewValue())); handleCreated(event.getKey().toString(),
toExpiringSession(event.getNewValue()));
} }
} }
/** /**
* Callback method triggered when an entry is destroyed in the GemFire cache {@link Region}. * Callback method triggered when an entry is destroyed in the GemFire cache
* {@link Region}.
* *
* @param event an EntryEvent containing the details of the cache operation. * @param event an EntryEvent containing the details of the cache operation.
* @see com.gemstone.gemfire.cache.EntryEvent * @see com.gemstone.gemfire.cache.EntryEvent
@@ -235,11 +254,13 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
*/ */
@Override @Override
public void afterDestroy(EntryEvent<Object, ExpiringSession> event) { public void afterDestroy(EntryEvent<Object, ExpiringSession> event) {
handleDestroyed(event.getKey().toString(), toExpiringSession(event.getOldValue())); handleDestroyed(event.getKey().toString(),
toExpiringSession(event.getOldValue()));
} }
/** /**
* Callback method triggered when an entry is invalidated in the GemFire cache {@link Region}. * Callback method triggered when an entry is invalidated in the GemFire cache
* {@link Region}.
* *
* @param event an EntryEvent containing the details of the cache operation. * @param event an EntryEvent containing the details of the cache operation.
* @see com.gemstone.gemfire.cache.EntryEvent * @see com.gemstone.gemfire.cache.EntryEvent
@@ -318,29 +339,34 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
getApplicationEventPublisher().publishEvent(event); getApplicationEventPublisher().publishEvent(event);
} }
catch (Throwable t) { catch (Throwable t) {
this.logger.error(String.format("error occurred publishing event (%1$s)", event), t); this.logger.error(
String.format("error occurred publishing event (%1$s)", event), t);
} }
} }
/** /**
* GemFireSession is a GemFire representation model of a Spring {@link ExpiringSession} for storing and accessing * GemFireSession is a GemFire representation model of a Spring
* Session state information in GemFire. This class implements GemFire's {@link DataSerializable} interface * {@link ExpiringSession} for storing and accessing Session state information in
* to better handle replication of Session information across the GemFire cluster. * GemFire. This class implements GemFire's {@link DataSerializable} interface to
* better handle replication of Session information across the GemFire cluster.
* *
* @see java.lang.Comparable * @see java.lang.Comparable
* @see org.springframework.session.ExpiringSession * @see org.springframework.session.ExpiringSession
* @see org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes * @see org.springframework.session.data.gemfire.
* AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes
* @see com.gemstone.gemfire.DataSerializable * @see com.gemstone.gemfire.DataSerializable
* @see com.gemstone.gemfire.DataSerializer * @see com.gemstone.gemfire.DataSerializer
* @see com.gemstone.gemfire.Delta * @see com.gemstone.gemfire.Delta
* @see com.gemstone.gemfire.Instantiator * @see com.gemstone.gemfire.Instantiator
*/ */
@SuppressWarnings("serial") @SuppressWarnings("serial")
public static class GemFireSession implements Comparable<ExpiringSession>, DataSerializable, Delta, ExpiringSession { public static class GemFireSession implements Comparable<ExpiringSession>,
DataSerializable, Delta, ExpiringSession {
protected static final boolean DEFAULT_ALLOW_JAVA_SERIALIZATION = true; protected static final boolean DEFAULT_ALLOW_JAVA_SERIALIZATION = true;
protected static final DateFormat TO_STRING_DATE_FORMAT = new SimpleDateFormat("YYYY-MM-dd-HH-mm-ss"); protected static final DateFormat TO_STRING_DATE_FORMAT = new SimpleDateFormat(
"YYYY-MM-dd-HH-mm-ss");
protected static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT"; protected static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT";
@@ -360,7 +386,8 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
private long creationTime; private long creationTime;
private long lastAccessedTime; private long lastAccessedTime;
private transient final GemFireSessionAttributes sessionAttributes = new GemFireSessionAttributes(this); private transient final GemFireSessionAttributes sessionAttributes = new GemFireSessionAttributes(
this);
private transient final SpelExpressionParser parser = new SpelExpressionParser(); private transient final SpelExpressionParser parser = new SpelExpressionParser();
@@ -460,7 +487,8 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
/* (non-Javadoc) */ /* (non-Javadoc) */
private long idleTimeout(long maxInactiveIntervalInSeconds) { private long idleTimeout(long maxInactiveIntervalInSeconds) {
return (System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(maxInactiveIntervalInSeconds)); return (System.currentTimeMillis()
- TimeUnit.SECONDS.toMillis(maxInactiveIntervalInSeconds));
} }
/* (non-Javadoc) */ /* (non-Javadoc) */
@@ -475,7 +503,8 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
} }
/* (non-Javadoc) */ /* (non-Javadoc) */
public synchronized void setMaxInactiveIntervalInSeconds(final int maxInactiveIntervalInSeconds) { public synchronized void setMaxInactiveIntervalInSeconds(
final int maxInactiveIntervalInSeconds) {
this.delta |= (this.maxInactiveIntervalInSeconds != maxInactiveIntervalInSeconds); this.delta |= (this.maxInactiveIntervalInSeconds != maxInactiveIntervalInSeconds);
this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds; this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds;
} }
@@ -498,7 +527,8 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
Object authentication = getAttribute(SPRING_SECURITY_CONTEXT); Object authentication = getAttribute(SPRING_SECURITY_CONTEXT);
if (authentication != null) { if (authentication != null) {
Expression expression = this.parser.parseExpression("authentication?.name"); Expression expression = this.parser
.parseExpression("authentication?.name");
principalName = expression.getValue(authentication, String.class); principalName = expression.getValue(authentication, String.class);
} }
} }
@@ -514,7 +544,8 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
out.writeInt(getMaxInactiveIntervalInSeconds()); out.writeInt(getMaxInactiveIntervalInSeconds());
String principalName = getPrincipalName(); String principalName = getPrincipalName();
int length = (StringUtils.hasText(principalName) ? principalName.length() : 0); int length = (StringUtils.hasText(principalName) ? principalName.length()
: 0);
out.writeInt(length); out.writeInt(length);
@@ -533,7 +564,8 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
} }
/* (non-Javadoc) */ /* (non-Javadoc) */
public synchronized void fromData(DataInput in) throws ClassNotFoundException, IOException { public synchronized void fromData(DataInput in)
throws ClassNotFoundException, IOException {
this.id = in.readUTF(); this.id = in.readUTF();
this.creationTime = in.readLong(); this.creationTime = in.readLong();
setLastAccessedTime(in.readLong()); setLastAccessedTime(in.readLong());
@@ -609,9 +641,11 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
/* (non-Javadoc) */ /* (non-Javadoc) */
@Override @Override
public synchronized String toString() { public synchronized String toString() {
return String.format("{ @type = %1$s, id = %2$s, creationTime = %3$s, lastAccessedTime = %4$s" return String.format(
+ ", maxInactiveIntervalInSeconds = %5$s, principalName = %6$s }", getClass().getName(), getId(), "{ @type = %1$s, id = %2$s, creationTime = %3$s, lastAccessedTime = %4$s"
toString(getCreationTime()), toString(getLastAccessedTime()), getMaxInactiveIntervalInSeconds(), + ", maxInactiveIntervalInSeconds = %5$s, principalName = %6$s }",
getClass().getName(), getId(), toString(getCreationTime()),
toString(getLastAccessedTime()), getMaxInactiveIntervalInSeconds(),
getPrincipalName()); getPrincipalName());
} }
@@ -622,10 +656,11 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
} }
/** /**
* The GemFireSessionAttributes class is a container for Session attributes that implements both * The GemFireSessionAttributes class is a container for Session attributes that
* the {@link DataSerializable} and {@link Delta} GemFire interfaces for efficient storage and distribution * implements both the {@link DataSerializable} and {@link Delta} GemFire interfaces
* (replication) in GemFire. Additionally, GemFireSessionAttributes extends {@link AbstractMap} providing * for efficient storage and distribution (replication) in GemFire. Additionally,
* {@link Map}-like behavior since attributes of a Session are effectively a name to value mapping. * GemFireSessionAttributes extends {@link AbstractMap} providing {@link Map}-like
* behavior since attributes of a Session are effectively a name to value mapping.
* *
* @see java.util.AbstractMap * @see java.util.AbstractMap
* @see com.gemstone.gemfire.DataSerializable * @see com.gemstone.gemfire.DataSerializable
@@ -640,7 +675,8 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
protected static final boolean DEFAULT_ALLOW_JAVA_SERIALIZATION = true; protected static final boolean DEFAULT_ALLOW_JAVA_SERIALIZATION = true;
static { static {
Instantiator.register(new Instantiator(GemFireSessionAttributes.class, 800828008) { Instantiator.register(
new Instantiator(GemFireSessionAttributes.class, 800828008) {
@Override @Override
public DataSerializable newInstance() { public DataSerializable newInstance() {
return new GemFireSessionAttributes(); return new GemFireSessionAttributes();
@@ -667,7 +703,8 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
public void setAttribute(String attributeName, Object attributeValue) { public void setAttribute(String attributeName, Object attributeValue) {
synchronized (this.lock) { synchronized (this.lock) {
if (attributeValue != null) { if (attributeValue != null) {
if (!attributeValue.equals(this.sessionAttributes.put(attributeName, attributeValue))) { if (!attributeValue.equals(
this.sessionAttributes.put(attributeName, attributeValue))) {
this.sessionAttributeDeltas.put(attributeName, attributeValue); this.sessionAttributeDeltas.put(attributeName, attributeValue);
} }
} }
@@ -697,7 +734,8 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
/* (non-Javadoc) */ /* (non-Javadoc) */
public Set<String> getAttributeNames() { public Set<String> getAttributeNames() {
synchronized (this.lock) { synchronized (this.lock) {
return Collections.unmodifiableSet(new HashSet<String>(this.sessionAttributes.keySet())); return Collections.unmodifiableSet(
new HashSet<String>(this.sessionAttributes.keySet()));
} }
} }
@@ -713,7 +751,10 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
return new AbstractSet<Entry<String, Object>>() { return new AbstractSet<Entry<String, Object>>() {
@Override @Override
public Iterator<Entry<String, Object>> iterator() { public Iterator<Entry<String, Object>> iterator() {
return Collections.unmodifiableMap(GemFireSessionAttributes.this.sessionAttributes).entrySet().iterator(); return Collections
.unmodifiableMap(
GemFireSessionAttributes.this.sessionAttributes)
.entrySet().iterator();
} }
@Override @Override
@@ -736,7 +777,8 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
public void from(GemFireSessionAttributes sessionAttributes) { public void from(GemFireSessionAttributes sessionAttributes) {
synchronized (this.lock) { synchronized (this.lock) {
for (String attributeName : sessionAttributes.getAttributeNames()) { for (String attributeName : sessionAttributes.getAttributeNames()) {
setAttribute(attributeName, sessionAttributes.getAttribute(attributeName)); setAttribute(attributeName,
sessionAttributes.getAttribute(attributeName));
} }
} }
} }
@@ -788,7 +830,8 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
synchronized (this.lock) { synchronized (this.lock) {
out.writeInt(this.sessionAttributeDeltas.size()); out.writeInt(this.sessionAttributeDeltas.size());
for (Map.Entry<String, Object> entry : this.sessionAttributeDeltas.entrySet()) { for (Map.Entry<String, Object> entry : this.sessionAttributeDeltas
.entrySet()) {
out.writeUTF(entry.getKey()); out.writeUTF(entry.getKey());
writeObject(entry.getValue(), out); writeObject(entry.getValue(), out);
} }

View File

@@ -25,31 +25,33 @@ import org.springframework.data.gemfire.GemfireOperations;
import org.springframework.session.ExpiringSession; import org.springframework.session.ExpiringSession;
/** /**
* The GemFireOperationsSessionRepository class is a Spring SessionRepository implementation that interfaces with * The GemFireOperationsSessionRepository class is a Spring SessionRepository
* and uses GemFire to back and store Spring Sessions. * implementation that interfaces with and uses GemFire to back and store Spring Sessions.
* *
* @author John Blum * @author John Blum
* @since 1.1.0 * @since 1.1.0
* @see org.springframework.data.gemfire.GemfireOperations * @see org.springframework.data.gemfire.GemfireOperations
* @see org.springframework.session.ExpiringSession * @see org.springframework.session.ExpiringSession
* @see org.springframework.session.Session * @see org.springframework.session.Session
* @see org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository * @see org.springframework.session.data.gemfire.
* AbstractGemFireOperationsSessionRepository
*/ */
public class GemFireOperationsSessionRepository extends AbstractGemFireOperationsSessionRepository { public class GemFireOperationsSessionRepository
extends AbstractGemFireOperationsSessionRepository {
// GemFire OQL query used to lookup Sessions by arbitrary attributes. // GemFire OQL query used to lookup Sessions by arbitrary attributes.
protected static final String FIND_SESSIONS_BY_INDEX_NAME_VALUE_QUERY = protected static final String FIND_SESSIONS_BY_INDEX_NAME_VALUE_QUERY = "SELECT s FROM %1$s s WHERE s.attributes['%2$s'] = $1";
"SELECT s FROM %1$s s WHERE s.attributes['%2$s'] = $1";
// GemFire OQL query used to look up Sessions by principal name. // GemFire OQL query used to look up Sessions by principal name.
protected static final String FIND_SESSIONS_BY_PRINCIPAL_NAME_QUERY = protected static final String FIND_SESSIONS_BY_PRINCIPAL_NAME_QUERY = "SELECT s FROM %1$s s WHERE s.principalName = $1";
"SELECT s FROM %1$s s WHERE s.principalName = $1";
/** /**
* Constructs an instance of GemFireOperationsSessionRepository initialized with the required GemfireOperations * Constructs an instance of GemFireOperationsSessionRepository initialized with the
* object used to perform data access operations to manage Session state. * required GemfireOperations object used to perform data access operations to manage
* Session state.
* *
* @param template the GemfireOperations object used to access and manage Session state in GemFire. * @param template the GemfireOperations object used to access and manage Session
* state in GemFire.
* @see org.springframework.data.gemfire.GemfireOperations * @see org.springframework.data.gemfire.GemfireOperations
*/ */
public GemFireOperationsSessionRepository(GemfireOperations template) { public GemFireOperationsSessionRepository(GemfireOperations template) {
@@ -57,20 +59,26 @@ public class GemFireOperationsSessionRepository extends AbstractGemFireOperation
} }
/** /**
* Looks up all available Sessions with the particular attribute indexed by name having the given value. * Looks up all available Sessions with the particular attribute indexed by name
* having the given value.
* *
* @param indexName name of the indexed Session attribute. * @param indexName name of the indexed Session attribute. (e.g.
* (e.g. {@link org.springframework.session.FindByIndexNameSessionRepository#PRINCIPAL_NAME_INDEX_NAME}). * {@link org.springframework.session.FindByIndexNameSessionRepository#PRINCIPAL_NAME_INDEX_NAME}
* @param indexValue value of the indexed Session attribute to search on (e.g. username). * ).
* @param indexValue value of the indexed Session attribute to search on (e.g.
* username).
* @return a mapping of Session ID to Session instances. * @return a mapping of Session ID to Session instances.
* @see org.springframework.session.ExpiringSession * @see org.springframework.session.ExpiringSession
* @see java.util.Map * @see java.util.Map
* @see #prepareQuery(String) * @see #prepareQuery(String)
*/ */
public Map<String, ExpiringSession> findByIndexNameAndIndexValue(String indexName, String indexValue) { public Map<String, ExpiringSession> findByIndexNameAndIndexValue(String indexName,
SelectResults<ExpiringSession> results = getTemplate().find(prepareQuery(indexName), indexValue); String indexValue) {
SelectResults<ExpiringSession> results = getTemplate()
.find(prepareQuery(indexName), indexValue);
Map<String, ExpiringSession> sessions = new HashMap<String, ExpiringSession>(results.size()); Map<String, ExpiringSession> sessions = new HashMap<String, ExpiringSession>(
results.size());
for (ExpiringSession session : results.asList()) { for (ExpiringSession session : results.asList()) {
sessions.put(session.getId(), session); sessions.put(session.getId(), session);
@@ -80,22 +88,26 @@ public class GemFireOperationsSessionRepository extends AbstractGemFireOperation
} }
/** /**
* Prepares the appropriate GemFire OQL query based on the indexed Session attribute name. * Prepares the appropriate GemFire OQL query based on the indexed Session attribute
* name.
* *
* @param indexName a String indicating the name of the indexed Session attribute. * @param indexName a String indicating the name of the indexed Session attribute.
* @return an appropriate GemFire OQL statement for querying on a particular indexed Session attribute. * @return an appropriate GemFire OQL statement for querying on a particular indexed
* Session attribute.
*/ */
protected String prepareQuery(String indexName) { protected String prepareQuery(String indexName) {
return (PRINCIPAL_NAME_INDEX_NAME.equals(indexName) return (PRINCIPAL_NAME_INDEX_NAME.equals(indexName)
? String.format(FIND_SESSIONS_BY_PRINCIPAL_NAME_QUERY, getFullyQualifiedRegionName()) ? String.format(FIND_SESSIONS_BY_PRINCIPAL_NAME_QUERY,
: String.format(FIND_SESSIONS_BY_INDEX_NAME_VALUE_QUERY, getFullyQualifiedRegionName(), indexName)); getFullyQualifiedRegionName())
: String.format(FIND_SESSIONS_BY_INDEX_NAME_VALUE_QUERY,
getFullyQualifiedRegionName(), indexName));
} }
/** /**
* Constructs a new {@link ExpiringSession} instance backed by GemFire. * Constructs a new {@link ExpiringSession} instance backed by GemFire.
* *
* @return an instance of {@link ExpiringSession} backed by GemFire. * @return an instance of {@link ExpiringSession} backed by GemFire.
* @see org.springframework.session.data.gemfire.GemFireOperationsSessionRepository.GemFireSession#create(int) * @see GemFireSession#create(int)
* @see org.springframework.session.ExpiringSession * @see org.springframework.session.ExpiringSession
* @see #getMaxInactiveIntervalInSeconds() * @see #getMaxInactiveIntervalInSeconds()
*/ */
@@ -104,8 +116,8 @@ public class GemFireOperationsSessionRepository extends AbstractGemFireOperation
} }
/** /**
* Gets a copy of an existing, non-expired {@link ExpiringSession} by ID. If the Session is expired, * Gets a copy of an existing, non-expired {@link ExpiringSession} by ID. If the
* then it is deleted. * Session is expired, then it is deleted.
* *
* @param sessionId a String indicating the ID of the Session to get. * @param sessionId a String indicating the ID of the Session to get.
* @return an existing {@link ExpiringSession} by ID or null if not Session exists. * @return an existing {@link ExpiringSession} by ID or null if not Session exists.
@@ -140,15 +152,16 @@ public class GemFireOperationsSessionRepository extends AbstractGemFireOperation
} }
/** /**
* Deletes (removes) any existing {@link ExpiringSession} from GemFire. This operation also results in * Deletes (removes) any existing {@link ExpiringSession} from GemFire. This operation
* a SessionDeletedEvent. * also results in a SessionDeletedEvent.
* *
* @param sessionId a String indicating the ID of the Session to remove from GemFire. * @param sessionId a String indicating the ID of the Session to remove from GemFire.
* @see org.springframework.data.gemfire.GemfireOperations#remove(Object) * @see org.springframework.data.gemfire.GemfireOperations#remove(Object)
* @see #handleDeleted(String, ExpiringSession) * @see #handleDeleted(String, ExpiringSession)
*/ */
public void delete(String sessionId) { public void delete(String sessionId) {
handleDeleted(sessionId, getTemplate().<Object, ExpiringSession>remove(sessionId)); handleDeleted(sessionId,
getTemplate().<Object, ExpiringSession>remove(sessionId));
} }
} }

View File

@@ -29,11 +29,13 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
/** /**
* Add this annotation to an {@code @Configuration} class to expose the SessionRepositoryFilter * Add this annotation to an {@code @Configuration} class to expose the
* as a bean named "springSessionRepositoryFilter" and backed by Pivotal GemFire or Apache Geode. * SessionRepositoryFilter as a bean named "springSessionRepositoryFilter" and backed by
* Pivotal GemFire or Apache Geode.
* *
* In order to leverage the annotation, a single Pivotal GemFire/Apache Geode {@link com.gemstone.gemfire.cache.Cache} * In order to leverage the annotation, a single Pivotal GemFire/Apache Geode
* or {@link com.gemstone.gemfire.cache.client.ClientCache} instance must be provided. * {@link com.gemstone.gemfire.cache.Cache} or
* {@link com.gemstone.gemfire.cache.client.ClientCache} instance must be provided.
* *
* For example: * For example:
* *
@@ -61,12 +63,11 @@ import org.springframework.context.annotation.Import;
* return clientCacheFactoryBean; * return clientCacheFactoryBean;
* } * }
* } * }
* </code> * </code> </pre>
* </pre>
* *
* Alternatively, a Spring Session can be configured to use Pivotal GemFire (Apache Geode) as a client * Alternatively, a Spring Session can be configured to use Pivotal GemFire (Apache Geode)
* using a dedicated GemFire Server cluster and a {@link com.gemstone.gemfire.cache.client.ClientCache}. * as a client using a dedicated GemFire Server cluster and a
* For example: * {@link com.gemstone.gemfire.cache.client.ClientCache}. For example:
* *
* <code> * <code>
* {@literal @Configuration} * {@literal @Configuration}
@@ -92,12 +93,14 @@ import org.springframework.context.annotation.Import;
* } * }
* </code> * </code>
* *
* More advanced configurations can extend {@link GemFireHttpSessionConfiguration} instead. * More advanced configurations can extend {@link GemFireHttpSessionConfiguration}
* instead.
* *
* @author John Blum * @author John Blum
* @see org.springframework.context.annotation.Configuration * @see org.springframework.context.annotation.Configuration
* @see org.springframework.context.annotation.Import * @see org.springframework.context.annotation.Import
* @see org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration * @see org.springframework.session.data.gemfire.config.annotation.web.http.
* GemFireHttpSessionConfiguration
* @see org.springframework.session.config.annotation.web.http.EnableSpringHttpSession * @see org.springframework.session.config.annotation.web.http.EnableSpringHttpSession
* @since 1.1.0 * @since 1.1.0
*/ */
@@ -111,31 +114,35 @@ public @interface EnableGemFireHttpSession {
/** /**
* Defines the GemFire ClientCache Region DataPolicy. * Defines the GemFire ClientCache Region DataPolicy.
* *
* @return a ClientRegionShortcut used to specify and configure the ClientCache Region DataPolicy. * @return a ClientRegionShortcut used to specify and configure the ClientCache Region
* DataPolicy.
* @see com.gemstone.gemfire.cache.client.ClientRegionShortcut * @see com.gemstone.gemfire.cache.client.ClientRegionShortcut
*/ */
ClientRegionShortcut clientRegionShortcut() default ClientRegionShortcut.PROXY; ClientRegionShortcut clientRegionShortcut() default ClientRegionShortcut.PROXY;
/** /**
* Identifies the Session attributes by name that should be indexed for query operations. * Identifies the Session attributes by name that should be indexed for query
* For instance, find all Sessions in GemFire having attribute A defined with value X. * operations. For instance, find all Sessions in GemFire having attribute A defined
* with value X.
* *
* @return an array of Strings identifying the names of Session attributes to index. * @return an array of Strings identifying the names of Session attributes to index.
*/ */
String[]indexableSessionAttributes() default {}; String[]indexableSessionAttributes() default {};
/** /**
* Defines the maximum interval in seconds that a Session can remain inactive before it is considered expired. * Defines the maximum interval in seconds that a Session can remain inactive before
* Defaults to 1800 seconds, or 30 minutes. * it is considered expired. Defaults to 1800 seconds, or 30 minutes.
* *
* @return an integer value defining the maximum inactive interval in seconds for declaring a Session expired. * @return an integer value defining the maximum inactive interval in seconds for
* declaring a Session expired.
*/ */
int maxInactiveIntervalInSeconds() default 1800; int maxInactiveIntervalInSeconds() default 1800;
/** /**
* Defines the name of the GemFire (Client)Cache Region used to store Sessions. * Defines the name of the GemFire (Client)Cache Region used to store Sessions.
* *
* @return a String specifying the name of the GemFire (Client)Cache Region used to store Sessions. * @return a String specifying the name of the GemFire (Client)Cache Region used to
* store Sessions.
* @see com.gemstone.gemfire.cache.Region#getName() * @see com.gemstone.gemfire.cache.Region#getName()
*/ */
String regionName() default "ClusteredSpringSessions"; String regionName() default "ClusteredSpringSessions";
@@ -143,7 +150,8 @@ public @interface EnableGemFireHttpSession {
/** /**
* Defines the GemFire, Peer Cache Region DataPolicy. * Defines the GemFire, Peer Cache Region DataPolicy.
* *
* @return a RegionShortcut used to specify and configure the Peer Cache Region DataPolicy. * @return a RegionShortcut used to specify and configure the Peer Cache Region
* DataPolicy.
* @see com.gemstone.gemfire.cache.RegionShortcut * @see com.gemstone.gemfire.cache.RegionShortcut
*/ */
RegionShortcut serverRegionShortcut() default RegionShortcut.PARTITION; RegionShortcut serverRegionShortcut() default RegionShortcut.PARTITION;

View File

@@ -49,8 +49,9 @@ import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
* The GemFireHttpSessionConfiguration class is a Spring @Configuration class used to configure and initialize * The GemFireHttpSessionConfiguration class is a Spring @Configuration class used to
* Pivotal GemFire (or Apache Geode) as a clustered, replicated HttpSession provider implementation in Spring Session. * configure and initialize Pivotal GemFire (or Apache Geode) as a clustered, replicated
* HttpSession provider implementation in Spring Session.
* *
* @author John Blum * @author John Blum
* @since 1.1.0 * @since 1.1.0
@@ -63,9 +64,11 @@ import org.springframework.util.StringUtils;
* @see org.springframework.data.gemfire.IndexFactoryBean * @see org.springframework.data.gemfire.IndexFactoryBean
* @see org.springframework.data.gemfire.RegionAttributesFactoryBean * @see org.springframework.data.gemfire.RegionAttributesFactoryBean
* @see org.springframework.session.ExpiringSession * @see org.springframework.session.ExpiringSession
* @see org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration * @see org.springframework.session.config.annotation.web.http.
* SpringHttpSessionConfiguration
* @see org.springframework.session.data.gemfire.GemFireOperationsSessionRepository * @see org.springframework.session.data.gemfire.GemFireOperationsSessionRepository
* @see org.springframework.session.data.gemfire.config.annotation.web.http.support.GemFireCacheTypeAwareRegionFactoryBean * @see org.springframework.session.data.gemfire.config.annotation.web.http.support.
* GemFireCacheTypeAwareRegionFactoryBean
* @see com.gemstone.gemfire.cache.ExpirationAttributes * @see com.gemstone.gemfire.cache.ExpirationAttributes
* @see com.gemstone.gemfire.cache.GemFireCache * @see com.gemstone.gemfire.cache.GemFireCache
* @see com.gemstone.gemfire.cache.Region * @see com.gemstone.gemfire.cache.Region
@@ -81,7 +84,8 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
* The default maximum interval in seconds in which a Session can remain inactive * The default maximum interval in seconds in which a Session can remain inactive
* before it is considered expired. * before it is considered expired.
*/ */
public static final int DEFAULT_MAX_INACTIVE_INTERVAL_IN_SECONDS = (int) TimeUnit.MINUTES.toSeconds(30); public static final int DEFAULT_MAX_INACTIVE_INTERVAL_IN_SECONDS = (int) TimeUnit.MINUTES
.toSeconds(30);
protected static final Class<Object> SPRING_SESSION_GEMFIRE_REGION_KEY_CONSTRAINT = Object.class; protected static final Class<Object> SPRING_SESSION_GEMFIRE_REGION_KEY_CONSTRAINT = Object.class;
protected static final Class<GemFireSession> SPRING_SESSION_GEMFIRE_REGION_VALUE_CONSTRAINT = GemFireSession.class; protected static final Class<GemFireSession> SPRING_SESSION_GEMFIRE_REGION_VALUE_CONSTRAINT = GemFireSession.class;
@@ -121,9 +125,11 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
private String[] indexableSessionAttributes = DEFAULT_INDEXABLE_SESSION_ATTRIBUTES; private String[] indexableSessionAttributes = DEFAULT_INDEXABLE_SESSION_ATTRIBUTES;
/** /**
* Sets a reference to the {@link ClassLoader} used to load bean definition class types in a Spring context. * Sets a reference to the {@link ClassLoader} used to load bean definition class
* types in a Spring context.
* *
* @param beanClassLoader the ClassLoader used by the Spring container to load bean class types. * @param beanClassLoader the ClassLoader used by the Spring container to load bean
* class types.
* @see org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader(ClassLoader) * @see org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader(ClassLoader)
* @see java.lang.ClassLoader * @see java.lang.ClassLoader
*/ */
@@ -132,7 +138,8 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
} }
/** /**
* Gets a reference to the {@link ClassLoader} used to load bean definition class types in a Spring context. * Gets a reference to the {@link ClassLoader} used to load bean definition class
* types in a Spring context.
* *
* @return the ClassLoader used by the Spring container to load bean class types. * @return the ClassLoader used by the Spring container to load bean class types.
* @see java.lang.ClassLoader * @see java.lang.ClassLoader
@@ -142,10 +149,11 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
} }
/** /**
* Sets the {@link ClientRegionShortcut} used to configure the GemFire ClientCache Region * Sets the {@link ClientRegionShortcut} used to configure the GemFire ClientCache
* that will store Spring Sessions. * Region that will store Spring Sessions.
* *
* @param shortcut the ClientRegionShortcut used to configure the GemFire ClientCache Region. * @param shortcut the ClientRegionShortcut used to configure the GemFire ClientCache
* Region.
* @see com.gemstone.gemfire.cache.client.ClientRegionShortcut * @see com.gemstone.gemfire.cache.client.ClientRegionShortcut
*/ */
public void setClientRegionShortcut(ClientRegionShortcut shortcut) { public void setClientRegionShortcut(ClientRegionShortcut shortcut) {
@@ -153,22 +161,24 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
} }
/** /**
* Gets the {@link ClientRegionShortcut} used to configure the GemFire ClientCache Region * Gets the {@link ClientRegionShortcut} used to configure the GemFire ClientCache
* that will store Spring Sessions. Defaults to {@link ClientRegionShortcut#PROXY}. * Region that will store Spring Sessions. Defaults to
* {@link ClientRegionShortcut#PROXY}.
* *
* @return the ClientRegionShortcut used to configure the GemFire ClientCache Region. * @return the ClientRegionShortcut used to configure the GemFire ClientCache Region.
* @see com.gemstone.gemfire.cache.client.ClientRegionShortcut * @see com.gemstone.gemfire.cache.client.ClientRegionShortcut
* @see EnableGemFireHttpSession#clientRegionShortcut() * @see EnableGemFireHttpSession#clientRegionShortcut()
*/ */
protected ClientRegionShortcut getClientRegionShortcut() { protected ClientRegionShortcut getClientRegionShortcut() {
return (this.clientRegionShortcut != null ? this.clientRegionShortcut : DEFAULT_CLIENT_REGION_SHORTCUT); return (this.clientRegionShortcut != null ? this.clientRegionShortcut
: DEFAULT_CLIENT_REGION_SHORTCUT);
} }
/** /**
* Sets the names of all Session attributes that should be indexed by GemFire. * Sets the names of all Session attributes that should be indexed by GemFire.
* *
* @param indexableSessionAttributes an array of Strings indicating the names of all Session attributes * @param indexableSessionAttributes an array of Strings indicating the names of all
* for which an Index will be created by GemFire. * Session attributes for which an Index will be created by GemFire.
*/ */
public void setIndexableSessionAttributes(String[] indexableSessionAttributes) { public void setIndexableSessionAttributes(String[] indexableSessionAttributes) {
this.indexableSessionAttributes = indexableSessionAttributes; this.indexableSessionAttributes = indexableSessionAttributes;
@@ -177,21 +187,23 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
/** /**
* Get the names of all Session attributes that should be indexed by GemFire. * Get the names of all Session attributes that should be indexed by GemFire.
* *
* @return an array of Strings indicating the names of all Session attributes for which an Index * @return an array of Strings indicating the names of all Session attributes for
* will be created by GemFire. Defaults to an empty String array if unspecified. * which an Index will be created by GemFire. Defaults to an empty String array if
* unspecified.
* @see EnableGemFireHttpSession#indexableSessionAttributes() * @see EnableGemFireHttpSession#indexableSessionAttributes()
*/ */
protected String[] getIndexableSessionAttributes() { protected String[] getIndexableSessionAttributes() {
return (this.indexableSessionAttributes != null ? this.indexableSessionAttributes : DEFAULT_INDEXABLE_SESSION_ATTRIBUTES); return (this.indexableSessionAttributes != null ? this.indexableSessionAttributes
: DEFAULT_INDEXABLE_SESSION_ATTRIBUTES);
} }
/** /**
* Gets the names of all Session attributes that will be indexed by GemFire as single String value constituting * Gets the names of all Session attributes that will be indexed by GemFire as single
* the Index expression of the Index definition. * String value constituting the Index expression of the Index definition.
* *
* @return a String composed of all the named Session attributes on which a GemFire Index will be created * @return a String composed of all the named Session attributes on which a GemFire
* as an Index definition expression. If the indexable Session attributes were not specified, then the * Index will be created as an Index definition expression. If the indexable Session
* wildcard ("*") is returned. * attributes were not specified, then the wildcard ("*") is returned.
* @see com.gemstone.gemfire.cache.query.Index#getIndexedExpression() * @see com.gemstone.gemfire.cache.query.Index#getIndexedExpression()
*/ */
protected String getIndexableSessionAttributesAsGemFireIndexExpression() { protected String getIndexableSessionAttributesAsGemFireIndexExpression() {
@@ -208,20 +220,23 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
} }
/** /**
* Sets the maximum interval in seconds in which a Session can remain inactive before it is considered expired. * Sets the maximum interval in seconds in which a Session can remain inactive before
* it is considered expired.
* *
* @param maxInactiveIntervalInSeconds an integer value specifying the maximum interval in seconds that a Session * @param maxInactiveIntervalInSeconds an integer value specifying the maximum
* can remain inactive before it is considered expired. * interval in seconds that a Session can remain inactive before it is considered
* expired.
*/ */
public void setMaxInactiveIntervalInSeconds(int maxInactiveIntervalInSeconds) { public void setMaxInactiveIntervalInSeconds(int maxInactiveIntervalInSeconds) {
this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds; this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds;
} }
/** /**
* Gets the maximum interval in seconds in which a Session can remain inactive before it is considered expired. * Gets the maximum interval in seconds in which a Session can remain inactive before
* it is considered expired.
* *
* @return an integer value specifying the maximum interval in seconds that a Session can remain inactive * @return an integer value specifying the maximum interval in seconds that a Session
* before it is considered expired. * can remain inactive before it is considered expired.
* @see EnableGemFireHttpSession#maxInactiveIntervalInSeconds() * @see EnableGemFireHttpSession#maxInactiveIntervalInSeconds()
*/ */
protected int getMaxInactiveIntervalInSeconds() { protected int getMaxInactiveIntervalInSeconds() {
@@ -229,7 +244,8 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
} }
/** /**
* Sets the {@link RegionShortcut} used to configure the GemFire Cache Region that will store Spring Sessions. * Sets the {@link RegionShortcut} used to configure the GemFire Cache Region that
* will store Spring Sessions.
* *
* @param shortcut the RegionShortcut used to configure the GemFire Cache Region. * @param shortcut the RegionShortcut used to configure the GemFire Cache Region.
* @see com.gemstone.gemfire.cache.RegionShortcut * @see com.gemstone.gemfire.cache.RegionShortcut
@@ -239,111 +255,131 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
} }
/** /**
* Gets the {@link RegionShortcut} used to configure the GemFire Cache Region that will store Spring Sessions. * Gets the {@link RegionShortcut} used to configure the GemFire Cache Region that
* Defaults to {@link RegionShortcut#PARTITION}. * will store Spring Sessions. Defaults to {@link RegionShortcut#PARTITION}.
* *
* @return the RegionShortcut used to configure the GemFire Cache Region. * @return the RegionShortcut used to configure the GemFire Cache Region.
* @see com.gemstone.gemfire.cache.RegionShortcut * @see com.gemstone.gemfire.cache.RegionShortcut
* @see EnableGemFireHttpSession#serverRegionShortcut() * @see EnableGemFireHttpSession#serverRegionShortcut()
*/ */
protected RegionShortcut getServerRegionShortcut() { protected RegionShortcut getServerRegionShortcut() {
return (this.serverRegionShortcut != null ? this.serverRegionShortcut : DEFAULT_SERVER_REGION_SHORTCUT); return (this.serverRegionShortcut != null ? this.serverRegionShortcut
: DEFAULT_SERVER_REGION_SHORTCUT);
} }
/** /**
* Sets the name of the Gemfire (Client)Cache Region used to store Sessions. * Sets the name of the Gemfire (Client)Cache Region used to store Sessions.
* *
* @param springSessionGemFireRegionName a String specifying the name of the GemFire (Client)Cache Region * @param springSessionGemFireRegionName a String specifying the name of the GemFire
* used to store the Session. * (Client)Cache Region used to store the Session.
*/ */
public void setSpringSessionGemFireRegionName(String springSessionGemFireRegionName) { public void setSpringSessionGemFireRegionName(String springSessionGemFireRegionName) {
this.springSessionGemFireRegionName = springSessionGemFireRegionName; this.springSessionGemFireRegionName = springSessionGemFireRegionName;
} }
/** /**
* Gets the name of the Gemfire (Client)Cache Region used to store Sessions. Defaults to 'ClusteredSpringSessions'. * Gets the name of the Gemfire (Client)Cache Region used to store Sessions. Defaults
* to 'ClusteredSpringSessions'.
* *
* @return a String specifying the name of the GemFire (Client)Cache Region * @return a String specifying the name of the GemFire (Client)Cache Region used to
* used to store the Session. * store the Session.
* @see com.gemstone.gemfire.cache.Region#getName() * @see com.gemstone.gemfire.cache.Region#getName()
* @see EnableGemFireHttpSession#regionName() * @see EnableGemFireHttpSession#regionName()
*/ */
protected String getSpringSessionGemFireRegionName() { protected String getSpringSessionGemFireRegionName() {
return (StringUtils.hasText(this.springSessionGemFireRegionName) ? this.springSessionGemFireRegionName return (StringUtils.hasText(this.springSessionGemFireRegionName)
? this.springSessionGemFireRegionName
: DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME); : DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME);
} }
/** /**
* Callback with the {@link AnnotationMetadata} of the class containing @Import annotation that imported * Callback with the {@link AnnotationMetadata} of the class containing @Import
* this @Configuration class. * annotation that imported this @Configuration class.
* *
* @param importMetadata the AnnotationMetadata of the class importing this @Configuration class. * @param importMetadata the AnnotationMetadata of the class importing
* @see org.springframework.session.data.gemfire.config.annotation.web.http.EnableGemFireHttpSession * this @Configuration class.
* @see org.springframework.session.data.gemfire.config.annotation.web.http.
* EnableGemFireHttpSession
* @see org.springframework.core.type.AnnotationMetadata * @see org.springframework.core.type.AnnotationMetadata
*/ */
public void setImportMetadata(AnnotationMetadata importMetadata) { public void setImportMetadata(AnnotationMetadata importMetadata) {
AnnotationAttributes enableGemFireHttpSessionAnnotationAttributes = AnnotationAttributes.fromMap( AnnotationAttributes enableGemFireHttpSessionAnnotationAttributes = AnnotationAttributes
importMetadata.getAnnotationAttributes(EnableGemFireHttpSession.class.getName())); .fromMap(importMetadata.getAnnotationAttributes(
EnableGemFireHttpSession.class.getName()));
setClientRegionShortcut(ClientRegionShortcut.class.cast(enableGemFireHttpSessionAnnotationAttributes.getEnum( setClientRegionShortcut(ClientRegionShortcut.class
"clientRegionShortcut"))); .cast(enableGemFireHttpSessionAnnotationAttributes
.getEnum("clientRegionShortcut")));
setIndexableSessionAttributes(enableGemFireHttpSessionAnnotationAttributes.getStringArray( setIndexableSessionAttributes(enableGemFireHttpSessionAnnotationAttributes
"indexableSessionAttributes")); .getStringArray("indexableSessionAttributes"));
setMaxInactiveIntervalInSeconds(enableGemFireHttpSessionAnnotationAttributes.getNumber( setMaxInactiveIntervalInSeconds(enableGemFireHttpSessionAnnotationAttributes
"maxInactiveIntervalInSeconds").intValue()); .getNumber("maxInactiveIntervalInSeconds").intValue());
setServerRegionShortcut(RegionShortcut.class.cast(enableGemFireHttpSessionAnnotationAttributes.getEnum( setServerRegionShortcut(
"serverRegionShortcut"))); RegionShortcut.class.cast(enableGemFireHttpSessionAnnotationAttributes
.getEnum("serverRegionShortcut")));
setSpringSessionGemFireRegionName(enableGemFireHttpSessionAnnotationAttributes.getString("regionName")); setSpringSessionGemFireRegionName(
enableGemFireHttpSessionAnnotationAttributes.getString("regionName"));
} }
/** /**
* Defines the Spring SessionRepository bean used to interact with GemFire as a Spring Session provider. * Defines the Spring SessionRepository bean used to interact with GemFire as a Spring
* Session provider.
* *
* @param gemfireOperations an instance of {@link GemfireOperations} used to manage Spring Sessions in GemFire. * @param gemfireOperations an instance of {@link GemfireOperations} used to manage
* @return a GemFireOperationsSessionRepository for managing (clustering/replicating) Sessions using GemFire. * Spring Sessions in GemFire.
* @return a GemFireOperationsSessionRepository for managing (clustering/replicating)
* Sessions using GemFire.
* @see org.springframework.session.data.gemfire.GemFireOperationsSessionRepository * @see org.springframework.session.data.gemfire.GemFireOperationsSessionRepository
* @see org.springframework.data.gemfire.GemfireOperations * @see org.springframework.data.gemfire.GemfireOperations
*/ */
@Bean @Bean
public GemFireOperationsSessionRepository sessionRepository(@Qualifier("sessionRegionTemplate") public GemFireOperationsSessionRepository sessionRepository(
GemfireOperations gemfireOperations) { @Qualifier("sessionRegionTemplate") GemfireOperations gemfireOperations) {
GemFireOperationsSessionRepository sessionRepository = new GemFireOperationsSessionRepository(gemfireOperations); GemFireOperationsSessionRepository sessionRepository = new GemFireOperationsSessionRepository(
gemfireOperations);
sessionRepository.setMaxInactiveIntervalInSeconds(getMaxInactiveIntervalInSeconds()); sessionRepository
.setMaxInactiveIntervalInSeconds(getMaxInactiveIntervalInSeconds());
return sessionRepository; return sessionRepository;
} }
/** /**
* Defines a Spring GemfireTemplate bean used to interact with GemFire's (Client)Cache {@link Region} * Defines a Spring GemfireTemplate bean used to interact with GemFire's (Client)Cache
* storing Sessions. * {@link Region} storing Sessions.
* *
* @param gemFireCache reference to the single GemFire cache instance used by the {@link GemfireTemplate} * @param gemFireCache reference to the single GemFire cache instance used by the
* to perform GemFire cache data access operations. * {@link GemfireTemplate} to perform GemFire cache data access operations.
* @return a {@link GemfireTemplate} used to interact with GemFire's (Client)Cache {@link Region} storing Sessions. * @return a {@link GemfireTemplate} used to interact with GemFire's (Client)Cache
* {@link Region} storing Sessions.
* @see org.springframework.data.gemfire.GemfireTemplate * @see org.springframework.data.gemfire.GemfireTemplate
* @see com.gemstone.gemfire.cache.Region * @see com.gemstone.gemfire.cache.Region
*/ */
@Bean @Bean
@DependsOn(DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME) @DependsOn(DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME)
public GemfireTemplate sessionRegionTemplate(GemFireCache gemFireCache) { public GemfireTemplate sessionRegionTemplate(GemFireCache gemFireCache) {
return new GemfireTemplate(gemFireCache.getRegion(getSpringSessionGemFireRegionName())); return new GemfireTemplate(
gemFireCache.getRegion(getSpringSessionGemFireRegionName()));
} }
/** /**
* Defines a Spring GemFire {@link com.gemstone.gemfire.cache.Cache} {@link Region} bean used to store * Defines a Spring GemFire {@link com.gemstone.gemfire.cache.Cache} {@link Region}
* and manage Sessions using either a client-server or peer-to-peer (p2p) topology. * bean used to store and manage Sessions using either a client-server or peer-to-peer
* (p2p) topology.
* *
* @param gemfireCache a reference to the GemFire {@link com.gemstone.gemfire.cache.Cache}. * @param gemfireCache a reference to the GemFire
* @param sessionRegionAttributes the GemFire {@link RegionAttributes} used to configure the {@link Region}. * {@link com.gemstone.gemfire.cache.Cache}.
* @return a {@link GemFireCacheTypeAwareRegionFactoryBean} used to configure and initialize a GemFire Cache * @param sessionRegionAttributes the GemFire {@link RegionAttributes} used to
* {@link Region} for storing and managing Sessions. * configure the {@link Region}.
* @see org.springframework.session.data.gemfire.config.annotation.web.http.support.GemFireCacheTypeAwareRegionFactoryBean * @return a {@link GemFireCacheTypeAwareRegionFactoryBean} used to configure and
* initialize a GemFire Cache {@link Region} for storing and managing Sessions.
* @see org.springframework.session.data.gemfire.config.annotation.web.http.support.
* GemFireCacheTypeAwareRegionFactoryBean
* @see com.gemstone.gemfire.cache.GemFireCache * @see com.gemstone.gemfire.cache.GemFireCache
* @see com.gemstone.gemfire.cache.RegionAttributes * @see com.gemstone.gemfire.cache.RegionAttributes
* @see #getClientRegionShortcut() * @see #getClientRegionShortcut()
@@ -351,11 +387,11 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
* @see #getServerRegionShortcut() * @see #getServerRegionShortcut()
*/ */
@Bean(name = DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME) @Bean(name = DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME)
public GemFireCacheTypeAwareRegionFactoryBean<Object, ExpiringSession> sessionRegion(GemFireCache gemfireCache, public GemFireCacheTypeAwareRegionFactoryBean<Object, ExpiringSession> sessionRegion(
GemFireCache gemfireCache,
RegionAttributes<Object, ExpiringSession> sessionRegionAttributes) { RegionAttributes<Object, ExpiringSession> sessionRegionAttributes) {
GemFireCacheTypeAwareRegionFactoryBean<Object, ExpiringSession> serverRegion = GemFireCacheTypeAwareRegionFactoryBean<Object, ExpiringSession> serverRegion = new GemFireCacheTypeAwareRegionFactoryBean<Object, ExpiringSession>();
new GemFireCacheTypeAwareRegionFactoryBean<Object, ExpiringSession>();
serverRegion.setGemfireCache(gemfireCache); serverRegion.setGemfireCache(gemfireCache);
serverRegion.setClientRegionShortcut(getClientRegionShortcut()); serverRegion.setClientRegionShortcut(getClientRegionShortcut());
@@ -367,13 +403,14 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
} }
/** /**
* Defines a Spring GemFire {@link RegionAttributes} bean used to configure and initialize the GemFire cache * Defines a Spring GemFire {@link RegionAttributes} bean used to configure and
* {@link Region} storing Sessions. Expiration is also configured for the {@link Region} on the basis that the * initialize the GemFire cache {@link Region} storing Sessions. Expiration is also
* GemFire cache {@link Region} is a not a proxy, on either the client or server. * configured for the {@link Region} on the basis that the GemFire cache
* {@link Region} is a not a proxy, on either the client or server.
* *
* @param gemfireCache a reference to the GemFire cache. * @param gemfireCache a reference to the GemFire cache.
* @return an instance of {@link RegionAttributes} used to configure and initialize the GemFire cache {@link Region} * @return an instance of {@link RegionAttributes} used to configure and initialize
* for storing and managing Sessions. * the GemFire cache {@link Region} for storing and managing Sessions.
* @see org.springframework.data.gemfire.RegionAttributesFactoryBean * @see org.springframework.data.gemfire.RegionAttributesFactoryBean
* @see com.gemstone.gemfire.cache.GemFireCache * @see com.gemstone.gemfire.cache.GemFireCache
* @see com.gemstone.gemfire.cache.PartitionAttributes * @see com.gemstone.gemfire.cache.PartitionAttributes
@@ -381,44 +418,49 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
*/ */
@Bean @Bean
@SuppressWarnings({ "unchecked", "deprecation" }) @SuppressWarnings({ "unchecked", "deprecation" })
public RegionAttributesFactoryBean sessionRegionAttributes(GemFireCache gemfireCache) { public RegionAttributesFactoryBean sessionRegionAttributes(
GemFireCache gemfireCache) {
RegionAttributesFactoryBean regionAttributes = new RegionAttributesFactoryBean(); RegionAttributesFactoryBean regionAttributes = new RegionAttributesFactoryBean();
regionAttributes.setKeyConstraint(SPRING_SESSION_GEMFIRE_REGION_KEY_CONSTRAINT); regionAttributes.setKeyConstraint(SPRING_SESSION_GEMFIRE_REGION_KEY_CONSTRAINT);
regionAttributes.setValueConstraint(SPRING_SESSION_GEMFIRE_REGION_VALUE_CONSTRAINT); regionAttributes
.setValueConstraint(SPRING_SESSION_GEMFIRE_REGION_VALUE_CONSTRAINT);
if (isExpirationAllowed(gemfireCache)) { if (isExpirationAllowed(gemfireCache)) {
regionAttributes.setStatisticsEnabled(true); regionAttributes.setStatisticsEnabled(true);
regionAttributes.setEntryIdleTimeout(new ExpirationAttributes( regionAttributes.setEntryIdleTimeout(new ExpirationAttributes(
Math.max(getMaxInactiveIntervalInSeconds(), 0), ExpirationAction.INVALIDATE)); Math.max(getMaxInactiveIntervalInSeconds(), 0),
ExpirationAction.INVALIDATE));
} }
return regionAttributes; return regionAttributes;
} }
/** /**
* Determines whether expiration configuration is allowed to be set on the GemFire cache {@link Region} * Determines whether expiration configuration is allowed to be set on the GemFire
* used to store and manage Sessions. * cache {@link Region} used to store and manage Sessions.
* *
* @param gemfireCache a reference to the GemFire cache. * @param gemfireCache a reference to the GemFire cache.
* @return a boolean indicating if a {@link Region} can be configured for Region entry idle-timeout expiration. * @return a boolean indicating if a {@link Region} can be configured for Region entry
* idle-timeout expiration.
* @see GemFireUtils#isClient(GemFireCache) * @see GemFireUtils#isClient(GemFireCache)
* @see GemFireUtils#isProxy(ClientRegionShortcut) * @see GemFireUtils#isProxy(ClientRegionShortcut)
* @see GemFireUtils#isProxy(RegionShortcut) * @see GemFireUtils#isProxy(RegionShortcut)
*/ */
boolean isExpirationAllowed(GemFireCache gemfireCache) { boolean isExpirationAllowed(GemFireCache gemfireCache) {
return !(GemFireUtils.isClient(gemfireCache) ? GemFireUtils.isProxy(getClientRegionShortcut()) return !(GemFireUtils.isClient(gemfireCache)
? GemFireUtils.isProxy(getClientRegionShortcut())
: GemFireUtils.isProxy(getServerRegionShortcut())); : GemFireUtils.isProxy(getServerRegionShortcut()));
} }
/** /**
* Defines a Spring GemFire Index bean on the GemFire cache {@link Region} storing and managing Sessions, * Defines a Spring GemFire Index bean on the GemFire cache {@link Region} storing and
* specifically on the 'principalName' property for quick lookup and queries. This index will only be created * managing Sessions, specifically on the 'principalName' property for quick lookup
* on a server @{link Region}. * and queries. This index will only be created on a server @{link Region}.
* *
* @param gemfireCache a reference to the GemFire cache. * @param gemfireCache a reference to the GemFire cache.
* @return a IndexFactoryBean creating an GemFire Index on the 'principalName' property of Sessions stored * @return a IndexFactoryBean creating an GemFire Index on the 'principalName'
* in the GemFire cache {@link Region}. * property of Sessions stored in the GemFire cache {@link Region}.
* @see org.springframework.data.gemfire.IndexFactoryBean * @see org.springframework.data.gemfire.IndexFactoryBean
* @see com.gemstone.gemfire.cache.GemFireCache * @see com.gemstone.gemfire.cache.GemFireCache
*/ */
@@ -445,12 +487,14 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
} }
/** /**
* Defines a Spring GemFire Index bean on the GemFire cache {@link Region} storing and managing Sessions, * Defines a Spring GemFire Index bean on the GemFire cache {@link Region} storing and
* specifically on Session attributes for quick lookup and queries on Session attribute names with a given value. * managing Sessions, specifically on Session attributes for quick lookup and queries
* This index will only be created on a server @{link Region}. * on Session attribute names with a given value. This index will only be created on a
* server @{link Region}.
* *
* @param gemfireCache a reference to the GemFire cache. * @param gemfireCache a reference to the GemFire cache.
* @return a IndexFactoryBean creating an GemFire Index on attributes of Sessions stored in the GemFire cache {@link Region}. * @return a IndexFactoryBean creating an GemFire Index on attributes of Sessions
* stored in the GemFire cache {@link Region}.
* @see org.springframework.data.gemfire.IndexFactoryBean * @see org.springframework.data.gemfire.IndexFactoryBean
* @see com.gemstone.gemfire.cache.GemFireCache * @see com.gemstone.gemfire.cache.GemFireCache
*/ */
@@ -460,7 +504,8 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
IndexFactoryBean index = new IndexFactoryBean() { IndexFactoryBean index = new IndexFactoryBean() {
@Override @Override
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
if (GemFireUtils.isPeer(gemfireCache) && !ObjectUtils.isEmpty(getIndexableSessionAttributes())) { if (GemFireUtils.isPeer(gemfireCache)
&& !ObjectUtils.isEmpty(getIndexableSessionAttributes())) {
super.afterPropertiesSet(); super.afterPropertiesSet();
} }
} }
@@ -468,8 +513,10 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
index.setCache(gemfireCache); index.setCache(gemfireCache);
index.setName("sessionAttributesIndex"); index.setName("sessionAttributesIndex");
index.setExpression(String.format("s.attributes[%1$s]", getIndexableSessionAttributesAsGemFireIndexExpression())); index.setExpression(String.format("s.attributes[%1$s]",
index.setFrom(String.format("%1$s s", GemFireUtils.toRegionPath(getSpringSessionGemFireRegionName()))); getIndexableSessionAttributesAsGemFireIndexExpression()));
index.setFrom(String.format("%1$s s",
GemFireUtils.toRegionPath(getSpringSessionGemFireRegionName())));
index.setOverride(true); index.setOverride(true);
return index; return index;

View File

@@ -34,8 +34,9 @@ import org.springframework.util.Assert;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
* The GemFireCacheTypeAwareRegionFactoryBean class is a Spring {@link FactoryBean} used to construct, configure * The GemFireCacheTypeAwareRegionFactoryBean class is a Spring {@link FactoryBean} used
* and initialize the GemFire cache {@link Region} used to store and manage Session state. * to construct, configure and initialize the GemFire cache {@link Region} used to store
* and manage Session state.
* *
* @param <K> the type of keys * @param <K> the type of keys
* @param <V> the type of values * @param <V> the type of values
@@ -45,7 +46,8 @@ import org.springframework.util.StringUtils;
* @see org.springframework.beans.factory.InitializingBean * @see org.springframework.beans.factory.InitializingBean
* @see org.springframework.data.gemfire.GenericRegionFactoryBean * @see org.springframework.data.gemfire.GenericRegionFactoryBean
* @see org.springframework.data.gemfire.client.ClientRegionFactoryBean * @see org.springframework.data.gemfire.client.ClientRegionFactoryBean
* @see org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration * @see org.springframework.session.data.gemfire.config.annotation.web.http.
* GemFireHttpSessionConfiguration
* @see com.gemstone.gemfire.cache.GemFireCache * @see com.gemstone.gemfire.cache.GemFireCache
* @see com.gemstone.gemfire.cache.InterestResultPolicy * @see com.gemstone.gemfire.cache.InterestResultPolicy
* @see com.gemstone.gemfire.cache.Region * @see com.gemstone.gemfire.cache.Region
@@ -53,16 +55,14 @@ import org.springframework.util.StringUtils;
* @see com.gemstone.gemfire.cache.RegionShortcut * @see com.gemstone.gemfire.cache.RegionShortcut
* @see com.gemstone.gemfire.cache.client.ClientRegionShortcut * @see com.gemstone.gemfire.cache.client.ClientRegionShortcut
*/ */
public class GemFireCacheTypeAwareRegionFactoryBean<K, V> implements FactoryBean<Region<K, V>>, InitializingBean { public class GemFireCacheTypeAwareRegionFactoryBean<K, V>
implements FactoryBean<Region<K, V>>, InitializingBean {
protected static final ClientRegionShortcut DEFAULT_CLIENT_REGION_SHORTCUT = protected static final ClientRegionShortcut DEFAULT_CLIENT_REGION_SHORTCUT = GemFireHttpSessionConfiguration.DEFAULT_CLIENT_REGION_SHORTCUT;
GemFireHttpSessionConfiguration.DEFAULT_CLIENT_REGION_SHORTCUT;
protected static final RegionShortcut DEFAULT_SERVER_REGION_SHORTCUT = protected static final RegionShortcut DEFAULT_SERVER_REGION_SHORTCUT = GemFireHttpSessionConfiguration.DEFAULT_SERVER_REGION_SHORTCUT;
GemFireHttpSessionConfiguration.DEFAULT_SERVER_REGION_SHORTCUT;
protected static final String DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME = protected static final String DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME = GemFireHttpSessionConfiguration.DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME;
GemFireHttpSessionConfiguration.DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME;
private ClientRegionShortcut clientRegionShortcut; private ClientRegionShortcut clientRegionShortcut;
@@ -77,9 +77,10 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> implements FactoryBean
private String regionName; private String regionName;
/** /**
* Post-construction initialization callback to create, configure and initialize the GemFire cache {@link Region} * Post-construction initialization callback to create, configure and initialize the
* used to store, replicate (distribute) and manage Session state. This method intelligently handles * GemFire cache {@link Region} used to store, replicate (distribute) and manage
* both client-server and peer-to-peer (p2p) GemFire supported distributed system topologies. * Session state. This method intelligently handles both client-server and
* peer-to-peer (p2p) GemFire supported distributed system topologies.
* *
* @throws Exception if the initialization of the GemFire cache {@link Region} fails. * @throws Exception if the initialization of the GemFire cache {@link Region} fails.
* @see org.springframework.session.data.gemfire.support.GemFireUtils#isClient(GemFireCache) * @see org.springframework.session.data.gemfire.support.GemFireUtils#isClient(GemFireCache)
@@ -95,13 +96,16 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> implements FactoryBean
} }
/** /**
* Constructs a GemFire cache {@link Region} using a peer-to-peer (p2p) GemFire topology to store * Constructs a GemFire cache {@link Region} using a peer-to-peer (p2p) GemFire
* and manage Session state in a GemFire server cluster accessible from a GemFire cache client. * topology to store and manage Session state in a GemFire server cluster accessible
* from a GemFire cache client.
* *
* @param gemfireCache a reference to the GemFire {@link com.gemstone.gemfire.cache.Cache}. * @param gemfireCache a reference to the GemFire
* @return a peer-to-peer-based GemFire cache {@link Region} to store and manage Session state. * {@link com.gemstone.gemfire.cache.Cache}.
* @throws Exception if the instantiation, configuration and initialization * @return a peer-to-peer-based GemFire cache {@link Region} to store and manage
* of the GemFire cache {@link Region} fails. * Session state.
* @throws Exception if the instantiation, configuration and initialization of the
* GemFire cache {@link Region} fails.
* @see org.springframework.data.gemfire.GenericRegionFactoryBean * @see org.springframework.data.gemfire.GenericRegionFactoryBean
* @see com.gemstone.gemfire.cache.GemFireCache * @see com.gemstone.gemfire.cache.GemFireCache
* @see com.gemstone.gemfire.cache.Region * @see com.gemstone.gemfire.cache.Region
@@ -122,13 +126,16 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> implements FactoryBean
} }
/** /**
* Constructs a GemFire cache {@link Region} using the client-server GemFire topology to store * Constructs a GemFire cache {@link Region} using the client-server GemFire topology
* and manage Session state in a GemFire server cluster accessible from a GemFire cache client. * to store and manage Session state in a GemFire server cluster accessible from a
* GemFire cache client.
* *
* @param gemfireCache a reference to the GemFire {@link com.gemstone.gemfire.cache.Cache}. * @param gemfireCache a reference to the GemFire
* @return a client-server-based GemFire cache {@link Region} to store and manage Session state. * {@link com.gemstone.gemfire.cache.Cache}.
* @throws Exception if the instantiation, configuration and initialization * @return a client-server-based GemFire cache {@link Region} to store and manage
* of the GemFire cache {@link Region} fails. * Session state.
* @throws Exception if the instantiation, configuration and initialization of the
* GemFire cache {@link Region} fails.
* @see org.springframework.data.gemfire.client.ClientRegionFactoryBean * @see org.springframework.data.gemfire.client.ClientRegionFactoryBean
* @see com.gemstone.gemfire.cache.GemFireCache * @see com.gemstone.gemfire.cache.GemFireCache
* @see com.gemstone.gemfire.cache.Region * @see com.gemstone.gemfire.cache.Region
@@ -155,12 +162,14 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> implements FactoryBean
/** /**
* Registers interests in all keys when the client {@link Region} is non-local. * Registers interests in all keys when the client {@link Region} is non-local.
* *
* @return an array of Interests specifying the server notifications of interests to the client. * @return an array of Interests specifying the server notifications of interests to
* the client.
* @see org.springframework.data.gemfire.client.Interest * @see org.springframework.data.gemfire.client.Interest
*/ */
/** /**
* Decides whether interests will be registered for all keys. Interests is only registered on a client * Decides whether interests will be registered for all keys. Interests is only
* and typically only when the client is a (CACHING) PROXY to the server (i.e. non-LOCAL only). * registered on a client and typically only when the client is a (CACHING) PROXY to
* the server (i.e. non-LOCAL only).
* *
* @param register a boolean value indicating whether interests should be registered. * @param register a boolean value indicating whether interests should be registered.
* @return an array of Interests KEY/VALUE registrations. * @return an array of Interests KEY/VALUE registrations.
@@ -168,13 +177,14 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> implements FactoryBean
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected Interest<K>[] registerInterests(boolean register) { protected Interest<K>[] registerInterests(boolean register) {
return (!register ? new Interest[0] : new Interest[] { return (!register ? new Interest[0]
new Interest<String>("ALL_KEYS", InterestResultPolicy.KEYS) : new Interest[] {
}); new Interest<String>("ALL_KEYS", InterestResultPolicy.KEYS) });
} }
/** /**
* Returns a reference to the constructed GemFire cache {@link Region} used to store and manage Session state. * Returns a reference to the constructed GemFire cache {@link Region} used to store
* and manage Session state.
* *
* @return the {@link Region} used to store and manage Session state. * @return the {@link Region} used to store and manage Session state.
* @throws Exception if the {@link Region} reference cannot be obtained. * @throws Exception if the {@link Region} reference cannot be obtained.
@@ -185,8 +195,8 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> implements FactoryBean
} }
/** /**
* Returns the specific type of GemFire cache {@link Region} this factory creates when initialized * Returns the specific type of GemFire cache {@link Region} this factory creates when
* or Region.class when uninitialized. * initialized or Region.class when uninitialized.
* *
* @return the GemFire cache {@link Region} class type constructed by this factory. * @return the GemFire cache {@link Region} class type constructed by this factory.
* @see com.gemstone.gemfire.cache.Region * @see com.gemstone.gemfire.cache.Region
@@ -197,19 +207,22 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> implements FactoryBean
} }
/** /**
* Returns true indicating the GemFire cache {@link Region} created by this factory is the sole instance. * Returns true indicating the GemFire cache {@link Region} created by this factory is
* the sole instance.
* *
* @return true to indicate the GemFire cache {@link Region} storing and managing Sessions is a Singleton. * @return true to indicate the GemFire cache {@link Region} storing and managing
* Sessions is a Singleton.
*/ */
public boolean isSingleton() { public boolean isSingleton() {
return true; return true;
} }
/** /**
* Sets the {@link Region} data policy used by the GemFire cache client to manage Session state. * Sets the {@link Region} data policy used by the GemFire cache client to manage
* Session state.
* *
* @param clientRegionShortcut a {@link ClientRegionShortcut} to specify the client {@link Region} * @param clientRegionShortcut a {@link ClientRegionShortcut} to specify the client
* data management policy. * {@link Region} data management policy.
* @see com.gemstone.gemfire.cache.client.ClientRegionShortcut * @see com.gemstone.gemfire.cache.client.ClientRegionShortcut
*/ */
public void setClientRegionShortcut(ClientRegionShortcut clientRegionShortcut) { public void setClientRegionShortcut(ClientRegionShortcut clientRegionShortcut) {
@@ -217,19 +230,22 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> implements FactoryBean
} }
/** /**
* Returns the {@link Region} data policy used by the GemFire cache client to manage Session state. Defaults to * Returns the {@link Region} data policy used by the GemFire cache client to manage
* {@link ClientRegionShortcut#PROXY}. * Session state. Defaults to {@link ClientRegionShortcut#PROXY}.
* *
* @return a {@link ClientRegionShortcut} specifying the client {@link Region} data management policy. * @return a {@link ClientRegionShortcut} specifying the client {@link Region} data
* management policy.
* @see org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration#DEFAULT_CLIENT_REGION_SHORTCUT * @see org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration#DEFAULT_CLIENT_REGION_SHORTCUT
* @see com.gemstone.gemfire.cache.client.ClientRegionShortcut * @see com.gemstone.gemfire.cache.client.ClientRegionShortcut
*/ */
protected ClientRegionShortcut getClientRegionShortcut() { protected ClientRegionShortcut getClientRegionShortcut() {
return (this.clientRegionShortcut != null ? this.clientRegionShortcut : DEFAULT_CLIENT_REGION_SHORTCUT); return (this.clientRegionShortcut != null ? this.clientRegionShortcut
: DEFAULT_CLIENT_REGION_SHORTCUT);
} }
/** /**
* Sets a reference to the GemFire cache used to construct the appropriate {@link Region}. * Sets a reference to the GemFire cache used to construct the appropriate
* {@link Region}.
* *
* @param gemfireCache a reference to the GemFire cache. * @param gemfireCache a reference to the GemFire cache.
* @throws IllegalArgumentException if the {@link GemFireCache} reference is null. * @throws IllegalArgumentException if the {@link GemFireCache} reference is null.
@@ -240,21 +256,24 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> implements FactoryBean
} }
/** /**
* Returns a reference to the GemFire cache used to construct the appropriate {@link Region}. * Returns a reference to the GemFire cache used to construct the appropriate
* {@link Region}.
* *
* @return a reference to the GemFire cache. * @return a reference to the GemFire cache.
* @throws IllegalStateException if the {@link GemFireCache} reference is null. * @throws IllegalStateException if the {@link GemFireCache} reference is null.
*/ */
protected GemFireCache getGemfireCache() { protected GemFireCache getGemfireCache() {
Assert.state(this.gemfireCache != null, "A reference to a GemFireCache was not properly configured"); Assert.state(this.gemfireCache != null,
"A reference to a GemFireCache was not properly configured");
return this.gemfireCache; return this.gemfireCache;
} }
/** /**
* Sets the GemFire {@link RegionAttributes} used to configure the GemFire cache {@link Region} used to * Sets the GemFire {@link RegionAttributes} used to configure the GemFire cache
* store and manage Session state. * {@link Region} used to store and manage Session state.
* *
* @param regionAttributes the GemFire {@link RegionAttributes} used to configure the GemFire cache {@link Region}. * @param regionAttributes the GemFire {@link RegionAttributes} used to configure the
* GemFire cache {@link Region}.
* @see com.gemstone.gemfire.cache.RegionAttributes * @see com.gemstone.gemfire.cache.RegionAttributes
*/ */
public void setRegionAttributes(RegionAttributes<K, V> regionAttributes) { public void setRegionAttributes(RegionAttributes<K, V> regionAttributes) {
@@ -262,10 +281,11 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> implements FactoryBean
} }
/** /**
* Returns the GemFire {@link RegionAttributes} used to configure the GemFire cache {@link Region} used to * Returns the GemFire {@link RegionAttributes} used to configure the GemFire cache
* store and manage Session state. * {@link Region} used to store and manage Session state.
* *
* @return the GemFire {@link RegionAttributes} used to configure the GemFire cache {@link Region}. * @return the GemFire {@link RegionAttributes} used to configure the GemFire cache
* {@link Region}.
* @see com.gemstone.gemfire.cache.RegionAttributes * @see com.gemstone.gemfire.cache.RegionAttributes
*/ */
protected RegionAttributes<K, V> getRegionAttributes() { protected RegionAttributes<K, V> getRegionAttributes() {
@@ -273,7 +293,8 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> implements FactoryBean
} }
/** /**
* Sets the name of the GemFire cache {@link Region} use to store and manage Session state. * Sets the name of the GemFire cache {@link Region} use to store and manage Session
* state.
* *
* @param regionName a String specifying the name of the GemFire cache {@link Region}. * @param regionName a String specifying the name of the GemFire cache {@link Region}.
*/ */
@@ -282,20 +303,23 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> implements FactoryBean
} }
/** /**
* Returns the configured name of the GemFire cache {@link Region} use to store and manage Session state. * Returns the configured name of the GemFire cache {@link Region} use to store and
* Defaults to "ClusteredSpringSessions" * manage Session state. Defaults to "ClusteredSpringSessions"
* *
* @return a String specifying the name of the GemFire cache {@link Region}. * @return a String specifying the name of the GemFire cache {@link Region}.
* @see com.gemstone.gemfire.cache.Region#getName() * @see com.gemstone.gemfire.cache.Region#getName()
*/ */
protected String getRegionName() { protected String getRegionName() {
return (StringUtils.hasText(this.regionName) ? this.regionName : DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME); return (StringUtils.hasText(this.regionName) ? this.regionName
: DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME);
} }
/** /**
* Sets the {@link Region} data policy used by the GemFire peer cache to manage Session state. * Sets the {@link Region} data policy used by the GemFire peer cache to manage
* Session state.
* *
* @param serverRegionShortcut a {@link RegionShortcut} to specify the peer {@link Region} data management policy. * @param serverRegionShortcut a {@link RegionShortcut} to specify the peer
* {@link Region} data management policy.
* @see com.gemstone.gemfire.cache.RegionShortcut * @see com.gemstone.gemfire.cache.RegionShortcut
*/ */
public void setServerRegionShortcut(RegionShortcut serverRegionShortcut) { public void setServerRegionShortcut(RegionShortcut serverRegionShortcut) {
@@ -303,14 +327,16 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> implements FactoryBean
} }
/** /**
* Returns the {@link Region} data policy used by the GemFire peer cache to manage Session state. Defaults to * Returns the {@link Region} data policy used by the GemFire peer cache to manage
* {@link RegionShortcut#PARTITION}. * Session state. Defaults to {@link RegionShortcut#PARTITION}.
* *
* @return a {@link RegionShortcut} specifying the peer {@link Region} data management policy. * @return a {@link RegionShortcut} specifying the peer {@link Region} data management
* policy.
* @see com.gemstone.gemfire.cache.RegionShortcut * @see com.gemstone.gemfire.cache.RegionShortcut
*/ */
protected RegionShortcut getServerRegionShortcut() { protected RegionShortcut getServerRegionShortcut() {
return (this.serverRegionShortcut != null ? this.serverRegionShortcut : DEFAULT_SERVER_REGION_SHORTCUT); return (this.serverRegionShortcut != null ? this.serverRegionShortcut
: DEFAULT_SERVER_REGION_SHORTCUT);
} }
} }

View File

@@ -28,8 +28,8 @@ import com.gemstone.gemfire.cache.client.ClientRegionShortcut;
import com.gemstone.gemfire.internal.cache.GemFireCacheImpl; import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
/** /**
* GemFireUtils is an abstract, extensible utility class for working with GemFire types and functionality * GemFireUtils is an abstract, extensible utility class for working with GemFire types
* and is used by Spring Session's GemFire adapter support classes. * and functionality and is used by Spring Session's GemFire adapter support classes.
* *
* @author John Blum * @author John Blum
* @since 1.1.0 * @since 1.1.0
@@ -40,8 +40,8 @@ public abstract class GemFireUtils {
* Null-safe method to close the given {@link Closeable} object. * Null-safe method to close the given {@link Closeable} object.
* *
* @param obj the {@link Closeable} object to close. * @param obj the {@link Closeable} object to close.
* @return true if the {@link Closeable} object is not null and was successfully closed, * @return true if the {@link Closeable} object is not null and was successfully
* otherwise return false. * closed, otherwise return false.
* @see java.io.Closeable * @see java.io.Closeable
*/ */
public static boolean close(Closeable obj) { public static boolean close(Closeable obj) {
@@ -67,7 +67,8 @@ public abstract class GemFireUtils {
*/ */
public static boolean isClient(GemFireCache gemFireCache) { public static boolean isClient(GemFireCache gemFireCache) {
boolean client = (gemFireCache instanceof ClientCache); boolean client = (gemFireCache instanceof ClientCache);
client &= (!(gemFireCache instanceof GemFireCacheImpl) || ((GemFireCacheImpl) gemFireCache).isClient()); client &= (!(gemFireCache instanceof GemFireCacheImpl)
|| ((GemFireCacheImpl) gemFireCache).isClient());
return client; return client;
} }
@@ -87,7 +88,8 @@ public abstract class GemFireUtils {
* Determines whether the given {@link ClientRegionShortcut} is local only. * Determines whether the given {@link ClientRegionShortcut} is local only.
* *
* @param shortcut the ClientRegionShortcut to evaluate. * @param shortcut the ClientRegionShortcut to evaluate.
* @return a boolean value indicating if the {@link ClientRegionShortcut} is local or not. * @return a boolean value indicating if the {@link ClientRegionShortcut} is local or
* not.
* @see com.gemstone.gemfire.cache.client.ClientRegionShortcut * @see com.gemstone.gemfire.cache.client.ClientRegionShortcut
*/ */
public static boolean isLocal(ClientRegionShortcut shortcut) { public static boolean isLocal(ClientRegionShortcut shortcut) {
@@ -104,12 +106,12 @@ public abstract class GemFireUtils {
} }
/** /**
* Determines whether the client {@link ClientRegionShortcut} is a proxy-based shortcut. * Determines whether the client {@link ClientRegionShortcut} is a proxy-based
* NOTE: "proxy"-based Regions keep no local state. * shortcut. NOTE: "proxy"-based Regions keep no local state.
* *
* @param shortcut the client {@link ClientRegionShortcut} to evaluate. * @param shortcut the client {@link ClientRegionShortcut} to evaluate.
* @return a boolean value indicating whether the client {@link ClientRegionShortcut} refers to * @return a boolean value indicating whether the client {@link ClientRegionShortcut}
* a proxy-based shortcut. * refers to a proxy-based shortcut.
* @see com.gemstone.gemfire.cache.client.ClientRegionShortcut * @see com.gemstone.gemfire.cache.client.ClientRegionShortcut
*/ */
public static boolean isProxy(ClientRegionShortcut shortcut) { public static boolean isProxy(ClientRegionShortcut shortcut) {
@@ -122,11 +124,12 @@ public abstract class GemFireUtils {
} }
/** /**
* Determines whether the peer {@link RegionShortcut} is a proxy-based shortcut. NOTE: "proxy"-based Regions * Determines whether the peer {@link RegionShortcut} is a proxy-based shortcut. NOTE:
* keep no local state. * "proxy"-based Regions keep no local state.
* *
* @param shortcut the peer {@link RegionShortcut} to evaluate. * @param shortcut the peer {@link RegionShortcut} to evaluate.
* @return a boolean value indicating whether the peer {@link RegionShortcut} refers to a proxy-based shortcut. * @return a boolean value indicating whether the peer {@link RegionShortcut} refers
* to a proxy-based shortcut.
* @see com.gemstone.gemfire.cache.RegionShortcut * @see com.gemstone.gemfire.cache.RegionShortcut
*/ */
public static boolean isProxy(RegionShortcut shortcut) { public static boolean isProxy(RegionShortcut shortcut) {

View File

@@ -1,7 +1,25 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.mongo; package org.springframework.session.data.mongo;
import java.util.List;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.core.convert.converter.GenericConverter; import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.IndexOperations; import org.springframework.data.mongodb.core.IndexOperations;
@@ -9,12 +27,10 @@ import org.springframework.data.mongodb.core.index.Index;
import org.springframework.data.mongodb.core.index.IndexInfo; import org.springframework.data.mongodb.core.index.IndexInfo;
import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Query;
import java.util.List;
/** /**
* Base class for serializing and deserializing session objects. * Base class for serializing and deserializing session objects. To create custom
* To create custom serializer you have to implement this interface * serializer you have to implement this interface and simply register your class as a
* and simply register your class as a bean. * bean.
* *
* @author Jakub Kubrynski * @author Jakub Kubrynski
* @since 1.2 * @since 1.2
@@ -26,7 +42,7 @@ public abstract class AbstractMongoSessionConverter implements GenericConverter
protected static final String EXPIRE_AT_FIELD_NAME = "expireAt"; protected static final String EXPIRE_AT_FIELD_NAME = "expireAt";
/** /**
* Returns query to be executed to return sessions based on a particular index * Returns query to be executed to return sessions based on a particular index.
* @param indexName name of the index * @param indexName name of the index
* @param indexValue value to query against * @param indexValue value to query against
* @return built query or null if indexName is not supported * @return built query or null if indexName is not supported
@@ -34,23 +50,26 @@ public abstract class AbstractMongoSessionConverter implements GenericConverter
protected abstract Query getQueryForIndex(String indexName, Object indexValue); protected abstract Query getQueryForIndex(String indexName, Object indexValue);
/** /**
* Method ensures that there is a TTL index on {@literal expireAt} field. * Method ensures that there is a TTL index on {@literal expireAt} field. It's has
* It's has {@literal expireAfterSeconds} set to zero seconds, so the expiration * {@literal expireAfterSeconds} set to zero seconds, so the expiration time is
* time is controlled by the application. * controlled by the application.
* *
* It can be extended in custom converters when there is a need for creating * It can be extended in custom converters when there is a need for creating
* additional custom indexes. * additional custom indexes.
* @param sessionCollectionIndexes {@link IndexOperations} to use
*/ */
protected void ensureIndexes(IndexOperations sessionCollectionIndexes) { protected void ensureIndexes(IndexOperations sessionCollectionIndexes) {
List<IndexInfo> indexInfo = sessionCollectionIndexes.getIndexInfo(); List<IndexInfo> indexInfo = sessionCollectionIndexes.getIndexInfo();
for (IndexInfo info : indexInfo) { for (IndexInfo info : indexInfo) {
if (EXPIRE_AT_FIELD_NAME.equals(info.getName())) { if (EXPIRE_AT_FIELD_NAME.equals(info.getName())) {
LOG.debug("TTL index on field " + EXPIRE_AT_FIELD_NAME + " already exists"); LOG.debug(
"TTL index on field " + EXPIRE_AT_FIELD_NAME + " already exists");
return; return;
} }
} }
LOG.info("Creating TTL index on field " + EXPIRE_AT_FIELD_NAME); LOG.info("Creating TTL index on field " + EXPIRE_AT_FIELD_NAME);
sessionCollectionIndexes sessionCollectionIndexes
.ensureIndex(new Index(EXPIRE_AT_FIELD_NAME, Sort.Direction.ASC).named(EXPIRE_AT_FIELD_NAME).expire(0)); .ensureIndex(new Index(EXPIRE_AT_FIELD_NAME, Sort.Direction.ASC)
.named(EXPIRE_AT_FIELD_NAME).expire(0));
} }
} }

View File

@@ -1,21 +1,36 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.mongo; package org.springframework.session.data.mongo;
import org.springframework.expression.Expression; import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser;
/** /**
* Utility class to extract principal name from {@code Authentication} object * Utility class to extract principal name from {@code Authentication} object.
* *
* @author Jakub Kubrynski * @author Jakub Kubrynski
*/ */
class AuthenticationParser { final class AuthenticationParser {
private static final String NAME_EXPRESSION = "authentication?.name"; private static final String NAME_EXPRESSION = "authentication?.name";
private static final SpelExpressionParser PARSER = new SpelExpressionParser(); private static final SpelExpressionParser PARSER = new SpelExpressionParser();
/** /**
* Extracts principal name from authentication * Extracts principal name from authentication.
* *
* @param authentication Authentication object * @param authentication Authentication object
* @return principal name * @return principal name
@@ -27,4 +42,7 @@ class AuthenticationParser {
} }
return null; return null;
} }
private AuthenticationParser() {
}
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2016 the original author or authors. * Copyright 2014-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -15,15 +15,6 @@
*/ */
package org.springframework.session.data.mongo; package org.springframework.session.data.mongo;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.session.Session;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
@@ -35,11 +26,20 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import static org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME; import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.Session;
/** /**
* {@code AbstractMongoSessionConverter} implementation transforming {@code MongoExpiringSession} to/from a BSON object * {@code AbstractMongoSessionConverter} implementation transforming.
* using standard Java serialization * {@code MongoExpiringSession} to/from a BSON object using standard Java serialization
* *
* @author Jakub Kubrynski * @author Jakub Kubrynski
* @since 1.2 * @since 1.2
@@ -57,25 +57,30 @@ class JdkMongoSessionConverter extends AbstractMongoSessionConverter {
private static final String PRINCIPAL_FIELD_NAME = "principal"; private static final String PRINCIPAL_FIELD_NAME = "principal";
private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT"; private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT";
@Override
public Query getQueryForIndex(String indexName, Object indexValue) { public Query getQueryForIndex(String indexName, Object indexValue) {
if (PRINCIPAL_NAME_INDEX_NAME.equals(indexName)) { if (FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME
.equals(indexName)) {
return Query.query(Criteria.where(PRINCIPAL_FIELD_NAME).is(indexValue)); return Query.query(Criteria.where(PRINCIPAL_FIELD_NAME).is(indexValue));
} }
return null; return null;
} }
public Set<ConvertiblePair> getConvertibleTypes() { public Set<ConvertiblePair> getConvertibleTypes() {
return Collections.singleton(new ConvertiblePair(DBObject.class, MongoExpiringSession.class)); return Collections.singleton(
new ConvertiblePair(DBObject.class, MongoExpiringSession.class));
} }
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { public Object convert(Object source, TypeDescriptor sourceType,
TypeDescriptor targetType) {
if (source == null) { if (source == null) {
return null; return null;
} }
if (DBObject.class.isAssignableFrom(sourceType.getType())) { if (DBObject.class.isAssignableFrom(sourceType.getType())) {
return convert((DBObject) source); return convert((DBObject) source);
} else { }
else {
return convert((MongoExpiringSession) source); return convert((MongoExpiringSession) source);
} }
} }
@@ -103,24 +108,29 @@ class JdkMongoSessionConverter extends AbstractMongoSessionConverter {
outputStream.writeObject(attributes); outputStream.writeObject(attributes);
outputStream.flush(); outputStream.flush();
return out.toByteArray(); return out.toByteArray();
} catch (IOException e) { }
catch (IOException e) {
LOG.error("Exception during session serialization", e); LOG.error("Exception during session serialization", e);
throw new IllegalStateException("Cannot serialize session", e); throw new IllegalStateException("Cannot serialize session", e);
} }
} }
private String extractPrincipal(Session expiringSession) { private String extractPrincipal(Session expiringSession) {
String resolvedPrincipal = AuthenticationParser.extractName(expiringSession.getAttribute(SPRING_SECURITY_CONTEXT)); String resolvedPrincipal = AuthenticationParser
.extractName(expiringSession.getAttribute(SPRING_SECURITY_CONTEXT));
if (resolvedPrincipal != null) { if (resolvedPrincipal != null) {
return resolvedPrincipal; return resolvedPrincipal;
} else { }
return expiringSession.getAttribute(PRINCIPAL_NAME_INDEX_NAME); else {
return expiringSession.getAttribute(
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME);
} }
} }
private MongoExpiringSession convert(DBObject sessionWrapper) { private MongoExpiringSession convert(DBObject sessionWrapper) {
MongoExpiringSession session = MongoExpiringSession session = new MongoExpiringSession(
new MongoExpiringSession((String) sessionWrapper.get(ID), (Integer) sessionWrapper.get(MAX_INTERVAL)); (String) sessionWrapper.get(ID),
(Integer) sessionWrapper.get(MAX_INTERVAL));
session.setCreationTime((Long) sessionWrapper.get(CREATION_TIME)); session.setCreationTime((Long) sessionWrapper.get(CREATION_TIME));
session.setLastAccessedTime((Long) sessionWrapper.get(LAST_ACCESSED_TIME)); session.setLastAccessedTime((Long) sessionWrapper.get(LAST_ACCESSED_TIME));
session.setExpireAt((Date) sessionWrapper.get(EXPIRE_AT_FIELD_NAME)); session.setExpireAt((Date) sessionWrapper.get(EXPIRE_AT_FIELD_NAME));
@@ -131,17 +141,21 @@ class JdkMongoSessionConverter extends AbstractMongoSessionConverter {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void deserializeAttributes(DBObject sessionWrapper, Session session) { private void deserializeAttributes(DBObject sessionWrapper, Session session) {
try { try {
ByteArrayInputStream in = new ByteArrayInputStream((byte[]) sessionWrapper.get(ATTRIBUTES)); ByteArrayInputStream in = new ByteArrayInputStream(
(byte[]) sessionWrapper.get(ATTRIBUTES));
ObjectInputStream objectInputStream = new ObjectInputStream(in); ObjectInputStream objectInputStream = new ObjectInputStream(in);
Map<String, Object> attributes = (Map<String, Object>) objectInputStream.readObject(); Map<String, Object> attributes = (Map<String, Object>) objectInputStream
.readObject();
for (Map.Entry<String, Object> entry : attributes.entrySet()) { for (Map.Entry<String, Object> entry : attributes.entrySet()) {
session.setAttribute(entry.getKey(), entry.getValue()); session.setAttribute(entry.getKey(), entry.getValue());
} }
objectInputStream.close(); objectInputStream.close();
} catch (IOException e) { }
catch (IOException e) {
LOG.error("Exception during session deserialization", e); LOG.error("Exception during session deserialization", e);
throw new IllegalStateException("Cannot deserialize session", e); throw new IllegalStateException("Cannot deserialize session", e);
} catch (ClassNotFoundException e) { }
catch (ClassNotFoundException e) {
LOG.error("Exception during session deserialization", e); LOG.error("Exception during session deserialization", e);
throw new IllegalStateException("Cannot deserialize session", e); throw new IllegalStateException("Cannot deserialize session", e);
} }

Some files were not shown because too many files have changed in this diff Show More