Compare commits

...

13 Commits

Author SHA1 Message Date
Rob Winch
4c50da3982 Release 2.1.6.RELEASE 2019-05-13 12:23:21 -05:00
Vedran Pavic
b1d53874e4 Ensure Redis session with immediate flush respects defaultMaxInactiveInterval
Resolves: #1423
2019-05-13 19:09:45 +02:00
Vedran Pavic
cc2a75b668 Upgrade Spring Data to Lovelace-SR8
Resolves: #1418
2019-05-13 17:49:30 +02:00
Vedran Pavic
006acba02a Upgrade Reactor to Californium-SR8
Resolves: #1419
2019-05-13 17:49:10 +02:00
Vedran Pavic
168ad85cc5 Upgrade Spring Data to Lovelace-SR7
Resolves: #1418
2019-05-10 22:31:28 +02:00
Vedran Pavic
3f61a30568 Update integration tests 2019-05-10 08:45:42 +02:00
Vedran Pavic
318036828d Upgrade test dependencies 2019-05-10 08:41:45 +02:00
Vedran Pavic
326e7070b1 Upgrade Hazelcast to 3.11.4
Resolves: #1421
2019-05-10 08:36:50 +02:00
Vedran Pavic
81ca7d5f83 Upgrade samples to Spring Boot 2.1.4.RELEASE
Resolves: #1420
2019-05-10 08:18:43 +02:00
Vedran Pavic
de8e47e4c3 Upgrade Reactor to Californium-SR7
Resolves: #1419
2019-05-10 08:18:43 +02:00
Vedran Pavic
ef6b9f8812 Upgrade Spring Framework to 5.1.7.RELEASE
Resolves: #1417
2019-05-10 08:16:42 +02:00
Vedran Pavic
14be439da0 Fix JdbcOperationsSessionRepository lazy deserialization
Resolves: #1412
2019-05-06 23:38:47 +02:00
Joe Grandja
2631ddc446 Next Development Version 2019-04-02 16:06:36 -04:00
23 changed files with 130 additions and 100 deletions

View File

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

View File

@@ -1 +1 @@
version=2.1.5.RELEASE
version=2.1.6.RELEASE

View File

@@ -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.1.6.RELEASE'
mavenBom 'org.springframework.data:spring-data-releasetrain:Lovelace-SR6'
mavenBom 'io.projectreactor:reactor-bom:Californium-SR8'
mavenBom 'org.springframework:spring-framework-bom:5.1.7.RELEASE'
mavenBom 'org.springframework.data:spring-data-releasetrain:Lovelace-SR8'
mavenBom 'org.springframework.security:spring-security-bom:5.1.5.RELEASE'
mavenBom 'org.testcontainers:testcontainers-bom:1.10.6'
mavenBom 'org.testcontainers:testcontainers-bom:1.11.2'
}
dependencies {
dependencySet(group: 'com.hazelcast', version: '3.11.2') {
dependencySet(group: 'com.hazelcast', version: '3.11.4') {
entry 'hazelcast'
entry 'hazelcast-client'
}
dependency 'com.h2database:h2:1.4.197'
dependency 'com.microsoft.sqlserver:mssql-jdbc:7.2.1.jre8'
dependency 'com.h2database:h2:1.4.199'
dependency 'com.microsoft.sqlserver:mssql-jdbc:7.2.2.jre8'
dependency 'com.zaxxer:HikariCP:3.3.1'
dependency 'edu.umd.cs.mtc:multithreadedtc:1.01'
dependency 'io.lettuce:lettuce-core:5.1.4.RELEASE'
dependency 'io.lettuce:lettuce-core:5.1.6.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.16'
dependency 'org.apache.derby:derby:10.14.2.0'
dependency 'org.assertj:assertj-core:3.11.1'
dependency 'org.assertj:assertj-core:3.12.2'
dependency 'org.hsqldb:hsqldb:2.4.1'
dependency 'org.mariadb.jdbc:mariadb-java-client:2.4.0'
dependency 'org.mockito:mockito-core:2.24.0'
dependency 'org.mariadb.jdbc:mariadb-java-client:2.4.1'
dependency 'org.mockito:mockito-core:2.27.0'
dependency 'org.postgresql:postgresql:42.2.5'
}
}

View File

@@ -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.3";
private static final String DOCKER_IMAGE = "redis:5.0.4";
@Autowired
private MockMvc mockMvc;

View File

@@ -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.3";
private static final String DOCKER_IMAGE = "redis:5.0.4";
@Autowired
private MockMvc mockMvc;

View File

@@ -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.3";
private static final String DOCKER_IMAGE = "redis:5.0.4";
@SpringSessionRedisOperations
private RedisTemplate<Object, Object> sessionRedisTemplate;

View File

@@ -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.3";
private static final String DOCKER_IMAGE = "redis:5.0.4";
@Autowired
private MockMvc mockMvc;

View File

@@ -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.3";
private static final String DOCKER_IMAGE = "redis:5.0.4";
@LocalServerPort
private int port;

View File

@@ -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.3";
private static final String DOCKER_IMAGE = "redis:5.0.4";
@Value("${local.server.port}")
private String port;

View File

@@ -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.3";
private static final String DOCKER_IMAGE = "redis:5.0.4";
@Bean
public GenericContainer redisContainer() {

View File

@@ -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.3";
private static final String DOCKER_IMAGE = "redis:5.0.4";
@Bean
public GenericContainer redisContainer() {

View File

@@ -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.3";
private static final String DOCKER_IMAGE = "redis:5.0.4";
@Autowired
private SessionRepositoryFilter<? extends Session> sessionRepositoryFilter;

View File

@@ -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.3";
private static final String DOCKER_IMAGE = "redis:5.0.4";
@Bean
public GenericContainer redisContainer() {

View File

@@ -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.3";
private static final String DOCKER_IMAGE = "redis:5.0.4";
@Bean
public GenericContainer redisContainer() {

View File

@@ -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.3";
private static final String DOCKER_IMAGE = "redis:5.0.4";
@Bean
public GenericContainer redisContainer() {

View File

@@ -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.3";
private static final String DOCKER_IMAGE = "redis:5.0.4";
protected static class BaseConfig {

View File

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

View File

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

View File

@@ -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.11.2")
"hazelcast/hazelcast:3.11.4")
.withExposedPorts(5701)
.withEnv("JAVA_OPTS",
"-Dhazelcast.config=/opt/hazelcast/config_ext/hazelcast.xml")

View File

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

View File

@@ -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.12");
super("mariadb:10.3.14");
}
@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.26");
}
@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.16");
}
@Override
@@ -143,7 +143,7 @@ final class DatabaseContainers {
extends PostgreSQLContainer<PostgreSql9Container> {
PostgreSql9Container() {
super("postgres:9.6.11");
super("postgres:9.6.13");
}
}
@@ -152,7 +152,7 @@ final class DatabaseContainers {
extends PostgreSQLContainer<PostgreSql10Container> {
PostgreSql10Container() {
super("postgres:10.6");
super("postgres:10.8");
}
}
@@ -161,7 +161,7 @@ final class DatabaseContainers {
extends PostgreSQLContainer<PostgreSql11Container> {
PostgreSql11Container() {
super("postgres:11.1");
super("postgres:11.3");
}
}
@@ -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-CU14");
}
}

View File

@@ -1 +1 @@
mcr.microsoft.com/mssql/server:2017-CU13
mcr.microsoft.com/mssql/server:2017-CU14

View File

@@ -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);
}