Compare commits
18 Commits
1.3.1.RELE
...
1.3.2.RELE
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e44cd45668 | ||
|
|
7f0de8126e | ||
|
|
d75b03f594 | ||
|
|
ca0fea3a54 | ||
|
|
92af786e6b | ||
|
|
d271a4ad1d | ||
|
|
04c1908378 | ||
|
|
f0e187fbd7 | ||
|
|
2d3001a24e | ||
|
|
f2d1badd60 | ||
|
|
6a6d60d8f8 | ||
|
|
b2cb3f6a3a | ||
|
|
d7ae5785eb | ||
|
|
96eb40439c | ||
|
|
8ed0999ad3 | ||
|
|
b2d2335d73 | ||
|
|
f597c5a824 | ||
|
|
212eca306c |
14
build.gradle
14
build.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,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
|
||||
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
|
||||
jstlelVersion=1.2.5
|
||||
version=1.3.2.RELEASE
|
||||
springDataRedisVersion=1.7.10.RELEASE
|
||||
# We cannot go beyond this version with Spring 3 support
|
||||
html5ShivVersion=3.7.3
|
||||
commonsLoggingVersion=1.2
|
||||
junitVersion=4.12
|
||||
springDataRedisSpring3Version=1.7.1.RELEASE
|
||||
lettuceVersion=3.5.0.Final
|
||||
gebVersion=0.13.1
|
||||
mockitoVersion=1.10.19
|
||||
hazelcastVersion=3.6.5
|
||||
seleniumVersion=2.52.0
|
||||
springDataGeodeVersion=1.0.0.INCUBATING-RELEASE
|
||||
springSecurityVersion=4.2.0.RELEASE
|
||||
springVersion=4.3.4.RELEASE
|
||||
httpClientVersion=4.5.1
|
||||
h2Version=1.4.192
|
||||
jedisVersion=2.8.1
|
||||
springDataMongoVersion=1.9.4.RELEASE
|
||||
springShellVersion=1.1.0.RELEASE
|
||||
springDataGemFireVersion=1.8.10.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.4
|
||||
|
||||
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" "$@"
|
||||
|
||||
@@ -16,7 +16,7 @@ group = 'samples'
|
||||
|
||||
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",
|
||||
|
||||
@@ -16,7 +16,7 @@ group = 'samples'
|
||||
|
||||
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",
|
||||
|
||||
@@ -10,12 +10,7 @@ buildscript {
|
||||
apply from: JAVA_GRADLE
|
||||
apply plugin: "application"
|
||||
apply plugin: 'org.springframework.boot'
|
||||
|
||||
tasks.findByPath("artifactoryPublish")?.enabled = false
|
||||
|
||||
sonarqube {
|
||||
skipProject = true
|
||||
}
|
||||
apply from: SAMPLE_GRADLE
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-session-data-gemfire'),
|
||||
@@ -44,24 +39,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'),
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -10,8 +10,7 @@ buildscript {
|
||||
apply plugin: 'org.springframework.boot'
|
||||
|
||||
apply from: JAVA_GRADLE
|
||||
|
||||
//tasks.findByPath("artifactoryPublish")?.enabled = false
|
||||
apply from: SAMPLE_GRADLE
|
||||
|
||||
group = 'samples'
|
||||
ext {
|
||||
@@ -23,7 +22,7 @@ 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 +65,4 @@ def reservePort() {
|
||||
def result = socket.localPort
|
||||
socket.close()
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -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,11 @@ public class RedisOperationsSessionRepository implements
|
||||
|
||||
RedisSession session = getSession(sessionId, true);
|
||||
|
||||
if (session == null) {
|
||||
logger.warn("Unable to publish SessionDestroyedEvent for session "
|
||||
+ sessionId);
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Publishing SessionDestroyedEvent for session " + sessionId);
|
||||
}
|
||||
@@ -525,10 +530,10 @@ public class RedisOperationsSessionRepository implements
|
||||
cleanupPrincipalIndex(session);
|
||||
|
||||
if (isDeleted) {
|
||||
handleDeleted(sessionId, session);
|
||||
handleDeleted(session);
|
||||
}
|
||||
else {
|
||||
handleExpired(sessionId, session);
|
||||
handleExpired(session);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -536,9 +541,6 @@ public class RedisOperationsSessionRepository implements
|
||||
}
|
||||
|
||||
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 +555,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.
|
||||
@@ -28,6 +28,8 @@ import javax.annotation.PreDestroy;
|
||||
|
||||
import com.hazelcast.core.EntryEvent;
|
||||
import com.hazelcast.core.IMap;
|
||||
import com.hazelcast.map.AbstractEntryProcessor;
|
||||
import com.hazelcast.map.EntryProcessor;
|
||||
import com.hazelcast.map.listener.EntryAddedListener;
|
||||
import com.hazelcast.map.listener.EntryEvictedListener;
|
||||
import com.hazelcast.map.listener.EntryRemovedListener;
|
||||
@@ -108,8 +110,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 +201,16 @@ 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.changed) {
|
||||
this.sessions.executeOnKey(session.getId(),
|
||||
new SessionUpdateEntryProcessor(session.getLastAccessedTime(),
|
||||
session.getMaxInactiveIntervalInSeconds(), session.delta));
|
||||
}
|
||||
session.clearFlags();
|
||||
}
|
||||
|
||||
public HazelcastSession getSession(String id) {
|
||||
@@ -223,13 +229,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,15 +276,20 @@ public class HazelcastSessionRepository implements
|
||||
final class HazelcastSession implements ExpiringSession {
|
||||
|
||||
private final MapSession delegate;
|
||||
|
||||
private boolean isNew;
|
||||
|
||||
private boolean changed;
|
||||
|
||||
private Map<String, Object> delta = new HashMap<String, Object>();
|
||||
|
||||
/**
|
||||
* Creates a new instance ensuring to mark all of the new attributes to be
|
||||
* persisted in the next save operation.
|
||||
*/
|
||||
HazelcastSession() {
|
||||
this(new MapSession());
|
||||
this.changed = true;
|
||||
this.isNew = true;
|
||||
flushImmediateIfNecessary();
|
||||
}
|
||||
|
||||
@@ -334,28 +345,28 @@ public class HazelcastSessionRepository implements
|
||||
|
||||
public void setAttribute(String attributeName, Object attributeValue) {
|
||||
this.delegate.setAttribute(attributeName, attributeValue);
|
||||
this.delta.put(attributeName, attributeValue);
|
||||
this.changed = true;
|
||||
flushImmediateIfNecessary();
|
||||
}
|
||||
|
||||
public void removeAttribute(String attributeName) {
|
||||
this.delegate.removeAttribute(attributeName);
|
||||
this.delta.put(attributeName, null);
|
||||
this.changed = true;
|
||||
flushImmediateIfNecessary();
|
||||
}
|
||||
|
||||
boolean isChanged() {
|
||||
return this.changed;
|
||||
}
|
||||
|
||||
void markUnchanged() {
|
||||
this.changed = false;
|
||||
}
|
||||
|
||||
MapSession getDelegate() {
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
void clearFlags() {
|
||||
this.isNew = false;
|
||||
this.changed = false;
|
||||
this.delta.clear();
|
||||
}
|
||||
|
||||
private void flushImmediateIfNecessary() {
|
||||
if (HazelcastSessionRepository.this.hazelcastFlushMode == HazelcastFlushMode.IMMEDIATE) {
|
||||
HazelcastSessionRepository.this.save(this);
|
||||
@@ -364,4 +375,44 @@ public class HazelcastSessionRepository implements
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Hazelcast {@link EntryProcessor} responsible for handling updates to session.
|
||||
*
|
||||
* @since 1.3.2
|
||||
* @see #save(HazelcastSession)
|
||||
*/
|
||||
private static final class SessionUpdateEntryProcessor
|
||||
extends AbstractEntryProcessor<String, MapSession> {
|
||||
|
||||
private final long lastAccessedTime;
|
||||
|
||||
private final int maxInactiveIntervalInSeconds;
|
||||
|
||||
private final Map<String, Object> delta;
|
||||
|
||||
SessionUpdateEntryProcessor(long lastAccessedTime,
|
||||
int maxInactiveIntervalInSeconds, Map<String, Object> delta) {
|
||||
this.lastAccessedTime = lastAccessedTime;
|
||||
this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds;
|
||||
this.delta = delta;
|
||||
}
|
||||
|
||||
public Object process(Map.Entry<String, MapSession> entry) {
|
||||
MapSession value = entry.getValue();
|
||||
value.setLastAccessedTime(this.lastAccessedTime);
|
||||
value.setMaxInactiveIntervalInSeconds(this.maxInactiveIntervalInSeconds);
|
||||
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 value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
@@ -289,9 +289,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();
|
||||
|
||||
@@ -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.
|
||||
@@ -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,8 +330,10 @@ 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));
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user