Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
03f008f283 | ||
|
|
00e7110594 | ||
|
|
f973e63fce | ||
|
|
edbf8bf587 | ||
|
|
234f6c954a | ||
|
|
e0417523f6 | ||
|
|
5865b0a715 | ||
|
|
67201417df | ||
|
|
01a149737e | ||
|
|
2d6f505a30 | ||
|
|
7c616a1adf | ||
|
|
61b01d9ecd |
3
.github/ISSUE_TEMPLATE.md
vendored
Normal file
3
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
<!--
|
||||
Thanks for raising a Spring Session issue. Please provide a brief description of your problem along with the version of Spring Session that you are using. If possible, please also consider putting together a sample application that reproduces the issue.
|
||||
-->
|
||||
6
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
6
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
<!--
|
||||
Thanks for contributing to Spring Session. Please provide a brief description of your pull-request and reference any related issue numbers (prefix references with #).
|
||||
-->
|
||||
|
||||
<!-- Please also confirm that you have signed the CLA by put an [X] in the box below: -->
|
||||
- [] I have signed the CLA
|
||||
@@ -160,7 +160,7 @@ Specifically, we notice the following things about our response:
|
||||
* We have a header with the name of *x-auth-token* which contains a new session id
|
||||
* The current username is displayed
|
||||
|
||||
We can now use the *x-auth-token* to make another request without providing the username and password again. For example, the following outputs the the username just as before:
|
||||
We can now use the *x-auth-token* to make another request without providing the username and password again. For example, the following outputs the username just as before:
|
||||
|
||||
$ curl -v http://localhost:8080/ -H "x-auth-token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3"
|
||||
|
||||
|
||||
@@ -1037,7 +1037,8 @@ However, you can override the default `ConversionService` by providing a Bean na
|
||||
[[api-jdbcoperationssessionrepository-storage]]
|
||||
==== Storage Details
|
||||
|
||||
By default, this implementation uses `SPRING_SESSION` table to store sessions. Note that the table name can be easily customized as already described.
|
||||
By default, this implementation uses `SPRING_SESSION` and `SPRING_SESSION_ATTRIBUTES` tables to store sessions.
|
||||
Note that the table name can be easily customized as already described. In that case the table used to store attributes will be named using the provided table name, suffixed with `_ATTRIBUTES`.
|
||||
|
||||
Due to the differences between the various database vendors, especially when it comes to storing binary data, make sure to use SQL script specific to your database.
|
||||
Scripts for most major database vendors are packaged as `org/springframework/session/jdbc/schema-\*.sql`, where `*` is the target database type.
|
||||
|
||||
@@ -115,9 +115,7 @@ public class HttpSessionGemFireIndexingITests extends AbstractGemFireIntegration
|
||||
CacheFactoryBean gemfireCache = new CacheFactoryBean();
|
||||
|
||||
gemfireCache.setClose(true);
|
||||
gemfireCache.setLazyInitialize(false);
|
||||
gemfireCache.setProperties(gemfireProperties());
|
||||
gemfireCache.setUseBeanFactoryLocator(false);
|
||||
|
||||
return gemfireCache;
|
||||
}
|
||||
|
||||
@@ -50,9 +50,7 @@ public class GemFireHttpSessionConfig {
|
||||
CacheFactoryBean gemfireCache = new CacheFactoryBean();
|
||||
|
||||
gemfireCache.setClose(true);
|
||||
gemfireCache.setLazyInitialize(false);
|
||||
gemfireCache.setProperties(gemfireProperties());
|
||||
gemfireCache.setUseBeanFactoryLocator(false);
|
||||
|
||||
return gemfireCache;
|
||||
}
|
||||
|
||||
@@ -4,8 +4,9 @@ jacksonVersion=2.6.5
|
||||
jspApiVersion=2.0
|
||||
servletApiVersion=3.0.1
|
||||
jstlelVersion=1.2.5
|
||||
version=1.2.0.RC2
|
||||
springDataRedisVersion=1.6.2.RELEASE
|
||||
version=1.2.0.RC3
|
||||
springDataRedisVersion=1.7.1.RELEASE
|
||||
commonsLoggingVersion=1.2
|
||||
junitVersion=4.12
|
||||
gebVersion=0.13.1
|
||||
mockitoVersion=1.10.19
|
||||
@@ -14,11 +15,11 @@ seleniumVersion=2.52.0
|
||||
springSecurityVersion=4.0.3.RELEASE
|
||||
springVersion=4.2.5.RELEASE
|
||||
httpClientVersion=4.5.1
|
||||
jedisVersion=2.7.3
|
||||
jedisVersion=2.8.1
|
||||
h2Version=1.4.191
|
||||
springDataMongoVersion=1.8.2.RELEASE
|
||||
springDataMongoVersion=1.9.1.RELEASE
|
||||
springShellVersion=1.1.0.RELEASE
|
||||
springDataGemFireVersion=1.7.4.RELEASE
|
||||
springDataGemFireVersion=1.8.1.RELEASE
|
||||
assertjVersion=2.3.0
|
||||
spockVersion=1.0-groovy-2.4
|
||||
jstlVersion=1.2.1
|
||||
|
||||
@@ -27,8 +27,8 @@ import org.springframework.context.annotation.ImportResource;
|
||||
public class Application {
|
||||
|
||||
public static void main(final String[] args) {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
|
||||
Application.class);
|
||||
AnnotationConfigApplicationContext context =
|
||||
new AnnotationConfigApplicationContext(Application.class);
|
||||
context.registerShutdownHook();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,35 +51,32 @@ public class GemFireCacheServerReadyBeanPostProcessor implements BeanPostProcess
|
||||
|
||||
// tag::class[]
|
||||
static {
|
||||
ClientMembership
|
||||
.registerClientMembershipListener(new ClientMembershipListenerAdapter() {
|
||||
public void memberJoined(final ClientMembershipEvent event) {
|
||||
if (!event.isClient()) {
|
||||
latch.countDown();
|
||||
}
|
||||
ClientMembership.registerClientMembershipListener(
|
||||
new ClientMembershipListenerAdapter() {
|
||||
public void memberJoined(final ClientMembershipEvent event) {
|
||||
if (!event.isClient()) {
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@Resource(name = "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) {
|
||||
String host = getServerHost(DEFAULT_SERVER_HOST);
|
||||
Assert.isTrue(waitForCacheServerToStart(host, this.port),
|
||||
String.format(
|
||||
"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;
|
||||
}
|
||||
|
||||
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) {
|
||||
try {
|
||||
latch.await(DEFAULT_WAIT_DURATION, TimeUnit.MILLISECONDS);
|
||||
@@ -157,4 +154,5 @@ public class GemFireCacheServerReadyBeanPostProcessor implements BeanPostProcess
|
||||
|
||||
return condition.evaluate();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
<prop key="log-level">${sample.httpsession.gemfire.log-level:warning}</prop>
|
||||
</util:properties>
|
||||
|
||||
<gfe:client-cache properties-ref="gemfireProperties"/>
|
||||
|
||||
<!--7-->
|
||||
<gfe:pool free-connection-timeout="5000"
|
||||
keep-alive="false"
|
||||
@@ -47,9 +49,6 @@
|
||||
<gfe:server host="${application.gemfire.client-server.host}"
|
||||
port="${spring.session.data.gemfire.port:${application.gemfire.client-server.port}}"/>
|
||||
</gfe:pool>
|
||||
|
||||
<gfe:client-cache properties-ref="gemfireProperties"
|
||||
use-bean-factory-locator="false"/>
|
||||
<!-- end::beans[] -->
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -9,9 +9,7 @@
|
||||
<!-- tag::context-param[] -->
|
||||
<context-param>
|
||||
<param-name>contextConfigLocation</param-name>
|
||||
<param-value>
|
||||
/WEB-INF/spring/session-client.xml
|
||||
</param-value>
|
||||
<param-value>/WEB-INF/spring/session-client.xml</param-value>
|
||||
</context-param>
|
||||
<!-- end::context-param[] -->
|
||||
|
||||
@@ -23,9 +21,9 @@
|
||||
<filter-mapping>
|
||||
<filter-name>springSessionRepositoryFilter</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
<dispatcher>REQUEST</dispatcher>
|
||||
<dispatcher>ERROR</dispatcher>
|
||||
<dispatcher>ASYNC</dispatcher>
|
||||
<dispatcher>REQUEST</dispatcher>
|
||||
<dispatcher>ERROR</dispatcher>
|
||||
<dispatcher>ASYNC</dispatcher>
|
||||
</filter-mapping>
|
||||
<!-- end::springSessionRepositoryFilter[] -->
|
||||
|
||||
@@ -36,9 +34,7 @@
|
||||
-->
|
||||
<!-- tag::listeners[] -->
|
||||
<listener>
|
||||
<listener-class>
|
||||
org.springframework.web.context.ContextLoaderListener
|
||||
</listener-class>
|
||||
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
|
||||
</listener>
|
||||
<!-- end::listeners[] -->
|
||||
|
||||
|
||||
@@ -36,7 +36,6 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
import org.springframework.data.gemfire.client.ClientCacheFactoryBean;
|
||||
import org.springframework.data.gemfire.client.PoolFactoryBean;
|
||||
import org.springframework.data.gemfire.config.GemfireConstants;
|
||||
import org.springframework.data.gemfire.support.ConnectionEndpoint;
|
||||
import org.springframework.session.data.gemfire.config.annotation.web.http.EnableGemFireHttpSession;
|
||||
import org.springframework.session.data.gemfire.support.GemFireUtils;
|
||||
@@ -52,17 +51,20 @@ public class ClientConfig {
|
||||
static final CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
static {
|
||||
System.setProperty("gemfire.log-level",
|
||||
System.getProperty("sample.httpsession.gemfire.log-level", "warning"));
|
||||
System.setProperty("gemfire.log-level", logLevel());
|
||||
|
||||
ClientMembership
|
||||
.registerClientMembershipListener(new ClientMembershipListenerAdapter() {
|
||||
public void memberJoined(ClientMembershipEvent event) {
|
||||
if (!event.isClient()) {
|
||||
latch.countDown();
|
||||
}
|
||||
ClientMembership.registerClientMembershipListener(
|
||||
new ClientMembershipListenerAdapter() {
|
||||
public void memberJoined(ClientMembershipEvent event) {
|
||||
if (!event.isClient()) {
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static String logLevel() {
|
||||
return System.getProperty("sample.httpsession.gemfire.log-level", "warning");
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -75,14 +77,22 @@ public class ClientConfig {
|
||||
return new Properties();
|
||||
}
|
||||
|
||||
@Bean(name = GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME)
|
||||
@Bean
|
||||
ClientCacheFactoryBean gemfireCache() { // <4>
|
||||
ClientCacheFactoryBean clientCacheFactory = new ClientCacheFactoryBean();
|
||||
|
||||
clientCacheFactory.setClose(true);
|
||||
clientCacheFactory.setProperties(gemfireProperties());
|
||||
|
||||
return clientCacheFactory;
|
||||
}
|
||||
|
||||
@Bean
|
||||
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();
|
||||
|
||||
poolFactory.setName(GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME);
|
||||
poolFactory.setFreeConnectionTimeout(5000); // 5 seconds
|
||||
poolFactory.setKeepAlive(false);
|
||||
poolFactory.setMaxConnections(ServerConfig.MAX_CONNECTIONS);
|
||||
@@ -92,46 +102,29 @@ public class ClientConfig {
|
||||
poolFactory.setSubscriptionEnabled(true);
|
||||
poolFactory.setThreadLocalConnections(false);
|
||||
|
||||
poolFactory.setServerEndpoints(Collections.singletonList(
|
||||
new ConnectionEndpoint(ServerConfig.SERVER_HOSTNAME, port)));
|
||||
poolFactory.setServers(Collections.singletonList(
|
||||
new ConnectionEndpoint(ServerConfig.SERVER_HOSTNAME, port)));
|
||||
|
||||
return poolFactory;
|
||||
}
|
||||
|
||||
@Bean
|
||||
ClientCacheFactoryBean gemfireCache(Pool gemfirePool) { // <4>
|
||||
ClientCacheFactoryBean clientCacheFactory = new ClientCacheFactoryBean();
|
||||
|
||||
clientCacheFactory.setClose(true);
|
||||
clientCacheFactory.setProperties(gemfireProperties());
|
||||
clientCacheFactory.setPool(gemfirePool);
|
||||
clientCacheFactory.setUseBeanFactoryLocator(false);
|
||||
|
||||
return clientCacheFactory;
|
||||
}
|
||||
|
||||
@Bean
|
||||
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() {
|
||||
|
||||
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) {
|
||||
Assert.isTrue(
|
||||
waitForCacheServerToStart(ServerConfig.SERVER_HOSTNAME, port),
|
||||
String.format(
|
||||
"GemFire Server failed to start [hostname: %1$s, port: %2$d]",
|
||||
ServerConfig.SERVER_HOSTNAME, port));
|
||||
Assert.isTrue(waitForCacheServerToStart(ServerConfig.SERVER_HOSTNAME, port),
|
||||
String.format("GemFire Server failed to start [hostname: %1$s, port: %2$d]",
|
||||
ServerConfig.SERVER_HOSTNAME, port));
|
||||
}
|
||||
|
||||
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) {
|
||||
try {
|
||||
latch.await(DEFAULT_WAIT_DURATION, TimeUnit.MILLISECONDS);
|
||||
@@ -206,4 +199,5 @@ public class ClientConfig {
|
||||
|
||||
return condition.evaluate();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -49,20 +49,23 @@ public class ServerConfig {
|
||||
|
||||
gemfireProperties.setProperty("name", "GemFireClientServerHttpSessionSample");
|
||||
gemfireProperties.setProperty("mcast-port", "0");
|
||||
gemfireProperties.setProperty("log-level",
|
||||
System.getProperty("sample.httpsession.gemfire.log-level", "warning"));
|
||||
gemfireProperties.setProperty("log-level", logLevel());
|
||||
gemfireProperties.setProperty("jmx-manager", "true");
|
||||
gemfireProperties.setProperty("jmx-manager-start", "true");
|
||||
|
||||
return gemfireProperties;
|
||||
}
|
||||
|
||||
private String logLevel() {
|
||||
return System.getProperty("sample.httpsession.gemfire.log-level", "warning");
|
||||
}
|
||||
|
||||
@Bean
|
||||
CacheFactoryBean gemfireCache() { // <3>
|
||||
CacheFactoryBean gemfireCache = new CacheFactoryBean();
|
||||
|
||||
gemfireCache.setClose(true);
|
||||
gemfireCache.setProperties(gemfireProperties());
|
||||
gemfireCache.setUseBeanFactoryLocator(false);
|
||||
|
||||
return gemfireCache;
|
||||
}
|
||||
@@ -76,6 +79,7 @@ public class ServerConfig {
|
||||
cacheServerFactory.setAutoStartup(true);
|
||||
cacheServerFactory.setBindAddress(SERVER_HOSTNAME);
|
||||
cacheServerFactory.setCache(gemfireCache);
|
||||
cacheServerFactory.setHostNameForClients(SERVER_HOSTNAME);
|
||||
cacheServerFactory.setMaxConnections(MAX_CONNECTIONS);
|
||||
cacheServerFactory.setPort(port);
|
||||
|
||||
@@ -86,5 +90,6 @@ public class ServerConfig {
|
||||
public static void main(final String[] args) throws IOException { // <5>
|
||||
new AnnotationConfigApplicationContext(ServerConfig.class).registerShutdownHook();
|
||||
}
|
||||
|
||||
}
|
||||
// end::class[]
|
||||
|
||||
@@ -44,8 +44,8 @@ public class Config {
|
||||
CacheFactoryBean gemfireCache() { // <3>
|
||||
CacheFactoryBean gemfireCache = new CacheFactoryBean();
|
||||
|
||||
gemfireCache.setClose(true);
|
||||
gemfireCache.setProperties(gemfireProperties());
|
||||
gemfireCache.setUseBeanFactoryLocator(false);
|
||||
|
||||
return gemfireCache;
|
||||
}
|
||||
|
||||
@@ -6,9 +6,12 @@ apply plugin: 'spring-io'
|
||||
description = "Aggregator for Spring Session and Spring Data Redis"
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-session'),
|
||||
"org.springframework.data:spring-data-redis:$springDataRedisVersion",
|
||||
"redis.clients:jedis:$jedisVersion",
|
||||
compile project(':spring-session')
|
||||
compile ("org.springframework.data:spring-data-redis:$springDataRedisVersion") {
|
||||
exclude group: "org.slf4j", module: 'slf4j-api'
|
||||
exclude group: "org.slf4j", module: 'jcl-over-slf4j'
|
||||
}
|
||||
compile "redis.clients:jedis:$jedisVersion",
|
||||
"org.apache.commons:commons-pool2:$commonsPoolVersion"
|
||||
}
|
||||
|
||||
@@ -18,4 +21,4 @@ dependencyManagement {
|
||||
mavenBom "io.spring.platform:platform-bom:${springIoVersion}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ configurations {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile "commons-logging:commons-logging:$commonsLoggingVersion"
|
||||
optional "org.springframework.data:spring-data-redis:$springDataRedisVersion",
|
||||
"com.hazelcast:hazelcast:$hazelcastVersion",
|
||||
"org.springframework.data:spring-data-gemfire:$springDataGemFireVersion",
|
||||
@@ -25,7 +26,7 @@ dependencies {
|
||||
"org.springframework:spring-messaging:$springVersion",
|
||||
"org.springframework:spring-websocket:$springVersion"
|
||||
provided "javax.servlet:javax.servlet-api:$servletApiVersion"
|
||||
integrationTestCompile "redis.clients:jedis:2.4.1",
|
||||
integrationTestCompile "redis.clients:jedis:$jedisVersion",
|
||||
"org.apache.commons:commons-pool2:2.2",
|
||||
"com.hazelcast:hazelcast-client:$hazelcastVersion",
|
||||
"com.h2database:h2:$h2Version",
|
||||
|
||||
@@ -65,24 +65,25 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
public abstract class AbstractGemFireIntegrationTests {
|
||||
|
||||
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 long DEFAULT_WAIT_DURATION = TimeUnit.SECONDS.toMillis(20);
|
||||
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 GEMFIRE_LOG_FILE_NAME = System
|
||||
.getProperty("spring.session.data.gemfire.log-file", "server.log");
|
||||
protected static final String GEMFIRE_LOG_FILE_NAME =
|
||||
System.getProperty("spring.session.data.gemfire.log-file", "server.log");
|
||||
|
||||
protected static final String GEMFIRE_LOG_LEVEL = System
|
||||
.getProperty("spring.session.data.gemfire.log-level", "warning");
|
||||
protected static final String GEMFIRE_LOG_LEVEL =
|
||||
System.getProperty("spring.session.data.gemfire.log-level", "warning");
|
||||
|
||||
@Autowired
|
||||
protected Cache gemfireCache;
|
||||
@@ -93,7 +94,7 @@ public abstract class AbstractGemFireIntegrationTests {
|
||||
@Before
|
||||
public void setup() {
|
||||
System.setProperty("gemfire.Query.VERBOSE",
|
||||
String.valueOf(isQueryDebuggingEnabled()));
|
||||
String.valueOf(isQueryDebuggingEnabled()));
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
|
||||
@@ -32,7 +32,6 @@ import com.gemstone.gemfire.cache.DataPolicy;
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
import com.gemstone.gemfire.cache.RegionAttributes;
|
||||
import com.gemstone.gemfire.cache.client.ClientCache;
|
||||
import com.gemstone.gemfire.cache.client.Pool;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
@@ -49,7 +48,6 @@ import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
import org.springframework.data.gemfire.CacheFactoryBean;
|
||||
import org.springframework.data.gemfire.client.ClientCacheFactoryBean;
|
||||
import org.springframework.data.gemfire.client.PoolFactoryBean;
|
||||
import org.springframework.data.gemfire.config.GemfireConstants;
|
||||
import org.springframework.data.gemfire.server.CacheServerFactoryBean;
|
||||
import org.springframework.data.gemfire.support.ConnectionEndpoint;
|
||||
import org.springframework.session.ExpiringSession;
|
||||
@@ -78,10 +76,8 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* @see org.junit.Test
|
||||
* @see org.junit.runner.RunWith
|
||||
* @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.
|
||||
* GemFireHttpSessionConfiguration
|
||||
* @see org.springframework.session.data.gemfire.config.annotation.web.http.EnableGemFireHttpSession
|
||||
* @see org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration
|
||||
* @see org.springframework.test.annotation.DirtiesContext
|
||||
* @see org.springframework.test.context.ContextConfiguration
|
||||
* @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner
|
||||
@@ -159,17 +155,17 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests
|
||||
public void setup() {
|
||||
assertThat(GemFireUtils.isClient(gemfireCache)).isTrue();
|
||||
|
||||
Region<Object, ExpiringSession> springSessionGemFireRegion = gemfireCache
|
||||
.getRegion(SPRING_SESSION_GEMFIRE_REGION_NAME);
|
||||
Region<Object, ExpiringSession> springSessionGemFireRegion =
|
||||
gemfireCache.getRegion(SPRING_SESSION_GEMFIRE_REGION_NAME);
|
||||
|
||||
assertThat(springSessionGemFireRegion).isNotNull();
|
||||
|
||||
RegionAttributes<Object, ExpiringSession> springSessionGemFireRegionAttributes = springSessionGemFireRegion
|
||||
.getAttributes();
|
||||
RegionAttributes<Object, ExpiringSession> springSessionGemFireRegionAttributes =
|
||||
springSessionGemFireRegion.getAttributes();
|
||||
|
||||
assertThat(springSessionGemFireRegionAttributes).isNotNull();
|
||||
assertThat(springSessionGemFireRegionAttributes.getDataPolicy())
|
||||
.isEqualTo(DataPolicy.EMPTY);
|
||||
.isEqualTo(DataPolicy.EMPTY);
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -270,54 +266,40 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests
|
||||
@Bean
|
||||
Properties gemfireProperties() {
|
||||
Properties gemfireProperties = new Properties();
|
||||
gemfireProperties.setProperty("name",
|
||||
ClientServerGemFireOperationsSessionRepositoryIntegrationTests.class
|
||||
.getName());
|
||||
gemfireProperties.setProperty("log-level", GEMFIRE_LOG_LEVEL);
|
||||
return gemfireProperties;
|
||||
}
|
||||
|
||||
@Bean(name = GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME)
|
||||
@Bean
|
||||
ClientCacheFactoryBean gemfireCache() {
|
||||
ClientCacheFactoryBean clientCacheFactory = new ClientCacheFactoryBean();
|
||||
|
||||
clientCacheFactory.setClose(true);
|
||||
clientCacheFactory.setProperties(gemfireProperties());
|
||||
|
||||
return clientCacheFactory;
|
||||
}
|
||||
|
||||
@Bean
|
||||
PoolFactoryBean gemfirePool(@Value("${spring.session.data.gemfire.port:"
|
||||
+ DEFAULT_GEMFIRE_SERVER_PORT + "}") int port) {
|
||||
PoolFactoryBean poolFactory = new PoolFactoryBean() {
|
||||
@Override
|
||||
protected Properties resolveGemfireProperties() {
|
||||
return gemfireProperties();
|
||||
}
|
||||
};
|
||||
PoolFactoryBean poolFactory = new PoolFactoryBean();
|
||||
|
||||
poolFactory.setName(GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME);
|
||||
poolFactory.setFreeConnectionTimeout(5000); // 5 seconds
|
||||
poolFactory.setKeepAlive(false);
|
||||
poolFactory.setMaxConnections(
|
||||
SpringSessionGemFireServerConfiguration.MAX_CONNECTIONS);
|
||||
poolFactory.setMaxConnections(SpringSessionGemFireServerConfiguration.MAX_CONNECTIONS);
|
||||
poolFactory.setPingInterval(TimeUnit.SECONDS.toMillis(5));
|
||||
poolFactory.setReadTimeout(2000); // 2 seconds
|
||||
poolFactory.setRetryAttempts(2);
|
||||
poolFactory.setSubscriptionEnabled(true);
|
||||
poolFactory.setThreadLocalConnections(false);
|
||||
|
||||
poolFactory
|
||||
.setServerEndpoints(Collections.singletonList(new ConnectionEndpoint(
|
||||
SpringSessionGemFireServerConfiguration.SERVER_HOSTNAME,
|
||||
port)));
|
||||
poolFactory.setServers(Collections.singletonList(new ConnectionEndpoint(
|
||||
SpringSessionGemFireServerConfiguration.SERVER_HOSTNAME, port)));
|
||||
|
||||
return poolFactory;
|
||||
}
|
||||
|
||||
@Bean
|
||||
ClientCacheFactoryBean gemfireCache(Pool gemfirePool) {
|
||||
ClientCacheFactoryBean clientCacheFactory = new ClientCacheFactoryBean();
|
||||
|
||||
clientCacheFactory.setClose(true);
|
||||
clientCacheFactory.setPool(gemfirePool);
|
||||
clientCacheFactory.setProperties(gemfireProperties());
|
||||
clientCacheFactory.setUseBeanFactoryLocator(false);
|
||||
|
||||
return clientCacheFactory;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SessionEventListener sessionEventListener() {
|
||||
return new SessionEventListener();
|
||||
@@ -335,7 +317,7 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests
|
||||
|
||||
for (InetSocketAddress server : clientCache.getCurrentServers()) {
|
||||
System.err.printf("GemFire Server [host: %1$s, port: %2$d]%n",
|
||||
server.getHostName(), server.getPort());
|
||||
server.getHostName(), server.getPort());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -366,12 +348,12 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests
|
||||
|
||||
@Bean
|
||||
CacheFactoryBean gemfireCache() {
|
||||
CacheFactoryBean cacheFactory = new CacheFactoryBean();
|
||||
CacheFactoryBean gemfireCache = new CacheFactoryBean();
|
||||
|
||||
cacheFactory.setProperties(gemfireProperties());
|
||||
cacheFactory.setUseBeanFactoryLocator(false);
|
||||
gemfireCache.setClose(true);
|
||||
gemfireCache.setProperties(gemfireProperties());
|
||||
|
||||
return cacheFactory;
|
||||
return gemfireCache;
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -391,9 +391,7 @@ public class GemFireOperationsSessionRepositoryIntegrationTests
|
||||
CacheFactoryBean gemfireCache = new CacheFactoryBean();
|
||||
|
||||
gemfireCache.setClose(true);
|
||||
gemfireCache.setLazyInitialize(false);
|
||||
gemfireCache.setProperties(gemfireProperties());
|
||||
gemfireCache.setUseBeanFactoryLocator(false);
|
||||
|
||||
return gemfireCache;
|
||||
}
|
||||
|
||||
@@ -253,9 +253,8 @@ public class EnableGemFireHttpSessionEventsIntegrationTests
|
||||
CacheFactoryBean gemfireCache() {
|
||||
CacheFactoryBean gemfireCache = new CacheFactoryBean();
|
||||
|
||||
gemfireCache.setLazyInitialize(false);
|
||||
gemfireCache.setClose(true);
|
||||
gemfireCache.setProperties(gemfireProperties());
|
||||
gemfireCache.setUseBeanFactoryLocator(false);
|
||||
|
||||
return gemfireCache;
|
||||
}
|
||||
|
||||
@@ -135,7 +135,6 @@ public class GemFireHttpSessionJavaConfigurationTests
|
||||
|
||||
cacheFactory.setClose(true);
|
||||
cacheFactory.setProperties(gemfireProperties());
|
||||
cacheFactory.setUseBeanFactoryLocator(false);
|
||||
|
||||
return cacheFactory;
|
||||
}
|
||||
|
||||
@@ -65,8 +65,8 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
|
||||
* The default maximum interval in seconds in which a Session can remain inactive
|
||||
* 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<GemFireSession> SPRING_SESSION_GEMFIRE_REGION_VALUE_CONSTRAINT = GemFireSession.class;
|
||||
@@ -152,7 +152,7 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
|
||||
*/
|
||||
protected ClientRegionShortcut getClientRegionShortcut() {
|
||||
return (this.clientRegionShortcut != null ? this.clientRegionShortcut
|
||||
: DEFAULT_CLIENT_REGION_SHORTCUT);
|
||||
: DEFAULT_CLIENT_REGION_SHORTCUT);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -175,7 +175,7 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
|
||||
*/
|
||||
protected String[] getIndexableSessionAttributes() {
|
||||
return (this.indexableSessionAttributes != null ? this.indexableSessionAttributes
|
||||
: DEFAULT_INDEXABLE_SESSION_ATTRIBUTES);
|
||||
: DEFAULT_INDEXABLE_SESSION_ATTRIBUTES);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -245,7 +245,7 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
|
||||
*/
|
||||
protected RegionShortcut getServerRegionShortcut() {
|
||||
return (this.serverRegionShortcut != null ? this.serverRegionShortcut
|
||||
: DEFAULT_SERVER_REGION_SHORTCUT);
|
||||
: DEFAULT_SERVER_REGION_SHORTCUT);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -269,8 +269,8 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
|
||||
*/
|
||||
protected String getSpringSessionGemFireRegionName() {
|
||||
return (StringUtils.hasText(this.springSessionGemFireRegionName)
|
||||
? this.springSessionGemFireRegionName
|
||||
: DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME);
|
||||
? this.springSessionGemFireRegionName
|
||||
: DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -281,26 +281,24 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
|
||||
* this @Configuration class.
|
||||
*/
|
||||
public void setImportMetadata(AnnotationMetadata importMetadata) {
|
||||
AnnotationAttributes enableGemFireHttpSessionAnnotationAttributes = AnnotationAttributes
|
||||
.fromMap(importMetadata.getAnnotationAttributes(
|
||||
EnableGemFireHttpSession.class.getName()));
|
||||
AnnotationAttributes enableGemFireHttpSessionAnnotationAttributes =
|
||||
AnnotationAttributes.fromMap(importMetadata.getAnnotationAttributes(
|
||||
EnableGemFireHttpSession.class.getName()));
|
||||
|
||||
setClientRegionShortcut(ClientRegionShortcut.class
|
||||
.cast(enableGemFireHttpSessionAnnotationAttributes
|
||||
.getEnum("clientRegionShortcut")));
|
||||
setClientRegionShortcut(ClientRegionShortcut.class.cast(
|
||||
enableGemFireHttpSessionAnnotationAttributes.getEnum("clientRegionShortcut")));
|
||||
|
||||
setIndexableSessionAttributes(enableGemFireHttpSessionAnnotationAttributes
|
||||
.getStringArray("indexableSessionAttributes"));
|
||||
.getStringArray("indexableSessionAttributes"));
|
||||
|
||||
setMaxInactiveIntervalInSeconds(enableGemFireHttpSessionAnnotationAttributes
|
||||
.getNumber("maxInactiveIntervalInSeconds").intValue());
|
||||
.getNumber("maxInactiveIntervalInSeconds").intValue());
|
||||
|
||||
setServerRegionShortcut(
|
||||
RegionShortcut.class.cast(enableGemFireHttpSessionAnnotationAttributes
|
||||
.getEnum("serverRegionShortcut")));
|
||||
setServerRegionShortcut(RegionShortcut.class.cast(
|
||||
enableGemFireHttpSessionAnnotationAttributes.getEnum("serverRegionShortcut")));
|
||||
|
||||
setSpringSessionGemFireRegionName(
|
||||
enableGemFireHttpSessionAnnotationAttributes.getString("regionName"));
|
||||
enableGemFireHttpSessionAnnotationAttributes.getString("regionName"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -316,11 +314,11 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
|
||||
public GemFireOperationsSessionRepository sessionRepository(
|
||||
@Qualifier("sessionRegionTemplate") GemfireOperations gemfireOperations) {
|
||||
|
||||
GemFireOperationsSessionRepository sessionRepository = new GemFireOperationsSessionRepository(
|
||||
gemfireOperations);
|
||||
GemFireOperationsSessionRepository sessionRepository =
|
||||
new GemFireOperationsSessionRepository(gemfireOperations);
|
||||
|
||||
sessionRepository
|
||||
.setMaxInactiveIntervalInSeconds(getMaxInactiveIntervalInSeconds());
|
||||
sessionRepository.setMaxInactiveIntervalInSeconds(
|
||||
getMaxInactiveIntervalInSeconds());
|
||||
|
||||
return sessionRepository;
|
||||
}
|
||||
@@ -339,8 +337,8 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
|
||||
@Bean
|
||||
@DependsOn(DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME)
|
||||
public GemfireTemplate sessionRegionTemplate(GemFireCache gemFireCache) {
|
||||
return new GemfireTemplate(
|
||||
gemFireCache.getRegion(getSpringSessionGemFireRegionName()));
|
||||
return new GemfireTemplate(gemFireCache.getRegion(
|
||||
getSpringSessionGemFireRegionName()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -363,7 +361,8 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
|
||||
GemFireCache gemfireCache,
|
||||
RegionAttributes<Object, ExpiringSession> sessionRegionAttributes) {
|
||||
|
||||
GemFireCacheTypeAwareRegionFactoryBean<Object, ExpiringSession> serverRegion = new GemFireCacheTypeAwareRegionFactoryBean<Object, ExpiringSession>();
|
||||
GemFireCacheTypeAwareRegionFactoryBean<Object, ExpiringSession> serverRegion =
|
||||
new GemFireCacheTypeAwareRegionFactoryBean<Object, ExpiringSession>();
|
||||
|
||||
serverRegion.setGemfireCache(gemfireCache);
|
||||
serverRegion.setClientRegionShortcut(getClientRegionShortcut());
|
||||
@@ -390,19 +389,18 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
|
||||
*/
|
||||
@Bean
|
||||
@SuppressWarnings({ "unchecked", "deprecation" })
|
||||
public RegionAttributesFactoryBean sessionRegionAttributes(
|
||||
GemFireCache gemfireCache) {
|
||||
public RegionAttributesFactoryBean sessionRegionAttributes(GemFireCache gemfireCache) {
|
||||
|
||||
RegionAttributesFactoryBean regionAttributes = new RegionAttributesFactoryBean();
|
||||
|
||||
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)) {
|
||||
regionAttributes.setStatisticsEnabled(true);
|
||||
regionAttributes.setEntryIdleTimeout(new ExpirationAttributes(
|
||||
Math.max(getMaxInactiveIntervalInSeconds(), 0),
|
||||
ExpirationAction.INVALIDATE));
|
||||
Math.max(getMaxInactiveIntervalInSeconds(), 0),
|
||||
ExpirationAction.INVALIDATE));
|
||||
}
|
||||
|
||||
return regionAttributes;
|
||||
@@ -421,8 +419,8 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
|
||||
*/
|
||||
boolean isExpirationAllowed(GemFireCache gemfireCache) {
|
||||
return !(GemFireUtils.isClient(gemfireCache)
|
||||
? GemFireUtils.isProxy(getClientRegionShortcut())
|
||||
: GemFireUtils.isProxy(getServerRegionShortcut()));
|
||||
? GemFireUtils.isProxy(getClientRegionShortcut())
|
||||
: GemFireUtils.isProxy(getServerRegionShortcut()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -486,9 +484,9 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
|
||||
index.setCache(gemfireCache);
|
||||
index.setName("sessionAttributesIndex");
|
||||
index.setExpression(String.format("s.attributes[%1$s]",
|
||||
getIndexableSessionAttributesAsGemFireIndexExpression()));
|
||||
getIndexableSessionAttributesAsGemFireIndexExpression()));
|
||||
index.setFrom(String.format("%1$s s",
|
||||
GemFireUtils.toRegionPath(getSpringSessionGemFireRegionName())));
|
||||
GemFireUtils.toRegionPath(getSpringSessionGemFireRegionName())));
|
||||
index.setOverride(true);
|
||||
|
||||
return index;
|
||||
|
||||
@@ -23,6 +23,8 @@ import com.gemstone.gemfire.cache.RegionAttributes;
|
||||
import com.gemstone.gemfire.cache.RegionShortcut;
|
||||
import com.gemstone.gemfire.cache.client.ClientRegionShortcut;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.data.gemfire.GenericRegionFactoryBean;
|
||||
@@ -43,9 +45,12 @@ import org.springframework.util.StringUtils;
|
||||
* @author John Blum
|
||||
* @since 1.1.0
|
||||
* @see org.springframework.data.gemfire.GenericRegionFactoryBean
|
||||
* @see org.springframework.beans.factory.BeanFactoryAware
|
||||
* @see org.springframework.beans.factory.FactoryBean
|
||||
* @see org.springframework.beans.factory.InitializingBean
|
||||
*/
|
||||
public class GemFireCacheTypeAwareRegionFactoryBean<K, V>
|
||||
implements FactoryBean<Region<K, V>>, InitializingBean {
|
||||
implements BeanFactoryAware, FactoryBean<Region<K, V>>, InitializingBean {
|
||||
|
||||
protected static final ClientRegionShortcut DEFAULT_CLIENT_REGION_SHORTCUT = GemFireHttpSessionConfiguration.DEFAULT_CLIENT_REGION_SHORTCUT;
|
||||
|
||||
@@ -53,6 +58,8 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V>
|
||||
|
||||
protected static final String DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME = GemFireHttpSessionConfiguration.DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME;
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
private ClientRegionShortcut clientRegionShortcut;
|
||||
|
||||
private GemFireCache gemfireCache;
|
||||
@@ -138,6 +145,7 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V>
|
||||
|
||||
ClientRegionShortcut shortcut = getClientRegionShortcut();
|
||||
|
||||
clientRegion.setBeanFactory(getBeanFactory());
|
||||
clientRegion.setCache(gemfireCache);
|
||||
clientRegion.setAttributes(getRegionAttributes());
|
||||
clientRegion.setInterests(registerInterests(!GemFireUtils.isLocal(shortcut)));
|
||||
@@ -206,6 +214,36 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V>
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a reference to the Spring {@link BeanFactory} responsible for
|
||||
* creating GemFire components.
|
||||
*
|
||||
* @param beanFactory reference to the Spring {@link BeanFactory}
|
||||
* @see org.springframework.beans.factory.BeanFactory
|
||||
* @throws IllegalArgumentException if the {@link BeanFactory} reference
|
||||
* is null.
|
||||
*/
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
Assert.notNull(beanFactory, "BeanFactory must not be null");
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to the Spring {@link BeanFactory} responsible for
|
||||
* creating GemFire components.
|
||||
*
|
||||
* @return a reference to the Spring {@link BeanFactory}
|
||||
* @throws IllegalStateException if the {@link BeanFactory} reference
|
||||
* is null.
|
||||
* @see org.springframework.beans.factory.BeanFactory
|
||||
*/
|
||||
protected BeanFactory getBeanFactory() {
|
||||
Assert.state(this.beanFactory != null,
|
||||
"A reference to the BeanFactory was not properly configured");
|
||||
return this.beanFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link Region} data policy used by the GemFire cache client to manage
|
||||
* Session state.
|
||||
@@ -240,7 +278,7 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V>
|
||||
* @throws IllegalArgumentException if the {@link GemFireCache} reference is null.
|
||||
*/
|
||||
public void setGemfireCache(GemFireCache gemfireCache) {
|
||||
Assert.notNull(gemfireCache, "The GemFireCache reference must not be null");
|
||||
Assert.notNull(gemfireCache, "GemFireCache must not be null");
|
||||
this.gemfireCache = gemfireCache;
|
||||
}
|
||||
|
||||
@@ -253,7 +291,7 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V>
|
||||
*/
|
||||
protected GemFireCache getGemfireCache() {
|
||||
Assert.state(this.gemfireCache != null,
|
||||
"A reference to a GemFireCache was not properly configured");
|
||||
"A reference to the GemFireCache was not properly configured");
|
||||
return this.gemfireCache;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,16 +25,18 @@ import org.springframework.data.mongodb.core.MongoOperations;
|
||||
import org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration;
|
||||
import org.springframework.session.data.mongo.AbstractMongoSessionConverter;
|
||||
import org.springframework.session.data.mongo.MongoOperationsSessionRepository;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Configuration class registering {@code MongoSessionRepository} bean. To import this
|
||||
* configuration use {@link EnableMongoHttpSession} annotation.
|
||||
*
|
||||
* @author Jakub Kubrynski
|
||||
* @author Eddú Meléndez
|
||||
* @since 1.2
|
||||
*/
|
||||
@Configuration
|
||||
class MongoHttpSessionConfiguration extends SpringHttpSessionConfiguration
|
||||
public class MongoHttpSessionConfiguration extends SpringHttpSessionConfiguration
|
||||
implements ImportAware {
|
||||
|
||||
private AbstractMongoSessionConverter mongoSessionConverter;
|
||||
@@ -43,18 +45,28 @@ class MongoHttpSessionConfiguration extends SpringHttpSessionConfiguration
|
||||
private String collectionName;
|
||||
|
||||
@Bean
|
||||
MongoOperationsSessionRepository mongoSessionRepository(
|
||||
public MongoOperationsSessionRepository mongoSessionRepository(
|
||||
MongoOperations mongoOperations) {
|
||||
MongoOperationsSessionRepository repository = new MongoOperationsSessionRepository(
|
||||
mongoOperations);
|
||||
repository.setCollectionName(this.collectionName);
|
||||
repository.setMaxInactiveIntervalInSeconds(this.maxInactiveIntervalInSeconds);
|
||||
if (this.mongoSessionConverter != null) {
|
||||
repository.setMongoSessionConverter(this.mongoSessionConverter);
|
||||
}
|
||||
if (StringUtils.hasText(this.collectionName)) {
|
||||
repository.setCollectionName(this.collectionName);
|
||||
}
|
||||
return repository;
|
||||
}
|
||||
|
||||
public void setCollectionName(String collectionName) {
|
||||
this.collectionName = collectionName;
|
||||
}
|
||||
|
||||
public void setMaxInactiveIntervalInSeconds(Integer maxInactiveIntervalInSeconds) {
|
||||
this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds;
|
||||
}
|
||||
|
||||
public void setImportMetadata(AnnotationMetadata importMetadata) {
|
||||
AnnotationAttributes attributes = AnnotationAttributes.fromMap(importMetadata
|
||||
.getAnnotationAttributes(EnableMongoHttpSession.class.getName()));
|
||||
|
||||
@@ -771,6 +771,9 @@ public class RedisOperationsSessionRepository implements
|
||||
* session.
|
||||
*/
|
||||
private void saveDelta() {
|
||||
if (this.delta.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
String sessionId = getId();
|
||||
getSessionBoundHashOperations(sessionId).putAll(this.delta);
|
||||
String principalSessionKey = getSessionAttrNameKey(
|
||||
@@ -781,7 +784,7 @@ public class RedisOperationsSessionRepository implements
|
||||
|| this.delta.containsKey(securityPrincipalSessionKey)) {
|
||||
if (this.originalPrincipalName != null) {
|
||||
String originalPrincipalRedisKey = getPrincipalKey(
|
||||
(String) this.originalPrincipalName);
|
||||
this.originalPrincipalName);
|
||||
RedisOperationsSessionRepository.this.sessionRedisOperations
|
||||
.boundSetOps(originalPrincipalRedisKey).remove(sessionId);
|
||||
}
|
||||
|
||||
@@ -16,9 +16,11 @@
|
||||
|
||||
package org.springframework.session.jdbc;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
@@ -36,11 +38,12 @@ import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.core.serializer.support.DeserializingConverter;
|
||||
import org.springframework.core.serializer.support.SerializingConverter;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
|
||||
import org.springframework.jdbc.core.JdbcOperations;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.PreparedStatementCreator;
|
||||
import org.springframework.jdbc.core.PreparedStatementSetter;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.jdbc.support.lob.DefaultLobHandler;
|
||||
@@ -84,20 +87,35 @@ import org.springframework.util.StringUtils;
|
||||
* <a href="http://docs.spring.io/spring/docs/current/spring-framework-reference/html/">
|
||||
* Spring Framework Reference Documentation</a>.
|
||||
* <p>
|
||||
* By default, this implementation uses <code>SPRING_SESSION</code> table to store
|
||||
* sessions. Note that the table name can be customized using the
|
||||
* {@link #setTableName(String)} method.
|
||||
* By default, this implementation uses <code>SPRING_SESSION</code> and
|
||||
* <code>SPRING_SESSION_ATTRIBUTES</code> tables to store sessions. Note that the table
|
||||
* name can be customized using the {@link #setTableName(String)} method. In that case the
|
||||
* table used to store attributes will be named using the provided table name, suffixed
|
||||
* with <code>_ATTRIBUTES</code>.
|
||||
*
|
||||
* Depending on your database, the table definition can be described as below:
|
||||
*
|
||||
* <pre class="code">
|
||||
* CREATE TABLE SPRING_SESSION (
|
||||
* SESSION_ID CHAR(36),
|
||||
* CREATION_TIME BIGINT NOT NULL,
|
||||
* LAST_ACCESS_TIME BIGINT NOT NULL,
|
||||
* MAX_INACTIVE_INTERVAL INT NOT NULL,
|
||||
* PRINCIPAL_NAME VARCHAR(100),
|
||||
* SESSION_BYTES BLOB,
|
||||
* CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID)
|
||||
* );
|
||||
*
|
||||
* CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME);
|
||||
*
|
||||
* CREATE TABLE SPRING_SESSION_ATTRIBUTES (
|
||||
* SESSION_ID CHAR(36),
|
||||
* ATTRIBUTE_NAME VARCHAR(100),
|
||||
* ATTRIBUTE_BYTES BYTEA,
|
||||
* CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME),
|
||||
* CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE
|
||||
* );
|
||||
*
|
||||
* CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID);
|
||||
* </pre>
|
||||
*
|
||||
* Due to the differences between the various database vendors, especially when it comes
|
||||
@@ -114,19 +132,49 @@ public class JdbcOperationsSessionRepository implements
|
||||
|
||||
private static final String DEFAULT_TABLE_NAME = "SPRING_SESSION";
|
||||
|
||||
private static final String CREATE_SESSION_QUERY = "INSERT INTO %TABLE_NAME%(SESSION_ID, LAST_ACCESS_TIME, PRINCIPAL_NAME, SESSION_BYTES) VALUES (?, ?, ?, ?)";
|
||||
private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT";
|
||||
|
||||
private static final String GET_SESSION_QUERY = "SELECT LAST_ACCESS_TIME, SESSION_BYTES FROM %TABLE_NAME% WHERE SESSION_ID = ?";
|
||||
private static final String CREATE_SESSION_QUERY =
|
||||
"INSERT INTO %TABLE_NAME%(SESSION_ID, CREATION_TIME, LAST_ACCESS_TIME, MAX_INACTIVE_INTERVAL, PRINCIPAL_NAME) " +
|
||||
"VALUES (?, ?, ?, ?, ?)";
|
||||
|
||||
private static final String UPDATE_SESSION_QUERY = "UPDATE %TABLE_NAME% SET LAST_ACCESS_TIME = ?, PRINCIPAL_NAME = ?, SESSION_BYTES = ? WHERE SESSION_ID = ?";
|
||||
private static final String CREATE_SESSION_ATTRIBUTE_QUERY =
|
||||
"INSERT INTO %TABLE_NAME%_ATTRIBUTES(SESSION_ID, ATTRIBUTE_NAME, ATTRIBUTE_BYTES) " +
|
||||
"VALUES (?, ?, ?)";
|
||||
|
||||
private static final String UPDATE_SESSION_LAST_ACCESS_TIME_QUERY = "UPDATE %TABLE_NAME% SET LAST_ACCESS_TIME = ? WHERE SESSION_ID = ?";
|
||||
private static final String GET_SESSION_QUERY =
|
||||
"SELECT S.SESSION_ID, S.CREATION_TIME, S.LAST_ACCESS_TIME, S.MAX_INACTIVE_INTERVAL, SA.ATTRIBUTE_NAME, SA.ATTRIBUTE_BYTES " +
|
||||
"FROM %TABLE_NAME% S " +
|
||||
"LEFT OUTER JOIN %TABLE_NAME%_ATTRIBUTES SA ON S.SESSION_ID = SA.SESSION_ID " +
|
||||
"WHERE S.SESSION_ID = ?";
|
||||
|
||||
private static final String DELETE_SESSION_QUERY = "DELETE FROM %TABLE_NAME% WHERE SESSION_ID = ?";
|
||||
private static final String UPDATE_SESSION_QUERY =
|
||||
"UPDATE %TABLE_NAME% SET LAST_ACCESS_TIME = ?, MAX_INACTIVE_INTERVAL = ?, PRINCIPAL_NAME = ? " +
|
||||
"WHERE SESSION_ID = ?";
|
||||
|
||||
private static final String LIST_SESSIONS_BY_PRINCIPAL_NAME_QUERY = "SELECT LAST_ACCESS_TIME, SESSION_BYTES FROM %TABLE_NAME% WHERE PRINCIPAL_NAME = ?";
|
||||
private static final String UPDATE_SESSION_ATTRIBUTE_QUERY =
|
||||
"UPDATE %TABLE_NAME%_ATTRIBUTES SET ATTRIBUTE_BYTES = ? " +
|
||||
"WHERE SESSION_ID = ? " +
|
||||
"AND ATTRIBUTE_NAME = ?";
|
||||
|
||||
private static final String DELETE_SESSIONS_BY_LAST_ACCESS_TIME_QUERY = "DELETE FROM %TABLE_NAME% WHERE LAST_ACCESS_TIME < ?";
|
||||
private static final String DELETE_SESSION_ATTRIBUTE_QUERY =
|
||||
"DELETE FROM %TABLE_NAME%_ATTRIBUTES " +
|
||||
"WHERE SESSION_ID = ? " +
|
||||
"AND ATTRIBUTE_NAME = ?";
|
||||
|
||||
private static final String DELETE_SESSION_QUERY =
|
||||
"DELETE FROM %TABLE_NAME% " +
|
||||
"WHERE SESSION_ID = ?";
|
||||
|
||||
private static final String LIST_SESSIONS_BY_PRINCIPAL_NAME_QUERY =
|
||||
"SELECT S.SESSION_ID, S.CREATION_TIME, S.LAST_ACCESS_TIME, S.MAX_INACTIVE_INTERVAL, SA.ATTRIBUTE_NAME, SA.ATTRIBUTE_BYTES " +
|
||||
"FROM %TABLE_NAME% S " +
|
||||
"LEFT OUTER JOIN %TABLE_NAME%_ATTRIBUTES SA ON S.SESSION_ID = SA.SESSION_ID " +
|
||||
"WHERE S.PRINCIPAL_NAME = ?";
|
||||
|
||||
private static final String DELETE_SESSIONS_BY_LAST_ACCESS_TIME_QUERY =
|
||||
"DELETE FROM %TABLE_NAME% " +
|
||||
"WHERE LAST_ACCESS_TIME < ?";
|
||||
|
||||
private static final Log logger = LogFactory
|
||||
.getLog(JdbcOperationsSessionRepository.class);
|
||||
@@ -231,9 +279,27 @@ public class JdbcOperationsSessionRepository implements
|
||||
|
||||
public void setValues(PreparedStatement ps) throws SQLException {
|
||||
ps.setString(1, session.getId());
|
||||
ps.setLong(2, session.getLastAccessedTime());
|
||||
ps.setString(3, session.getPrincipalName());
|
||||
serialize(ps, 4, session.delegate);
|
||||
ps.setLong(2, session.getCreationTime());
|
||||
ps.setLong(3, session.getLastAccessedTime());
|
||||
ps.setInt(4, session.getMaxInactiveIntervalInSeconds());
|
||||
ps.setString(5, session.getPrincipalName());
|
||||
}
|
||||
|
||||
});
|
||||
final List<String> attributeNames = new ArrayList<String>(session.getAttributeNames());
|
||||
JdbcOperationsSessionRepository.this.jdbcOperations.batchUpdate(
|
||||
getQuery(CREATE_SESSION_ATTRIBUTE_QUERY),
|
||||
new BatchPreparedStatementSetter() {
|
||||
|
||||
public void setValues(PreparedStatement ps, int i) throws SQLException {
|
||||
String attributeName = attributeNames.get(i);
|
||||
ps.setString(1, session.getId());
|
||||
ps.setString(2, attributeName);
|
||||
serialize(ps, 3, session.getAttribute(attributeName));
|
||||
}
|
||||
|
||||
public int getBatchSize() {
|
||||
return attributeNames.size();
|
||||
}
|
||||
|
||||
});
|
||||
@@ -242,10 +308,10 @@ public class JdbcOperationsSessionRepository implements
|
||||
});
|
||||
}
|
||||
else {
|
||||
if (session.isAttributesChanged()) {
|
||||
this.transactionOperations.execute(new TransactionCallbackWithoutResult() {
|
||||
this.transactionOperations.execute(new TransactionCallbackWithoutResult() {
|
||||
|
||||
protected void doInTransactionWithoutResult(TransactionStatus status) {
|
||||
protected void doInTransactionWithoutResult(TransactionStatus status) {
|
||||
if (session.isChanged()) {
|
||||
JdbcOperationsSessionRepository.this.jdbcOperations.update(
|
||||
getQuery(UPDATE_SESSION_QUERY),
|
||||
new PreparedStatementSetter() {
|
||||
@@ -253,55 +319,84 @@ public class JdbcOperationsSessionRepository implements
|
||||
public void setValues(PreparedStatement ps)
|
||||
throws SQLException {
|
||||
ps.setLong(1, session.getLastAccessedTime());
|
||||
ps.setString(2, session.getPrincipalName());
|
||||
serialize(ps, 3, session.delegate);
|
||||
ps.setInt(2, session.getMaxInactiveIntervalInSeconds());
|
||||
ps.setString(3, session.getPrincipalName());
|
||||
ps.setString(4, session.getId());
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
Map<String, Object> delta = session.getDelta();
|
||||
if (!delta.isEmpty()) {
|
||||
for (final Map.Entry<String, Object> entry : delta.entrySet()) {
|
||||
if (entry.getValue() == null) {
|
||||
JdbcOperationsSessionRepository.this.jdbcOperations.update(
|
||||
getQuery(DELETE_SESSION_ATTRIBUTE_QUERY),
|
||||
new PreparedStatementSetter() {
|
||||
|
||||
});
|
||||
}
|
||||
else if (session.isLastAccessTimeChanged()) {
|
||||
this.transactionOperations.execute(new TransactionCallbackWithoutResult() {
|
||||
public void setValues(PreparedStatement ps) throws SQLException {
|
||||
ps.setString(1, session.getId());
|
||||
ps.setString(2, entry.getKey());
|
||||
}
|
||||
|
||||
protected void doInTransactionWithoutResult(TransactionStatus status) {
|
||||
JdbcOperationsSessionRepository.this.jdbcOperations.update(
|
||||
getQuery(UPDATE_SESSION_LAST_ACCESS_TIME_QUERY),
|
||||
new PreparedStatementSetter() {
|
||||
});
|
||||
}
|
||||
else {
|
||||
int updatedCount = JdbcOperationsSessionRepository.this.jdbcOperations.update(
|
||||
getQuery(UPDATE_SESSION_ATTRIBUTE_QUERY),
|
||||
new PreparedStatementSetter() {
|
||||
|
||||
public void setValues(PreparedStatement ps)
|
||||
throws SQLException {
|
||||
ps.setLong(1, session.getLastAccessedTime());
|
||||
ps.setString(2, session.getId());
|
||||
}
|
||||
public void setValues(PreparedStatement ps) throws SQLException {
|
||||
serialize(ps, 1, entry.getValue());
|
||||
ps.setString(2, session.getId());
|
||||
ps.setString(3, entry.getKey());
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
if (updatedCount == 0) {
|
||||
JdbcOperationsSessionRepository.this.jdbcOperations.update(
|
||||
getQuery(CREATE_SESSION_ATTRIBUTE_QUERY),
|
||||
new PreparedStatementSetter() {
|
||||
|
||||
public void setValues(PreparedStatement ps) throws SQLException {
|
||||
ps.setString(1, session.getId());
|
||||
ps.setString(2, entry.getKey());
|
||||
serialize(ps, 3, entry.getValue());
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
session.clearChangeFlags();
|
||||
}
|
||||
|
||||
public JdbcSession getSession(final String id) {
|
||||
ExpiringSession session = this.transactionOperations.execute(new TransactionCallback<ExpiringSession>() {
|
||||
final ExpiringSession session = this.transactionOperations.execute(new TransactionCallback<ExpiringSession>() {
|
||||
|
||||
public ExpiringSession doInTransaction(TransactionStatus status) {
|
||||
try {
|
||||
return JdbcOperationsSessionRepository.this.jdbcOperations.queryForObject(
|
||||
getQuery(GET_SESSION_QUERY),
|
||||
new Object[] { id },
|
||||
JdbcOperationsSessionRepository.this.mapper);
|
||||
}
|
||||
catch (EmptyResultDataAccessException ignored) {
|
||||
List<ExpiringSession> sessions = JdbcOperationsSessionRepository.this.jdbcOperations.query(
|
||||
new PreparedStatementCreator() {
|
||||
|
||||
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
|
||||
PreparedStatement ps = con.prepareStatement(getQuery(GET_SESSION_QUERY),
|
||||
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
|
||||
ps.setString(1, id);
|
||||
return ps;
|
||||
}
|
||||
|
||||
},
|
||||
JdbcOperationsSessionRepository.this.mapper
|
||||
);
|
||||
if (sessions.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return sessions.get(0);
|
||||
}
|
||||
|
||||
});
|
||||
@@ -338,9 +433,19 @@ public class JdbcOperationsSessionRepository implements
|
||||
|
||||
public List<ExpiringSession> doInTransaction(TransactionStatus status) {
|
||||
return JdbcOperationsSessionRepository.this.jdbcOperations.query(
|
||||
getQuery(LIST_SESSIONS_BY_PRINCIPAL_NAME_QUERY),
|
||||
new Object[] { indexValue },
|
||||
JdbcOperationsSessionRepository.this.mapper);
|
||||
new PreparedStatementCreator() {
|
||||
|
||||
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
|
||||
PreparedStatement ps = con.prepareStatement(
|
||||
getQuery(LIST_SESSIONS_BY_PRINCIPAL_NAME_QUERY),
|
||||
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
|
||||
ps.setString(1, indexValue);
|
||||
return ps;
|
||||
}
|
||||
|
||||
},
|
||||
JdbcOperationsSessionRepository.this.mapper
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
@@ -402,9 +507,9 @@ public class JdbcOperationsSessionRepository implements
|
||||
|
||||
private static GenericConversionService createDefaultConversionService() {
|
||||
GenericConversionService converter = new GenericConversionService();
|
||||
converter.addConverter(ExpiringSession.class, byte[].class,
|
||||
converter.addConverter(Object.class, byte[].class,
|
||||
new SerializingConverter());
|
||||
converter.addConverter(byte[].class, ExpiringSession.class,
|
||||
converter.addConverter(byte[].class, Object.class,
|
||||
new DeserializingConverter());
|
||||
return converter;
|
||||
}
|
||||
@@ -413,20 +518,20 @@ public class JdbcOperationsSessionRepository implements
|
||||
return StringUtils.replace(base, "%TABLE_NAME%", this.tableName);
|
||||
}
|
||||
|
||||
private void serialize(PreparedStatement ps, int paramIndex, ExpiringSession session)
|
||||
private void serialize(PreparedStatement ps, int paramIndex, Object attributeValue)
|
||||
throws SQLException {
|
||||
this.lobHandler.getLobCreator().setBlobAsBytes(ps, paramIndex,
|
||||
(byte[]) this.conversionService.convert(session,
|
||||
TypeDescriptor.valueOf(ExpiringSession.class),
|
||||
(byte[]) this.conversionService.convert(attributeValue,
|
||||
TypeDescriptor.valueOf(Object.class),
|
||||
TypeDescriptor.valueOf(byte[].class)));
|
||||
}
|
||||
|
||||
private ExpiringSession deserialize(ResultSet rs, String columnName)
|
||||
private Object deserialize(ResultSet rs, String columnName)
|
||||
throws SQLException {
|
||||
return (ExpiringSession) this.conversionService.convert(
|
||||
return this.conversionService.convert(
|
||||
this.lobHandler.getBlobAsBytes(rs, columnName),
|
||||
TypeDescriptor.valueOf(byte[].class),
|
||||
TypeDescriptor.valueOf(ExpiringSession.class));
|
||||
TypeDescriptor.valueOf(Object.class));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -440,9 +545,9 @@ public class JdbcOperationsSessionRepository implements
|
||||
|
||||
private boolean isNew;
|
||||
|
||||
private boolean lastAccessTimeChanged;
|
||||
private boolean changed;
|
||||
|
||||
private boolean attributesChanged;
|
||||
private Map<String, Object> delta = new HashMap<String, Object>();
|
||||
|
||||
JdbcSession() {
|
||||
this.delegate = new MapSession();
|
||||
@@ -454,54 +559,28 @@ public class JdbcOperationsSessionRepository implements
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public boolean isNew() {
|
||||
boolean isNew() {
|
||||
return this.isNew;
|
||||
}
|
||||
|
||||
public boolean isLastAccessTimeChanged() {
|
||||
return this.lastAccessTimeChanged;
|
||||
boolean isChanged() {
|
||||
return this.changed;
|
||||
}
|
||||
|
||||
public boolean isAttributesChanged() {
|
||||
return this.attributesChanged;
|
||||
Map<String, Object> getDelta() {
|
||||
return this.delta;
|
||||
}
|
||||
|
||||
public void clearChangeFlags() {
|
||||
void clearChangeFlags() {
|
||||
this.isNew = false;
|
||||
this.lastAccessTimeChanged = false;
|
||||
this.attributesChanged = false;
|
||||
this.changed = false;
|
||||
this.delta.clear();
|
||||
}
|
||||
|
||||
public String getPrincipalName() {
|
||||
String getPrincipalName() {
|
||||
return PRINCIPAL_NAME_RESOLVER.resolvePrincipal(this);
|
||||
}
|
||||
|
||||
public long getCreationTime() {
|
||||
return this.delegate.getCreationTime();
|
||||
}
|
||||
|
||||
public void setLastAccessedTime(long lastAccessedTime) {
|
||||
this.delegate.setLastAccessedTime(lastAccessedTime);
|
||||
this.lastAccessTimeChanged = true;
|
||||
}
|
||||
|
||||
public long getLastAccessedTime() {
|
||||
return this.delegate.getLastAccessedTime();
|
||||
}
|
||||
|
||||
public void setMaxInactiveIntervalInSeconds(int interval) {
|
||||
this.delegate.setMaxInactiveIntervalInSeconds(interval);
|
||||
this.attributesChanged = true;
|
||||
}
|
||||
|
||||
public int getMaxInactiveIntervalInSeconds() {
|
||||
return this.delegate.getMaxInactiveIntervalInSeconds();
|
||||
}
|
||||
|
||||
public boolean isExpired() {
|
||||
return this.delegate.isExpired();
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return this.delegate.getId();
|
||||
}
|
||||
@@ -516,12 +595,42 @@ public class JdbcOperationsSessionRepository implements
|
||||
|
||||
public void setAttribute(String attributeName, Object attributeValue) {
|
||||
this.delegate.setAttribute(attributeName, attributeValue);
|
||||
this.attributesChanged = true;
|
||||
this.delta.put(attributeName, attributeValue);
|
||||
if (PRINCIPAL_NAME_INDEX_NAME.equals(attributeName) ||
|
||||
SPRING_SECURITY_CONTEXT.equals(attributeName)) {
|
||||
this.changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAttribute(String attributeName) {
|
||||
this.delegate.removeAttribute(attributeName);
|
||||
this.attributesChanged = true;
|
||||
this.delta.put(attributeName, null);
|
||||
}
|
||||
|
||||
public long getCreationTime() {
|
||||
return this.delegate.getCreationTime();
|
||||
}
|
||||
|
||||
public void setLastAccessedTime(long lastAccessedTime) {
|
||||
this.delegate.setLastAccessedTime(lastAccessedTime);
|
||||
this.changed = true;
|
||||
}
|
||||
|
||||
public long getLastAccessedTime() {
|
||||
return this.delegate.getLastAccessedTime();
|
||||
}
|
||||
|
||||
public void setMaxInactiveIntervalInSeconds(int interval) {
|
||||
this.delegate.setMaxInactiveIntervalInSeconds(interval);
|
||||
this.changed = true;
|
||||
}
|
||||
|
||||
public int getMaxInactiveIntervalInSeconds() {
|
||||
return this.delegate.getMaxInactiveIntervalInSeconds();
|
||||
}
|
||||
|
||||
public boolean isExpired() {
|
||||
return this.delegate.isExpired();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -533,8 +642,6 @@ public class JdbcOperationsSessionRepository implements
|
||||
*/
|
||||
static class PrincipalNameResolver {
|
||||
|
||||
private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT";
|
||||
|
||||
private SpelExpressionParser parser = new SpelExpressionParser();
|
||||
|
||||
public String resolvePrincipal(Session session) {
|
||||
@@ -556,8 +663,19 @@ public class JdbcOperationsSessionRepository implements
|
||||
private class ExpiringSessionMapper implements RowMapper<ExpiringSession> {
|
||||
|
||||
public ExpiringSession mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
ExpiringSession session = deserialize(rs, "SESSION_BYTES");
|
||||
MapSession session = new MapSession(rs.getString("SESSION_ID"));
|
||||
session.setCreationTime(rs.getLong("CREATION_TIME"));
|
||||
session.setLastAccessedTime(rs.getLong("LAST_ACCESS_TIME"));
|
||||
session.setMaxInactiveIntervalInSeconds(rs.getInt("MAX_INACTIVE_INTERVAL"));
|
||||
String attributeName = rs.getString("ATTRIBUTE_NAME");
|
||||
if (attributeName != null) {
|
||||
session.setAttribute(attributeName, deserialize(rs, "ATTRIBUTE_BYTES"));
|
||||
while (rs.next() && session.getId().equals(rs.getString("SESSION_ID"))) {
|
||||
session.setAttribute(rs.getString("ATTRIBUTE_NAME"),
|
||||
deserialize(rs, "ATTRIBUTE_BYTES"));
|
||||
}
|
||||
rs.previous();
|
||||
}
|
||||
return session;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ import org.springframework.util.StringUtils;
|
||||
* {@link DataSource} must be exposed as a Bean.
|
||||
*
|
||||
* @author Vedran Pavic
|
||||
* @author Eddú Meléndez
|
||||
* @since 1.2.0
|
||||
* @see EnableJdbcHttpSession
|
||||
*/
|
||||
@@ -106,6 +107,14 @@ public class JdbcHttpSessionConfiguration extends SpringHttpSessionConfiguration
|
||||
this.springSessionConversionService = conversionService;
|
||||
}
|
||||
|
||||
public void setTableName(String tableName) {
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
public void setMaxInactiveIntervalInSeconds(Integer maxInactiveIntervalInSeconds) {
|
||||
this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds;
|
||||
}
|
||||
|
||||
private String getTableName() {
|
||||
if (StringUtils.hasText(this.tableName)) {
|
||||
return this.tableName;
|
||||
|
||||
@@ -42,7 +42,7 @@ import org.springframework.web.util.UrlPathHelper;
|
||||
* The configuration:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>Ensures the the {@link Session} is kept alive on incoming web socket messages.</li>
|
||||
* <li>Ensures the {@link Session} is kept alive on incoming web socket messages.</li>
|
||||
* <li>Ensures that Web Socket Sessions are destroyed when a {@link Session} is terminated
|
||||
* </li>
|
||||
* </ul>
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
CREATE TABLE SPRING_SESSION (
|
||||
SESSION_ID CHAR(36),
|
||||
CREATION_TIME BIGINT NOT NULL,
|
||||
LAST_ACCESS_TIME BIGINT NOT NULL,
|
||||
MAX_INACTIVE_INTERVAL INT NOT NULL,
|
||||
PRINCIPAL_NAME VARCHAR(100),
|
||||
SESSION_BYTES BLOB,
|
||||
CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID)
|
||||
);
|
||||
|
||||
CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME);
|
||||
|
||||
CREATE TABLE SPRING_SESSION_ATTRIBUTES (
|
||||
SESSION_ID CHAR(36),
|
||||
ATTRIBUTE_NAME VARCHAR(100),
|
||||
ATTRIBUTE_BYTES BLOB,
|
||||
CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME),
|
||||
CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID);
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
CREATE TABLE SPRING_SESSION (
|
||||
SESSION_ID CHAR(36),
|
||||
CREATION_TIME BIGINT NOT NULL,
|
||||
LAST_ACCESS_TIME BIGINT NOT NULL,
|
||||
MAX_INACTIVE_INTERVAL INT NOT NULL,
|
||||
PRINCIPAL_NAME VARCHAR(100),
|
||||
SESSION_BYTES BLOB,
|
||||
CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID)
|
||||
);
|
||||
|
||||
CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME);
|
||||
|
||||
CREATE TABLE SPRING_SESSION_ATTRIBUTES (
|
||||
SESSION_ID CHAR(36),
|
||||
ATTRIBUTE_NAME VARCHAR(100),
|
||||
ATTRIBUTE_BYTES BLOB,
|
||||
CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME),
|
||||
CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID);
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
CREATE TABLE SPRING_SESSION (
|
||||
SESSION_ID CHAR(36),
|
||||
CREATION_TIME BIGINT NOT NULL,
|
||||
LAST_ACCESS_TIME BIGINT NOT NULL,
|
||||
MAX_INACTIVE_INTERVAL INT NOT NULL,
|
||||
PRINCIPAL_NAME VARCHAR(100),
|
||||
SESSION_BYTES LONGVARBINARY,
|
||||
CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID)
|
||||
);
|
||||
|
||||
CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME);
|
||||
|
||||
CREATE TABLE SPRING_SESSION_ATTRIBUTES (
|
||||
SESSION_ID CHAR(36),
|
||||
ATTRIBUTE_NAME VARCHAR(100),
|
||||
ATTRIBUTE_BYTES LONGVARBINARY,
|
||||
CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME),
|
||||
CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID);
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
CREATE TABLE SPRING_SESSION (
|
||||
SESSION_ID CHAR(36),
|
||||
CREATION_TIME BIGINT NOT NULL,
|
||||
LAST_ACCESS_TIME BIGINT NOT NULL,
|
||||
MAX_INACTIVE_INTERVAL INT NOT NULL,
|
||||
PRINCIPAL_NAME VARCHAR(100),
|
||||
SESSION_BYTES LONGVARBINARY,
|
||||
CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID)
|
||||
);
|
||||
|
||||
CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME);
|
||||
|
||||
CREATE TABLE SPRING_SESSION_ATTRIBUTES (
|
||||
SESSION_ID CHAR(36),
|
||||
ATTRIBUTE_NAME VARCHAR(100),
|
||||
ATTRIBUTE_BYTES LONGVARBINARY,
|
||||
CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME),
|
||||
CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID);
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
CREATE TABLE SPRING_SESSION (
|
||||
SESSION_ID CHAR(36),
|
||||
CREATION_TIME BIGINT NOT NULL,
|
||||
LAST_ACCESS_TIME BIGINT NOT NULL,
|
||||
MAX_INACTIVE_INTERVAL INT NOT NULL,
|
||||
PRINCIPAL_NAME VARCHAR(100),
|
||||
SESSION_BYTES BLOB,
|
||||
CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME);
|
||||
|
||||
CREATE TABLE SPRING_SESSION_ATTRIBUTES (
|
||||
SESSION_ID CHAR(36),
|
||||
ATTRIBUTE_NAME VARCHAR(100),
|
||||
ATTRIBUTE_BYTES BLOB,
|
||||
CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME),
|
||||
CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID);
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
CREATE TABLE SPRING_SESSION (
|
||||
SESSION_ID CHAR(36),
|
||||
CREATION_TIME NUMBER(19,0) NOT NULL,
|
||||
LAST_ACCESS_TIME NUMBER(19,0) NOT NULL,
|
||||
MAX_INACTIVE_INTERVAL NUMBER(10,0) NOT NULL,
|
||||
PRINCIPAL_NAME VARCHAR2(100 CHAR),
|
||||
SESSION_BYTES BLOB,
|
||||
CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID)
|
||||
);
|
||||
|
||||
CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME);
|
||||
|
||||
CREATE TABLE SPRING_SESSION_ATTRIBUTES (
|
||||
SESSION_ID CHAR(36),
|
||||
ATTRIBUTE_NAME VARCHAR2(100 CHAR),
|
||||
ATTRIBUTE_BYTES BLOB,
|
||||
CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME),
|
||||
CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID);
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
CREATE TABLE SPRING_SESSION (
|
||||
SESSION_ID CHAR(36),
|
||||
CREATION_TIME BIGINT NOT NULL,
|
||||
LAST_ACCESS_TIME BIGINT NOT NULL,
|
||||
MAX_INACTIVE_INTERVAL INT NOT NULL,
|
||||
PRINCIPAL_NAME VARCHAR(100),
|
||||
SESSION_BYTES BYTEA,
|
||||
CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID)
|
||||
);
|
||||
|
||||
CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME);
|
||||
|
||||
CREATE TABLE SPRING_SESSION_ATTRIBUTES (
|
||||
SESSION_ID CHAR(36),
|
||||
ATTRIBUTE_NAME VARCHAR(100),
|
||||
ATTRIBUTE_BYTES BYTEA,
|
||||
CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME),
|
||||
CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID);
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
CREATE TABLE SPRING_SESSION (
|
||||
SESSION_ID CHARACTER(36),
|
||||
CREATION_TIME INTEGER NOT NULL,
|
||||
LAST_ACCESS_TIME INTEGER NOT NULL,
|
||||
MAX_INACTIVE_INTERVAL INTEGER NOT NULL,
|
||||
PRINCIPAL_NAME VARCHAR(100),
|
||||
SESSION_BYTES BLOB,
|
||||
CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID)
|
||||
);
|
||||
|
||||
CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME);
|
||||
|
||||
CREATE TABLE SPRING_SESSION_ATTRIBUTES (
|
||||
SESSION_ID CHAR(36),
|
||||
ATTRIBUTE_NAME VARCHAR(100),
|
||||
ATTRIBUTE_BYTES BLOB,
|
||||
CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME),
|
||||
CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID);
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
CREATE TABLE SPRING_SESSION (
|
||||
SESSION_ID CHAR(36),
|
||||
CREATION_TIME BIGINT NOT NULL,
|
||||
LAST_ACCESS_TIME BIGINT NOT NULL,
|
||||
MAX_INACTIVE_INTERVAL INT NOT NULL,
|
||||
PRINCIPAL_NAME VARCHAR(100),
|
||||
SESSION_BYTES IMAGE,
|
||||
CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID)
|
||||
);
|
||||
|
||||
CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME);
|
||||
|
||||
CREATE TABLE SPRING_SESSION_ATTRIBUTES (
|
||||
SESSION_ID CHAR(36),
|
||||
ATTRIBUTE_NAME VARCHAR(100),
|
||||
ATTRIBUTE_BYTES IMAGE,
|
||||
CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME),
|
||||
CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID);
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
CREATE TABLE SPRING_SESSION (
|
||||
SESSION_ID CHAR(36),
|
||||
CREATION_TIME BIGINT NOT NULL,
|
||||
LAST_ACCESS_TIME BIGINT NOT NULL,
|
||||
MAX_INACTIVE_INTERVAL INT NOT NULL,
|
||||
PRINCIPAL_NAME VARCHAR(100),
|
||||
SESSION_BYTES IMAGE,
|
||||
CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID)
|
||||
) LOCK DATAROWS;
|
||||
|
||||
CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME);
|
||||
|
||||
CREATE TABLE SPRING_SESSION_ATTRIBUTES (
|
||||
SESSION_ID CHAR(36),
|
||||
ATTRIBUTE_NAME VARCHAR(100),
|
||||
ATTRIBUTE_BYTES IMAGE,
|
||||
CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME),
|
||||
CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE
|
||||
) LOCK DATAROWS;
|
||||
|
||||
CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID);
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.data.gemfire.client.Interest;
|
||||
import org.springframework.session.ExpiringSession;
|
||||
|
||||
@@ -47,6 +48,7 @@ import static org.mockito.Mockito.mock;
|
||||
* @since 1.1.0
|
||||
* @see org.junit.Rule
|
||||
* @see org.junit.Test
|
||||
* @see org.junit.rules.ExpectedException
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.springframework.session.data.gemfire.config.annotation.web.http.support.
|
||||
* GemFireCacheTypeAwareRegionFactoryBean
|
||||
@@ -63,14 +65,16 @@ import static org.mockito.Mockito.mock;
|
||||
public class GemFireCacheTypeAwareRegionFactoryBeanTest {
|
||||
|
||||
@Rule
|
||||
public ExpectedException expectedException = ExpectedException.none();
|
||||
public ExpectedException exception = ExpectedException.none();
|
||||
|
||||
@Mock
|
||||
ClientCache mockClientCache;
|
||||
|
||||
@Mock
|
||||
Region<Object, ExpiringSession> mockClientRegion;
|
||||
|
||||
@Mock
|
||||
Region<Object, ExpiringSession> mockServerRegion;
|
||||
@Mock
|
||||
ClientCache mockClientCache;
|
||||
|
||||
private GemFireCacheTypeAwareRegionFactoryBean<Object, ExpiringSession> regionFactoryBean;
|
||||
|
||||
@@ -164,13 +168,37 @@ public class GemFireCacheTypeAwareRegionFactoryBeanTest {
|
||||
assertThat(this.regionFactoryBean.isSingleton()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAndGetBeanFactory() {
|
||||
BeanFactory mockBeanFactory = mock(BeanFactory.class);
|
||||
|
||||
this.regionFactoryBean.setBeanFactory(mockBeanFactory);
|
||||
|
||||
assertThat(this.regionFactoryBean.getBeanFactory()).isEqualTo(mockBeanFactory);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setBeanFactoryToNullThrowsIllegalArgumentException() {
|
||||
this.exception.expect(IllegalArgumentException.class);
|
||||
this.exception.expectMessage("BeanFactory must not be null");
|
||||
this.regionFactoryBean.setBeanFactory(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getBeanFactoryWhenNullThrowsIllegalStateException() {
|
||||
this.exception.expect(IllegalStateException.class);
|
||||
this.exception.expectMessage(
|
||||
"A reference to the BeanFactory was not properly configured");
|
||||
this.regionFactoryBean.getBeanFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAndGetClientRegionShortcut() {
|
||||
assertThat(this.regionFactoryBean.getClientRegionShortcut()).isEqualTo(
|
||||
GemFireCacheTypeAwareRegionFactoryBean.DEFAULT_CLIENT_REGION_SHORTCUT);
|
||||
|
||||
this.regionFactoryBean
|
||||
.setClientRegionShortcut(ClientRegionShortcut.LOCAL_PERSISTENT);
|
||||
this.regionFactoryBean.setClientRegionShortcut(
|
||||
ClientRegionShortcut.LOCAL_PERSISTENT);
|
||||
|
||||
assertThat(this.regionFactoryBean.getClientRegionShortcut())
|
||||
.isEqualTo(ClientRegionShortcut.LOCAL_PERSISTENT);
|
||||
@@ -192,17 +220,16 @@ public class GemFireCacheTypeAwareRegionFactoryBeanTest {
|
||||
|
||||
@Test
|
||||
public void setGemfireCacheToNullThrowsIllegalArgumentException() {
|
||||
this.expectedException.expect(IllegalArgumentException.class);
|
||||
this.expectedException
|
||||
.expectMessage("The GemFireCache reference must not be null");
|
||||
this.exception.expect(IllegalArgumentException.class);
|
||||
this.exception.expectMessage("GemFireCache must not be null");
|
||||
this.regionFactoryBean.setGemfireCache(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getGemfireCacheWhenNullThrowsIllegalStateException() {
|
||||
this.expectedException.expect(IllegalStateException.class);
|
||||
this.expectedException.expectMessage(
|
||||
"A reference to a GemFireCache was not properly configured");
|
||||
this.exception.expect(IllegalStateException.class);
|
||||
this.exception.expectMessage(
|
||||
"A reference to the GemFireCache was not properly configured");
|
||||
this.regionFactoryBean.getGemfireCache();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* 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.config.annotation.web.http;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.mongodb.core.IndexOperations;
|
||||
import org.springframework.data.mongodb.core.MongoOperations;
|
||||
import org.springframework.session.data.mongo.MongoOperationsSessionRepository;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
public class MongoHttpSessionConfigurationTest {
|
||||
|
||||
private AnnotationConfigApplicationContext context;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultCollectionName() {
|
||||
registerAndRefresh(DefaultConfiguration.class);
|
||||
MongoHttpSessionConfiguration session = this.context
|
||||
.getBean(MongoHttpSessionConfiguration.class);
|
||||
assertThat(session).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(session, "collectionName")).isEqualTo(
|
||||
"sessions");
|
||||
MongoOperationsSessionRepository repository = this.context.getBean(MongoOperationsSessionRepository.class);
|
||||
assertThat(ReflectionTestUtils.getField(repository, "collectionName")).isEqualTo(
|
||||
"sessions");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customCollectionName() {
|
||||
registerAndRefresh(CustomCollectionNameConfiguration.class);
|
||||
MongoHttpSessionConfiguration session = this.context
|
||||
.getBean(MongoHttpSessionConfiguration.class);
|
||||
assertThat(session).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(session, "collectionName")).isEqualTo(
|
||||
"testSessions");
|
||||
|
||||
MongoOperationsSessionRepository repository = this.context.getBean(MongoOperationsSessionRepository.class);
|
||||
assertThat(ReflectionTestUtils.getField(repository, "collectionName")).isEqualTo(
|
||||
"testSessions");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setCustomCollectionName() {
|
||||
registerAndRefresh(CustomConfiguration.class, CustomCollectionNameSetConfiguration.class);
|
||||
MongoHttpSessionConfiguration session = this.context
|
||||
.getBean(MongoHttpSessionConfiguration.class);
|
||||
assertThat(session).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(session, "collectionName")).isEqualTo(
|
||||
"customSession");
|
||||
MongoOperationsSessionRepository repository = this.context.getBean(MongoOperationsSessionRepository.class);
|
||||
assertThat(ReflectionTestUtils.getField(repository, "collectionName")).isEqualTo(
|
||||
"customSession");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customMaxInactiveIntervalInSeconds() {
|
||||
registerAndRefresh(CustomConfiguration.class, CustomMaxInactiveIntervalInSecondsSetConfiguration.class);
|
||||
MongoHttpSessionConfiguration session = this.context
|
||||
.getBean(MongoHttpSessionConfiguration.class);
|
||||
assertThat(session).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(session, "maxInactiveIntervalInSeconds")).isEqualTo(
|
||||
10);
|
||||
MongoOperationsSessionRepository repository = this.context.getBean(MongoOperationsSessionRepository.class);
|
||||
assertThat(ReflectionTestUtils.getField(repository, "maxInactiveIntervalInSeconds")).isEqualTo(
|
||||
10);
|
||||
}
|
||||
|
||||
private void registerAndRefresh(Class<?>... annotatedClasses) {
|
||||
this.context.register(annotatedClasses);
|
||||
this.context.refresh();
|
||||
}
|
||||
|
||||
static class BaseConfiguration {
|
||||
|
||||
@Bean
|
||||
public MongoOperations mongoOperations() throws UnknownHostException {
|
||||
MongoOperations mongoOperations = mock(MongoOperations.class);
|
||||
IndexOperations indexOperations = mock(IndexOperations.class);
|
||||
given(mongoOperations.indexOps(anyString())).willReturn(indexOperations);
|
||||
return mongoOperations;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableMongoHttpSession(collectionName = "testSessions")
|
||||
static class CustomCollectionNameConfiguration extends BaseConfiguration {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableMongoHttpSession
|
||||
static class DefaultConfiguration extends BaseConfiguration {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CustomCollectionNameSetConfiguration extends MongoHttpSessionConfiguration {
|
||||
|
||||
CustomCollectionNameSetConfiguration() {
|
||||
setCollectionName("customSession");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CustomMaxInactiveIntervalInSecondsSetConfiguration extends MongoHttpSessionConfiguration {
|
||||
|
||||
CustomMaxInactiveIntervalInSecondsSetConfiguration() {
|
||||
setMaxInactiveIntervalInSeconds(10);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CustomConfiguration extends BaseConfiguration {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -166,6 +166,16 @@ public class RedisOperationsSessionRepositoryTests {
|
||||
.isEqualTo(session.getCreationTime());
|
||||
}
|
||||
|
||||
// gh-467
|
||||
@Test
|
||||
public void saveSessionNothingChanged() {
|
||||
RedisSession session = this.redisRepository.new RedisSession(this.cached);
|
||||
|
||||
this.redisRepository.save(session);
|
||||
|
||||
verifyZeroInteractions(this.redisOperations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveJavadocSummary() {
|
||||
RedisSession session = this.redisRepository.createSession();
|
||||
@@ -202,6 +212,7 @@ public class RedisOperationsSessionRepositoryTests {
|
||||
@Test
|
||||
public void saveJavadoc() {
|
||||
RedisSession session = this.redisRepository.new RedisSession(this.cached);
|
||||
session.setLastAccessedTime(session.getLastAccessedTime());
|
||||
|
||||
given(this.redisOperations.boundHashOps("spring:session:sessions:session-id"))
|
||||
.willReturn(this.boundHashOperations);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.session.jdbc;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -31,6 +32,7 @@ import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import org.springframework.jdbc.core.JdbcOperations;
|
||||
import org.springframework.jdbc.core.PreparedStatementCreator;
|
||||
import org.springframework.jdbc.core.PreparedStatementSetter;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
@@ -44,7 +46,6 @@ import org.springframework.transaction.TransactionDefinition;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.AdditionalMatchers.and;
|
||||
import static org.mockito.AdditionalMatchers.not;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Matchers.anyLong;
|
||||
import static org.mockito.Matchers.contains;
|
||||
@@ -200,7 +201,7 @@ public class JdbcOperationsSessionRepositoryTests {
|
||||
assertThat(session.isNew()).isFalse();
|
||||
assertPropagationRequiresNew();
|
||||
verify(this.jdbcOperations, times(1)).update(
|
||||
and(startsWith("UPDATE"), contains("SESSION_BYTES")),
|
||||
and(startsWith("UPDATE"), contains("ATTRIBUTE_BYTES")),
|
||||
isA(PreparedStatementSetter.class));
|
||||
}
|
||||
|
||||
@@ -215,7 +216,7 @@ public class JdbcOperationsSessionRepositoryTests {
|
||||
assertThat(session.isNew()).isFalse();
|
||||
assertPropagationRequiresNew();
|
||||
verify(this.jdbcOperations, times(1)).update(
|
||||
and(startsWith("UPDATE"), not(contains("SESSION_BYTES"))),
|
||||
and(startsWith("UPDATE"), contains("LAST_ACCESS_TIME")),
|
||||
isA(PreparedStatementSetter.class));
|
||||
}
|
||||
|
||||
@@ -239,8 +240,8 @@ public class JdbcOperationsSessionRepositoryTests {
|
||||
|
||||
assertThat(session).isNull();
|
||||
assertPropagationRequiresNew();
|
||||
verify(this.jdbcOperations, times(1)).queryForObject(startsWith("SELECT"),
|
||||
eq(new Object[] { sessionId }), isA(RowMapper.class));
|
||||
verify(this.jdbcOperations, times(1)).query(
|
||||
isA(PreparedStatementCreator.class), isA(RowMapper.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -248,17 +249,16 @@ public class JdbcOperationsSessionRepositoryTests {
|
||||
MapSession expired = new MapSession();
|
||||
expired.setLastAccessedTime(System.currentTimeMillis() -
|
||||
(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS * 1000 + 1000));
|
||||
given(this.jdbcOperations.queryForObject(startsWith("SELECT"),
|
||||
eq(new Object[] { expired.getId() }), isA(RowMapper.class)))
|
||||
.willReturn(expired);
|
||||
given(this.jdbcOperations.query(isA(PreparedStatementCreator.class),
|
||||
isA(RowMapper.class))).willReturn(Collections.singletonList(expired));
|
||||
|
||||
JdbcOperationsSessionRepository.JdbcSession session = this.repository
|
||||
.getSession(expired.getId());
|
||||
|
||||
assertThat(session).isNull();
|
||||
assertPropagationRequiresNew();
|
||||
verify(this.jdbcOperations, times(1)).queryForObject(startsWith("SELECT"),
|
||||
eq(new Object[] { expired.getId() }), isA(RowMapper.class));
|
||||
verify(this.jdbcOperations, times(1)).query(
|
||||
isA(PreparedStatementCreator.class), isA(RowMapper.class));
|
||||
verify(this.jdbcOperations, times(1)).update(startsWith("DELETE"),
|
||||
eq(expired.getId()));
|
||||
}
|
||||
@@ -267,9 +267,8 @@ public class JdbcOperationsSessionRepositoryTests {
|
||||
public void getSessionFound() {
|
||||
MapSession saved = new MapSession();
|
||||
saved.setAttribute("savedName", "savedValue");
|
||||
given(this.jdbcOperations.queryForObject(startsWith("SELECT"),
|
||||
eq(new Object[] { saved.getId() }), isA(RowMapper.class)))
|
||||
.willReturn(saved);
|
||||
given(this.jdbcOperations.query(isA(PreparedStatementCreator.class),
|
||||
isA(RowMapper.class))).willReturn(Collections.singletonList(saved));
|
||||
|
||||
JdbcOperationsSessionRepository.JdbcSession session = this.repository
|
||||
.getSession(saved.getId());
|
||||
@@ -278,8 +277,8 @@ public class JdbcOperationsSessionRepositoryTests {
|
||||
assertThat(session.isNew()).isFalse();
|
||||
assertThat(session.getAttribute("savedName")).isEqualTo("savedValue");
|
||||
assertPropagationRequiresNew();
|
||||
verify(this.jdbcOperations, times(1)).queryForObject(startsWith("SELECT"),
|
||||
eq(new Object[] { saved.getId() }), isA(RowMapper.class));
|
||||
verify(this.jdbcOperations, times(1)).query(
|
||||
isA(PreparedStatementCreator.class), isA(RowMapper.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -314,8 +313,8 @@ public class JdbcOperationsSessionRepositoryTests {
|
||||
|
||||
assertThat(sessions).isEmpty();
|
||||
assertPropagationRequiresNew();
|
||||
verify(this.jdbcOperations, times(1)).query(startsWith("SELECT"),
|
||||
eq(new Object[] { principal }), isA(RowMapper.class));
|
||||
verify(this.jdbcOperations, times(1)).query(
|
||||
isA(PreparedStatementCreator.class), isA(RowMapper.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -330,8 +329,8 @@ public class JdbcOperationsSessionRepositoryTests {
|
||||
MapSession saved2 = new MapSession();
|
||||
saved2.setAttribute(SPRING_SECURITY_CONTEXT, authentication);
|
||||
saved.add(saved2);
|
||||
given(this.jdbcOperations.query(startsWith("SELECT"),
|
||||
eq(new Object[] { principal }), isA(RowMapper.class))).willReturn(saved);
|
||||
given(this.jdbcOperations.query(isA(PreparedStatementCreator.class),
|
||||
isA(RowMapper.class))).willReturn(saved);
|
||||
|
||||
Map<String, JdbcOperationsSessionRepository.JdbcSession> sessions = this.repository
|
||||
.findByIndexNameAndIndexValue(
|
||||
@@ -340,8 +339,8 @@ public class JdbcOperationsSessionRepositoryTests {
|
||||
|
||||
assertThat(sessions).hasSize(2);
|
||||
assertPropagationRequiresNew();
|
||||
verify(this.jdbcOperations, times(1)).query(startsWith("SELECT"),
|
||||
eq(new Object[] { principal }), isA(RowMapper.class));
|
||||
verify(this.jdbcOperations, times(1)).query(
|
||||
isA(PreparedStatementCreator.class), isA(RowMapper.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -40,6 +40,7 @@ import static org.mockito.Mockito.mock;
|
||||
* Tests for {@link JdbcHttpSessionConfiguration}.
|
||||
*
|
||||
* @author Vedran Pavic
|
||||
* @author Eddú Meléndez
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class JdbcHttpSessionConfigurationTests {
|
||||
@@ -107,6 +108,30 @@ public class JdbcHttpSessionConfigurationTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setCustomTableName() {
|
||||
registerAndRefresh(BaseConfiguration.class,
|
||||
CustomTableNameSetConfiguration.class);
|
||||
|
||||
JdbcHttpSessionConfiguration repository = this.context
|
||||
.getBean(JdbcHttpSessionConfiguration.class);
|
||||
assertThat(repository).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(repository, "tableName")).isEqualTo(
|
||||
"custom_session");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setCustomMaxInactiveIntervalInSeconds() {
|
||||
registerAndRefresh(BaseConfiguration.class,
|
||||
CustomMaxInactiveIntervalInSecondsSetConfiguration.class);
|
||||
|
||||
JdbcHttpSessionConfiguration repository = this.context
|
||||
.getBean(JdbcHttpSessionConfiguration.class);
|
||||
assertThat(repository).isNotNull();
|
||||
assertThat(ReflectionTestUtils.getField(repository, "maxInactiveIntervalInSeconds")).isEqualTo(
|
||||
10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customMaxInactiveIntervalInSeconds() {
|
||||
registerAndRefresh(CustomMaxInactiveIntervalInSecondsConfiguration.class);
|
||||
@@ -180,6 +205,24 @@ public class JdbcHttpSessionConfigurationTests {
|
||||
static class CustomTableNameConfiguration extends BaseConfiguration {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CustomTableNameSetConfiguration extends JdbcHttpSessionConfiguration {
|
||||
|
||||
CustomTableNameSetConfiguration() {
|
||||
setTableName("custom_session");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CustomMaxInactiveIntervalInSecondsSetConfiguration extends JdbcHttpSessionConfiguration {
|
||||
|
||||
CustomMaxInactiveIntervalInSecondsSetConfiguration() {
|
||||
setMaxInactiveIntervalInSeconds(10);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableJdbcHttpSession(maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS)
|
||||
static class CustomMaxInactiveIntervalInSecondsConfiguration
|
||||
|
||||
Reference in New Issue
Block a user