Compare commits
48 Commits
1.3.1.RELE
...
1.3.5.RELE
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
774e6df063 | ||
|
|
6911bd359b | ||
|
|
ddae03c79e | ||
|
|
bba095f276 | ||
|
|
61937a9251 | ||
|
|
3885b7e7ff | ||
|
|
bea569c3c8 | ||
|
|
7f1434cc4c | ||
|
|
cd8f87e0a9 | ||
|
|
95f41a7024 | ||
|
|
d245cc1a36 | ||
|
|
695f2f1509 | ||
|
|
3940a22d5e | ||
|
|
eb4ce12915 | ||
|
|
46bac131d0 | ||
|
|
9675278729 | ||
|
|
f0c216d9d5 | ||
|
|
cb6f7fdfa6 | ||
|
|
b50a4e247e | ||
|
|
6b3d78ac09 | ||
|
|
c0bd38c46f | ||
|
|
2262600b21 | ||
|
|
0c11a4297a | ||
|
|
b778d97dc7 | ||
|
|
d0887fe40d | ||
|
|
1a94d742b1 | ||
|
|
c433b01ee5 | ||
|
|
a3195f1f4b | ||
|
|
467ecaaeff | ||
|
|
4a18242d95 | ||
|
|
e44cd45668 | ||
|
|
7f0de8126e | ||
|
|
d75b03f594 | ||
|
|
ca0fea3a54 | ||
|
|
92af786e6b | ||
|
|
d271a4ad1d | ||
|
|
04c1908378 | ||
|
|
f0e187fbd7 | ||
|
|
2d3001a24e | ||
|
|
f2d1badd60 | ||
|
|
6a6d60d8f8 | ||
|
|
b2cb3f6a3a | ||
|
|
d7ae5785eb | ||
|
|
96eb40439c | ||
|
|
8ed0999ad3 | ||
|
|
b2d2335d73 | ||
|
|
f597c5a824 | ||
|
|
212eca306c |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -10,5 +10,5 @@ target
|
||||
out
|
||||
.springBeans
|
||||
*.rdb
|
||||
!eclispe/.checkstyle
|
||||
.checkstyle
|
||||
.checkstyle
|
||||
!etc/eclipse/.checkstyle
|
||||
|
||||
16
build.gradle
16
build.gradle
@@ -19,7 +19,7 @@ plugins {
|
||||
|
||||
group = 'org.springframework.session'
|
||||
|
||||
ext.springBootVersion = '1.4.2.RELEASE'
|
||||
ext.springBootVersion = '1.4.7.RELEASE'
|
||||
ext.IDE_GRADLE = "$rootDir/gradle/ide.gradle"
|
||||
ext.JAVA_GRADLE = "$rootDir/gradle/java.gradle"
|
||||
ext.SPRING3_GRADLE = "$rootDir/gradle/spring3.gradle"
|
||||
@@ -51,12 +51,14 @@ sonarqube {
|
||||
}
|
||||
}
|
||||
|
||||
task configDocsZip(dependsOn: [':docs:asciidoctor',':spring-session:javadoc']) << {
|
||||
project.tasks.docsZip.from(project(':docs').asciidoctor) {
|
||||
into('reference')
|
||||
}
|
||||
project.tasks.docsZip.from(project(':spring-session').javadoc) {
|
||||
into('api')
|
||||
task configDocsZip(dependsOn: [':docs:asciidoctor',':spring-session:javadoc']) {
|
||||
doLast {
|
||||
project.tasks.docsZip.from(project(':docs').asciidoctor) {
|
||||
into('reference')
|
||||
}
|
||||
project.tasks.docsZip.from(project(':spring-session').javadoc) {
|
||||
into('api')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ If you are using Maven, ensure to add the following dependencies:
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-redis</artifactId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
----
|
||||
|
||||
@@ -127,3 +127,6 @@ Alternatively, you can also delete the explicit key. Enter the following into yo
|
||||
$ redis-cli del spring:session:sessions:7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
|
||||
|
||||
Now visit the application at http://localhost:8080/test/index and observe that we are no longer authenticated.
|
||||
|
||||
NOTE: Spring Session will not work with grails flash scope without additional work. +
|
||||
See this answer for an explanation: https://stackoverflow.com/a/43311427
|
||||
|
||||
@@ -95,7 +95,7 @@ and managed by GemFire. As well, we have specified an arbitrary expiration attr
|
||||
for when the Session will timeout, which is triggered by a GemFire Region entry expiration event that also invalidates
|
||||
the Session object in the Region.
|
||||
<2> Next, we define a few `Properties` that allow us to configure certain aspects of the GemFire Server using
|
||||
http://gemfire.docs.pivotal.io/docs-gemfire/reference/topics/gemfire_properties.html[GemFire's System properties].
|
||||
http://gemfire.docs.pivotal.io/docs-gemfire/latest/reference/topics/gemfire_properties.html[GemFire's System properties].
|
||||
<3> Then, we create an instance of the GemFire `Cache` using our defined `Properties`.
|
||||
<4> Finally, we configure and start a `CacheServer` running in the GemFire Server to listen for connections
|
||||
from cache clients. The `CacheServer's` `Socket` will be used to connect our GemFire cache client,
|
||||
@@ -159,7 +159,7 @@ and GemFire out-of-the-box using the following attributes:
|
||||
* `maxInactiveIntervalInSeconds` - controls _HttpSession_ idle-timeout expiration (defaults to **30 minutes**).
|
||||
* `regionName` - specifies the name of the GemFire Region used to store `HttpSession` state (defaults is "*ClusteredSpringSessions*").
|
||||
* `clientRegionShort` - specifies GemFire's http://gemfire.docs.pivotal.io/docs-gemfire/latest/developing/management_all_region_types/chapter_overview.html[data management policy]
|
||||
with a GemFire http://gemfire.docs.pivotal.io/docs-gemfire/latest/javadocs/japi/com/gemstone/gemfire/cache/client/ClientRegionShortcut.html[ClientRegionShortcut]
|
||||
with a GemFire http://data-docs-samples.cfapps.io/docs-gemfire/latest/javadocs/japi/com/gemstone/gemfire/cache/client/ClientRegionShortcut.html[ClientRegionShortcut]
|
||||
(default is `PROXY`). This attribute is only used when configuring client Region.
|
||||
* `poolName` - name of the dedicated GemFire Pool used to connect a client to the cluster of servers. The attribute
|
||||
is only used when the application is a GemFire cache client. Defaults to `gemfirePool`.
|
||||
@@ -230,7 +230,7 @@ Go ahead and view the cookies (click for help with https://developer.chrome.com/
|
||||
or https://getfirebug.com/wiki/index.php/Cookies_Panel#Cookies_List[Firefox]).
|
||||
|
||||
NOTE: The following instructions assume you have a local GemFire installation. For more information on installation,
|
||||
see http://gemfire.docs.pivotal.io/docs-gemfire/latest/getting_started/installation/install_intro.html[Installing Pivotal GemFire].
|
||||
see http://gemfire.docs.pivotal.io/docs-gemfire/getting_started/installation/install_intro.html[Installing Pivotal GemFire].
|
||||
|
||||
NOTE: In order to run the following, you must uncomment the lines in the `GemFireServer` class, `gemfireProperties` bean
|
||||
for the following GemFire System properties: `jmx-manager` and `jmx-manager-start`.
|
||||
|
||||
@@ -92,7 +92,7 @@ bean to replace placeholders in the Spring XML configuration meta-data with the
|
||||
at the designated host/port is running and listening for client connections, blocking client startup until
|
||||
the server is available and ready.
|
||||
<4> Next, we include a `Properties` bean to configure certain aspects of the GemFire client cache using
|
||||
http://gemfire.docs.pivotal.io/docs-gemfire/reference/topics/gemfire_properties.html[GemFire's System Properties].
|
||||
http://gemfire.docs.pivotal.io/docs-gemfire/latest/reference/topics/gemfire_properties.html[GemFire's System Properties].
|
||||
In this case, we are just setting GemFire's `log-level` from a application-specific System property, defaulting
|
||||
to `warning` if unspecified.
|
||||
<5> Then we create a instance of a GemFire `ClientCache` initialized with our `gemfireProperties`.
|
||||
@@ -234,7 +234,7 @@ Go ahead and view the cookies (click for help with https://developer.chrome.com/
|
||||
or https://getfirebug.com/wiki/index.php/Cookies_Panel#Cookies_List[Firefox]).
|
||||
|
||||
NOTE: The following instructions assume you have a local GemFire installation. For more information on installation,
|
||||
see http://gemfire.docs.pivotal.io/docs-gemfire/latest/getting_started/installation/install_intro.html[Installing Pivotal GemFire].
|
||||
see https://gemfire.docs.pivotal.io/gemfire/getting_started/installation/install_intro.html[Installing Pivotal GemFire].
|
||||
|
||||
If you like, you can easily remove the session using `gfsh`. For example, on a Linux-based system type the following
|
||||
at the command-line:
|
||||
|
||||
@@ -87,12 +87,12 @@ include::{samples-dir}httpsession-gemfire-clientserver/src/main/java/sample/Clie
|
||||
implements `Filter`. The filter is what replaces the `HttpSession` with an implementation backed by Spring Session
|
||||
and GemFire.
|
||||
<2> Next, we register a `Properties` bean that allows us to configure certain aspects of the GemFire client cache
|
||||
using http://gemfire.docs.pivotal.io/docs-gemfire/reference/topics/gemfire_properties.html[GemFire's System properties].
|
||||
using http://gemfire.docs.pivotal.io/docs-gemfire/latest/reference/topics/gemfire_properties.html[GemFire's System properties].
|
||||
<3> We use the `Properties` to configure an instance of a GemFire `ClientCache`.
|
||||
<4> Then, we configure a `Pool` of client connections to talk to the GemFire Server in our Client/Server topology. In our
|
||||
configuration, we have used sensible settings for timeouts, number of connections and so on. Also, the `Pool` has been
|
||||
configured to connect directly to a server. Learn more about various `Pool` configuration settings from the
|
||||
http://gemfire.docs.pivotal.io/docs-gemfire/latest/javadocs/japi/com/gemstone/gemfire/cache/client/PoolFactory.html[PoolFactory API].
|
||||
http://data-docs-samples.cfapps.io/docs-gemfire/latest/javadocs/japi/com/gemstone/gemfire/cache/client/PoolFactory.html[PoolFactory API].
|
||||
<56> Finally, we include a Spring `BeanPostProcessor` to block the client until our GemFire Server is up and running,
|
||||
listening for and accepting client connections.
|
||||
|
||||
@@ -100,7 +100,7 @@ The `gemfireCacheServerReadyBeanPostProcessor` is necessary in order to coordina
|
||||
an automated fashion during testing, but unnecessary in situations where the GemFire cluster is already presently
|
||||
running, such as in production.
|
||||
|
||||
The `BeanPostProcessor` uses a GemFire http://gemfire.docs.pivotal.io/docs-gemfire/latest/javadocs/japi/com/gemstone/gemfire/management/membership/ClientMembershipListener.html[ClientMembershipListener]
|
||||
The `BeanPostProcessor` uses a GemFire https://data-docs-samples.cfapps.io/docs-gemfire/latest/javadocs/japi/com/gemstone/gemfire/management/membership/ClientMembershipListener.html[ClientMembershipListener]
|
||||
that will be notified when the client has successfully connected to the server. Once a connection has been established,
|
||||
the listener releases the latch that the `BeanPostProcessor` will wait on (up to the specified timeout) in the
|
||||
`postProcessAfterInitialization` callback to block the client.
|
||||
@@ -118,7 +118,7 @@ and GemFire out-of-the-box using the following attributes:
|
||||
* `maxInactiveIntervalInSeconds` - controls _HttpSession_ idle-timeout expiration (defaults to **30 minutes**).
|
||||
* `regionName` - specifies the name of the GemFire Region used to store `HttpSession` state (defaults is "*ClusteredSpringSessions*").
|
||||
* `clientRegionShort` - specifies GemFire's http://gemfire.docs.pivotal.io/docs-gemfire/latest/developing/management_all_region_types/chapter_overview.html[data management policy]
|
||||
with a GemFire http://gemfire.docs.pivotal.io/docs-gemfire/latest/javadocs/japi/com/gemstone/gemfire/cache/client/ClientRegionShortcut.html[ClientRegionShortcut]
|
||||
with a GemFire https://data-docs-samples.cfapps.io/docs-gemfire/latest/javadocs/japi/com/gemstone/gemfire/cache/client/ClientRegionShortcut.html[ClientRegionShortcut]
|
||||
(default is `PROXY`). This attribute is only used when configuring client Region.
|
||||
* `poolName` - name of the dedicated GemFire Pool used to connect a client to the cluster of servers. The attribute
|
||||
is only used when the application is a GemFire cache client. Defaults to `gemfirePool`.
|
||||
@@ -233,7 +233,7 @@ Go ahead and view the cookies (click for help with https://developer.chrome.com/
|
||||
or https://getfirebug.com/wiki/index.php/Cookies_Panel#Cookies_List[Firefox]).
|
||||
|
||||
NOTE: The following instructions assume you have a local GemFire installation. For more information on installation,
|
||||
see http://gemfire.docs.pivotal.io/docs-gemfire/latest/getting_started/installation/install_intro.html[Installing Pivotal GemFire].
|
||||
see https://gemfire.docs.pivotal.io/gemfire/getting_started/installation/install_intro.html[Installing Pivotal GemFire].
|
||||
|
||||
If you like, you can easily remove the session using `gfsh`. For example, on a Linux-based system type the following
|
||||
at the command-line:
|
||||
|
||||
@@ -176,7 +176,7 @@ Go ahead and view the cookies (click for help with https://developer.chrome.com/
|
||||
or https://getfirebug.com/wiki/index.php/Cookies_Panel#Cookies_List[Firefox]).
|
||||
|
||||
NOTE: The following instructions assume you have a local GemFire installation. For more information on installation,
|
||||
see http://gemfire.docs.pivotal.io/docs-gemfire/latest/getting_started/installation/install_intro.html[Installing Pivotal GemFire].
|
||||
see http://gemfire.docs.pivotal.io/gemfire/getting_started/installation/install_intro.html[Installing Pivotal GemFire].
|
||||
|
||||
If you like, you can easily remove the session using `gfsh`. For example, on a Linux-based system type the following
|
||||
at the command-line:
|
||||
|
||||
@@ -104,7 +104,7 @@ and GemFire out-of-the-box using the following attributes:
|
||||
* `maxInactiveIntervalInSeconds` - controls HttpSession idle-timeout expiration (defaults to **30 minutes**).
|
||||
* `regionName` - specifies the name of the GemFire Region used to store `HttpSession` state (defaults is "_ClusteredSpringSessions_").
|
||||
* `serverRegionShort` - specifies GemFire http://gemfire.docs.pivotal.io/docs-gemfire/latest/developing/management_all_region_types/chapter_overview.html[data management policies]
|
||||
with a GemFire http://gemfire.docs.pivotal.io/docs-gemfire/latest/javadocs/japi/com/gemstone/gemfire/cache/RegionShortcut.html[RegionShortcut]
|
||||
with a GemFire https://data-docs-samples.cfapps.io/docs-gemfire/latest/javadocs/japi/com/gemstone/gemfire/cache/RegionShortcut.html[RegionShortcut]
|
||||
(default is `PARTITION`).
|
||||
|
||||
NOTE: `clientRegionShort` is ignored in a peer cache configuration and only applies when a client-server topology,
|
||||
@@ -175,7 +175,7 @@ Go ahead and view the cookies (click for help with https://developer.chrome.com/
|
||||
or https://getfirebug.com/wiki/index.php/Cookies_Panel#Cookies_List[Firefox]).
|
||||
|
||||
NOTE: The following instructions assume you have a local GemFire installation. For more information on installation,
|
||||
see http://gemfire.docs.pivotal.io/docs-gemfire/latest/getting_started/installation/install_intro.html[Installing Pivotal GemFire].
|
||||
see https://gemfire.docs.pivotal.io/gemfire/getting_started/installation/install_intro.html[Installing Pivotal GemFire].
|
||||
|
||||
If you like, you can easily remove the session using `gfsh`. For example, on a Linux-based system type the following
|
||||
at the command-line:
|
||||
|
||||
@@ -192,7 +192,7 @@ The two most common topologies to manage Spring Sessions using GemFire include:
|
||||
* <<httpsession-gemfire-clientserver,Client-Server>>
|
||||
* <<httpsession-gemfire-p2p,Peer-To-Peer (P2P)>>
|
||||
|
||||
Additionally, GemFire supports site-to-site replication using http://gemfire.docs.pivotal.io/docs-gemfire/topologies_and_comm/multi_site_configuration/chapter_overview.html[WAN functionality].
|
||||
Additionally, GemFire supports site-to-site replication using http://gemfire.docs.pivotal.io/docs-gemfire/latest/topologies_and_comm/multi_site_configuration/chapter_overview.html[WAN functionality].
|
||||
The ability to configure and use GemFire's WAN support is independent of Spring Session, and is beyond the scope
|
||||
of this document. More details on GemFire WAN functionality can be found http://docs.spring.io/spring-data-gemfire/docs/current/reference/html/#bootstrap:gateway[here].
|
||||
|
||||
@@ -829,12 +829,12 @@ EXPIRE spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe 1800
|
||||
|
||||
When a session expires key is deleted or expires, the keyspace notification triggers a lookup of the actual session and a SessionDestroyedEvent is fired.
|
||||
|
||||
One problem with relying on Redis expiration exclusively is that Redis makes no guarantee of when the expired event will be fired if they key has not been accessed.
|
||||
One problem with relying on Redis expiration exclusively is that Redis makes no guarantee of when the expired event will be fired if the key has not been accessed.
|
||||
Specifically the background task that Redis uses to clean up expired keys is a low priority task and may not trigger the key expiration.
|
||||
For additional details see http://redis.io/topics/notifications[Timing of expired events] section in the Redis documentation.
|
||||
|
||||
To circumvent the fact that expired events are not guaranteed to happen we can ensure that each key is accessed when it is expected to expire.
|
||||
This means that if the TTL is expired on the key, Redis will remove the key and fire the expired event when we try to access they key.
|
||||
This means that if the TTL is expired on the key, Redis will remove the key and fire the expired event when we try to access the key.
|
||||
|
||||
For this reason, each session expiration is also tracked to the nearest minute.
|
||||
This allows a background task to access the potentially expired sessions to ensure that Redis expired events are fired in a more deterministic fashion.
|
||||
@@ -846,7 +846,7 @@ EXPIRE spring:session:expirations1439245080000 2100
|
||||
----
|
||||
|
||||
The background task will then use these mappings to explicitly request each key.
|
||||
By accessing they key, rather than deleting it, we ensure that Redis deletes the key for us only if the TTL is expired.
|
||||
By accessing the key, rather than deleting it, we ensure that Redis deletes the key for us only if the TTL is expired.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
@@ -1199,8 +1199,17 @@ Spring Session is Open Source software released under the http://www.apache.org/
|
||||
|
||||
[[community-extensions]]
|
||||
=== Community Extensions
|
||||
https://github.com/maseev/spring-session-orientdb[Spring Session OrientDB]
|
||||
http://infinispan.org/docs/dev/user_guide/user_guide.html#externalizing_session_using_spring_session[Spring Session Infinispan]
|
||||
|
||||
|===
|
||||
| Name | Location
|
||||
|
||||
| Spring Session OrientDB
|
||||
| https://github.com/maseev/spring-session-orientdb
|
||||
|
||||
| Spring Session Infinispan
|
||||
| http://infinispan.org/docs/dev/user_guide/user_guide.html#externalizing_session_using_spring_session
|
||||
|
||||
|===
|
||||
|
||||
[[minimum-requirements]]
|
||||
== Minimum Requirements
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,7 +22,6 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.security.web.authentication.RememberMeServices;
|
||||
import org.springframework.session.MapSessionRepository;
|
||||
import org.springframework.session.config.annotation.web.http.EnableSpringHttpSession;
|
||||
import org.springframework.session.security.web.authentication.SpringSessionRememberMeServices;
|
||||
@@ -52,7 +51,7 @@ public class RememberMeSecurityConfiguration extends WebSecurityConfigurerAdapte
|
||||
|
||||
// tag::rememberme-bean[]
|
||||
@Bean
|
||||
RememberMeServices rememberMeServices() {
|
||||
public SpringSessionRememberMeServices rememberMeServices() {
|
||||
SpringSessionRememberMeServices rememberMeServices =
|
||||
new SpringSessionRememberMeServices();
|
||||
// optionally customize
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2019 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.
|
||||
@@ -21,7 +21,6 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.session.ExpiringSession;
|
||||
import org.springframework.session.FindByIndexNameSessionRepository;
|
||||
import org.springframework.session.security.SpringSessionBackedSessionRegistry;
|
||||
|
||||
@@ -33,7 +32,7 @@ import org.springframework.session.security.SpringSessionBackedSessionRegistry;
|
||||
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Autowired
|
||||
FindByIndexNameSessionRepository<ExpiringSession> sessionRepository;
|
||||
private FindByIndexNameSessionRepository sessionRepository;
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
@@ -45,7 +44,8 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
}
|
||||
|
||||
@Bean
|
||||
SpringSessionBackedSessionRegistry sessionRegistry() {
|
||||
@SuppressWarnings("unchecked")
|
||||
public SpringSessionBackedSessionRegistry sessionRegistry() {
|
||||
return new SpringSessionBackedSessionRegistry(this.sessionRepository);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ cleanup_profile=_Spring Boot Cleanup Conventions
|
||||
cleanup_settings_version=2
|
||||
eclipse.preferences.version=1
|
||||
editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
|
||||
formatter_profile=_Spring Boot Java Conventions
|
||||
formatter_profile=Spring Session Java Conventions
|
||||
formatter_settings_version=12
|
||||
org.eclipse.jdt.ui.exception.name=e
|
||||
org.eclipse.jdt.ui.gettersetter.use.is=true
|
||||
@@ -1,32 +1,31 @@
|
||||
assertjVersion=2.5.0
|
||||
bootstrapVersion=2.3.2
|
||||
commonsLoggingVersion=1.2
|
||||
commonsPoolVersion=2.4.2
|
||||
gebVersion=0.13.1
|
||||
groovyVersion=2.4.4
|
||||
h2Version=1.4.192
|
||||
hazelcastVersion=3.6.5
|
||||
html5ShivVersion=3.7.3
|
||||
httpClientVersion=4.5.1
|
||||
jacksonVersion=2.6.5
|
||||
jedisVersion=2.8.1
|
||||
jacksonVersion=2.8.8
|
||||
jspApiVersion=2.0
|
||||
jstlVersion=1.2.1
|
||||
jstlelVersion=1.2.5
|
||||
junitVersion=4.12
|
||||
lettuceVersion=3.5.0.Final
|
||||
mockitoVersion=1.10.19
|
||||
seleniumVersion=2.52.0
|
||||
servletApiVersion=3.0.1
|
||||
spockVersion=1.0-groovy-2.4
|
||||
springVersion=4.3.4.RELEASE
|
||||
springDataGemFireVersion=1.8.10.RELEASE
|
||||
springDataGeodeVersion=1.0.0.INCUBATING-RELEASE
|
||||
springDataMongoVersion=1.9.4.RELEASE
|
||||
springDataRedisVersion=1.7.10.RELEASE
|
||||
# We cannot go beyond this version with Spring 3 support
|
||||
jstlelVersion=1.2.5
|
||||
version=1.3.5.RELEASE
|
||||
springDataRedisVersion=1.7.11.RELEASE
|
||||
html5ShivVersion=3.7.3
|
||||
commonsLoggingVersion=1.2
|
||||
junitVersion=4.12
|
||||
springDataRedisSpring3Version=1.7.1.RELEASE
|
||||
springSecurityVersion=4.2.0.RELEASE
|
||||
lettuceVersion=3.5.0.Final
|
||||
gebVersion=0.13.1
|
||||
mockitoVersion=1.10.19
|
||||
hazelcastVersion=3.6.8
|
||||
seleniumVersion=2.52.0
|
||||
springDataGeodeVersion=1.0.0.INCUBATING-RELEASE
|
||||
springSecurityVersion=4.2.11.RELEASE
|
||||
springVersion=4.3.19.RELEASE
|
||||
httpClientVersion=4.5.3
|
||||
h2Version=1.4.195
|
||||
jedisVersion=2.8.2
|
||||
springDataMongoVersion=1.9.11.RELEASE
|
||||
springShellVersion=1.1.0.RELEASE
|
||||
springDataGemFireVersion=1.8.11.RELEASE
|
||||
assertjVersion=2.5.0
|
||||
spockVersion=1.0-groovy-2.4
|
||||
webjarsTaglibVersion=0.3
|
||||
version=1.3.1.BUILD-SNAPSHOT
|
||||
jstlVersion=1.2.1
|
||||
groovyVersion=2.4.11
|
||||
|
||||
@@ -78,7 +78,7 @@ task integrationTest(type: Test, dependsOn: jar) {
|
||||
check.dependsOn integrationTest
|
||||
|
||||
checkstyle {
|
||||
configFile = rootProject.file('config/checkstyle/checkstyle.xml')
|
||||
configFile = rootProject.file('etc/checkstyle/checkstyle.xml')
|
||||
configProperties.configDir = configFile.parentFile
|
||||
toolVersion = '6.16.1'
|
||||
}
|
||||
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
||||
#Fri Nov 11 19:46:57 CET 2016
|
||||
#Mon Jan 29 18:35:20 CET 2018
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-3.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-3.5.1-bin.zip
|
||||
|
||||
19
gradlew
vendored
19
gradlew
vendored
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
@@ -154,16 +154,19 @@ if $cygwin ; then
|
||||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
# Escape application args
|
||||
save ( ) {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [[ "$(uname)" == "Darwin" ]] && [[ "$HOME" == "$PWD" ]]; then
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
||||
exec "$JAVACMD" "$@"
|
||||
|
||||
@@ -14,9 +14,11 @@ apply from: SAMPLE_GRADLE
|
||||
|
||||
group = 'samples'
|
||||
|
||||
ext['spring-security.version'] = springSecurityVersion
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-session'),
|
||||
"org.springframework.boot:spring-boot-starter-redis",
|
||||
"org.springframework.boot:spring-boot-starter-data-redis",
|
||||
"org.springframework.boot:spring-boot-starter-web",
|
||||
"org.springframework.boot:spring-boot-starter-thymeleaf",
|
||||
"org.springframework.boot:spring-boot-starter-security",
|
||||
|
||||
@@ -14,9 +14,11 @@ apply from: SAMPLE_GRADLE
|
||||
|
||||
group = 'samples'
|
||||
|
||||
ext['spring-security.version'] = springSecurityVersion
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-session'),
|
||||
"org.springframework.boot:spring-boot-starter-redis",
|
||||
"org.springframework.boot:spring-boot-starter-data-redis",
|
||||
"org.springframework.boot:spring-boot-starter-web",
|
||||
"org.springframework.boot:spring-boot-starter-security",
|
||||
"org.springframework.boot:spring-boot-starter-thymeleaf",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -42,7 +42,8 @@ public class SessionConfig {
|
||||
int port = SocketUtils.findAvailableTcpPort();
|
||||
|
||||
config.getNetworkConfig()
|
||||
.setPort(port);
|
||||
.setPort(port)
|
||||
.getJoin().getMulticastConfig().setEnabled(false);
|
||||
|
||||
System.out.println("Hazelcast port #: " + port);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -52,6 +52,7 @@ public class Initializer implements ServletContextListener {
|
||||
Config cfg = new Config();
|
||||
NetworkConfig netConfig = new NetworkConfig();
|
||||
netConfig.setPort(getAvailablePort());
|
||||
netConfig.getJoin().getMulticastConfig().setEnabled(false);
|
||||
cfg.setNetworkConfig(netConfig);
|
||||
SerializerConfig serializer = new SerializerConfig().setTypeClass(Object.class)
|
||||
.setImplementation(new ObjectStreamSerializer());
|
||||
|
||||
@@ -10,12 +10,9 @@ buildscript {
|
||||
apply from: JAVA_GRADLE
|
||||
apply plugin: "application"
|
||||
apply plugin: 'org.springframework.boot'
|
||||
apply from: SAMPLE_GRADLE
|
||||
|
||||
tasks.findByPath("artifactoryPublish")?.enabled = false
|
||||
|
||||
sonarqube {
|
||||
skipProject = true
|
||||
}
|
||||
ext['spring-security.version'] = springSecurityVersion
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-session-data-gemfire'),
|
||||
@@ -24,14 +21,14 @@ dependencies {
|
||||
"org.webjars:bootstrap:$bootstrapVersion",
|
||||
"org.webjars:webjars-locator"
|
||||
|
||||
runtime "org.springframework.shell:spring-shell:1.0.0.RELEASE"
|
||||
runtime "org.springframework.shell:spring-shell:$springShellVersion"
|
||||
|
||||
testCompile "org.springframework.boot:spring-boot-starter-test"
|
||||
|
||||
integrationTestCompile gebDependencies,
|
||||
"org.spockframework:spock-spring:$spockVersion"
|
||||
|
||||
integrationTestRuntime "org.springframework.shell:spring-shell:1.0.0.RELEASE"
|
||||
integrationTestRuntime "org.springframework.shell:spring-shell:$springShellVersion"
|
||||
}
|
||||
|
||||
run {
|
||||
@@ -44,24 +41,26 @@ springBoot {
|
||||
mainClass = 'sample.client.Application'
|
||||
}
|
||||
|
||||
task runGemFireServer() << {
|
||||
println 'STARTING GEMFIRE SERVER...'
|
||||
task runGemFireServer() {
|
||||
doLast {
|
||||
println 'STARTING GEMFIRE SERVER...'
|
||||
|
||||
ext.port = reservePort()
|
||||
ext.port = reservePort()
|
||||
|
||||
String classpath = sourceSets.main.runtimeClasspath.collect { it }.join(File.pathSeparator)
|
||||
String classpath = sourceSets.main.runtimeClasspath.collect { it }.join(File.pathSeparator)
|
||||
|
||||
String[] commandLine = ['java', '-server', '-ea', '-classpath', classpath,
|
||||
"-Dgemfire.cache.server.port=$port",
|
||||
"-Dgemfire.log-level=" + System.getProperty('gemfire.log.level', 'warning'),
|
||||
'sample.server.GemFireServer']
|
||||
String[] commandLine = ['java', '-server', '-ea', '-classpath', classpath,
|
||||
"-Dgemfire.cache.server.port=$port",
|
||||
"-Dgemfire.log-level=" + System.getProperty('gemfire.log.level', 'warning'),
|
||||
'sample.server.GemFireServer']
|
||||
|
||||
//println commandLine
|
||||
//println commandLine
|
||||
|
||||
ext.process = commandLine.execute()
|
||||
process.in.close()
|
||||
process.out.close()
|
||||
process.err.close()
|
||||
ext.process = commandLine.execute()
|
||||
process.in.close()
|
||||
process.out.close()
|
||||
process.err.close()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
apply from: JAVA_GRADLE
|
||||
apply from: TOMCAT_7_GRADLE
|
||||
apply plugin: "application"
|
||||
|
||||
tasks.findByPath("artifactoryPublish")?.enabled = false
|
||||
|
||||
sonarqube {
|
||||
skipProject = true
|
||||
}
|
||||
apply from: SAMPLE_GRADLE
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-session-data-gemfire'),
|
||||
@@ -17,13 +12,13 @@ dependencies {
|
||||
|
||||
providedCompile "javax.servlet:javax.servlet-api:$servletApiVersion"
|
||||
|
||||
runtime "org.springframework.shell:spring-shell:1.0.0.RELEASE"
|
||||
runtime "org.springframework.shell:spring-shell:$springShellVersion"
|
||||
|
||||
testCompile "junit:junit:$junitVersion"
|
||||
|
||||
integrationTestCompile gebDependencies
|
||||
|
||||
integrationTestRuntime "org.springframework.shell:spring-shell:1.0.0.RELEASE"
|
||||
integrationTestRuntime "org.springframework.shell:spring-shell:$springShellVersion"
|
||||
}
|
||||
|
||||
mainClassName = 'sample.Application'
|
||||
@@ -31,29 +26,33 @@ mainClassName = 'sample.Application'
|
||||
def port
|
||||
def process
|
||||
|
||||
task availablePort() << {
|
||||
def serverSocket = new ServerSocket(0)
|
||||
port = serverSocket.localPort
|
||||
serverSocket.close()
|
||||
task availablePort() {
|
||||
doLast {
|
||||
def serverSocket = new ServerSocket(0)
|
||||
port = serverSocket.localPort
|
||||
serverSocket.close()
|
||||
}
|
||||
}
|
||||
|
||||
task runGemFireServer(dependsOn: availablePort) << {
|
||||
println 'STARTING GEMFIRE SERVER...'
|
||||
task runGemFireServer(dependsOn: availablePort) {
|
||||
doLast {
|
||||
println 'STARTING GEMFIRE SERVER...'
|
||||
|
||||
String classpath = sourceSets.main.runtimeClasspath.collect { it }.join(File.pathSeparator)
|
||||
String classpath = sourceSets.main.runtimeClasspath.collect { it }.join(File.pathSeparator)
|
||||
|
||||
String[] commandLine = ['java', '-server', '-ea',
|
||||
"-Dspring.session.data.gemfire.port=$port",
|
||||
"-Dsample.httpsession.gemfire.log-level="
|
||||
+ System.getProperty('sample.httpsession.gemfire.log-level', 'warning'),
|
||||
'-classpath', classpath, 'sample.Application' ]
|
||||
String[] commandLine = ['java', '-server', '-ea',
|
||||
"-Dspring.session.data.gemfire.port=$port",
|
||||
"-Dsample.httpsession.gemfire.log-level="
|
||||
+ System.getProperty('sample.httpsession.gemfire.log-level', 'warning'),
|
||||
'-classpath', classpath, 'sample.Application']
|
||||
|
||||
//println commandLine
|
||||
//println commandLine
|
||||
|
||||
process = commandLine.execute()
|
||||
process.in.close()
|
||||
process.out.close()
|
||||
process.err.close()
|
||||
process = commandLine.execute()
|
||||
process.in.close()
|
||||
process.out.close()
|
||||
process.err.close()
|
||||
}
|
||||
}
|
||||
|
||||
integrationTest.doLast {
|
||||
|
||||
@@ -12,13 +12,13 @@ dependencies {
|
||||
|
||||
providedCompile "javax.servlet:javax.servlet-api:$servletApiVersion"
|
||||
|
||||
runtime "org.springframework.shell:spring-shell:1.0.0.RELEASE"
|
||||
runtime "org.springframework.shell:spring-shell:$springShellVersion"
|
||||
|
||||
testCompile "junit:junit:$junitVersion"
|
||||
|
||||
integrationTestCompile gebDependencies
|
||||
|
||||
integrationTestRuntime "org.springframework.shell:spring-shell:1.0.0.RELEASE"
|
||||
integrationTestRuntime "org.springframework.shell:spring-shell:$springShellVersion"
|
||||
}
|
||||
|
||||
|
||||
@@ -27,29 +27,33 @@ def process
|
||||
|
||||
mainClassName = "sample.ServerConfig"
|
||||
|
||||
task availablePort() << {
|
||||
def serverSocket = new ServerSocket(0)
|
||||
port = serverSocket.localPort
|
||||
serverSocket.close()
|
||||
task availablePort() {
|
||||
doLast {
|
||||
def serverSocket = new ServerSocket(0)
|
||||
port = serverSocket.localPort
|
||||
serverSocket.close()
|
||||
}
|
||||
}
|
||||
|
||||
task runGemFireServer(dependsOn: availablePort) << {
|
||||
println 'STARTING GEMFIRE SERVER...'
|
||||
task runGemFireServer(dependsOn: availablePort) {
|
||||
doLast {
|
||||
println 'STARTING GEMFIRE SERVER...'
|
||||
|
||||
String classpath = sourceSets.main.runtimeClasspath.collect { it }.join(File.pathSeparator)
|
||||
String classpath = sourceSets.main.runtimeClasspath.collect { it }.join(File.pathSeparator)
|
||||
|
||||
String[] commandLine = ['java', '-server', '-ea',
|
||||
"-Dspring.session.data.gemfire.port=$port",
|
||||
"-Dsample.httpsession.gemfire.log-level="
|
||||
+ System.getProperty('sample.httpsession.gemfire.log-level', 'warning'),
|
||||
'-classpath', classpath, 'sample.ServerConfig']
|
||||
String[] commandLine = ['java', '-server', '-ea',
|
||||
"-Dspring.session.data.gemfire.port=$port",
|
||||
"-Dsample.httpsession.gemfire.log-level="
|
||||
+ System.getProperty('sample.httpsession.gemfire.log-level', 'warning'),
|
||||
'-classpath', classpath, 'sample.ServerConfig']
|
||||
|
||||
//println commandLine
|
||||
//println commandLine
|
||||
|
||||
process = commandLine.execute()
|
||||
process.in.close()
|
||||
process.out.close()
|
||||
process.err.close()
|
||||
process = commandLine.execute()
|
||||
process.in.close()
|
||||
process.out.close()
|
||||
process.err.close()
|
||||
}
|
||||
}
|
||||
|
||||
integrationTest.doLast {
|
||||
|
||||
@@ -15,5 +15,5 @@ dependencies {
|
||||
|
||||
integrationTestCompile gebDependencies
|
||||
|
||||
integrationTestRuntime "org.springframework.shell:spring-shell:1.0.0.RELEASE"
|
||||
integrationTestRuntime "org.springframework.shell:spring-shell:$springShellVersion"
|
||||
}
|
||||
|
||||
@@ -15,5 +15,5 @@ dependencies {
|
||||
|
||||
integrationTestCompile gebDependencies
|
||||
|
||||
integrationTestRuntime "org.springframework.shell:spring-shell:1.0.0.RELEASE"
|
||||
integrationTestRuntime "org.springframework.shell:spring-shell:$springShellVersion"
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ apply from: SAMPLE_GRADLE
|
||||
|
||||
group = 'samples'
|
||||
|
||||
ext['spring-security.version'] = springSecurityVersion
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-session-jdbc'),
|
||||
"org.springframework.boot:spring-boot-starter-jdbc",
|
||||
|
||||
@@ -10,20 +10,18 @@ buildscript {
|
||||
apply plugin: 'org.springframework.boot'
|
||||
|
||||
apply from: JAVA_GRADLE
|
||||
|
||||
//tasks.findByPath("artifactoryPublish")?.enabled = false
|
||||
apply from: SAMPLE_GRADLE
|
||||
|
||||
group = 'samples'
|
||||
ext {
|
||||
jsonassertVersion="1.3.0"
|
||||
assertjVersion = "2.4.0"
|
||||
}
|
||||
|
||||
ext['spring-security.version'] = springSecurityVersion
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-session'),
|
||||
"org.springframework.boot:spring-boot-starter-redis",
|
||||
"org.springframework.boot:spring-boot-starter-data-redis",
|
||||
"org.springframework.boot:spring-boot-starter-web",
|
||||
"org.springframework.boot:spring-boot-starter-thymeleaf",
|
||||
"org.springframework.boot:spring-boot-starter-security",
|
||||
@@ -66,4 +64,4 @@ def reservePort() {
|
||||
def result = socket.localPort
|
||||
socket.close()
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ apply from: SAMPLE_GRADLE
|
||||
|
||||
group = 'samples'
|
||||
|
||||
ext['spring-security.version'] = springSecurityVersion
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-session'),
|
||||
"org.springframework.boot:spring-boot-starter-data-mongodb",
|
||||
|
||||
@@ -15,6 +15,8 @@ apply from: SAMPLE_GRADLE
|
||||
|
||||
group = 'samples'
|
||||
|
||||
ext['spring-security.version'] = springSecurityVersion
|
||||
|
||||
dependencies {
|
||||
compile(project(':spring-session-data-redis')) {
|
||||
exclude module: 'jedis'
|
||||
|
||||
@@ -23,7 +23,6 @@ include 'samples:security'
|
||||
include 'samples:users'
|
||||
include 'samples:websocket'
|
||||
include 'samples:mongo'
|
||||
include 'samples:grails3'
|
||||
|
||||
include 'spring-session'
|
||||
include 'spring-session-data-gemfire'
|
||||
|
||||
@@ -29,14 +29,14 @@ dependencies {
|
||||
"org.springframework.security:spring-security-web:$springSecurityVersion"
|
||||
provided "javax.servlet:javax.servlet-api:$servletApiVersion"
|
||||
integrationTestCompile "redis.clients:jedis:$jedisVersion",
|
||||
"org.apache.commons:commons-pool2:2.2",
|
||||
"org.apache.commons:commons-pool2:$commonsPoolVersion",
|
||||
"com.hazelcast:hazelcast-client:$hazelcastVersion",
|
||||
"com.h2database:h2:$h2Version",
|
||||
"org.hsqldb:hsqldb:2.3.3",
|
||||
"org.apache.derby:derby:10.12.1.1",
|
||||
"de.flapdoodle.embed:de.flapdoodle.embed.mongo:1.50.2"
|
||||
"de.flapdoodle.embed:de.flapdoodle.embed.mongo:1.50.5"
|
||||
|
||||
integrationTestRuntime "org.springframework.shell:spring-shell:1.0.0.RELEASE"
|
||||
integrationTestRuntime "org.springframework.shell:spring-shell:$springShellVersion"
|
||||
|
||||
testCompile "junit:junit:$junitVersion",
|
||||
"org.mockito:mockito-core:$mockitoVersion",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -18,9 +18,17 @@ package org.springframework.session.hazelcast;
|
||||
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.core.IMap;
|
||||
import com.hazelcast.instance.HazelcastInstanceProxy;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.session.FindByIndexNameSessionRepository;
|
||||
import org.springframework.session.MapSession;
|
||||
import org.springframework.session.hazelcast.HazelcastSessionRepository.HazelcastSession;
|
||||
|
||||
@@ -34,8 +42,10 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*/
|
||||
public abstract class AbstractHazelcastRepositoryITests {
|
||||
|
||||
private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT";
|
||||
|
||||
@Autowired
|
||||
private HazelcastInstance hazelcast;
|
||||
private HazelcastInstance hazelcastInstance;
|
||||
|
||||
@Autowired
|
||||
private HazelcastSessionRepository repository;
|
||||
@@ -45,8 +55,8 @@ public abstract class AbstractHazelcastRepositoryITests {
|
||||
HazelcastSession sessionToSave = this.repository.createSession();
|
||||
String sessionId = sessionToSave.getId();
|
||||
|
||||
IMap<String, MapSession> hazelcastMap = this.hazelcast.getMap(
|
||||
"spring:session:sessions");
|
||||
IMap<String, MapSession> hazelcastMap = this.hazelcastInstance
|
||||
.getMap("spring:session:sessions");
|
||||
|
||||
assertThat(hazelcastMap.size()).isEqualTo(0);
|
||||
|
||||
@@ -60,4 +70,70 @@ public abstract class AbstractHazelcastRepositoryITests {
|
||||
assertThat(hazelcastMap.size()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test // gh-1076
|
||||
public void attemptToUpdateSessionAfterDelete() {
|
||||
HazelcastSession session = this.repository.createSession();
|
||||
String sessionId = session.getId();
|
||||
this.repository.save(session);
|
||||
session = this.repository.getSession(sessionId);
|
||||
session.setAttribute("attributeName", "attributeValue");
|
||||
this.repository.delete(sessionId);
|
||||
this.repository.save(session);
|
||||
|
||||
assertThat(this.repository.getSession(sessionId)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createAndUpdateSession() {
|
||||
HazelcastSession session = this.repository.createSession();
|
||||
String sessionId = session.getId();
|
||||
|
||||
this.repository.save(session);
|
||||
|
||||
session = this.repository.getSession(sessionId);
|
||||
session.setAttribute("attributeName", "attributeValue");
|
||||
|
||||
this.repository.save(session);
|
||||
|
||||
assertThat(this.repository.getSession(sessionId)).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createSessionWithSecurityContextAndFindById() {
|
||||
HazelcastSession session = this.repository.createSession();
|
||||
String sessionId = session.getId();
|
||||
|
||||
Authentication authentication = new UsernamePasswordAuthenticationToken(
|
||||
"saves-" + System.currentTimeMillis(), "password",
|
||||
AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
|
||||
securityContext.setAuthentication(authentication);
|
||||
session.setAttribute(SPRING_SECURITY_CONTEXT, securityContext);
|
||||
|
||||
this.repository.save(session);
|
||||
|
||||
assertThat(this.repository.getSession(sessionId)).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createSessionWithSecurityContextAndFindByPrincipal() {
|
||||
Assume.assumeTrue("Hazelcast runs in embedded server topology",
|
||||
this.hazelcastInstance instanceof HazelcastInstanceProxy);
|
||||
|
||||
HazelcastSession session = this.repository.createSession();
|
||||
|
||||
String username = "saves-" + System.currentTimeMillis();
|
||||
Authentication authentication = new UsernamePasswordAuthenticationToken(username,
|
||||
"password", AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
|
||||
securityContext.setAuthentication(authentication);
|
||||
session.setAttribute(SPRING_SECURITY_CONTEXT, securityContext);
|
||||
|
||||
this.repository.save(session);
|
||||
|
||||
assertThat(this.repository.findByIndexNameAndIndexValue(
|
||||
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, username))
|
||||
.isNotNull();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -49,12 +49,12 @@ public class HazelcastClientRepositoryITests extends AbstractHazelcastRepository
|
||||
private static HazelcastInstance hazelcastInstance;
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() {
|
||||
public static void setUpClass() {
|
||||
hazelcastInstance = HazelcastITestUtils.embeddedHazelcastServer(PORT);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void teardown() {
|
||||
public static void tearDownClass() {
|
||||
if (hazelcastInstance != null) {
|
||||
hazelcastInstance.shutdown();
|
||||
}
|
||||
@@ -65,7 +65,7 @@ public class HazelcastClientRepositoryITests extends AbstractHazelcastRepository
|
||||
static class HazelcastSessionConfig {
|
||||
|
||||
@Bean
|
||||
public HazelcastInstance embeddedHazelcastClient() {
|
||||
public HazelcastInstance hazelcastInstance() {
|
||||
ClientConfig clientConfig = new ClientConfig();
|
||||
clientConfig.getNetworkConfig().addAddress("127.0.0.1:" + PORT);
|
||||
return HazelcastClient.newHazelcastClient(clientConfig);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -19,6 +19,7 @@ package org.springframework.session.hazelcast;
|
||||
import com.hazelcast.config.Config;
|
||||
import com.hazelcast.config.MapAttributeConfig;
|
||||
import com.hazelcast.config.MapIndexConfig;
|
||||
import com.hazelcast.config.NetworkConfig;
|
||||
import com.hazelcast.core.Hazelcast;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
|
||||
@@ -46,8 +47,12 @@ public final class HazelcastITestUtils {
|
||||
|
||||
Config config = new Config();
|
||||
|
||||
config.getNetworkConfig()
|
||||
.setPort(port);
|
||||
NetworkConfig networkConfig = config.getNetworkConfig();
|
||||
|
||||
networkConfig.setPort(port);
|
||||
|
||||
networkConfig.getJoin()
|
||||
.getMulticastConfig().setEnabled(false);
|
||||
|
||||
config.getMapConfig("spring:session:sessions")
|
||||
.addMapAttributeConfig(attributeConfig)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -43,7 +43,7 @@ public class HazelcastServerRepositoryITests extends AbstractHazelcastRepository
|
||||
static class HazelcastSessionConfig {
|
||||
|
||||
@Bean
|
||||
public HazelcastInstance embeddedHazelcastServer() {
|
||||
public HazelcastInstance hazelcastInstance() {
|
||||
return HazelcastITestUtils.embeddedHazelcastServer();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -34,10 +34,8 @@ import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.session.ExpiringSession;
|
||||
import org.springframework.session.FindByIndexNameSessionRepository;
|
||||
import org.springframework.session.MapSession;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.session.jdbc.config.annotation.web.http.EnableJdbcHttpSession;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
@@ -82,6 +80,19 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
|
||||
AuthorityUtils.createAuthorityList("ROLE_USER")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveWhenNoAttributesThenCanBeFound() {
|
||||
JdbcOperationsSessionRepository.JdbcSession toSave = this.repository
|
||||
.createSession();
|
||||
|
||||
this.repository.save(toSave);
|
||||
JdbcOperationsSessionRepository.JdbcSession session = this.repository.getSession(toSave.getId());
|
||||
|
||||
assertThat(session).isNotNull();
|
||||
assertThat(session.isChanged()).isFalse();
|
||||
assertThat(session.getDelta()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saves() throws InterruptedException {
|
||||
String username = "saves-" + System.currentTimeMillis();
|
||||
@@ -100,9 +111,11 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
|
||||
|
||||
this.repository.save(toSave);
|
||||
|
||||
Session session = this.repository.getSession(toSave.getId());
|
||||
JdbcOperationsSessionRepository.JdbcSession session = this.repository.getSession(toSave.getId());
|
||||
|
||||
assertThat(session.getId()).isEqualTo(toSave.getId());
|
||||
assertThat(session.isChanged()).isFalse();
|
||||
assertThat(session.getDelta()).isEmpty();
|
||||
assertThat(session.getAttributeNames()).isEqualTo(toSave.getAttributeNames());
|
||||
assertThat(session.getAttribute(expectedAttributeName))
|
||||
.isEqualTo(toSave.getAttribute(expectedAttributeName));
|
||||
@@ -135,7 +148,9 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
|
||||
this.repository.save(toSave);
|
||||
toSave = this.repository.getSession(toSave.getId());
|
||||
|
||||
Session session = this.repository.getSession(toSave.getId());
|
||||
JdbcOperationsSessionRepository.JdbcSession session = this.repository.getSession(toSave.getId());
|
||||
assertThat(session.isChanged()).isFalse();
|
||||
assertThat(session.getDelta()).isEmpty();
|
||||
assertThat(session.getAttributeNames().size()).isEqualTo(2);
|
||||
assertThat(session.getAttribute("a")).isEqualTo("b");
|
||||
assertThat(session.getAttribute("1")).isEqualTo("2");
|
||||
@@ -156,9 +171,11 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
|
||||
toSave.setLastAccessedTime(lastAccessedTime);
|
||||
this.repository.save(toSave);
|
||||
|
||||
ExpiringSession session = this.repository.getSession(toSave.getId());
|
||||
JdbcOperationsSessionRepository.JdbcSession session = this.repository.getSession(toSave.getId());
|
||||
|
||||
assertThat(session).isNotNull();
|
||||
assertThat(session.isChanged()).isFalse();
|
||||
assertThat(session.getDelta()).isEmpty();
|
||||
assertThat(session.isExpired()).isFalse();
|
||||
assertThat(session.getLastAccessedTime()).isEqualTo(lastAccessedTime);
|
||||
}
|
||||
@@ -225,6 +242,10 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
|
||||
|
||||
assertThat(findByPrincipalName).hasSize(1);
|
||||
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
|
||||
for (JdbcOperationsSessionRepository.JdbcSession session : findByPrincipalName.values()) {
|
||||
assertThat(session.isChanged()).isFalse();
|
||||
assertThat(session.getDelta()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -247,6 +268,10 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
|
||||
|
||||
assertThat(findByPrincipalName).hasSize(1);
|
||||
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
|
||||
for (JdbcOperationsSessionRepository.JdbcSession session : findByPrincipalName.values()) {
|
||||
assertThat(session.isChanged()).isFalse();
|
||||
assertThat(session.getDelta()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -289,6 +314,10 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
|
||||
|
||||
assertThat(findByPrincipalName).hasSize(1);
|
||||
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
|
||||
for (JdbcOperationsSessionRepository.JdbcSession session : findByPrincipalName.values()) {
|
||||
assertThat(session.isChanged()).isFalse();
|
||||
assertThat(session.getDelta()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -336,6 +365,10 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
|
||||
|
||||
assertThat(findByPrincipalName).hasSize(1);
|
||||
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
|
||||
for (JdbcOperationsSessionRepository.JdbcSession session : findByPrincipalName.values()) {
|
||||
assertThat(session.isChanged()).isFalse();
|
||||
assertThat(session.getDelta()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -395,6 +428,10 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
|
||||
|
||||
assertThat(findByPrincipalName).hasSize(1);
|
||||
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
|
||||
for (JdbcOperationsSessionRepository.JdbcSession session : findByPrincipalName.values()) {
|
||||
assertThat(session.isChanged()).isFalse();
|
||||
assertThat(session.getDelta()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -416,6 +453,10 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
|
||||
|
||||
assertThat(findByPrincipalName).hasSize(1);
|
||||
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
|
||||
for (JdbcOperationsSessionRepository.JdbcSession session : findByPrincipalName.values()) {
|
||||
assertThat(session.isChanged()).isFalse();
|
||||
assertThat(session.getDelta()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -455,6 +496,10 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
|
||||
|
||||
assertThat(findByPrincipalName).hasSize(1);
|
||||
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
|
||||
for (JdbcOperationsSessionRepository.JdbcSession session : findByPrincipalName.values()) {
|
||||
assertThat(session.isChanged()).isFalse();
|
||||
assertThat(session.getDelta()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -499,6 +544,10 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
|
||||
|
||||
assertThat(findByPrincipalName).hasSize(1);
|
||||
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
|
||||
for (JdbcOperationsSessionRepository.JdbcSession session : findByPrincipalName.values()) {
|
||||
assertThat(session.isChanged()).isFalse();
|
||||
assertThat(session.getDelta()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -559,6 +608,46 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
|
||||
assertThat(this.repository.getSession(session.getId())).isNull();
|
||||
}
|
||||
|
||||
@Test // gh-1031
|
||||
public void saveDeleted() {
|
||||
JdbcOperationsSessionRepository.JdbcSession session = this.repository.createSession();
|
||||
this.repository.save(session);
|
||||
session = this.repository.getSession(session.getId());
|
||||
this.repository.delete(session.getId());
|
||||
session.setLastAccessedTime(System.currentTimeMillis());
|
||||
this.repository.save(session);
|
||||
|
||||
assertThat(this.repository.getSession(session.getId())).isNull();
|
||||
}
|
||||
|
||||
@Test // gh-1031
|
||||
public void saveDeletedAddAttribute() {
|
||||
JdbcOperationsSessionRepository.JdbcSession session = this.repository.createSession();
|
||||
this.repository.save(session);
|
||||
session = this.repository.getSession(session.getId());
|
||||
this.repository.delete(session.getId());
|
||||
session.setLastAccessedTime(System.currentTimeMillis());
|
||||
session.setAttribute("testName", "testValue1");
|
||||
this.repository.save(session);
|
||||
|
||||
assertThat(this.repository.getSession(session.getId())).isNull();
|
||||
}
|
||||
|
||||
@Test // gh-1203
|
||||
public void saveWithLargeAttribute() {
|
||||
String attributeName = "largeAttribute";
|
||||
int arraySize = 4000;
|
||||
|
||||
JdbcOperationsSessionRepository.JdbcSession session = this.repository
|
||||
.createSession();
|
||||
session.setAttribute(attributeName, new byte[arraySize]);
|
||||
this.repository.save(session);
|
||||
session = this.repository.getSession(session.getId());
|
||||
|
||||
assertThat(session).isNotNull();
|
||||
assertThat((byte[]) session.getAttribute(attributeName)).hasSize(arraySize);
|
||||
}
|
||||
|
||||
private String getSecurityName() {
|
||||
return this.context.getAuthentication().getName();
|
||||
}
|
||||
|
||||
@@ -14,16 +14,7 @@
|
||||
<ports>0</ports>
|
||||
</outbound-ports>
|
||||
<join>
|
||||
<multicast enabled="false">
|
||||
</multicast>
|
||||
<tcp-ip enabled="true">
|
||||
<interface>127.0.0.1</interface>
|
||||
<member-list>
|
||||
<member>127.0.0.1</member>
|
||||
</member-list>
|
||||
</tcp-ip>
|
||||
<aws enabled="false">
|
||||
</aws>
|
||||
<multicast enabled="false"/>
|
||||
</join>
|
||||
</network>
|
||||
|
||||
@@ -14,16 +14,7 @@
|
||||
<ports>0</ports>
|
||||
</outbound-ports>
|
||||
<join>
|
||||
<multicast enabled="false">
|
||||
</multicast>
|
||||
<tcp-ip enabled="true">
|
||||
<interface>127.0.0.1</interface>
|
||||
<member-list>
|
||||
<member>127.0.0.1</member>
|
||||
</member-list>
|
||||
</tcp-ip>
|
||||
<aws enabled="false">
|
||||
</aws>
|
||||
<multicast enabled="false"/>
|
||||
</join>
|
||||
</network>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -52,7 +52,7 @@ public interface FindByIndexNameSessionRepository<S extends Session>
|
||||
* {@link FindByIndexNameSessionRepository#PRINCIPAL_NAME_INDEX_NAME} and the value of
|
||||
* the specified principal name.
|
||||
*
|
||||
* @param indexName the name if the index (i.e.
|
||||
* @param indexName the name of the index (i.e.
|
||||
* {@link FindByIndexNameSessionRepository#PRINCIPAL_NAME_INDEX_NAME})
|
||||
* @param indexValue the value of the index to search for.
|
||||
* @return a Map (never null) of the session id to the {@link Session} of all sessions
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -18,6 +18,7 @@ package org.springframework.session;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
@@ -141,7 +142,7 @@ public final class MapSession implements ExpiringSession, Serializable {
|
||||
}
|
||||
|
||||
public Set<String> getAttributeNames() {
|
||||
return this.sessionAttrs.keySet();
|
||||
return new HashSet<String>(this.sessionAttrs.keySet());
|
||||
}
|
||||
|
||||
public void setAttribute(String attributeName, Object attributeValue) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -201,7 +201,7 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* <p>
|
||||
* One problem with relying on Redis expiration exclusively is that Redis makes no
|
||||
* guarantee of when the expired event will be fired if they key has not been accessed.
|
||||
* guarantee of when the expired event will be fired if the key has not been accessed.
|
||||
* Specifically the background task that Redis uses to clean up expired keys is a low
|
||||
* priority task and may not trigger the key expiration. For additional details see
|
||||
* <a href="http://redis.io/topics/notifications">Timing of expired events</a> section in
|
||||
@@ -212,7 +212,7 @@ import org.springframework.util.Assert;
|
||||
* To circumvent the fact that expired events are not guaranteed to happen we can ensure
|
||||
* that each key is accessed when it is expected to expire. This means that if the TTL is
|
||||
* expired on the key, Redis will remove the key and fire the expired event when we try to
|
||||
* access they key.
|
||||
* access the key.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
@@ -277,7 +277,7 @@ public class RedisOperationsSessionRepository implements
|
||||
static final String LAST_ACCESSED_ATTR = "lastAccessedTime";
|
||||
|
||||
/**
|
||||
* The prefix of the key for used for session attributes. The suffix is the name of
|
||||
* The prefix of the key used for session attributes. The suffix is the name of
|
||||
* the session attribute. For example, if the session contained an attribute named
|
||||
* attributeName, then there would be an entry in the hash named
|
||||
* sessionAttr:attributeName that mapped to its value.
|
||||
@@ -518,6 +518,12 @@ public class RedisOperationsSessionRepository implements
|
||||
|
||||
RedisSession session = getSession(sessionId, true);
|
||||
|
||||
if (session == null) {
|
||||
logger.warn("Unable to publish SessionDestroyedEvent for session "
|
||||
+ sessionId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Publishing SessionDestroyedEvent for session " + sessionId);
|
||||
}
|
||||
@@ -525,20 +531,15 @@ public class RedisOperationsSessionRepository implements
|
||||
cleanupPrincipalIndex(session);
|
||||
|
||||
if (isDeleted) {
|
||||
handleDeleted(sessionId, session);
|
||||
handleDeleted(session);
|
||||
}
|
||||
else {
|
||||
handleExpired(sessionId, session);
|
||||
handleExpired(session);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanupPrincipalIndex(RedisSession session) {
|
||||
if (session == null) {
|
||||
return;
|
||||
}
|
||||
String sessionId = session.getId();
|
||||
String principal = PRINCIPAL_NAME_RESOLVER.resolvePrincipal(session);
|
||||
if (principal != null) {
|
||||
@@ -553,22 +554,12 @@ public class RedisOperationsSessionRepository implements
|
||||
publishEvent(new SessionCreatedEvent(this, session));
|
||||
}
|
||||
|
||||
private void handleDeleted(String sessionId, RedisSession session) {
|
||||
if (session == null) {
|
||||
publishEvent(new SessionDeletedEvent(this, sessionId));
|
||||
}
|
||||
else {
|
||||
publishEvent(new SessionDeletedEvent(this, session));
|
||||
}
|
||||
private void handleDeleted(RedisSession session) {
|
||||
publishEvent(new SessionDeletedEvent(this, session));
|
||||
}
|
||||
|
||||
private void handleExpired(String sessionId, RedisSession session) {
|
||||
if (session == null) {
|
||||
publishEvent(new SessionExpiredEvent(this, sessionId));
|
||||
}
|
||||
else {
|
||||
publishEvent(new SessionExpiredEvent(this, session));
|
||||
}
|
||||
private void handleExpired(RedisSession session) {
|
||||
publishEvent(new SessionExpiredEvent(this, session));
|
||||
}
|
||||
|
||||
private void publishEvent(ApplicationEvent event) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -108,8 +108,7 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class HazelcastSessionRepository implements
|
||||
FindByIndexNameSessionRepository<HazelcastSessionRepository.HazelcastSession>,
|
||||
EntryAddedListener<String, MapSession>,
|
||||
EntryEvictedListener<String, MapSession>,
|
||||
EntryAddedListener<String, MapSession>, EntryEvictedListener<String, MapSession>,
|
||||
EntryRemovedListener<String, MapSession> {
|
||||
|
||||
/**
|
||||
@@ -200,11 +199,24 @@ public class HazelcastSessionRepository implements
|
||||
}
|
||||
|
||||
public void save(HazelcastSession session) {
|
||||
if (session.isChanged()) {
|
||||
this.sessions.put(session.getId(), session.getDelegate(),
|
||||
if (session.isNew) {
|
||||
this.sessions.set(session.getId(), session.getDelegate(),
|
||||
session.getMaxInactiveIntervalInSeconds(), TimeUnit.SECONDS);
|
||||
session.markUnchanged();
|
||||
}
|
||||
else if (session.hasChanges()) {
|
||||
SessionUpdateEntryProcessor entryProcessor = new SessionUpdateEntryProcessor();
|
||||
if (session.lastAccessedTimeChanged) {
|
||||
entryProcessor.setLastAccessedTime(session.getLastAccessedTime());
|
||||
}
|
||||
if (session.maxInactiveIntervalChanged) {
|
||||
entryProcessor.setMaxInactiveInterval(session.getMaxInactiveIntervalInSeconds());
|
||||
}
|
||||
if (!session.delta.isEmpty()) {
|
||||
entryProcessor.setDelta(session.delta);
|
||||
}
|
||||
this.sessions.executeOnKey(session.getId(), entryProcessor);
|
||||
}
|
||||
session.clearChangeFlags();
|
||||
}
|
||||
|
||||
public HazelcastSession getSession(String id) {
|
||||
@@ -223,13 +235,13 @@ public class HazelcastSessionRepository implements
|
||||
this.sessions.remove(id);
|
||||
}
|
||||
|
||||
public Map<String, HazelcastSession> findByIndexNameAndIndexValue(
|
||||
String indexName, String indexValue) {
|
||||
public Map<String, HazelcastSession> findByIndexNameAndIndexValue(String indexName,
|
||||
String indexValue) {
|
||||
if (!PRINCIPAL_NAME_INDEX_NAME.equals(indexName)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Collection<MapSession> sessions = this.sessions.values(
|
||||
Predicates.equal(PRINCIPAL_NAME_ATTRIBUTE, indexValue));
|
||||
Collection<MapSession> sessions = this.sessions
|
||||
.values(Predicates.equal(PRINCIPAL_NAME_ATTRIBUTE, indexValue));
|
||||
Map<String, HazelcastSession> sessionMap = new HashMap<String, HazelcastSession>(
|
||||
sessions.size());
|
||||
for (MapSession session : sessions) {
|
||||
@@ -270,7 +282,16 @@ public class HazelcastSessionRepository implements
|
||||
final class HazelcastSession implements ExpiringSession {
|
||||
|
||||
private final MapSession delegate;
|
||||
private boolean changed;
|
||||
|
||||
private boolean isNew;
|
||||
|
||||
private boolean sessionIdChanged;
|
||||
|
||||
private boolean lastAccessedTimeChanged;
|
||||
|
||||
private boolean maxInactiveIntervalChanged;
|
||||
|
||||
private Map<String, Object> delta = new HashMap<String, Object>();
|
||||
|
||||
/**
|
||||
* Creates a new instance ensuring to mark all of the new attributes to be
|
||||
@@ -278,7 +299,7 @@ public class HazelcastSessionRepository implements
|
||||
*/
|
||||
HazelcastSession() {
|
||||
this(new MapSession());
|
||||
this.changed = true;
|
||||
this.isNew = true;
|
||||
flushImmediateIfNecessary();
|
||||
}
|
||||
|
||||
@@ -294,7 +315,7 @@ public class HazelcastSessionRepository implements
|
||||
|
||||
public void setLastAccessedTime(long lastAccessedTime) {
|
||||
this.delegate.setLastAccessedTime(lastAccessedTime);
|
||||
this.changed = true;
|
||||
this.lastAccessedTimeChanged = true;
|
||||
flushImmediateIfNecessary();
|
||||
}
|
||||
|
||||
@@ -316,7 +337,7 @@ public class HazelcastSessionRepository implements
|
||||
|
||||
public void setMaxInactiveIntervalInSeconds(int interval) {
|
||||
this.delegate.setMaxInactiveIntervalInSeconds(interval);
|
||||
this.changed = true;
|
||||
this.maxInactiveIntervalChanged = true;
|
||||
flushImmediateIfNecessary();
|
||||
}
|
||||
|
||||
@@ -334,28 +355,33 @@ public class HazelcastSessionRepository implements
|
||||
|
||||
public void setAttribute(String attributeName, Object attributeValue) {
|
||||
this.delegate.setAttribute(attributeName, attributeValue);
|
||||
this.changed = true;
|
||||
this.delta.put(attributeName, attributeValue);
|
||||
flushImmediateIfNecessary();
|
||||
}
|
||||
|
||||
public void removeAttribute(String attributeName) {
|
||||
this.delegate.removeAttribute(attributeName);
|
||||
this.changed = true;
|
||||
this.delta.put(attributeName, null);
|
||||
flushImmediateIfNecessary();
|
||||
}
|
||||
|
||||
boolean isChanged() {
|
||||
return this.changed;
|
||||
}
|
||||
|
||||
void markUnchanged() {
|
||||
this.changed = false;
|
||||
}
|
||||
|
||||
MapSession getDelegate() {
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
boolean hasChanges() {
|
||||
return (this.lastAccessedTimeChanged || this.maxInactiveIntervalChanged
|
||||
|| !this.delta.isEmpty());
|
||||
}
|
||||
|
||||
void clearChangeFlags() {
|
||||
this.isNew = false;
|
||||
this.lastAccessedTimeChanged = false;
|
||||
this.sessionIdChanged = false;
|
||||
this.maxInactiveIntervalChanged = false;
|
||||
this.delta.clear();
|
||||
}
|
||||
|
||||
private void flushImmediateIfNecessary() {
|
||||
if (HazelcastSessionRepository.this.hazelcastFlushMode == HazelcastFlushMode.IMMEDIATE) {
|
||||
HazelcastSessionRepository.this.save(this);
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2014-2018 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.hazelcast;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.hazelcast.map.AbstractEntryProcessor;
|
||||
import com.hazelcast.map.EntryProcessor;
|
||||
|
||||
import org.springframework.session.MapSession;
|
||||
|
||||
/**
|
||||
* Hazelcast {@link EntryProcessor} responsible for handling updates to session.
|
||||
*
|
||||
* @author Vedran Pavic
|
||||
* @since 1.3.4
|
||||
* @see HazelcastSessionRepository#save(HazelcastSessionRepository.HazelcastSession)
|
||||
*/
|
||||
public class SessionUpdateEntryProcessor
|
||||
extends AbstractEntryProcessor<String, MapSession> {
|
||||
|
||||
private long lastAccessedTime;
|
||||
|
||||
private boolean lastAccessedTimeSet;
|
||||
|
||||
private int maxInactiveInterval;
|
||||
|
||||
private boolean maxInactiveIntervalSet;
|
||||
|
||||
private Map<String, Object> delta;
|
||||
|
||||
public Object process(Map.Entry<String, MapSession> entry) {
|
||||
MapSession value = entry.getValue();
|
||||
if (value == null) {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
if (this.lastAccessedTimeSet) {
|
||||
value.setLastAccessedTime(this.lastAccessedTime);
|
||||
}
|
||||
if (this.maxInactiveIntervalSet) {
|
||||
value.setMaxInactiveIntervalInSeconds(this.maxInactiveInterval);
|
||||
}
|
||||
if (this.delta != null) {
|
||||
for (final Map.Entry<String, Object> attribute : this.delta.entrySet()) {
|
||||
if (attribute.getValue() != null) {
|
||||
value.setAttribute(attribute.getKey(), attribute.getValue());
|
||||
}
|
||||
else {
|
||||
value.removeAttribute(attribute.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
entry.setValue(value);
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
void setLastAccessedTime(long lastAccessedTime) {
|
||||
this.lastAccessedTime = lastAccessedTime;
|
||||
this.lastAccessedTimeSet = true;
|
||||
}
|
||||
|
||||
void setMaxInactiveInterval(int maxInactiveInterval) {
|
||||
this.maxInactiveInterval = maxInactiveInterval;
|
||||
this.maxInactiveIntervalSet = true;
|
||||
}
|
||||
|
||||
void setDelta(Map<String, Object> delta) {
|
||||
this.delta = delta;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -105,6 +105,7 @@ import org.springframework.util.StringUtils;
|
||||
* );
|
||||
*
|
||||
* CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME);
|
||||
* CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (PRINCIPAL_NAME);
|
||||
*
|
||||
* CREATE TABLE SPRING_SESSION_ATTRIBUTES (
|
||||
* SESSION_ID CHAR(36),
|
||||
@@ -142,7 +143,9 @@ public class JdbcOperationsSessionRepository implements
|
||||
|
||||
private static final String CREATE_SESSION_ATTRIBUTE_QUERY =
|
||||
"INSERT INTO %TABLE_NAME%_ATTRIBUTES(SESSION_ID, ATTRIBUTE_NAME, ATTRIBUTE_BYTES) " +
|
||||
"VALUES (?, ?, ?)";
|
||||
"SELECT SESSION_ID, ?, ? " +
|
||||
"FROM %TABLE_NAME% " +
|
||||
"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 " +
|
||||
@@ -187,8 +190,7 @@ public class JdbcOperationsSessionRepository implements
|
||||
|
||||
private final TransactionOperations transactionOperations;
|
||||
|
||||
private final ResultSetExtractor<List<ExpiringSession>> extractor =
|
||||
new ExpiringSessionResultSetExtractor();
|
||||
private final ResultSetExtractor<List<JdbcSession>> extractor = new SessionResultSetExtractor();
|
||||
|
||||
/**
|
||||
* The name of database table used by Spring Session to store sessions.
|
||||
@@ -398,9 +400,9 @@ public class JdbcOperationsSessionRepository implements
|
||||
|
||||
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));
|
||||
ps.setString(1, attributeName);
|
||||
serialize(ps, 2, session.getAttribute(attributeName));
|
||||
ps.setString(3, session.getId());
|
||||
}
|
||||
|
||||
public int getBatchSize() {
|
||||
@@ -465,9 +467,9 @@ public class JdbcOperationsSessionRepository implements
|
||||
new PreparedStatementSetter() {
|
||||
|
||||
public void setValues(PreparedStatement ps) throws SQLException {
|
||||
ps.setString(1, session.getId());
|
||||
ps.setString(2, entry.getKey());
|
||||
serialize(ps, 3, entry.getValue());
|
||||
ps.setString(1, entry.getKey());
|
||||
serialize(ps, 2, entry.getValue());
|
||||
ps.setString(3, session.getId());
|
||||
}
|
||||
|
||||
});
|
||||
@@ -483,10 +485,10 @@ public class JdbcOperationsSessionRepository implements
|
||||
}
|
||||
|
||||
public JdbcSession getSession(final String id) {
|
||||
final ExpiringSession session = this.transactionOperations.execute(new TransactionCallback<ExpiringSession>() {
|
||||
final JdbcSession session = this.transactionOperations.execute(new TransactionCallback<JdbcSession>() {
|
||||
|
||||
public ExpiringSession doInTransaction(TransactionStatus status) {
|
||||
List<ExpiringSession> sessions = JdbcOperationsSessionRepository.this.jdbcOperations.query(
|
||||
public JdbcSession doInTransaction(TransactionStatus status) {
|
||||
List<JdbcSession> sessions = JdbcOperationsSessionRepository.this.jdbcOperations.query(
|
||||
JdbcOperationsSessionRepository.this.getSessionQuery,
|
||||
new PreparedStatementSetter() {
|
||||
|
||||
@@ -510,7 +512,7 @@ public class JdbcOperationsSessionRepository implements
|
||||
delete(id);
|
||||
}
|
||||
else {
|
||||
return new JdbcSession(session);
|
||||
return session;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -533,9 +535,9 @@ public class JdbcOperationsSessionRepository implements
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
List<ExpiringSession> sessions = this.transactionOperations.execute(new TransactionCallback<List<ExpiringSession>>() {
|
||||
List<JdbcSession> sessions = this.transactionOperations.execute(new TransactionCallback<List<JdbcSession>>() {
|
||||
|
||||
public List<ExpiringSession> doInTransaction(TransactionStatus status) {
|
||||
public List<JdbcSession> doInTransaction(TransactionStatus status) {
|
||||
return JdbcOperationsSessionRepository.this.jdbcOperations.query(
|
||||
JdbcOperationsSessionRepository.this.listSessionsByPrincipalNameQuery,
|
||||
new PreparedStatementSetter() {
|
||||
@@ -554,8 +556,8 @@ public class JdbcOperationsSessionRepository implements
|
||||
Map<String, JdbcSession> sessionMap = new HashMap<String, JdbcSession>(
|
||||
sessions.size());
|
||||
|
||||
for (ExpiringSession session : sessions) {
|
||||
sessionMap.put(session.getId(), new JdbcSession(session));
|
||||
for (JdbcSession session : sessions) {
|
||||
sessionMap.put(session.getId(), session);
|
||||
}
|
||||
|
||||
return sessionMap;
|
||||
@@ -763,33 +765,33 @@ public class JdbcOperationsSessionRepository implements
|
||||
|
||||
}
|
||||
|
||||
private class ExpiringSessionResultSetExtractor
|
||||
implements ResultSetExtractor<List<ExpiringSession>> {
|
||||
private class SessionResultSetExtractor implements ResultSetExtractor<List<JdbcSession>> {
|
||||
|
||||
public List<ExpiringSession> extractData(ResultSet rs) throws SQLException, DataAccessException {
|
||||
List<ExpiringSession> sessions = new ArrayList<ExpiringSession>();
|
||||
public List<JdbcSession> extractData(ResultSet rs) throws SQLException, DataAccessException {
|
||||
List<JdbcSession> sessions = new ArrayList<JdbcSession>();
|
||||
while (rs.next()) {
|
||||
String id = rs.getString("SESSION_ID");
|
||||
MapSession session;
|
||||
JdbcSession session;
|
||||
if (sessions.size() > 0 && getLast(sessions).getId().equals(id)) {
|
||||
session = (MapSession) getLast(sessions);
|
||||
session = getLast(sessions);
|
||||
}
|
||||
else {
|
||||
session = new MapSession(id);
|
||||
session.setCreationTime(rs.getLong("CREATION_TIME"));
|
||||
session.setLastAccessedTime(rs.getLong("LAST_ACCESS_TIME"));
|
||||
session.setMaxInactiveIntervalInSeconds(rs.getInt("MAX_INACTIVE_INTERVAL"));
|
||||
MapSession delegate = new MapSession(id);
|
||||
delegate.setCreationTime(rs.getLong("CREATION_TIME"));
|
||||
delegate.setLastAccessedTime(rs.getLong("LAST_ACCESS_TIME"));
|
||||
delegate.setMaxInactiveIntervalInSeconds(rs.getInt("MAX_INACTIVE_INTERVAL"));
|
||||
session = new JdbcSession(delegate);
|
||||
}
|
||||
String attributeName = rs.getString("ATTRIBUTE_NAME");
|
||||
if (attributeName != null) {
|
||||
session.setAttribute(attributeName, deserialize(rs, "ATTRIBUTE_BYTES"));
|
||||
session.delegate.setAttribute(attributeName, deserialize(rs, "ATTRIBUTE_BYTES"));
|
||||
}
|
||||
sessions.add(session);
|
||||
}
|
||||
return sessions;
|
||||
}
|
||||
|
||||
private ExpiringSession getLast(List<ExpiringSession> sessions) {
|
||||
private JdbcSession getLast(List<JdbcSession> sessions) {
|
||||
return sessions.get(sessions.size() - 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -33,8 +33,10 @@ import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.core.serializer.support.DeserializingConverter;
|
||||
import org.springframework.core.serializer.support.SerializingConverter;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.jdbc.core.JdbcOperations;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
import org.springframework.jdbc.support.MetaDataAccessException;
|
||||
import org.springframework.jdbc.support.lob.DefaultLobHandler;
|
||||
import org.springframework.jdbc.support.lob.LobHandler;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration;
|
||||
@@ -85,7 +87,7 @@ public class JdbcHttpSessionConfiguration extends SpringHttpSessionConfiguration
|
||||
|
||||
@Bean
|
||||
public JdbcOperationsSessionRepository sessionRepository(
|
||||
@Qualifier("springSessionJdbcOperations") JdbcOperations jdbcOperations,
|
||||
@Qualifier("springSessionJdbcOperations") JdbcTemplate jdbcOperations,
|
||||
PlatformTransactionManager transactionManager) {
|
||||
JdbcOperationsSessionRepository sessionRepository =
|
||||
new JdbcOperationsSessionRepository(jdbcOperations, transactionManager);
|
||||
@@ -98,6 +100,11 @@ public class JdbcHttpSessionConfiguration extends SpringHttpSessionConfiguration
|
||||
if (this.lobHandler != null) {
|
||||
sessionRepository.setLobHandler(this.lobHandler);
|
||||
}
|
||||
else if (requiresTemporaryLob(jdbcOperations.getDataSource())) {
|
||||
DefaultLobHandler lobHandler = new DefaultLobHandler();
|
||||
lobHandler.setCreateTemporaryLob(true);
|
||||
sessionRepository.setLobHandler(lobHandler);
|
||||
}
|
||||
if (this.springSessionConversionService != null) {
|
||||
sessionRepository.setConversionService(this.springSessionConversionService);
|
||||
}
|
||||
@@ -111,11 +118,22 @@ public class JdbcHttpSessionConfiguration extends SpringHttpSessionConfiguration
|
||||
return sessionRepository;
|
||||
}
|
||||
|
||||
private static boolean requiresTemporaryLob(DataSource dataSource) {
|
||||
try {
|
||||
String productName = (String) JdbcUtils.extractDatabaseMetaData(dataSource,
|
||||
"getDatabaseProductName");
|
||||
return "Oracle".equalsIgnoreCase(JdbcUtils.commonDatabaseName(productName));
|
||||
}
|
||||
catch (MetaDataAccessException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This must be a separate method because some ClassLoaders load the entire method
|
||||
* definition even if an if statement guards against it loading. This means that older
|
||||
* versions of Spring would cause a NoSuchMethodError if this were defined in
|
||||
* {@link #sessionRepository(JdbcOperations, PlatformTransactionManager)}.
|
||||
* {@link #sessionRepository(JdbcTemplate, PlatformTransactionManager)}.
|
||||
*
|
||||
* @return the default {@link ConversionService}
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -250,18 +250,18 @@ public final class CookieHttpSessionStrategy
|
||||
return sessionIds.values().iterator().next();
|
||||
}
|
||||
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Map.Entry<String, String> entry : sessionIds.entrySet()) {
|
||||
String alias = entry.getKey();
|
||||
String id = entry.getValue();
|
||||
|
||||
buffer.append(alias);
|
||||
buffer.append(this.serializationDelimiter);
|
||||
buffer.append(id);
|
||||
buffer.append(this.serializationDelimiter);
|
||||
sb.append(alias);
|
||||
sb.append(this.serializationDelimiter);
|
||||
sb.append(id);
|
||||
sb.append(this.serializationDelimiter);
|
||||
}
|
||||
buffer.deleteCharAt(buffer.length() - 1);
|
||||
return buffer.toString();
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void onInvalidateSession(HttpServletRequest request,
|
||||
|
||||
@@ -26,6 +26,9 @@ import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* The default implementation of {@link CookieSerializer}.
|
||||
*
|
||||
@@ -35,6 +38,8 @@ import javax.servlet.http.HttpServletResponse;
|
||||
*/
|
||||
public class DefaultCookieSerializer implements CookieSerializer {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(DefaultCookieSerializer.class);
|
||||
|
||||
private String cookieName = "SESSION";
|
||||
|
||||
private Boolean useSecureCookie;
|
||||
@@ -138,6 +143,7 @@ public class DefaultCookieSerializer implements CookieSerializer {
|
||||
return new String(decodedCookieBytes);
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.debug("Unable to Base64 decode value: " + base64Value);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,8 +22,11 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
@@ -48,7 +51,7 @@ import org.springframework.session.SessionRepository;
|
||||
* {@link org.springframework.session.SessionRepository}.
|
||||
*
|
||||
* The {@link SessionRepositoryFilter} uses a {@link HttpSessionStrategy} (default
|
||||
* {@link CookieHttpSessionStrategy} to bridge logic between an
|
||||
* {@link CookieHttpSessionStrategy}) to bridge logic between an
|
||||
* {@link javax.servlet.http.HttpSession} and the
|
||||
* {@link org.springframework.session.Session} abstraction. Specifically:
|
||||
*
|
||||
@@ -72,6 +75,7 @@ import org.springframework.session.SessionRepository;
|
||||
* @param <S> the {@link ExpiringSession} type.
|
||||
* @since 1.0
|
||||
* @author Rob Winch
|
||||
* @author Josh Cummings
|
||||
*/
|
||||
@Order(SessionRepositoryFilter.DEFAULT_ORDER)
|
||||
public class SessionRepositoryFilter<S extends ExpiringSession>
|
||||
@@ -289,9 +293,10 @@ public class SessionRepositoryFilter<S extends ExpiringSession>
|
||||
setCurrentSession(null);
|
||||
|
||||
HttpSessionWrapper newSession = getSession();
|
||||
int originalMaxInactiveInterval = session.getMaxInactiveInterval();
|
||||
original.setSession(newSession.getSession());
|
||||
|
||||
newSession.setMaxInactiveInterval(session.getMaxInactiveInterval());
|
||||
newSession.setMaxInactiveInterval(originalMaxInactiveInterval);
|
||||
for (Map.Entry<String, Object> attr : attrs.entrySet()) {
|
||||
String attrName = attr.getKey();
|
||||
Object attrValue = attr.getValue();
|
||||
@@ -396,6 +401,12 @@ public class SessionRepositoryFilter<S extends ExpiringSession>
|
||||
.getRequestedSessionId(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestDispatcher getRequestDispatcher(String path) {
|
||||
RequestDispatcher requestDispatcher = super.getRequestDispatcher(path);
|
||||
return new SessionCommittingRequestDispatcher(requestDispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows creating an HttpSession from a Session instance.
|
||||
*
|
||||
@@ -416,6 +427,34 @@ public class SessionRepositoryFilter<S extends ExpiringSession>
|
||||
SessionRepositoryFilter.this.sessionRepository.delete(getId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures session is committed before issuing an include.
|
||||
*
|
||||
* @since 1.3.4
|
||||
*/
|
||||
private final class SessionCommittingRequestDispatcher
|
||||
implements RequestDispatcher {
|
||||
|
||||
private final RequestDispatcher delegate;
|
||||
|
||||
SessionCommittingRequestDispatcher(RequestDispatcher delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public void forward(ServletRequest request, ServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
this.delegate.forward(request, response);
|
||||
}
|
||||
|
||||
public void include(ServletRequest request, ServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
SessionRepositoryRequestWrapper.this.commitSession();
|
||||
this.delegate.include(request, response);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,6 +8,7 @@ CREATE TABLE SPRING_SESSION (
|
||||
);
|
||||
|
||||
CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME);
|
||||
CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (PRINCIPAL_NAME);
|
||||
|
||||
CREATE TABLE SPRING_SESSION_ATTRIBUTES (
|
||||
SESSION_ID CHAR(36) NOT NULL,
|
||||
|
||||
@@ -8,6 +8,7 @@ CREATE TABLE SPRING_SESSION (
|
||||
);
|
||||
|
||||
CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME);
|
||||
CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (PRINCIPAL_NAME);
|
||||
|
||||
CREATE TABLE SPRING_SESSION_ATTRIBUTES (
|
||||
SESSION_ID CHAR(36) NOT NULL,
|
||||
|
||||
@@ -8,6 +8,7 @@ CREATE TABLE SPRING_SESSION (
|
||||
);
|
||||
|
||||
CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME);
|
||||
CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (PRINCIPAL_NAME);
|
||||
|
||||
CREATE TABLE SPRING_SESSION_ATTRIBUTES (
|
||||
SESSION_ID CHAR(36) NOT NULL,
|
||||
|
||||
@@ -8,6 +8,7 @@ CREATE TABLE SPRING_SESSION (
|
||||
);
|
||||
|
||||
CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME);
|
||||
CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (PRINCIPAL_NAME);
|
||||
|
||||
CREATE TABLE SPRING_SESSION_ATTRIBUTES (
|
||||
SESSION_ID CHAR(36) NOT NULL,
|
||||
|
||||
@@ -8,6 +8,7 @@ CREATE TABLE SPRING_SESSION (
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME);
|
||||
CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (PRINCIPAL_NAME);
|
||||
|
||||
CREATE TABLE SPRING_SESSION_ATTRIBUTES (
|
||||
SESSION_ID CHAR(36) NOT NULL,
|
||||
|
||||
@@ -8,6 +8,7 @@ CREATE TABLE SPRING_SESSION (
|
||||
);
|
||||
|
||||
CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME);
|
||||
CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (PRINCIPAL_NAME);
|
||||
|
||||
CREATE TABLE SPRING_SESSION_ATTRIBUTES (
|
||||
SESSION_ID CHAR(36) NOT NULL,
|
||||
|
||||
@@ -8,6 +8,7 @@ CREATE TABLE SPRING_SESSION (
|
||||
);
|
||||
|
||||
CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME);
|
||||
CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (PRINCIPAL_NAME);
|
||||
|
||||
CREATE TABLE SPRING_SESSION_ATTRIBUTES (
|
||||
SESSION_ID CHAR(36) NOT NULL,
|
||||
|
||||
@@ -8,6 +8,7 @@ CREATE TABLE SPRING_SESSION (
|
||||
);
|
||||
|
||||
CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME);
|
||||
CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (PRINCIPAL_NAME);
|
||||
|
||||
CREATE TABLE SPRING_SESSION_ATTRIBUTES (
|
||||
SESSION_ID CHAR(36) NOT NULL,
|
||||
|
||||
@@ -8,6 +8,7 @@ CREATE TABLE SPRING_SESSION (
|
||||
);
|
||||
|
||||
CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME);
|
||||
CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (PRINCIPAL_NAME);
|
||||
|
||||
CREATE TABLE SPRING_SESSION_ATTRIBUTES (
|
||||
SESSION_ID CHAR(36) NOT NULL,
|
||||
|
||||
@@ -8,6 +8,7 @@ CREATE TABLE SPRING_SESSION (
|
||||
) LOCK DATAROWS;
|
||||
|
||||
CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME);
|
||||
CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (PRINCIPAL_NAME);
|
||||
|
||||
CREATE TABLE SPRING_SESSION_ATTRIBUTES (
|
||||
SESSION_ID CHAR(36) NOT NULL,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -64,4 +64,18 @@ public class MapSessionRepositoryTests {
|
||||
assertThat(session.getMaxInactiveIntervalInSeconds())
|
||||
.isEqualTo(expectedMaxInterval);
|
||||
}
|
||||
|
||||
@Test // gh-1120
|
||||
public void getAttributeNamesAndRemove() {
|
||||
ExpiringSession session = this.repository.createSession();
|
||||
session.setAttribute("attribute1", "value1");
|
||||
session.setAttribute("attribute2", "value2");
|
||||
|
||||
for (String attributeName : session.getAttributeNames()) {
|
||||
session.removeAttribute(attributeName);
|
||||
}
|
||||
|
||||
assertThat(session.getAttributeNames()).isEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -85,6 +85,18 @@ public class MapSessionTests {
|
||||
assertThat(this.session.isExpired(now)).isTrue();
|
||||
}
|
||||
|
||||
@Test // gh-1120
|
||||
public void getAttributeNamesAndRemove() {
|
||||
this.session.setAttribute("attribute1", "value1");
|
||||
this.session.setAttribute("attribute2", "value2");
|
||||
|
||||
for (String attributeName : this.session.getAttributeNames()) {
|
||||
this.session.removeAttribute(attributeName);
|
||||
}
|
||||
|
||||
assertThat(this.session.getAttributeNames()).isEmpty();
|
||||
}
|
||||
|
||||
static class CustomSession implements ExpiringSession {
|
||||
|
||||
public long getCreationTime() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -59,6 +59,7 @@ import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyLong;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.reset;
|
||||
@@ -529,6 +530,104 @@ public class RedisOperationsSessionRepositoryTests {
|
||||
verify(this.defaultSerializer).deserialize(body);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onMessageDeletedSessionFound() throws Exception {
|
||||
String deletedId = "deleted-id";
|
||||
given(this.redisOperations.boundHashOps(getKey(deletedId)))
|
||||
.willReturn(this.boundHashOperations);
|
||||
Map map = map(RedisOperationsSessionRepository.MAX_INACTIVE_ATTR, 0,
|
||||
RedisOperationsSessionRepository.LAST_ACCESSED_ATTR,
|
||||
System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(5));
|
||||
given(this.boundHashOperations.entries()).willReturn(map);
|
||||
|
||||
String channel = "__keyevent@0__:del";
|
||||
String body = "spring:session:sessions:expires:" + deletedId;
|
||||
DefaultMessage message = new DefaultMessage(channel.getBytes("UTF-8"), body.getBytes("UTF-8"));
|
||||
|
||||
this.redisRepository.setApplicationEventPublisher(this.publisher);
|
||||
this.redisRepository.onMessage(message, "".getBytes("UTF-8"));
|
||||
|
||||
verify(this.redisOperations).boundHashOps(eq(getKey(deletedId)));
|
||||
verify(this.boundHashOperations).entries();
|
||||
verify(this.publisher).publishEvent(this.event.capture());
|
||||
assertThat(this.event.getValue().getSessionId()).isEqualTo(deletedId);
|
||||
verifyZeroInteractions(this.defaultSerializer);
|
||||
verifyZeroInteractions(this.publisher);
|
||||
verifyZeroInteractions(this.redisOperations);
|
||||
verifyZeroInteractions(this.boundHashOperations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onMessageDeletedSessionNotFound() throws Exception {
|
||||
String deletedId = "deleted-id";
|
||||
given(this.redisOperations.boundHashOps(getKey(deletedId)))
|
||||
.willReturn(this.boundHashOperations);
|
||||
given(this.boundHashOperations.entries()).willReturn(map());
|
||||
|
||||
String channel = "__keyevent@0__:del";
|
||||
String body = "spring:session:sessions:expires:" + deletedId;
|
||||
DefaultMessage message = new DefaultMessage(channel.getBytes("UTF-8"), body.getBytes("UTF-8"));
|
||||
|
||||
this.redisRepository.setApplicationEventPublisher(this.publisher);
|
||||
this.redisRepository.onMessage(message, "".getBytes("UTF-8"));
|
||||
|
||||
verify(this.redisOperations).boundHashOps(eq(getKey(deletedId)));
|
||||
verify(this.boundHashOperations).entries();
|
||||
verifyZeroInteractions(this.defaultSerializer);
|
||||
verifyZeroInteractions(this.publisher);
|
||||
verifyZeroInteractions(this.redisOperations);
|
||||
verifyZeroInteractions(this.boundHashOperations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onMessageExpiredSessionFound() throws Exception {
|
||||
String expiredId = "expired-id";
|
||||
given(this.redisOperations.boundHashOps(getKey(expiredId)))
|
||||
.willReturn(this.boundHashOperations);
|
||||
Map map = map(RedisOperationsSessionRepository.MAX_INACTIVE_ATTR, 1,
|
||||
RedisOperationsSessionRepository.LAST_ACCESSED_ATTR,
|
||||
System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(5));
|
||||
given(this.boundHashOperations.entries()).willReturn(map);
|
||||
|
||||
String channel = "__keyevent@0__:expired";
|
||||
String body = "spring:session:sessions:expires:" + expiredId;
|
||||
DefaultMessage message = new DefaultMessage(channel.getBytes("UTF-8"), body.getBytes("UTF-8"));
|
||||
|
||||
this.redisRepository.setApplicationEventPublisher(this.publisher);
|
||||
this.redisRepository.onMessage(message, "".getBytes("UTF-8"));
|
||||
|
||||
verify(this.redisOperations).boundHashOps(eq(getKey(expiredId)));
|
||||
verify(this.boundHashOperations).entries();
|
||||
verify(this.publisher).publishEvent(this.event.capture());
|
||||
assertThat(this.event.getValue().getSessionId()).isEqualTo(expiredId);
|
||||
verifyZeroInteractions(this.defaultSerializer);
|
||||
verifyZeroInteractions(this.publisher);
|
||||
verifyZeroInteractions(this.redisOperations);
|
||||
verifyZeroInteractions(this.boundHashOperations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onMessageExpiredSessionNotFound() throws Exception {
|
||||
String expiredId = "expired-id";
|
||||
given(this.redisOperations.boundHashOps(getKey(expiredId)))
|
||||
.willReturn(this.boundHashOperations);
|
||||
given(this.boundHashOperations.entries()).willReturn(map());
|
||||
|
||||
String channel = "__keyevent@0__:expired";
|
||||
String body = "spring:session:sessions:expires:" + expiredId;
|
||||
DefaultMessage message = new DefaultMessage(channel.getBytes("UTF-8"), body.getBytes("UTF-8"));
|
||||
|
||||
this.redisRepository.setApplicationEventPublisher(this.publisher);
|
||||
this.redisRepository.onMessage(message, "".getBytes("UTF-8"));
|
||||
|
||||
verify(this.redisOperations).boundHashOps(eq(getKey(expiredId)));
|
||||
verify(this.boundHashOperations).entries();
|
||||
verifyZeroInteractions(this.defaultSerializer);
|
||||
verifyZeroInteractions(this.publisher);
|
||||
verifyZeroInteractions(this.redisOperations);
|
||||
verifyZeroInteractions(this.boundHashOperations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolvePrincipalIndex() {
|
||||
PrincipalNameResolver resolver = RedisOperationsSessionRepository.PRINCIPAL_NAME_RESOLVER;
|
||||
@@ -706,6 +805,19 @@ public class RedisOperationsSessionRepositoryTests {
|
||||
this.redisRepository.setRedisFlushMode(null);
|
||||
}
|
||||
|
||||
@Test // gh-1120
|
||||
public void getAttributeNamesAndRemove() {
|
||||
RedisSession session = this.redisRepository.new RedisSession(this.cached);
|
||||
session.setAttribute("attribute1", "value1");
|
||||
session.setAttribute("attribute2", "value2");
|
||||
|
||||
for (String attributeName : session.getAttributeNames()) {
|
||||
session.removeAttribute(attributeName);
|
||||
}
|
||||
|
||||
assertThat(session.getAttributeNames()).isEmpty();
|
||||
}
|
||||
|
||||
private String getKey(String id) {
|
||||
return "spring:session:sessions:" + id;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,6 +22,7 @@ import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.hazelcast.core.IMap;
|
||||
import com.hazelcast.map.EntryProcessor;
|
||||
import com.hazelcast.query.impl.predicates.EqualPredicate;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
@@ -40,6 +41,7 @@ import org.springframework.session.hazelcast.HazelcastSessionRepository.Hazelcas
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Matchers.isA;
|
||||
import static org.mockito.Mockito.times;
|
||||
@@ -104,8 +106,8 @@ public class HazelcastSessionRepositoryTests {
|
||||
verifyZeroInteractions(this.sessions);
|
||||
|
||||
this.repository.save(session);
|
||||
verify(this.sessions, times(1)).put(eq(session.getId()), eq(session.getDelegate()),
|
||||
isA(Long.class), eq(TimeUnit.SECONDS));
|
||||
verify(this.sessions, times(1)).set(eq(session.getId()),
|
||||
eq(session.getDelegate()), isA(Long.class), eq(TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -113,8 +115,8 @@ public class HazelcastSessionRepositoryTests {
|
||||
this.repository.setHazelcastFlushMode(HazelcastFlushMode.IMMEDIATE);
|
||||
|
||||
HazelcastSession session = this.repository.createSession();
|
||||
verify(this.sessions, times(1)).put(eq(session.getId()), eq(session.getDelegate()),
|
||||
isA(Long.class), eq(TimeUnit.SECONDS));
|
||||
verify(this.sessions, times(1)).set(eq(session.getId()),
|
||||
eq(session.getDelegate()), isA(Long.class), eq(TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -124,8 +126,8 @@ public class HazelcastSessionRepositoryTests {
|
||||
verifyZeroInteractions(this.sessions);
|
||||
|
||||
this.repository.save(session);
|
||||
verify(this.sessions, times(1)).put(eq(session.getId()), eq(session.getDelegate()),
|
||||
isA(Long.class), eq(TimeUnit.SECONDS));
|
||||
verify(this.sessions, times(1)).set(eq(session.getId()),
|
||||
eq(session.getDelegate()), isA(Long.class), eq(TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -134,8 +136,10 @@ public class HazelcastSessionRepositoryTests {
|
||||
|
||||
HazelcastSession session = this.repository.createSession();
|
||||
session.setAttribute("testName", "testValue");
|
||||
verify(this.sessions, times(2)).put(eq(session.getId()), eq(session.getDelegate()),
|
||||
isA(Long.class), eq(TimeUnit.SECONDS));
|
||||
verify(this.sessions, times(1)).set(eq(session.getId()),
|
||||
eq(session.getDelegate()), isA(Long.class), eq(TimeUnit.SECONDS));
|
||||
verify(this.sessions, times(1)).executeOnKey(eq(session.getId()),
|
||||
any(EntryProcessor.class));
|
||||
|
||||
this.repository.save(session);
|
||||
verifyZeroInteractions(this.sessions);
|
||||
@@ -148,8 +152,8 @@ public class HazelcastSessionRepositoryTests {
|
||||
verifyZeroInteractions(this.sessions);
|
||||
|
||||
this.repository.save(session);
|
||||
verify(this.sessions, times(1)).put(eq(session.getId()), eq(session.getDelegate()),
|
||||
isA(Long.class), eq(TimeUnit.SECONDS));
|
||||
verify(this.sessions, times(1)).set(eq(session.getId()),
|
||||
eq(session.getDelegate()), isA(Long.class), eq(TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -158,8 +162,10 @@ public class HazelcastSessionRepositoryTests {
|
||||
|
||||
HazelcastSession session = this.repository.createSession();
|
||||
session.removeAttribute("testName");
|
||||
verify(this.sessions, times(2)).put(eq(session.getId()), eq(session.getDelegate()),
|
||||
isA(Long.class), eq(TimeUnit.SECONDS));
|
||||
verify(this.sessions, times(1)).set(eq(session.getId()),
|
||||
eq(session.getDelegate()), isA(Long.class), eq(TimeUnit.SECONDS));
|
||||
verify(this.sessions, times(1)).executeOnKey(eq(session.getId()),
|
||||
any(EntryProcessor.class));
|
||||
|
||||
this.repository.save(session);
|
||||
verifyZeroInteractions(this.sessions);
|
||||
@@ -172,8 +178,8 @@ public class HazelcastSessionRepositoryTests {
|
||||
verifyZeroInteractions(this.sessions);
|
||||
|
||||
this.repository.save(session);
|
||||
verify(this.sessions, times(1)).put(eq(session.getId()), eq(session.getDelegate()),
|
||||
isA(Long.class), eq(TimeUnit.SECONDS));
|
||||
verify(this.sessions, times(1)).set(eq(session.getId()),
|
||||
eq(session.getDelegate()), isA(Long.class), eq(TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -182,8 +188,10 @@ public class HazelcastSessionRepositoryTests {
|
||||
|
||||
HazelcastSession session = this.repository.createSession();
|
||||
session.setLastAccessedTime(System.currentTimeMillis());
|
||||
verify(this.sessions, times(2)).put(eq(session.getId()), eq(session.getDelegate()),
|
||||
isA(Long.class), eq(TimeUnit.SECONDS));
|
||||
verify(this.sessions, times(1)).set(eq(session.getId()),
|
||||
eq(session.getDelegate()), isA(Long.class), eq(TimeUnit.SECONDS));
|
||||
verify(this.sessions, times(1)).executeOnKey(eq(session.getId()),
|
||||
any(EntryProcessor.class));
|
||||
|
||||
this.repository.save(session);
|
||||
verifyZeroInteractions(this.sessions);
|
||||
@@ -196,8 +204,8 @@ public class HazelcastSessionRepositoryTests {
|
||||
verifyZeroInteractions(this.sessions);
|
||||
|
||||
this.repository.save(session);
|
||||
verify(this.sessions, times(1)).put(eq(session.getId()), eq(session.getDelegate()),
|
||||
isA(Long.class), eq(TimeUnit.SECONDS));
|
||||
verify(this.sessions, times(1)).set(eq(session.getId()),
|
||||
eq(session.getDelegate()), isA(Long.class), eq(TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -206,8 +214,10 @@ public class HazelcastSessionRepositoryTests {
|
||||
|
||||
HazelcastSession session = this.repository.createSession();
|
||||
session.setMaxInactiveIntervalInSeconds(1);
|
||||
verify(this.sessions, times(2)).put(eq(session.getId()), eq(session.getDelegate()),
|
||||
isA(Long.class), eq(TimeUnit.SECONDS));
|
||||
verify(this.sessions, times(1)).set(eq(session.getId()),
|
||||
eq(session.getDelegate()), isA(Long.class), eq(TimeUnit.SECONDS));
|
||||
verify(this.sessions, times(1)).executeOnKey(eq(session.getId()),
|
||||
any(EntryProcessor.class));
|
||||
|
||||
this.repository.save(session);
|
||||
verifyZeroInteractions(this.sessions);
|
||||
@@ -217,8 +227,8 @@ public class HazelcastSessionRepositoryTests {
|
||||
public void saveUnchangedFlushModeOnSave() {
|
||||
HazelcastSession session = this.repository.createSession();
|
||||
this.repository.save(session);
|
||||
verify(this.sessions, times(1)).put(eq(session.getId()), eq(session.getDelegate()),
|
||||
isA(Long.class), eq(TimeUnit.SECONDS));
|
||||
verify(this.sessions, times(1)).set(eq(session.getId()),
|
||||
eq(session.getDelegate()), isA(Long.class), eq(TimeUnit.SECONDS));
|
||||
|
||||
this.repository.save(session);
|
||||
verifyZeroInteractions(this.sessions);
|
||||
@@ -229,8 +239,8 @@ public class HazelcastSessionRepositoryTests {
|
||||
this.repository.setHazelcastFlushMode(HazelcastFlushMode.IMMEDIATE);
|
||||
|
||||
HazelcastSession session = this.repository.createSession();
|
||||
verify(this.sessions, times(1)).put(eq(session.getId()), eq(session.getDelegate()),
|
||||
isA(Long.class), eq(TimeUnit.SECONDS));
|
||||
verify(this.sessions, times(1)).set(eq(session.getId()),
|
||||
eq(session.getDelegate()), isA(Long.class), eq(TimeUnit.SECONDS));
|
||||
|
||||
this.repository.save(session);
|
||||
verifyZeroInteractions(this.sessions);
|
||||
@@ -249,8 +259,8 @@ public class HazelcastSessionRepositoryTests {
|
||||
@Test
|
||||
public void getSessionExpired() {
|
||||
MapSession expired = new MapSession();
|
||||
expired.setLastAccessedTime(System.currentTimeMillis() -
|
||||
(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS * 1000 + 1000));
|
||||
expired.setLastAccessedTime(System.currentTimeMillis()
|
||||
- (MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS * 1000 + 1000));
|
||||
given(this.sessions.get(eq(expired.getId()))).willReturn(expired);
|
||||
|
||||
HazelcastSession session = this.repository.getSession(expired.getId());
|
||||
@@ -286,8 +296,8 @@ public class HazelcastSessionRepositoryTests {
|
||||
public void findByIndexNameAndIndexValueUnknownIndexName() {
|
||||
String indexValue = "testIndexValue";
|
||||
|
||||
Map<String, HazelcastSession> sessions = this.repository.findByIndexNameAndIndexValue(
|
||||
"testIndexName", indexValue);
|
||||
Map<String, HazelcastSession> sessions = this.repository
|
||||
.findByIndexNameAndIndexValue("testIndexName", indexValue);
|
||||
|
||||
assertThat(sessions).isEmpty();
|
||||
verifyZeroInteractions(this.sessions);
|
||||
@@ -297,8 +307,10 @@ public class HazelcastSessionRepositoryTests {
|
||||
public void findByIndexNameAndIndexValuePrincipalIndexNameNotFound() {
|
||||
String principal = "username";
|
||||
|
||||
Map<String, HazelcastSession> sessions = this.repository.findByIndexNameAndIndexValue(
|
||||
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, principal);
|
||||
Map<String, HazelcastSession> sessions = this.repository
|
||||
.findByIndexNameAndIndexValue(
|
||||
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME,
|
||||
principal);
|
||||
|
||||
assertThat(sessions).isEmpty();
|
||||
verify(this.sessions, times(1)).values(isA(EqualPredicate.class));
|
||||
@@ -318,11 +330,26 @@ public class HazelcastSessionRepositoryTests {
|
||||
saved.add(saved2);
|
||||
given(this.sessions.values(isA(EqualPredicate.class))).willReturn(saved);
|
||||
|
||||
Map<String, HazelcastSession> sessions = this.repository.findByIndexNameAndIndexValue(
|
||||
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, principal);
|
||||
Map<String, HazelcastSession> sessions = this.repository
|
||||
.findByIndexNameAndIndexValue(
|
||||
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME,
|
||||
principal);
|
||||
|
||||
assertThat(sessions).hasSize(2);
|
||||
verify(this.sessions, times(1)).values(isA(EqualPredicate.class));
|
||||
}
|
||||
|
||||
@Test // gh-1120
|
||||
public void getAttributeNamesAndRemove() {
|
||||
HazelcastSession session = this.repository.createSession();
|
||||
session.setAttribute("attribute1", "value1");
|
||||
session.setAttribute("attribute2", "value2");
|
||||
|
||||
for (String attributeName : session.getAttributeNames()) {
|
||||
session.removeAttribute(attributeName);
|
||||
}
|
||||
|
||||
assertThat(session.getAttributeNames()).isEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -412,7 +412,7 @@ public class JdbcOperationsSessionRepositoryTests {
|
||||
|
||||
@Test
|
||||
public void getSessionExpired() {
|
||||
MapSession expired = new MapSession();
|
||||
JdbcOperationsSessionRepository.JdbcSession expired = this.repository.new JdbcSession();
|
||||
expired.setLastAccessedTime(System.currentTimeMillis() -
|
||||
(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS * 1000 + 1000));
|
||||
given(this.jdbcOperations.query(isA(String.class),
|
||||
@@ -432,7 +432,8 @@ public class JdbcOperationsSessionRepositoryTests {
|
||||
|
||||
@Test
|
||||
public void getSessionFound() {
|
||||
MapSession saved = new MapSession();
|
||||
JdbcOperationsSessionRepository.JdbcSession saved = this.repository.new JdbcSession(
|
||||
new MapSession());
|
||||
saved.setAttribute("savedName", "savedValue");
|
||||
given(this.jdbcOperations.query(isA(String.class),
|
||||
isA(PreparedStatementSetter.class), isA(ResultSetExtractor.class)))
|
||||
@@ -493,11 +494,12 @@ public class JdbcOperationsSessionRepositoryTests {
|
||||
String principal = "username";
|
||||
Authentication authentication = new UsernamePasswordAuthenticationToken(principal,
|
||||
"notused", AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
List<MapSession> saved = new ArrayList<MapSession>(2);
|
||||
MapSession saved1 = new MapSession();
|
||||
List<JdbcOperationsSessionRepository.JdbcSession> saved =
|
||||
new ArrayList<JdbcOperationsSessionRepository.JdbcSession>(2);
|
||||
JdbcOperationsSessionRepository.JdbcSession saved1 = this.repository.new JdbcSession();
|
||||
saved1.setAttribute(SPRING_SECURITY_CONTEXT, authentication);
|
||||
saved.add(saved1);
|
||||
MapSession saved2 = new MapSession();
|
||||
JdbcOperationsSessionRepository.JdbcSession saved2 = this.repository.new JdbcSession();
|
||||
saved2.setAttribute(SPRING_SECURITY_CONTEXT, authentication);
|
||||
saved.add(saved2);
|
||||
given(this.jdbcOperations.query(isA(String.class),
|
||||
@@ -523,6 +525,19 @@ public class JdbcOperationsSessionRepositoryTests {
|
||||
verify(this.jdbcOperations, times(1)).update(startsWith("DELETE"), anyLong());
|
||||
}
|
||||
|
||||
@Test // gh-1120
|
||||
public void getAttributeNamesAndRemove() {
|
||||
JdbcOperationsSessionRepository.JdbcSession session = this.repository.createSession();
|
||||
session.setAttribute("attribute1", "value1");
|
||||
session.setAttribute("attribute2", "value2");
|
||||
|
||||
for (String attributeName : session.getAttributeNames()) {
|
||||
session.removeAttribute(attributeName);
|
||||
}
|
||||
|
||||
assertThat(session.getAttributeNames()).isEmpty();
|
||||
}
|
||||
|
||||
private void assertPropagationRequiresNew() {
|
||||
ArgumentCaptor<TransactionDefinition> argument =
|
||||
ArgumentCaptor.forClass(TransactionDefinition.class);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -710,19 +710,19 @@ public class CookieHttpSessionStrategyTests {
|
||||
}
|
||||
|
||||
private String createSessionCookieValue(long size) {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (long i = 0; i < size; i++) {
|
||||
String hex = Long.toHexString(i);
|
||||
buffer.append(hex);
|
||||
buffer.append(" ");
|
||||
buffer.append(i);
|
||||
sb.append(hex);
|
||||
sb.append(" ");
|
||||
sb.append(i);
|
||||
if (i < size - 1) {
|
||||
buffer.append(" ");
|
||||
sb.append(" ");
|
||||
}
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -568,6 +568,27 @@ public class SessionRepositoryFilterTests {
|
||||
});
|
||||
}
|
||||
|
||||
// gh-951
|
||||
@Test
|
||||
public void doFilterChangeSessionIdCopyAttributes() throws Exception {
|
||||
// change the session id
|
||||
doFilter(new DoInFilter() {
|
||||
@Override
|
||||
public void doFilter(HttpServletRequest wrappedRequest) {
|
||||
HttpSession session = wrappedRequest.getSession();
|
||||
session.setMaxInactiveInterval(300);
|
||||
String originalSessionId = session.getId();
|
||||
int originalMaxInactiveInterval = session.getMaxInactiveInterval();
|
||||
|
||||
String changeSessionId = ReflectionTestUtils.invokeMethod(wrappedRequest,
|
||||
"changeSessionId");
|
||||
assertThat(changeSessionId).isNotEqualTo(originalSessionId);
|
||||
assertThat(session.getMaxInactiveInterval())
|
||||
.isEqualTo(originalMaxInactiveInterval);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// gh-142, gh-153
|
||||
@Test
|
||||
public void doFilterIsRequestedValidSessionFalseInvalidId() throws Exception {
|
||||
@@ -1154,6 +1175,22 @@ public class SessionRepositoryFilterTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test // gh-1243
|
||||
public void doFilterInclude() throws Exception {
|
||||
doFilter(new DoInFilter() {
|
||||
@Override
|
||||
public void doFilter(HttpServletRequest wrappedRequest,
|
||||
HttpServletResponse wrappedResponse)
|
||||
throws IOException, ServletException {
|
||||
String id = wrappedRequest.getSession().getId();
|
||||
wrappedRequest.getRequestDispatcher("/").include(wrappedRequest,
|
||||
wrappedResponse);
|
||||
assertThat(SessionRepositoryFilterTests.this.sessionRepository
|
||||
.getSession(id)).isNotNull();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// --- MultiHttpSessionStrategyAdapter
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user