Compare commits
53 Commits
2.2.0.M1
...
2.1.8.RELE
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
84479a0ba0 | ||
|
|
643f9cfd1a | ||
|
|
95e6d710ba | ||
|
|
0cf723c6aa | ||
|
|
66cc442b5f | ||
|
|
23d8c18b22 | ||
|
|
28d1d4fd00 | ||
|
|
e82a856d00 | ||
|
|
e40e55d1e9 | ||
|
|
a289938c7c | ||
|
|
63927aa4da | ||
|
|
88071796a2 | ||
|
|
76bc9563bb | ||
|
|
819b341a9f | ||
|
|
3b0be07c8e | ||
|
|
6761f2cc68 | ||
|
|
c8f266cea2 | ||
|
|
7d71aa5d00 | ||
|
|
bee9c7c2e2 | ||
|
|
8788165966 | ||
|
|
aadc806447 | ||
|
|
0fb942f795 | ||
|
|
49ebaa5cb7 | ||
|
|
a48edd5e71 | ||
|
|
17ddfc0fa8 | ||
|
|
f2f9562a01 | ||
|
|
4c50da3982 | ||
|
|
b1d53874e4 | ||
|
|
cc2a75b668 | ||
|
|
006acba02a | ||
|
|
168ad85cc5 | ||
|
|
3f61a30568 | ||
|
|
318036828d | ||
|
|
326e7070b1 | ||
|
|
81ca7d5f83 | ||
|
|
de8e47e4c3 | ||
|
|
ef6b9f8812 | ||
|
|
14be439da0 | ||
|
|
2631ddc446 | ||
|
|
1e15f0d010 | ||
|
|
87c4fb7103 | ||
|
|
e05ca40d26 | ||
|
|
68615cdfce | ||
|
|
51f9bd17ac | ||
|
|
15f7d91660 | ||
|
|
edbeb98f9a | ||
|
|
354346a62c | ||
|
|
aa81c18093 | ||
|
|
d426792b57 | ||
|
|
2007f45ea0 | ||
|
|
3d8fa846d5 | ||
|
|
c9c172ce89 | ||
|
|
8b189962eb |
18
Jenkinsfile
vendored
18
Jenkinsfile
vendored
@@ -15,7 +15,9 @@ try {
|
||||
node('ubuntu1804') {
|
||||
checkout scm
|
||||
try {
|
||||
sh './gradlew clean check --no-daemon --refresh-dependencies'
|
||||
withEnv(["JAVA_HOME=${tool 'jdk8'}"]) {
|
||||
sh './gradlew clean check --no-daemon --refresh-dependencies --stacktrace'
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
currentBuild.result = 'FAILED: check'
|
||||
@@ -35,7 +37,7 @@ try {
|
||||
checkout scm
|
||||
try {
|
||||
withEnv(["JAVA_HOME=${tool 'jdk9'}"]) {
|
||||
sh './gradlew clean test --no-daemon --refresh-dependencies'
|
||||
sh './gradlew clean test --no-daemon --refresh-dependencies --stacktrace'
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
@@ -53,7 +55,7 @@ try {
|
||||
checkout scm
|
||||
try {
|
||||
withEnv(["JAVA_HOME=${tool 'jdk10'}"]) {
|
||||
sh './gradlew clean test --no-daemon --refresh-dependencies'
|
||||
sh './gradlew clean test --no-daemon --refresh-dependencies --stacktrace'
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
@@ -71,7 +73,7 @@ try {
|
||||
checkout scm
|
||||
try {
|
||||
withEnv(["JAVA_HOME=${tool 'jdk11'}"]) {
|
||||
sh './gradlew clean test integrationTest --no-daemon --refresh-dependencies'
|
||||
sh './gradlew clean test integrationTest --no-daemon --refresh-dependencies --stacktrace'
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
@@ -93,7 +95,9 @@ try {
|
||||
withCredentials([string(credentialsId: 'spring-gpg-passphrase', variable: 'SIGNING_PASSWORD')]) {
|
||||
withCredentials([usernamePassword(credentialsId: 'oss-token', passwordVariable: 'OSSRH_PASSWORD', usernameVariable: 'OSSRH_USERNAME')]) {
|
||||
withCredentials([usernamePassword(credentialsId: '02bd1690-b54f-4c9f-819d-a77cb7a9822c', usernameVariable: 'ARTIFACTORY_USERNAME', passwordVariable: 'ARTIFACTORY_PASSWORD')]) {
|
||||
sh './gradlew deployArtifacts finalizeDeployArtifacts --stacktrace --no-daemon --refresh-dependencies -Psigning.secretKeyRingFile=$SIGNING_KEYRING_FILE -Psigning.keyId=$SPRING_SIGNING_KEYID -Psigning.password=$SIGNING_PASSWORD -PossrhUsername=$OSSRH_USERNAME -PossrhPassword=$OSSRH_PASSWORD -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD'
|
||||
withEnv(["JAVA_HOME=${tool 'jdk8'}"]) {
|
||||
sh './gradlew deployArtifacts finalizeDeployArtifacts --no-daemon --refresh-dependencies --stacktrace -Psigning.secretKeyRingFile=$SIGNING_KEYRING_FILE -Psigning.keyId=$SPRING_SIGNING_KEYID -Psigning.password=$SIGNING_PASSWORD -PossrhUsername=$OSSRH_USERNAME -PossrhPassword=$OSSRH_PASSWORD -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,7 +116,9 @@ try {
|
||||
checkout scm
|
||||
try {
|
||||
withCredentials([file(credentialsId: 'docs.spring.io-jenkins_private_ssh_key', variable: 'DEPLOY_SSH_KEY')]) {
|
||||
sh './gradlew deployDocs --stacktrace --no-daemon --refresh-dependencies -PdeployDocsSshKeyPath=$DEPLOY_SSH_KEY -PdeployDocsSshUsername=$SPRING_DOCS_USERNAME'
|
||||
withEnv(["JAVA_HOME=${tool 'jdk8'}"]) {
|
||||
sh './gradlew deployDocs --no-daemon --refresh-dependencies --stacktrace -PdeployDocsSshKeyPath=$DEPLOY_SSH_KEY -PdeployDocsSshUsername=$SPRING_DOCS_USERNAME'
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
|
||||
16
build.gradle
16
build.gradle
@@ -4,7 +4,7 @@ buildscript {
|
||||
snapshotBuild = version.endsWith('SNAPSHOT')
|
||||
milestoneBuild = !(releaseBuild || snapshotBuild)
|
||||
|
||||
springBootVersion = '2.1.3.RELEASE'
|
||||
springBootVersion = '2.1.6.RELEASE'
|
||||
}
|
||||
|
||||
repositories {
|
||||
@@ -23,16 +23,8 @@ apply plugin: 'io.spring.convention.root'
|
||||
group = 'org.springframework.session'
|
||||
description = 'Spring Session'
|
||||
|
||||
gradle.taskGraph.whenReady { graph ->
|
||||
def jacocoEnabled = graph.allTasks.any { it instanceof JacocoReport }
|
||||
subprojects {
|
||||
plugins.withType(JavaPlugin) {
|
||||
sourceCompatibility = 1.8
|
||||
}
|
||||
plugins.withType(JacocoPlugin) {
|
||||
tasks.withType(Test) {
|
||||
jacoco.enabled = jacocoEnabled
|
||||
}
|
||||
}
|
||||
subprojects {
|
||||
plugins.withType(JavaPlugin) {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
version=2.2.0.M1
|
||||
version=2.1.8.RELEASE
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom 'com.fasterxml.jackson:jackson-bom:2.9.6'
|
||||
mavenBom 'io.projectreactor:reactor-bom:Californium-SR6'
|
||||
mavenBom 'org.springframework:spring-framework-bom:5.2.0.M1'
|
||||
mavenBom 'org.springframework.data:spring-data-releasetrain:Moore-M3'
|
||||
mavenBom 'org.springframework.security:spring-security-bom:5.2.0.M1'
|
||||
mavenBom 'org.testcontainers:testcontainers-bom:1.11.1'
|
||||
mavenBom 'io.projectreactor:reactor-bom:Californium-SR10'
|
||||
mavenBom 'org.springframework:spring-framework-bom:5.1.9.RELEASE'
|
||||
mavenBom 'org.springframework.data:spring-data-releasetrain:Lovelace-SR10'
|
||||
mavenBom 'org.springframework.security:spring-security-bom:5.1.5.RELEASE'
|
||||
mavenBom 'org.testcontainers:testcontainers-bom:1.12.0'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
dependencySet(group: 'com.hazelcast', version: '3.12') {
|
||||
dependencySet(group: 'com.hazelcast', version: '3.11.4') {
|
||||
entry 'hazelcast'
|
||||
entry 'hazelcast-client'
|
||||
}
|
||||
|
||||
dependency 'com.h2database:h2:1.4.199'
|
||||
dependency 'com.microsoft.sqlserver:mssql-jdbc:7.2.1.jre8'
|
||||
dependency 'com.microsoft.sqlserver:mssql-jdbc:7.4.1.jre8'
|
||||
dependency 'com.zaxxer:HikariCP:3.3.1'
|
||||
dependency 'edu.umd.cs.mtc:multithreadedtc:1.01'
|
||||
dependency 'io.lettuce:lettuce-core:5.1.6.RELEASE'
|
||||
dependency 'io.lettuce:lettuce-core:5.1.8.RELEASE'
|
||||
dependency 'javax.annotation:javax.annotation-api:1.3.2'
|
||||
dependency 'javax.servlet:javax.servlet-api:4.0.1'
|
||||
dependency 'junit:junit:4.12'
|
||||
dependency 'mysql:mysql-connector-java:8.0.15'
|
||||
dependency 'mysql:mysql-connector-java:8.0.17'
|
||||
dependency 'org.apache.derby:derby:10.14.2.0'
|
||||
dependency 'org.assertj:assertj-core:3.12.2'
|
||||
dependency 'org.hsqldb:hsqldb:2.4.1'
|
||||
dependency 'org.mariadb.jdbc:mariadb-java-client:2.4.1'
|
||||
dependency 'org.mockito:mockito-core:2.26.0'
|
||||
dependency 'org.postgresql:postgresql:42.2.5'
|
||||
dependency 'org.assertj:assertj-core:3.13.2'
|
||||
dependency 'org.hsqldb:hsqldb:2.5.0'
|
||||
dependency 'org.mariadb.jdbc:mariadb-java-client:2.4.3'
|
||||
dependency 'org.mockito:mockito-core:3.0.0'
|
||||
dependency 'org.postgresql:postgresql:42.2.6'
|
||||
}
|
||||
}
|
||||
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.3.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
18
gradlew
vendored
18
gradlew
vendored
@@ -1,21 +1,5 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright 2015 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.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
@@ -44,7 +28,7 @@ APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
18
gradlew.bat
vendored
18
gradlew.bat
vendored
@@ -1,19 +1,3 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem http://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@@ -30,7 +14,7 @@ set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
@@ -46,7 +46,7 @@ import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDr
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
|
||||
public class FindByUsernameTests {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.4";
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.5";
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@@ -50,7 +50,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
@AutoConfigureMockMvc
|
||||
public class HttpRedisJsonTest {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.4";
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.5";
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@@ -39,7 +39,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
@SpringBootTest
|
||||
public class RedisSerializerTest {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.4";
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.5";
|
||||
|
||||
@SpringSessionRedisOperations
|
||||
private RedisTemplate<Object, Object> sessionRedisTemplate;
|
||||
|
||||
@@ -45,7 +45,7 @@ import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDr
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
|
||||
public class BootTests {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.4";
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.5";
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@@ -47,7 +47,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
public class AttributeTests {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.4";
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.5";
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
@@ -52,7 +52,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
public class ApplicationTests {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.4";
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.5";
|
||||
|
||||
@Value("${local.server.port}")
|
||||
private String port;
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
|
||||
@Profile("embedded-redis")
|
||||
public class EmbeddedRedisConfig {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.4";
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.5";
|
||||
|
||||
@Bean
|
||||
public GenericContainer redisContainer() {
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
|
||||
@Profile("embedded-redis")
|
||||
public class EmbeddedRedisConfig {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.4";
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.5";
|
||||
|
||||
@Bean
|
||||
public GenericContainer redisContainer() {
|
||||
|
||||
@@ -54,7 +54,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
@WebAppConfiguration
|
||||
public class RestMockMvcTests {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.4";
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.5";
|
||||
|
||||
@Autowired
|
||||
private SessionRepositoryFilter<? extends Session> sessionRepositoryFilter;
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
|
||||
@Profile("embedded-redis")
|
||||
public class EmbeddedRedisConfig {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.4";
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.5";
|
||||
|
||||
@Bean
|
||||
public GenericContainer redisContainer() {
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
|
||||
@Profile("embedded-redis")
|
||||
public class EmbeddedRedisConfig {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.4";
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.5";
|
||||
|
||||
@Bean
|
||||
public GenericContainer redisContainer() {
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
|
||||
@Profile("embedded-redis")
|
||||
public class EmbeddedRedisConfig {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.4";
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.5";
|
||||
|
||||
@Bean
|
||||
public GenericContainer redisContainer() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2019 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.
|
||||
@@ -126,6 +126,7 @@ public class SpringHttpSessionConfiguration implements ApplicationContextAware {
|
||||
SessionRepository<S> sessionRepository) {
|
||||
SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter<>(
|
||||
sessionRepository);
|
||||
sessionRepositoryFilter.setServletContext(this.servletContext);
|
||||
sessionRepositoryFilter.setHttpSessionIdResolver(this.httpSessionIdResolver);
|
||||
return sessionRepositoryFilter;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,6 +18,7 @@ package org.springframework.session.web.http;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
@@ -66,27 +67,66 @@ abstract class OncePerRequestFilter implements Filter {
|
||||
}
|
||||
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
||||
String alreadyFilteredAttributeName = this.alreadyFilteredAttributeName;
|
||||
boolean hasAlreadyFilteredAttribute = request
|
||||
.getAttribute(this.alreadyFilteredAttributeName) != null;
|
||||
.getAttribute(alreadyFilteredAttributeName) != null;
|
||||
|
||||
if (hasAlreadyFilteredAttribute) {
|
||||
|
||||
if (DispatcherType.ERROR.equals(request.getDispatcherType())) {
|
||||
doFilterNestedErrorDispatch(httpRequest, httpResponse, filterChain);
|
||||
return;
|
||||
}
|
||||
// Proceed without invoking this filter...
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
else {
|
||||
// Do invoke this filter...
|
||||
request.setAttribute(this.alreadyFilteredAttributeName, Boolean.TRUE);
|
||||
request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);
|
||||
try {
|
||||
doFilterInternal(httpRequest, httpResponse, filterChain);
|
||||
}
|
||||
finally {
|
||||
// Remove the "already filtered" request attribute for this request.
|
||||
request.removeAttribute(this.alreadyFilteredAttributeName);
|
||||
request.removeAttribute(alreadyFilteredAttributeName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the request attribute that identifies that a request is already
|
||||
* filtered.
|
||||
* <p>
|
||||
* The default implementation takes the configured name of the concrete filter
|
||||
* instance and appends ".FILTERED". If the filter is not fully initialized, it falls
|
||||
* back to its class name.
|
||||
* @return the name of request attribute indicating already filtered request
|
||||
* @see #ALREADY_FILTERED_SUFFIX
|
||||
*/
|
||||
protected String getAlreadyFilteredAttributeName() {
|
||||
return this.alreadyFilteredAttributeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Typically an ERROR dispatch happens after the REQUEST dispatch completes, and the
|
||||
* filter chain starts anew. On some servers however the ERROR dispatch may be nested
|
||||
* within the REQUEST dispatch, e.g. as a result of calling {@code sendError} on the
|
||||
* response. In that case we are still in the filter chain, on the same thread, but
|
||||
* the request and response have been switched to the original, unwrapped ones.
|
||||
* <p>
|
||||
* Sub-classes may use this method to filter such nested ERROR dispatches and re-apply
|
||||
* wrapping on the request or response. {@code ThreadLocal} context, if any, should
|
||||
* still be active as we are still nested within the filter chain.
|
||||
* @param request the request
|
||||
* @param response the response
|
||||
* @param filterChain the filter chain
|
||||
* @throws ServletException if request is not HTTP request
|
||||
* @throws IOException in case of I/O operation exception
|
||||
*/
|
||||
protected void doFilterNestedErrorDispatch(HttpServletRequest request, HttpServletResponse response,
|
||||
FilterChain filterChain) throws ServletException, IOException {
|
||||
doFilter(request, response, filterChain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same contract as for {@code doFilter}, but guaranteed to be just invoked once per
|
||||
* request within a single request thread.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2019 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.
|
||||
@@ -106,6 +106,8 @@ public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFi
|
||||
|
||||
private final SessionRepository<S> sessionRepository;
|
||||
|
||||
private ServletContext servletContext;
|
||||
|
||||
private HttpSessionIdResolver httpSessionIdResolver = new CookieHttpSessionIdResolver();
|
||||
|
||||
/**
|
||||
@@ -141,7 +143,7 @@ public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFi
|
||||
request.setAttribute(SESSION_REPOSITORY_ATTR, this.sessionRepository);
|
||||
|
||||
SessionRepositoryRequestWrapper wrappedRequest = new SessionRepositoryRequestWrapper(
|
||||
request, response);
|
||||
request, response, this.servletContext);
|
||||
SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryResponseWrapper(
|
||||
wrappedRequest, response);
|
||||
|
||||
@@ -153,6 +155,16 @@ public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFi
|
||||
}
|
||||
}
|
||||
|
||||
public void setServletContext(ServletContext servletContext) {
|
||||
this.servletContext = servletContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFilterNestedErrorDispatch(HttpServletRequest request, HttpServletResponse response,
|
||||
FilterChain filterChain) throws ServletException, IOException {
|
||||
doFilterInternal(request, response, filterChain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows ensuring that the session is saved if the response is committed.
|
||||
*
|
||||
@@ -197,6 +209,8 @@ public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFi
|
||||
|
||||
private final HttpServletResponse response;
|
||||
|
||||
private final ServletContext servletContext;
|
||||
|
||||
private S requestedSession;
|
||||
|
||||
private boolean requestedSessionCached;
|
||||
@@ -208,9 +222,10 @@ public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFi
|
||||
private boolean requestedSessionInvalidated;
|
||||
|
||||
private SessionRepositoryRequestWrapper(HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
HttpServletResponse response, ServletContext servletContext) {
|
||||
super(request);
|
||||
this.response = response;
|
||||
this.servletContext = servletContext;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -331,6 +346,15 @@ public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFi
|
||||
return currentSession;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletContext getServletContext() {
|
||||
if (this.servletContext != null) {
|
||||
return this.servletContext;
|
||||
}
|
||||
// Servlet 3.0+
|
||||
return super.getServletContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpSessionWrapper getSession() {
|
||||
return getSession(true);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2017 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.
|
||||
@@ -20,6 +20,7 @@ import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
@@ -32,6 +33,7 @@ import org.junit.Test;
|
||||
import org.springframework.mock.web.MockFilterChain;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.web.util.WebUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -95,4 +97,36 @@ public class OncePerRequestFilterTests {
|
||||
|
||||
assertThat(this.invocations).containsOnly(this.filter, filter2);
|
||||
}
|
||||
|
||||
@Test // gh-1470
|
||||
public void filterNestedErrorDispatch() throws ServletException, IOException {
|
||||
TestOncePerRequestFilter filter = new TestOncePerRequestFilter();
|
||||
this.request.setAttribute(filter.getAlreadyFilteredAttributeName(), Boolean.TRUE);
|
||||
this.request.setDispatcherType(DispatcherType.ERROR);
|
||||
this.request.setAttribute(WebUtils.ERROR_REQUEST_URI_ATTRIBUTE, "/error");
|
||||
filter.doFilter(this.request, new MockHttpServletResponse(), this.chain);
|
||||
assertThat(filter.didFilter).isFalse();
|
||||
assertThat(filter.didFilterNestedErrorDispatch).isTrue();
|
||||
}
|
||||
|
||||
private static class TestOncePerRequestFilter extends OncePerRequestFilter {
|
||||
|
||||
private boolean didFilter;
|
||||
|
||||
private boolean didFilterNestedErrorDispatch;
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
|
||||
FilterChain filterChain) {
|
||||
this.didFilter = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFilterNestedErrorDispatch(HttpServletRequest request, HttpServletResponse response,
|
||||
FilterChain filterChain) {
|
||||
this.didFilterNestedErrorDispatch = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2019 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.
|
||||
@@ -54,6 +54,7 @@ import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.mock.web.MockFilterChain;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.session.MapSession;
|
||||
import org.springframework.session.MapSessionRepository;
|
||||
import org.springframework.session.Session;
|
||||
@@ -239,6 +240,22 @@ public class SessionRepositoryFilterTests {
|
||||
});
|
||||
}
|
||||
|
||||
// gh-111
|
||||
@Test
|
||||
public void doFilterServletContextExplicit() throws Exception {
|
||||
final ServletContext expectedContext = new MockServletContext();
|
||||
this.filter = new SessionRepositoryFilter<>(this.sessionRepository);
|
||||
this.filter.setServletContext(expectedContext);
|
||||
|
||||
doFilter(new DoInFilter() {
|
||||
@Override
|
||||
public void doFilter(HttpServletRequest wrappedRequest) {
|
||||
ServletContext context = wrappedRequest.getSession().getServletContext();
|
||||
assertThat(context).isSameAs(expectedContext);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterMaxInactiveIntervalDefault() throws Exception {
|
||||
doFilter(new DoInFilter() {
|
||||
|
||||
@@ -29,7 +29,7 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
|
||||
*/
|
||||
public abstract class AbstractRedisITests {
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.4";
|
||||
private static final String DOCKER_IMAGE = "redis:5.0.5";
|
||||
|
||||
protected static class BaseConfig {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -20,6 +20,7 @@ import java.time.Instant;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -68,6 +69,17 @@ public class ReactiveRedisOperationsSessionRepositoryITests extends AbstractRedi
|
||||
assertThat(this.repository.findById(toSave.getId()).block()).isNull();
|
||||
}
|
||||
|
||||
@Test // gh-1399
|
||||
public void saveMultipleTimes() {
|
||||
ReactiveRedisOperationsSessionRepository.RedisSession session = this.repository
|
||||
.createSession().block();
|
||||
session.setAttribute("attribute1", "value1");
|
||||
Mono<Void> save1 = this.repository.save(session);
|
||||
session.setAttribute("attribute2", "value2");
|
||||
Mono<Void> save2 = this.repository.save(session);
|
||||
Mono.zip(save1, save2).block();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void putAllOnSingleAttrDoesNotRemoveOld() {
|
||||
ReactiveRedisOperationsSessionRepository.RedisSession toSave = this.repository
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -143,23 +143,15 @@ public class ReactiveRedisOperationsSessionRepository implements
|
||||
|
||||
@Override
|
||||
public Mono<Void> save(RedisSession session) {
|
||||
Mono<Void> result = session.saveChangeSessionId().and(session.saveDelta())
|
||||
.and((s) -> {
|
||||
session.isNew = false;
|
||||
s.onComplete();
|
||||
});
|
||||
if (session.isNew) {
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
String sessionKey = getSessionKey(
|
||||
session.hasChangedSessionId() ? session.originalSessionId
|
||||
: session.getId());
|
||||
return this.sessionRedisOperations.hasKey(sessionKey)
|
||||
.flatMap((exists) -> exists ? result
|
||||
: Mono.error(new IllegalStateException(
|
||||
"Session was invalidated")));
|
||||
return session.save();
|
||||
}
|
||||
String sessionKey = getSessionKey(
|
||||
session.hasChangedSessionId() ? session.originalSessionId
|
||||
: session.getId());
|
||||
return this.sessionRedisOperations.hasKey(sessionKey).flatMap((exists) -> exists
|
||||
? session.save()
|
||||
: Mono.error(new IllegalStateException("Session was invalidated")));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -305,7 +297,7 @@ public class ReactiveRedisOperationsSessionRepository implements
|
||||
|
||||
private void flushImmediateIfNecessary() {
|
||||
if (ReactiveRedisOperationsSessionRepository.this.redisFlushMode == RedisFlushMode.IMMEDIATE) {
|
||||
saveDelta();
|
||||
save();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,6 +306,11 @@ public class ReactiveRedisOperationsSessionRepository implements
|
||||
flushImmediateIfNecessary();
|
||||
}
|
||||
|
||||
private Mono<Void> save() {
|
||||
return Mono.defer(() -> saveChangeSessionId().then(saveDelta())
|
||||
.doOnSuccess((aVoid) -> this.isNew = false));
|
||||
}
|
||||
|
||||
private Mono<Void> saveDelta() {
|
||||
if (this.delta.isEmpty()) {
|
||||
return Mono.empty();
|
||||
@@ -321,7 +318,7 @@ public class ReactiveRedisOperationsSessionRepository implements
|
||||
|
||||
String sessionKey = getSessionKey(getId());
|
||||
Mono<Boolean> update = ReactiveRedisOperationsSessionRepository.this.sessionRedisOperations
|
||||
.opsForHash().putAll(sessionKey, this.delta);
|
||||
.opsForHash().putAll(sessionKey, new HashMap<>(this.delta));
|
||||
Mono<Boolean> setTtl = ReactiveRedisOperationsSessionRepository.this.sessionRedisOperations
|
||||
.expire(sessionKey, getMaxInactiveInterval());
|
||||
|
||||
|
||||
@@ -418,7 +418,7 @@ public class RedisOperationsSessionRepository implements
|
||||
|
||||
@Override
|
||||
public void save(RedisSession session) {
|
||||
session.saveDelta();
|
||||
session.save();
|
||||
if (session.isNew()) {
|
||||
String sessionCreatedKey = getSessionCreatedChannel(session.getId());
|
||||
this.sessionRedisOperations.convertAndSend(sessionCreatedKey, session.delta);
|
||||
@@ -516,12 +516,13 @@ public class RedisOperationsSessionRepository implements
|
||||
|
||||
@Override
|
||||
public RedisSession createSession() {
|
||||
RedisSession redisSession = new RedisSession();
|
||||
if (this.defaultMaxInactiveInterval != null) {
|
||||
redisSession.setMaxInactiveInterval(
|
||||
Duration.ofSeconds(this.defaultMaxInactiveInterval));
|
||||
}
|
||||
return redisSession;
|
||||
Duration maxInactiveInterval = Duration
|
||||
.ofSeconds((this.defaultMaxInactiveInterval != null)
|
||||
? this.defaultMaxInactiveInterval
|
||||
: MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
|
||||
RedisSession session = new RedisSession(maxInactiveInterval);
|
||||
session.flushImmediateIfNecessary();
|
||||
return session;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -711,14 +712,17 @@ public class RedisOperationsSessionRepository implements
|
||||
/**
|
||||
* Creates a new instance ensuring to mark all of the new attributes to be
|
||||
* persisted in the next save operation.
|
||||
*
|
||||
* @param maxInactiveInterval the amount of time that the {@link Session} should
|
||||
* be kept alive between client requests.
|
||||
*/
|
||||
RedisSession() {
|
||||
RedisSession(Duration maxInactiveInterval) {
|
||||
this(new MapSession());
|
||||
this.cached.setMaxInactiveInterval(maxInactiveInterval);
|
||||
this.delta.put(CREATION_TIME_ATTR, getCreationTime().toEpochMilli());
|
||||
this.delta.put(MAX_INACTIVE_ATTR, (int) getMaxInactiveInterval().getSeconds());
|
||||
this.delta.put(LAST_ACCESSED_ATTR, getLastAccessedTime().toEpochMilli());
|
||||
this.isNew = true;
|
||||
this.flushImmediateIfNecessary();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -808,7 +812,7 @@ public class RedisOperationsSessionRepository implements
|
||||
|
||||
private void flushImmediateIfNecessary() {
|
||||
if (RedisOperationsSessionRepository.this.redisFlushMode == RedisFlushMode.IMMEDIATE) {
|
||||
saveDelta();
|
||||
save();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -817,16 +821,20 @@ public class RedisOperationsSessionRepository implements
|
||||
this.flushImmediateIfNecessary();
|
||||
}
|
||||
|
||||
private void save() {
|
||||
saveChangeSessionId();
|
||||
saveDelta();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves any attributes that have been changed and updates the expiration of this
|
||||
* session.
|
||||
*/
|
||||
private void saveDelta() {
|
||||
String sessionId = getId();
|
||||
saveChangeSessionId(sessionId);
|
||||
if (this.delta.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
String sessionId = getId();
|
||||
getSessionBoundHashOperations(sessionId).putAll(this.delta);
|
||||
String principalSessionKey = getSessionAttrNameKey(
|
||||
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME);
|
||||
@@ -859,30 +867,32 @@ public class RedisOperationsSessionRepository implements
|
||||
.onExpirationUpdated(originalExpiration, this);
|
||||
}
|
||||
|
||||
private void saveChangeSessionId(String sessionId) {
|
||||
if (!sessionId.equals(this.originalSessionId)) {
|
||||
if (!isNew()) {
|
||||
String originalSessionIdKey = getSessionKey(this.originalSessionId);
|
||||
String sessionIdKey = getSessionKey(sessionId);
|
||||
try {
|
||||
RedisOperationsSessionRepository.this.sessionRedisOperations
|
||||
.rename(originalSessionIdKey, sessionIdKey);
|
||||
}
|
||||
catch (NonTransientDataAccessException ex) {
|
||||
handleErrNoSuchKeyError(ex);
|
||||
}
|
||||
String originalExpiredKey = getExpiredKey(this.originalSessionId);
|
||||
String expiredKey = getExpiredKey(sessionId);
|
||||
try {
|
||||
RedisOperationsSessionRepository.this.sessionRedisOperations
|
||||
.rename(originalExpiredKey, expiredKey);
|
||||
}
|
||||
catch (NonTransientDataAccessException ex) {
|
||||
handleErrNoSuchKeyError(ex);
|
||||
}
|
||||
}
|
||||
this.originalSessionId = sessionId;
|
||||
private void saveChangeSessionId() {
|
||||
String sessionId = getId();
|
||||
if (sessionId.equals(this.originalSessionId)) {
|
||||
return;
|
||||
}
|
||||
if (!isNew()) {
|
||||
String originalSessionIdKey = getSessionKey(this.originalSessionId);
|
||||
String sessionIdKey = getSessionKey(sessionId);
|
||||
try {
|
||||
RedisOperationsSessionRepository.this.sessionRedisOperations
|
||||
.rename(originalSessionIdKey, sessionIdKey);
|
||||
}
|
||||
catch (NonTransientDataAccessException ex) {
|
||||
handleErrNoSuchKeyError(ex);
|
||||
}
|
||||
String originalExpiredKey = getExpiredKey(this.originalSessionId);
|
||||
String expiredKey = getExpiredKey(sessionId);
|
||||
try {
|
||||
RedisOperationsSessionRepository.this.sessionRedisOperations
|
||||
.rename(originalExpiredKey, expiredKey);
|
||||
}
|
||||
catch (NonTransientDataAccessException ex) {
|
||||
handleErrNoSuchKeyError(ex);
|
||||
}
|
||||
}
|
||||
this.originalSessionId = sessionId;
|
||||
}
|
||||
|
||||
private void handleErrNoSuchKeyError(NonTransientDataAccessException ex) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2019 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.
|
||||
@@ -125,8 +125,7 @@ public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguratio
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RedisMessageListenerContainer springSessionRedisMessageListenerContainer(
|
||||
RedisOperationsSessionRepository sessionRepository) {
|
||||
public RedisMessageListenerContainer redisMessageListenerContainer() {
|
||||
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
|
||||
container.setConnectionFactory(this.redisConnectionFactory);
|
||||
if (this.redisTaskExecutor != null) {
|
||||
@@ -135,13 +134,12 @@ public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguratio
|
||||
if (this.redisSubscriptionExecutor != null) {
|
||||
container.setSubscriptionExecutor(this.redisSubscriptionExecutor);
|
||||
}
|
||||
container.addMessageListener(sessionRepository,
|
||||
Arrays.asList(
|
||||
new ChannelTopic(sessionRepository.getSessionDeletedChannel()),
|
||||
new ChannelTopic(sessionRepository.getSessionExpiredChannel())));
|
||||
container.addMessageListener(sessionRepository,
|
||||
container.addMessageListener(sessionRepository(), Arrays.asList(
|
||||
new ChannelTopic(sessionRepository().getSessionDeletedChannel()),
|
||||
new ChannelTopic(sessionRepository().getSessionExpiredChannel())));
|
||||
container.addMessageListener(sessionRepository(),
|
||||
Collections.singletonList(new PatternTopic(
|
||||
sessionRepository.getSessionCreatedChannelPrefix() + "*")));
|
||||
sessionRepository().getSessionCreatedChannelPrefix() + "*")));
|
||||
return container;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -132,9 +132,10 @@ public class ReactiveRedisOperationsSessionRepositoryTests {
|
||||
|
||||
@Test
|
||||
public void createSessionDefaultMaxInactiveInterval() {
|
||||
StepVerifier.create(this.repository.createSession()).consumeNextWith(
|
||||
(session) -> assertThat(session.getMaxInactiveInterval()).isEqualTo(Duration
|
||||
.ofSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS)))
|
||||
StepVerifier.create(this.repository.createSession())
|
||||
.consumeNextWith((session) -> assertThat(session.getMaxInactiveInterval())
|
||||
.isEqualTo(Duration.ofSeconds(
|
||||
MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS)))
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@@ -155,30 +156,26 @@ public class ReactiveRedisOperationsSessionRepositoryTests {
|
||||
given(this.redisOperations.expire(anyString(), any()))
|
||||
.willReturn(Mono.just(true));
|
||||
|
||||
StepVerifier
|
||||
.create(this.repository.createSession().doOnNext(this.repository::save))
|
||||
.consumeNextWith((session) -> {
|
||||
verify(this.redisOperations).opsForHash();
|
||||
verify(this.hashOperations).putAll(anyString(), this.delta.capture());
|
||||
verify(this.redisOperations).expire(anyString(), any());
|
||||
verifyZeroInteractions(this.redisOperations);
|
||||
verifyZeroInteractions(this.hashOperations);
|
||||
RedisSession newSession = this.repository.new RedisSession();
|
||||
StepVerifier.create(this.repository.save(newSession)).verifyComplete();
|
||||
|
||||
Map<String, Object> delta = this.delta.getAllValues().get(0);
|
||||
assertThat(delta.size()).isEqualTo(3);
|
||||
assertThat(delta.get(
|
||||
ReactiveRedisOperationsSessionRepository.CREATION_TIME_KEY))
|
||||
.isEqualTo(session.getCreationTime().toEpochMilli());
|
||||
assertThat(delta.get(
|
||||
ReactiveRedisOperationsSessionRepository.MAX_INACTIVE_INTERVAL_KEY))
|
||||
.isEqualTo((int) Duration.ofSeconds(
|
||||
MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS)
|
||||
.getSeconds());
|
||||
assertThat(delta.get(
|
||||
ReactiveRedisOperationsSessionRepository.LAST_ACCESSED_TIME_KEY))
|
||||
.isEqualTo(
|
||||
session.getLastAccessedTime().toEpochMilli());
|
||||
}).verifyComplete();
|
||||
verify(this.redisOperations).opsForHash();
|
||||
verify(this.hashOperations).putAll(anyString(), this.delta.capture());
|
||||
verify(this.redisOperations).expire(anyString(), any());
|
||||
verifyZeroInteractions(this.redisOperations);
|
||||
verifyZeroInteractions(this.hashOperations);
|
||||
|
||||
Map<String, Object> delta = this.delta.getAllValues().get(0);
|
||||
assertThat(delta.size()).isEqualTo(3);
|
||||
assertThat(delta.get(ReactiveRedisOperationsSessionRepository.CREATION_TIME_KEY))
|
||||
.isEqualTo(newSession.getCreationTime().toEpochMilli());
|
||||
assertThat(delta
|
||||
.get(ReactiveRedisOperationsSessionRepository.MAX_INACTIVE_INTERVAL_KEY))
|
||||
.isEqualTo(
|
||||
(int) newSession.getMaxInactiveInterval().getSeconds());
|
||||
assertThat(delta
|
||||
.get(ReactiveRedisOperationsSessionRepository.LAST_ACCESSED_TIME_KEY))
|
||||
.isEqualTo(newSession.getLastAccessedTime().toEpochMilli());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -207,7 +204,7 @@ public class ReactiveRedisOperationsSessionRepositoryTests {
|
||||
|
||||
RedisSession session = this.repository.new RedisSession(this.cached);
|
||||
session.setLastAccessedTime(Instant.ofEpochMilli(12345678L));
|
||||
Mono.just(session).subscribe(this.repository::save);
|
||||
StepVerifier.create(this.repository.save(session)).verifyComplete();
|
||||
|
||||
verify(this.redisOperations).hasKey(anyString());
|
||||
verify(this.redisOperations).opsForHash();
|
||||
@@ -232,7 +229,7 @@ public class ReactiveRedisOperationsSessionRepositoryTests {
|
||||
String attrName = "attrName";
|
||||
RedisSession session = this.repository.new RedisSession(this.cached);
|
||||
session.setAttribute(attrName, "attrValue");
|
||||
Mono.just(session).subscribe(this.repository::save);
|
||||
StepVerifier.create(this.repository.save(session)).verifyComplete();
|
||||
|
||||
verify(this.redisOperations).hasKey(anyString());
|
||||
verify(this.redisOperations).opsForHash();
|
||||
@@ -257,7 +254,7 @@ public class ReactiveRedisOperationsSessionRepositoryTests {
|
||||
String attrName = "attrName";
|
||||
RedisSession session = this.repository.new RedisSession(new MapSession());
|
||||
session.removeAttribute(attrName);
|
||||
Mono.just(session).subscribe(this.repository::save);
|
||||
StepVerifier.create(this.repository.save(session)).verifyComplete();
|
||||
|
||||
verify(this.redisOperations).hasKey(anyString());
|
||||
verify(this.redisOperations).opsForHash();
|
||||
@@ -333,24 +330,25 @@ public class ReactiveRedisOperationsSessionRepositoryTests {
|
||||
given(this.hashOperations.entries(anyString()))
|
||||
.willReturn(Flux.fromIterable(map.entrySet()));
|
||||
|
||||
StepVerifier.create(this.repository.findById("test")).consumeNextWith((session) -> {
|
||||
verify(this.redisOperations).opsForHash();
|
||||
verify(this.hashOperations).entries(anyString());
|
||||
verifyZeroInteractions(this.redisOperations);
|
||||
verifyZeroInteractions(this.hashOperations);
|
||||
StepVerifier.create(this.repository.findById("test"))
|
||||
.consumeNextWith((session) -> {
|
||||
verify(this.redisOperations).opsForHash();
|
||||
verify(this.hashOperations).entries(anyString());
|
||||
verifyZeroInteractions(this.redisOperations);
|
||||
verifyZeroInteractions(this.hashOperations);
|
||||
|
||||
assertThat(session.getId()).isEqualTo(expected.getId());
|
||||
assertThat(session.getAttributeNames())
|
||||
.isEqualTo(expected.getAttributeNames());
|
||||
assertThat(session.<String>getAttribute(attribute1))
|
||||
.isEqualTo(expected.getAttribute(attribute1));
|
||||
assertThat(session.<String>getAttribute(attribute2))
|
||||
.isEqualTo(expected.getAttribute(attribute2));
|
||||
assertThat(session.getId()).isEqualTo(expected.getId());
|
||||
assertThat(session.getAttributeNames())
|
||||
.isEqualTo(expected.getAttributeNames());
|
||||
assertThat(session.<String>getAttribute(attribute1))
|
||||
.isEqualTo(expected.getAttribute(attribute1));
|
||||
assertThat(session.<String>getAttribute(attribute2))
|
||||
.isEqualTo(expected.getAttribute(attribute2));
|
||||
assertThat(session.getCreationTime().truncatedTo(ChronoUnit.MILLIS))
|
||||
.isEqualTo(expected.getCreationTime()
|
||||
.truncatedTo(ChronoUnit.MILLIS));
|
||||
assertThat(session.getMaxInactiveInterval())
|
||||
.isEqualTo(expected.getMaxInactiveInterval());
|
||||
.isEqualTo(expected.getMaxInactiveInterval());
|
||||
assertThat(
|
||||
session.getLastAccessedTime().truncatedTo(ChronoUnit.MILLIS))
|
||||
.isEqualTo(expected.getLastAccessedTime()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -343,7 +343,8 @@ public class RedisOperationsSessionRepositoryTests {
|
||||
@Test
|
||||
public void redisSessionGetAttributes() {
|
||||
String attrName = "attrName";
|
||||
RedisSession session = this.redisRepository.new RedisSession();
|
||||
RedisSession session = this.redisRepository.new RedisSession(
|
||||
Duration.ofSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS));
|
||||
assertThat(session.getAttributeNames()).isEmpty();
|
||||
session.setAttribute(attrName, "attrValue");
|
||||
assertThat(session.getAttributeNames()).containsOnly(attrName);
|
||||
@@ -757,6 +758,23 @@ public class RedisOperationsSessionRepositoryTests {
|
||||
.isEqualTo(session.getCreationTime().toEpochMilli());
|
||||
}
|
||||
|
||||
@Test // gh-1409
|
||||
public void flushModeImmediateCreateWithCustomMaxInactiveInterval() {
|
||||
given(this.redisOperations.boundHashOps(anyString()))
|
||||
.willReturn(this.boundHashOperations);
|
||||
given(this.redisOperations.boundSetOps(anyString()))
|
||||
.willReturn(this.boundSetOperations);
|
||||
given(this.redisOperations.boundValueOps(anyString()))
|
||||
.willReturn(this.boundValueOperations);
|
||||
this.redisRepository.setDefaultMaxInactiveInterval(60);
|
||||
this.redisRepository.setRedisFlushMode(RedisFlushMode.IMMEDIATE);
|
||||
this.redisRepository.createSession();
|
||||
Map<String, Object> delta = getDelta();
|
||||
assertThat(delta.size()).isEqualTo(3);
|
||||
assertThat(delta.get(RedisOperationsSessionRepository.MAX_INACTIVE_ATTR))
|
||||
.isEqualTo(60);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void flushModeImmediateSetAttribute() {
|
||||
given(this.redisOperations.boundHashOps(anyString()))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2019 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.
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.session.data.redis.config.annotation.web.http;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.junit.After;
|
||||
@@ -32,7 +31,6 @@ import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
import org.springframework.data.redis.connection.RedisConnection;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisOperations;
|
||||
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
import org.springframework.session.data.redis.RedisOperationsSessionRepository;
|
||||
import org.springframework.session.data.redis.config.annotation.SpringSessionRedisConnectionFactory;
|
||||
@@ -192,17 +190,6 @@ public class RedisHttpSessionConfigurationTests {
|
||||
.withMessageContaining("expected single matching bean but found 2");
|
||||
}
|
||||
|
||||
@Test // gh-1252
|
||||
public void customRedisMessageListenerContainerConfig() {
|
||||
registerAndRefresh(RedisConfig.class,
|
||||
CustomRedisMessageListenerContainerConfig.class);
|
||||
Map<String, RedisMessageListenerContainer> beans = this.context
|
||||
.getBeansOfType(RedisMessageListenerContainer.class);
|
||||
assertThat(beans).hasSize(2);
|
||||
assertThat(beans).containsKeys("springSessionRedisMessageListenerContainer",
|
||||
"redisMessageListenerContainer");
|
||||
}
|
||||
|
||||
private void registerAndRefresh(Class<?>... annotatedClasses) {
|
||||
this.context.register(annotatedClasses);
|
||||
this.context.refresh();
|
||||
@@ -327,15 +314,4 @@ public class RedisHttpSessionConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableRedisHttpSession
|
||||
static class CustomRedisMessageListenerContainerConfig {
|
||||
|
||||
@Bean
|
||||
public RedisMessageListenerContainer redisMessageListenerContainer() {
|
||||
return new RedisMessageListenerContainer();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -48,7 +48,7 @@ import org.springframework.test.context.web.WebAppConfiguration;
|
||||
public class HazelcastClientRepositoryITests extends AbstractHazelcastRepositoryITests {
|
||||
|
||||
private static GenericContainer container = new GenericContainer<>(
|
||||
"hazelcast/hazelcast:3.12")
|
||||
"hazelcast/hazelcast:3.11.4")
|
||||
.withExposedPorts(5701)
|
||||
.withEnv("JAVA_OPTS",
|
||||
"-Dhazelcast.config=/opt/hazelcast/config_ext/hazelcast.xml")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<hazelcast xmlns="http://www.hazelcast.com/schema/config"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.hazelcast.com/schema/config https://www.hazelcast.com/schema/config/hazelcast-config-3.12.xsd">
|
||||
xsi:schemaLocation="http://www.hazelcast.com/schema/config https://www.hazelcast.com/schema/config/hazelcast-config-3.11.xsd">
|
||||
|
||||
<user-code-deployment enabled="true">
|
||||
<class-cache-mode>ETERNAL</class-cache-mode>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<hazelcast xmlns="http://www.hazelcast.com/schema/config"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.hazelcast.com/schema/config https://www.hazelcast.com/schema/config/hazelcast-config-3.12.xsd">
|
||||
xsi:schemaLocation="http://www.hazelcast.com/schema/config https://www.hazelcast.com/schema/config/hazelcast-config-3.11.xsd">
|
||||
|
||||
<group>
|
||||
<name>spring-session-it-test-idle-time-map-name</name>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<hazelcast xmlns="http://www.hazelcast.com/schema/config"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.hazelcast.com/schema/config https://www.hazelcast.com/schema/config/hazelcast-config-3.12.xsd">
|
||||
xsi:schemaLocation="http://www.hazelcast.com/schema/config https://www.hazelcast.com/schema/config/hazelcast-config-3.11.xsd">
|
||||
|
||||
<group>
|
||||
<name>spring-session-it-test-map-name</name>
|
||||
|
||||
@@ -40,8 +40,6 @@ import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.session.FindByIndexNameSessionRepository;
|
||||
import org.springframework.session.MapSession;
|
||||
import org.springframework.session.Session;
|
||||
@@ -123,15 +121,11 @@ public class HazelcastSessionRepository implements
|
||||
*/
|
||||
public static final String PRINCIPAL_NAME_ATTRIBUTE = "principalName";
|
||||
|
||||
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(HazelcastSessionRepository.class);
|
||||
|
||||
private static final PrincipalNameResolver principalNameResolver = new PrincipalNameResolver();
|
||||
|
||||
private final HazelcastInstance hazelcastInstance;
|
||||
|
||||
private ApplicationEventPublisher eventPublisher = new ApplicationEventPublisher() {
|
||||
@@ -433,18 +427,14 @@ public class HazelcastSessionRepository implements
|
||||
public void setAttribute(String attributeName, Object attributeValue) {
|
||||
this.delegate.setAttribute(attributeName, attributeValue);
|
||||
this.delta.put(attributeName, attributeValue);
|
||||
if (SPRING_SECURITY_CONTEXT.equals(attributeName)) {
|
||||
String principal = (attributeValue != null)
|
||||
? principalNameResolver.resolvePrincipal(this)
|
||||
: null;
|
||||
this.delegate.setAttribute(PRINCIPAL_NAME_INDEX_NAME, principal);
|
||||
}
|
||||
flushImmediateIfNecessary();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttribute(String attributeName) {
|
||||
setAttribute(attributeName, null);
|
||||
this.delegate.removeAttribute(attributeName);
|
||||
this.delta.put(attributeName, null);
|
||||
flushImmediateIfNecessary();
|
||||
}
|
||||
|
||||
MapSession getDelegate() {
|
||||
@@ -472,27 +462,4 @@ public class HazelcastSessionRepository implements
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the Spring Security principal name.
|
||||
*/
|
||||
static class PrincipalNameResolver {
|
||||
|
||||
private SpelExpressionParser parser = new SpelExpressionParser();
|
||||
|
||||
public String resolvePrincipal(Session session) {
|
||||
String principalName = session.getAttribute(PRINCIPAL_NAME_INDEX_NAME);
|
||||
if (principalName != null) {
|
||||
return principalName;
|
||||
}
|
||||
Object authentication = session.getAttribute(SPRING_SECURITY_CONTEXT);
|
||||
if (authentication != null) {
|
||||
Expression expression = this.parser
|
||||
.parseExpression("authentication?.name");
|
||||
return expression.getValue(authentication, String.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,8 +19,11 @@ package org.springframework.session.hazelcast;
|
||||
import com.hazelcast.query.extractor.ValueCollector;
|
||||
import com.hazelcast.query.extractor.ValueExtractor;
|
||||
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.session.FindByIndexNameSessionRepository;
|
||||
import org.springframework.session.MapSession;
|
||||
import org.springframework.session.Session;
|
||||
|
||||
/**
|
||||
* Hazelcast {@link ValueExtractor} responsible for extracting principal name from the
|
||||
@@ -31,14 +34,43 @@ import org.springframework.session.MapSession;
|
||||
*/
|
||||
public class PrincipalNameExtractor extends ValueExtractor<MapSession, String> {
|
||||
|
||||
private static final PrincipalNameResolver PRINCIPAL_NAME_RESOLVER =
|
||||
new PrincipalNameResolver();
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void extract(MapSession target, String argument, ValueCollector collector) {
|
||||
String principalName = target
|
||||
.getAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME);
|
||||
public void extract(MapSession target, String argument,
|
||||
ValueCollector collector) {
|
||||
String principalName = PRINCIPAL_NAME_RESOLVER.resolvePrincipal(target);
|
||||
if (principalName != null) {
|
||||
collector.addObject(principalName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the Spring Security principal name.
|
||||
*/
|
||||
static class PrincipalNameResolver {
|
||||
|
||||
private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT";
|
||||
|
||||
private SpelExpressionParser parser = new SpelExpressionParser();
|
||||
|
||||
public String resolvePrincipal(Session session) {
|
||||
String principalName = session.getAttribute(
|
||||
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME);
|
||||
if (principalName != null) {
|
||||
return principalName;
|
||||
}
|
||||
Object authentication = session.getAttribute(SPRING_SECURITY_CONTEXT);
|
||||
if (authentication != null) {
|
||||
Expression expression = this.parser
|
||||
.parseExpression("authentication?.name");
|
||||
return expression.getValue(authentication, String.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -797,18 +797,14 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
|
||||
MapSession delegate = (MapSession) ReflectionTestUtils.getField(session,
|
||||
"delegate");
|
||||
|
||||
Supplier attribute1 = delegate.getAttribute("attribute1");
|
||||
assertThat(ReflectionTestUtils.getField(attribute1, "value")).isNull();
|
||||
assertThat((String) session.getAttribute("attribute1")).isEqualTo("value1");
|
||||
assertThat(delegate).isNotNull();
|
||||
assertThat(ReflectionTestUtils
|
||||
.getField((Supplier) delegate.getAttribute("attribute1"), "value"))
|
||||
.isEqualTo("value1");
|
||||
assertThat(ReflectionTestUtils
|
||||
.getField((Supplier) delegate.getAttribute("attribute2"), "value"))
|
||||
.isNull();
|
||||
assertThat(ReflectionTestUtils.getField(attribute1, "value")).isEqualTo("value1");
|
||||
Supplier attribute2 = delegate.getAttribute("attribute2");
|
||||
assertThat(ReflectionTestUtils.getField(attribute2, "value")).isNull();
|
||||
assertThat((String) session.getAttribute("attribute2")).isEqualTo("value2");
|
||||
assertThat(ReflectionTestUtils
|
||||
.getField((Supplier) delegate.getAttribute("attribute2"), "value"))
|
||||
.isEqualTo("value2");
|
||||
assertThat(ReflectionTestUtils.getField(attribute2, "value")).isEqualTo("value2");
|
||||
}
|
||||
|
||||
@Test // gh-1203
|
||||
|
||||
@@ -72,7 +72,7 @@ final class DatabaseContainers {
|
||||
private static class MariaDb5Container extends MariaDBContainer<MariaDb5Container> {
|
||||
|
||||
MariaDb5Container() {
|
||||
super("mariadb:5.5.63");
|
||||
super("mariadb:5.5.64");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -88,7 +88,7 @@ final class DatabaseContainers {
|
||||
private static class MariaDb10Container extends MariaDBContainer<MariaDb10Container> {
|
||||
|
||||
MariaDb10Container() {
|
||||
super("mariadb:10.3.14");
|
||||
super("mariadb:10.4.7");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -103,7 +103,7 @@ final class DatabaseContainers {
|
||||
private static class MySql5Container extends MySQLContainer<MySql5Container> {
|
||||
|
||||
MySql5Container() {
|
||||
super("mysql:5.7.25");
|
||||
super("mysql:5.7.27");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -123,7 +123,7 @@ final class DatabaseContainers {
|
||||
private static class MySql8Container extends MySQLContainer<MySql8Container> {
|
||||
|
||||
MySql8Container() {
|
||||
super("mysql:8.0.15");
|
||||
super("mysql:8.0.17");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -143,7 +143,7 @@ final class DatabaseContainers {
|
||||
extends PostgreSQLContainer<PostgreSql9Container> {
|
||||
|
||||
PostgreSql9Container() {
|
||||
super("postgres:9.6.12");
|
||||
super("postgres:9.6.14");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -152,7 +152,7 @@ final class DatabaseContainers {
|
||||
extends PostgreSQLContainer<PostgreSql10Container> {
|
||||
|
||||
PostgreSql10Container() {
|
||||
super("postgres:10.7");
|
||||
super("postgres:10.9");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -161,7 +161,7 @@ final class DatabaseContainers {
|
||||
extends PostgreSQLContainer<PostgreSql11Container> {
|
||||
|
||||
PostgreSql11Container() {
|
||||
super("postgres:11.2");
|
||||
super("postgres:11.4");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -170,7 +170,7 @@ final class DatabaseContainers {
|
||||
extends MSSQLServerContainer<SqlServer2017Container> {
|
||||
|
||||
SqlServer2017Container() {
|
||||
super("mcr.microsoft.com/mssql/server:2017-CU13");
|
||||
super("mcr.microsoft.com/mssql/server:2017-cu16");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
mcr.microsoft.com/mssql/server:2017-CU13
|
||||
mcr.microsoft.com/mssql/server:2017-cu16
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -532,7 +532,8 @@ public class JdbcOperationsSessionRepository implements
|
||||
public void setValues(PreparedStatement ps, int i) throws SQLException {
|
||||
String attributeName = attributeNames.get(i);
|
||||
ps.setString(1, attributeName);
|
||||
setObjectAsBlob(ps, 2, session.getAttribute(attributeName));
|
||||
getLobHandler().getLobCreator().setBlobAsBytes(ps, 2,
|
||||
serialize(session.getAttribute(attributeName)));
|
||||
ps.setString(3, session.getId());
|
||||
}
|
||||
|
||||
@@ -547,7 +548,8 @@ public class JdbcOperationsSessionRepository implements
|
||||
this.jdbcOperations.update(this.createSessionAttributeQuery, (ps) -> {
|
||||
String attributeName = attributeNames.get(0);
|
||||
ps.setString(1, attributeName);
|
||||
setObjectAsBlob(ps, 2, session.getAttribute(attributeName));
|
||||
getLobHandler().getLobCreator().setBlobAsBytes(ps, 2,
|
||||
serialize(session.getAttribute(attributeName)));
|
||||
ps.setString(3, session.getId());
|
||||
});
|
||||
}
|
||||
@@ -561,7 +563,8 @@ public class JdbcOperationsSessionRepository implements
|
||||
@Override
|
||||
public void setValues(PreparedStatement ps, int i) throws SQLException {
|
||||
String attributeName = attributeNames.get(i);
|
||||
setObjectAsBlob(ps, 1, session.getAttribute(attributeName));
|
||||
getLobHandler().getLobCreator().setBlobAsBytes(ps, 1,
|
||||
serialize(session.getAttribute(attributeName)));
|
||||
ps.setString(2, session.primaryKey);
|
||||
ps.setString(3, attributeName);
|
||||
}
|
||||
@@ -576,7 +579,8 @@ public class JdbcOperationsSessionRepository implements
|
||||
else {
|
||||
this.jdbcOperations.update(this.updateSessionAttributeQuery, (ps) -> {
|
||||
String attributeName = attributeNames.get(0);
|
||||
setObjectAsBlob(ps, 1, session.getAttribute(attributeName));
|
||||
getLobHandler().getLobCreator().setBlobAsBytes(ps, 1,
|
||||
serialize(session.getAttribute(attributeName)));
|
||||
ps.setString(2, session.primaryKey);
|
||||
ps.setString(3, attributeName);
|
||||
});
|
||||
@@ -659,16 +663,17 @@ public class JdbcOperationsSessionRepository implements
|
||||
getQuery(DELETE_SESSIONS_BY_EXPIRY_TIME_QUERY);
|
||||
}
|
||||
|
||||
private void setObjectAsBlob(PreparedStatement ps, int paramIndex, Object object)
|
||||
throws SQLException {
|
||||
byte[] bytes = (byte[]) this.conversionService.convert(object,
|
||||
TypeDescriptor.valueOf(Object.class),
|
||||
TypeDescriptor.valueOf(byte[].class));
|
||||
this.lobHandler.getLobCreator().setBlobAsBytes(ps, paramIndex, bytes);
|
||||
private LobHandler getLobHandler() {
|
||||
return this.lobHandler;
|
||||
}
|
||||
|
||||
private Object getBlobAsObject(ResultSet rs, String columnName) throws SQLException {
|
||||
byte[] bytes = this.lobHandler.getBlobAsBytes(rs, columnName);
|
||||
private byte[] serialize(Object object) {
|
||||
return (byte[]) this.conversionService.convert(object,
|
||||
TypeDescriptor.valueOf(Object.class),
|
||||
TypeDescriptor.valueOf(byte[].class));
|
||||
}
|
||||
|
||||
private Object deserialize(byte[] bytes) {
|
||||
return this.conversionService.convert(bytes, TypeDescriptor.valueOf(byte[].class),
|
||||
TypeDescriptor.valueOf(Object.class));
|
||||
}
|
||||
@@ -898,8 +903,9 @@ public class JdbcOperationsSessionRepository implements
|
||||
}
|
||||
String attributeName = rs.getString("ATTRIBUTE_NAME");
|
||||
if (attributeName != null) {
|
||||
Object attributeValue = getBlobAsObject(rs, "ATTRIBUTE_BYTES");
|
||||
session.delegate.setAttribute(attributeName, lazily(() -> attributeValue));
|
||||
byte[] bytes = getLobHandler().getBlobAsBytes(rs, "ATTRIBUTE_BYTES");
|
||||
session.delegate.setAttribute(attributeName,
|
||||
lazily(() -> deserialize(bytes)));
|
||||
}
|
||||
sessions.add(session);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user