Compare commits

..

49 Commits

Author SHA1 Message Date
Spring Buildmaster
cd8f87e0a9 Release version 1.3.4.RELEASE 2018-11-14 16:51:11 +00:00
Vedran Pavic
95f41a7024 Polish 2018-11-08 22:32:46 +01:00
Vedran Pavic
d245cc1a36 Polish contribution
Resolves: #1250
2018-11-08 22:00:52 +01:00
Josh Cummings
695f2f1509 Commit Session on Include Dispatch
The servlet spec disallows any writing of headers after an include has been issued.

This commit intercepts the include and commits the session, then
allowing the include to proceed.

See: #1250
2018-11-08 22:00:50 +01:00
Vedran Pavic
3940a22d5e Disable network join in Hazelcast samples 2018-09-26 13:53:44 +02:00
Vedran Pavic
eb4ce12915 Upgrade dependencies and samples to Spring Boot 1.4.7.RELEASE levels
Resolves: #1108
2018-09-26 12:25:08 +02:00
Vedran Pavic
46bac131d0 Configure default LobHandler to use temporary LOBs on Oracle
JdbcOperationsSessionRepository recently introduced validation when inserting new session attributes in order to prevent data integrity violations in highly concurrent environments. This is done by using INSERT INTO ... SELECT statement to verify existence of session record in parent table. Such arrangement causes problems with Oracle if inserted attribute is of size 4 kb or more.

This commit enhances JdbcHttpSessionConfiguration to detect Oracle database is used, and set createTemporaryLob option on default LobHandler to true.

Resolves: #1212
2018-09-26 06:36:06 +02:00
Vedran Pavic
9675278729 Fix SpringSessionRememberMeServices documentation example
Resolves: #1211
2018-09-26 06:08:57 +02:00
Vedran Pavic
f0c216d9d5 Improve support for Hazelcast client-server topology
See: #1130
2018-09-26 06:01:42 +02:00
Vedran Pavic
cb6f7fdfa6 Insert new attributes conditionally in JDBC repo
At present, the insert of new attributes in JdbcOperationsSessionRepository is done unconditionally. This can cause data integrity violation errors with concurrent requests, where one request attempts to add new session attribute while the other, concurrent request, deletes the session.

This commit addresses the described scenario by executing insert of new attributes conditionally on presence of parent record.

Closes gh-1153
2018-08-13 08:21:34 +02:00
Vedran Pavic
b50a4e247e Improve support for Hazelcast client-server topology
This commit improves support for use of Spring Session with Hazelcast's client-server topology by ensuring SessionUpdateEntryProcessor is easier to serialize to the cluster. This is done by refactoring SessionUpdateEntryProcessor from static inner class of HazelcastSessionRepository to a dedicated class, therefore minimizing the dependencies to other Spring Session components.

Closes gh-1130
2018-08-03 17:16:55 +02:00
Vedran Pavic
6b3d78ac09 Disable network join in Hazelcast integration tests 2018-08-03 17:16:52 +02:00
Vedran Pavic
c0bd38c46f Improve HazelcastSessionRepository write operations
Closes gh-1106
2018-08-03 13:06:13 +02:00
Vedran Pavic
2262600b21 Improve update handling in HazelcastSessionRepository
See gh-1106
2018-08-03 13:05:29 +02:00
Vedran Pavic
0c11a4297a Add logging for errors decoding Base64 cookies
Closes gh-1134
2018-08-02 19:01:10 +02:00
Vedran Pavic
b778d97dc7 Ensure Session#getAttributeNames implementations return a copy
Currently, Session#getAttributeNames implementations, by delegating to MapSession, all return a session attribute map's key set. This causes ConcurrentModificationException when an attempt to modify session attributes is made while iterating over the returned attribute names.

Closes gh-1129
2018-08-02 18:59:29 +02:00
Spring Buildmaster
d0887fe40d Next development version 2018-05-08 18:25:17 +00:00
Spring Buildmaster
1a94d742b1 Release version 1.3.3.RELEASE 2018-05-08 18:25:07 +00:00
Vedran Pavic
c433b01ee5 Optimize session retrieval in JdbcOperationsSessionRepository
Previously, SessionResultSetExtractor used JdbcSession.setAttribute which had a side effect of freshly loaded session potentially having a non-empty delta and/or changed flag set. This commit optimizes session retrieval to invoke setAttribute directly on the delegate, therefore preventing unnecessary modifications of delta and change flags.

Closes gh-1053
2018-04-16 10:33:55 +02:00
Vedran Pavic
a3195f1f4b Fix NPE in RedisOperationsSessionRepository event handling
Closes gh-1049
2018-04-16 10:33:55 +02:00
Vedran Pavic
467ecaaeff Harmonize config locations 2018-04-16 10:33:54 +02:00
Spring Buildmaster
4a18242d95 Next development version 2018-02-09 20:11:48 +00:00
Spring Buildmaster
e44cd45668 Release version 1.3.2.RELEASE 2018-02-09 20:11:39 +00:00
Vedran Pavic
7f0de8126e Improve layout of community extensions doc section
Closes gh-993
2018-02-05 12:43:25 +01:00
Vedran Pavic
d75b03f594 Fix Gradle deprecation warnings 2018-01-29 18:45:38 +01:00
Vedran Pavic
ca0fea3a54 Upgrade Gradle to 3.5.1 2018-01-29 18:36:40 +01:00
Eddú Meléndez
92af786e6b Polish samples
Closes gh-986
2018-01-29 18:17:42 +01:00
Vedran Pavic
d271a4ad1d Polish contribution
Closes gh-920
2018-01-29 18:12:01 +01:00
Roman Cherepanov
04c1908378 Fix link to GemFire documentation
See gh-920
2018-01-29 18:11:33 +01:00
Vedran Pavic
f0e187fbd7 Update references to Spring Boot's Redis starter
Closes gh-952
2018-01-29 17:06:51 +01:00
Vedran Pavic
2d3001a24e Fix SessionRepositoryFilter not retaining original maxInactiveInterval
Closes gh-951
2018-01-29 16:45:46 +01:00
Vedran Pavic
f2d1badd60 Fix misc typos
Closes gh-985
2018-01-29 16:27:20 +01:00
Vedran Pavic
6a6d60d8f8 Improve session event handling
Closes gh-984
2018-01-29 16:27:20 +01:00
Vedran Pavic
b2cb3f6a3a Optimize HazelcastSessionRepository write operations
Closes gh-983
2018-01-29 16:27:20 +01:00
Vedran Pavic
d7ae5785eb Improve JDBC data store schema scripts
Closes gh-982
2018-01-29 16:27:15 +01:00
Kanjie Lu
96eb40439c fix typo
change "they key" to  "the key"

Closes gh-981
2018-01-29 16:26:08 +01:00
mikemassa84
8ed0999ad3 Update grails3.adoc
Add a note about spring-session and grails flash scope, with link to stackoverflow answer.

Closes gh-980
2018-01-29 16:26:08 +01:00
Vedran Pavic
b2d2335d73 Replace StringBuffer usages with StringBuilder
Closes gh-979
2018-01-29 16:25:59 +01:00
Spring Buildmaster
f597c5a824 Next development version 2017-04-27 18:57:32 +00:00
Spring Buildmaster
212eca306c Release version 1.3.1.RELEASE 2017-04-27 18:57:22 +00:00
Vedran Pavic
a64e6d1a9c Use explicit constraints in JDBC schema scripts
Fixes gh-765
2017-04-26 23:33:35 +02:00
Vedran Pavic
598715f219 Remove logging for "Skip invoking on" response committed
Fixes gh-764
2017-04-26 23:18:00 +02:00
Sebastian Laskawiec
4d90fcc7a8 Add link to Infinispan for Spring Session documentation
Fixes gh-763
2017-04-26 23:17:33 +02:00
John Blum
4f57c6c6c1 Fix invalid not null assertions
Fixes gh-762
2017-04-26 23:16:55 +02:00
Vedran Pavic
c210a4a3cf Prevent NPE inMongoOperationsSessionRepository when creating session if max inactive interval is undefined
Fixes gh-761
2017-04-26 23:15:40 +02:00
Rob Winch
a1380d722b SpringSessionRememberMeServices rm SecurityContext attribute
SpringSessionRememberMeServices use to invalidate the session which would
cause Spring Security's saved request to be lost.

Now SpringSessionRememberMeServices deletes the SecurityContext from the
HttpSession instead.

Fixes gh-752
2017-04-26 09:09:12 -05:00
Rob Winch
c029922bf4 Update to Spring Data Redis 1.7.10
Note the Spring 3 tests must stick to 1.7.1

Fixes gh-756
2017-04-26 07:56:15 -05:00
John Blum
6b55f3f7d2 Restore proper behavior of HttpSession created events in GemFire support when client Region is a PROXY in the client/server topology
Fixes gh-757

(cherry picked from commit c0c404ab96)
Signed-off-by: John Blum <jblum@pivotal.io>
2017-04-25 20:41:13 -07:00
John Blum
6668e41b0a Improve GemFire SessionRepository, Session copy logic to avoid issues with delta propagation on updates
Upgrade to Spring Data GemFire 1.8.10.RELEASE

Fixes #gh-755
2017-04-21 15:48:40 -07:00
570 changed files with 4544 additions and 6873 deletions

2
.gitignore vendored
View File

@@ -10,5 +10,5 @@ target
out
.springBeans
*.rdb
!eclipse/.checkstyle
.checkstyle
!etc/eclipse/.checkstyle

View File

@@ -40,5 +40,5 @@ appropriate to the circumstances. Maintainers are obligated to maintain confiden
with regard to the reporter of an incident.
This Code of Conduct is adapted from the
https://contributor-covenant.org[Contributor Covenant], version 1.3.0, available at
https://contributor-covenant.org/version/1/3/0/[contributor-covenant.org/version/1/3/0/]
http://contributor-covenant.org[Contributor Covenant], version 1.3.0, available at
http://contributor-covenant.org/version/1/3/0/[contributor-covenant.org/version/1/3/0/]

View File

@@ -10,8 +10,8 @@ By participating, you are expected to uphold this code. Please report unaccepta
== Using GitHub issues
We use GitHub issues to track bugs and enhancements. If you have a general usage question
please ask on https://stackoverflow.com[Stack Overflow]. The Spring Session team and the
broader community monitor the https://stackoverflow.com/tags/spring-session[`spring-session`]
please ask on http://stackoverflow.com[Stack Overflow]. The Spring Session team and the
broader community monitor the http://stackoverflow.com/tags/spring-session[`spring-session`]
tag.
If you are reporting a bug, please help to speed up problem diagnosis by providing as much

View File

@@ -19,8 +19,8 @@ By participating, you are expected to uphold this code. Please report unaccepta
= Spring Session Project Site
You can find the documentation, issue management, support, samples, and guides for using Spring Session at https://projects.spring.io/spring-session/
You can find the documentation, issue management, support, samples, and guides for using Spring Session at http://projects.spring.io/spring-session/
= License
Spring Session is Open Source software released under the https://www.apache.org/licenses/LICENSE-2.0.html[Apache 2.0 license].
Spring Session is Open Source software released under the http://www.apache.org/licenses/LICENSE-2.0.html[Apache 2.0 license].

View File

@@ -1,13 +1,12 @@
buildscript {
repositories {
maven { url "https://repo.spring.io/plugins-release" }
maven { url "https://repo.spring.io/milestone" }
}
dependencies {
classpath 'io.spring.gradle:dependency-management-plugin:1.0.3.RELEASE'
classpath 'io.spring.gradle:dependency-management-plugin:0.6.1.RELEASE'
classpath("com.bmuschko:gradle-tomcat-plugin:2.2.5")
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.7")
classpath("io.spring.gradle:spring-io-plugin:0.0.6.RELEASE")
classpath("io.spring.gradle:spring-io-plugin:0.0.4.RELEASE")
classpath('me.champeau.gradle:gradle-javadoc-hotfix-plugin:0.1')
classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.2'
classpath 'com.github.ben-manes:gradle-versions-plugin:0.12.0'
@@ -20,9 +19,10 @@ plugins {
group = 'org.springframework.session'
ext.springBootVersion = '1.5.4.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"
ext.MAVEN_GRADLE = "$rootDir/gradle/publish-maven.gradle"
ext.BOM_GRADLE = "$rootDir/gradle/bom.gradle"
ext.SAMPLE_GRADLE = "$rootDir/gradle/sample.gradle"

View File

@@ -50,7 +50,7 @@ dependencies {
asciidoctor {
def ghTag = snapshotBuild ? 'master' : project.version
def ghUrl = "https://github.com/spring-projects/spring-session/tree/$ghTag"
def ghUrl = "https://github.com/spring-projects/spring-session/tree/$ghTag/"
attributes 'version-snapshot': snapshotBuild,
'version-milestone': milestoneBuild,
'version-release': releaseBuild,
@@ -76,5 +76,3 @@ asciidoctor {
'docinfo1':'true',
'revnumber' : project.version
}
eclipse.project.name = 'spring-session-docs'

View File

@@ -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>
----
@@ -72,7 +72,7 @@ Add the following Spring Configuration:
[source,java]
----
include::{samples-dir}boot/redis/src/main/java/sample/config/HttpSessionConfig.java[tags=class]
include::{samples-dir}boot/src/main/java/sample/config/HttpSessionConfig.java[tags=class]
----
<1> The `@EnableRedisHttpSession` annotation creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements Filter.
@@ -93,7 +93,7 @@ spring.redis.password=secret
spring.redis.port=6379
----
For more information, refer to https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-connecting-to-redis[Connecting to Redis] portion of the Spring Boot documentation.
For more information, refer to http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-connecting-to-redis[Connecting to Redis] portion of the Spring Boot documentation.
[[boot-servlet-configuration]]
== Servlet Container Initialization
@@ -117,7 +117,7 @@ You can run the sample by obtaining the {download-url}[source code] and invoking
[NOTE]
====
For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
For the sample to work, you must http://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `JedisConnectionFactory` to point to a Redis server.
====
@@ -153,7 +153,7 @@ If you like, you can easily remove the session using redis-cli. For example, on
$ redis-cli keys '*' | xargs redis-cli del
TIP: The Redis documentation has instructions for https://redis.io/topics/quickstart[installing redis-cli].
TIP: The Redis documentation has instructions for http://redis.io/topics/quickstart[installing redis-cli].
Alternatively, you can also delete the explicit key. Enter the following into your terminal ensuring to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your SESSION cookie:

View File

@@ -17,7 +17,7 @@ You can find an example of customizing Spring Session's cookie below:
[source,java]
----
include::{samples-dir}javaconfig/custom-cookie/src/main/java/sample/Config.java[tags=cookie-serializer]
include::{samples-dir}custom-cookie/src/main/java/sample/Config.java[tags=cookie-serializer]
----
<1> We customize the name of the cookie to be JSESSIONID
@@ -27,7 +27,7 @@ This allows sharing a session across domains and applications.
If the regular expression does not match, no domain is set and the existing domain will be used.
If the regular expression matches, the first https://docs.oracle.com/javase/tutorial/essential/regex/groups.html[grouping] will be used as the domain.
This means that a request to https://child.example.com will set the domain to example.com.
However, a request to http://localhost:8080/ or https://192.168.1.100:8080/ will leave the cookie unset and thus still work in development without any changes necessary for production.
However, a request to http://localhost:8080/ or http://192.168.1.100:8080/ will leave the cookie unset and thus still work in development without any changes necessary for production.
[WARNING]
====
@@ -78,7 +78,7 @@ You can run the sample by obtaining the {download-url}[source code] and invoking
[NOTE]
====
For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
For the sample to work, you must http://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `LettuceConnectionFactory` to point to a Redis server.
====
@@ -98,4 +98,4 @@ Try using the application. Fill out the form with the following information:
Now click the **Set Attribute** button.
You should now see the values displayed in the table.
If you look at the cookies for the application, you can see the cookie is saved to the custom name of JSESSIONID
If you look at the cookies for the application, you can see the cookie is saved to the custom name of JSESSIONID

View File

@@ -65,7 +65,7 @@ For example, our sample application includes the location and access type of the
[source,java,indent=0]
----
include::{samples-dir}boot/findbyusername/src/main/java/sample/session/SessionDetails.java[tags=class]
include::{samples-dir}findbyusername/src/main/java/sample/session/SessionDetails.java[tags=class]
----
We then inject that information into the session on each HTTP request using a `SessionDetailsFilter`.
@@ -73,7 +73,7 @@ For example:
[source,java,indent=0]
----
include::{samples-dir}boot/findbyusername/src/main/java/sample/session/SessionDetailsFilter.java[tags=dofilterinternal]
include::{samples-dir}findbyusername/src/main/java/sample/session/SessionDetailsFilter.java[tags=dofilterinternal]
----
We obtain the information we want and then set the `SessionDetails` as an attribute in the `Session`.
@@ -93,7 +93,7 @@ We can now find all the sessions for a specific user.
[source,java,indent=0]
----
include::{samples-dir}boot/findbyusername/src/main/java/sample/mvc/IndexController.java[tags=findbyusername]
include::{samples-dir}findbyusername/src/main/java/sample/mvc/IndexController.java[tags=findbyusername]
----
In our instance, we find all sessions for the currently logged in user.
@@ -108,7 +108,7 @@ You can run the sample by obtaining the {download-url}[source code] and invoking
[NOTE]
====
For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
For the sample to work, you must http://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `JedisConnectionFactory` to point to a Redis server.
====

View File

@@ -70,7 +70,7 @@ spring:
port: 6397
----
For more information, refer to https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-connecting-to-redis[Connecting to Redis] portion of the Spring Boot documentation.
For more information, refer to http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-connecting-to-redis[Connecting to Redis] portion of the Spring Boot documentation.
[[grails3-sample]]
== Grails 3 Sample Application
@@ -84,7 +84,7 @@ You can run the sample by obtaining the {download-url}[source code] and invoking
[NOTE]
====
For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
For the sample to work, you must http://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `JedisConnectionFactory` to point to a Redis server.
====
@@ -120,10 +120,13 @@ If you like, you can easily remove the session using redis-cli. For example, on
$ redis-cli keys '*' | xargs redis-cli del
TIP: The Redis documentation has instructions for https://redis.io/topics/quickstart[installing redis-cli].
TIP: The Redis documentation has instructions for http://redis.io/topics/quickstart[installing redis-cli].
Alternatively, you can also delete the explicit key. Enter the following into your terminal ensuring to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your SESSION cookie:
$ 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

View File

@@ -85,7 +85,7 @@ In this instance Spring Session is backed by Hazelcast.
Spring Session provides `PrincipalNameExtractor` for this purpose.
<3> We create a `HazelcastInstance` that connects Spring Session to Hazelcast.
By default, an embedded instance of Hazelcast is started and connected to by the application.
For more information on configuring Hazelcast, refer to the https://docs.hazelcast.org/docs/latest/manual/html-single/index.html#hazelcast-configuration[reference documentation].
For more information on configuring Hazelcast, refer to the http://docs.hazelcast.org/docs/latest/manual/html-single/index.html#hazelcast-configuration[reference documentation].
== Servlet Container Initialization
@@ -98,7 +98,7 @@ Since our application is already loading Spring configuration using our `Securit
.src/main/java/sample/SecurityInitializer.java
[source,java]
----
include::{samples-dir}javaconfig/hazelcast/src/main/java/sample/SecurityInitializer.java[tags=class]
include::{samples-dir}hazelcast-spring/src/main/java/sample/SecurityInitializer.java[tags=class]
----
Last we need to ensure that our Servlet Container (i.e. Tomcat) uses our `springSessionRepositoryFilter` for every request.
@@ -110,7 +110,7 @@ You can find an example below:
.src/main/java/sample/Initializer.java
[source,java]
----
include::{samples-dir}javaconfig/hazelcast/src/main/java/sample/Initializer.java[tags=class]
include::{samples-dir}hazelcast-spring/src/main/java/sample/Initializer.java[tags=class]
----
NOTE: The name of our class (Initializer) does not matter. What is important is that we extend `AbstractHttpSessionApplicationInitializer`.
@@ -130,7 +130,7 @@ You can run the sample by obtaining the {download-url}[source code] and invoking
====
Hazelcast will run in embedded mode with your application by default, but if you want to connect
to a stand alone instance instead, you can configure it by following the instructions in the
https://docs.hazelcast.org/docs/latest/manual/html-single/index.html#hazelcast-configuration[reference documentation].
http://docs.hazelcast.org/docs/latest/manual/html-single/index.html#hazelcast-configuration[reference documentation].
====
----
@@ -161,9 +161,9 @@ Go ahead and view the cookies (click for help with https://developer.chrome.com/
=== Interact with the data store
If you like, you can remove the session using https://docs.hazelcast.org/docs/latest/manual/html-single/index.html#hazelcast-java-client[a Java client],
https://docs.hazelcast.org/docs/latest/manual/html-single/index.html#other-client-implementations[one of the other clients], or the
https://docs.hazelcast.org/docs/latest/manual/html-single/index.html#management-center[management center].
If you like, you can remove the session using http://docs.hazelcast.org/docs/latest/manual/html-single/index.html#hazelcast-java-client[a Java client],
http://docs.hazelcast.org/docs/latest/manual/html-single/index.html#other-client-implementations[one of the other clients], or the
http://docs.hazelcast.org/docs/latest/manual/html-single/index.html#management-center[management center].
==== Using the console
@@ -172,7 +172,7 @@ For example, using the management center console after connecting to your Hazelc
default> ns spring:session:sessions
spring:session:sessions> m.clear
TIP: The Hazelcast documentation has instructions for https://docs.hazelcast.org/docs/latest/manual/html-single/index.html#executing-console-commands[the console].
TIP: The Hazelcast documentation has instructions for http://docs.hazelcast.org/docs/latest/manual/html-single/index.html#executing-console-commands[the console].
Alternatively, you can also delete the explicit key. Enter the following into the console ensuring to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your SESSION cookie:
@@ -183,7 +183,7 @@ Now visit the application at http://localhost:8080/ and observe that we are no l
==== Using the REST API
As described in the other clients section of the documentation, there is a
https://docs.hazelcast.org/docs/latest/manual/html-single/index.html#rest-client[REST API]
http://docs.hazelcast.org/docs/latest/manual/html-single/index.html#rest-client[REST API]
provided by the Hazelcast node(s).
For example, you could delete an individual key as follows (replacing `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your SESSION cookie):

View File

@@ -86,7 +86,7 @@ We start with the _Spring Boot_ application for configuring and bootstrapping a
[source,java]
----
include::{samples-dir}boot/gemfire/src/main/java/sample/server/GemFireServer.java[tags=class]
include::{samples-dir}httpsession-gemfire-boot/src/main/java/sample/server/GemFireServer.java[tags=class]
----
<1> The `@EnableGemFireHttpSession` annotation is used on the GemFire Server to mainly define the corresponding
@@ -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
https://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,
@@ -113,7 +113,7 @@ to manage Session state in a clustered, replicated fashion.
[source,java]
----
include::{samples-dir}boot/gemfire/src/main/java/sample/client/Application.java[tags=class]
include::{samples-dir}httpsession-gemfire-boot/src/main/java/sample/client/Application.java[tags=class]
----
<1> Here, again, we use the `@EnableGemFireHttpSession` annotation to not only configure the GemFire cache client,
@@ -149,22 +149,22 @@ TIP: In typical GemFire deployments, where the cluster includes potentially hund
(servers), it is more common for clients to connect to one or more GemFire Locators running in the cluster. A Locator
passes meta-data to clients about the servers available, their load and which servers have the client's data of interest,
which is particularly important in direct, single-hop data access and latency-sensitive operations. See more details
about the https://gemfire.docs.pivotal.io/docs-gemfire/latest/topologies_and_comm/cs_configuration/chapter_overview.html[Client/Server Topology in GemFire's User Guide].
about the http://gemfire.docs.pivotal.io/docs-gemfire/latest/topologies_and_comm/cs_configuration/chapter_overview.html[Client/Server Topology in GemFire's User Guide].
NOTE: For more information on configuring _Spring Data GemFire_, refer to the https://docs.spring.io/spring-data-gemfire/docs/current/reference/html/[reference guide].
NOTE: For more information on configuring _Spring Data GemFire_, refer to the http://docs.spring.io/spring-data-gemfire/docs/current/reference/html/[reference guide].
The `@EnableGemFireHttpSession` annotation enables a developer to configure certain aspects of both _Spring Session_
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 https://gemfire.docs.pivotal.io/docs-gemfire/latest/developing/management_all_region_types/chapter_overview.html[data management policy]
with a GemFire https://gemfire.docs.pivotal.io/docs-gemfire/latest/javadocs/japi/com/gemstone/gemfire/cache/client/ClientRegionShortcut.html[ClientRegionShortcut]
* `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://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`.
* `serverRegionShort` - specifies GemFire's https://gemfire.docs.pivotal.io/docs-gemfire/latest/developing/management_all_region_types/chapter_overview.html[data management policy]
using a GemFire https://data-docs-samples.cfapps.io/docs-gemfire/latest/javadocs/japi/com/gemstone/gemfire/cache/RegionShortcut.html[RegionShortcut]
* `serverRegionShort` - specifies GemFire's http://gemfire.docs.pivotal.io/docs-gemfire/latest/developing/management_all_region_types/chapter_overview.html[data management policy]
using a GemFire http://data-docs-samples.cfapps.io/docs-gemfire/latest/javadocs/japi/com/gemstone/gemfire/cache/RegionShortcut.html[RegionShortcut]
(default is `PARTITION`). This attribute is only used when configuring server Regions, or when a p2p topology is employed.
NOTE: It is important to remember that the GemFire client Region name must match a server Region by the same name if
@@ -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 https://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`.
@@ -262,7 +262,7 @@ NEXT_STEP_NAME : END
gfsh>remove --region=/ClusteredSpringSessions --key="70002719-3c54-4c20-82c3-e7faa6b718f3"
....
NOTE: The _GemFire User Guide_ has more detailed instructions on using https://gemfire.docs.pivotal.io/docs-gemfire/latest/tools_modules/gfsh/chapter_overview.html[gfsh].
NOTE: The _GemFire User Guide_ has more detailed instructions on using http://gemfire.docs.pivotal.io/docs-gemfire/latest/tools_modules/gfsh/chapter_overview.html[gfsh].
Now visit the application at http://localhost:8080/ again and observe that the attribute we added is no longer displayed.

View File

@@ -80,7 +80,7 @@ Add the following Spring Configuration:
[source,xml]
----
include::{samples-dir}xml/gemfire-clientserver/src/main/webapp/WEB-INF/spring/session-client.xml[tags=beans]
include::{samples-dir}httpsession-gemfire-clientserver-xml/src/main/webapp/WEB-INF/spring/session-client.xml[tags=beans]
----
<1> Spring annotation configuration support is enabled with `<context:annotation-config/>` element so that any
@@ -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
https://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`.
@@ -104,9 +104,9 @@ has been configured to connect directly to a server.
TIP: In typical GemFire deployments, where the cluster includes potentially hundreds of GemFire data nodes (servers),
it is more common for clients to connect to one or more GemFire Locators running in the cluster. A Locator passes meta-data
to clients about the servers available, load and which servers have the client's data of interest, which is particularly
important for single-hop, direct data access. See more details about the https://gemfire.docs.pivotal.io/docs-gemfire/latest/topologies_and_comm/cs_configuration/chapter_overview.html[Client/Server Topology in GemFire's User Guide].
important for single-hop, direct data access. See more details about the http://gemfire.docs.pivotal.io/docs-gemfire/latest/topologies_and_comm/cs_configuration/chapter_overview.html[Client/Server Topology in GemFire's User Guide].
NOTE: For more information on configuring _Spring Data GemFire_, refer to the https://docs.spring.io/spring-data-gemfire/docs/current/reference/html/[reference guide].
NOTE: For more information on configuring _Spring Data GemFire_, refer to the http://docs.spring.io/spring-data-gemfire/docs/current/reference/html/[reference guide].
=== Server Configuration
@@ -117,7 +117,7 @@ In this sample, we will use the following GemFire Server Java Configuration:
[source,xml]
----
include::{samples-dir}xml/gemfire-clientserver/src/main/resources/META-INF/spring/session-server.xml[tags=beans]
include::{samples-dir}httpsession-gemfire-clientserver-xml/src/main/resources/META-INF/spring/session-server.xml[tags=beans]
----
<1> First, we enable Spring annotation config support with the `<context:annotation-config>` element so that any
@@ -139,7 +139,7 @@ The GemFire Server configuration gets bootstrapped with the following:
[source,java]
----
include::{samples-dir}xml/gemfire-clientserver/src/main/java/sample/Application.java[tags=class]
include::{samples-dir}httpsession-gemfire-clientserver-xml/src/main/java/sample/Application.java[tags=class]
----
TIP: Instead of a simple Java class with a main method, you could also use _Spring Boot_.
@@ -163,11 +163,11 @@ We do this with the following configuration:
.src/main/webapp/WEB-INF/web.xml
[source,xml,indent=0]
----
include::{samples-dir}xml/gemfire-clientserver/src/main/webapp/WEB-INF/web.xml[tags=context-param]
include::{samples-dir}xml/gemfire-clientserver/src/main/webapp/WEB-INF/web.xml[tags=listeners]
include::{samples-dir}httpsession-gemfire-clientserver-xml/src/main/webapp/WEB-INF/web.xml[tags=context-param]
include::{samples-dir}httpsession-gemfire-clientserver-xml/src/main/webapp/WEB-INF/web.xml[tags=listeners]
----
The https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#context-create[ContextLoaderListener]
The http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#context-create[ContextLoaderListener]
reads the `contextConfigLocation` context parameter value and picks up our _session-client.xml_ configuration file.
Finally, we need to ensure that our Servlet Container (i.e. Tomcat) uses our `springSessionRepositoryFilter`
@@ -178,10 +178,10 @@ The following snippet performs this last step for us:
.src/main/webapp/WEB-INF/web.xml
[source,xml,indent=0]
----
include::{samples-dir}xml/gemfire-clientserver/src/main/webapp/WEB-INF/web.xml[tags=springSessionRepositoryFilter]
include::{samples-dir}httpsession-gemfire-clientserver-xml/src/main/webapp/WEB-INF/web.xml[tags=springSessionRepositoryFilter]
----
The https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/filter/DelegatingFilterProxy.html[DelegatingFilterProxy]
The http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/filter/DelegatingFilterProxy.html[DelegatingFilterProxy]
will look up a bean by the name of `springSessionRepositoryFilter` and cast it to a `Filter`. For every request that `DelegatingFilterProxy`
is invoked, the `springSessionRepositoryFilter` will be invoked.
// end::config[]
@@ -225,7 +225,7 @@ We interact with the standard `HttpSession` in the `SessionServlet` shown below:
.src/main/java/sample/SessionServlet.java
[source,java]
----
include::{samples-dir}xml/gemfire-clientserver/src/main/java/sample/SessionServlet.java[tags=class]
include::{samples-dir}httpsession-gemfire-clientserver/src/main/java/sample/SessionServlet.java[tags=class]
----
Instead of using Tomcat's `HttpSession`, we are actually persisting the values in GemFire.
@@ -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 https://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:
@@ -263,7 +263,7 @@ NEXT_STEP_NAME : END
gfsh>remove --region=/ClusteredSpringSessions --key="70002719-3c54-4c20-82c3-e7faa6b718f3"
....
NOTE: The _GemFire User Guide_ has more detailed instructions on using https://gemfire.docs.pivotal.io/docs-gemfire/latest/tools_modules/gfsh/chapter_overview.html[gfsh].
NOTE: The _GemFire User Guide_ has more detailed instructions on using http://gemfire.docs.pivotal.io/docs-gemfire/latest/tools_modules/gfsh/chapter_overview.html[gfsh].
Now visit the application at http://localhost:8080/ again and observe that the attribute we added is no longer displayed.

View File

@@ -80,27 +80,27 @@ Add the following Spring Configuration:
[source,java]
----
include::{samples-dir}javaconfig/gemfire-clientserver/src/main/java/sample/ClientConfig.java[tags=class]
include::{samples-dir}httpsession-gemfire-clientserver/src/main/java/sample/ClientConfig.java[tags=class]
----
<1> The `@EnableGemFireHttpSession` annotation creates a Spring bean named `springSessionRepositoryFilter` that
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 https://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
https://gemfire.docs.pivotal.io/docs-gemfire/latest/javadocs/japi/com/gemstone/gemfire/cache/client/PoolFactory.html[PoolFactory API].
<5> Finally, we include a Spring `BeanPostProcessor` to block the client until our GemFire Server is up and running,
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.
The `gemfireCacheServerReadyBeanPostProcessor` is necessary in order to coordinate the client and server in
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 https://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.
@@ -108,22 +108,22 @@ the listener releases the latch that the `BeanPostProcessor` will wait on (up to
TIP: In typical GemFire deployments, where the cluster includes potentially hundreds of GemFire data nodes (servers),
it is more common for clients to connect to one or more GemFire Locators running in the cluster. A Locator passes meta-data
to clients about the servers available, load and which servers have the client's data of interest, which is particularly
important for single-hop, direct data access. See more details about the https://gemfire.docs.pivotal.io/docs-gemfire/latest/topologies_and_comm/cs_configuration/chapter_overview.html[Client/Server Topology in GemFire's User Guide].
important for single-hop, direct data access. See more details about the http://gemfire.docs.pivotal.io/docs-gemfire/latest/topologies_and_comm/cs_configuration/chapter_overview.html[Client/Server Topology in GemFire's User Guide].
NOTE: For more information on configuring _Spring Data GemFire_, refer to the https://docs.spring.io/spring-data-gemfire/docs/current/reference/html/[reference guide].
NOTE: For more information on configuring _Spring Data GemFire_, refer to the http://docs.spring.io/spring-data-gemfire/docs/current/reference/html/[reference guide].
The `@EnableGemFireHttpSession` annotation enables a developer to configure certain aspects of both Spring Session
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 https://gemfire.docs.pivotal.io/docs-gemfire/latest/developing/management_all_region_types/chapter_overview.html[data management policy]
with a GemFire https://gemfire.docs.pivotal.io/docs-gemfire/latest/javadocs/japi/com/gemstone/gemfire/cache/client/ClientRegionShortcut.html[ClientRegionShortcut]
* `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 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`.
* `serverRegionShort` - specifies GemFire's https://gemfire.docs.pivotal.io/docs-gemfire/latest/developing/management_all_region_types/chapter_overview.html[data management policy]
using a GemFire https://data-docs-samples.cfapps.io/docs-gemfire/latest/javadocs/japi/com/gemstone/gemfire/cache/RegionShortcut.html[RegionShortcut]
* `serverRegionShort` - specifies GemFire's http://gemfire.docs.pivotal.io/docs-gemfire/latest/developing/management_all_region_types/chapter_overview.html[data management policy]
using a GemFire http://data-docs-samples.cfapps.io/docs-gemfire/latest/javadocs/japi/com/gemstone/gemfire/cache/RegionShortcut.html[RegionShortcut]
(default is `PARTITION`). This attribute is only used when configuring server Regions, or when a p2p topology is employed.
NOTE: It is important to note that the GemFire client Region name must match a server Region by the same name if
@@ -144,7 +144,7 @@ In this sample, we will use the following GemFire Server Java Configuration:
[source,java]
----
include::{samples-dir}javaconfig/gemfire-clientserver/src/main/java/sample/ServerConfig.java[tags=class]
include::{samples-dir}httpsession-gemfire-clientserver/src/main/java/sample/ServerConfig.java[tags=class]
----
<1> On the server, we also configure Spring Session using the `@EnableGemFireHttpSession` annotation. This ensures
@@ -174,7 +174,7 @@ You can find an example below:
.src/main/java/sample/Initializer.java
[source,java]
----
include::{samples-dir}javaconfig/gemfire-clientserver/src/main/java/sample/Initializer.java[tags=class]
include::{samples-dir}httpsession-gemfire-clientserver/src/main/java/sample/Initializer.java[tags=class]
----
NOTE: The name of our class (`Initializer`) does not matter. What is important is that we extend `AbstractHttpSessionApplicationInitializer`.
@@ -224,7 +224,7 @@ We interact with the standard `HttpSession` in the `SessionServlet` shown below:
.src/main/java/sample/SessionServlet.java
[source,java]
----
include::{samples-dir}javaconfig/gemfire-clientserver/src/main/java/sample/SessionServlet.java[tags=class]
include::{samples-dir}httpsession-gemfire-clientserver/src/main/java/sample/SessionServlet.java[tags=class]
----
Instead of using Tomcat's `HttpSession`, we are actually persisting the values in GemFire.
@@ -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 https://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:
@@ -262,7 +262,7 @@ NEXT_STEP_NAME : END
gfsh>remove --region=/ClusteredSpringSessions --key="70002719-3c54-4c20-82c3-e7faa6b718f3"
....
NOTE: The _GemFire User Guide_ has more detailed instructions on using https://gemfire.docs.pivotal.io/docs-gemfire/latest/tools_modules/gfsh/chapter_overview.html[gfsh].
NOTE: The _GemFire User Guide_ has more detailed instructions on using http://gemfire.docs.pivotal.io/docs-gemfire/latest/tools_modules/gfsh/chapter_overview.html[gfsh].
Now visit the application at http://localhost:8080/ again and observe that the attribute we added is no longer displayed.

View File

@@ -81,7 +81,7 @@ Add the following Spring Configuration:
.src/main/webapp/WEB-INF/spring/session.xml
[source,xml,indent=0]
----
include::{samples-dir}xml/gemfire-p2p/src/main/webapp/WEB-INF/spring/session.xml[tags=beans]
include::{samples-dir}httpsession-gemfire-p2p-xml/src/main/webapp/WEB-INF/spring/session.xml[tags=beans]
----
<1> We use the combination of `<context:annotation-config/>` and `GemFireHttpSessionConfiguration` because Spring Session
@@ -100,7 +100,7 @@ Spring Session sample application.
TIP: Additionally, we have configured this data node (server) as a GemFire Manager as well using GemFire-specific
JMX System properties that enable JMX client (e.g. _Gfsh_) to connect to this running data node.
NOTE: For more information on configuring _Spring Data GemFire_, refer to the https://docs.spring.io/spring-data-gemfire/docs/current/reference/html/[reference guide].
NOTE: For more information on configuring _Spring Data GemFire_, refer to the http://docs.spring.io/spring-data-gemfire/docs/current/reference/html/[reference guide].
== XML Servlet Container Initialization
@@ -114,11 +114,11 @@ We do this with the following configuration:
.src/main/webapp/WEB-INF/web.xml
[source,xml,indent=0]
----
include::{samples-dir}xml/gemfire-p2p/src/main/webapp/WEB-INF/web.xml[tags=context-param]
include::{samples-dir}xml/gemfire-p2p/src/main/webapp/WEB-INF/web.xml[tags=listeners]
include::{samples-dir}httpsession-gemfire-p2p-xml/src/main/webapp/WEB-INF/web.xml[tags=context-param]
include::{samples-dir}httpsession-gemfire-p2p-xml/src/main/webapp/WEB-INF/web.xml[tags=listeners]
----
The https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#context-create[ContextLoaderListener]
The http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#context-create[ContextLoaderListener]
reads the `contextConfigLocation` context parameter value and picks up our _session.xml_ configuration file.
Finally, we need to ensure that our Servlet Container (i.e. Tomcat) uses our `springSessionRepositoryFilter`
@@ -129,10 +129,10 @@ The following snippet performs this last step for us:
.src/main/webapp/WEB-INF/web.xml
[source,xml,indent=0]
----
include::{samples-dir}xml/gemfire-p2p/src/main/webapp/WEB-INF/web.xml[tags=springSessionRepositoryFilter]
include::{samples-dir}httpsession-gemfire-p2p-xml/src/main/webapp/WEB-INF/web.xml[tags=springSessionRepositoryFilter]
----
The https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/filter/DelegatingFilterProxy.html[DelegatingFilterProxy]
The http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/filter/DelegatingFilterProxy.html[DelegatingFilterProxy]
will look up a bean by the name of `springSessionRepositoryFilter` and cast it to a `Filter`. For every request that `DelegatingFilterProxy`
is invoked, the `springSessionRepositoryFilter` will be invoked.
// end::config[]
@@ -167,7 +167,7 @@ We interact with the standard `HttpSession` in the `SessionServlet` shown below:
.src/main/java/sample/SessionServlet.java
[source,java]
----
include::{samples-dir}xml/gemfire-p2p/src/main/java/sample/SessionServlet.java[tags=class]
include::{samples-dir}httpsession-gemfire-p2p-xml/src/main/java/sample/SessionServlet.java[tags=class]
----
Instead of using Tomcat's `HttpSession`, we are actually persisting the values in GemFire.
@@ -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 https://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:
@@ -205,6 +205,6 @@ NEXT_STEP_NAME : END
gfsh>remove --region=/ClusteredSpringSessions --key="70002719-3c54-4c20-82c3-e7faa6b718f3"
....
NOTE: The _GemFire User Guide_ has more detailed instructions on using https://gemfire.docs.pivotal.io/docs-gemfire/latest/tools_modules/gfsh/chapter_overview.html[gfsh].
NOTE: The _GemFire User Guide_ has more detailed instructions on using http://gemfire.docs.pivotal.io/docs-gemfire/latest/tools_modules/gfsh/chapter_overview.html[gfsh].
Now visit the application at http://localhost:8080/ and observe that the attribute we added is no longer displayed.

View File

@@ -80,7 +80,7 @@ Add the following Spring Configuration:
[source,java]
----
include::{samples-dir}javaconfig/gemfire-p2p/src/main/java/sample/Config.java[tags=class]
include::{samples-dir}httpsession-gemfire-p2p/src/main/java/sample/Config.java[tags=class]
----
<1> The `@EnableGemFireHttpSession` annotation creates a Spring bean named `springSessionRepositoryFilter` that
@@ -96,15 +96,15 @@ Spring Session sample application.
TIP: Additionally, we have configured this data node (server) as a GemFire Manager as well using GemFire-specific
JMX System properties that enable JMX client (e.g. _Gfsh_) to connect to this running data node.
NOTE: For more information on configuring _Spring Data GemFire_, refer to the https://docs.spring.io/spring-data-gemfire/docs/current/reference/html/[reference guide].
NOTE: For more information on configuring _Spring Data GemFire_, refer to the http://docs.spring.io/spring-data-gemfire/docs/current/reference/html/[reference guide].
The `@EnableGemFireHttpSession` annotation enables a developer to configure certain aspects of Spring Session
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 https://gemfire.docs.pivotal.io/docs-gemfire/latest/developing/management_all_region_types/chapter_overview.html[data management policies]
with a GemFire https://gemfire.docs.pivotal.io/docs-gemfire/latest/javadocs/japi/com/gemstone/gemfire/cache/RegionShortcut.html[RegionShortcut]
* `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 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,
@@ -125,7 +125,7 @@ You can find an example below:
.src/main/java/sample/Initializer.java
[source,java]
----
include::{samples-dir}javaconfig/gemfire-p2p/src/main/java/sample/Initializer.java[tags=class]
include::{samples-dir}httpsession-gemfire-p2p/src/main/java/sample/Initializer.java[tags=class]
----
NOTE: The name of our class (`Initializer`) does not matter. What is important is that we extend `AbstractHttpSessionApplicationInitializer`.
@@ -166,7 +166,7 @@ We interact with the standard `HttpSession` in the `SessionServlet` shown below:
.src/main/java/sample/SessionServlet.java
[source,java]
----
include::{samples-dir}javaconfig/gemfire-p2p/src/main/java/sample/SessionServlet.java[tags=class]
include::{samples-dir}httpsession-gemfire-p2p/src/main/java/sample/SessionServlet.java[tags=class]
----
Instead of using Tomcat's `HttpSession`, we are actually persisting the values in GemFire.
@@ -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 https://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:
@@ -204,6 +204,6 @@ NEXT_STEP_NAME : END
gfsh>remove --region=/ClusteredSpringSessions --key="70002719-3c54-4c20-82c3-e7faa6b718f3"
....
NOTE: The _GemFire User Guide_ has more detailed instructions on using https://gemfire.docs.pivotal.io/docs-gemfire/latest/tools_modules/gfsh/chapter_overview.html[gfsh].
NOTE: The _GemFire User Guide_ has more detailed instructions on using http://gemfire.docs.pivotal.io/docs-gemfire/latest/tools_modules/gfsh/chapter_overview.html[gfsh].
Now visit the application at http://localhost:8080/ and observe that the attribute we added is no longer displayed.

View File

@@ -74,7 +74,7 @@ Add the following Spring Configuration:
[source,java]
----
include::{samples-dir}boot/jdbc/src/main/java/sample/config/HttpSessionConfig.java[tags=class]
include::{samples-dir}httpsession-jdbc-boot/src/main/java/sample/config/HttpSessionConfig.java[tags=class]
----
<1> The `@EnableJdbcHttpSession` annotation creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements Filter.
@@ -95,7 +95,7 @@ spring.datasource.username=myapp
spring.datasource.password=secret
----
For more information, refer to https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-configure-datasource[Configure a DataSource] portion of the Spring Boot documentation.
For more information, refer to http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-configure-datasource[Configure a DataSource] portion of the Spring Boot documentation.
[[httpsession-jdbc-boot-servlet-configuration]]
== Servlet Container Initialization

View File

@@ -76,7 +76,7 @@ Add the following Spring Configuration:
.src/main/webapp/WEB-INF/spring/session.xml
[source,xml,indent=0]
----
include::{samples-dir}xml/jdbc/src/main/webapp/WEB-INF/spring/session.xml[tags=beans]
include::{samples-dir}httpsession-jdbc-xml/src/main/webapp/WEB-INF/spring/session.xml[tags=beans]
----
<1> We use the combination of `<context:annotation-config/>` and `JdbcHttpSessionConfiguration` because Spring Session does not yet provide XML Namespace support (see https://github.com/spring-projects/spring-session/issues/104[gh-104]).
@@ -87,7 +87,7 @@ In this instance Spring Session is backed by a relational database.
We configure the H2 database to create database tables using the SQL script which is included in Spring Session.
<3> We create a `transactionManager` that manages transactions for previously configured `dataSource`.
For additional information on how to configure data access related concerns, please refer to the https://docs.spring.io/spring/docs/current/spring-framework-reference/html/spring-data-tier.html[Spring Framework Reference Documentation].
For additional information on how to configure data access related concerns, please refer to the http://docs.spring.io/spring/docs/current/spring-framework-reference/html/spring-data-tier.html[Spring Framework Reference Documentation].
== XML Servlet Container Initialization
@@ -101,11 +101,11 @@ We do this with the following configuration:
.src/main/webapp/WEB-INF/web.xml
[source,xml,indent=0]
----
include::{samples-dir}xml/jdbc/src/main/webapp/WEB-INF/web.xml[tags=context-param]
include::{samples-dir}xml/jdbc/src/main/webapp/WEB-INF/web.xml[tags=listeners]
include::{samples-dir}httpsession-xml/src/main/webapp/WEB-INF/web.xml[tags=context-param]
include::{samples-dir}httpsession-xml/src/main/webapp/WEB-INF/web.xml[tags=listeners]
----
The https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#context-create[ContextLoaderListener] reads the contextConfigLocation and picks up our session.xml configuration.
The http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#context-create[ContextLoaderListener] reads the contextConfigLocation and picks up our session.xml configuration.
Last we need to ensure that our Servlet Container (i.e. Tomcat) uses our `springSessionRepositoryFilter` for every request.
The following snippet performs this last step for us:
@@ -113,10 +113,10 @@ The following snippet performs this last step for us:
.src/main/webapp/WEB-INF/web.xml
[source,xml,indent=0]
----
include::{samples-dir}xml/jdbc/src/main/webapp/WEB-INF/web.xml[tags=springSessionRepositoryFilter]
include::{samples-dir}httpsession-xml/src/main/webapp/WEB-INF/web.xml[tags=springSessionRepositoryFilter]
----
The https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/filter/DelegatingFilterProxy.html[DelegatingFilterProxy] will look up a Bean by the name of `springSessionRepositoryFilter` and cast it to a `Filter`.
The http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/filter/DelegatingFilterProxy.html[DelegatingFilterProxy] will look up a Bean by the name of `springSessionRepositoryFilter` and cast it to a `Filter`.
For every request that `DelegatingFilterProxy` is invoked, the `springSessionRepositoryFilter` will be invoked.
// end::config[]
@@ -150,7 +150,7 @@ We interact with the standard `HttpSession` in the `SessionServlet` shown below:
.src/main/java/sample/SessionServlet.java
[source,java]
----
include::{samples-dir}xml/jdbc/src/main/java/sample/SessionServlet.java[tags=class]
include::{samples-dir}httpsession-jdbc-xml/src/main/java/sample/SessionServlet.java[tags=class]
----
Instead of using Tomcat's `HttpSession`, we are actually persisting the values in H2 database.

View File

@@ -75,7 +75,7 @@ Add the following Spring Configuration:
[source,java]
----
include::{samples-dir}javaconfig/jdbc/src/main/java/sample/Config.java[tags=class]
include::{samples-dir}httpsession-jdbc/src/main/java/sample/Config.java[tags=class]
----
<1> The `@EnableJdbcHttpSession` annotation creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements Filter.
@@ -85,7 +85,7 @@ In this instance Spring Session is backed by a relational database.
We configure the H2 database to create database tables using the SQL script which is included in Spring Session.
<3> We create a `transactionManager` that manages transactions for previously configured `dataSource`.
For additional information on how to configure data access related concerns, please refer to the https://docs.spring.io/spring/docs/current/spring-framework-reference/html/spring-data-tier.html[Spring Framework Reference Documentation].
For additional information on how to configure data access related concerns, please refer to the http://docs.spring.io/spring/docs/current/spring-framework-reference/html/spring-data-tier.html[Spring Framework Reference Documentation].
== Java Servlet Container Initialization
@@ -100,7 +100,7 @@ You can find an example below:
.src/main/java/sample/Initializer.java
[source,java]
----
include::{samples-dir}javaconfig/jdbc/src/main/java/sample/Initializer.java[tags=class]
include::{samples-dir}httpsession/src/main/java/sample/Initializer.java[tags=class]
----
NOTE: The name of our class (Initializer) does not matter. What is important is that we extend `AbstractHttpSessionApplicationInitializer`.
@@ -140,7 +140,7 @@ We interact with the standard `HttpSession` in the `SessionServlet` shown below:
.src/main/java/sample/SessionServlet.java
[source,java]
----
include::{samples-dir}javaconfig/jdbc/src/main/java/sample/SessionServlet.java[tags=class]
include::{samples-dir}httpsession-jdbc/src/main/java/sample/SessionServlet.java[tags=class]
----
Instead of using Tomcat's `HttpSession`, we are actually persisting the values in H2 database.

View File

@@ -81,7 +81,7 @@ Add the following Spring Configuration:
.src/main/webapp/WEB-INF/spring/session.xml
[source,xml,indent=0]
----
include::{samples-dir}xml/redis/src/main/webapp/WEB-INF/spring/session.xml[tags=beans]
include::{samples-dir}httpsession-xml/src/main/webapp/WEB-INF/spring/session.xml[tags=beans]
----
<1> We use the combination of `<context:annotation-config/>` and `RedisHttpSessionConfiguration` because Spring Session does not yet provide XML Namespace support (see https://github.com/spring-projects/spring-session/issues/104[gh-104]).
@@ -90,7 +90,7 @@ The filter is what is in charge of replacing the `HttpSession` implementation to
In this instance Spring Session is backed by Redis.
<2> We create a `RedisConnectionFactory` that connects Spring Session to the Redis Server.
We configure the connection to connect to localhost on the default port (6379)
For more information on configuring Spring Data Redis, refer to the https://docs.spring.io/spring-data/data-redis/docs/current/reference/html/[reference documentation].
For more information on configuring Spring Data Redis, refer to the http://docs.spring.io/spring-data/data-redis/docs/current/reference/html/[reference documentation].
== XML Servlet Container Initialization
@@ -104,11 +104,11 @@ We do this with the following configuration:
.src/main/webapp/WEB-INF/web.xml
[source,xml,indent=0]
----
include::{samples-dir}xml/redis/src/main/webapp/WEB-INF/web.xml[tags=context-param]
include::{samples-dir}xml/redis/src/main/webapp/WEB-INF/web.xml[tags=listeners]
include::{samples-dir}httpsession-xml/src/main/webapp/WEB-INF/web.xml[tags=context-param]
include::{samples-dir}httpsession-xml/src/main/webapp/WEB-INF/web.xml[tags=listeners]
----
The https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#context-create[ContextLoaderListener] reads the contextConfigLocation and picks up our session.xml configuration.
The http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#context-create[ContextLoaderListener] reads the contextConfigLocation and picks up our session.xml configuration.
Last we need to ensure that our Servlet Container (i.e. Tomcat) uses our `springSessionRepositoryFilter` for every request.
The following snippet performs this last step for us:
@@ -116,10 +116,10 @@ The following snippet performs this last step for us:
.src/main/webapp/WEB-INF/web.xml
[source,xml,indent=0]
----
include::{samples-dir}xml/redis/src/main/webapp/WEB-INF/web.xml[tags=springSessionRepositoryFilter]
include::{samples-dir}httpsession-xml/src/main/webapp/WEB-INF/web.xml[tags=springSessionRepositoryFilter]
----
The https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/filter/DelegatingFilterProxy.html[DelegatingFilterProxy] will look up a Bean by the name of `springSessionRepositoryFilter` and cast it to a `Filter`.
The http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/filter/DelegatingFilterProxy.html[DelegatingFilterProxy] will look up a Bean by the name of `springSessionRepositoryFilter` and cast it to a `Filter`.
For every request that `DelegatingFilterProxy` is invoked, the `springSessionRepositoryFilter` will be invoked.
// end::config[]
@@ -133,7 +133,7 @@ You can run the sample by obtaining the {download-url}[source code] and invoking
[NOTE]
====
For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
For the sample to work, you must http://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `LettuceConnectionFactory` to point to a Redis server.
====
@@ -159,7 +159,7 @@ We interact with the standard `HttpSession` in the `SessionServlet` shown below:
.src/main/java/sample/SessionServlet.java
[source,java]
----
include::{samples-dir}xml/redis/src/main/java/sample/SessionServlet.java[tags=class]
include::{samples-dir}httpsession-xml/src/main/java/sample/SessionServlet.java[tags=class]
----
Instead of using Tomcat's `HttpSession`, we are actually persisting the values in Redis.
@@ -170,10 +170,10 @@ If you like, you can easily remove the session using redis-cli. For example, on
$ redis-cli keys '*' | xargs redis-cli del
TIP: The Redis documentation has instructions for https://redis.io/topics/quickstart[installing redis-cli].
TIP: The Redis documentation has instructions for http://redis.io/topics/quickstart[installing redis-cli].
Alternatively, you can also delete the explicit key. Enter the following into your terminal ensuring to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your SESSION cookie:
$ redis-cli del spring:session:sessions:7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
Now visit the application at http://localhost:8080/ and observe that the attribute we added is no longer displayed.
Now visit the application at http://localhost:8080/ and observe that the attribute we added is no longer displayed.

View File

@@ -80,7 +80,7 @@ Add the following Spring Configuration:
[source,java]
----
include::{samples-dir}javaconfig/redis/src/main/java/sample/Config.java[tags=class]
include::{samples-dir}httpsession/src/main/java/sample/Config.java[tags=class]
----
<1> The `@EnableRedisHttpSession` annotation creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements Filter.
@@ -88,7 +88,7 @@ The filter is what is in charge of replacing the `HttpSession` implementation to
In this instance Spring Session is backed by Redis.
<2> We create a `RedisConnectionFactory` that connects Spring Session to the Redis Server.
We configure the connection to connect to localhost on the default port (6379)
For more information on configuring Spring Data Redis, refer to the https://docs.spring.io/spring-data/data-redis/docs/current/reference/html/[reference documentation].
For more information on configuring Spring Data Redis, refer to the http://docs.spring.io/spring-data/data-redis/docs/current/reference/html/[reference documentation].
== Java Servlet Container Initialization
@@ -103,7 +103,7 @@ You can find an example below:
.src/main/java/sample/Initializer.java
[source,java]
----
include::{samples-dir}javaconfig/redis/src/main/java/sample/Initializer.java[tags=class]
include::{samples-dir}httpsession/src/main/java/sample/Initializer.java[tags=class]
----
NOTE: The name of our class (Initializer) does not matter. What is important is that we extend `AbstractHttpSessionApplicationInitializer`.
@@ -125,7 +125,7 @@ You can run the sample by obtaining the {download-url}[source code] and invoking
[NOTE]
====
For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
For the sample to work, you must http://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `LettuceConnectionFactory` to point to a Redis server.
====
@@ -151,7 +151,7 @@ We interact with the standard `HttpSession` in the `SessionServlet` shown below:
.src/main/java/sample/SessionServlet.java
[source,java]
----
include::{samples-dir}javaconfig/redis/src/main/java/sample/SessionServlet.java[tags=class]
include::{samples-dir}httpsession/src/main/java/sample/SessionServlet.java[tags=class]
----
Instead of using Tomcat's `HttpSession`, we are actually persisting the values in Redis.
@@ -162,10 +162,10 @@ If you like, you can easily remove the session using redis-cli. For example, on
$ redis-cli keys '*' | xargs redis-cli del
TIP: The Redis documentation has instructions for https://redis.io/topics/quickstart[installing redis-cli].
TIP: The Redis documentation has instructions for http://redis.io/topics/quickstart[installing redis-cli].
Alternatively, you can also delete the explicit key. Enter the following into your terminal ensuring to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your SESSION cookie:
$ redis-cli del spring:session:sessions:7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
Now visit the application at http://localhost:8080/ and observe that the attribute we added is no longer displayed.
Now visit the application at http://localhost:8080/ and observe that the attribute we added is no longer displayed.

View File

@@ -75,7 +75,7 @@ All you have to do is to add the following Spring Configuration:
[source,java]
----
include::{samples-dir}boot/mongo/src/main/java/sample/config/HttpSessionConfig.java[tags=class]
include::{samples-dir}mongo/src/main/java/sample/config/HttpSessionConfig.java[tags=class]
----
<1> The `@EnableMongoHttpSession` annotation creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements Filter.
@@ -100,7 +100,7 @@ spring.data.mongodb.port=27018
spring.data.mongodb.database=prod
----
For more information, refer to https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-connecting-to-mongodb[Connecting to MongoDB] portion of the Spring Boot documentation.
For more information, refer to http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-connecting-to-mongodb[Connecting to MongoDB] portion of the Spring Boot documentation.
[[boot-servlet-configuration]]
== Servlet Container Initialization

View File

@@ -80,7 +80,7 @@ Add the following Spring Configuration:
[source,java]
----
include::{samples-dir}javaconfig/rest/src/main/java/sample/HttpSessionConfig.java[tags=class]
include::{samples-dir}rest/src/main/java/sample/HttpSessionConfig.java[tags=class]
----
<1> The `@EnableRedisHttpSession` annotation creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements `Filter`.
@@ -88,7 +88,7 @@ The filter is what is in charge of replacing the `HttpSession` implementation to
In this instance Spring Session is backed by Redis.
<2> We create a `RedisConnectionFactory` that connects Spring Session to the Redis Server.
We configure the connection to connect to localhost on the default port (6379)
For more information on configuring Spring Data Redis, refer to the https://docs.spring.io/spring-data/data-redis/docs/current/reference/html/[reference documentation].
For more information on configuring Spring Data Redis, refer to the http://docs.spring.io/spring-data/data-redis/docs/current/reference/html/[reference documentation].
<3> We customize Spring Session's HttpSession integration to use HTTP headers to convey the current session information instead of cookies.
== Servlet Container Initialization
@@ -101,7 +101,7 @@ In order for our `Filter` to do its magic, Spring needs to load our `Config` cla
.src/main/java/sample/mvc/MvcInitializer.java
[source,java,indent=0]
----
include::{samples-dir}javaconfig/rest/src/main/java/sample/mvc/MvcInitializer.java[tags=config]
include::{samples-dir}rest/src/main/java/sample/mvc/MvcInitializer.java[tags=config]
----
Last we need to ensure that our Servlet Container (i.e. Tomcat) uses our `springSessionRepositoryFilter` for every request.
@@ -110,7 +110,7 @@ Fortunately, Spring Session provides a utility class named `AbstractHttpSessionA
.src/main/java/sample/Initializer.java
[source,java]
----
include::{samples-dir}javaconfig/rest/src/main/java/sample/Initializer.java[tags=class]
include::{samples-dir}rest/src/main/java/sample/Initializer.java[tags=class]
----
NOTE: The name of our class (Initializer) does not matter. What is important is that we extend `AbstractHttpSessionApplicationInitializer`.
@@ -126,7 +126,7 @@ You can run the sample by obtaining the {download-url}[source code] and invoking
[NOTE]
====
For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
For the sample to work, you must http://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `LettuceConnectionFactory` to point to a Redis server.
====
@@ -154,7 +154,7 @@ In the output you will notice the following:
----
HTTP/1.1 200 OK
...
X-Auth-Token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3
x-auth-token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3
{"username":"user"}
----
@@ -162,25 +162,25 @@ X-Auth-Token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3
Specifically, we notice the following things about our response:
* The HTTP Status is now a 200
* We have a header with the name of *X-Auth-Token* which contains a new session id
* We have a header with the name of *x-auth-token* which contains a new session id
* The current username is displayed
We can now use the *X-Auth-Token* to make another request without providing the username and password again. For example, the following outputs the username just as before:
We can now use the *x-auth-token* to make another request without providing the username and password again. For example, the following outputs the username just as before:
$ curl -v http://localhost:8080/ -H "X-Auth-Token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3"
$ curl -v http://localhost:8080/ -H "x-auth-token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3"
The only difference is that the session id is not provided in the response headers because we are reusing an existing session.
If we invalidate the session, then the X-Auth-Token is displayed in the response with an empty value. For example, the following will invalidate our session:
If we invalidate the session, then the x-auth-token is displayed in the response with an empty value. For example, the following will invalidate our session:
$ curl -v http://localhost:8080/logout -H "X-Auth-Token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3"
$ curl -v http://localhost:8080/logout -H "x-auth-token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3"
You will see in the output that the X-Auth-Token provides an empty String indicating that the previous session was invalidated.
You will see in the output that the x-auth-token provides an empty String indicating that the previous session was invalidated.
----
HTTP/1.1 204 No Content
...
X-Auth-Token:
x-auth-token:
----
=== How does it work?
@@ -188,7 +188,7 @@ X-Auth-Token:
Spring Security interacts with the standard `HttpSession` in `SecurityContextPersistenceFilter`.
Instead of using Tomcat's `HttpSession`, Spring Security is now persisting the values in Redis.
Spring Session creates a header named X-Auth-Token in your browser that contains the id of your session.
Spring Session creates a header named x-auth-token in your browser that contains the id of your session.
If you like, you can easily see that the session is created in Redis. First create a session using the following:
@@ -199,7 +199,7 @@ In the output you will notice the following:
----
HTTP/1.1 200 OK
...
X-Auth-Token: 7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
x-auth-token: 7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
{"username":"user"}
----
@@ -208,12 +208,12 @@ Now remove the session using redis-cli. For example, on a Linux based system you
$ redis-cli keys '*' | xargs redis-cli del
TIP: The Redis documentation has instructions for https://redis.io/topics/quickstart[installing redis-cli].
TIP: The Redis documentation has instructions for http://redis.io/topics/quickstart[installing redis-cli].
Alternatively, you can also delete the explicit key. Enter the following into your terminal ensuring to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your SESSION cookie:
$ redis-cli del spring:session:sessions:7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
We can now use the *X-Auth-Token* to make another request with the session we deleted and observe we are prompted for a authentication. For example, the following returns an HTTP 401:
We can now use the *x-auth-token* to make another request with the session we deleted and observe we are prompted for a authentication. For example, the following returns an HTTP 401:
$ curl -v http://localhost:8080/ -H "X-Auth-Token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3"
$ curl -v http://localhost:8080/ -H "x-auth-token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3"

View File

@@ -79,7 +79,7 @@ Add the following Spring Configuration:
[source,java]
----
include::{samples-dir}javaconfig/security/src/main/java/sample/Config.java[tags=class]
include::{samples-dir}security/src/main/java/sample/Config.java[tags=class]
----
<1> The `@EnableRedisHttpSession` annotation creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements Filter.
@@ -87,7 +87,7 @@ The filter is what is in charge of replacing the `HttpSession` implementation to
In this instance Spring Session is backed by Redis.
<2> We create a `RedisConnectionFactory` that connects Spring Session to the Redis Server.
We configure the connection to connect to localhost on the default port (6379)
For more information on configuring Spring Data Redis, refer to the https://docs.spring.io/spring-data/data-redis/docs/current/reference/html/[reference documentation].
For more information on configuring Spring Data Redis, refer to the http://docs.spring.io/spring-data/data-redis/docs/current/reference/html/[reference documentation].
== Servlet Container Initialization
@@ -100,7 +100,7 @@ Since our application is already loading Spring configuration using our `Securit
.src/main/java/sample/SecurityInitializer.java
[source,java]
----
include::{samples-dir}javaconfig/security/src/main/java/sample/SecurityInitializer.java[tags=class]
include::{samples-dir}security/src/main/java/sample/SecurityInitializer.java[tags=class]
----
Last we need to ensure that our Servlet Container (i.e. Tomcat) uses our `springSessionRepositoryFilter` for every request.
@@ -112,7 +112,7 @@ You can find an example below:
.src/main/java/sample/Initializer.java
[source,java]
----
include::{samples-dir}javaconfig/security/src/main/java/sample/Initializer.java[tags=class]
include::{samples-dir}security/src/main/java/sample/Initializer.java[tags=class]
----
NOTE: The name of our class (Initializer) does not matter. What is important is that we extend `AbstractHttpSessionApplicationInitializer`.
@@ -130,7 +130,7 @@ You can run the sample by obtaining the {download-url}[source code] and invoking
[NOTE]
====
For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
For the sample to work, you must http://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `LettuceConnectionFactory` to point to a Redis server.
====
@@ -164,10 +164,10 @@ If you like, you can easily remove the session using redis-cli. For example, on
$ redis-cli keys '*' | xargs redis-cli del
TIP: The Redis documentation has instructions for https://redis.io/topics/quickstart[installing redis-cli].
TIP: The Redis documentation has instructions for http://redis.io/topics/quickstart[installing redis-cli].
Alternatively, you can also delete the explicit key. Enter the following into your terminal ensuring to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your SESSION cookie:
$ redis-cli del spring:session:sessions:7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
Now visit the application at http://localhost:8080/ and observe that we are no longer authenticated.
Now visit the application at http://localhost:8080/ and observe that we are no longer authenticated.

View File

@@ -19,7 +19,7 @@ You can run the sample by obtaining the {download-url}[source code] and invoking
[NOTE]
====
For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
For the sample to work, you must http://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `LettuceConnectionFactory` to point to a Redis server.
====
@@ -99,7 +99,7 @@ We can obtain the `HttpSessionManager` from the `HttpServletRequest` using the f
.src/main/java/sample/UserAccountsFilter.java
[source,java,indent=0]
----
include::{samples-dir}javaconfig/users/src/main/java/sample/UserAccountsFilter.java[tags=HttpSessionManager]
include::{samples-dir}users/src/main/java/sample/UserAccountsFilter.java[tags=HttpSessionManager]
----
We can now use it to create a URL to add another session.
@@ -107,7 +107,7 @@ We can now use it to create a URL to add another session.
.src/main/java/sample/UserAccountsFilter.java
[source,java,indent=0]
----
include::{samples-dir}javaconfig/users/src/main/java/sample/UserAccountsFilter.java[tags=addAccountUrl]
include::{samples-dir}users/src/main/java/sample/UserAccountsFilter.java[tags=addAccountUrl]
----
<1> We have an existing variable named `unauthenticatedAlias`.
@@ -140,7 +140,7 @@ For example, if the URL is http://localhost:8080/?_s=1 this alias would be used.
The nice thing about specifying the session alias in the URL is that we can have multiple tabs open with different active sessions.
The bad thing is that we need to include the session alias in every URL of our application.
Fortunately, Spring Session will automatically include the session alias in any URL that passes through https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse.html#encodeURL(java.lang.String)[HttpServletResponse#encodeURL(java.lang.String)]
Fortunately, Spring Session will automatically include the session alias in any URL that passes through http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse.html#encodeURL(java.lang.String)[HttpServletResponse#encodeURL(java.lang.String)]
This means that if you are using standard tag libraries the session alias is automatically included in the URL.
For example, if we are currently using the session with the alias of *1*, then the following:
@@ -148,7 +148,7 @@ For example, if we are currently using the session with the alias of *1*, then t
.src/main/webapp/index.jsp
[source,xml,indent=0]
----
include::{samples-dir}javaconfig/users/src/main/webapp/index.jsp[tags=link]
include::{samples-dir}users/src/main/webapp/index.jsp[tags=link]
----
will output a link of:

View File

@@ -38,7 +38,7 @@ For example:
.src/main/java/samples/config/WebSocketConfig.java
[source,java]
----
include::{samples-dir}boot/websocket/src/main/java/sample/config/WebSocketConfig.java[tags=class]
include::{samples-dir}websocket/src/main/java/sample/config/WebSocketConfig.java[tags=class]
----
To hook in the Spring Session support we only need to change two things:
@@ -78,13 +78,13 @@ For the purposes of testing session expiration, you may want to change the sessi
.src/main/java/samples/config/WebSecurityConfig.java
[source,java]
----
include::{samples-dir}boot/websocket/src/main/java/sample/config/WebSecurityConfig.java[tags=enable-redis-httpsession]
include::{samples-dir}websocket/src/main/java/sample/config/WebSecurityConfig.java[tags=enable-redis-httpsession]
----
====
[NOTE]
====
For the sample to work, you must https://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
For the sample to work, you must http://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `LettuceConnectionFactory` to point to a Redis server.
====

View File

@@ -31,8 +31,8 @@ https://github.com/spring-projects/spring-session/milestone/18?closed=1[1.3.0.M2
https://github.com/spring-projects/spring-session/milestone/16?closed=1[1.3.0.RC1], and
https://github.com/spring-projects/spring-session/milestone/19?closed=1[1.3.0.RELEASE].
* First class support for https://docs.spring.io/spring-session/docs/1.3.0.RELEASE/reference/html5/#httpsession-hazelcast[Hazelcast]
* First class support for https://docs.spring.io/spring-session/docs/1.3.0.RELEASE/reference/html5/#spring-security-concurrent-sessions-how[Spring Security's concurrent session management]
* First class support for http://docs.spring.io/spring-session/docs/1.3.0.RELEASE/reference/html5/#httpsession-hazelcast[Hazelcast]
* First class support for http://docs.spring.io/spring-session/docs/1.3.0.RELEASE/reference/html5/#spring-security-concurrent-sessions-how[Spring Security's concurrent session management]
* Added https://github.com/maseev/spring-session-orientdb[OrientDB Community Extension]
* https://github.com/spring-projects/spring-session/tree/1.3.0.RELEASE/samples/httpsession-redis-json[GenericJackson2JsonRedisSerializer sample] with Spring Security's new Jackson Support
* Guides now https://github.com/spring-projects/spring-session/pull/652[use Lettuce]
@@ -44,116 +44,96 @@ https://github.com/spring-projects/spring-session/milestone/19?closed=1[1.3.0.RE
If you are looking to get started with Spring Session, the best place to start is our Sample Applications.
.Sample Applications using Spring Boot
.Sample Applications
|===
| Source | Description | Guide
| {gh-samples-url}boot/redis[HttpSession with Redis]
| Demonstrates how to use Spring Session to replace the `HttpSession` with Redis.
| link:guides/boot-redis.html[HttpSession with Redis Guide]
| {gh-samples-url}boot/gemfire[HttpSession with GemFire]
| Demonstrates how to use Spring Session to replace the `HttpSession` with GemFire using a Client/Server topology.
| link:guides/boot-gemfire.html[HttpSession with GemFire Guide]
| {gh-samples-url}boot/mongo[HttpSession with Mongo]
| Demonstrates how to use Spring Session to replace the `HttpSession` with Mongo.
| link:guides/boot-mongo.html[HttpSession with Mongo Guide]
| {gh-samples-url}boot/jdbc[HttpSession with JDBC]
| Demonstrates how to use Spring Session to replace the `HttpSession` with a relational database store.
| link:guides/boot-jdbc.html[HttpSession with JDBC Guide]
| {gh-samples-url}boot/findbyusername[Find by Username]
| Demonstrates how to use Spring Session to find sessions by username.
| link:guides/boot-findbyusername.html[Find by Username Guide]
| {gh-samples-url}boot/websocket[WebSockets]
| Demonstrates how to use Spring Session with WebSockets.
| link:guides/boot-websocket.html[WebSockets Guide]
| {gh-samples-url}boot/redis-json[HttpSession with Redis JSON serialization]
| Demonstrates how to use Spring Session to replace the `HttpSession` with Redis using JSON serialization.
| TBD
|===
.Sample Applications using Spring Java based configuration
|===
| Source | Description | Guide
| {gh-samples-url}javaconfig/redis[HttpSession with Redis]
| Demonstrates how to use Spring Session to replace the `HttpSession` with Redis.
| link:guides/java-redis.html[HttpSession with Redis Guide]
| {gh-samples-url}javaconfig/gemfire-clientserver[HttpSession with GemFire (Client/Server)]
| Demonstrates how to use Spring Session to replace the `HttpSession` with GemFire using a Client/Server topology.
| link:guides/java-gemfire-clientserver.html[HttpSession with GemFire (Client/Server) Guide]
| {gh-samples-url}javaconfig/gemfire-p2p[HttpSession with GemFire (P2P)]
| Demonstrates how to use Spring Session to replace the `HttpSession` with GemFire using a P2P topology.
| link:guides/java-gemfire-p2p.html[HttpSession with GemFire (P2P) Guide]
| {gh-samples-url}javaconfig/jdbc[HttpSession with JDBC]
| Demonstrates how to use Spring Session to replace the `HttpSession` with a relational database store.
| link:guides/java-jdbc.html[HttpSession with JDBC Guide]
| {gh-samples-url}javaconfig/hazelcast[HttpSession with Hazelcast]
| Demonstrates how to use Spring Session to replace the `HttpSession` with Hazelcast.
| link:guides/java-hazelcast.html[HttpSession with Hazelcast Guide]
| {gh-samples-url}javaconfig/custom-cookie[Custom Cookie]
| Demonstrates how to use Spring Session and customize the cookie.
| link:guides/java-custom-cookie.html[Custom Cookie Guide]
| {gh-samples-url}javaconfig/security[Spring Security]
| Demonstrates how to use Spring Session with an existing Spring Security application.
| link:guides/java-security.html[Spring Security Guide]
| {gh-samples-url}javaconfig/rest[REST]
| Demonstrates how to use Spring Session in a REST application to support authenticating with a header.
| link:guides/java-rest.html[REST Guide]
| {gh-samples-url}javaconfig/users[Multiple Users]
| Demonstrates how to use Spring Session to manage multiple simultaneous browser sessions (i.e Google Accounts).
| link:guides/java-users.html[Multiple Users Guide]
|===
.Sample Applications using Spring XML based configuration
|===
| Source | Description | Guide
| {gh-samples-url}xml/redis[HttpSession with Redis]
| {gh-samples-url}httpsession[HttpSession]
| Demonstrates how to use Spring Session to replace the `HttpSession` with a Redis store.
| link:guides/xml-redis.html[HttpSession with Redis Guide]
| link:guides/httpsession.html[HttpSession Guide]
| {gh-samples-url}xml/gemfire-clientserver[HttpSession with GemFire (Client/Server)]
| {gh-samples-url}httpsession-xml[HttpSession XML]
| Demonstrates how to use Spring Session to replace the `HttpSession` with a Redis store using XML based configuration.
| link:guides/httpsession-xml.html[HttpSession XML Guide]
| {gh-samples-url}httpsession-gemfire-boot[HttpSession with GemFire using Spring Boot]
| Demonstrates how to use Spring Session to replace the `HttpSession` with GemFire using a Client/Server topology in a Spring Boot application.
| link:guides/httpsession-gemfire-boot.html[HttpSession GemFire Boot Guide]
| {gh-samples-url}httpsession-gemfire-clientserver[HttpSession with GemFire (Client/Server)]
| Demonstrates how to use Spring Session to replace the `HttpSession` with GemFire using a Client/Server topology.
| link:guides/xml-gemfire-clientserver.html[HttpSession with GemFire (Client/Server) Guide]
| link:guides/httpsession-gemfire-clientserver.html[HttpSession GemFire Client/Server Guide]
| {gh-samples-url}xml/gemfire-p2p[HttpSession with GemFire (P2P)]
| {gh-samples-url}httpsession-gemfire-clientserver-xml[HttpSession with GemFire (Client/Server) using XML]
| Demonstrates how to use Spring Session to replace the `HttpSession` with GemFire using a Client/Server topology configured with XML.
| link:guides/httpsession-gemfire-clientserver-xml.html[HttpSession GemFire Client/Server XML Guide]
| {gh-samples-url}httpsession-gemfire-p2p[HttpSession with GemFire (P2P)]
| Demonstrates how to use Spring Session to replace the `HttpSession` with GemFire using a P2P topology.
| link:guides/xml-gemfire-p2p.html[HttpSession with GemFire (P2P) Guide]
| link:guides/httpsession-gemfire-p2p.html[HttpSession GemFire P2P Guide]
| {gh-samples-url}xml/jdbc[HttpSession with JDBC]
| Demonstrates how to use Spring Session to replace the `HttpSession` with a relational database store.
| link:guides/xml-jdbc.html[HttpSession with JDBC Guide]
| {gh-samples-url}httpsession-gemfire-p2p-xml[HttpSession with GemFire (P2P) using XML]
| Demonstrates how to use Spring Session to replace the `HttpSession` with GemFire using a P2P topology configured with XML.
| link:guides/httpsession-gemfire-p2p-xml.html[HttpSession GemFire P2P XML Guide]
|===
| {gh-samples-url}custom-cookie[Custom Cookie]
| Demonstrates how to use Spring Session and customize the cookie.
| link:guides/custom-cookie.html[Custom Cookie Guide]
.Misc sample Applications
|===
| Source | Description | Guide
| {gh-samples-url}boot[Spring Boot]
| Demonstrates how to use Spring Session with Spring Boot.
| link:guides/boot.html[Spring Boot Guide]
| {gh-samples-url}misc/grails3[Grails 3]
| {gh-samples-url}grails3[Grails 3]
| Demonstrates how to use Spring Session with Grails 3.
| link:guides/grails3.html[Grails 3 Guide]
| {gh-samples-url}misc/hazelcast[Hazelcast]
| Demonstrates how to use Spring Session with Hazelcast in a Java EE application.
| {gh-samples-url}security[Spring Security]
| Demonstrates how to use Spring Session with an existing Spring Security application.
| link:guides/security.html[Spring Security Guide]
| {gh-samples-url}rest[REST]
| Demonstrates how to use Spring Session in a REST application to support authenticating with a header.
| link:guides/rest.html[REST Guide]
| {gh-samples-url}findbyusername[Find by Username]
| Demonstrates how to use Spring Session to find sessions by username.
| link:guides/findbyusername.html[Find by Username]
| {gh-samples-url}users[Multiple Users]
| Demonstrates how to use Spring Session to manage multiple simultaneous browser sessions (i.e Google Accounts).
| link:guides/users.html[Manage Multiple Users Guide]
| {gh-samples-url}websocket[WebSocket]
| Demonstrates how to use Spring Session with WebSockets.
| link:guides/websocket.html[WebSocket Guide]
| {gh-samples-url}mongo[Mongo]
| Demonstrates how to use Spring Session with Mongo.
| link:guides/mongo.html[Mongo Guide]
[[samples-hazelcast]]
| {gh-samples-url}hazelcast[Hazelcast]
| Demonstrates how to use Spring Session with Hazelcast.
| TBD
[[samples-hazelcast-spring]]
| {gh-samples-url}hazelcast-spring[Hazelcast Spring]
| Demonstrates how to use Spring Session and Hazelcast with an existing Spring Security application.
| link:guides/hazelcast-spring.html[Hazelcast Spring Guide]
| {gh-samples-url}httpsession-jdbc[HttpSession JDBC]
| Demonstrates how to use Spring Session to replace the `HttpSession` with a relational database store.
| link:guides/httpsession-jdbc.html[HttpSession JDBC Guide]
| {gh-samples-url}httpsession-jdbc-xml[HttpSession JDBC XML]
| Demonstrates how to use Spring Session to replace the `HttpSession` with a relational database store using XML based configuration.
| link:guides/httpsession-jdbc-xml.html[HttpSession JDBC XML Guide]
| {gh-samples-url}httpsession-jdbc-boot[HttpSession JDBC Spring Boot]
| Demonstrates how to use Spring Session to replace the `HttpSession` with a relational database store when using Spring Boot.
| link:guides/httpsession-jdbc-boot.html[HttpSession JDBC Spring Boot Guide]
|===
[[httpsession]]
@@ -188,7 +168,7 @@ This section describes how to use Redis to back `HttpSession` using Java based c
NOTE: The <<samples, HttpSession Sample>> provides a working sample on how to integrate Spring Session and `HttpSession` using Java configuration.
You can read the basic steps for integration below, but you are encouraged to follow along with the detailed HttpSession Guide when integrating with your own application.
include::guides/java-redis.adoc[tags=config,leveloffset=+3]
include::guides/httpsession.adoc[tags=config,leveloffset=+3]
[[httpsession-redis-xml]]
==== Redis XML Based Configuration
@@ -198,7 +178,7 @@ This section describes how to use Redis to back `HttpSession` using XML based co
NOTE: The <<samples, HttpSession XML Sample>> provides a working sample on how to integrate Spring Session and `HttpSession` using XML configuration.
You can read the basic steps for integration below, but you are encouraged to follow along with the detailed HttpSession XML Guide when integrating with your own application.
include::guides/xml-redis.adoc[tags=config,leveloffset=+3]
include::guides/httpsession-xml.adoc[tags=config,leveloffset=+3]
[[httpsession-gemfire]]
=== HttpSession with Pivotal GemFire
@@ -212,14 +192,14 @@ 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 https://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 https://docs.spring.io/spring-data-gemfire/docs/current/reference/html/#bootstrap:gateway[here].
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].
[[httpsession-gemfire-clientserver]]
==== GemFire Client-Server
The https://gemfire.docs.pivotal.io/docs-gemfire/latest/topologies_and_comm/cs_configuration/chapter_overview.html[Client-Server]
The http://gemfire.docs.pivotal.io/docs-gemfire/latest/topologies_and_comm/cs_configuration/chapter_overview.html[Client-Server]
topology will probably be the more common configuration preference for users when using GemFire as a provider in
Spring Session since a GemFire server will have significantly different and unique JVM heap requirements when compared
to the application. Using a client-server topology enables an application to manage (e.g. replicate) application state
@@ -243,7 +223,7 @@ Spring Session and GemFire to replace the HttpSession using Java configuration.
integration below, but you are encouraged to follow along with the detailed HttpSession with GemFire (Client-Server)
Guide when integrating with your own application.
include::guides/java-gemfire-clientserver.adoc[tags=config,leveloffset=+3]
include::guides/httpsession-gemfire-clientserver.adoc[tags=config,leveloffset=+3]
[[http-session-gemfire-clientserver-xml]]
===== GemFire Client-Server XML-based Configuration
@@ -255,20 +235,20 @@ integrate Spring Session and GemFire to replace the `HttpSession` using XML conf
for integration below, but you are encouraged to follow along with the detailed HttpSession with GemFire (Client-Server)
using XML Guide when integrating with your own application.
include::guides/xml-gemfire-clientserver.adoc[tags=config,leveloffset=+3]
include::guides/httpsession-gemfire-clientserver-xml.adoc[tags=config,leveloffset=+3]
[[httpsession-gemfire-p2p]]
==== GemFire Peer-To-Peer (P2P)
Perhaps less common would be to configure the Spring Session application as a peer member in the GemFire cluster using
the https://gemfire.docs.pivotal.io/docs-gemfire/latest/topologies_and_comm/p2p_configuration/chapter_overview.html[Peer-To-Peer (P2P)] topology.
the http://gemfire.docs.pivotal.io/docs-gemfire/latest/topologies_and_comm/p2p_configuration/chapter_overview.html[Peer-To-Peer (P2P)] topology.
In this configuration, a Spring Session application would be an actual data node (server) in the GemFire cluster,
and **not** a cache client as before.
One advantage to this approach is the proximity of the application to the application's state (i.e. it's data). However,
there are other effective means of accomplishing similar data dependent computations, such as using GemFire's
https://gemfire.docs.pivotal.io/docs-gemfire/latest/developing/function_exec/chapter_overview.html[Function Execution].
Any of GemFire's other https://gemfire.docs.pivotal.io/docs-gemfire/latest/getting_started/product_intro.html[features]
http://gemfire.docs.pivotal.io/docs-gemfire/latest/developing/function_exec/chapter_overview.html[Function Execution].
Any of GemFire's other http://gemfire.docs.pivotal.io/docs-gemfire/latest/getting_started/product_intro.html[features]
can be used when GemFire is serving as a provider in Spring Session.
P2P is very useful for both testing purposes as well as smaller, more focused and self-contained applications,
@@ -290,7 +270,7 @@ Spring Session and GemFire to replace the `HttpSession` using Java configuration
for integration below, but you are encouraged to follow along with the detailed HttpSession with GemFire (P2P) Guide
when integrating with your own application.
include::guides/java-gemfire-p2p.adoc[tags=config,leveloffset=+3]
include::guides/httpsession-gemfire-p2p.adoc[tags=config,leveloffset=+3]
[[httpsession-gemfire-p2p-xml]]
===== GemFire Peer-To-Peer (P2P) XML-based Configuration
@@ -302,7 +282,7 @@ Spring Session and GemFire to replace the `HttpSession` using XML configuration.
integration below, but you are encouraged to follow along with the detailed HttpSession with GemFire (P2P) using XML
Guide when integrating with your own application.
include::guides/xml-gemfire-p2p.adoc[tags=config,leveloffset=+3]
include::guides/httpsession-gemfire-p2p-xml.adoc[tags=config,leveloffset=+3]
[[httpsession-jdbc]]
=== HttpSession with JDBC
@@ -322,7 +302,7 @@ This section describes how to use a relational database to back `HttpSession` us
NOTE: The <<samples, HttpSession JDBC Sample>> provides a working sample on how to integrate Spring Session and `HttpSession` using Java configuration.
You can read the basic steps for integration below, but you are encouraged to follow along with the detailed HttpSession JDBC Guide when integrating with your own application.
include::guides/java-jdbc.adoc[tags=config,leveloffset=+3]
include::guides/httpsession-jdbc.adoc[tags=config,leveloffset=+3]
[[httpsession-jdbc-xml]]
==== JDBC XML Based Configuration
@@ -332,7 +312,7 @@ This section describes how to use a relational database to back `HttpSession` us
NOTE: The <<samples, HttpSession JDBC XML Sample>> provides a working sample on how to integrate Spring Session and `HttpSession` using XML configuration.
You can read the basic steps for integration below, but you are encouraged to follow along with the detailed HttpSession JDBC XML Guide when integrating with your own application.
include::guides/xml-jdbc.adoc[tags=config,leveloffset=+3]
include::guides/httpsession-jdbc-xml.adoc[tags=config,leveloffset=+3]
[[httpsession-jdbc-boot]]
==== JDBC Spring Boot Based Configuration
@@ -342,7 +322,7 @@ This section describes how to use a relational database to back `HttpSession` wh
NOTE: The <<samples, HttpSession JDBC Spring Boot Sample>> provides a working sample on how to integrate Spring Session and `HttpSession` using Spring Boot.
You can read the basic steps for integration below, but you are encouraged to follow along with the detailed HttpSession JDBC Spring Boot Guide when integrating with your own application.
include::guides/boot-jdbc.adoc[tags=config,leveloffset=+3]
include::guides/httpsession-jdbc-boot.adoc[tags=config,leveloffset=+3]
[[httpsession-mongo]]
=== HttpSession with Mongo
@@ -354,7 +334,7 @@ This section describes how to use Mongo to back `HttpSession` using Java based c
NOTE: The <<samples, HttpSession Mongo Sample>> provides a working sample on how to integrate Spring Session and `HttpSession` using Java configuration.
You can read the basic steps for integration below, but you are encouraged to follow along with the detailed HttpSession Guide when integrating with your own application.
include::guides/boot-mongo.adoc[tags=config,leveloffset=+3]
include::guides/mongo.adoc[tags=config,leveloffset=+3]
==== Session serialization mechanisms
@@ -405,7 +385,7 @@ This section describes how to use Hazelcast to back `HttpSession` using Java bas
NOTE: The <<samples, Hazelcast Spring Sample>> provides a working sample on how to integrate Spring Session and `HttpSession` using Java configuration.
You can read the basic steps for integration below, but you are encouraged to follow along with the detailed Hazelcast Spring Guide when integrating with your own application.
include::guides/java-hazelcast.adoc[tags=config,leveloffset=+2]
include::guides/hazelcast-spring.adoc[tags=config,leveloffset=+2]
[[httpsession-how]]
=== How HttpSession Integration Works
@@ -472,7 +452,7 @@ This provides the ability to support authenticating with multiple users in the s
NOTE: The <<samples,Manage Multiple Users Guide>> provides a complete working example of managing multiple users in the same browser instance.
You can follow the basic steps for integration below, but you are encouraged to follow along with the detailed Manage Multiple Users Guide when integrating with your own application.
include::guides/java-users.adoc[tags=how-does-it-work,leveloffset=+1]
include::guides/users.adoc[tags=how-does-it-work,leveloffset=+1]
[[httpsession-rest]]
=== HttpSession & RESTful APIs
@@ -483,7 +463,7 @@ Spring Session can work with RESTful APIs by allowing the session to be provided
NOTE: The <<samples, REST Sample>> provides a working sample on how to use Spring Session in a REST application to support authenticating with a header.
You can follow the basic steps for integration below, but you are encouraged to follow along with the detailed REST Guide when integrating with your own application.
include::guides/java-rest.adoc[tags=config,leveloffset=+2]
include::guides/rest.adoc[tags=config,leveloffset=+2]
[[httpsession-httpsessionlistener]]
=== HttpSessionListener
@@ -516,7 +496,7 @@ include::{docs-test-resources-dir}docs/http/HttpSessionListenerXmlTests-context.
Spring Session provides transparent integration with Spring's WebSocket support.
include::guides/boot-websocket.adoc[tags=disclaimer,leveloffset=+1]
include::guides/websocket.adoc[tags=disclaimer,leveloffset=+1]
[[websocket-why]]
=== Why Spring Session & WebSockets?
@@ -542,7 +522,7 @@ You can follow the basic steps for integration below, but you are encouraged to
Before using WebSocket integration, you should be sure that you have <<httpsession>> working first.
include::guides/boot-websocket.adoc[tags=config,leveloffset=+2]
include::guides/websocket.adoc[tags=config,leveloffset=+2]
[[spring-security]]
== Spring Security Integration
@@ -552,7 +532,7 @@ Spring Session provides integration with Spring Security.
[[spring-security-rememberme]]
=== Spring Security Remember-Me Support
Spring Session provides integration with https://docs.spring.io/spring-security/site/docs/4.2.x/reference/htmlsingle/#remember-me[Spring Security's Remember-Me Authentication].
Spring Session provides integration with http://docs.spring.io/spring-security/site/docs/4.2.x/reference/htmlsingle/#remember-me[Spring Security's Remember-Me Authentication].
The support will:
* Change the session expiration length
@@ -757,7 +737,7 @@ You can customize the serialization by creating a Bean named `springSessionDefau
`RedisOperationsSessionRepository` is subscribed to receive events from redis using a `RedisMessageListenerContainer`.
You can customize the way those events are dispatched, by creating a Bean named `springSessionRedisTaskExecutor` and/or a Bean `springSessionRedisSubscriptionExecutor`.
More details on configuring redis task executors can be found https://docs.spring.io/spring-data-redis/docs/current/reference/html/#redis:pubsub:subscribe:containers[here].
More details on configuring redis task executors can be found http://docs.spring.io/spring-data-redis/docs/current/reference/html/#redis:pubsub:subscribe:containers[here].
[[api-redisoperationssessionrepository-storage]]
==== Storage Details
@@ -836,7 +816,7 @@ The `SessionRepository.getSession(String)` method ensures that no expired sessio
This means there is no need to check the expiration before using a session.
====
Spring Session relies on the delete and expired https://redis.io/topics/notifications[keyspace notifications] from Redis to fire a <<api-redisoperationssessionrepository-sessiondestroyedevent,SessionDeletedEvent>> and <<api-redisoperationssessionrepository-sessiondestroyedevent,SessionExpiredEvent>> respectively.
Spring Session relies on the delete and expired http://redis.io/topics/notifications[keyspace notifications] from Redis to fire a <<api-redisoperationssessionrepository-sessiondestroyedevent,SessionDeletedEvent>> and <<api-redisoperationssessionrepository-sessiondestroyedevent,SessionExpiredEvent>> respectively.
It is the `SessionDeletedEvent` or `SessionExpiredEvent` that ensures resources associated with the Session are cleaned up.
For example, when using Spring Session's WebSocket support the Redis expired or delete event is what triggers any WebSocket connections associated with the session to be closed.
@@ -849,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 https://redis.io/topics/notifications[Timing of expired events] section in the Redis documentation.
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.
@@ -866,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]
====
@@ -886,7 +866,7 @@ This is necessary to ensure resources associated with the `Session` are properly
For example, when integrating with WebSockets the `SessionDestroyedEvent` is in charge of closing any active WebSocket connections.
Firing `SessionDeletedEvent` or `SessionExpiredEvent` is made available through the `SessionMessageListener` which listens to https://redis.io/topics/notifications[Redis Keyspace events].
Firing `SessionDeletedEvent` or `SessionExpiredEvent` is made available through the `SessionMessageListener` which listens to http://redis.io/topics/notifications[Redis Keyspace events].
In order for this to work, Redis Keyspace events for Generic commands and Expired events needs to be enabled.
For example:
@@ -925,7 +905,7 @@ If registered as a MessageListener (default), then `RedisOperationsSessionReposi
[[api-redisoperationssessionrepository-cli]]
==== Viewing the Session in Redis
After https://redis.io/topics/quickstart[installing redis-cli], you can inspect the values in Redis https://redis.io/commands#hash[using the redis-cli].
After http://redis.io/topics/quickstart[installing redis-cli], you can inspect the values in Redis http://redis.io/commands#hash[using the redis-cli].
For example, enter the following into a terminal:
[source,bash]
@@ -1030,9 +1010,9 @@ Session attribute a value that is not `Comparable` and the Session is saved to G
NOTE: Any Session attribute that is not indexed may store non-`Comparable` values.
To learn more about GemFire's Range-based Indexes, see https://gemfire.docs.pivotal.io/docs-gemfire/latest/developing/query_index/creating_map_indexes.html[Creating Indexes on Map Fields].
To learn more about GemFire's Range-based Indexes, see http://gemfire.docs.pivotal.io/docs-gemfire/latest/developing/query_index/creating_map_indexes.html[Creating Indexes on Map Fields].
To learn more about GemFire Indexing in general, see https://gemfire.docs.pivotal.io/docs-gemfire/latest/developing/query_index/query_index.html[Working with Indexes].
To learn more about GemFire Indexing in general, see http://gemfire.docs.pivotal.io/docs-gemfire/latest/developing/query_index/query_index.html[Working with Indexes].
[[api-mapsessionrepository]]
@@ -1086,7 +1066,7 @@ A typical example of how to create a new instance can be seen below:
include::{indexdoc-tests}[tags=new-jdbcoperationssessionrepository]
----
For additional information on how to create and configure `JdbcTemplate` and `PlatformTransactionManager`, refer to the https://docs.spring.io/spring/docs/current/spring-framework-reference/html/spring-data-tier.html[Spring Framework Reference Documentation].
For additional information on how to create and configure `JdbcTemplate` and `PlatformTransactionManager`, refer to the http://docs.spring.io/spring/docs/current/spring-framework-reference/html/spring-data-tier.html[Spring Framework Reference Documentation].
[[api-jdbcoperationssessionrepository-config]]
==== EnableJdbcHttpSession
@@ -1153,16 +1133,26 @@ A typical example of how to create a new instance can be seen below:
include::{indexdoc-tests}[tags=new-hazelcastsessionrepository]
----
For additional information on how to create and configure Hazelcast instance, refer to the https://docs.hazelcast.org/docs/latest/manual/html-single/index.html#hazelcast-configuration[Hazelcast documentation].
For additional information on how to create and configure Hazelcast instance, refer to the http://docs.hazelcast.org/docs/latest/manual/html-single/index.html#hazelcast-configuration[Hazelcast documentation].
[[api-enablehazelcasthttpsession]]
==== EnableHazelcastHttpSession
If you wish to use https://hazelcast.org/[Hazelcast] as your backing source for the `SessionRepository`, then the `@EnableHazelcastHttpSession` annotation
If you wish to use http://hazelcast.org/[Hazelcast] as your backing source for the `SessionRepository`, then the `@EnableHazelcastHttpSession` annotation
can be added to an `@Configuration` class. This extends the functionality provided by the `@EnableSpringHttpSession` annotation but makes the `SessionRepository` for you in Hazelcast.
You must provide a single `HazelcastInstance` bean for the configuration to work.
Complete configuration example can be found in the <<samples>>
[[api-enablehazelcasthttpsession-storage]]
==== Storage Details
Sessions will be stored in a distributed `IMap` in Hazelcast using a <<api-mapsessionrepository,MapSessionRepository>>.
The `IMap` interface methods will be used to `get()` and `put()` Sessions.
Additionally, `values()` method is used to support `FindByIndexNameSessionRepository#findByIndexNameAndIndexValue` operation, together with appropriate `ValueExtractor` that needs to be registered with Hazelcast. Refer to <<samples, Hazelcast Spring Sample>> for more details on this configuration.
The expiration of a session in the `IMap` is handled by Hazelcast's support for setting the time to live on an entry when it is `put()` into the `IMap`. Entries (sessions) that have been idle longer than the time to live will be automatically removed from the `IMap`.
You shouldn't need to configure any settings such as `max-idle-seconds` or `time-to-live-seconds` for the `IMap` within the Hazelcast configuration.
[[api-enablehazelcasthttpsession-customize]]
==== Basic Customization
You can use the following attributes on `@EnableHazelcastHttpSession` to customize the configuration:
@@ -1173,22 +1163,7 @@ You can use the following attributes on `@EnableHazelcastHttpSession` to customi
[[api-enablehazelcasthttpsession-events]]
==== Session Events
Using a `MapListener` to respond to entries being added, evicted, and removed from the distributed `Map`, these events will trigger
publishing `SessionCreatedEvent`, `SessionExpiredEvent`, and `SessionDeletedEvent` events respectively using the `ApplicationEventPublisher`.
[[api-enablehazelcasthttpsession-storage]]
==== Storage Details
Sessions will be stored in a distributed `IMap` in Hazelcast.
The `IMap` interface methods will be used to `get()` and `put()` Sessions.
Additionally, `values()` method is used to support `FindByIndexNameSessionRepository#findByIndexNameAndIndexValue` operation, together with appropriate `ValueExtractor` that needs to be registered with Hazelcast. Refer to <<samples, Hazelcast Spring Sample>> for more details on this configuration.
The expiration of a session in the `IMap` is handled by Hazelcast's support for setting the time to live on an entry when it is `put()` into the `IMap`. Entries (sessions) that have been idle longer than the time to live will be automatically removed from the `IMap`.
You shouldn't need to configure any settings such as `max-idle-seconds` or `time-to-live-seconds` for the `IMap` within the Hazelcast configuration.
Note that if you use Hazelcast's `MapStore` to persist your sessions `IMap` there are some limitations when reloading the sessions from `MapStore`:
* reload triggers `EntryAddedListener` which results in `SessionCreatedEvent` being re-published
* reload uses default TTL for a given `IMap` which results in sessions losing their original TTL
publishing SessionCreatedEvent, SessionExpiredEvent, and SessionDeletedEvent events respectively using the `ApplicationEventPublisher`.
[[community]]
== Spring Session Community
@@ -1199,7 +1174,7 @@ Please find additional information below.
[[community-support]]
=== Support
You can get help by asking questions on https://stackoverflow.com/questions/tagged/spring-session[StackOverflow with the tag spring-session].
You can get help by asking questions on http://stackoverflow.com/questions/tagged/spring-session[StackOverflow with the tag spring-session].
Similarly we encourage helping others by answering questions on StackOverflow.
[[community-source]]
@@ -1220,12 +1195,21 @@ We appreciate https://help.github.com/articles/using-pull-requests/[Pull Request
[[community-license]]
=== License
Spring Session is Open Source software released under the https://www.apache.org/licenses/LICENSE-2.0.html[Apache 2.0 license].
Spring Session is Open Source software released under the http://www.apache.org/licenses/LICENSE-2.0.html[Apache 2.0 license].
[[community-extensions]]
=== Community Extensions
https://github.com/maseev/spring-session-orientdb[Spring Session OrientDB]
https://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

View File

@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -71,6 +71,8 @@ public class AbstractGemFireIntegrationTests {
protected static final boolean GEMFIRE_QUERY_DEBUG = Boolean
.getBoolean("spring.session.data.gemfire.query.debug");
protected static final int DEFAULT_GEMFIRE_SERVER_PORT = CacheServer.DEFAULT_PORT;
protected static final long DEFAULT_WAIT_DURATION = TimeUnit.SECONDS.toMillis(20);
protected static final long DEFAULT_WAIT_INTERVAL = 500L;
@@ -80,7 +82,7 @@ public class AbstractGemFireIntegrationTests {
protected static final String DEFAULT_PROCESS_CONTROL_FILENAME = "process.ctl";
protected static final String GEMFIRE_LOG_FILE_NAME = System
.getProperty("spring.session.data.gemfire.log-file", "gemfire-server.log");
.getProperty("spring.session.data.gemfire.log-file", "server.log");
@Autowired
protected Cache gemfireCache;

View File

@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,

View File

@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,

View File

@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,

View File

@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,

View File

@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,

View File

@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,

View File

@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,

View File

@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,

View File

@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,

View File

@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,

View File

@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,

View File

@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,

View File

@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,

View File

@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,

View File

@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,

View File

@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,

View File

@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,

View File

@@ -1,11 +1,11 @@
/*
* 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -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

View File

@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,

View File

@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -33,23 +33,20 @@ import org.springframework.session.security.SpringSessionBackedSessionRegistry;
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private FindByIndexNameSessionRepository<ExpiringSession> sessionRepository;
FindByIndexNameSessionRepository<ExpiringSession> sessionRepository;
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
// other config goes here...
.sessionManagement()
.maximumSessions(2)
.sessionRegistry(sessionRegistry());
// @formatter:on
}
@Bean
SpringSessionBackedSessionRegistry sessionRegistry() {
return new SpringSessionBackedSessionRegistry<ExpiringSession>(
this.sessionRepository);
return new SpringSessionBackedSessionRegistry(this.sessionRepository);
}
}
// end::class[]

View File

@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,

View File

@@ -4,9 +4,9 @@
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util-4.1.xsd">
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd">
<context:annotation-config/>

View File

@@ -4,9 +4,9 @@
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util-4.1.xsd">
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd">
<!-- tag::config[] -->
<bean class="org.springframework.security.web.session.HttpSessionEventPublisher"/>

View File

@@ -3,8 +3,8 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- tag::config[] -->
<security:http>

View File

@@ -2,8 +2,8 @@
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd">
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
<!-- tag::config[] -->
<security:http>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"https://www.puppycrawl.com/dtds/configuration_1_3.dtd">
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
<module name="Checker">
<!-- Suppressions -->
<module name="SuppressionFilter">

View File

@@ -5,7 +5,7 @@
^\Q * you may not use this file except in compliance with the License.\E$
^\Q * You may obtain a copy of the License at\E$
^\Q *\E$
^\Q * https://www.apache.org/licenses/LICENSE-2.0\E$
^\Q * http://www.apache.org/licenses/LICENSE-2.0\E$
^\Q *\E$
^\Q * Unless required by applicable law or agreed to in writing, software\E$
^\Q * distributed under the License is distributed on an "AS IS" BASIS,\E$

View File

@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC "-//Puppy Crawl//DTD Suppressions 1.1//EN"
"https://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
"http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
<suppressions>
<suppress files=".+Application\.java" checks="HideUtilityClassConstructor"/>
<suppress files=".+Configuration\.java" checks="HideUtilityClassConstructor"/>

View File

@@ -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

View File

@@ -1,30 +1,31 @@
assertjVersion=2.6.0
bootstrapVersion=2.3.2
commonsLoggingVersion=1.2
commonsPoolVersion=2.4.2
gebVersion=0.13.1
groovyVersion=2.4.11
h2Version=1.4.195
hazelcastVersion=3.7.7
httpClientVersion=4.5.3
html5ShivVersion=3.7.3
jacksonVersion=2.8.8
jedisVersion=2.9.0
jspApiVersion=2.0
jstlVersion=1.2.1
jstlelVersion=1.2.5
junitVersion=4.12
lettuceVersion=4.3.0.Final
mockitoVersion=1.10.19
seleniumVersion=2.52.0
servletApiVersion=3.0.1
springVersion=4.3.9.RELEASE
springDataGemFireVersion=1.9.4.RELEASE
jstlelVersion=1.2.5
version=1.3.4.RELEASE
springDataRedisVersion=1.7.11.RELEASE
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.8
seleniumVersion=2.52.0
springDataGeodeVersion=1.0.0.INCUBATING-RELEASE
springDataMongoVersion=1.10.4.RELEASE
springDataRedisVersion=1.8.4.RELEASE
springSecurityVersion=4.2.3.RELEASE
springSecurityVersion=4.2.8.RELEASE
springVersion=4.3.9.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.4.0.BUILD-SNAPSHOT
jstlVersion=1.2.1
groovyVersion=2.4.11

View File

@@ -5,12 +5,6 @@ import org.gradle.plugins.ide.eclipse.model.SourceFolder
apply plugin: "propdeps-eclipse"
apply plugin: "propdeps-idea"
eclipse {
jdt {
javaRuntimeName = "J2SE-1.5"
}
}
eclipse.project.buildCommand "net.sf.eclipsecs.core.CheckstyleBuilder"
eclipse.project.natures "net.sf.eclipsecs.core.CheckstyleNature"

View File

@@ -14,7 +14,7 @@ group = 'org.springframework.session'
sourceCompatibility = 1.5
targetCompatibility = 1.5
ext.springIoVersion = project.hasProperty('platformVersion') ? platformVersion : 'Brussels-SR3'
ext.springIoVersion = project.hasProperty('platformVersion') ? platformVersion : 'Brussels-BUILD-SNAPSHOT'
ext.spockDependencies = [
dependencies.create("org.spockframework:spock-core:$spockVersion") {
@@ -28,14 +28,9 @@ ext.gebDependencies = spockDependencies + [
"org.codehaus.groovy:groovy:$groovyVersion"
]
ext.seleniumDependencies = [
"org.seleniumhq.selenium:selenium-htmlunit-driver:$seleniumVersion",
"org.seleniumhq.selenium:selenium-firefox-driver:$seleniumVersion"
]
ext.jstlDependencies = [
"javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:$jstlVersion",
"org.apache.taglibs:taglibs-standard-jstlel:$jstlelVersion"
"org.apache.taglibs:taglibs-standard-jstlel:1.2.1"
]
repositories {
@@ -83,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'
}

View File

@@ -21,12 +21,12 @@ def customizePom(pom, gradleProject) {
url = "https://github.com/spring-projects/spring-session"
organization {
name = "Spring IO"
url = "https://projects.spring.io/spring-session"
url = "http://projects.spring.io/spring-session"
}
licenses {
license {
name "The Apache Software License, Version 2.0"
url "https://www.apache.org/licenses/LICENSE-2.0.txt"
url "http://www.apache.org/licenses/LICENSE-2.0.txt"
distribution "repo"
}
}

27
gradle/spring3.gradle Normal file
View File

@@ -0,0 +1,27 @@
configurations {
spring3TestRuntime.extendsFrom testRuntime
}
configurations.spring3TestRuntime {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
if (details.requested.group == 'org.springframework'
&& details.requested.name != 'spring-websocket'
&& details.requested.name != 'spring-messaging') {
details.useVersion '3.2.14.RELEASE'
}
if (details.requested.name == 'spring-data-redis') {
details.useVersion springDataRedisSpring3Version
}
}
}
task spring3Test(type: Test) {
jvmArgs = ['-ea', '-Xmx500m', '-XX:MaxPermSize=128M']
classpath = sourceSets.test.output + sourceSets.main.output + configurations.spring3TestRuntime
exclude "org/springframework/session/web/socket/**"
reports {
html.destination = project.file("$buildDir/spring3-test-results/")
junitXml.destination = project.file("$buildDir/reports/spring3-tests/")
}
}
check.dependsOn spring3Test

View File

@@ -45,7 +45,9 @@ task integrationTomcatStop(type: com.bmuschko.gradle.tomcat.tasks.TomcatStop) {
integrationTest {
dependsOn integrationTomcatRun
doFirst {
systemProperties['tomcat.port'] = integrationTomcatRun.httpPort
def host = 'localhost:' + integrationTomcatRun.httpPort
systemProperties['geb.build.baseUrl'] = 'http://'+host+'/' + integrationTomcatRun.contextPath
systemProperties['geb.build.reportsDir'] = 'build/geb-reports'
}
finalizedBy integrationTomcatStop
}

Binary file not shown.

View File

@@ -1,6 +1,6 @@
#Wed Jan 11 10:54:44 CST 2017
#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.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-3.5.1-bin.zip

19
gradlew vendored
View File

@@ -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" "$@"

View File

@@ -1,7 +1,6 @@
buildscript {
repositories {
mavenCentral()
maven { url "https://repo.spring.io/plugins-snapshot" }
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion")
@@ -15,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-redis",
@@ -29,7 +30,8 @@ dependencies {
testCompile "org.springframework.boot:spring-boot-starter-test"
integrationTestCompile seleniumDependencies
integrationTestCompile gebDependencies,
"org.spockframework:spock-spring:$spockVersion"
}
@@ -37,6 +39,9 @@ integrationTest {
doFirst {
def port = reservePort()
def host = 'localhost:' + port
systemProperties['geb.build.baseUrl'] = 'http://'+host+'/'
systemProperties['geb.build.reportsDir'] = 'build/geb-reports'
systemProperties['server.port'] = port
systemProperties['management.port'] = 0

View File

@@ -1,75 +0,0 @@
/*
* Copyright 2014-2017 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
*
* https://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 sample;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.WebDriver;
import sample.pages.HomePage;
import sample.pages.LoginPage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder;
/**
* @author Eddú Meléndez
* @author Rob Winch
*/
@RunWith(SpringRunner.class)
@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
public class FindByUsernameTests {
@Autowired
private MockMvc mockMvc;
private WebDriver driver;
@Before
public void setup() {
this.driver = MockMvcHtmlUnitDriverBuilder.mockMvcSetup(this.mockMvc).build();
}
@After
public void tearDown() {
this.driver.quit();
}
@Test
public void home() {
LoginPage login = HomePage.go(this.driver);
login.assertAt();
}
@Test
public void login() {
LoginPage login = HomePage.go(this.driver);
HomePage home = login.form().login(HomePage.class);
home.assertAt();
home.containCookie("SESSION");
home.doesNotContainCookie("JSESSIONID");
home.terminateButtonDisabled();
}
}

View File

@@ -1,41 +0,0 @@
/*
* Copyright 2014-2017 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
*
* https://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 sample.pages;
import org.openqa.selenium.WebDriver;
/**
* @author Eddú Meléndez
*/
public class BasePage {
private WebDriver driver;
public BasePage(WebDriver driver) {
this.driver = driver;
}
public WebDriver getDriver() {
return this.driver;
}
public static void get(WebDriver driver, String get) {
String baseUrl = "http://localhost";
driver.get(baseUrl + get);
}
}

View File

@@ -1,78 +0,0 @@
/*
* Copyright 2014-2017 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
*
* https://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 sample.pages;
import java.util.Set;
import org.openqa.selenium.By;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Eddú Meléndez
* @author Rob Winch
*/
public class HomePage extends BasePage {
@FindBy(css = "input[type=\"submit\"]")
WebElement logout;
public HomePage(WebDriver driver) {
super(driver);
}
public void assertAt() {
assertThat(getDriver().getTitle())
.isEqualTo("Spring Session Sample - Secured Content");
}
public void containCookie(String cookieName) {
Set<Cookie> cookies = getDriver().manage().getCookies();
assertThat(cookies).extracting("name").contains(cookieName);
}
public void doesNotContainCookie(String cookieName) {
Set<Cookie> cookies = getDriver().manage().getCookies();
assertThat(cookies).extracting("name").doesNotContain(cookieName);
}
public void terminateButtonDisabled() {
Set<Cookie> cookies = getDriver().manage().getCookies();
String cookieValue = null;
for (Cookie cookie : cookies) {
if ("SESSION".equals(cookie.getName())) {
cookieValue = cookie.getValue();
}
}
WebElement element = getDriver().findElement(By.id("terminate-" + cookieValue));
assertThat(element.isEnabled()).isFalse();
}
public HomePage logout() {
this.logout.click();
return PageFactory.initElements(getDriver(), HomePage.class);
}
public static LoginPage go(WebDriver driver) {
get(driver, "/");
return PageFactory.initElements(driver, LoginPage.class);
}
}

View File

@@ -1,68 +0,0 @@
/*
* Copyright 2014-2017 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
*
* https://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 sample.pages;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.pagefactory.DefaultElementLocatorFactory;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Eddú Meléndez
* @author Rob Winch
*/
public class LoginPage extends BasePage {
public LoginPage(WebDriver driver) {
super(driver);
}
public void assertAt() {
assertThat(getDriver().getTitle()).isEqualTo("Spring Session Sample - Log In");
}
public Form form() {
return new Form(getDriver());
}
public class Form {
@FindBy(name = "username")
private WebElement username;
@FindBy(name = "password")
private WebElement password;
@FindBy(tagName = "button")
private WebElement button;
public Form(SearchContext context) {
PageFactory.initElements(new DefaultElementLocatorFactory(context), this);
}
public <T> T login(Class<T> page) {
this.username.sendKeys("user");
this.password.sendKeys("password");
this.button.click();
return PageFactory.initElements(getDriver(), page);
}
}
}

View File

@@ -1,96 +0,0 @@
/*
* Copyright 2014-2017 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
*
* https://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 sample;
import java.util.List;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.WebDriver;
import sample.client.Application;
import sample.pages.HomePage;
import sample.pages.HomePage.Attribute;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Eddú Meléndez
* @author Rob Winch
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class, webEnvironment = WebEnvironment.MOCK)
@AutoConfigureMockMvc
public class AttributeTests {
@Autowired
private MockMvc mockMvc;
private WebDriver driver;
@Before
public void setup() {
this.driver = MockMvcHtmlUnitDriverBuilder
.mockMvcSetup(this.mockMvc)
.build();
}
@After
public void tearDown() {
this.driver.quit();
}
@Test
public void home() {
HomePage home = HomePage.go(this.driver);
home.assertAt();
}
@Test
public void noAttributes() {
HomePage home = HomePage.go(this.driver);
assertThat(home.attributes()).isEmpty();
}
@Test
public void createAttribute() {
HomePage home = HomePage.go(this.driver);
// @formatter:off
home = home.form()
.attributeName("a")
.attributeValue("b")
.submit(HomePage.class);
// @formatter:on
List<Attribute> attributes = home.attributes();
assertThat(attributes).hasSize(2);
assertThat(attributes.get(0).getAttributeName()).isEqualTo("requestCount");
assertThat(attributes.get(0).getAttributeValue()).isEqualTo("1");
assertThat(attributes.get(1).getAttributeName()).isEqualTo("a");
assertThat(attributes.get(1).getAttributeValue()).isEqualTo("b");
}
}

View File

@@ -1,135 +0,0 @@
/*
* Copyright 2014-2017 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
*
* https://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 sample.pages;
import java.util.ArrayList;
import java.util.List;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.pagefactory.DefaultElementLocatorFactory;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Eddú Meléndez
* @author Rob Winch
*/
public class HomePage {
private WebDriver driver;
@FindBy(css = "form")
WebElement form;
@FindBy(css = "table tbody tr")
List<WebElement> trs;
List<Attribute> attributes;
public HomePage(WebDriver driver) {
this.driver = driver;
this.attributes = new ArrayList<Attribute>();
}
private static void get(WebDriver driver, String get) {
String baseUrl = "http://localhost:" + System.getProperty("tomcat.port", "8080");
driver.get(baseUrl + get);
}
public static HomePage go(WebDriver driver) {
get(driver, "/");
return PageFactory.initElements(driver, HomePage.class);
}
public void assertAt() {
assertThat(this.driver.getTitle()).isEqualTo("Session Attributes");
}
public List<Attribute> attributes() {
List<Attribute> rows = new ArrayList<Attribute>();
for (WebElement tr : this.trs) {
rows.add(new Attribute(tr));
}
this.attributes.addAll(rows);
return this.attributes;
}
public Form form() {
return new Form(this.form);
}
public class Form {
@FindBy(name = "attributeName")
WebElement attributeName;
@FindBy(name = "attributeValue")
WebElement attributeValue;
@FindBy(css = "input[type=\"submit\"]")
WebElement submit;
public Form(SearchContext context) {
PageFactory.initElements(new DefaultElementLocatorFactory(context), this);
}
public Form attributeName(String text) {
this.attributeName.sendKeys(text);
return this;
}
public Form attributeValue(String text) {
this.attributeValue.sendKeys(text);
return this;
}
public <T> T submit(Class<T> page) {
this.submit.click();
return PageFactory.initElements(HomePage.this.driver, page);
}
}
public static class Attribute {
@FindBy(xpath = ".//td[1]")
WebElement attributeName;
@FindBy(xpath = ".//td[2]")
WebElement attributeValue;
public Attribute(SearchContext context) {
PageFactory.initElements(new DefaultElementLocatorFactory(context), this);
}
/**
* @return the attributeName
*/
public String getAttributeName() {
return this.attributeName.getText();
}
/**
* @return the attributeValue
*/
public String getAttributeValue() {
return this.attributeValue.getText();
}
}
}

View File

@@ -1,186 +0,0 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://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 sample.server;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Properties;
import com.gemstone.gemfire.cache.Cache;
import com.gemstone.gemfire.cache.CacheFactory;
import com.gemstone.gemfire.cache.ExpirationAction;
import com.gemstone.gemfire.cache.ExpirationAttributes;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.RegionFactory;
import com.gemstone.gemfire.cache.RegionShortcut;
import com.gemstone.gemfire.cache.server.CacheServer;
import org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository;
import org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration;
import org.springframework.util.StringUtils;
/**
* The {@link NativeGemFireServer} class uses the GemFire API to create a GemFire (cache) instance.
*
* @author John Blum
* @see com.gemstone.gemfire.cache.Cache
* @see com.gemstone.gemfire.cache.Region
* @see com.gemstone.gemfire.cache.server.CacheServer
* @see org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration
* @since 1.3.0
*/
@SuppressWarnings("unused")
public final class NativeGemFireServer implements Runnable {
private static final int GEMFIRE_CACHE_SERVER_PORT =
Integer.getInteger("spring-session-data-gemfire.cache.server.port", 12480);
private static final String GEMFIRE_CACHE_SERVER_HOST = "localhost";
private static final String GEMFIRE_CACHE_SERVER_HOSTNAME_FOR_CLIENTS = GEMFIRE_CACHE_SERVER_HOST;
private static final String GEMFIRE_LOG_FILENAME_PATTERN =
String.format("%s", NativeGemFireServer.class.getSimpleName()).concat("-%s.log");
public static void main(String[] args) {
newNativeGemFireServer(args).run();
}
private final String[] args;
private static File newGemFireLogFile(String suffix) {
return new File(String.format(GEMFIRE_LOG_FILENAME_PATTERN, suffix));
}
private static NativeGemFireServer newNativeGemFireServer(String[] args) {
return new NativeGemFireServer(args);
}
private static String[] nullSafeStringArray(String[] array) {
return (array != null ? array.clone() : new String[0]);
}
private static void writeStringTo(File file, String fileContents) {
PrintWriter fileWriter = null;
try {
fileWriter = new PrintWriter(new BufferedWriter(new FileWriter(file, true)), true);
fileWriter.println(fileContents);
fileWriter.flush();
}
catch (IOException e) {
throw new RuntimeException(String.format("Failed to write [%s] to file [%s]", fileContents, file), e);
}
finally {
if (fileWriter != null) {
fileWriter.close();
}
}
}
private NativeGemFireServer(String[] args) {
this.args = nullSafeStringArray(args);
}
/**
* @inheritDoc
*/
public void run() {
run(this.args);
}
private void run(String[] args) {
try {
writeStringTo(newGemFireLogFile("stdout"), "Before");
registerShutdownHook(addCacheServer(createRegion(gemfireCache(
gemfireProperties(applicationName())))));
writeStringTo(newGemFireLogFile("stdout"), "After");
}
catch (Throwable e) {
writeStringTo(newGemFireLogFile("stderr"), e.toString());
}
}
private String applicationName() {
return applicationName(null);
}
private String applicationName(String applicationName) {
return StringUtils.hasText(applicationName) ? applicationName
: "spring-session-data-gemfire.boot.sample." + NativeGemFireServer.class.getSimpleName();
}
private Properties gemfireProperties(String applicationName) {
Properties gemfireProperties = new Properties();
gemfireProperties.setProperty("name", applicationName);
gemfireProperties.setProperty("log-file", "gemfire-server.log");
gemfireProperties.setProperty("log-level", "config");
//gemfireProperties.setProperty("jmx-manager", "true");
//gemfireProperties.setProperty("jmx-manager-start", "true");
return gemfireProperties;
}
private Cache gemfireCache(Properties gemfireProperties) {
return new CacheFactory(gemfireProperties).create();
}
private Cache createRegion(Cache gemfireCache) {
RegionFactory<Object, AbstractGemFireOperationsSessionRepository.GemFireSession> regionFactory =
gemfireCache.createRegionFactory(RegionShortcut.PARTITION);
regionFactory.setKeyConstraint(Object.class);
regionFactory.setValueConstraint(AbstractGemFireOperationsSessionRepository.GemFireSession.class);
regionFactory.setStatisticsEnabled(true);
regionFactory.setEntryIdleTimeout(newExpirationAttributes(1800, ExpirationAction.INVALIDATE));
Region region = regionFactory.create(
GemFireHttpSessionConfiguration.DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME);
return gemfireCache;
}
private ExpirationAttributes newExpirationAttributes(int expirationTime, ExpirationAction expirationAction) {
return new ExpirationAttributes(expirationTime, expirationAction);
}
private Cache addCacheServer(Cache gemfireCache) throws IOException {
CacheServer cacheServer = gemfireCache.addCacheServer();
cacheServer.setBindAddress(GEMFIRE_CACHE_SERVER_HOST);
cacheServer.setHostnameForClients(GEMFIRE_CACHE_SERVER_HOSTNAME_FOR_CLIENTS);
cacheServer.setPort(GEMFIRE_CACHE_SERVER_PORT);
cacheServer.start();
return gemfireCache;
}
private Cache registerShutdownHook(final Cache gemfireCache) {
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
public void run() {
if (gemfireCache != null) {
gemfireCache.close();
}
}
}));
return gemfireCache;
}
}

View File

@@ -1,82 +0,0 @@
/*
* Copyright 2014-2017 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
*
* https://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 sample;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.WebDriver;
import sample.pages.HomePage;
import sample.pages.LoginPage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder;
/**
* @author Eddú Meléndez
*/
@RunWith(SpringRunner.class)
@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
public class BootTests {
@Autowired
private MockMvc mockMvc;
private WebDriver driver;
@Before
public void setup() {
this.driver = MockMvcHtmlUnitDriverBuilder.mockMvcSetup(this.mockMvc).build();
}
@After
public void tearDown() {
this.driver.quit();
}
@Test
public void home() {
LoginPage login = HomePage.go(this.driver);
login.assertAt();
HomePage home = login.form().login(HomePage.class);
home.assertAt();
}
@Test
public void login() {
LoginPage login = HomePage.go(this.driver);
HomePage home = login.form().login(HomePage.class);
home.containCookie("SESSION");
home.doesNotContainCookie("JSESSIONID");
}
@Test
public void logout() {
LoginPage login = HomePage.go(this.driver);
HomePage home = login.form().login(HomePage.class);
login = home.logout();
login.assertAt();
}
}

View File

@@ -1,41 +0,0 @@
/*
* Copyright 2014-2017 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
*
* https://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 sample.pages;
import org.openqa.selenium.WebDriver;
/**
* @author Eddú Meléndez
*/
public class BasePage {
private WebDriver driver;
public BasePage(WebDriver driver) {
this.driver = driver;
}
public WebDriver getDriver() {
return this.driver;
}
public static void get(WebDriver driver, String get) {
String baseUrl = "http://localhost";
driver.get(baseUrl + get);
}
}

View File

@@ -1,63 +0,0 @@
/*
* Copyright 2014-2017 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
*
* https://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 sample.pages;
import java.util.Set;
import org.openqa.selenium.By;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.PageFactory;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Eddú Meléndez
*/
public class HomePage extends BasePage {
public HomePage(WebDriver driver) {
super(driver);
}
public static LoginPage go(WebDriver driver) {
get(driver, "/");
return PageFactory.initElements(driver, LoginPage.class);
}
public void assertAt() {
assertThat(getDriver().getTitle()).isEqualTo("Spring Session Sample - Secured Content");
}
public void containCookie(String cookieName) {
Set<Cookie> cookies = getDriver().manage().getCookies();
assertThat(cookies).extracting("name").contains(cookieName);
}
public void doesNotContainCookie(String cookieName) {
Set<Cookie> cookies = getDriver().manage().getCookies();
assertThat(cookies).extracting("name").doesNotContain(cookieName);
}
public LoginPage logout() {
WebElement logout = getDriver().findElement(By.cssSelector("input[type=\"submit\"]"));
logout.click();
return PageFactory.initElements(getDriver(), LoginPage.class);
}
}

View File

@@ -1,69 +0,0 @@
/*
* Copyright 2014-2017 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
*
* https://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 sample.pages;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.pagefactory.DefaultElementLocatorFactory;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Eddú Meléndez
* @author Rob Winch
*/
public class LoginPage extends BasePage {
public LoginPage(WebDriver driver) {
super(driver);
}
public void assertAt() {
assertThat(getDriver().getTitle()).isEqualTo("Login Page");
}
public Form form() {
return new Form(getDriver());
}
public class Form {
@FindBy(name = "username")
private WebElement username;
@FindBy(name = "password")
private WebElement password;
@FindBy(name = "submit")
private WebElement button;
public Form(SearchContext context) {
PageFactory.initElements(new DefaultElementLocatorFactory(context), this);
}
public <T> T login(Class<T> page) {
this.username.sendKeys("user");
this.password.sendKeys("password");
this.button.click();
return PageFactory.initElements(getDriver(), page);
}
}
}

View File

@@ -1,104 +0,0 @@
/*
* Copyright 2014-2017 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
*
* https://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 sample;
import java.util.Set;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.By;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import sample.pages.HomePage;
import sample.pages.LoginPage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Pool Dolorier
*/
@RunWith(SpringRunner.class)
@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
public class BootTests {
@Autowired
private MockMvc mockMvc;
private WebDriver driver;
@Before
public void setUp() {
this.driver = MockMvcHtmlUnitDriverBuilder
.mockMvcSetup(this.mockMvc)
.build();
}
@After
public void tearDown() {
this.driver.quit();
}
@Test
public void unauthenticatedUserSentToLogInPage() {
HomePage homePage = HomePage.go(this.driver);
LoginPage loginPage = homePage.unauthenticated();
loginPage.assertAt();
}
@Test
public void logInViewsHomePage() {
LoginPage loginPage = LoginPage.go(this.driver);
loginPage.assertAt();
HomePage homePage = loginPage.login("user", "password");
homePage.assertAt();
WebElement username = homePage.getDriver().findElement(By.id("un"));
assertThat(username.getText()).isEqualTo("user");
Set<Cookie> cookies = homePage.getDriver().manage().getCookies();
assertThat(cookies).extracting("name").contains("SESSION");
assertThat(cookies).extracting("name").doesNotContain("JSESSIONID");
}
@Test
public void logoutSuccess() {
LoginPage loginPage = LoginPage.go(this.driver);
HomePage homePage = loginPage.login("user", "password");
LoginPage successLogoutPage = homePage.logout();
successLogoutPage.assertAt();
}
@Test
public void loggedOutUserSentToLoginPage() {
LoginPage loginPage = LoginPage.go(this.driver);
HomePage homePage = loginPage.login("user", "password");
homePage.logout();
HomePage backHomePage = HomePage.go(this.driver);
LoginPage backLoginPage = backHomePage.unauthenticated();
backLoginPage.assertAt();
}
}

View File

@@ -1,40 +0,0 @@
/*
* Copyright 2014-2017 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
*
* https://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 sample.pages;
import org.openqa.selenium.WebDriver;
/**
* @author Pool Dolorier
*/
public abstract class BasePage {
private WebDriver driver;
public BasePage(WebDriver driver) {
this.driver = driver;
}
public WebDriver getDriver() {
return this.driver;
}
public static void get(WebDriver driver, String get) {
String baseUrl = "http://localhost";
driver.get(baseUrl + get);
}
}

View File

@@ -1,55 +0,0 @@
/*
* Copyright 2014-2017 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
*
* https://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 sample.pages;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Pool Dolorier
*/
public class HomePage extends BasePage {
@FindBy(css = "input[type='submit']")
private WebElement submit;
public HomePage(WebDriver driver) {
super(driver);
}
public static HomePage go(WebDriver driver) {
get(driver, "/");
return PageFactory.initElements(driver, HomePage.class);
}
public LoginPage unauthenticated() {
return LoginPage.go(getDriver());
}
public LoginPage logout() {
this.submit.click();
return LoginPage.go(getDriver());
}
public void assertAt() {
assertThat(getDriver().getTitle()).isEqualTo("Spring Session Sample - Secured Content");
}
}

View File

@@ -1,59 +0,0 @@
/*
* Copyright 2014-2017 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
*
* https://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 sample.pages;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Pool Dolorier
*/
public class LoginPage extends BasePage {
@FindBy(name = "username")
private WebElement username;
@FindBy(name = "password")
private WebElement password;
@FindBy(css = "input[name='submit']")
private WebElement submit;
public LoginPage(WebDriver driver) {
super(driver);
}
public static LoginPage go(WebDriver driver) {
get(driver, "/login");
return PageFactory.initElements(driver, LoginPage.class);
}
public void assertAt() {
assertThat(getDriver().getTitle()).isEqualTo("Login Page");
}
public HomePage login(String user, String password) {
this.username.sendKeys(user);
this.password.sendKeys(password);
this.submit.click();
return HomePage.go(getDriver());
}
}

View File

@@ -1,99 +0,0 @@
/*
* Copyright 2014-2017 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
*
* https://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 sample;
import java.util.List;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.WebDriver;
import sample.pages.HomePage;
import sample.pages.HomePage.Attribute;
import sample.pages.LoginPage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Eddú Meléndez
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
@AutoConfigureMockMvc
public class HttpRedisJsonTest {
@Autowired
private MockMvc mockMvc;
private WebDriver driver;
@Before
public void setup() {
this.driver = MockMvcHtmlUnitDriverBuilder.mockMvcSetup(this.mockMvc).build();
}
@After
public void tearDown() {
this.driver.quit();
}
@Test
public void goLoginRedirectToLogin() {
LoginPage login = HomePage.go(this.driver, LoginPage.class);
login.assertAt();
}
@Test
public void goHomeRedirectLoginPage() {
LoginPage login = HomePage.go(this.driver, LoginPage.class);
login.assertAt();
}
@Test
public void login() {
LoginPage login = HomePage.go(this.driver, LoginPage.class);
HomePage home = login.form().login(HomePage.class);
home.containCookie("SESSION");
home.doesNotContainCookie("JSESSIONID");
}
@Test
public void createAttribute() {
LoginPage login = HomePage.go(this.driver, LoginPage.class);
HomePage home = login.form().login(HomePage.class);
// @formatter:off
home = home.form()
.attributeName("Demo Key")
.attributeValue("Demo Value")
.submit(HomePage.class);
// @formatter:on
List<Attribute> attributes = home.attributes();
assertThat(attributes).extracting("attributeName").contains("Demo Key");
assertThat(attributes).extracting("attributeValue").contains("Demo Value");
}
}

View File

@@ -1,41 +0,0 @@
/*
* Copyright 2014-2017 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
*
* https://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 sample.pages;
import org.openqa.selenium.WebDriver;
/**
* @author Eddú Meléndez
*/
public class BasePage {
private WebDriver driver;
public BasePage(WebDriver driver) {
this.driver = driver;
}
public WebDriver getDriver() {
return this.driver;
}
public static void get(WebDriver driver, String get) {
String baseUrl = "http://localhost";
driver.get(baseUrl + get);
}
}

View File

@@ -1,151 +0,0 @@
/*
* Copyright 2014-2017 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
*
* https://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 sample.pages;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.openqa.selenium.By;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.pagefactory.DefaultElementLocatorFactory;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Eddú Meléndez
* @author Rob Winch
*/
public class HomePage {
private WebDriver driver;
@FindBy(css = "form[name=\"f\"]")
WebElement form;
@FindBy(css = "table tbody tr")
List<WebElement> trs;
List<Attribute> attributes;
public HomePage(WebDriver driver) {
this.driver = driver;
this.attributes = new ArrayList<Attribute>();
}
private static void get(WebDriver driver, String get) {
String baseUrl = "http://localhost:" + System.getProperty("tomcat.port", "8080");
driver.get(baseUrl + get);
}
public static <T> T go(WebDriver driver, Class<T> page) {
get(driver, "/");
return PageFactory.initElements(driver, page);
}
public void containCookie(String cookieName) {
Set<Cookie> cookies = this.driver.manage().getCookies();
assertThat(cookies).extracting("name").contains(cookieName);
}
public void doesNotContainCookie(String cookieName) {
Set<Cookie> cookies = this.driver.manage().getCookies();
assertThat(cookies).extracting("name").doesNotContain(cookieName);
}
public HomePage logout() {
WebElement logout = this.driver
.findElement(By.cssSelector("input[type=\"submit\"]"));
logout.click();
return PageFactory.initElements(this.driver, HomePage.class);
}
public List<Attribute> attributes() {
List<Attribute> rows = new ArrayList<Attribute>();
for (WebElement tr : this.trs) {
rows.add(new Attribute(tr));
}
this.attributes.addAll(rows);
return this.attributes;
}
public Form form() {
return new Form(this.form);
}
public class Form {
@FindBy(name = "key")
WebElement attributeName;
@FindBy(name = "value")
WebElement attributeValue;
@FindBy(css = "button[type=\"submit\"]")
WebElement submit;
public Form(SearchContext context) {
PageFactory.initElements(new DefaultElementLocatorFactory(context), this);
}
public Form attributeName(String text) {
this.attributeName.sendKeys(text);
return this;
}
public Form attributeValue(String text) {
this.attributeValue.sendKeys(text);
return this;
}
public <T> T submit(Class<T> page) {
this.submit.click();
return PageFactory.initElements(HomePage.this.driver, page);
}
}
public static class Attribute {
@FindBy(xpath = ".//td[1]")
WebElement attributeName;
@FindBy(xpath = ".//td[2]")
WebElement attributeValue;
public Attribute(SearchContext context) {
PageFactory.initElements(new DefaultElementLocatorFactory(context), this);
}
/**
* @return the attributeName
*/
public String getAttributeName() {
return this.attributeName.getText();
}
/**
* @return the attributeValue
*/
public String getAttributeValue() {
return this.attributeValue.getText();
}
}
}

View File

@@ -1,69 +0,0 @@
/*
* Copyright 2014-2017 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
*
* https://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 sample.pages;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.pagefactory.DefaultElementLocatorFactory;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Eddú Meléndez
* @author Rob Winch
*/
public class LoginPage extends BasePage {
public LoginPage(WebDriver driver) {
super(driver);
}
public void assertAt() {
assertThat(getDriver().getTitle()).isEqualTo("Spring Session Sample - Login");
}
public Form form() {
return new Form(getDriver());
}
public class Form {
@FindBy(name = "username")
private WebElement username;
@FindBy(name = "password")
private WebElement password;
@FindBy(tagName = "button")
private WebElement button;
public Form(SearchContext context) {
PageFactory.initElements(new DefaultElementLocatorFactory(context), this);
}
public <T> T login(Class<T> page) {
this.username.sendKeys("user");
this.password.sendKeys("password");
this.button.click();
return PageFactory.initElements(getDriver(), page);
}
}
}

View File

@@ -1,81 +0,0 @@
/*
* Copyright 2014-2017 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
*
* https://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 sample;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.WebDriver;
import sample.pages.HomePage;
import sample.pages.LoginPage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder;
/**
* @author Eddú Meléndez
*/
@RunWith(SpringRunner.class)
@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
public class BootTests {
@Autowired
private MockMvc mockMvc;
private WebDriver driver;
@Before
public void setup() {
this.driver = MockMvcHtmlUnitDriverBuilder.mockMvcSetup(this.mockMvc).build();
}
@After
public void tearDown() {
this.driver.quit();
}
@Test
public void home() {
LoginPage login = HomePage.go(this.driver);
login.assertAt();
}
@Test
public void login() {
LoginPage login = HomePage.go(this.driver);
HomePage home = login.form().login(HomePage.class);
home.assertAt();
home.containCookie("SESSION");
home.doesNotContainCookie("JSESSIONID");
}
@Test
public void logout() {
LoginPage login = HomePage.go(this.driver);
HomePage home = login.form().login(HomePage.class);
home.logout();
login.assertAt();
}
}

View File

@@ -1,41 +0,0 @@
/*
* Copyright 2014-2017 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
*
* https://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 sample.pages;
import org.openqa.selenium.WebDriver;
/**
* @author Eddú Meléndez
*/
public class BasePage {
private WebDriver driver;
public BasePage(WebDriver driver) {
this.driver = driver;
}
public WebDriver getDriver() {
return this.driver;
}
public static void get(WebDriver driver, String get) {
String baseUrl = "http://localhost";
driver.get(baseUrl + get);
}
}

View File

@@ -1,63 +0,0 @@
/*
* Copyright 2014-2017 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
*
* https://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 sample.pages;
import java.util.Set;
import org.openqa.selenium.By;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.PageFactory;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Eddú Meléndez
*/
public class HomePage extends BasePage {
public HomePage(WebDriver driver) {
super(driver);
}
public static LoginPage go(WebDriver driver) {
get(driver, "/");
return PageFactory.initElements(driver, LoginPage.class);
}
public void assertAt() {
assertThat(getDriver().getTitle()).isEqualTo("Spring Session Sample - Secured Content");
}
public void containCookie(String cookieName) {
Set<Cookie> cookies = getDriver().manage().getCookies();
assertThat(cookies).extracting("name").contains(cookieName);
}
public void doesNotContainCookie(String cookieName) {
Set<Cookie> cookies = getDriver().manage().getCookies();
assertThat(cookies).extracting("name").doesNotContain(cookieName);
}
public HomePage logout() {
WebElement logout = getDriver().findElement(By.cssSelector("input[type=\"submit\"]"));
logout.click();
return PageFactory.initElements(getDriver(), HomePage.class);
}
}

View File

@@ -1,69 +0,0 @@
/*
* Copyright 2014-2017 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
*
* https://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 sample.pages;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.pagefactory.DefaultElementLocatorFactory;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Eddú Meléndez
* @author Rob Winch
*/
public class LoginPage extends BasePage {
public LoginPage(WebDriver driver) {
super(driver);
}
public void assertAt() {
assertThat(getDriver().getTitle()).isEqualTo("Login Page");
}
public Form form() {
return new Form(getDriver());
}
public class Form {
@FindBy(name = "username")
private WebElement username;
@FindBy(name = "password")
private WebElement password;
@FindBy(name = "submit")
private WebElement button;
public Form(SearchContext context) {
PageFactory.initElements(new DefaultElementLocatorFactory(context), this);
}
public <T> T login(Class<T> page) {
this.username.sendKeys("user");
this.password.sendKeys("password");
this.button.click();
return PageFactory.initElements(getDriver(), page);
}
}
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample
import geb.spock.*
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.test.IntegrationTest
import org.springframework.boot.test.SpringApplicationConfiguration
import org.springframework.boot.test.SpringApplicationContextLoader
import org.springframework.test.context.ContextConfiguration
import org.springframework.test.context.web.WebAppConfiguration
import sample.pages.HomePage
import sample.pages.LoginPage
import spock.lang.Stepwise
import pages.*
/**
* Tests the demo that supports multiple sessions
*
* @author Rob Winch
*/
@Stepwise
@ContextConfiguration(classes = Application, loader = SpringApplicationContextLoader)
@WebAppConfiguration
@IntegrationTest
class BootTests extends GebReportingSpec {
def 'Unauthenticated user sent to log in page'() {
when: 'unauthenticated user request protected page'
via HomePage
then: 'sent to the log in page'
at LoginPage
}
def 'Log in views home page'() {
when: 'log in successfully'
login()
then: 'sent to original page'
at HomePage
and: 'the username is displayed'
username == 'user'
and: 'Spring Session Management is being used'
driver.manage().cookies.find { it.name == 'SESSION' }
and: 'Standard Session is NOT being used'
!driver.manage().cookies.find { it.name == 'JSESSIONID' }
}
def 'Log out success'() {
when:
logout()
then:
at LoginPage
}
def 'Logged out user sent to log in page'() {
when: 'logged out user request protected page'
via HomePage
then: 'sent to the log in page'
at LoginPage
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.pages
import geb.*
/**
* The home page
*
* @author Rob Winch
*/
class HomePage extends Page {
static url = ''
static at = { assert driver.title == 'Spring Session Sample - Secured Content'; true}
static content = {
username { $('#un').text() }
logout(to:LoginPage) { $('input[type=submit]').click() }
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.pages
import geb.*
/**
* The Links Page
*
* @author Rob Winch
*/
class LoginPage extends Page {
static url = '/login'
static at = { assert driver.title == 'Login Page'; true}
static content = {
form { $('form') }
submit { $('input[type=submit]') }
login(required:false) { user='user', pass='password' ->
form.username = user
form.password = pass
submit.click(HomePage)
}
}
}

View File

@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,

View File

@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,

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