Compare commits

..

18 Commits

Author SHA1 Message Date
Eleftheria Stein
d0fabc0a35 Release 2.6.0-M1 2021-08-17 15:50:52 +02:00
Eleftheria Stein
cae8b51eab Upgrade test dependencies 2021-08-17 15:14:03 +02:00
Eleftheria Stein
2236449635 Revert "Upgrade test dependencies"
This reverts commit 9fde87c11b.
2021-08-17 14:07:13 +02:00
Eleftheria Stein
d862836d41 Upgrade Hazelcast 4 to 4.2.2
Closes gh-1887
2021-08-17 13:45:48 +02:00
Eleftheria Stein
4008afe47b Upgrade Spring Security to 5.6.0-M2
Closes gh-1884
2021-08-17 13:29:58 +02:00
Eleftheria Stein
9fde87c11b Upgrade test dependencies 2021-08-17 13:23:08 +02:00
Eleftheria Stein
93c62104ee Make Websocket sample compatible with Spring Boot 2.5.3
Closes gh-1886
2021-08-16 15:08:38 +02:00
Eleftheria Stein
8fdcfc28bc Upgrade samples to Spring Boot 2.5.3
Closes gh-1885
2021-08-16 15:08:09 +02:00
Eleftheria Stein
1f6445999f Upgrade Spring Framework to 5.3.9
Closes gh-1882
2021-08-16 14:00:02 +02:00
Eleftheria Stein
cf4aeae02a Upgrade Spring Data to 2021.1.0-M2
Closes gh-1883
2021-08-16 13:59:25 +02:00
Eleftheria Stein
f8dcee7304 Upgrade Reactor to 2020.0.10
Closes gh-1881
2021-08-16 13:57:00 +02:00
Eleftheria Stein
971a2d17d9 Set cookie path to context path without trailing slash
Closes gh-1863
2021-07-20 10:00:53 +02:00
Ellie Bahadori
8b5b3701da Prevent builds from running on forks
Resolves gh-1678
2021-07-06 17:19:30 +02:00
Eleftheria Stein
21c9fb0cfa Point "What's New" section to Wiki
Closes gh-1878
2021-06-29 16:08:03 +02:00
Jay Bryant
33993b2ff6 Add links to Mongo and Geode docs
Spring Session for MongoDB and Geodo have their own reference guides.
This PR adds links to them.
2021-06-14 13:34:36 +02:00
Jay Bryant
9f4a723160 Add links to the other documentation format
Add a link from the HTML to the PDF and vice-versa.
2021-06-04 08:55:57 +02:00
Eleftheria Stein
25032fbd61 Use GPG_PRIVATE_KEY directly in build
Closes gh-1861
2021-05-31 15:42:16 +03:00
Eleftheria Stein
d195579ced Next development version 2021-05-19 00:41:23 +02:00
29 changed files with 160 additions and 336 deletions

View File

@@ -1,9 +1,9 @@
name: 2.5.x CI
name: CI
on:
push:
branches:
- 2.5.x
- main
schedule:
- cron: '0 10 * * *' # Once per day at 10am UTC
workflow_dispatch: # Manual trigger
@@ -19,6 +19,7 @@ jobs:
build:
name: Build
runs-on: ubuntu-latest
if: github.repository == 'spring-projects/spring-session'
strategy:
matrix:
jdk: [8, 11]
@@ -48,6 +49,7 @@ jobs:
name: Deploy Artifacts
needs: [build]
runs-on: ubuntu-latest
if: github.repository == 'spring-projects/spring-session'
steps:
- uses: actions/checkout@v2
- name: Set up JDK
@@ -63,14 +65,11 @@ jobs:
export GRADLE_ENTERPRISE_CACHE_USERNAME="$GRADLE_ENTERPRISE_CACHE_USER"
export GRADLE_ENTERPRISE_CACHE_PASSWORD="$GRADLE_ENTERPRISE_CACHE_PASSWORD"
export GRADLE_ENTERPRISE_ACCESS_KEY="$GRADLE_ENTERPRISE_SECRET_ACCESS_KEY"
export VERSION_HEADER=$'Version: GnuPG v2\n\n'
export ORG_GRADLE_PROJECT_signingKey=${GPG_PRIVATE_KEY#"$VERSION_HEADER"}
export ORG_GRADLE_PROJECT_signingPassword="$GPG_PASSPHRASE"
./gradlew deployArtifacts -PossrhUsername="$OSSRH_TOKEN_USERNAME" -PossrhPassword="$OSSRH_TOKEN_PASSWORD" -PartifactoryUsername="$ARTIFACTORY_USERNAME" -PartifactoryPassword="$ARTIFACTORY_PASSWORD" --stacktrace --no-parallel
./gradlew finalizeDeployArtifacts -PossrhUsername="$OSSRH_TOKEN_USERNAME" -PossrhPassword="$OSSRH_TOKEN_PASSWORD" -PartifactoryUsername="$ARTIFACTORY_USERNAME" -PartifactoryPassword="$ARTIFACTORY_PASSWORD" --stacktrace --no-parallel
env:
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY_NO_HEADER }}
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
ORG_GRADLE_PROJECT_signingKey: ${{ secrets.GPG_PRIVATE_KEY_NO_HEADER }}
ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.GPG_PASSPHRASE }}
OSSRH_TOKEN_USERNAME: ${{ secrets.OSSRH_TOKEN_USERNAME }}
OSSRH_TOKEN_PASSWORD: ${{ secrets.OSSRH_TOKEN_PASSWORD }}
ARTIFACTORY_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}
@@ -79,6 +78,7 @@ jobs:
name: Deploy Docs
needs: [build]
runs-on: ubuntu-latest
if: github.repository == 'spring-projects/spring-session'
steps:
- uses: actions/checkout@v2
- name: Set up JDK

View File

@@ -1,14 +1,12 @@
name: 2.5.x PR Build
name: PR Build
on:
pull_request:
branches:
- 2.5.x
on: pull_request
jobs:
build:
name: Build
runs-on: ubuntu-latest
if: github.repository == 'spring-projects/spring-session'
strategy:
matrix:
jdk: [8, 11]

View File

@@ -4,7 +4,7 @@ buildscript {
snapshotBuild = version.endsWith('SNAPSHOT')
milestoneBuild = !(releaseBuild || snapshotBuild)
springBootVersion = '2.4.7'
springBootVersion = '2.5.3'
}
repositories {

View File

@@ -1,3 +1,3 @@
org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
org.gradle.parallel=true
version=2.5.3
version=2.6.0-M1

View File

@@ -1,11 +1,11 @@
dependencyManagement {
imports {
mavenBom 'io.projectreactor:reactor-bom:2020.0.12'
mavenBom 'io.projectreactor:reactor-bom:2020.0.10'
mavenBom 'org.junit:junit-bom:5.7.2'
mavenBom 'org.springframework:spring-framework-bom:5.3.11'
mavenBom 'org.springframework.data:spring-data-bom:2021.0.6'
mavenBom 'org.springframework.security:spring-security-bom:5.5.3'
mavenBom 'org.testcontainers:testcontainers-bom:1.15.3'
mavenBom 'org.springframework:spring-framework-bom:5.3.9'
mavenBom 'org.springframework.data:spring-data-bom:2021.1.0-M2'
mavenBom 'org.springframework.security:spring-security-bom:5.6.0-M2'
mavenBom 'org.testcontainers:testcontainers-bom:1.16.0'
}
dependencies {
@@ -16,21 +16,21 @@ dependencyManagement {
dependency 'org.aspectj:aspectjweaver:1.9.7'
dependency 'com.h2database:h2:1.4.200'
dependency 'com.ibm.db2:jcc:11.5.5.0'
dependency 'com.microsoft.sqlserver:mssql-jdbc:7.4.1.jre8'
dependency 'com.oracle.database.jdbc:ojdbc8:19.10.0.0'
dependency 'com.ibm.db2:jcc:11.5.6.0'
dependency 'com.microsoft.sqlserver:mssql-jdbc:9.4.0.jre8'
dependency 'com.oracle.database.jdbc:ojdbc8:21.1.0.0'
dependency 'com.zaxxer:HikariCP:3.4.5'
dependency 'edu.umd.cs.mtc:multithreadedtc:1.01'
dependency 'io.lettuce:lettuce-core:6.1.5.RELEASE'
dependency 'io.lettuce:lettuce-core:6.1.4.RELEASE'
dependency 'javax.annotation:javax.annotation-api:1.3.2'
dependency 'javax.servlet:javax.servlet-api:4.0.1'
dependency 'junit:junit:4.13.2'
dependency 'mysql:mysql-connector-java:8.0.26'
dependency 'org.apache.derby:derby:10.14.2.0'
dependency 'org.assertj:assertj-core:3.19.0'
dependency 'org.hsqldb:hsqldb:2.5.2'
dependency 'org.assertj:assertj-core:3.20.2'
dependency 'org.hsqldb:hsqldb:2.5.1'
dependency 'org.mariadb.jdbc:mariadb-java-client:2.7.4'
dependency 'org.mockito:mockito-core:3.10.0'
dependency 'org.postgresql:postgresql:42.2.24'
dependency 'org.mockito:mockito-core:3.11.2'
dependency 'org.postgresql:postgresql:42.2.23'
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2019 the original author or authors.
* Copyright 2014-2021 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.
@@ -432,7 +432,8 @@ public class DefaultCookieSerializer implements CookieSerializer {
private String getCookiePath(HttpServletRequest request) {
if (this.cookiePath == null) {
return request.getContextPath() + "/";
String contextPath = request.getContextPath();
return (contextPath != null && contextPath.length() > 0) ? contextPath : "/";
}
return this.cookiePath;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2019 the original author or authors.
* Copyright 2014-2021 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.
@@ -109,7 +109,7 @@ class CookieHttpSessionIdResolverTests {
this.strategy.setSessionId(this.request, this.response, this.session.getId());
Cookie sessionCookie = this.response.getCookie(this.cookieName);
assertThat(sessionCookie.getPath()).isEqualTo(this.request.getContextPath() + "/");
assertThat(sessionCookie.getPath()).isEqualTo(this.request.getContextPath());
}
@Test
@@ -131,7 +131,7 @@ class CookieHttpSessionIdResolverTests {
this.strategy.expireSession(this.request, this.response);
Cookie sessionCookie = this.response.getCookie(this.cookieName);
assertThat(sessionCookie.getPath()).isEqualTo(this.request.getContextPath() + "/");
assertThat(sessionCookie.getPath()).isEqualTo(this.request.getContextPath());
}
@Test

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2019 the original author or authors.
* Copyright 2014-2021 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.
@@ -267,7 +267,7 @@ class DefaultCookieSerializerTests {
void writeCookieCookiePathDefaultContextPathUsed() {
this.request.setContextPath("/context");
this.serializer.writeCookieValue(cookieValue(this.sessionId));
assertThat(getCookie().getPath()).isEqualTo("/context/");
assertThat(getCookie().getPath()).isEqualTo("/context");
}
@Test
@@ -275,7 +275,7 @@ class DefaultCookieSerializerTests {
this.request.setContextPath("/context");
this.serializer.setCookiePath(null);
this.serializer.writeCookieValue(cookieValue(this.sessionId));
assertThat(getCookie().getPath()).isEqualTo("/context/");
assertThat(getCookie().getPath()).isEqualTo("/context");
}
@Test

View File

@@ -5,6 +5,14 @@ Rob Winch; Vedran Pavić; Jay Bryant; Eleftheria Stein-Kousathana
:websocketdoc-test-dir: {docs-test-dir}docs/websocket/
:toc: left
ifdef::backend-html5[]
NOTE: This documentation is also available as https://docs.spring.io/spring-session/docs/{spring-session-version}/reference/pdf/spring-session-reference.pdf[PDF].
endif::[]
ifdef::backend-pdf[]
NOTE: This documentation is also available as https://docs.spring.io/spring-session/docs/{spring-session-version}/reference/html5/index.html[HTML].
endif::[]
[[abstract]]
Spring Session provides an API and implementations for managing a user's session information.
@@ -18,28 +26,10 @@ It also provides transparent integration with:
* <<websocket,WebSocket>>: Provides the ability to keep the `HttpSession` alive when receiving WebSocket messages
* <<websession,WebSession>>: Allows replacing the Spring WebFlux's `WebSession` in an application container-neutral way.
== What's New in 2.0
== What's New
The following list highlights what is new in Spring Session 2.0:
* Upgraded to Java 8 and Spring Framework 5 as baseline
* https://github.com/spring-projects/spring-session/issues/683[Added support for managing Spring WebFlux's `WebSession`] with https://github.com/spring-projects/spring-session/issues/816[Redis `ReactiveSessionRepository`]
* https://github.com/spring-projects/spring-session/issues/768[Extracted `SessionRepository` implementations to separate modules]
* Improved https://github.com/spring-projects/spring-session/issues/682[`Session`] and https://github.com/spring-projects/spring-session/issues/809[`SessionRepository`] APIs
* Improved and harmonized configuration support for all supported session stores
* https://github.com/spring-projects/spring-session/pull/713[Added support for configuring default `CookieSerializer` using `SessionCookieConfig`]
* Lots of performance improvements and bug fixes
You can find a complete list of what is new by referring to the changelogs of
* https://github.com/spring-projects/spring-session/milestone/17?closed=1[2.0.0.M1]
* https://github.com/spring-projects/spring-session/milestone/22?closed=1[2.0.0.M2]
* https://github.com/spring-projects/spring-session/milestone/23?closed=1[2.0.0.M3]
* https://github.com/spring-projects/spring-session/milestone/24?closed=1[2.0.0.M4]
* https://github.com/spring-projects/spring-session/milestone/25?closed=1[2.0.0.M5]
* https://github.com/spring-projects/spring-session/milestone/26?closed=1[2.0.0.RC1]
* https://github.com/spring-projects/spring-session/milestone/27?closed=1[2.0.0.RC2]
* https://github.com/spring-projects/spring-session/milestone/30?closed=1[2.0.0.RELEASE]
Check also the Spring Session BOM https://github.com/spring-projects/spring-session-bom/wiki#release-notes[release notes]
for a list of new and noteworthy features, as well as upgrade instructions for each release.
[[samples]]
== Samples and Guides (Start Here)
@@ -156,9 +146,10 @@ Now the situation with project's repositories/modules is as follows:
* https://github.com/spring-projects/spring-session[`spring-session` repository]
** Hosts the Spring Session Core, Spring Session Data Redis, Spring Session JDBC, and Spring Session Hazelcast modules
* https://github.com/spring-projects/spring-session-data-mongodb[`spring-session-data-mongodb` repository]
** Hosts the Spring Session Data MongoDB module
** Hosts the Spring Session Data MongoDB module. Spring Session Data MongoDB has its own user guide, which you can find at the [https://spring.io/projects/spring-session-data-mongodb#learnSpring site].
* https://github.com/spring-projects/spring-session-data-geode[`spring-session-data-geode` repository]
** Hosts the Spring Session Data Geode and Spring Session Data Geode modules
** Hosts the Spring Session Data Geode modules. Spring Session Data Geode has its own user guide, which you can find at the [https://spring.io/projects/spring-session-data-geode#learn site].
Finally, Spring Session now also provides a Maven BOM ("`bill of materials`") module in order to help users with version management concerns:

View File

@@ -42,7 +42,7 @@ dependencies {
testRuntime "org.junit.jupiter:junit-jupiter-engine"
integrationTestCompile "org.testcontainers:testcontainers"
integrationTestCompile "com.hazelcast:hazelcast:4.2.2"
integrationTestCompile "com.hazelcast:hazelcast:4.2"
integrationTestCompile project(":spring-session-hazelcast")
}

View File

@@ -16,9 +16,6 @@
package org.springframework.session.hazelcast;
import java.time.Duration;
import java.time.Instant;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.map.IMap;
import org.junit.jupiter.api.Test;
@@ -201,51 +198,4 @@ abstract class AbstractHazelcast4IndexedSessionRepositoryITests {
this.repository.deleteById(sessionId);
}
@Test
void createAndUpdateSessionWhileKeepingOriginalTimeToLiveConfiguredOnRepository() {
final Duration defaultSessionTimeout = Duration.ofSeconds(1800);
final IMap<String, MapSession> hazelcastMap = this.hazelcastInstance
.getMap(Hazelcast4IndexedSessionRepository.DEFAULT_SESSION_MAP_NAME);
HazelcastSession session = this.repository.createSession();
String sessionId = session.getId();
this.repository.save(session);
assertThat(session.getMaxInactiveInterval()).isEqualTo(defaultSessionTimeout);
assertThat(hazelcastMap.getEntryView(sessionId).getTtl()).isEqualTo(defaultSessionTimeout.toMillis());
session = this.repository.findById(sessionId);
session.setLastAccessedTime(Instant.now());
this.repository.save(session);
session = this.repository.findById(sessionId);
assertThat(session.getMaxInactiveInterval()).isEqualTo(defaultSessionTimeout);
assertThat(hazelcastMap.getEntryView(sessionId).getTtl()).isEqualTo(defaultSessionTimeout.toMillis());
}
@Test
void createAndUpdateSessionWhileKeepingTimeToLiveSetOnSession() {
final Duration individualSessionTimeout = Duration.ofSeconds(23);
final IMap<String, MapSession> hazelcastMap = this.hazelcastInstance
.getMap(Hazelcast4IndexedSessionRepository.DEFAULT_SESSION_MAP_NAME);
HazelcastSession session = this.repository.createSession();
session.setMaxInactiveInterval(individualSessionTimeout);
String sessionId = session.getId();
this.repository.save(session);
assertThat(session.getMaxInactiveInterval()).isEqualTo(individualSessionTimeout);
assertThat(hazelcastMap.getEntryView(sessionId).getTtl()).isEqualTo(individualSessionTimeout.toMillis());
session = this.repository.findById(sessionId);
session.setAttribute("attribute", "value");
this.repository.save(session);
session = this.repository.findById(sessionId);
assertThat(session.getMaxInactiveInterval()).isEqualTo(individualSessionTimeout);
assertThat(hazelcastMap.getEntryView(sessionId).getTtl()).isEqualTo(individualSessionTimeout.toMillis());
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2021 the original author or authors.
* Copyright 2014-2020 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.
@@ -57,7 +57,7 @@ import static org.assertj.core.api.Assertions.assertThat;
@WebAppConfiguration
class SessionEventHazelcast4IndexedSessionRepositoryTests<S extends Session> {
private static final int MAX_INACTIVE_INTERVAL_IN_SECONDS = 2;
private static final int MAX_INACTIVE_INTERVAL_IN_SECONDS = 1;
@Autowired
private SessionRepository<S> repository;
@@ -199,29 +199,6 @@ class SessionEventHazelcast4IndexedSessionRepositoryTests<S extends Session> {
assertThat(this.repository.findById(sessionToUpdate.getId())).isNull();
}
@Test // gh-1899
void updateSessionAndExpireAfterOriginalTimeToLiveTest() throws InterruptedException {
S sessionToSave = this.repository.createSession();
this.repository.save(sessionToSave);
assertThat(this.registry.receivedEvent(sessionToSave.getId())).isTrue();
assertThat(this.registry.<SessionCreatedEvent>getEvent(sessionToSave.getId()))
.isInstanceOf(SessionCreatedEvent.class);
this.registry.clear();
S sessionToUpdate = this.repository.findById(sessionToSave.getId());
sessionToUpdate.setLastAccessedTime(Instant.now());
this.repository.save(sessionToUpdate);
assertThat(this.registry.receivedEvent(sessionToUpdate.getId())).isTrue();
assertThat(this.registry.<SessionExpiredEvent>getEvent(sessionToUpdate.getId()))
.isInstanceOf(SessionExpiredEvent.class);
// Assert this after the expired event was received because it would otherwise do
// its own expiration check and explicitly delete the session from Hazelcast
// regardless of the TTL of the IMap entry.
assertThat(this.repository.findById(sessionToUpdate.getId())).isNull();
}
@Configuration
@EnableHazelcastHttpSession(maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS)
static class HazelcastSessionConfig {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2021 the original author or authors.
* Copyright 2014-2020 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.
@@ -54,6 +54,7 @@ import org.springframework.session.events.SessionCreatedEvent;
import org.springframework.session.events.SessionDeletedEvent;
import org.springframework.session.events.SessionExpiredEvent;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* A {@link org.springframework.session.SessionRepository} implementation using Hazelcast
@@ -127,6 +128,8 @@ public class Hazelcast4IndexedSessionRepository
private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT";
private static final boolean SUPPORTS_SET_TTL = ClassUtils.hasAtLeastOneMethodWithName(IMap.class, "setTtl");
private static final Log logger = LogFactory.getLog(Hazelcast4IndexedSessionRepository.class);
private final HazelcastInstance hazelcastInstance;
@@ -259,6 +262,9 @@ public class Hazelcast4IndexedSessionRepository
entryProcessor.setLastAccessedTime(session.getLastAccessedTime());
}
if (session.maxInactiveIntervalChanged) {
if (SUPPORTS_SET_TTL) {
updateTtl(session);
}
entryProcessor.setMaxInactiveInterval(session.getMaxInactiveInterval());
}
if (!session.delta.isEmpty()) {
@@ -269,6 +275,10 @@ public class Hazelcast4IndexedSessionRepository
session.clearChangeFlags();
}
private void updateTtl(HazelcastSession session) {
this.sessions.setTtl(session.getId(), session.getMaxInactiveInterval().getSeconds(), TimeUnit.SECONDS);
}
@Override
public HazelcastSession findById(String id) {
MapSession saved = this.sessions.get(id);
@@ -406,7 +416,6 @@ public class Hazelcast4IndexedSessionRepository
@Override
public void setMaxInactiveInterval(Duration interval) {
Assert.notNull(interval, "interval must not be null");
this.delegate.setMaxInactiveInterval(interval);
this.maxInactiveIntervalChanged = true;
flushImmediateIfNecessary();

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2021 the original author or authors.
* Copyright 2014-2020 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.
@@ -63,8 +63,13 @@ public class Hazelcast4SessionUpdateEntryProcessor implements EntryProcessor<Str
}
}
}
((ExtendedMapEntry<String, MapSession>) entry).setValue(value, value.getMaxInactiveInterval().getSeconds(),
TimeUnit.SECONDS);
if (this.maxInactiveInterval != null) {
((ExtendedMapEntry<String, MapSession>) entry).setValue(value, this.maxInactiveInterval.getSeconds(),
TimeUnit.SECONDS);
}
else {
entry.setValue(value);
}
return Boolean.TRUE;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2021 the original author or authors.
* Copyright 2014-2020 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.
@@ -46,6 +46,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
@@ -253,6 +254,7 @@ class Hazelcast4IndexedSessionRepositoryTests {
session.setMaxInactiveInterval(Duration.ofSeconds(1));
verify(this.sessions, times(1)).set(eq(sessionId), eq(session.getDelegate()), isA(Long.class),
eq(TimeUnit.SECONDS));
verify(this.sessions).setTtl(eq(sessionId), anyLong(), any());
verify(this.sessions, times(1)).executeOnKey(eq(sessionId), any(EntryProcessor.class));
this.repository.save(session);

View File

@@ -1,126 +0,0 @@
/*
* Copyright 2014-2021 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 org.springframework.session.hazelcast;
import java.time.Duration;
import java.time.Instant;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;
import com.hazelcast.map.ExtendedMapEntry;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.session.MapSession;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
class Hazelcast4SessionUpdateEntryProcessorTest {
private Hazelcast4SessionUpdateEntryProcessor processor;
@BeforeEach
void setUp() {
this.processor = new Hazelcast4SessionUpdateEntryProcessor();
}
@Test
void shouldReturnFalseIfNoSessionExistsInHazelcastMapEntry() {
@SuppressWarnings("unchecked")
ExtendedMapEntry<String, MapSession> mapEntry = mock(ExtendedMapEntry.class);
Object result = this.processor.process(mapEntry);
assertThat(result).isEqualTo(Boolean.FALSE);
}
@Test
void shouldUpdateMaxInactiveIntervalOnSessionAndSetMapEntryValueWithNewTimeToLive() {
Duration newMaxInactiveInterval = Duration.ofSeconds(123L);
MapSession mapSession = new MapSession();
@SuppressWarnings("unchecked")
ExtendedMapEntry<String, MapSession> mapEntry = mock(ExtendedMapEntry.class);
given(mapEntry.getValue()).willReturn(mapSession);
this.processor.setMaxInactiveInterval(newMaxInactiveInterval);
Object result = this.processor.process(mapEntry);
assertThat(result).isEqualTo(Boolean.TRUE);
assertThat(mapSession.getMaxInactiveInterval()).isEqualTo(newMaxInactiveInterval);
verify(mapEntry).setValue(mapSession, newMaxInactiveInterval.getSeconds(), TimeUnit.SECONDS);
}
@Test
void shouldSetMapEntryValueWithOldTimeToLiveIfNoChangeToMaxInactiveIntervalIsRegistered() {
Duration maxInactiveInterval = Duration.ofSeconds(123L);
MapSession mapSession = new MapSession();
mapSession.setMaxInactiveInterval(maxInactiveInterval);
@SuppressWarnings("unchecked")
ExtendedMapEntry<String, MapSession> mapEntry = mock(ExtendedMapEntry.class);
given(mapEntry.getValue()).willReturn(mapSession);
Object result = this.processor.process(mapEntry);
assertThat(result).isEqualTo(Boolean.TRUE);
assertThat(mapSession.getMaxInactiveInterval()).isEqualTo(maxInactiveInterval);
verify(mapEntry).setValue(mapSession, maxInactiveInterval.getSeconds(), TimeUnit.SECONDS);
}
@Test
void shouldUpdateLastAccessTimeOnSessionAndSetMapEntryValueWithOldTimeToLive() {
Instant lastAccessTime = Instant.ofEpochSecond(1234L);
MapSession mapSession = new MapSession();
@SuppressWarnings("unchecked")
ExtendedMapEntry<String, MapSession> mapEntry = mock(ExtendedMapEntry.class);
given(mapEntry.getValue()).willReturn(mapSession);
this.processor.setLastAccessedTime(lastAccessTime);
Object result = this.processor.process(mapEntry);
assertThat(result).isEqualTo(Boolean.TRUE);
assertThat(mapSession.getLastAccessedTime()).isEqualTo(lastAccessTime);
verify(mapEntry).setValue(mapSession, mapSession.getMaxInactiveInterval().getSeconds(), TimeUnit.SECONDS);
}
@Test
void shouldUpdateSessionAttributesFromDeltaAndSetMapEntryValueWithOldTimeToLive() {
MapSession mapSession = new MapSession();
mapSession.setAttribute("changed", "oldValue");
mapSession.setAttribute("removed", "existingValue");
@SuppressWarnings("unchecked")
ExtendedMapEntry<String, MapSession> mapEntry = mock(ExtendedMapEntry.class);
given(mapEntry.getValue()).willReturn(mapSession);
HashMap<String, Object> delta = new HashMap<>();
delta.put("added", "addedValue");
delta.put("changed", "newValue");
delta.put("removed", null);
this.processor.setDelta(delta);
Object result = this.processor.process(mapEntry);
assertThat(result).isEqualTo(Boolean.TRUE);
assertThat((String) mapSession.getAttribute("added")).isEqualTo("addedValue");
assertThat((String) mapSession.getAttribute("changed")).isEqualTo("newValue");
assertThat((String) mapSession.getAttribute("removed")).isNull();
verify(mapEntry).setValue(mapSession, mapSession.getMaxInactiveInterval().getSeconds(), TimeUnit.SECONDS);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2021 the original author or authors.
* Copyright 2014-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -58,7 +58,7 @@ import static org.assertj.core.api.Assertions.assertThat;
@WebAppConfiguration
class SessionEventHazelcastIndexedSessionRepositoryTests<S extends Session> {
private static final int MAX_INACTIVE_INTERVAL_IN_SECONDS = 2;
private static final int MAX_INACTIVE_INTERVAL_IN_SECONDS = 1;
@Autowired
private SessionRepository<S> repository;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2021 the original author or authors.
* Copyright 2014-2020 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.
@@ -30,12 +30,12 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.FlushMode;
import org.springframework.session.IndexResolver;
import org.springframework.session.MapSession;
import org.springframework.session.SaveMode;
import org.springframework.session.Session;
import org.springframework.session.SessionRepository;
import org.springframework.session.config.SessionRepositoryCustomizer;
import org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration;
import org.springframework.session.hazelcast.Hazelcast4IndexedSessionRepository;
@@ -85,7 +85,7 @@ public class HazelcastHttpSessionConfiguration extends SpringHttpSessionConfigur
}
@Bean
public FindByIndexNameSessionRepository<?> sessionRepository() {
public SessionRepository<?> sessionRepository() {
if (hazelcast4) {
return createHazelcast4IndexedSessionRepository();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2020 the original author or authors.
* Copyright 2014-2021 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.
@@ -46,7 +46,7 @@ final class DatabaseContainers {
}
static MySQLContainer<?> mySql() {
return new MySQLContainer<>("mysql:8.0.27");
return new MySQLContainer<>("mysql:8.0.26");
}
static OracleContainer oracle() {
@@ -68,7 +68,7 @@ final class DatabaseContainers {
}
static PostgreSQLContainer<?> postgreSql() {
return new PostgreSQLContainer<>("postgres:13.3");
return new PostgreSQLContainer<>("postgres:13.4");
}
static MSSQLServerContainer<?> sqlServer() {

View File

@@ -1,15 +1,15 @@
dependencyManagement {
imports {
mavenBom 'com.fasterxml.jackson:jackson-bom:2.12.5'
mavenBom 'com.fasterxml.jackson:jackson-bom:2.12.4'
}
dependencies {
dependency 'ch.qos.logback:logback-classic:1.2.6'
dependency 'ch.qos.logback:logback-classic:1.2.5'
dependency 'com.maxmind.geoip2:geoip2:2.15.0'
dependency 'javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.2'
dependency 'javax.servlet.jsp:javax.servlet.jsp-api:2.3.3'
dependency 'org.apache.taglibs:taglibs-standard-jstlel:1.2.5'
dependency 'org.seleniumhq.selenium:htmlunit-driver:2.49.1'
dependency 'org.seleniumhq.selenium:htmlunit-driver:2.52.0'
dependency 'org.slf4j:jcl-over-slf4j:1.7.32'
dependency 'org.slf4j:log4j-over-slf4j:1.7.32'
dependency 'org.webjars:bootstrap:2.3.2'

View File

@@ -1,19 +1,19 @@
apply plugin: 'io.spring.convention.spring-sample-boot'
dependencies {
compile project(':spring-session-hazelcast')
compile "org.springframework.boot:spring-boot-starter-web"
compile "org.springframework.boot:spring-boot-starter-actuator"
compile "org.springframework.boot:spring-boot-starter-thymeleaf"
compile "org.springframework.boot:spring-boot-starter-security"
compile "com.hazelcast:hazelcast"
compile "nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect"
compile "org.webjars:bootstrap"
compile "org.webjars:html5shiv"
compile "org.webjars:webjars-locator-core"
compile project(':spring-session-hazelcast')
compile "org.springframework.boot:spring-boot-starter-web"
compile "org.springframework.boot:spring-boot-starter-thymeleaf"
compile "org.springframework.boot:spring-boot-starter-security"
compile "com.hazelcast:hazelcast-client"
compile "nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect"
compile "org.webjars:bootstrap"
compile "org.webjars:html5shiv"
compile "org.webjars:webjars-locator-core"
testCompile "org.springframework.boot:spring-boot-starter-test"
testCompile "org.junit.jupiter:junit-jupiter-api"
testRuntime "org.junit.jupiter:junit-jupiter-engine"
integrationTestCompile seleniumDependencies
testCompile "org.springframework.boot:spring-boot-starter-test"
testCompile "org.junit.jupiter:junit-jupiter-api"
testRuntime "org.junit.jupiter:junit-jupiter-engine"
integrationTestCompile seleniumDependencies
integrationTestCompile "org.testcontainers:testcontainers"
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2021 the original author or authors.
* Copyright 2014-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,29 +19,32 @@ package sample;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.openqa.selenium.WebDriver;
import org.testcontainers.containers.GenericContainer;
import sample.pages.HomePage;
import sample.pages.LoginPage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.session.SessionsEndpoint;
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.context.ApplicationContext;
import org.springframework.session.hazelcast.HazelcastIndexedSessionRepository;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.junit.jupiter.SpringExtension;
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 Ellie Bahadori
*/
@ExtendWith(SpringExtension.class)
@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
class BootTests {
private static final String DOCKER_IMAGE = "hazelcast/hazelcast:latest";
@Autowired
private MockMvc mockMvc;
@@ -57,12 +60,6 @@ class BootTests {
this.driver.quit();
}
@Test // gh-1905
void contextLoads(ApplicationContext context) {
assertThat(context.getBeansOfType(HazelcastIndexedSessionRepository.class)).hasSize(1);
assertThat(context.getBeansOfType(SessionsEndpoint.class)).hasSize(1);
}
@Test
void home() {
LoginPage login = HomePage.go(this.driver);
@@ -86,4 +83,16 @@ class BootTests {
login.assertAt();
}
@TestConfiguration
static class Config {
@Bean
GenericContainer hazelcastContainer() {
GenericContainer hazelcastContainer = new GenericContainer(DOCKER_IMAGE).withExposedPorts(5701);
hazelcastContainer.start();
return hazelcastContainer;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2021 the original author or authors.
* Copyright 2014-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,7 +34,7 @@ import org.springframework.session.hazelcast.PrincipalNameExtractor;
public class SessionConfig {
@Bean
public Config hazelcastConfig() {
public Config clientConfig() {
Config config = new Config();
NetworkConfig networkConfig = config.getNetworkConfig();
networkConfig.setPort(0);

View File

@@ -1,2 +1 @@
management.endpoints.web.exposure.include=sessions
spring.security.user.password=password

View File

@@ -1,20 +1,20 @@
apply plugin: 'io.spring.convention.spring-sample-boot'
dependencies {
compile project(':spring-session-hazelcast')
compile project(':hazelcast4')
compile "org.springframework.boot:spring-boot-starter-web"
compile "org.springframework.boot:spring-boot-starter-actuator"
compile "org.springframework.boot:spring-boot-starter-thymeleaf"
compile "org.springframework.boot:spring-boot-starter-security"
compile "com.hazelcast:hazelcast:4.2.2"
compile "nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect"
compile "org.webjars:bootstrap"
compile "org.webjars:html5shiv"
compile "org.webjars:webjars-locator-core"
compile project(':spring-session-hazelcast')
compile project(':hazelcast4')
compile "org.springframework.boot:spring-boot-starter-web"
compile "org.springframework.boot:spring-boot-starter-thymeleaf"
compile "org.springframework.boot:spring-boot-starter-security"
compile "com.hazelcast:hazelcast:4.2.2"
compile "nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect"
compile "org.webjars:bootstrap"
compile "org.webjars:html5shiv"
compile "org.webjars:webjars-locator-core"
testCompile "org.springframework.boot:spring-boot-starter-test"
testCompile "org.junit.jupiter:junit-jupiter-api"
testRuntime "org.junit.jupiter:junit-jupiter-engine"
integrationTestCompile seleniumDependencies
testCompile "org.springframework.boot:spring-boot-starter-test"
testCompile "org.junit.jupiter:junit-jupiter-api"
testRuntime "org.junit.jupiter:junit-jupiter-engine"
integrationTestCompile seleniumDependencies
integrationTestCompile "org.testcontainers:testcontainers"
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2021 the original author or authors.
* Copyright 2014-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,26 +19,29 @@ package sample;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.openqa.selenium.WebDriver;
import org.testcontainers.containers.GenericContainer;
import sample.pages.HomePage;
import sample.pages.LoginPage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.session.SessionsEndpoint;
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.context.ApplicationContext;
import org.springframework.session.hazelcast.Hazelcast4IndexedSessionRepository;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder;
import static org.assertj.core.api.Assertions.assertThat;
@ExtendWith(SpringExtension.class)
@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
class BootTests {
private static final String DOCKER_IMAGE = "hazelcast/hazelcast:latest";
@Autowired
private MockMvc mockMvc;
@@ -54,12 +57,6 @@ class BootTests {
this.driver.quit();
}
@Test // gh-1905
void contextLoads(ApplicationContext context) {
assertThat(context.getBeansOfType(Hazelcast4IndexedSessionRepository.class)).hasSize(1);
assertThat(context.getBeansOfType(SessionsEndpoint.class)).hasSize(1);
}
@Test
void home() {
LoginPage login = HomePage.go(this.driver);
@@ -83,4 +80,16 @@ class BootTests {
login.assertAt();
}
@TestConfiguration
static class Config {
@Bean
GenericContainer hazelcastContainer() {
GenericContainer hazelcastContainer = new GenericContainer(DOCKER_IMAGE).withExposedPorts(5701);
hazelcastContainer.start();
return hazelcastContainer;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2021 the original author or authors.
* Copyright 2014-2020 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.
@@ -35,7 +35,7 @@ import org.springframework.session.hazelcast.HazelcastSessionSerializer;
public class SessionConfig {
@Bean
public Config hazelcastConfig() {
public Config clientConfig() {
Config config = new Config();
NetworkConfig networkConfig = config.getNetworkConfig();
networkConfig.setPort(0);

View File

@@ -1,2 +1 @@
management.endpoints.web.exposure.include=sessions
spring.security.user.password=password

View File

@@ -1,2 +1,3 @@
#server.servlet.session.timeout=1m
spring.h2.console.enabled=true
spring.jpa.defer-datasource-initialization=true