Compare commits

..

21 Commits

Author SHA1 Message Date
Vedran Pavic
1f7232f12e Release 2.0.4.RELEASE 2018-06-13 23:06:09 +02:00
Vedran Pavic
03f0a571b6 Upgrade Spring Data to Kay-SR8
See gh-1094
2018-06-13 22:44:12 +02:00
Vedran Pavic
63a215f73b Disable network join in Hazelcast integration tests 2018-06-13 17:01:57 +02:00
Vedran Pavic
8dac35cf73 Fix session event handling in HazelcastSessionRepository
Previously, invoking HttpServletRequest#changeSessionId on session backed by HazelcastSessionRepository generated generated invalid session destroyed and session created events. This was due to use of IMap#remove and IMap#set when handling the change session id.

This commit improves change session id handling to prevent publishing invalid events by using IMap#delete instead of IMap#remove and keeping track of originally assigned session id.

Closes gh-1077
2018-06-13 16:12:28 +02:00
Vedran Pavic
19b8583d65 Adapt to Spring Framework deprecations
See gh-1092
2018-06-13 05:59:50 +02:00
Vedran Pavic
6de0f44241 Upgrade dependencies 2018-06-13 05:41:23 +02:00
Vedran Pavic
60d6120b9c Upgrade Spring Security to 5.0.6.RELEASE
Closes gh-1095
2018-06-13 05:23:56 +02:00
Vedran Pavic
3bc899e695 Upgrade Spring Framework to 5.0.7.RELEASE
Closes gh-1092
2018-06-12 17:41:16 +02:00
Vedran Pavic
c2fe999d6c Update reference manual to mention BOM module
Closes gh-1099
2018-06-12 12:02:48 +02:00
Vedran Pavic
d214971e72 Upgrade Reactor to Bismuth-SR10
Closes gh-1093
2018-06-11 15:21:55 +02:00
Vedran Pavic
f4704293a1 Update integration tests 2018-06-08 16:48:31 +02:00
Vedran Pavic
a8c4f65903 Upgrade spring-build-conventions to 0.0.16.RELEASE 2018-06-05 21:35:48 +02:00
Vedran Pavic
4a52de0c18 Upgrade Gradle to 4.8 2018-06-05 21:34:19 +02:00
Vedran Pavic
63f105082a Optimize Redis integration tests
This commit ensures that Redis Testcontainers used for integration testing are managed by Spring to ensure proper ordering on shutdown.

Previously, Redis Testcontainer was closed before LettuceConnectionFactory which caused pending commands to hang and added a lot of wait to project build.

Closes gh-1086
2018-06-01 11:50:01 +02:00
Vedran Pavic
f55b793185 Remove Servlet API version check from DefaultCookieSerializer
Closes gh-1079
2018-05-31 10:42:44 +02:00
Vedran Pavic
6d027900ee Fix caching of requested session in SessionRepositoryFilter
Closes gh-1076
2018-05-15 10:03:41 +02:00
Vedran Pavic
42818a1b90 Improve update handling in HazelcastSessionRepository
This commit improves HazelcastSessionRepository.SessionUpdateEntryProcessor to avoid NPE in scenario where save operation was invoked for session that was already deleted.

See gh-1076
2018-05-15 08:16:20 +02:00
Vedran Pavic
b6348736ac Polish contribution
Closes gh-1070
2018-05-14 10:38:27 +02:00
Craig Andrews
60581c6427 Fix delta handling in JdbcOperationsSessionRepository
See gh-1070
2018-05-13 21:05:34 +02:00
Craig Andrews
836ea12e93 Upgrade samples to Spring Boot 2.0.2.RELEASE 2018-05-11 09:34:46 -05:00
Rob Winch
670148f182 Next Development Version 2018-05-08 14:45:39 -05:00
39 changed files with 531 additions and 362 deletions

View File

@@ -1,6 +1,6 @@
buildscript {
dependencies {
classpath 'io.spring.gradle:spring-build-conventions:0.0.13.RELEASE'
classpath 'io.spring.gradle:spring-build-conventions:0.0.16.RELEASE'
classpath "org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion"
}
repositories {

View File

@@ -147,11 +147,12 @@ As a part of this split, the Spring Session Data MongoDB and Spring Session Data
* https://github.com/spring-projects/spring-session-data-mongodb[`spring-session-data-mongodb` repository]
** Hosts Spring Session Data MongoDB module
* https://github.com/spring-projects/spring-session-data-geode[`spring-session-data-geode` repository]
** Hosts Spring Session Data Geode/GemFire module
** Hosts Spring Session Data Geode and Spring Session Data Geode modules
Going forward, the plan is to externalize each of the `SessionRepository` implementations into a dedicated repository and provide a Maven BOM (as in "bill of materials") module in order to help users with version management concerns.
Finally, Spring Session now also provides a Maven BOM (as in "bill of materials") module in order to help users with version management concerns:
Modules maintained by the members of Spring Team will be hosted within the https://github.com/spring-projects[`spring-projects` organization], while the community maintained modules will continue to be promoted via <<community-extensions,Community Extensions>> section of this manual.
* https://github.com/spring-projects/spring-session-bom[`spring-session-bom` repository]
** Hosts Spring Session BOM module
[[httpsession]]
== HttpSession Integration

View File

@@ -1,2 +1,2 @@
springBootVersion=2.0.1.RELEASE
version=2.0.3.RELEASE
springBootVersion=2.0.2.RELEASE
version=2.0.4.RELEASE

View File

@@ -1,11 +1,11 @@
dependencyManagement {
imports {
mavenBom 'com.fasterxml.jackson:jackson-bom:2.9.4'
mavenBom 'io.projectreactor:reactor-bom:Bismuth-SR9'
mavenBom 'org.springframework:spring-framework-bom:5.0.6.RELEASE'
mavenBom 'org.springframework.data:spring-data-releasetrain:Kay-SR7'
mavenBom 'org.springframework.security:spring-security-bom:5.0.5.RELEASE'
mavenBom 'org.testcontainers:testcontainers-bom:1.7.2'
mavenBom 'com.fasterxml.jackson:jackson-bom:2.9.6'
mavenBom 'io.projectreactor:reactor-bom:Bismuth-SR10'
mavenBom 'org.springframework:spring-framework-bom:5.0.7.RELEASE'
mavenBom 'org.springframework.data:spring-data-releasetrain:Kay-SR8'
mavenBom 'org.springframework.security:spring-security-bom:5.0.6.RELEASE'
mavenBom 'org.testcontainers:testcontainers-bom:1.7.3'
}
dependencies {
@@ -22,9 +22,9 @@ dependencyManagement {
dependency 'junit:junit:4.12'
dependency 'mysql:mysql-connector-java:8.0.11'
dependency 'org.apache.derby:derby:10.14.2.0'
dependency 'org.assertj:assertj-core:3.9.1'
dependency 'org.hsqldb:hsqldb:2.4.0'
dependency 'org.mariadb.jdbc:mariadb-java-client:2.2.3'
dependency 'org.assertj:assertj-core:3.10.0'
dependency 'org.hsqldb:hsqldb:2.4.1'
dependency 'org.mariadb.jdbc:mariadb-java-client:2.2.5'
dependency 'org.mockito:mockito-core:2.18.3'
dependency 'org.postgresql:postgresql:42.2.2'
}

Binary file not shown.

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.7-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -17,9 +17,7 @@
package sample;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.WebDriver;
@@ -31,10 +29,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder;
@@ -46,25 +43,11 @@ import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDr
*/
@RunWith(SpringRunner.class)
@AutoConfigureMockMvc
@SpringBootTest(classes = FindByUsernameApplication.class, webEnvironment = WebEnvironment.MOCK)
@ContextConfiguration(initializers = FindByUsernameTests.Initializer.class)
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
public class FindByUsernameTests {
private static final String DOCKER_IMAGE = "redis:4.0.9";
private static GenericContainer container = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
@BeforeClass
public static void setUpClass() {
container.start();
}
@AfterClass
public static void tearDownClass() {
container.stop();
}
@Autowired
private MockMvc mockMvc;
@@ -96,16 +79,21 @@ public class FindByUsernameTests {
home.terminateButtonDisabled();
}
static class Initializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@TestConfiguration
static class Config {
@Override
public void initialize(
ConfigurableApplicationContext configurableApplicationContext) {
TestPropertyValues
.of("spring.redis.host=" + container.getContainerIpAddress(),
"spring.redis.port=" + container.getFirstMappedPort())
.applyTo(configurableApplicationContext.getEnvironment());
@Bean
public GenericContainer redisContainer() {
GenericContainer redisContainer = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
redisContainer.start();
return redisContainer;
}
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(redisContainer().getContainerIpAddress(),
redisContainer().getFirstMappedPort());
}
}

View File

@@ -19,9 +19,7 @@ package sample;
import java.util.List;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.WebDriver;
@@ -34,10 +32,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder;
@@ -49,26 +46,12 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Vedran Pavic
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class, webEnvironment = WebEnvironment.MOCK)
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
@AutoConfigureMockMvc
@ContextConfiguration(initializers = HttpRedisJsonTest.Initializer.class)
public class HttpRedisJsonTest {
private static final String DOCKER_IMAGE = "redis:4.0.9";
private static GenericContainer container = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
@BeforeClass
public static void setUpClass() {
container.start();
}
@AfterClass
public static void tearDownClass() {
container.stop();
}
@Autowired
private MockMvc mockMvc;
@@ -120,16 +103,21 @@ public class HttpRedisJsonTest {
assertThat(attributes).extracting("attributeValue").contains("Demo Value");
}
static class Initializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@TestConfiguration
static class Config {
@Override
public void initialize(
ConfigurableApplicationContext configurableApplicationContext) {
TestPropertyValues
.of("spring.redis.host=" + container.getContainerIpAddress(),
"spring.redis.port=" + container.getFirstMappedPort())
.applyTo(configurableApplicationContext.getEnvironment());
@Bean
public GenericContainer redisContainer() {
GenericContainer redisContainer = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
redisContainer.start();
return redisContainer;
}
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(redisContainer().getContainerIpAddress(),
redisContainer().getFirstMappedPort());
}
}

View File

@@ -16,20 +16,17 @@
package sample;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.testcontainers.containers.GenericContainer;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.session.data.redis.config.annotation.SpringSessionRedisOperations;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
@@ -39,25 +36,11 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Vedran Pavic
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
@ContextConfiguration(initializers = RedisSerializerTest.Initializer.class)
@SpringBootTest
public class RedisSerializerTest {
private static final String DOCKER_IMAGE = "redis:4.0.9";
private static GenericContainer container = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
@BeforeClass
public static void setUpClass() {
container.start();
}
@AfterClass
public static void tearDownClass() {
container.stop();
}
@SpringSessionRedisOperations
private RedisTemplate<Object, Object> sessionRedisTemplate;
@@ -69,16 +52,21 @@ public class RedisSerializerTest {
.isInstanceOf(GenericJackson2JsonRedisSerializer.class);
}
static class Initializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@TestConfiguration
static class Config {
@Override
public void initialize(
ConfigurableApplicationContext configurableApplicationContext) {
TestPropertyValues
.of("spring.redis.host=" + container.getContainerIpAddress(),
"spring.redis.port=" + container.getFirstMappedPort())
.applyTo(configurableApplicationContext.getEnvironment());
@Bean
public GenericContainer redisContainer() {
GenericContainer redisContainer = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
redisContainer.start();
return redisContainer;
}
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(redisContainer().getContainerIpAddress(),
redisContainer().getFirstMappedPort());
}
}

View File

@@ -17,9 +17,7 @@
package sample;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.WebDriver;
@@ -31,10 +29,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder;
@@ -45,25 +42,11 @@ import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDr
*/
@RunWith(SpringRunner.class)
@AutoConfigureMockMvc
@SpringBootTest(classes = Application.class, webEnvironment = WebEnvironment.MOCK)
@ContextConfiguration(initializers = BootTests.Initializer.class)
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
public class BootTests {
private static final String DOCKER_IMAGE = "redis:4.0.9";
private static GenericContainer container = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
@BeforeClass
public static void setUpClass() {
container.start();
}
@AfterClass
public static void tearDownClass() {
container.stop();
}
@Autowired
private MockMvc mockMvc;
@@ -102,16 +85,21 @@ public class BootTests {
login.assertAt();
}
static class Initializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@TestConfiguration
static class Config {
@Override
public void initialize(
ConfigurableApplicationContext configurableApplicationContext) {
TestPropertyValues
.of("spring.redis.host=" + container.getContainerIpAddress(),
"spring.redis.port=" + container.getFirstMappedPort())
.applyTo(configurableApplicationContext.getEnvironment());
@Bean
public GenericContainer redisContainer() {
GenericContainer redisContainer = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
redisContainer.start();
return redisContainer;
}
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(redisContainer().getContainerIpAddress(),
redisContainer().getFirstMappedPort());
}
}

View File

@@ -19,9 +19,7 @@ package sample;
import java.util.List;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.WebDriver;
@@ -32,11 +30,10 @@ import sample.pages.HomePage.Attribute;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
@@ -44,27 +41,14 @@ import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Eddú Meléndez
* @author Rob Winch
* @author Vedran Pavic
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = HelloWebFluxApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT)
@ContextConfiguration(initializers = AttributeTests.Initializer.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class AttributeTests {
private static final String DOCKER_IMAGE = "redis:4.0.9";
private static GenericContainer container = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
@BeforeClass
public static void setUpClass() {
container.start();
}
@AfterClass
public static void tearDownClass() {
container.stop();
}
@LocalServerPort
private int port;
@@ -109,16 +93,21 @@ public class AttributeTests {
assertThat(row.getAttributeValue()).isEqualTo("b");
}
static class Initializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@TestConfiguration
static class Config {
@Override
public void initialize(
ConfigurableApplicationContext configurableApplicationContext) {
TestPropertyValues
.of("spring.redis.host=" + container.getContainerIpAddress(),
"spring.redis.port=" + container.getFirstMappedPort())
.applyTo(configurableApplicationContext.getEnvironment());
@Bean
public GenericContainer redisContainer() {
GenericContainer redisContainer = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
redisContainer.start();
return redisContainer;
}
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(redisContainer().getContainerIpAddress(),
redisContainer().getFirstMappedPort());
}
}

View File

@@ -20,8 +20,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.testcontainers.containers.GenericContainer;
@@ -30,10 +28,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.web.socket.TextMessage;
@@ -52,25 +49,11 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
* @author Vedran Pavic
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class, webEnvironment = WebEnvironment.RANDOM_PORT)
@ContextConfiguration(initializers = ApplicationTests.Initializer.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class ApplicationTests {
private static final String DOCKER_IMAGE = "redis:4.0.9";
private static GenericContainer container = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
@BeforeClass
public static void setUpClass() {
container.start();
}
@AfterClass
public static void tearDownClass() {
container.stop();
}
@Value("${local.server.port}")
private String port;
@@ -91,16 +74,21 @@ public class ApplicationTests {
.isInstanceOf(ExecutionException.class);
}
static class Initializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@TestConfiguration
static class Config {
@Override
public void initialize(
ConfigurableApplicationContext configurableApplicationContext) {
TestPropertyValues
.of("spring.redis.host=" + container.getContainerIpAddress(),
"spring.redis.port=" + container.getFirstMappedPort())
.applyTo(configurableApplicationContext.getEnvironment());
@Bean
public GenericContainer redisContainer() {
GenericContainer redisContainer = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
redisContainer.start();
return redisContainer;
}
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(redisContainer().getContainerIpAddress(),
redisContainer().getFirstMappedPort());
}
}

View File

@@ -28,11 +28,14 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
@Profile("embedded-redis")
public class EmbeddedRedisConfig {
private static final String REDIS_DOCKER_IMAGE = "redis:4.0.9";
private static final String DOCKER_IMAGE = "redis:4.0.9";
@Bean(initMethod = "start")
@Bean
public GenericContainer redisContainer() {
return new GenericContainer(REDIS_DOCKER_IMAGE).withExposedPorts(6379);
GenericContainer redisContainer = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
redisContainer.start();
return redisContainer;
}
@Bean

View File

@@ -28,11 +28,14 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
@Profile("embedded-redis")
public class EmbeddedRedisConfig {
private static final String REDIS_DOCKER_IMAGE = "redis:4.0.9";
private static final String DOCKER_IMAGE = "redis:4.0.9";
@Bean(initMethod = "start")
@Bean
public GenericContainer redisContainer() {
return new GenericContainer(REDIS_DOCKER_IMAGE).withExposedPorts(6379);
GenericContainer redisContainer = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
redisContainer.start();
return redisContainer;
}
@Bean

View File

@@ -16,9 +16,7 @@
package rest;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.testcontainers.containers.GenericContainer;
@@ -58,19 +56,6 @@ public class RestMockMvcTests {
private static final String DOCKER_IMAGE = "redis:4.0.9";
private static GenericContainer container = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
@BeforeClass
public static void setUpClass() {
container.start();
}
@AfterClass
public static void tearDownClass() {
container.stop();
}
@Autowired
private SessionRepositoryFilter<? extends Session> sessionRepositoryFilter;
@@ -107,10 +92,18 @@ public class RestMockMvcTests {
@EnableRedisHttpSession
static class Config {
@Bean
public GenericContainer redisContainer() {
GenericContainer redisContainer = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
redisContainer.start();
return redisContainer;
}
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(container.getContainerIpAddress(),
container.getFirstMappedPort());
return new LettuceConnectionFactory(redisContainer().getContainerIpAddress(),
redisContainer().getFirstMappedPort());
}
@Bean

View File

@@ -28,11 +28,14 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
@Profile("embedded-redis")
public class EmbeddedRedisConfig {
private static final String REDIS_DOCKER_IMAGE = "redis:4.0.9";
private static final String DOCKER_IMAGE = "redis:4.0.9";
@Bean(initMethod = "start")
@Bean
public GenericContainer redisContainer() {
return new GenericContainer(REDIS_DOCKER_IMAGE).withExposedPorts(6379);
GenericContainer redisContainer = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
redisContainer.start();
return redisContainer;
}
@Bean

View File

@@ -28,11 +28,14 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
@Profile("embedded-redis")
public class EmbeddedRedisConfig {
private static final String REDIS_DOCKER_IMAGE = "redis:4.0.9";
private static final String DOCKER_IMAGE = "redis:4.0.9";
@Bean(initMethod = "start")
@Bean
public GenericContainer redisContainer() {
return new GenericContainer(REDIS_DOCKER_IMAGE).withExposedPorts(6379);
GenericContainer redisContainer = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
redisContainer.start();
return redisContainer;
}
@Bean

View File

@@ -28,11 +28,14 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
@Profile("embedded-redis")
public class EmbeddedRedisConfig {
private static final String REDIS_DOCKER_IMAGE = "redis:4.0.9";
private static final String DOCKER_IMAGE = "redis:4.0.9";
@Bean(initMethod = "start")
@Bean
public GenericContainer redisContainer() {
return new GenericContainer(REDIS_DOCKER_IMAGE).withExposedPorts(6379);
GenericContainer redisContainer = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
redisContainer.start();
return redisContainer;
}
@Bean

View File

@@ -122,7 +122,12 @@ public final class MapSession implements Session, Serializable {
return this.id;
}
String getOriginalId() {
/**
* Get the original session id.
* @return the original session id
* @see #changeSessionId()
*/
public String getOriginalId() {
return this.originalId;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,7 +22,6 @@ import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.ServletRequest;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -41,7 +40,7 @@ public class DefaultCookieSerializer implements CookieSerializer {
private Boolean useSecureCookie;
private boolean useHttpOnlyCookie = isServlet3();
private boolean useHttpOnlyCookie = true;
private String cookiePath;
@@ -168,16 +167,11 @@ public class DefaultCookieSerializer implements CookieSerializer {
}
/**
* Sets if a Cookie marked as HTTP Only should be used. The default is true in Servlet
* 3+ environments, else false.
* Sets if a Cookie marked as HTTP Only should be used. The default is true.
*
* @param useHttpOnlyCookie determines if the cookie should be marked as HTTP Only.
*/
public void setUseHttpOnlyCookie(boolean useHttpOnlyCookie) {
if (useHttpOnlyCookie && !isServlet3()) {
throw new IllegalArgumentException(
"You cannot set useHttpOnlyCookie to true in pre Servlet 3 environment");
}
this.useHttpOnlyCookie = useHttpOnlyCookie;
}
@@ -337,19 +331,4 @@ public class DefaultCookieSerializer implements CookieSerializer {
return this.cookiePath;
}
/**
* Returns true if the Servlet 3 APIs are detected.
*
* @return whether the Servlet 3 APIs are detected
*/
private boolean isServlet3() {
try {
ServletRequest.class.getMethod("startAsync");
return true;
}
catch (NoSuchMethodException e) {
}
return false;
}
}

View File

@@ -230,7 +230,8 @@ public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFi
}
else {
S session = wrappedSession.getSession();
saveSession(session);
clearRequestedSessionCache();
SessionRepositoryFilter.this.sessionRepository.save(session);
String sessionId = session.getId();
if (!isRequestedSessionIdValid()
|| !sessionId.equals(getRequestedSessionId())) {
@@ -371,10 +372,9 @@ public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFi
return this.requestedSession;
}
private void saveSession(S session) {
private void clearRequestedSessionCache() {
this.requestedSessionCached = false;
this.requestedSession = null;
SessionRepositoryFilter.this.sessionRepository.save(session);
}
/**
@@ -394,6 +394,7 @@ public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFi
super.invalidate();
SessionRepositoryRequestWrapper.this.requestedSessionInvalidated = true;
setCurrentSession(null);
clearRequestedSessionCache();
SessionRepositoryFilter.this.sessionRepository.deleteById(getId());
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 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.
@@ -31,7 +31,6 @@ import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
import org.springframework.messaging.simp.SimpMessageType;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.messaging.support.ChannelInterceptorAdapter;
import org.springframework.session.Session;
import org.springframework.session.SessionRepository;
import org.springframework.util.Assert;
@@ -63,7 +62,7 @@ import org.springframework.web.socket.server.HandshakeInterceptor;
* @since 1.0
*/
public final class SessionRepositoryMessageInterceptor<S extends Session>
extends ChannelInterceptorAdapter implements HandshakeInterceptor {
implements ChannelInterceptor, HandshakeInterceptor {
private static final String SPRING_SESSION_ID_ATTR_NAME = "SPRING.SESSION.ID";
@@ -114,7 +113,7 @@ public final class SessionRepositoryMessageInterceptor<S extends Session>
SimpMessageType messageType = SimpMessageHeaderAccessor
.getMessageType(message.getHeaders());
if (!this.matchingMessageTypes.contains(messageType)) {
return super.preSend(message, channel);
return message;
}
Map<String, Object> sessionHeaders = SimpMessageHeaderAccessor
.getSessionAttributes(message.getHeaders());
@@ -128,7 +127,7 @@ public final class SessionRepositoryMessageInterceptor<S extends Session>
this.sessionRepository.save(session);
}
}
return super.preSend(message, channel);
return message;
}
@Override

View File

@@ -67,6 +67,7 @@ import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
@@ -1335,6 +1336,32 @@ public class SessionRepositoryFilterTests {
verifyZeroInteractions(sessionRepository);
}
@Test
public void doFilterSessionRetrievalIsCached() throws Exception {
MapSession session = this.sessionRepository.createSession();
this.sessionRepository.save(session);
SessionRepository<MapSession> sessionRepository = spy(this.sessionRepository);
setSessionCookie(session.getId());
this.filter = new SessionRepositoryFilter<>(sessionRepository);
doFilter(new DoInFilter() {
@Override
public void doFilter(HttpServletRequest wrappedRequest,
HttpServletResponse wrappedResponse) {
wrappedRequest.getSession().invalidate();
wrappedRequest.getSession();
}
});
// 3 invocations expected: initial resolution, after invalidation, after commit
verify(sessionRepository, times(3)).findById(eq(session.getId()));
verify(sessionRepository).deleteById(eq(session.getId()));
verify(sessionRepository).createSession();
verify(sessionRepository).save(any());
verifyZeroInteractions(sessionRepository);
}
// --- order
@Test

View File

@@ -16,8 +16,6 @@
package org.springframework.session.data.redis;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.testcontainers.containers.GenericContainer;
import org.springframework.context.annotation.Bean;
@@ -33,25 +31,21 @@ public abstract class AbstractRedisITests {
private static final String DOCKER_IMAGE = "redis:4.0.9";
private static GenericContainer container = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
@BeforeClass
public static void setUpClass() {
container.start();
}
@AfterClass
public static void tearDownClass() {
container.stop();
}
protected static class BaseConfig {
@Bean
public GenericContainer redisContainer() {
GenericContainer redisContainer = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
redisContainer.start();
return redisContainer;
}
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(
container.getContainerIpAddress(), container.getFirstMappedPort());
redisContainer().getContainerIpAddress(),
redisContainer().getFirstMappedPort());
return new LettuceConnectionFactory(configuration);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 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.
@@ -153,4 +153,18 @@ public abstract class AbstractHazelcastRepositoryITests {
this.repository.deleteById(toSave.getId());
}
@Test // gh-1076
public void attemptToUpdateSessionAfterDelete() {
HazelcastSession session = this.repository.createSession();
String sessionId = session.getId();
this.repository.save(session);
session = this.repository.findById(sessionId);
session.setAttribute("attributeName", "attributeValue");
this.repository.deleteById(sessionId);
this.repository.save(session);
assertThat(this.repository.findById(sessionId)).isNull();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@ package org.springframework.session.hazelcast;
import com.hazelcast.config.Config;
import com.hazelcast.config.MapAttributeConfig;
import com.hazelcast.config.MapIndexConfig;
import com.hazelcast.config.NetworkConfig;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
@@ -46,8 +47,12 @@ public final class HazelcastITestUtils {
Config config = new Config();
config.getNetworkConfig()
.setPort(port);
NetworkConfig networkConfig = config.getNetworkConfig();
networkConfig.setPort(port);
networkConfig.getJoin()
.getMulticastConfig().setEnabled(false);
config.getMapConfig(HazelcastSessionRepository.DEFAULT_SESSION_MAP_NAME)
.addMapAttributeConfig(attributeConfig)

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -52,6 +52,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* expected after each SessionEvent.
*
* @author Tommy Ludwig
* @author Vedran Pavic
*/
@RunWith(SpringRunner.class)
@ContextConfiguration
@@ -168,6 +169,24 @@ public class EnableHazelcastHttpSessionEventsTests<S extends Session> {
assertThat(this.repository.findById(sessionToUpdate.getId())).isNotNull();
}
@Test // gh-1077
public void changeSessionIdNoEventTest() throws InterruptedException {
S sessionToSave = this.repository.createSession();
sessionToSave.setMaxInactiveInterval(Duration.ofMinutes(30));
this.repository.save(sessionToSave);
assertThat(this.registry.receivedEvent(sessionToSave.getId())).isTrue();
assertThat(this.registry.<SessionCreatedEvent>getEvent(sessionToSave.getId()))
.isInstanceOf(SessionCreatedEvent.class);
this.registry.clear();
sessionToSave.changeSessionId();
this.repository.save(sessionToSave);
assertThat(this.registry.receivedEvent(sessionToSave.getId())).isFalse();
}
@Configuration
@EnableHazelcastHttpSession(maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS)
static class HazelcastSessionConfig {

View File

@@ -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 hazelcast-config-3.8.xsd">
xsi:schemaLocation="http://www.hazelcast.com/schema/config hazelcast-config-3.9.xsd">
<group>
<name>spring-session-it-test-idle-time-map-name</name>
@@ -14,16 +14,7 @@
<ports>0</ports>
</outbound-ports>
<join>
<multicast enabled="false">
</multicast>
<tcp-ip enabled="true">
<interface>127.0.0.1</interface>
<member-list>
<member>127.0.0.1</member>
</member-list>
</tcp-ip>
<aws enabled="false">
</aws>
<multicast enabled="false"/>
</join>
</network>

View File

@@ -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 hazelcast-config-3.8.xsd">
xsi:schemaLocation="http://www.hazelcast.com/schema/config hazelcast-config-3.9.xsd">
<group>
<name>spring-session-it-test-map-name</name>
@@ -14,16 +14,7 @@
<ports>0</ports>
</outbound-ports>
<join>
<multicast enabled="false">
</multicast>
<tcp-ip enabled="true">
<interface>127.0.0.1</interface>
<member-list>
<member>127.0.0.1</member>
</member-list>
</tcp-ip>
<aws enabled="false">
</aws>
<multicast enabled="false"/>
</join>
</network>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 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.
@@ -224,20 +224,30 @@ public class HazelcastSessionRepository implements
@Override
public void save(HazelcastSession session) {
if (!session.getId().equals(session.originalId)) {
this.sessions.remove(session.originalId);
session.originalId = session.getId();
}
if (session.isNew) {
this.sessions.set(session.getId(), session.getDelegate(),
session.getMaxInactiveInterval().getSeconds(), TimeUnit.SECONDS);
}
else if (session.changed) {
this.sessions.executeOnKey(session.getId(),
new SessionUpdateEntryProcessor(session.getLastAccessedTime(),
session.getMaxInactiveInterval(), session.delta));
else if (session.sessionIdChanged) {
this.sessions.delete(session.originalId);
session.originalId = session.getId();
this.sessions.set(session.getId(), session.getDelegate(),
session.getMaxInactiveInterval().getSeconds(), TimeUnit.SECONDS);
}
session.clearFlags();
else if (session.hasChanges()) {
SessionUpdateEntryProcessor entryProcessor = new SessionUpdateEntryProcessor();
if (session.lastAccessedTimeChanged) {
entryProcessor.setLastAccessedTime(session.getLastAccessedTime());
}
if (session.maxInactiveIntervalChanged) {
entryProcessor.setMaxInactiveInterval(session.getMaxInactiveInterval());
}
if (!session.delta.isEmpty()) {
entryProcessor.setDelta(session.delta);
}
this.sessions.executeOnKey(session.getId(), entryProcessor);
}
session.clearChangeFlags();
}
@Override
@@ -275,10 +285,13 @@ public class HazelcastSessionRepository implements
@Override
public void entryAdded(EntryEvent<String, MapSession> event) {
if (logger.isDebugEnabled()) {
logger.debug("Session created with id: " + event.getValue().getId());
MapSession session = event.getValue();
if (session.getId().equals(session.getOriginalId())) {
if (logger.isDebugEnabled()) {
logger.debug("Session created with id: " + session.getId());
}
this.eventPublisher.publishEvent(new SessionCreatedEvent(this, session));
}
this.eventPublisher.publishEvent(new SessionCreatedEvent(this, event.getValue()));
}
@Override
@@ -292,11 +305,13 @@ public class HazelcastSessionRepository implements
@Override
public void entryRemoved(EntryEvent<String, MapSession> event) {
if (logger.isDebugEnabled()) {
logger.debug("Session deleted with id: " + event.getOldValue().getId());
MapSession session = event.getOldValue();
if (session != null) {
if (logger.isDebugEnabled()) {
logger.debug("Session deleted with id: " + session.getId());
}
this.eventPublisher.publishEvent(new SessionDeletedEvent(this, session));
}
this.eventPublisher
.publishEvent(new SessionDeletedEvent(this, event.getOldValue()));
}
/**
@@ -311,7 +326,11 @@ public class HazelcastSessionRepository implements
private boolean isNew;
private boolean changed;
private boolean sessionIdChanged;
private boolean lastAccessedTimeChanged;
private boolean maxInactiveIntervalChanged;
private String originalId;
@@ -341,7 +360,7 @@ public class HazelcastSessionRepository implements
@Override
public void setLastAccessedTime(Instant lastAccessedTime) {
this.delegate.setLastAccessedTime(lastAccessedTime);
this.changed = true;
this.lastAccessedTimeChanged = true;
flushImmediateIfNecessary();
}
@@ -362,8 +381,9 @@ public class HazelcastSessionRepository implements
@Override
public String changeSessionId() {
this.isNew = true;
return this.delegate.changeSessionId();
String newSessionId = this.delegate.changeSessionId();
this.sessionIdChanged = true;
return newSessionId;
}
@Override
@@ -374,7 +394,7 @@ public class HazelcastSessionRepository implements
@Override
public void setMaxInactiveInterval(Duration interval) {
this.delegate.setMaxInactiveInterval(interval);
this.changed = true;
this.maxInactiveIntervalChanged = true;
flushImmediateIfNecessary();
}
@@ -397,7 +417,6 @@ public class HazelcastSessionRepository implements
public void setAttribute(String attributeName, Object attributeValue) {
this.delegate.setAttribute(attributeName, attributeValue);
this.delta.put(attributeName, attributeValue);
this.changed = true;
flushImmediateIfNecessary();
}
@@ -405,7 +424,6 @@ public class HazelcastSessionRepository implements
public void removeAttribute(String attributeName) {
this.delegate.removeAttribute(attributeName);
this.delta.put(attributeName, null);
this.changed = true;
flushImmediateIfNecessary();
}
@@ -413,9 +431,16 @@ public class HazelcastSessionRepository implements
return this.delegate;
}
void clearFlags() {
boolean hasChanges() {
return (this.lastAccessedTimeChanged || this.maxInactiveIntervalChanged
|| !this.delta.isEmpty());
}
void clearChangeFlags() {
this.isNew = false;
this.changed = false;
this.lastAccessedTimeChanged = false;
this.sessionIdChanged = false;
this.maxInactiveIntervalChanged = false;
this.delta.clear();
}
@@ -436,34 +461,48 @@ public class HazelcastSessionRepository implements
private static final class SessionUpdateEntryProcessor
extends AbstractEntryProcessor<String, MapSession> {
private final Instant lastAccessedTime;
private Instant lastAccessedTime;
private final Duration maxInactiveInterval;
private Duration maxInactiveInterval;
private final Map<String, Object> delta;
SessionUpdateEntryProcessor(Instant lastAccessedTime,
Duration maxInactiveInterval, Map<String, Object> delta) {
this.lastAccessedTime = lastAccessedTime;
this.maxInactiveInterval = maxInactiveInterval;
this.delta = delta;
}
private Map<String, Object> delta;
@Override
public Object process(Map.Entry<String, MapSession> entry) {
MapSession value = entry.getValue();
value.setLastAccessedTime(this.lastAccessedTime);
value.setMaxInactiveInterval(this.maxInactiveInterval);
for (final Map.Entry<String, Object> attribute : this.delta.entrySet()) {
if (attribute.getValue() != null) {
value.setAttribute(attribute.getKey(), attribute.getValue());
}
else {
value.removeAttribute(attribute.getKey());
if (value == null) {
return Boolean.FALSE;
}
if (this.lastAccessedTime != null) {
value.setLastAccessedTime(this.lastAccessedTime);
}
if (this.maxInactiveInterval != null) {
value.setMaxInactiveInterval(this.maxInactiveInterval);
}
if (this.delta != null) {
for (final Map.Entry<String, Object> attribute : this.delta.entrySet()) {
if (attribute.getValue() != null) {
value.setAttribute(attribute.getKey(), attribute.getValue());
}
else {
value.removeAttribute(attribute.getKey());
}
}
}
entry.setValue(value);
return value;
return Boolean.TRUE;
}
public void setLastAccessedTime(Instant lastAccessedTime) {
this.lastAccessedTime = lastAccessedTime;
}
public void setMaxInactiveInterval(Duration maxInactiveInterval) {
this.maxInactiveInterval = maxInactiveInterval;
}
public void setDelta(Map<String, Object> delta) {
this.delta = delta;
}
}

View File

@@ -689,6 +689,60 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
assertThat(this.repository.findById(originalId)).isNull();
}
@Test // gh-1070
public void saveUpdatedAddAndModifyAttribute() {
JdbcOperationsSessionRepository.JdbcSession session = this.repository.createSession();
this.repository.save(session);
session = this.repository.findById(session.getId());
session.setAttribute("testName", "testValue1");
session.setAttribute("testName", "testValue2");
this.repository.save(session);
session = this.repository.findById(session.getId());
assertThat(session.<String>getAttribute("testName")).isEqualTo("testValue2");
}
@Test // gh-1070
public void saveUpdatedAddAndRemoveAttribute() {
JdbcOperationsSessionRepository.JdbcSession session = this.repository.createSession();
this.repository.save(session);
session = this.repository.findById(session.getId());
session.setAttribute("testName", "testValue");
session.removeAttribute("testName");
this.repository.save(session);
session = this.repository.findById(session.getId());
assertThat(session.<String>getAttribute("testName")).isNull();
}
@Test // gh-1070
public void saveUpdatedModifyAndRemoveAttribute() {
JdbcOperationsSessionRepository.JdbcSession session = this.repository.createSession();
session.setAttribute("testName", "testValue1");
this.repository.save(session);
session = this.repository.findById(session.getId());
session.setAttribute("testName", "testValue2");
session.removeAttribute("testName");
this.repository.save(session);
session = this.repository.findById(session.getId());
assertThat(session.<String>getAttribute("testName")).isNull();
}
@Test // gh-1070
public void saveUpdatedRemoveAndAddAttribute() {
JdbcOperationsSessionRepository.JdbcSession session = this.repository.createSession();
session.setAttribute("testName", "testValue1");
this.repository.save(session);
session = this.repository.findById(session.getId());
session.removeAttribute("testName");
session.setAttribute("testName", "testValue2");
this.repository.save(session);
session = this.repository.findById(session.getId());
assertThat(session.<String>getAttribute("testName")).isEqualTo("testValue2");
}
private String getSecurityName() {
return this.context.getAuthentication().getName();
}

View File

@@ -86,7 +86,7 @@ public class MariaDb10JdbcOperationsSessionRepositoryITests
private static class MariaDb10Container extends MariaDBContainer<MariaDb10Container> {
MariaDb10Container() {
super("mariadb:10.2.14");
super("mariadb:10.3.7");
}
@Override

View File

@@ -18,6 +18,7 @@ package org.springframework.session.jdbc;
import javax.sql.DataSource;
import com.mysql.cj.jdbc.Driver;
import com.mysql.cj.jdbc.MysqlDataSource;
import org.junit.AfterClass;
import org.junit.BeforeClass;
@@ -94,6 +95,11 @@ public class MySql5JdbcOperationsSessionRepositoryITests
"--collation-server=utf8mb4_unicode_ci");
}
@Override
public String getDriverClassName() {
return Driver.class.getName();
}
}
}

View File

@@ -18,10 +18,10 @@ package org.springframework.session.jdbc;
import javax.sql.DataSource;
import com.mysql.cj.jdbc.Driver;
import com.mysql.cj.jdbc.MysqlDataSource;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.runner.RunWith;
import org.testcontainers.containers.MySQLContainer;
@@ -39,7 +39,6 @@ import org.springframework.test.context.web.WebAppConfiguration;
*
* @author Vedran Pavic
*/
@Ignore
@RunWith(SpringRunner.class)
@WebAppConfiguration
@ContextConfiguration
@@ -92,8 +91,12 @@ public class MySql8JdbcOperationsSessionRepositoryITests
@Override
protected void configure() {
super.configure();
setCommand("mysqld", "--character-set-server=utf8mb4",
"--collation-server=utf8mb4_unicode_ci");
setCommand("mysqld", "--default-authentication-plugin=mysql_native_password");
}
@Override
public String getDriverClassName() {
return Driver.class.getName();
}
}

View File

@@ -86,7 +86,7 @@ public class PostgreSql10JdbcOperationsSessionRepositoryITests
extends PostgreSQLContainer<PostgreSql10Container> {
PostgreSql10Container() {
super("postgres:10.3");
super("postgres:10.4");
}
}

View File

@@ -86,7 +86,7 @@ public class PostgreSql9JdbcOperationsSessionRepositoryITests
extends PostgreSQLContainer<PostgreSql9Container> {
PostgreSql9Container() {
super("postgres:9.6.8");
super("postgres:9.6.9");
}
}

View File

@@ -88,7 +88,12 @@ public class SqlServerJdbcOperationsSessionRepositoryITests
extends MSSQLServerContainer<SqlServer2007Container> {
SqlServer2007Container() {
super("microsoft/mssql-server-linux:2017-CU6");
super("microsoft/mssql-server-linux:2017-CU7");
}
@Override
protected int getStartupTimeoutSeconds() {
return 240;
}
}

View File

@@ -732,14 +732,30 @@ public class JdbcOperationsSessionRepository implements
@Override
public void setAttribute(String attributeName, Object attributeValue) {
if (attributeValue == null) {
this.delta.put(attributeName, DeltaValue.REMOVED);
boolean attributeExists = (this.delegate.getAttribute(attributeName) != null);
boolean attributeRemoved = (attributeValue == null);
if (!attributeExists && attributeRemoved) {
return;
}
else if (this.delegate.getAttribute(attributeName) != null) {
this.delta.put(attributeName, DeltaValue.UPDATED);
if (attributeExists) {
if (attributeRemoved) {
this.delta.merge(attributeName, DeltaValue.REMOVED,
(oldDeltaValue, deltaValue) -> oldDeltaValue == DeltaValue.ADDED
? null
: deltaValue);
}
else {
this.delta.merge(attributeName, DeltaValue.UPDATED,
(oldDeltaValue, deltaValue) -> oldDeltaValue == DeltaValue.ADDED
? oldDeltaValue
: deltaValue);
}
}
else {
this.delta.put(attributeName, DeltaValue.ADDED);
this.delta.merge(attributeName, DeltaValue.ADDED,
(oldDeltaValue, deltaValue) -> oldDeltaValue == DeltaValue.ADDED
? oldDeltaValue
: DeltaValue.UPDATED);
}
this.delegate.setAttribute(attributeName, attributeValue);
if (PRINCIPAL_NAME_INDEX_NAME.equals(attributeName) ||

View File

@@ -57,6 +57,7 @@ import static org.mockito.Mockito.verifyZeroInteractions;
* Tests for {@link JdbcOperationsSessionRepository}.
*
* @author Vedran Pavic
* @author Craig Andrews
* @since 1.2.0
*/
public class JdbcOperationsSessionRepositoryTests {
@@ -411,6 +412,19 @@ public class JdbcOperationsSessionRepositoryTests {
verifyZeroInteractions(this.jdbcOperations);
}
@Test
public void saveUpdatedRemoveNonExistingAttribute() {
JdbcOperationsSessionRepository.JdbcSession session = this.repository.new JdbcSession("primaryKey",
new MapSession());
session.removeAttribute("testName");
this.repository.save(session);
assertThat(session.isNew()).isFalse();
assertPropagationRequiresNew();
verifyZeroInteractions(this.jdbcOperations);
}
@Test
public void saveUpdatedRemoveMultipleAttributes() {
JdbcOperationsSessionRepository.JdbcSession session = this.repository.new JdbcSession("primaryKey",
@@ -431,6 +445,75 @@ public class JdbcOperationsSessionRepositoryTests {
verifyZeroInteractions(this.jdbcOperations);
}
@Test // gh-1070
public void saveUpdatedAddAndModifyAttribute() {
JdbcOperationsSessionRepository.JdbcSession session = this.repository.new JdbcSession("primaryKey",
new MapSession());
session.setAttribute("testName", "testValue1");
session.setAttribute("testName", "testValue2");
this.repository.save(session);
assertThat(session.isNew()).isFalse();
assertPropagationRequiresNew();
verify(this.jdbcOperations).update(
startsWith("INSERT INTO SPRING_SESSION_ATTRIBUTES("),
isA(PreparedStatementSetter.class));
verifyZeroInteractions(this.jdbcOperations);
}
@Test // gh-1070
public void saveUpdatedAddAndRemoveAttribute() {
JdbcOperationsSessionRepository.JdbcSession session = this.repository.new JdbcSession("primaryKey",
new MapSession());
session.setAttribute("testName", "testValue");
session.removeAttribute("testName");
this.repository.save(session);
assertThat(session.isNew()).isFalse();
assertPropagationRequiresNew();
verifyZeroInteractions(this.jdbcOperations);
}
@Test // gh-1070
public void saveUpdatedModifyAndRemoveAttribute() {
JdbcOperationsSessionRepository.JdbcSession session = this.repository.new JdbcSession("primaryKey",
new MapSession());
session.setAttribute("testName", "testValue1");
session.clearChangeFlags();
session.setAttribute("testName", "testValue2");
session.removeAttribute("testName");
this.repository.save(session);
assertThat(session.isNew()).isFalse();
assertPropagationRequiresNew();
verify(this.jdbcOperations).update(
startsWith("DELETE FROM SPRING_SESSION_ATTRIBUTES WHERE"),
isA(PreparedStatementSetter.class));
verifyZeroInteractions(this.jdbcOperations);
}
@Test // gh-1070
public void saveUpdatedRemoveAndAddAttribute() {
JdbcOperationsSessionRepository.JdbcSession session = this.repository.new JdbcSession("primaryKey",
new MapSession());
session.setAttribute("testName", "testValue1");
session.clearChangeFlags();
session.removeAttribute("testName");
session.setAttribute("testName", "testValue2");
this.repository.save(session);
assertThat(session.isNew()).isFalse();
assertPropagationRequiresNew();
verify(this.jdbcOperations).update(
startsWith("UPDATE SPRING_SESSION_ATTRIBUTES SET"),
isA(PreparedStatementSetter.class));
verifyZeroInteractions(this.jdbcOperations);
}
@Test
public void saveUpdatedLastAccessedTime() {
JdbcOperationsSessionRepository.JdbcSession session = this.repository.new JdbcSession("primaryKey",