From f697850d2326d6bac8c5c4d5d2382a28bd72a892 Mon Sep 17 00:00:00 2001 From: Eleftheria Stein Date: Thu, 11 Nov 2021 18:28:14 +0100 Subject: [PATCH] Remove Hazelcast 3 support Closes gh-1947 --- gradle/dependency-management.gradle | 6 +- settings.gradle | 2 - .../hazelcast4/hazelcast4.gradle | 41 -- ...elcast4IndexedSessionRepositoryITests.java | 251 --------- ...elcast4IndexedSessionRepositoryITests.java | 78 --- ...elcast4IndexedSessionRepositoryITests.java | 51 -- ...elcast4IndexedSessionRepositoryITests.java | 90 ---- .../hazelcast/Hazelcast4ITestUtils.java | 61 --- ...zelcast4IndexedSessionRepositoryTests.java | 241 --------- .../hazelcast/SessionEventRegistry.java | 72 --- .../resources/hazelcast-server.xml | 17 - .../resources/testcontainers.properties | 1 - .../Hazelcast4IndexedSessionRepository.java | 478 ------------------ .../Hazelcast4PrincipalNameExtractor.java | 43 -- ...Hazelcast4SessionUpdateEntryProcessor.java | 83 --- ...zelcast4IndexedSessionRepositoryTests.java | 470 ----------------- .../spring-session-hazelcast.gradle | 13 - ...zelcastIndexedSessionRepositoryITests.java | 54 +- ...zelcastIndexedSessionRepositoryITests.java | 2 +- .../hazelcast/HazelcastITestUtils.java | 15 +- .../resources/hazelcast-server.xml | 2 +- .../HazelcastIndexedSessionRepository.java | 40 +- .../hazelcast/HazelcastSessionSerializer.java | 2 +- .../hazelcast/PrincipalNameExtractor.java | 4 +- .../SessionUpdateEntryProcessor.java | 19 +- .../HazelcastHttpSessionConfiguration.java | 43 +- ...azelcastIndexedSessionRepositoryTests.java | 6 +- .../HazelcastSessionSerializerTests.java | 99 ---- .../SessionUpdateEntryProcessorTest.java} | 6 +- ...azelcastHttpSessionConfigurationTests.java | 4 +- .../java/sample/config/SessionConfig.java | 13 +- ...ring-session-sample-boot-hazelcast4.gradle | 21 - .../java/sample/BootTests.java | 86 ---- .../java/sample/pages/BasePage.java | 38 -- .../java/sample/pages/HomePage.java | 60 --- .../java/sample/pages/LoginPage.java | 66 --- .../resources/testcontainers.properties | 1 - .../src/main/java/sample/Application.java | 31 -- .../java/sample/config/IndexController.java | 30 -- .../java/sample/config/SecurityConfig.java | 43 -- .../java/sample/config/SessionConfig.java | 57 --- .../src/main/resources/application.properties | 2 - .../src/main/resources/static/favicon.ico | Bin 1150 -> 0 bytes .../src/main/resources/static/images/logo.png | Bin 1123 -> 0 bytes .../src/main/resources/templates/index.html | 11 - .../src/main/resources/templates/layout.html | 122 ----- ...session-sample-javaconfig-hazelcast.gradle | 2 +- .../src/main/java/sample/SessionConfig.java | 15 +- ...pring-session-sample-misc-hazelcast.gradle | 2 +- 49 files changed, 119 insertions(+), 2775 deletions(-) delete mode 100644 spring-session-hazelcast/hazelcast4/hazelcast4.gradle delete mode 100644 spring-session-hazelcast/hazelcast4/src/integration-test/java/org/springframework/session/hazelcast/AbstractHazelcast4IndexedSessionRepositoryITests.java delete mode 100644 spring-session-hazelcast/hazelcast4/src/integration-test/java/org/springframework/session/hazelcast/ClientServerHazelcast4IndexedSessionRepositoryITests.java delete mode 100644 spring-session-hazelcast/hazelcast4/src/integration-test/java/org/springframework/session/hazelcast/EmbeddedHazelcast4IndexedSessionRepositoryITests.java delete mode 100644 spring-session-hazelcast/hazelcast4/src/integration-test/java/org/springframework/session/hazelcast/FlushImmediateHazelcast4IndexedSessionRepositoryITests.java delete mode 100644 spring-session-hazelcast/hazelcast4/src/integration-test/java/org/springframework/session/hazelcast/Hazelcast4ITestUtils.java delete mode 100644 spring-session-hazelcast/hazelcast4/src/integration-test/java/org/springframework/session/hazelcast/SessionEventHazelcast4IndexedSessionRepositoryTests.java delete mode 100644 spring-session-hazelcast/hazelcast4/src/integration-test/java/org/springframework/session/hazelcast/SessionEventRegistry.java delete mode 100644 spring-session-hazelcast/hazelcast4/src/integration-test/resources/hazelcast-server.xml delete mode 100644 spring-session-hazelcast/hazelcast4/src/integration-test/resources/testcontainers.properties delete mode 100644 spring-session-hazelcast/hazelcast4/src/main/java/org/springframework/session/hazelcast/Hazelcast4IndexedSessionRepository.java delete mode 100644 spring-session-hazelcast/hazelcast4/src/main/java/org/springframework/session/hazelcast/Hazelcast4PrincipalNameExtractor.java delete mode 100644 spring-session-hazelcast/hazelcast4/src/main/java/org/springframework/session/hazelcast/Hazelcast4SessionUpdateEntryProcessor.java delete mode 100644 spring-session-hazelcast/hazelcast4/src/test/java/org/springframework/session/hazelcast/Hazelcast4IndexedSessionRepositoryTests.java delete mode 100644 spring-session-hazelcast/src/test/java/org/springframework/session/hazelcast/HazelcastSessionSerializerTests.java rename spring-session-hazelcast/{hazelcast4/src/test/java/org/springframework/session/hazelcast/Hazelcast4SessionUpdateEntryProcessorTest.java => src/test/java/org/springframework/session/hazelcast/SessionUpdateEntryProcessorTest.java} (96%) delete mode 100644 spring-session-samples/spring-session-sample-boot-hazelcast4/spring-session-sample-boot-hazelcast4.gradle delete mode 100644 spring-session-samples/spring-session-sample-boot-hazelcast4/src/integration-test/java/sample/BootTests.java delete mode 100644 spring-session-samples/spring-session-sample-boot-hazelcast4/src/integration-test/java/sample/pages/BasePage.java delete mode 100644 spring-session-samples/spring-session-sample-boot-hazelcast4/src/integration-test/java/sample/pages/HomePage.java delete mode 100644 spring-session-samples/spring-session-sample-boot-hazelcast4/src/integration-test/java/sample/pages/LoginPage.java delete mode 100644 spring-session-samples/spring-session-sample-boot-hazelcast4/src/integration-test/resources/testcontainers.properties delete mode 100644 spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/java/sample/Application.java delete mode 100644 spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/java/sample/config/IndexController.java delete mode 100644 spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/java/sample/config/SecurityConfig.java delete mode 100644 spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/java/sample/config/SessionConfig.java delete mode 100644 spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/resources/application.properties delete mode 100644 spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/resources/static/favicon.ico delete mode 100644 spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/resources/static/images/logo.png delete mode 100644 spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/resources/templates/index.html delete mode 100644 spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/resources/templates/layout.html diff --git a/gradle/dependency-management.gradle b/gradle/dependency-management.gradle index 3f4e6da8..a0369daf 100644 --- a/gradle/dependency-management.gradle +++ b/gradle/dependency-management.gradle @@ -10,11 +10,7 @@ dependencyManagement { } dependencies { - dependencySet(group: 'com.hazelcast', version: '3.12.12') { - entry 'hazelcast' - entry 'hazelcast-client' - } - + dependency 'com.hazelcast:hazelcast:4.2.2' dependency 'org.aspectj:aspectjweaver:1.9.7' dependency 'ch.qos.logback:logback-core:1.2.3' dependency 'com.google.code.findbugs:jsr305:3.0.2' diff --git a/settings.gradle b/settings.gradle index 67cdd447..74f79bce 100644 --- a/settings.gradle +++ b/settings.gradle @@ -18,8 +18,6 @@ include 'spring-session-data-redis' include 'spring-session-docs' include 'spring-session-hazelcast' include 'spring-session-jdbc' -include 'hazelcast4' -project(':hazelcast4').projectDir = file('spring-session-hazelcast/hazelcast4') file('spring-session-samples').eachDirMatch(~/spring-session-sample-.*/) { dir -> include dir.name diff --git a/spring-session-hazelcast/hazelcast4/hazelcast4.gradle b/spring-session-hazelcast/hazelcast4/hazelcast4.gradle deleted file mode 100644 index eac0d9b4..00000000 --- a/spring-session-hazelcast/hazelcast4/hazelcast4.gradle +++ /dev/null @@ -1,41 +0,0 @@ -plugins { - id 'java-library' - id 'io.spring.convention.repository' - id 'io.spring.convention.springdependencymangement' - id 'io.spring.convention.checkstyle' - id 'io.spring.convention.tests-configuration' - id 'io.spring.convention.integration-test' - id 'org.springframework.propdeps' -} - -configurations { - classesOnlyElements { - canBeConsumed = true - canBeResolved = false - } -} - -artifacts { - classesOnlyElements(compileJava.destinationDir) -} - -dependencies { - api project(':spring-session-core') - optional "com.hazelcast:hazelcast:4.2.2" - api "org.springframework:spring-context" - api "javax.annotation:javax.annotation-api" - - testImplementation "javax.servlet:javax.servlet-api" - testImplementation "org.assertj:assertj-core" - testImplementation "org.mockito:mockito-core" - testImplementation "org.springframework:spring-test" - testImplementation "org.springframework:spring-web" - testImplementation "org.junit.jupiter:junit-jupiter-api" - testImplementation "org.springframework.security:spring-security-core" - testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine" - - integrationTestCompile "org.testcontainers:testcontainers" - integrationTestCompile "com.hazelcast:hazelcast:4.2" - integrationTestCompile project(":spring-session-hazelcast") -} - diff --git a/spring-session-hazelcast/hazelcast4/src/integration-test/java/org/springframework/session/hazelcast/AbstractHazelcast4IndexedSessionRepositoryITests.java b/spring-session-hazelcast/hazelcast4/src/integration-test/java/org/springframework/session/hazelcast/AbstractHazelcast4IndexedSessionRepositoryITests.java deleted file mode 100644 index f38d7647..00000000 --- a/spring-session-hazelcast/hazelcast4/src/integration-test/java/org/springframework/session/hazelcast/AbstractHazelcast4IndexedSessionRepositoryITests.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright 2014-2021 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.session.hazelcast; - -import java.time.Duration; -import java.time.Instant; - -import com.hazelcast.core.HazelcastInstance; -import com.hazelcast.map.IMap; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.session.MapSession; -import org.springframework.session.hazelcast.Hazelcast4IndexedSessionRepository.HazelcastSession; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Base class for {@link Hazelcast4IndexedSessionRepository} integration tests. - * - * @author Eleftheria Stein - */ -abstract class AbstractHazelcast4IndexedSessionRepositoryITests { - - private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT"; - - @Autowired - private HazelcastInstance hazelcastInstance; - - @Autowired - private Hazelcast4IndexedSessionRepository repository; - - @Test - void createAndDestroySession() { - HazelcastSession sessionToSave = this.repository.createSession(); - String sessionId = sessionToSave.getId(); - - IMap hazelcastMap = this.hazelcastInstance - .getMap(Hazelcast4IndexedSessionRepository.DEFAULT_SESSION_MAP_NAME); - - this.repository.save(sessionToSave); - - assertThat(hazelcastMap.get(sessionId)).isEqualTo(sessionToSave); - - this.repository.deleteById(sessionId); - - assertThat(hazelcastMap.get(sessionId)).isNull(); - } - - @Test - void changeSessionIdWhenOnlyChangeId() { - String attrName = "changeSessionId"; - String attrValue = "changeSessionId-value"; - HazelcastSession toSave = this.repository.createSession(); - toSave.setAttribute(attrName, attrValue); - - this.repository.save(toSave); - - HazelcastSession findById = this.repository.findById(toSave.getId()); - - assertThat(findById.getAttribute(attrName)).isEqualTo(attrValue); - - String originalFindById = findById.getId(); - String changeSessionId = findById.changeSessionId(); - - this.repository.save(findById); - - assertThat(this.repository.findById(originalFindById)).isNull(); - - HazelcastSession findByChangeSessionId = this.repository.findById(changeSessionId); - - assertThat(findByChangeSessionId.getAttribute(attrName)).isEqualTo(attrValue); - - this.repository.deleteById(changeSessionId); - } - - @Test - void changeSessionIdWhenChangeTwice() { - HazelcastSession toSave = this.repository.createSession(); - - this.repository.save(toSave); - - String originalId = toSave.getId(); - String changeId1 = toSave.changeSessionId(); - String changeId2 = toSave.changeSessionId(); - - this.repository.save(toSave); - - assertThat(this.repository.findById(originalId)).isNull(); - assertThat(this.repository.findById(changeId1)).isNull(); - assertThat(this.repository.findById(changeId2)).isNotNull(); - - this.repository.deleteById(changeId2); - } - - @Test - void changeSessionIdWhenSetAttributeOnChangedSession() { - String attrName = "changeSessionId"; - String attrValue = "changeSessionId-value"; - - HazelcastSession toSave = this.repository.createSession(); - - this.repository.save(toSave); - - HazelcastSession findById = this.repository.findById(toSave.getId()); - - findById.setAttribute(attrName, attrValue); - - String originalFindById = findById.getId(); - String changeSessionId = findById.changeSessionId(); - - this.repository.save(findById); - - assertThat(this.repository.findById(originalFindById)).isNull(); - - HazelcastSession findByChangeSessionId = this.repository.findById(changeSessionId); - - assertThat(findByChangeSessionId.getAttribute(attrName)).isEqualTo(attrValue); - - this.repository.deleteById(changeSessionId); - } - - @Test - void changeSessionIdWhenHasNotSaved() { - HazelcastSession toSave = this.repository.createSession(); - String originalId = toSave.getId(); - toSave.changeSessionId(); - - this.repository.save(toSave); - - assertThat(this.repository.findById(toSave.getId())).isNotNull(); - assertThat(this.repository.findById(originalId)).isNull(); - - this.repository.deleteById(toSave.getId()); - } - - @Test // gh-1076 - 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(); - } - - @Test - void createAndUpdateSession() { - HazelcastSession session = this.repository.createSession(); - String sessionId = session.getId(); - - this.repository.save(session); - - session = this.repository.findById(sessionId); - session.setAttribute("attributeName", "attributeValue"); - - this.repository.save(session); - - assertThat(this.repository.findById(sessionId)).isNotNull(); - - this.repository.deleteById(sessionId); - } - - @Test - void createSessionWithSecurityContextAndFindById() { - HazelcastSession session = this.repository.createSession(); - String sessionId = session.getId(); - - Authentication authentication = new UsernamePasswordAuthenticationToken("saves-" + System.currentTimeMillis(), - "password", AuthorityUtils.createAuthorityList("ROLE_USER")); - SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); - securityContext.setAuthentication(authentication); - session.setAttribute(SPRING_SECURITY_CONTEXT, securityContext); - - this.repository.save(session); - - assertThat(this.repository.findById(sessionId)).isNotNull(); - - this.repository.deleteById(sessionId); - } - - @Test - void createAndUpdateSessionWhileKeepingOriginalTimeToLiveConfiguredOnRepository() { - final Duration defaultSessionTimeout = Duration.ofSeconds(1800); - - final IMap hazelcastMap = this.hazelcastInstance - .getMap(Hazelcast4IndexedSessionRepository.DEFAULT_SESSION_MAP_NAME); - - HazelcastSession session = this.repository.createSession(); - String sessionId = session.getId(); - this.repository.save(session); - - assertThat(session.getMaxInactiveInterval()).isEqualTo(defaultSessionTimeout); - assertThat(hazelcastMap.getEntryView(sessionId).getTtl()).isEqualTo(defaultSessionTimeout.toMillis()); - - session = this.repository.findById(sessionId); - session.setLastAccessedTime(Instant.now()); - this.repository.save(session); - - session = this.repository.findById(sessionId); - assertThat(session.getMaxInactiveInterval()).isEqualTo(defaultSessionTimeout); - assertThat(hazelcastMap.getEntryView(sessionId).getTtl()).isEqualTo(defaultSessionTimeout.toMillis()); - } - - @Test - void createAndUpdateSessionWhileKeepingTimeToLiveSetOnSession() { - final Duration individualSessionTimeout = Duration.ofSeconds(23); - - final IMap hazelcastMap = this.hazelcastInstance - .getMap(Hazelcast4IndexedSessionRepository.DEFAULT_SESSION_MAP_NAME); - - HazelcastSession session = this.repository.createSession(); - session.setMaxInactiveInterval(individualSessionTimeout); - String sessionId = session.getId(); - this.repository.save(session); - - assertThat(session.getMaxInactiveInterval()).isEqualTo(individualSessionTimeout); - assertThat(hazelcastMap.getEntryView(sessionId).getTtl()).isEqualTo(individualSessionTimeout.toMillis()); - - session = this.repository.findById(sessionId); - session.setAttribute("attribute", "value"); - this.repository.save(session); - - session = this.repository.findById(sessionId); - assertThat(session.getMaxInactiveInterval()).isEqualTo(individualSessionTimeout); - assertThat(hazelcastMap.getEntryView(sessionId).getTtl()).isEqualTo(individualSessionTimeout.toMillis()); - } - -} diff --git a/spring-session-hazelcast/hazelcast4/src/integration-test/java/org/springframework/session/hazelcast/ClientServerHazelcast4IndexedSessionRepositoryITests.java b/spring-session-hazelcast/hazelcast4/src/integration-test/java/org/springframework/session/hazelcast/ClientServerHazelcast4IndexedSessionRepositoryITests.java deleted file mode 100644 index dae3d4ec..00000000 --- a/spring-session-hazelcast/hazelcast4/src/integration-test/java/org/springframework/session/hazelcast/ClientServerHazelcast4IndexedSessionRepositoryITests.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2014-2021 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.session.hazelcast; - -import com.hazelcast.client.HazelcastClient; -import com.hazelcast.client.config.ClientConfig; -import com.hazelcast.core.HazelcastInstance; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.extension.ExtendWith; -import org.testcontainers.containers.GenericContainer; -import org.testcontainers.utility.MountableFile; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.session.MapSession; -import org.springframework.session.Session; -import org.springframework.session.hazelcast.config.annotation.web.http.EnableHazelcastHttpSession; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.context.web.WebAppConfiguration; - -/** - * Integration tests for {@link Hazelcast4IndexedSessionRepository} using client-server - * topology. - * - * @author Eleftheria Stein - */ -@ExtendWith(SpringExtension.class) -@ContextConfiguration -@WebAppConfiguration -class ClientServerHazelcast4IndexedSessionRepositoryITests extends AbstractHazelcast4IndexedSessionRepositoryITests { - - private static GenericContainer container = new GenericContainer<>("hazelcast/hazelcast:4.2.2") - .withExposedPorts(5701).withCopyFileToContainer(MountableFile.forClasspathResource("/hazelcast-server.xml"), - "/opt/hazelcast/hazelcast.xml"); - - @BeforeAll - static void setUpClass() { - container.start(); - } - - @AfterAll - static void tearDownClass() { - container.stop(); - } - - @Configuration - @EnableHazelcastHttpSession - static class HazelcastSessionConfig { - - @Bean - HazelcastInstance hazelcastInstance() { - ClientConfig clientConfig = new ClientConfig(); - clientConfig.getNetworkConfig() - .addAddress(container.getContainerIpAddress() + ":" + container.getFirstMappedPort()); - clientConfig.getUserCodeDeploymentConfig().setEnabled(true).addClass(Session.class) - .addClass(MapSession.class).addClass(Hazelcast4SessionUpdateEntryProcessor.class); - return HazelcastClient.newHazelcastClient(clientConfig); - } - - } - -} diff --git a/spring-session-hazelcast/hazelcast4/src/integration-test/java/org/springframework/session/hazelcast/EmbeddedHazelcast4IndexedSessionRepositoryITests.java b/spring-session-hazelcast/hazelcast4/src/integration-test/java/org/springframework/session/hazelcast/EmbeddedHazelcast4IndexedSessionRepositoryITests.java deleted file mode 100644 index 66db1b85..00000000 --- a/spring-session-hazelcast/hazelcast4/src/integration-test/java/org/springframework/session/hazelcast/EmbeddedHazelcast4IndexedSessionRepositoryITests.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2014-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.session.hazelcast; - -import com.hazelcast.core.HazelcastInstance; -import org.junit.jupiter.api.extension.ExtendWith; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.session.hazelcast.config.annotation.web.http.EnableHazelcastHttpSession; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.context.web.WebAppConfiguration; - -/** - * Integration tests for {@link Hazelcast4IndexedSessionRepository} using embedded - * topology. - * - * @author Eleftheria Stein - */ -@ExtendWith(SpringExtension.class) -@ContextConfiguration -@WebAppConfiguration -class EmbeddedHazelcast4IndexedSessionRepositoryITests extends AbstractHazelcast4IndexedSessionRepositoryITests { - - @EnableHazelcastHttpSession - @Configuration - static class HazelcastSessionConfig { - - @Bean - HazelcastInstance hazelcastInstance() { - return Hazelcast4ITestUtils.embeddedHazelcastServer(); - } - - } - -} diff --git a/spring-session-hazelcast/hazelcast4/src/integration-test/java/org/springframework/session/hazelcast/FlushImmediateHazelcast4IndexedSessionRepositoryITests.java b/spring-session-hazelcast/hazelcast4/src/integration-test/java/org/springframework/session/hazelcast/FlushImmediateHazelcast4IndexedSessionRepositoryITests.java deleted file mode 100644 index e1827ddf..00000000 --- a/spring-session-hazelcast/hazelcast4/src/integration-test/java/org/springframework/session/hazelcast/FlushImmediateHazelcast4IndexedSessionRepositoryITests.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2014-2021 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.session.hazelcast; - -import java.util.Map; - -import com.hazelcast.core.HazelcastInstance; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.session.FlushMode; -import org.springframework.session.hazelcast.config.annotation.web.http.EnableHazelcastHttpSession; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.context.web.WebAppConfiguration; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Integration tests for {@link Hazelcast4IndexedSessionRepository} using embedded - * topology, with flush mode set to immediate. - * - * @author Eleftheria Stein - */ -@ExtendWith(SpringExtension.class) -@ContextConfiguration -@WebAppConfiguration -class FlushImmediateHazelcast4IndexedSessionRepositoryITests { - - @Autowired - private Hazelcast4IndexedSessionRepository repository; - - @Test - void createSessionWithSecurityContextAndFindByPrincipalName() { - String username = "saves-" + System.currentTimeMillis(); - - Hazelcast4IndexedSessionRepository.HazelcastSession session = this.repository.createSession(); - String sessionId = session.getId(); - - Authentication authentication = new UsernamePasswordAuthenticationToken(username, "password", - AuthorityUtils.createAuthorityList("ROLE_USER")); - SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); - securityContext.setAuthentication(authentication); - session.setAttribute("SPRING_SECURITY_CONTEXT", securityContext); - - this.repository.save(session); - - Map findByPrincipalName = this.repository - .findByPrincipalName(username); - - assertThat(findByPrincipalName).hasSize(1); - assertThat(findByPrincipalName.keySet()).containsOnly(sessionId); - - this.repository.deleteById(sessionId); - } - - @EnableHazelcastHttpSession(flushMode = FlushMode.IMMEDIATE) - @Configuration - static class HazelcastSessionConfig { - - @Bean - HazelcastInstance hazelcastInstance() { - return Hazelcast4ITestUtils.embeddedHazelcastServer(); - } - - } - -} diff --git a/spring-session-hazelcast/hazelcast4/src/integration-test/java/org/springframework/session/hazelcast/Hazelcast4ITestUtils.java b/spring-session-hazelcast/hazelcast4/src/integration-test/java/org/springframework/session/hazelcast/Hazelcast4ITestUtils.java deleted file mode 100644 index 5c5c1d12..00000000 --- a/spring-session-hazelcast/hazelcast4/src/integration-test/java/org/springframework/session/hazelcast/Hazelcast4ITestUtils.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2014-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.session.hazelcast; - -import com.hazelcast.config.AttributeConfig; -import com.hazelcast.config.Config; -import com.hazelcast.config.IndexConfig; -import com.hazelcast.config.IndexType; -import com.hazelcast.config.NetworkConfig; -import com.hazelcast.config.SerializerConfig; -import com.hazelcast.core.Hazelcast; -import com.hazelcast.core.HazelcastInstance; - -import org.springframework.session.MapSession; - -/** - * Utility class for Hazelcast integration tests. - * - * @author Eleftheria Stein - */ -final class Hazelcast4ITestUtils { - - private Hazelcast4ITestUtils() { - } - - /** - * Creates {@link HazelcastInstance} for use in integration tests. - * @return the Hazelcast instance - */ - static HazelcastInstance embeddedHazelcastServer() { - Config config = new Config(); - NetworkConfig networkConfig = config.getNetworkConfig(); - networkConfig.setPort(0); - networkConfig.getJoin().getMulticastConfig().setEnabled(false); - AttributeConfig attributeConfig = new AttributeConfig() - .setName(Hazelcast4IndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE) - .setExtractorClassName(Hazelcast4PrincipalNameExtractor.class.getName()); - config.getMapConfig(Hazelcast4IndexedSessionRepository.DEFAULT_SESSION_MAP_NAME) - .addAttributeConfig(attributeConfig).addIndexConfig( - new IndexConfig(IndexType.HASH, Hazelcast4IndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE)); - SerializerConfig serializerConfig = new SerializerConfig(); - serializerConfig.setImplementation(new HazelcastSessionSerializer()).setTypeClass(MapSession.class); - config.getSerializationConfig().addSerializerConfig(serializerConfig); - return Hazelcast.newHazelcastInstance(config); - } - -} diff --git a/spring-session-hazelcast/hazelcast4/src/integration-test/java/org/springframework/session/hazelcast/SessionEventHazelcast4IndexedSessionRepositoryTests.java b/spring-session-hazelcast/hazelcast4/src/integration-test/java/org/springframework/session/hazelcast/SessionEventHazelcast4IndexedSessionRepositoryTests.java deleted file mode 100644 index a0ba4999..00000000 --- a/spring-session-hazelcast/hazelcast4/src/integration-test/java/org/springframework/session/hazelcast/SessionEventHazelcast4IndexedSessionRepositoryTests.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright 2014-2021 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.session.hazelcast; - -import java.time.Duration; -import java.time.Instant; - -import com.hazelcast.core.HazelcastInstance; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.session.FindByIndexNameSessionRepository; -import org.springframework.session.Session; -import org.springframework.session.SessionRepository; -import org.springframework.session.events.SessionCreatedEvent; -import org.springframework.session.events.SessionDeletedEvent; -import org.springframework.session.events.SessionExpiredEvent; -import org.springframework.session.hazelcast.config.annotation.web.http.EnableHazelcastHttpSession; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.context.web.WebAppConfiguration; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Ensure that the appropriate SessionEvents are fired at the expected times. Additionally - * ensure that the interactions with the {@link SessionRepository} abstraction behave as - * expected after each SessionEvent. - * - * @author Eleftheria Stein - */ -@ExtendWith(SpringExtension.class) -@ContextConfiguration -@WebAppConfiguration -class SessionEventHazelcast4IndexedSessionRepositoryTests { - - private static final int MAX_INACTIVE_INTERVAL_IN_SECONDS = 2; - - @Autowired - private SessionRepository repository; - - @Autowired - private SessionEventRegistry registry; - - @BeforeEach - void setup() { - this.registry.clear(); - } - - @Test - void saveSessionTest() throws InterruptedException { - String username = "saves-" + System.currentTimeMillis(); - - S sessionToSave = this.repository.createSession(); - - String expectedAttributeName = "a"; - String expectedAttributeValue = "b"; - sessionToSave.setAttribute(expectedAttributeName, expectedAttributeValue); - Authentication toSaveToken = new UsernamePasswordAuthenticationToken(username, "password", - AuthorityUtils.createAuthorityList("ROLE_USER")); - SecurityContext toSaveContext = SecurityContextHolder.createEmptyContext(); - toSaveContext.setAuthentication(toSaveToken); - sessionToSave.setAttribute("SPRING_SECURITY_CONTEXT", toSaveContext); - sessionToSave.setAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, username); - - this.repository.save(sessionToSave); - - assertThat(this.registry.receivedEvent(sessionToSave.getId())).isTrue(); - assertThat(this.registry.getEvent(sessionToSave.getId())) - .isInstanceOf(SessionCreatedEvent.class); - - Session session = this.repository.findById(sessionToSave.getId()); - - assertThat(session.getId()).isEqualTo(sessionToSave.getId()); - assertThat(session.getAttributeNames()).isEqualTo(sessionToSave.getAttributeNames()); - assertThat(session.getAttribute(expectedAttributeName)) - .isEqualTo(sessionToSave.getAttribute(expectedAttributeName)); - } - - @Test - void expiredSessionTest() throws InterruptedException { - S sessionToSave = this.repository.createSession(); - - this.repository.save(sessionToSave); - - assertThat(this.registry.receivedEvent(sessionToSave.getId())).isTrue(); - assertThat(this.registry.getEvent(sessionToSave.getId())) - .isInstanceOf(SessionCreatedEvent.class); - this.registry.clear(); - - assertThat(sessionToSave.getMaxInactiveInterval()) - .isEqualTo(Duration.ofSeconds(MAX_INACTIVE_INTERVAL_IN_SECONDS)); - - assertThat(this.registry.receivedEvent(sessionToSave.getId())).isTrue(); - assertThat(this.registry.getEvent(sessionToSave.getId())) - .isInstanceOf(SessionExpiredEvent.class); - - assertThat(this.repository.findById(sessionToSave.getId())).isNull(); - } - - @Test - void deletedSessionTest() throws InterruptedException { - S sessionToSave = this.repository.createSession(); - - this.repository.save(sessionToSave); - - assertThat(this.registry.receivedEvent(sessionToSave.getId())).isTrue(); - assertThat(this.registry.getEvent(sessionToSave.getId())) - .isInstanceOf(SessionCreatedEvent.class); - this.registry.clear(); - - this.repository.deleteById(sessionToSave.getId()); - - assertThat(this.registry.receivedEvent(sessionToSave.getId())).isTrue(); - assertThat(this.registry.getEvent(sessionToSave.getId())) - .isInstanceOf(SessionDeletedEvent.class); - - assertThat(this.repository.findById(sessionToSave.getId())).isNull(); - } - - @Test - void saveUpdatesTimeToLiveTest() throws InterruptedException { - S sessionToSave = this.repository.createSession(); - sessionToSave.setMaxInactiveInterval(Duration.ofSeconds(3)); - this.repository.save(sessionToSave); - - Thread.sleep(2000); - - // Get and save the session like SessionRepositoryFilter would. - S sessionToUpdate = this.repository.findById(sessionToSave.getId()); - sessionToUpdate.setLastAccessedTime(Instant.now()); - this.repository.save(sessionToUpdate); - - Thread.sleep(2000); - - assertThat(this.repository.findById(sessionToUpdate.getId())).isNotNull(); - } - - @Test // gh-1077 - 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.getEvent(sessionToSave.getId())) - .isInstanceOf(SessionCreatedEvent.class); - this.registry.clear(); - - sessionToSave.changeSessionId(); - this.repository.save(sessionToSave); - - assertThat(this.registry.receivedEvent(sessionToSave.getId())).isFalse(); - } - - @Test // gh-1300 - void updateMaxInactiveIntervalTest() 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.getEvent(sessionToSave.getId())) - .isInstanceOf(SessionCreatedEvent.class); - this.registry.clear(); - - S sessionToUpdate = this.repository.findById(sessionToSave.getId()); - sessionToUpdate.setLastAccessedTime(Instant.now()); - sessionToUpdate.setMaxInactiveInterval(Duration.ofSeconds(1)); - this.repository.save(sessionToUpdate); - - assertThat(this.registry.receivedEvent(sessionToUpdate.getId())).isTrue(); - assertThat(this.registry.getEvent(sessionToUpdate.getId())) - .isInstanceOf(SessionExpiredEvent.class); - assertThat(this.repository.findById(sessionToUpdate.getId())).isNull(); - } - - @Test // gh-1899 - void updateSessionAndExpireAfterOriginalTimeToLiveTest() throws InterruptedException { - S sessionToSave = this.repository.createSession(); - this.repository.save(sessionToSave); - - assertThat(this.registry.receivedEvent(sessionToSave.getId())).isTrue(); - assertThat(this.registry.getEvent(sessionToSave.getId())) - .isInstanceOf(SessionCreatedEvent.class); - this.registry.clear(); - - S sessionToUpdate = this.repository.findById(sessionToSave.getId()); - sessionToUpdate.setLastAccessedTime(Instant.now()); - this.repository.save(sessionToUpdate); - - assertThat(this.registry.receivedEvent(sessionToUpdate.getId())).isTrue(); - assertThat(this.registry.getEvent(sessionToUpdate.getId())) - .isInstanceOf(SessionExpiredEvent.class); - // Assert this after the expired event was received because it would otherwise do - // its own expiration check and explicitly delete the session from Hazelcast - // regardless of the TTL of the IMap entry. - assertThat(this.repository.findById(sessionToUpdate.getId())).isNull(); - } - - @Configuration - @EnableHazelcastHttpSession(maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS) - static class HazelcastSessionConfig { - - @Bean - HazelcastInstance embeddedHazelcast() { - return Hazelcast4ITestUtils.embeddedHazelcastServer(); - } - - @Bean - SessionEventRegistry sessionEventRegistry() { - return new SessionEventRegistry(); - } - - } - -} diff --git a/spring-session-hazelcast/hazelcast4/src/integration-test/java/org/springframework/session/hazelcast/SessionEventRegistry.java b/spring-session-hazelcast/hazelcast4/src/integration-test/java/org/springframework/session/hazelcast/SessionEventRegistry.java deleted file mode 100644 index 0cee61e3..00000000 --- a/spring-session-hazelcast/hazelcast4/src/integration-test/java/org/springframework/session/hazelcast/SessionEventRegistry.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2014-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.session.hazelcast; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import org.springframework.context.ApplicationListener; -import org.springframework.session.events.AbstractSessionEvent; - -class SessionEventRegistry implements ApplicationListener { - - private Map events = new HashMap<>(); - - private ConcurrentMap locks = new ConcurrentHashMap<>(); - - @Override - public void onApplicationEvent(AbstractSessionEvent event) { - String sessionId = event.getSessionId(); - this.events.put(sessionId, event); - Object lock = getLock(sessionId); - synchronized (lock) { - lock.notifyAll(); - } - } - - void clear() { - this.events.clear(); - this.locks.clear(); - } - - boolean receivedEvent(String sessionId) throws InterruptedException { - return waitForEvent(sessionId) != null; - } - - @SuppressWarnings("unchecked") - E getEvent(String sessionId) throws InterruptedException { - return (E) waitForEvent(sessionId); - } - - @SuppressWarnings("unchecked") - private E waitForEvent(String sessionId) throws InterruptedException { - Object lock = getLock(sessionId); - synchronized (lock) { - if (!this.events.containsKey(sessionId)) { - lock.wait(10000); - } - } - return (E) this.events.get(sessionId); - } - - private Object getLock(String sessionId) { - return this.locks.computeIfAbsent(sessionId, (k) -> new Object()); - } - -} diff --git a/spring-session-hazelcast/hazelcast4/src/integration-test/resources/hazelcast-server.xml b/spring-session-hazelcast/hazelcast4/src/integration-test/resources/hazelcast-server.xml deleted file mode 100644 index 394eaf8d..00000000 --- a/spring-session-hazelcast/hazelcast4/src/integration-test/resources/hazelcast-server.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - ETERNAL - LOCAL_AND_CACHED_CLASSES - - - diff --git a/spring-session-hazelcast/hazelcast4/src/integration-test/resources/testcontainers.properties b/spring-session-hazelcast/hazelcast4/src/integration-test/resources/testcontainers.properties deleted file mode 100644 index e3e83419..00000000 --- a/spring-session-hazelcast/hazelcast4/src/integration-test/resources/testcontainers.properties +++ /dev/null @@ -1 +0,0 @@ -ryuk.container.timeout=120 diff --git a/spring-session-hazelcast/hazelcast4/src/main/java/org/springframework/session/hazelcast/Hazelcast4IndexedSessionRepository.java b/spring-session-hazelcast/hazelcast4/src/main/java/org/springframework/session/hazelcast/Hazelcast4IndexedSessionRepository.java deleted file mode 100644 index 0406c31b..00000000 --- a/spring-session-hazelcast/hazelcast4/src/main/java/org/springframework/session/hazelcast/Hazelcast4IndexedSessionRepository.java +++ /dev/null @@ -1,478 +0,0 @@ -/* - * Copyright 2014-2021 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.session.hazelcast; - -import java.time.Duration; -import java.time.Instant; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.TimeUnit; - -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; - -import com.hazelcast.core.EntryEvent; -import com.hazelcast.core.HazelcastInstance; -import com.hazelcast.map.IMap; -import com.hazelcast.map.listener.EntryAddedListener; -import com.hazelcast.map.listener.EntryEvictedListener; -import com.hazelcast.map.listener.EntryExpiredListener; -import com.hazelcast.map.listener.EntryRemovedListener; -import com.hazelcast.query.Predicates; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.session.DelegatingIndexResolver; -import org.springframework.session.FindByIndexNameSessionRepository; -import org.springframework.session.FlushMode; -import org.springframework.session.IndexResolver; -import org.springframework.session.MapSession; -import org.springframework.session.PrincipalNameIndexResolver; -import org.springframework.session.SaveMode; -import org.springframework.session.Session; -import org.springframework.session.events.AbstractSessionEvent; -import org.springframework.session.events.SessionCreatedEvent; -import org.springframework.session.events.SessionDeletedEvent; -import org.springframework.session.events.SessionExpiredEvent; -import org.springframework.util.Assert; - -/** - * A {@link org.springframework.session.SessionRepository} implementation using Hazelcast - * 4 that stores sessions in Hazelcast's distributed {@link IMap}. - * - *

- * An example of how to create a new instance can be seen below: - * - *

- * Config config = new Config();
- *
- * // ... configure Hazelcast ...
- *
- * HazelcastInstance hazelcastInstance = Hazelcast.newHazelcastInstance(config);
- *
- * Hazelcast4IndexedSessionRepository sessionRepository =
- *         new Hazelcast4IndexedSessionRepository(hazelcastInstance);
- * 
- * - * In order to support finding sessions by principal name using - * {@link #findByIndexNameAndIndexValue(String, String)} method, custom configuration of - * {@code IMap} supplied to this implementation is required. - * - * The following snippet demonstrates how to define required configuration using - * programmatic Hazelcast Configuration: - * - *
- * AttributeConfig attributeConfig = new AttributeConfig()
- *         .setName(Hazelcast4IndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE)
- *         .setExtractorClassName(Hazelcast4PrincipalNameExtractor.class.getName());
- *
- * Config config = new Config();
- *
- * config.getMapConfig(Hazelcast4IndexedSessionRepository.DEFAULT_SESSION_MAP_NAME)
- *         .addAttributeConfig(attributeConfig)
- *         .addIndexConfig(new IndexConfig(
- *                 IndexType.HASH,
- *                 Hazelcast4IndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE));
- *
- * Hazelcast.newHazelcastInstance(config);
- * 
- * - * This implementation listens for events on the Hazelcast-backed SessionRepository and - * translates those events into the corresponding Spring Session events. Publish the - * Spring Session events with the given {@link ApplicationEventPublisher}. - * - *
    - *
  • entryAdded - {@link SessionCreatedEvent}
  • - *
  • entryEvicted - {@link SessionExpiredEvent}
  • - *
  • entryExpired - {@link SessionExpiredEvent}
  • - *
  • entryRemoved - {@link SessionDeletedEvent}
  • - *
- * - * @author Eleftheria Stein - * @since 2.4.0 - */ -public class Hazelcast4IndexedSessionRepository - implements FindByIndexNameSessionRepository, - EntryAddedListener, EntryEvictedListener, - EntryRemovedListener, EntryExpiredListener { - - /** - * The default name of map used by Spring Session to store sessions. - */ - public static final String DEFAULT_SESSION_MAP_NAME = "spring:session:sessions"; - - /** - * The principal name custom attribute name. - */ - public static final String PRINCIPAL_NAME_ATTRIBUTE = "principalName"; - - private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT"; - - private static final Log logger = LogFactory.getLog(Hazelcast4IndexedSessionRepository.class); - - private final HazelcastInstance hazelcastInstance; - - private ApplicationEventPublisher eventPublisher = (event) -> { - }; - - /** - * If non-null, this value is used to override - * {@link MapSession#setMaxInactiveInterval(Duration)}. - */ - private Integer defaultMaxInactiveInterval; - - private IndexResolver indexResolver = new DelegatingIndexResolver<>(new PrincipalNameIndexResolver<>()); - - private String sessionMapName = DEFAULT_SESSION_MAP_NAME; - - private FlushMode flushMode = FlushMode.ON_SAVE; - - private SaveMode saveMode = SaveMode.ON_SET_ATTRIBUTE; - - private IMap sessions; - - private UUID sessionListenerId; - - /** - * Create a new {@link Hazelcast4IndexedSessionRepository} instance. - * @param hazelcastInstance the {@link HazelcastInstance} to use for managing sessions - */ - public Hazelcast4IndexedSessionRepository(HazelcastInstance hazelcastInstance) { - Assert.notNull(hazelcastInstance, "HazelcastInstance must not be null"); - this.hazelcastInstance = hazelcastInstance; - } - - @PostConstruct - public void init() { - this.sessions = this.hazelcastInstance.getMap(this.sessionMapName); - this.sessionListenerId = this.sessions.addEntryListener(this, true); - } - - @PreDestroy - public void close() { - this.sessions.removeEntryListener(this.sessionListenerId); - } - - /** - * Sets the {@link ApplicationEventPublisher} that is used to publish - * {@link AbstractSessionEvent session events}. The default is to not publish session - * events. - * @param applicationEventPublisher the {@link ApplicationEventPublisher} that is used - * to publish session events. Cannot be null. - */ - public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { - Assert.notNull(applicationEventPublisher, "ApplicationEventPublisher cannot be null"); - this.eventPublisher = applicationEventPublisher; - } - - /** - * Set the maximum inactive interval in seconds between requests before newly created - * sessions will be invalidated. A negative time indicates that the session will never - * timeout. The default is 1800 (30 minutes). - * @param defaultMaxInactiveInterval the maximum inactive interval in seconds - */ - public void setDefaultMaxInactiveInterval(Integer defaultMaxInactiveInterval) { - this.defaultMaxInactiveInterval = defaultMaxInactiveInterval; - } - - /** - * Set the {@link IndexResolver} to use. - * @param indexResolver the index resolver - */ - public void setIndexResolver(IndexResolver indexResolver) { - Assert.notNull(indexResolver, "indexResolver cannot be null"); - this.indexResolver = indexResolver; - } - - /** - * Set the name of map used to store sessions. - * @param sessionMapName the session map name - */ - public void setSessionMapName(String sessionMapName) { - Assert.hasText(sessionMapName, "Map name must not be empty"); - this.sessionMapName = sessionMapName; - } - - /** - * Sets the Hazelcast flush mode. Default flush mode is {@link FlushMode#ON_SAVE}. - * @param flushMode the new Hazelcast flush mode - */ - public void setFlushMode(FlushMode flushMode) { - Assert.notNull(flushMode, "flushMode cannot be null"); - this.flushMode = flushMode; - } - - /** - * Set the save mode. - * @param saveMode the save mode - */ - public void setSaveMode(SaveMode saveMode) { - Assert.notNull(saveMode, "saveMode must not be null"); - this.saveMode = saveMode; - } - - @Override - public HazelcastSession createSession() { - MapSession cached = new MapSession(); - if (this.defaultMaxInactiveInterval != null) { - cached.setMaxInactiveInterval(Duration.ofSeconds(this.defaultMaxInactiveInterval)); - } - HazelcastSession session = new HazelcastSession(cached, true); - session.flushImmediateIfNecessary(); - return session; - } - - @Override - public void save(HazelcastSession session) { - if (session.isNew) { - this.sessions.set(session.getId(), session.getDelegate(), session.getMaxInactiveInterval().getSeconds(), - TimeUnit.SECONDS); - } - 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); - } - else if (session.hasChanges()) { - Hazelcast4SessionUpdateEntryProcessor entryProcessor = new Hazelcast4SessionUpdateEntryProcessor(); - if (session.lastAccessedTimeChanged) { - entryProcessor.setLastAccessedTime(session.getLastAccessedTime()); - } - if (session.maxInactiveIntervalChanged) { - entryProcessor.setMaxInactiveInterval(session.getMaxInactiveInterval()); - } - if (!session.delta.isEmpty()) { - entryProcessor.setDelta(new HashMap<>(session.delta)); - } - this.sessions.executeOnKey(session.getId(), entryProcessor); - } - session.clearChangeFlags(); - } - - @Override - public HazelcastSession findById(String id) { - MapSession saved = this.sessions.get(id); - if (saved == null) { - return null; - } - if (saved.isExpired()) { - deleteById(saved.getId()); - return null; - } - return new HazelcastSession(saved, false); - } - - @Override - public void deleteById(String id) { - this.sessions.remove(id); - } - - @Override - public Map findByIndexNameAndIndexValue(String indexName, String indexValue) { - if (!PRINCIPAL_NAME_INDEX_NAME.equals(indexName)) { - return Collections.emptyMap(); - } - Collection sessions = this.sessions.values(Predicates.equal(PRINCIPAL_NAME_ATTRIBUTE, indexValue)); - Map sessionMap = new HashMap<>(sessions.size()); - for (MapSession session : sessions) { - sessionMap.put(session.getId(), new HazelcastSession(session, false)); - } - return sessionMap; - } - - @Override - public void entryAdded(EntryEvent event) { - 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)); - } - } - - @Override - public void entryEvicted(EntryEvent event) { - if (logger.isDebugEnabled()) { - logger.debug("Session expired with id: " + event.getOldValue().getId()); - } - this.eventPublisher.publishEvent(new SessionExpiredEvent(this, event.getOldValue())); - } - - @Override - public void entryRemoved(EntryEvent event) { - 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)); - } - } - - @Override - public void entryExpired(EntryEvent event) { - if (logger.isDebugEnabled()) { - logger.debug("Session expired with id: " + event.getOldValue().getId()); - } - this.eventPublisher.publishEvent(new SessionExpiredEvent(this, event.getOldValue())); - } - - /** - * A custom implementation of {@link Session} that uses a {@link MapSession} as the - * basis for its mapping. It keeps track if changes have been made since last save. - * - * @author Aleksandar Stojsavljevic - */ - final class HazelcastSession implements Session { - - private final MapSession delegate; - - private boolean isNew; - - private boolean sessionIdChanged; - - private boolean lastAccessedTimeChanged; - - private boolean maxInactiveIntervalChanged; - - private String originalId; - - private Map delta = new HashMap<>(); - - HazelcastSession(MapSession cached, boolean isNew) { - this.delegate = cached; - this.isNew = isNew; - this.originalId = cached.getId(); - if (this.isNew || (Hazelcast4IndexedSessionRepository.this.saveMode == SaveMode.ALWAYS)) { - getAttributeNames() - .forEach((attributeName) -> this.delta.put(attributeName, cached.getAttribute(attributeName))); - } - } - - @Override - public void setLastAccessedTime(Instant lastAccessedTime) { - this.delegate.setLastAccessedTime(lastAccessedTime); - this.lastAccessedTimeChanged = true; - flushImmediateIfNecessary(); - } - - @Override - public boolean isExpired() { - return this.delegate.isExpired(); - } - - @Override - public Instant getCreationTime() { - return this.delegate.getCreationTime(); - } - - @Override - public String getId() { - return this.delegate.getId(); - } - - @Override - public String changeSessionId() { - String newSessionId = this.delegate.changeSessionId(); - this.sessionIdChanged = true; - return newSessionId; - } - - @Override - public Instant getLastAccessedTime() { - return this.delegate.getLastAccessedTime(); - } - - @Override - public void setMaxInactiveInterval(Duration interval) { - Assert.notNull(interval, "interval must not be null"); - this.delegate.setMaxInactiveInterval(interval); - this.maxInactiveIntervalChanged = true; - flushImmediateIfNecessary(); - } - - @Override - public Duration getMaxInactiveInterval() { - return this.delegate.getMaxInactiveInterval(); - } - - @Override - public T getAttribute(String attributeName) { - T attributeValue = this.delegate.getAttribute(attributeName); - if (attributeValue != null - && Hazelcast4IndexedSessionRepository.this.saveMode.equals(SaveMode.ON_GET_ATTRIBUTE)) { - this.delta.put(attributeName, attributeValue); - } - return attributeValue; - } - - @Override - public Set getAttributeNames() { - return this.delegate.getAttributeNames(); - } - - @Override - public void setAttribute(String attributeName, Object attributeValue) { - this.delegate.setAttribute(attributeName, attributeValue); - this.delta.put(attributeName, attributeValue); - if (SPRING_SECURITY_CONTEXT.equals(attributeName)) { - Map indexes = Hazelcast4IndexedSessionRepository.this.indexResolver - .resolveIndexesFor(this); - String principal = (attributeValue != null) ? indexes.get(PRINCIPAL_NAME_INDEX_NAME) : null; - this.delegate.setAttribute(PRINCIPAL_NAME_INDEX_NAME, principal); - this.delta.put(PRINCIPAL_NAME_INDEX_NAME, principal); - } - flushImmediateIfNecessary(); - } - - @Override - public void removeAttribute(String attributeName) { - setAttribute(attributeName, null); - } - - MapSession getDelegate() { - return this.delegate; - } - - boolean hasChanges() { - return (this.lastAccessedTimeChanged || this.maxInactiveIntervalChanged || !this.delta.isEmpty()); - } - - void clearChangeFlags() { - this.isNew = false; - this.lastAccessedTimeChanged = false; - this.sessionIdChanged = false; - this.maxInactiveIntervalChanged = false; - this.delta.clear(); - } - - private void flushImmediateIfNecessary() { - if (Hazelcast4IndexedSessionRepository.this.flushMode == FlushMode.IMMEDIATE) { - Hazelcast4IndexedSessionRepository.this.save(this); - } - } - - } - -} diff --git a/spring-session-hazelcast/hazelcast4/src/main/java/org/springframework/session/hazelcast/Hazelcast4PrincipalNameExtractor.java b/spring-session-hazelcast/hazelcast4/src/main/java/org/springframework/session/hazelcast/Hazelcast4PrincipalNameExtractor.java deleted file mode 100644 index b879bd5f..00000000 --- a/spring-session-hazelcast/hazelcast4/src/main/java/org/springframework/session/hazelcast/Hazelcast4PrincipalNameExtractor.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2014-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.session.hazelcast; - -import com.hazelcast.query.extractor.ValueCollector; -import com.hazelcast.query.extractor.ValueExtractor; - -import org.springframework.session.FindByIndexNameSessionRepository; -import org.springframework.session.MapSession; - -/** - * Hazelcast {@link ValueExtractor} responsible for extracting principal name from the - * {@link MapSession} to be used with Hazelcast 4. - * - * @author Eleftheria Stein - * @since 2.4.0 - */ -public class Hazelcast4PrincipalNameExtractor implements ValueExtractor { - - @Override - @SuppressWarnings("unchecked") - public void extract(MapSession target, String argument, ValueCollector collector) { - String principalName = target.getAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME); - if (principalName != null) { - collector.addObject(principalName); - } - } - -} diff --git a/spring-session-hazelcast/hazelcast4/src/main/java/org/springframework/session/hazelcast/Hazelcast4SessionUpdateEntryProcessor.java b/spring-session-hazelcast/hazelcast4/src/main/java/org/springframework/session/hazelcast/Hazelcast4SessionUpdateEntryProcessor.java deleted file mode 100644 index eb29a74e..00000000 --- a/spring-session-hazelcast/hazelcast4/src/main/java/org/springframework/session/hazelcast/Hazelcast4SessionUpdateEntryProcessor.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2014-2021 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.session.hazelcast; - -import java.time.Duration; -import java.time.Instant; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import com.hazelcast.map.EntryProcessor; -import com.hazelcast.map.ExtendedMapEntry; - -import org.springframework.session.MapSession; - -/** - * Hazelcast {@link EntryProcessor} responsible for handling updates to session when using - * Hazelcast 4. - * - * @author Eleftheria Stein - * @since 2.4.0 - */ -public class Hazelcast4SessionUpdateEntryProcessor implements EntryProcessor { - - private Instant lastAccessedTime; - - private Duration maxInactiveInterval; - - private Map delta; - - @Override - public Object process(Map.Entry entry) { - MapSession value = entry.getValue(); - 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 attribute : this.delta.entrySet()) { - if (attribute.getValue() != null) { - value.setAttribute(attribute.getKey(), attribute.getValue()); - } - else { - value.removeAttribute(attribute.getKey()); - } - } - } - ((ExtendedMapEntry) entry).setValue(value, value.getMaxInactiveInterval().getSeconds(), - TimeUnit.SECONDS); - return Boolean.TRUE; - } - - void setLastAccessedTime(Instant lastAccessedTime) { - this.lastAccessedTime = lastAccessedTime; - } - - void setMaxInactiveInterval(Duration maxInactiveInterval) { - this.maxInactiveInterval = maxInactiveInterval; - } - - void setDelta(Map delta) { - this.delta = delta; - } - -} diff --git a/spring-session-hazelcast/hazelcast4/src/test/java/org/springframework/session/hazelcast/Hazelcast4IndexedSessionRepositoryTests.java b/spring-session-hazelcast/hazelcast4/src/test/java/org/springframework/session/hazelcast/Hazelcast4IndexedSessionRepositoryTests.java deleted file mode 100644 index 8cc271a0..00000000 --- a/spring-session-hazelcast/hazelcast4/src/test/java/org/springframework/session/hazelcast/Hazelcast4IndexedSessionRepositoryTests.java +++ /dev/null @@ -1,470 +0,0 @@ -/* - * Copyright 2014-2021 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.session.hazelcast; - -import java.time.Duration; -import java.time.Instant; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import com.hazelcast.core.HazelcastInstance; -import com.hazelcast.map.EntryProcessor; -import com.hazelcast.map.IMap; -import com.hazelcast.map.listener.MapListener; -import com.hazelcast.query.impl.predicates.EqualPredicate; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; - -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.session.FindByIndexNameSessionRepository; -import org.springframework.session.FlushMode; -import org.springframework.session.MapSession; -import org.springframework.session.SaveMode; -import org.springframework.session.hazelcast.Hazelcast4IndexedSessionRepository.HazelcastSession; -import org.springframework.test.util.ReflectionTestUtils; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.isA; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; - -/** - * Tests for {@link Hazelcast4IndexedSessionRepository}. - * - * @author Eleftheria Stein - */ -class Hazelcast4IndexedSessionRepositoryTests { - - private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT"; - - private HazelcastInstance hazelcastInstance = mock(HazelcastInstance.class); - - @SuppressWarnings("unchecked") - private IMap sessions = mock(IMap.class); - - private Hazelcast4IndexedSessionRepository repository; - - @BeforeEach - void setUp() { - given(this.hazelcastInstance.getMap(anyString())).willReturn(this.sessions); - this.repository = new Hazelcast4IndexedSessionRepository(this.hazelcastInstance); - this.repository.init(); - } - - @Test - void constructorNullHazelcastInstance() { - assertThatIllegalArgumentException().isThrownBy(() -> new Hazelcast4IndexedSessionRepository(null)) - .withMessage("HazelcastInstance must not be null"); - } - - @Test - void setSaveModeNull() { - assertThatIllegalArgumentException().isThrownBy(() -> this.repository.setSaveMode(null)) - .withMessage("saveMode must not be null"); - } - - @Test - void createSessionDefaultMaxInactiveInterval() { - verify(this.sessions, times(1)).addEntryListener(any(MapListener.class), anyBoolean()); - - HazelcastSession session = this.repository.createSession(); - - assertThat(session.getMaxInactiveInterval()).isEqualTo(new MapSession().getMaxInactiveInterval()); - verifyNoMoreInteractions(this.sessions); - } - - @Test - void createSessionCustomMaxInactiveInterval() { - verify(this.sessions, times(1)).addEntryListener(any(MapListener.class), anyBoolean()); - - int interval = 1; - this.repository.setDefaultMaxInactiveInterval(interval); - - HazelcastSession session = this.repository.createSession(); - - assertThat(session.getMaxInactiveInterval()).isEqualTo(Duration.ofSeconds(interval)); - verifyNoMoreInteractions(this.sessions); - } - - @Test - void saveNewFlushModeOnSave() { - verify(this.sessions, times(1)).addEntryListener(any(MapListener.class), anyBoolean()); - - HazelcastSession session = this.repository.createSession(); - verifyNoMoreInteractions(this.sessions); - - this.repository.save(session); - verify(this.sessions, times(1)).set(eq(session.getId()), eq(session.getDelegate()), isA(Long.class), - eq(TimeUnit.SECONDS)); - verifyNoMoreInteractions(this.sessions); - } - - @Test - void saveNewFlushModeImmediate() { - verify(this.sessions, times(1)).addEntryListener(any(MapListener.class), anyBoolean()); - - this.repository.setFlushMode(FlushMode.IMMEDIATE); - - HazelcastSession session = this.repository.createSession(); - verify(this.sessions, times(1)).set(eq(session.getId()), eq(session.getDelegate()), isA(Long.class), - eq(TimeUnit.SECONDS)); - verifyNoMoreInteractions(this.sessions); - } - - @Test - void saveUpdatedAttributeFlushModeOnSave() { - verify(this.sessions, times(1)).addEntryListener(any(MapListener.class), anyBoolean()); - - HazelcastSession session = this.repository.createSession(); - session.setAttribute("testName", "testValue"); - verifyNoMoreInteractions(this.sessions); - - this.repository.save(session); - verify(this.sessions, times(1)).set(eq(session.getId()), eq(session.getDelegate()), isA(Long.class), - eq(TimeUnit.SECONDS)); - verifyNoMoreInteractions(this.sessions); - } - - @Test - void saveUpdatedAttributeFlushModeImmediate() { - verify(this.sessions, times(1)).addEntryListener(any(MapListener.class), anyBoolean()); - - this.repository.setFlushMode(FlushMode.IMMEDIATE); - - HazelcastSession session = this.repository.createSession(); - session.setAttribute("testName", "testValue"); - verify(this.sessions, times(1)).set(eq(session.getId()), eq(session.getDelegate()), isA(Long.class), - eq(TimeUnit.SECONDS)); - verify(this.sessions, times(1)).executeOnKey(eq(session.getId()), any(EntryProcessor.class)); - - this.repository.save(session); - verifyNoMoreInteractions(this.sessions); - } - - @Test - void removeAttributeFlushModeOnSave() { - verify(this.sessions, times(1)).addEntryListener(any(MapListener.class), anyBoolean()); - - HazelcastSession session = this.repository.createSession(); - session.removeAttribute("testName"); - verifyNoMoreInteractions(this.sessions); - - this.repository.save(session); - verify(this.sessions, times(1)).set(eq(session.getId()), eq(session.getDelegate()), isA(Long.class), - eq(TimeUnit.SECONDS)); - verifyNoMoreInteractions(this.sessions); - } - - @Test - void removeAttributeFlushModeImmediate() { - verify(this.sessions, times(1)).addEntryListener(any(MapListener.class), anyBoolean()); - - this.repository.setFlushMode(FlushMode.IMMEDIATE); - - HazelcastSession session = this.repository.createSession(); - session.removeAttribute("testName"); - verify(this.sessions, times(1)).set(eq(session.getId()), eq(session.getDelegate()), isA(Long.class), - eq(TimeUnit.SECONDS)); - verify(this.sessions, times(1)).executeOnKey(eq(session.getId()), any(EntryProcessor.class)); - - this.repository.save(session); - verifyNoMoreInteractions(this.sessions); - } - - @Test - void saveUpdatedLastAccessedTimeFlushModeOnSave() { - verify(this.sessions, times(1)).addEntryListener(any(MapListener.class), anyBoolean()); - - HazelcastSession session = this.repository.createSession(); - session.setLastAccessedTime(Instant.now()); - verifyNoMoreInteractions(this.sessions); - - this.repository.save(session); - verify(this.sessions, times(1)).set(eq(session.getId()), eq(session.getDelegate()), isA(Long.class), - eq(TimeUnit.SECONDS)); - verifyNoMoreInteractions(this.sessions); - } - - @Test - void saveUpdatedLastAccessedTimeFlushModeImmediate() { - verify(this.sessions, times(1)).addEntryListener(any(MapListener.class), anyBoolean()); - - this.repository.setFlushMode(FlushMode.IMMEDIATE); - - HazelcastSession session = this.repository.createSession(); - session.setLastAccessedTime(Instant.now()); - verify(this.sessions, times(1)).set(eq(session.getId()), eq(session.getDelegate()), isA(Long.class), - eq(TimeUnit.SECONDS)); - verify(this.sessions, times(1)).executeOnKey(eq(session.getId()), any(EntryProcessor.class)); - - this.repository.save(session); - verifyNoMoreInteractions(this.sessions); - } - - @Test - void saveUpdatedMaxInactiveIntervalInSecondsFlushModeOnSave() { - verify(this.sessions, times(1)).addEntryListener(any(MapListener.class), anyBoolean()); - - HazelcastSession session = this.repository.createSession(); - session.setMaxInactiveInterval(Duration.ofSeconds(1)); - verifyNoMoreInteractions(this.sessions); - - this.repository.save(session); - verify(this.sessions, times(1)).set(eq(session.getId()), eq(session.getDelegate()), isA(Long.class), - eq(TimeUnit.SECONDS)); - verifyNoMoreInteractions(this.sessions); - } - - @Test - void saveUpdatedMaxInactiveIntervalInSecondsFlushModeImmediate() { - verify(this.sessions, times(1)).addEntryListener(any(MapListener.class), anyBoolean()); - - this.repository.setFlushMode(FlushMode.IMMEDIATE); - - HazelcastSession session = this.repository.createSession(); - String sessionId = session.getId(); - session.setMaxInactiveInterval(Duration.ofSeconds(1)); - verify(this.sessions, times(1)).set(eq(sessionId), eq(session.getDelegate()), isA(Long.class), - eq(TimeUnit.SECONDS)); - verify(this.sessions, times(1)).executeOnKey(eq(sessionId), any(EntryProcessor.class)); - - this.repository.save(session); - verifyNoMoreInteractions(this.sessions); - } - - @Test - void saveUnchangedFlushModeOnSave() { - verify(this.sessions, times(1)).addEntryListener(any(MapListener.class), anyBoolean()); - - HazelcastSession session = this.repository.createSession(); - this.repository.save(session); - verify(this.sessions, times(1)).set(eq(session.getId()), eq(session.getDelegate()), isA(Long.class), - eq(TimeUnit.SECONDS)); - - this.repository.save(session); - verifyNoMoreInteractions(this.sessions); - } - - @Test - void saveUnchangedFlushModeImmediate() { - verify(this.sessions, times(1)).addEntryListener(any(MapListener.class), anyBoolean()); - - this.repository.setFlushMode(FlushMode.IMMEDIATE); - - HazelcastSession session = this.repository.createSession(); - verify(this.sessions, times(1)).set(eq(session.getId()), eq(session.getDelegate()), isA(Long.class), - eq(TimeUnit.SECONDS)); - - this.repository.save(session); - verifyNoMoreInteractions(this.sessions); - } - - @Test - void getSessionNotFound() { - verify(this.sessions, times(1)).addEntryListener(any(MapListener.class), anyBoolean()); - - String sessionId = "testSessionId"; - - HazelcastSession session = this.repository.findById(sessionId); - - assertThat(session).isNull(); - verify(this.sessions, times(1)).get(eq(sessionId)); - verifyNoMoreInteractions(this.sessions); - } - - @Test - void getSessionExpired() { - verify(this.sessions, times(1)).addEntryListener(any(MapListener.class), anyBoolean()); - - MapSession expired = new MapSession(); - expired.setLastAccessedTime(Instant.now().minusSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS + 1)); - given(this.sessions.get(eq(expired.getId()))).willReturn(expired); - - HazelcastSession session = this.repository.findById(expired.getId()); - - assertThat(session).isNull(); - verify(this.sessions, times(1)).get(eq(expired.getId())); - verify(this.sessions, times(1)).remove(eq(expired.getId())); - verifyNoMoreInteractions(this.sessions); - } - - @Test - void getSessionFound() { - verify(this.sessions, times(1)).addEntryListener(any(MapListener.class), anyBoolean()); - - MapSession saved = new MapSession(); - saved.setAttribute("savedName", "savedValue"); - given(this.sessions.get(eq(saved.getId()))).willReturn(saved); - - HazelcastSession session = this.repository.findById(saved.getId()); - - assertThat(session.getId()).isEqualTo(saved.getId()); - assertThat(session.getAttribute("savedName")).isEqualTo("savedValue"); - verify(this.sessions, times(1)).get(eq(saved.getId())); - verifyNoMoreInteractions(this.sessions); - } - - @Test - void delete() { - verify(this.sessions, times(1)).addEntryListener(any(MapListener.class), anyBoolean()); - - String sessionId = "testSessionId"; - - this.repository.deleteById(sessionId); - - verify(this.sessions, times(1)).remove(eq(sessionId)); - verifyNoMoreInteractions(this.sessions); - } - - @Test - void findByIndexNameAndIndexValueUnknownIndexName() { - verify(this.sessions, times(1)).addEntryListener(any(MapListener.class), anyBoolean()); - - String indexValue = "testIndexValue"; - - Map sessions = this.repository.findByIndexNameAndIndexValue("testIndexName", - indexValue); - - assertThat(sessions).isEmpty(); - verifyNoMoreInteractions(this.sessions); - } - - @Test - void findByIndexNameAndIndexValuePrincipalIndexNameNotFound() { - verify(this.sessions, times(1)).addEntryListener(any(MapListener.class), anyBoolean()); - - String principal = "username"; - - Map sessions = this.repository - .findByIndexNameAndIndexValue(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, principal); - - assertThat(sessions).isEmpty(); - verify(this.sessions, times(1)).values(isA(EqualPredicate.class)); - verifyNoMoreInteractions(this.sessions); - } - - @Test - void findByIndexNameAndIndexValuePrincipalIndexNameFound() { - verify(this.sessions, times(1)).addEntryListener(any(MapListener.class), anyBoolean()); - - String principal = "username"; - Authentication authentication = new UsernamePasswordAuthenticationToken(principal, "notused", - AuthorityUtils.createAuthorityList("ROLE_USER")); - List saved = new ArrayList<>(2); - MapSession saved1 = new MapSession(); - saved1.setAttribute(SPRING_SECURITY_CONTEXT, authentication); - saved.add(saved1); - MapSession saved2 = new MapSession(); - saved2.setAttribute(SPRING_SECURITY_CONTEXT, authentication); - saved.add(saved2); - given(this.sessions.values(isA(EqualPredicate.class))).willReturn(saved); - - Map sessions = this.repository - .findByIndexNameAndIndexValue(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, principal); - - assertThat(sessions).hasSize(2); - verify(this.sessions, times(1)).values(isA(EqualPredicate.class)); - verifyNoMoreInteractions(this.sessions); - } - - @Test // gh-1120 - void getAttributeNamesAndRemove() { - HazelcastSession session = this.repository.createSession(); - session.setAttribute("attribute1", "value1"); - session.setAttribute("attribute2", "value2"); - - for (String attributeName : session.getAttributeNames()) { - session.removeAttribute(attributeName); - } - - assertThat(session.getAttributeNames()).isEmpty(); - } - - @Test - @SuppressWarnings("unchecked") - void saveWithSaveModeOnSetAttribute() { - verify(this.sessions).addEntryListener(any(MapListener.class), anyBoolean()); - this.repository.setSaveMode(SaveMode.ON_SET_ATTRIBUTE); - MapSession delegate = new MapSession(); - delegate.setAttribute("attribute1", "value1"); - delegate.setAttribute("attribute2", "value2"); - delegate.setAttribute("attribute3", "value3"); - HazelcastSession session = this.repository.new HazelcastSession(delegate, false); - session.getAttribute("attribute2"); - session.setAttribute("attribute3", "value4"); - this.repository.save(session); - ArgumentCaptor captor = ArgumentCaptor - .forClass(Hazelcast4SessionUpdateEntryProcessor.class); - verify(this.sessions).executeOnKey(eq(session.getId()), captor.capture()); - assertThat((Map) ReflectionTestUtils.getField(captor.getValue(), "delta")).hasSize(1); - verifyNoMoreInteractions(this.sessions); - } - - @Test - @SuppressWarnings("unchecked") - void saveWithSaveModeOnGetAttribute() { - verify(this.sessions).addEntryListener(any(MapListener.class), anyBoolean()); - this.repository.setSaveMode(SaveMode.ON_GET_ATTRIBUTE); - MapSession delegate = new MapSession(); - delegate.setAttribute("attribute1", "value1"); - delegate.setAttribute("attribute2", "value2"); - delegate.setAttribute("attribute3", "value3"); - HazelcastSession session = this.repository.new HazelcastSession(delegate, false); - session.getAttribute("attribute2"); - session.setAttribute("attribute3", "value4"); - this.repository.save(session); - ArgumentCaptor captor = ArgumentCaptor - .forClass(Hazelcast4SessionUpdateEntryProcessor.class); - verify(this.sessions).executeOnKey(eq(session.getId()), captor.capture()); - assertThat((Map) ReflectionTestUtils.getField(captor.getValue(), "delta")).hasSize(2); - verifyNoMoreInteractions(this.sessions); - } - - @Test - @SuppressWarnings("unchecked") - void saveWithSaveModeAlways() { - verify(this.sessions).addEntryListener(any(MapListener.class), anyBoolean()); - this.repository.setSaveMode(SaveMode.ALWAYS); - MapSession delegate = new MapSession(); - delegate.setAttribute("attribute1", "value1"); - delegate.setAttribute("attribute2", "value2"); - delegate.setAttribute("attribute3", "value3"); - HazelcastSession session = this.repository.new HazelcastSession(delegate, false); - session.getAttribute("attribute2"); - session.setAttribute("attribute3", "value4"); - this.repository.save(session); - ArgumentCaptor captor = ArgumentCaptor - .forClass(Hazelcast4SessionUpdateEntryProcessor.class); - verify(this.sessions).executeOnKey(eq(session.getId()), captor.capture()); - assertThat((Map) ReflectionTestUtils.getField(captor.getValue(), "delta")).hasSize(3); - verifyNoMoreInteractions(this.sessions); - } - -} diff --git a/spring-session-hazelcast/spring-session-hazelcast.gradle b/spring-session-hazelcast/spring-session-hazelcast.gradle index b7cd931f..787465ac 100644 --- a/spring-session-hazelcast/spring-session-hazelcast.gradle +++ b/spring-session-hazelcast/spring-session-hazelcast.gradle @@ -1,18 +1,11 @@ apply plugin: 'io.spring.convention.spring-module' -configurations { - hazelcast4 -} - dependencies { api project(':spring-session-core') api "com.hazelcast:hazelcast" api "jakarta.annotation:jakarta.annotation-api" api "org.springframework:spring-context" - hazelcast4(project(path: ":hazelcast4", configuration: 'classesOnlyElements')) - compileOnly(project(":hazelcast4")) - testImplementation "jakarta.servlet:jakarta.servlet-api" testImplementation "org.assertj:assertj-core" testImplementation "org.mockito:mockito-core" @@ -20,13 +13,7 @@ dependencies { testImplementation "org.springframework:spring-web" testImplementation "org.springframework.security:spring-security-core" testImplementation "org.junit.jupiter:junit-jupiter-api" - testRuntimeOnly project(':hazelcast4') testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine" - integrationTestCompile "com.hazelcast:hazelcast-client" integrationTestCompile "org.testcontainers:testcontainers" } - -jar { - from configurations.hazelcast4 -} diff --git a/spring-session-hazelcast/src/integration-test/java/org/springframework/session/hazelcast/AbstractHazelcastIndexedSessionRepositoryITests.java b/spring-session-hazelcast/src/integration-test/java/org/springframework/session/hazelcast/AbstractHazelcastIndexedSessionRepositoryITests.java index be313420..668f1b42 100644 --- a/spring-session-hazelcast/src/integration-test/java/org/springframework/session/hazelcast/AbstractHazelcastIndexedSessionRepositoryITests.java +++ b/spring-session-hazelcast/src/integration-test/java/org/springframework/session/hazelcast/AbstractHazelcastIndexedSessionRepositoryITests.java @@ -16,9 +16,12 @@ package org.springframework.session.hazelcast; +import java.time.Duration; +import java.time.Instant; + import com.hazelcast.core.HazelcastInstance; -import com.hazelcast.core.IMap; -import com.hazelcast.instance.HazelcastInstanceProxy; +import com.hazelcast.instance.impl.HazelcastInstanceProxy; +import com.hazelcast.map.IMap; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; @@ -225,4 +228,51 @@ abstract class AbstractHazelcastIndexedSessionRepositoryITests { this.repository.deleteById(session.getId()); } + @Test + void createAndUpdateSessionWhileKeepingOriginalTimeToLiveConfiguredOnRepository() { + final Duration defaultSessionTimeout = Duration.ofSeconds(1800); + + final IMap hazelcastMap = this.hazelcastInstance + .getMap(HazelcastIndexedSessionRepository.DEFAULT_SESSION_MAP_NAME); + + HazelcastSession session = this.repository.createSession(); + String sessionId = session.getId(); + this.repository.save(session); + + assertThat(session.getMaxInactiveInterval()).isEqualTo(defaultSessionTimeout); + assertThat(hazelcastMap.getEntryView(sessionId).getTtl()).isEqualTo(defaultSessionTimeout.toMillis()); + + session = this.repository.findById(sessionId); + session.setLastAccessedTime(Instant.now()); + this.repository.save(session); + + session = this.repository.findById(sessionId); + assertThat(session.getMaxInactiveInterval()).isEqualTo(defaultSessionTimeout); + assertThat(hazelcastMap.getEntryView(sessionId).getTtl()).isEqualTo(defaultSessionTimeout.toMillis()); + } + + @Test + void createAndUpdateSessionWhileKeepingTimeToLiveSetOnSession() { + final Duration individualSessionTimeout = Duration.ofSeconds(23); + + final IMap hazelcastMap = this.hazelcastInstance + .getMap(HazelcastIndexedSessionRepository.DEFAULT_SESSION_MAP_NAME); + + HazelcastSession session = this.repository.createSession(); + session.setMaxInactiveInterval(individualSessionTimeout); + String sessionId = session.getId(); + this.repository.save(session); + + assertThat(session.getMaxInactiveInterval()).isEqualTo(individualSessionTimeout); + assertThat(hazelcastMap.getEntryView(sessionId).getTtl()).isEqualTo(individualSessionTimeout.toMillis()); + + session = this.repository.findById(sessionId); + session.setAttribute("attribute", "value"); + this.repository.save(session); + + session = this.repository.findById(sessionId); + assertThat(session.getMaxInactiveInterval()).isEqualTo(individualSessionTimeout); + assertThat(hazelcastMap.getEntryView(sessionId).getTtl()).isEqualTo(individualSessionTimeout.toMillis()); + } + } diff --git a/spring-session-hazelcast/src/integration-test/java/org/springframework/session/hazelcast/ClientServerHazelcastIndexedSessionRepositoryITests.java b/spring-session-hazelcast/src/integration-test/java/org/springframework/session/hazelcast/ClientServerHazelcastIndexedSessionRepositoryITests.java index 94fc3626..008ab58a 100644 --- a/spring-session-hazelcast/src/integration-test/java/org/springframework/session/hazelcast/ClientServerHazelcastIndexedSessionRepositoryITests.java +++ b/spring-session-hazelcast/src/integration-test/java/org/springframework/session/hazelcast/ClientServerHazelcastIndexedSessionRepositoryITests.java @@ -46,7 +46,7 @@ import org.springframework.test.context.web.WebAppConfiguration; @WebAppConfiguration class ClientServerHazelcastIndexedSessionRepositoryITests extends AbstractHazelcastIndexedSessionRepositoryITests { - private static GenericContainer container = new GenericContainer<>("hazelcast/hazelcast:3.12.12") + private static GenericContainer container = new GenericContainer<>("hazelcast/hazelcast:4.2.2") .withExposedPorts(5701).withCopyFileToContainer(MountableFile.forClasspathResource("/hazelcast-server.xml"), "/opt/hazelcast/hazelcast.xml"); diff --git a/spring-session-hazelcast/src/integration-test/java/org/springframework/session/hazelcast/HazelcastITestUtils.java b/spring-session-hazelcast/src/integration-test/java/org/springframework/session/hazelcast/HazelcastITestUtils.java index 76158a0d..e3144dfb 100644 --- a/spring-session-hazelcast/src/integration-test/java/org/springframework/session/hazelcast/HazelcastITestUtils.java +++ b/spring-session-hazelcast/src/integration-test/java/org/springframework/session/hazelcast/HazelcastITestUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2019 the original author or authors. + * Copyright 2014-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,9 +16,10 @@ package org.springframework.session.hazelcast; +import com.hazelcast.config.AttributeConfig; import com.hazelcast.config.Config; -import com.hazelcast.config.MapAttributeConfig; -import com.hazelcast.config.MapIndexConfig; +import com.hazelcast.config.IndexConfig; +import com.hazelcast.config.IndexType; import com.hazelcast.config.NetworkConfig; import com.hazelcast.config.SerializerConfig; import com.hazelcast.core.Hazelcast; @@ -45,12 +46,12 @@ final class HazelcastITestUtils { NetworkConfig networkConfig = config.getNetworkConfig(); networkConfig.setPort(0); networkConfig.getJoin().getMulticastConfig().setEnabled(false); - MapAttributeConfig attributeConfig = new MapAttributeConfig() + AttributeConfig attributeConfig = new AttributeConfig() .setName(HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE) - .setExtractor(PrincipalNameExtractor.class.getName()); + .setExtractorClassName(PrincipalNameExtractor.class.getName()); config.getMapConfig(HazelcastIndexedSessionRepository.DEFAULT_SESSION_MAP_NAME) - .addMapAttributeConfig(attributeConfig).addMapIndexConfig( - new MapIndexConfig(HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE, false)); + .addAttributeConfig(attributeConfig).addIndexConfig( + new IndexConfig(IndexType.HASH, HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE)); SerializerConfig serializerConfig = new SerializerConfig(); serializerConfig.setImplementation(new HazelcastSessionSerializer()).setTypeClass(MapSession.class); config.getSerializationConfig().addSerializerConfig(serializerConfig); diff --git a/spring-session-hazelcast/src/integration-test/resources/hazelcast-server.xml b/spring-session-hazelcast/src/integration-test/resources/hazelcast-server.xml index 3c16584c..394eaf8d 100644 --- a/spring-session-hazelcast/src/integration-test/resources/hazelcast-server.xml +++ b/spring-session-hazelcast/src/integration-test/resources/hazelcast-server.xml @@ -1,7 +1,7 @@ + xsi:schemaLocation="http://www.hazelcast.com/schema/config https://www.hazelcast.com/schema/config/hazelcast-config-4.2.xsd"> diff --git a/spring-session-hazelcast/src/main/java/org/springframework/session/hazelcast/HazelcastIndexedSessionRepository.java b/spring-session-hazelcast/src/main/java/org/springframework/session/hazelcast/HazelcastIndexedSessionRepository.java index b19e6f6c..7024bc31 100644 --- a/spring-session-hazelcast/src/main/java/org/springframework/session/hazelcast/HazelcastIndexedSessionRepository.java +++ b/spring-session-hazelcast/src/main/java/org/springframework/session/hazelcast/HazelcastIndexedSessionRepository.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2019 the original author or authors. + * Copyright 2014-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; +import java.util.UUID; import java.util.concurrent.TimeUnit; import jakarta.annotation.PostConstruct; @@ -30,9 +31,10 @@ import jakarta.annotation.PreDestroy; import com.hazelcast.core.EntryEvent; import com.hazelcast.core.HazelcastInstance; -import com.hazelcast.core.IMap; +import com.hazelcast.map.IMap; import com.hazelcast.map.listener.EntryAddedListener; import com.hazelcast.map.listener.EntryEvictedListener; +import com.hazelcast.map.listener.EntryExpiredListener; import com.hazelcast.map.listener.EntryRemovedListener; import com.hazelcast.query.Predicates; import org.apache.commons.logging.Log; @@ -52,7 +54,6 @@ import org.springframework.session.events.SessionCreatedEvent; import org.springframework.session.events.SessionDeletedEvent; import org.springframework.session.events.SessionExpiredEvent; import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; /** * A {@link org.springframework.session.SessionRepository} implementation that stores @@ -80,16 +81,17 @@ import org.springframework.util.ClassUtils; * programmatic Hazelcast Configuration: * *
- * MapAttributeConfig attributeConfig = new MapAttributeConfig()
+ * AttributeConfig attributeConfig = new AttributeConfig()
  *         .setName(HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE)
- *         .setExtractor(PrincipalNameExtractor.class.getName());
+ *         .setExtractorClassName(rincipalNameExtractor.class.getName());
  *
  * Config config = new Config();
  *
  * config.getMapConfig(HazelcastIndexedSessionRepository.DEFAULT_SESSION_MAP_NAME)
- *         .addMapAttributeConfig(attributeConfig)
- *         .addMapIndexConfig(new MapIndexConfig(
- *                 HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE, false));
+ *         .addAttributeConfig(attributeConfig)
+ *         .addIndexConfig(new IndexConfig(
+ *                 IndexType.HASH,
+ *                 HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE));
  *
  * Hazelcast.newHazelcastInstance(config);
  * 
@@ -108,12 +110,13 @@ import org.springframework.util.ClassUtils; * @author Tommy Ludwig * @author Mark Anderson * @author Aleksandar Stojsavljevic + * @author Eleftheria Stein * @since 2.2.0 */ public class HazelcastIndexedSessionRepository implements FindByIndexNameSessionRepository, EntryAddedListener, EntryEvictedListener, - EntryRemovedListener { + EntryRemovedListener, EntryExpiredListener { /** * The default name of map used by Spring Session to store sessions. @@ -127,8 +130,6 @@ public class HazelcastIndexedSessionRepository 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(HazelcastIndexedSessionRepository.class); private final HazelcastInstance hazelcastInstance; @@ -152,7 +153,7 @@ public class HazelcastIndexedSessionRepository private IMap sessions; - private String sessionListenerId; + private UUID sessionListenerId; /** * Create a new {@link HazelcastIndexedSessionRepository} instance. @@ -261,9 +262,6 @@ public class HazelcastIndexedSessionRepository entryProcessor.setLastAccessedTime(session.getLastAccessedTime()); } if (session.maxInactiveIntervalChanged) { - if (SUPPORTS_SET_TTL) { - updateTtl(session); - } entryProcessor.setMaxInactiveInterval(session.getMaxInactiveInterval()); } if (!session.delta.isEmpty()) { @@ -274,10 +272,6 @@ public class HazelcastIndexedSessionRepository session.clearChangeFlags(); } - private void updateTtl(HazelcastSession session) { - this.sessions.setTtl(session.getId(), session.getMaxInactiveInterval().getSeconds(), TimeUnit.SECONDS); - } - @Override public HazelcastSession findById(String id) { MapSession saved = this.sessions.get(id); @@ -339,6 +333,14 @@ public class HazelcastIndexedSessionRepository } } + @Override + public void entryExpired(EntryEvent event) { + if (logger.isDebugEnabled()) { + logger.debug("Session expired with id: " + event.getOldValue().getId()); + } + this.eventPublisher.publishEvent(new SessionExpiredEvent(this, event.getOldValue())); + } + /** * A custom implementation of {@link Session} that uses a {@link MapSession} as the * basis for its mapping. It keeps track if changes have been made since last save. diff --git a/spring-session-hazelcast/src/main/java/org/springframework/session/hazelcast/HazelcastSessionSerializer.java b/spring-session-hazelcast/src/main/java/org/springframework/session/hazelcast/HazelcastSessionSerializer.java index d88df92b..238d3dbb 100644 --- a/spring-session-hazelcast/src/main/java/org/springframework/session/hazelcast/HazelcastSessionSerializer.java +++ b/spring-session-hazelcast/src/main/java/org/springframework/session/hazelcast/HazelcastSessionSerializer.java @@ -29,7 +29,7 @@ import org.springframework.session.MapSession; /** * A {@link com.hazelcast.nio.serialization.Serializer} implementation that handles the - * (de)serialization of {@link MapSession} stored on {@link com.hazelcast.core.IMap}. + * (de)serialization of {@link MapSession} stored on {@link com.hazelcast.map.IMap}. * *

* The use of this serializer is optional and provides faster serialization of sessions. diff --git a/spring-session-hazelcast/src/main/java/org/springframework/session/hazelcast/PrincipalNameExtractor.java b/spring-session-hazelcast/src/main/java/org/springframework/session/hazelcast/PrincipalNameExtractor.java index 6de56c6c..b7ee1ade 100644 --- a/spring-session-hazelcast/src/main/java/org/springframework/session/hazelcast/PrincipalNameExtractor.java +++ b/spring-session-hazelcast/src/main/java/org/springframework/session/hazelcast/PrincipalNameExtractor.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2019 the original author or authors. + * Copyright 2014-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,7 +29,7 @@ import org.springframework.session.MapSession; * @author Vedran Pavic * @since 1.3.0 */ -public class PrincipalNameExtractor extends ValueExtractor { +public class PrincipalNameExtractor implements ValueExtractor { @Override @SuppressWarnings("unchecked") diff --git a/spring-session-hazelcast/src/main/java/org/springframework/session/hazelcast/SessionUpdateEntryProcessor.java b/spring-session-hazelcast/src/main/java/org/springframework/session/hazelcast/SessionUpdateEntryProcessor.java index 9d0f0e3e..be0a45cf 100644 --- a/spring-session-hazelcast/src/main/java/org/springframework/session/hazelcast/SessionUpdateEntryProcessor.java +++ b/spring-session-hazelcast/src/main/java/org/springframework/session/hazelcast/SessionUpdateEntryProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2019 the original author or authors. + * Copyright 2014-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,22 +19,21 @@ package org.springframework.session.hazelcast; import java.time.Duration; import java.time.Instant; import java.util.Map; +import java.util.concurrent.TimeUnit; -import com.hazelcast.core.Offloadable; -import com.hazelcast.map.AbstractEntryProcessor; import com.hazelcast.map.EntryProcessor; +import com.hazelcast.map.ExtendedMapEntry; import org.springframework.session.MapSession; -import org.springframework.session.hazelcast.HazelcastIndexedSessionRepository.HazelcastSession; /** * Hazelcast {@link EntryProcessor} responsible for handling updates to session. * * @author Vedran Pavic + * @author Eleftheria Stein * @since 1.3.4 - * @see HazelcastIndexedSessionRepository#save(HazelcastSession) */ -public class SessionUpdateEntryProcessor extends AbstractEntryProcessor implements Offloadable { +public class SessionUpdateEntryProcessor implements EntryProcessor { private Instant lastAccessedTime; @@ -64,15 +63,11 @@ public class SessionUpdateEntryProcessor extends AbstractEntryProcessor) entry).setValue(value, value.getMaxInactiveInterval().getSeconds(), + TimeUnit.SECONDS); return Boolean.TRUE; } - @Override - public String getExecutorName() { - return OFFLOADABLE_EXECUTOR; - } - void setLastAccessedTime(Instant lastAccessedTime) { this.lastAccessedTime = lastAccessedTime; } diff --git a/spring-session-hazelcast/src/main/java/org/springframework/session/hazelcast/config/annotation/web/http/HazelcastHttpSessionConfiguration.java b/spring-session-hazelcast/src/main/java/org/springframework/session/hazelcast/config/annotation/web/http/HazelcastHttpSessionConfiguration.java index 5721d6e6..2fc75598 100644 --- a/spring-session-hazelcast/src/main/java/org/springframework/session/hazelcast/config/annotation/web/http/HazelcastHttpSessionConfiguration.java +++ b/spring-session-hazelcast/src/main/java/org/springframework/session/hazelcast/config/annotation/web/http/HazelcastHttpSessionConfiguration.java @@ -38,12 +38,10 @@ import org.springframework.session.SaveMode; import org.springframework.session.Session; import org.springframework.session.config.SessionRepositoryCustomizer; import org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration; -import org.springframework.session.hazelcast.Hazelcast4IndexedSessionRepository; import org.springframework.session.hazelcast.HazelcastFlushMode; import org.springframework.session.hazelcast.HazelcastIndexedSessionRepository; import org.springframework.session.hazelcast.config.annotation.SpringSessionHazelcastInstance; import org.springframework.session.web.http.SessionRepositoryFilter; -import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; /** @@ -75,23 +73,9 @@ public class HazelcastHttpSessionConfiguration extends SpringHttpSessionConfigur private List> sessionRepositoryCustomizers; - private List> hazelcast4SessionRepositoryCustomizers; - - private static final boolean hazelcast4; - - static { - ClassLoader classLoader = HazelcastHttpSessionConfiguration.class.getClassLoader(); - hazelcast4 = ClassUtils.isPresent("com.hazelcast.map.IMap", classLoader); - } - @Bean public FindByIndexNameSessionRepository sessionRepository() { - if (hazelcast4) { - return createHazelcast4IndexedSessionRepository(); - } - else { - return createHazelcastIndexedSessionRepository(); - } + return createHazelcastIndexedSessionRepository(); } public void setMaxInactiveIntervalInSeconds(int maxInactiveIntervalInSeconds) { @@ -142,13 +126,6 @@ public class HazelcastHttpSessionConfiguration extends SpringHttpSessionConfigur this.sessionRepositoryCustomizers = sessionRepositoryCustomizers.orderedStream().collect(Collectors.toList()); } - @Autowired(required = false) - public void setHazelcast4SessionRepositoryCustomizer( - ObjectProvider> sessionRepositoryCustomizers) { - this.hazelcast4SessionRepositoryCustomizers = sessionRepositoryCustomizers.orderedStream() - .collect(Collectors.toList()); - } - @Override @SuppressWarnings("deprecation") public void setImportMetadata(AnnotationMetadata importMetadata) { @@ -187,22 +164,4 @@ public class HazelcastHttpSessionConfiguration extends SpringHttpSessionConfigur return sessionRepository; } - private Hazelcast4IndexedSessionRepository createHazelcast4IndexedSessionRepository() { - Hazelcast4IndexedSessionRepository sessionRepository = new Hazelcast4IndexedSessionRepository( - this.hazelcastInstance); - sessionRepository.setApplicationEventPublisher(this.applicationEventPublisher); - if (this.indexResolver != null) { - sessionRepository.setIndexResolver(this.indexResolver); - } - if (StringUtils.hasText(this.sessionMapName)) { - sessionRepository.setSessionMapName(this.sessionMapName); - } - sessionRepository.setDefaultMaxInactiveInterval(this.maxInactiveIntervalInSeconds); - sessionRepository.setFlushMode(this.flushMode); - sessionRepository.setSaveMode(this.saveMode); - this.hazelcast4SessionRepositoryCustomizers - .forEach((sessionRepositoryCustomizer) -> sessionRepositoryCustomizer.customize(sessionRepository)); - return sessionRepository; - } - } diff --git a/spring-session-hazelcast/src/test/java/org/springframework/session/hazelcast/HazelcastIndexedSessionRepositoryTests.java b/spring-session-hazelcast/src/test/java/org/springframework/session/hazelcast/HazelcastIndexedSessionRepositoryTests.java index 2441647b..c8ef7006 100644 --- a/spring-session-hazelcast/src/test/java/org/springframework/session/hazelcast/HazelcastIndexedSessionRepositoryTests.java +++ b/spring-session-hazelcast/src/test/java/org/springframework/session/hazelcast/HazelcastIndexedSessionRepositoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2019 the original author or authors. + * Copyright 2014-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,8 +24,8 @@ import java.util.Map; import java.util.concurrent.TimeUnit; import com.hazelcast.core.HazelcastInstance; -import com.hazelcast.core.IMap; import com.hazelcast.map.EntryProcessor; +import com.hazelcast.map.IMap; import com.hazelcast.map.listener.MapListener; import com.hazelcast.query.impl.predicates.EqualPredicate; import org.junit.jupiter.api.BeforeEach; @@ -46,7 +46,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isA; @@ -255,7 +254,6 @@ class HazelcastIndexedSessionRepositoryTests { session.setMaxInactiveInterval(Duration.ofSeconds(1)); verify(this.sessions, times(1)).set(eq(sessionId), eq(session.getDelegate()), isA(Long.class), eq(TimeUnit.SECONDS)); - verify(this.sessions).setTtl(eq(sessionId), anyLong(), any()); verify(this.sessions, times(1)).executeOnKey(eq(sessionId), any(EntryProcessor.class)); this.repository.save(session); diff --git a/spring-session-hazelcast/src/test/java/org/springframework/session/hazelcast/HazelcastSessionSerializerTests.java b/spring-session-hazelcast/src/test/java/org/springframework/session/hazelcast/HazelcastSessionSerializerTests.java deleted file mode 100644 index b79a3bf1..00000000 --- a/spring-session-hazelcast/src/test/java/org/springframework/session/hazelcast/HazelcastSessionSerializerTests.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2014-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.session.hazelcast; - -import java.io.Serializable; -import java.time.Duration; -import java.time.Instant; - -import com.hazelcast.config.SerializationConfig; -import com.hazelcast.config.SerializerConfig; -import com.hazelcast.internal.serialization.impl.DefaultSerializationServiceBuilder; -import com.hazelcast.nio.serialization.Data; -import com.hazelcast.spi.serialization.SerializationService; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.session.MapSession; - -import static org.assertj.core.api.Assertions.assertThat; - -class HazelcastSessionSerializerTests { - - private SerializationService serializationService; - - @BeforeEach - void setUp() { - SerializationConfig serializationConfig = new SerializationConfig(); - SerializerConfig serializerConfig = new SerializerConfig().setImplementation(new HazelcastSessionSerializer()) - .setTypeClass(MapSession.class); - serializationConfig.addSerializerConfig(serializerConfig); - this.serializationService = new DefaultSerializationServiceBuilder().setConfig(serializationConfig).build(); - } - - @Test - void serializeSessionWithStreamSerializer() { - MapSession originalSession = new MapSession(); - originalSession.setAttribute("attr1", "value1"); - originalSession.setAttribute("attr2", "value2"); - originalSession.setAttribute("attr3", new SerializableTestAttribute(3)); - originalSession.setMaxInactiveInterval(Duration.ofDays(5)); - originalSession.setLastAccessedTime(Instant.now()); - originalSession.setId("custom-id"); - - Data serialized = this.serializationService.toData(originalSession); - MapSession cached = this.serializationService.toObject(serialized); - - assertThat(originalSession.getCreationTime()).isEqualTo(cached.getCreationTime()); - assertThat(originalSession.getMaxInactiveInterval()).isEqualTo(cached.getMaxInactiveInterval()); - assertThat(originalSession.getId()).isEqualTo(cached.getId()); - assertThat(originalSession.getOriginalId()).isEqualTo(cached.getOriginalId()); - assertThat(originalSession.getAttributeNames().size()).isEqualTo(cached.getAttributeNames().size()); - assertThat(originalSession.getAttribute("attr1")).isEqualTo(cached.getAttribute("attr1")); - assertThat(originalSession.getAttribute("attr2")).isEqualTo(cached.getAttribute("attr2")); - assertThat(originalSession.getAttribute("attr3")) - .isEqualTo(cached.getAttribute("attr3")); - } - - static class SerializableTestAttribute implements Serializable { - - private int id; - - SerializableTestAttribute(int id) { - this.id = id; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof SerializableTestAttribute)) { - return false; - } - SerializableTestAttribute that = (SerializableTestAttribute) o; - return this.id == that.id; - } - - @Override - public int hashCode() { - return this.id; - } - - } - -} diff --git a/spring-session-hazelcast/hazelcast4/src/test/java/org/springframework/session/hazelcast/Hazelcast4SessionUpdateEntryProcessorTest.java b/spring-session-hazelcast/src/test/java/org/springframework/session/hazelcast/SessionUpdateEntryProcessorTest.java similarity index 96% rename from spring-session-hazelcast/hazelcast4/src/test/java/org/springframework/session/hazelcast/Hazelcast4SessionUpdateEntryProcessorTest.java rename to spring-session-hazelcast/src/test/java/org/springframework/session/hazelcast/SessionUpdateEntryProcessorTest.java index eec0b19b..72e811e1 100644 --- a/spring-session-hazelcast/hazelcast4/src/test/java/org/springframework/session/hazelcast/Hazelcast4SessionUpdateEntryProcessorTest.java +++ b/spring-session-hazelcast/src/test/java/org/springframework/session/hazelcast/SessionUpdateEntryProcessorTest.java @@ -32,13 +32,13 @@ import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -class Hazelcast4SessionUpdateEntryProcessorTest { +class SessionUpdateEntryProcessorTest { - private Hazelcast4SessionUpdateEntryProcessor processor; + private SessionUpdateEntryProcessor processor; @BeforeEach void setUp() { - this.processor = new Hazelcast4SessionUpdateEntryProcessor(); + this.processor = new SessionUpdateEntryProcessor(); } @Test diff --git a/spring-session-hazelcast/src/test/java/org/springframework/session/hazelcast/config/annotation/web/http/HazelcastHttpSessionConfigurationTests.java b/spring-session-hazelcast/src/test/java/org/springframework/session/hazelcast/config/annotation/web/http/HazelcastHttpSessionConfigurationTests.java index eb0db925..4d14fc6b 100644 --- a/spring-session-hazelcast/src/test/java/org/springframework/session/hazelcast/config/annotation/web/http/HazelcastHttpSessionConfigurationTests.java +++ b/spring-session-hazelcast/src/test/java/org/springframework/session/hazelcast/config/annotation/web/http/HazelcastHttpSessionConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2019 the original author or authors. + * Copyright 2014-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ package org.springframework.session.hazelcast.config.annotation.web.http; import com.hazelcast.core.HazelcastInstance; -import com.hazelcast.core.IMap; +import com.hazelcast.map.IMap; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; diff --git a/spring-session-samples/spring-session-sample-boot-hazelcast/src/main/java/sample/config/SessionConfig.java b/spring-session-samples/spring-session-sample-boot-hazelcast/src/main/java/sample/config/SessionConfig.java index c54ad16c..e7589c7d 100644 --- a/spring-session-samples/spring-session-sample-boot-hazelcast/src/main/java/sample/config/SessionConfig.java +++ b/spring-session-samples/spring-session-sample-boot-hazelcast/src/main/java/sample/config/SessionConfig.java @@ -16,9 +16,10 @@ package sample.config; +import com.hazelcast.config.AttributeConfig; import com.hazelcast.config.Config; -import com.hazelcast.config.MapAttributeConfig; -import com.hazelcast.config.MapIndexConfig; +import com.hazelcast.config.IndexConfig; +import com.hazelcast.config.IndexType; import com.hazelcast.config.NetworkConfig; import com.hazelcast.config.SerializerConfig; @@ -39,12 +40,12 @@ public class SessionConfig { NetworkConfig networkConfig = config.getNetworkConfig(); networkConfig.setPort(0); networkConfig.getJoin().getMulticastConfig().setEnabled(false); - MapAttributeConfig attributeConfig = new MapAttributeConfig() + AttributeConfig attributeConfig = new AttributeConfig() .setName(HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE) - .setExtractor(PrincipalNameExtractor.class.getName()); + .setExtractorClassName(PrincipalNameExtractor.class.getName()); config.getMapConfig(HazelcastIndexedSessionRepository.DEFAULT_SESSION_MAP_NAME) - .addMapAttributeConfig(attributeConfig).addMapIndexConfig( - new MapIndexConfig(HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE, false)); + .addAttributeConfig(attributeConfig).addIndexConfig( + new IndexConfig(IndexType.HASH, HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE)); SerializerConfig serializerConfig = new SerializerConfig(); serializerConfig.setImplementation(new HazelcastSessionSerializer()).setTypeClass(MapSession.class); config.getSerializationConfig().addSerializerConfig(serializerConfig); diff --git a/spring-session-samples/spring-session-sample-boot-hazelcast4/spring-session-sample-boot-hazelcast4.gradle b/spring-session-samples/spring-session-sample-boot-hazelcast4/spring-session-sample-boot-hazelcast4.gradle deleted file mode 100644 index 69e068c9..00000000 --- a/spring-session-samples/spring-session-sample-boot-hazelcast4/spring-session-sample-boot-hazelcast4.gradle +++ /dev/null @@ -1,21 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-boot' - -dependencies { - implementation project(':spring-session-hazelcast') - implementation project(':hazelcast4') - implementation "org.springframework.boot:spring-boot-starter-web" - implementation "org.springframework.boot:spring-boot-starter-actuator" - implementation "org.springframework.boot:spring-boot-starter-thymeleaf" - implementation "org.springframework.boot:spring-boot-starter-security" - implementation "com.hazelcast:hazelcast:4.2.2" - implementation "nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect" - implementation "org.webjars:bootstrap" - implementation "org.webjars:html5shiv" - implementation "org.webjars:webjars-locator-core" - - testImplementation "org.springframework.boot:spring-boot-starter-test" - testImplementation "org.junit.jupiter:junit-jupiter-api" - testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine" - integrationTestCompile "org.seleniumhq.selenium:htmlunit-driver" - integrationTestCompile "org.seleniumhq.selenium:selenium-support" -} diff --git a/spring-session-samples/spring-session-sample-boot-hazelcast4/src/integration-test/java/sample/BootTests.java b/spring-session-samples/spring-session-sample-boot-hazelcast4/src/integration-test/java/sample/BootTests.java deleted file mode 100644 index 4806a60a..00000000 --- a/spring-session-samples/spring-session-sample-boot-hazelcast4/src/integration-test/java/sample/BootTests.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2014-2021 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.openqa.selenium.WebDriver; -import sample.pages.HomePage; -import sample.pages.LoginPage; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.actuate.session.SessionsEndpoint; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.context.ApplicationContext; -import org.springframework.session.hazelcast.Hazelcast4IndexedSessionRepository; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder; - -import static org.assertj.core.api.Assertions.assertThat; - -@AutoConfigureMockMvc -@SpringBootTest(webEnvironment = WebEnvironment.MOCK) -class BootTests { - - @Autowired - private MockMvc mockMvc; - - private WebDriver driver; - - @BeforeEach - void setup() { - this.driver = MockMvcHtmlUnitDriverBuilder.mockMvcSetup(this.mockMvc).build(); - } - - @AfterEach - void tearDown() { - this.driver.quit(); - } - - @Test // gh-1905 - void contextLoads(ApplicationContext context) { - assertThat(context.getBeansOfType(Hazelcast4IndexedSessionRepository.class)).hasSize(1); - assertThat(context.getBeansOfType(SessionsEndpoint.class)).hasSize(1); - } - - @Test - void home() { - LoginPage login = HomePage.go(this.driver); - login.assertAt(); - } - - @Test - void login() { - LoginPage login = HomePage.go(this.driver); - HomePage home = login.form().login(HomePage.class); - home.assertAt(); - home.containCookie("SESSION"); - home.doesNotContainCookie("JSESSIONID"); - } - - @Test - void logout() { - LoginPage login = HomePage.go(this.driver); - HomePage home = login.form().login(HomePage.class); - home.logout(); - login.assertAt(); - } - -} diff --git a/spring-session-samples/spring-session-sample-boot-hazelcast4/src/integration-test/java/sample/pages/BasePage.java b/spring-session-samples/spring-session-sample-boot-hazelcast4/src/integration-test/java/sample/pages/BasePage.java deleted file mode 100644 index 4fe74ffa..00000000 --- a/spring-session-samples/spring-session-sample-boot-hazelcast4/src/integration-test/java/sample/pages/BasePage.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2014-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample.pages; - -import org.openqa.selenium.WebDriver; - -public class BasePage { - - private WebDriver driver; - - public BasePage(WebDriver driver) { - this.driver = driver; - } - - public WebDriver getDriver() { - return this.driver; - } - - public static void get(WebDriver driver, String get) { - String baseUrl = "http://localhost"; - driver.get(baseUrl + get); - } - -} diff --git a/spring-session-samples/spring-session-sample-boot-hazelcast4/src/integration-test/java/sample/pages/HomePage.java b/spring-session-samples/spring-session-sample-boot-hazelcast4/src/integration-test/java/sample/pages/HomePage.java deleted file mode 100644 index 3c520880..00000000 --- a/spring-session-samples/spring-session-sample-boot-hazelcast4/src/integration-test/java/sample/pages/HomePage.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2014-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample.pages; - -import java.util.Set; - -import org.openqa.selenium.By; -import org.openqa.selenium.Cookie; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.PageFactory; - -import static org.assertj.core.api.Assertions.assertThat; - -public class HomePage extends BasePage { - - public HomePage(WebDriver driver) { - super(driver); - } - - public static LoginPage go(WebDriver driver) { - get(driver, "/"); - return PageFactory.initElements(driver, LoginPage.class); - } - - public void assertAt() { - assertThat(getDriver().getTitle()).isEqualTo("Spring Session Sample - Secured Content"); - } - - public void containCookie(String cookieName) { - Set cookies = getDriver().manage().getCookies(); - assertThat(cookies).extracting("name").contains(cookieName); - } - - public void doesNotContainCookie(String cookieName) { - Set cookies = getDriver().manage().getCookies(); - assertThat(cookies).extracting("name").doesNotContain(cookieName); - } - - public HomePage logout() { - WebElement logout = getDriver().findElement(By.cssSelector("input[type=\"submit\"]")); - logout.click(); - return PageFactory.initElements(getDriver(), HomePage.class); - } - -} diff --git a/spring-session-samples/spring-session-sample-boot-hazelcast4/src/integration-test/java/sample/pages/LoginPage.java b/spring-session-samples/spring-session-sample-boot-hazelcast4/src/integration-test/java/sample/pages/LoginPage.java deleted file mode 100644 index 90f99a79..00000000 --- a/spring-session-samples/spring-session-sample-boot-hazelcast4/src/integration-test/java/sample/pages/LoginPage.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2014-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample.pages; - -import org.openqa.selenium.SearchContext; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.FindBy; -import org.openqa.selenium.support.PageFactory; -import org.openqa.selenium.support.pagefactory.DefaultElementLocatorFactory; - -import static org.assertj.core.api.Assertions.assertThat; - -public class LoginPage extends BasePage { - - public LoginPage(WebDriver driver) { - super(driver); - } - - public void assertAt() { - assertThat(getDriver().getTitle()).isEqualTo("Please sign in"); - } - - public Form form() { - return new Form(getDriver()); - } - - public class Form { - - @FindBy(name = "username") - private WebElement username; - - @FindBy(name = "password") - private WebElement password; - - @FindBy(tagName = "button") - private WebElement button; - - public Form(SearchContext context) { - PageFactory.initElements(new DefaultElementLocatorFactory(context), this); - } - - public T login(Class page) { - this.username.sendKeys("user"); - this.password.sendKeys("password"); - this.button.click(); - return PageFactory.initElements(getDriver(), page); - } - - } - -} diff --git a/spring-session-samples/spring-session-sample-boot-hazelcast4/src/integration-test/resources/testcontainers.properties b/spring-session-samples/spring-session-sample-boot-hazelcast4/src/integration-test/resources/testcontainers.properties deleted file mode 100644 index e3e83419..00000000 --- a/spring-session-samples/spring-session-sample-boot-hazelcast4/src/integration-test/resources/testcontainers.properties +++ /dev/null @@ -1 +0,0 @@ -ryuk.container.timeout=120 diff --git a/spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/java/sample/Application.java b/spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/java/sample/Application.java deleted file mode 100644 index e4ab62fa..00000000 --- a/spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/java/sample/Application.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2014-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cache.annotation.EnableCaching; - -@EnableCaching -@SpringBootApplication -public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } - -} diff --git a/spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/java/sample/config/IndexController.java b/spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/java/sample/config/IndexController.java deleted file mode 100644 index 2da7bead..00000000 --- a/spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/java/sample/config/IndexController.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2014-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample.config; - -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; - -@Controller -public class IndexController { - - @RequestMapping("/") - public String index() { - return "index"; - } - -} diff --git a/spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/java/sample/config/SecurityConfig.java b/spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/java/sample/config/SecurityConfig.java deleted file mode 100644 index 60a3cd4b..00000000 --- a/spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/java/sample/config/SecurityConfig.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2014-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample.config; - -import org.springframework.boot.autoconfigure.security.servlet.PathRequest; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; - -@Configuration -public class SecurityConfig extends WebSecurityConfigurerAdapter { - - // @formatter:off - // tag::config[] - @Override - protected void configure(HttpSecurity http) throws Exception { - http - .authorizeRequests((authorize) -> authorize - .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll() - .anyRequest().authenticated() - ) - .formLogin((formLogin) -> formLogin - .permitAll() - ); - } - // end::config[] - // @formatter:on - -} diff --git a/spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/java/sample/config/SessionConfig.java b/spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/java/sample/config/SessionConfig.java deleted file mode 100644 index 1e545e0a..00000000 --- a/spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/java/sample/config/SessionConfig.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2014-2021 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sample.config; - -import com.hazelcast.config.AttributeConfig; -import com.hazelcast.config.Config; -import com.hazelcast.config.IndexConfig; -import com.hazelcast.config.IndexType; -import com.hazelcast.config.NetworkConfig; -import com.hazelcast.config.SerializerConfig; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.session.MapSession; -import org.springframework.session.hazelcast.Hazelcast4IndexedSessionRepository; -import org.springframework.session.hazelcast.Hazelcast4PrincipalNameExtractor; -import org.springframework.session.hazelcast.HazelcastSessionSerializer; - -// tag::class[] -@Configuration -public class SessionConfig { - - @Bean - public Config hazelcastConfig() { - Config config = new Config(); - NetworkConfig networkConfig = config.getNetworkConfig(); - networkConfig.setPort(0); - networkConfig.getJoin().getMulticastConfig().setEnabled(false); - AttributeConfig attributeConfig = new AttributeConfig() - .setName(Hazelcast4IndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE) - .setExtractorClassName(Hazelcast4PrincipalNameExtractor.class.getName()); - config.getMapConfig(Hazelcast4IndexedSessionRepository.DEFAULT_SESSION_MAP_NAME) - .addAttributeConfig(attributeConfig).addIndexConfig( - new IndexConfig(IndexType.HASH, Hazelcast4IndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE)); - SerializerConfig serializerConfig = new SerializerConfig(); - serializerConfig.setImplementation(new HazelcastSessionSerializer()).setTypeClass(MapSession.class); - config.getSerializationConfig().addSerializerConfig(serializerConfig); - return config; - - } - -} -// end::class[] diff --git a/spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/resources/application.properties b/spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/resources/application.properties deleted file mode 100644 index cf1552e6..00000000 --- a/spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/resources/application.properties +++ /dev/null @@ -1,2 +0,0 @@ -management.endpoints.web.exposure.include=sessions -spring.security.user.password=password diff --git a/spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/resources/static/favicon.ico b/spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/resources/static/favicon.ico deleted file mode 100644 index bfb9974019d4b8b978cf34ea67f0c6804f9b76c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1150 zcmZQzU<5(|0R|wcz>vYhz#zuJz@P!dKp~(AL>x#lFaYI*xFHzK2NLHVUHb1iG2*{Y zgB?lOds5VYkY4wx3IDZQ-O0jkQ{(?@bp=p{C&v8O!h&CXe)}H=o_u_bRSig==8O!i zc=x^YFzx?WUq6CX4M?xX{1U9V`}7vL{^Em6v8n;-RbSqS702#f2-g1(NLsD$!KwzN zS8ZJ%R&20o^8Y{o{{6r8@eNjaxV~+({;Q#3&F!=Q_uf49|L5O7|6hFn@<03RE(|p= zJ*s<_{YS^WcP_&H4q|}(5Orn`hB}ZwmBSk_@QDwvQS^g2lONu|PzTm~V&{JqG(7$3 zJq-P6H_u_H1L;#fa{vQto;~z`$*ZUT-~ayo|MAc7|C=7&#!v&-2UM#}0rtFhmTdiw fS5E!E^7Zq7x2tDJHpBVK>Hp`xeEbh92gs!XBi)`m diff --git a/spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/resources/static/images/logo.png b/spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/resources/static/images/logo.png deleted file mode 100644 index 393230883fb4e04829339f7c21b6ab6de7393891..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1123 zcmV-p1f2VcP)P000yS1^@s74{)X{0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU$1xZ9fRCwBAJakr>0R&#%?*!8<7oReN z=>H6CRSb*_9RHalf3;=rzRt=3!VW|AET)fs_IS z5aXsJDqv;5UUXCgspCNG%qCu4_4m8Q8J4{_Ss=DB)G%-}OK$)A_qiv-M@As~;az|L zf?EIsP`7cheE7}?GEN=HaRK6^jLh%PvWj*xv3z@3xac)oRV-9P3=lIhyklZuIsRdC zEQk#P>`Ve}KmUCIvzcu9Tf*+YVP*hfGu{$8D7y_HfEf3kMztIrynEOQW2*Ct&A;*G zO}I7VlHICc5w;GSdsSFH1nBbCHtgWCZ;JNm@ z`XjO?7RGP?S?;`M26}|$>d$}7+Q^c380tVF%ErLJjAqwYZkA^sS%0xHF}~wxlbiD5 z`(qoR=no*41>&DbDvtqiaJE+C3lIk&fG}bK9l%ly6jZSM`Nu#MU}XG#RzRlJh~>*q zMz|m_S~GwYKiDe_40nN83W%$i`8HWIa~)&&`WqMkpMdet@v+_G7x%2~|M)9$Tk#!Y zFw1)&gOROi`~TlS|Ne#uGBU8e{?G6W7-39r7#RMspu`I>^-8__`jg@PS4KGI{tDI)dzZ%dlS>M59FF!%vUTz)~b4X4$^~`TvW7 ziIMs5zyE)kk;ES}`AIdM1t$C=P~wMS3!!9Ap!k0ap%i9haWBalIY!4O?f(oAd%r+4 zo)k2;d7%b_#Jhnp-2~zQ1Q@}XCIrw@0t|34GX2=V#dp;1>j!5(mhZn98K?y0fw-87 z<#h&!;7V3zwkKdg)?fU+ET4a(DSgvn03;_eFu%5AV7&(n_piW02N=Hpff?mLFf{&g z0%=ZYR2CvOD9l@{`Ma!o3LDu1eZb}An>(a<~Q?=8{fF=xc@W!MoZ)b z{O|{gu_$Ev|5TXe{Z}Tay7jj||2@OO@D(hD)hsRsjrwm4H=1C4P6p+J-x==O;Vpp} zelf7T{l>^3$L4GI;MZmjLQek2%+jdD-YkChTV1vRXZ6WjKj)c!`-fi-2P5B87D!gv za)A+O=YLR%j|aSGxW@31vGu^;|BMVrzfaux>)%&1LJk9(o(#_DK=28Oy@5ho@oC^@ z5m@o{&xh3zgTK{rGV>dM|NF@cm+`=a;1wp - - Secured Content - - -

-

Secured Page

-

This page is secured using Spring Boot, Spring Session, and Spring Security.

-
- - diff --git a/spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/resources/templates/layout.html b/spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/resources/templates/layout.html deleted file mode 100644 index 50be94b5..00000000 --- a/spring-session-samples/spring-session-sample-boot-hazelcast4/src/main/resources/templates/layout.html +++ /dev/null @@ -1,122 +0,0 @@ - - - - Spring Session Sample - - - - - - - - - - - -
- - -
-
- Some Success message -
-
- Fake content -
-
- -
-
- - - - diff --git a/spring-session-samples/spring-session-sample-javaconfig-hazelcast/spring-session-sample-javaconfig-hazelcast.gradle b/spring-session-samples/spring-session-sample-javaconfig-hazelcast/spring-session-sample-javaconfig-hazelcast.gradle index 010cdb6b..f4f18651 100644 --- a/spring-session-samples/spring-session-sample-javaconfig-hazelcast/spring-session-sample-javaconfig-hazelcast.gradle +++ b/spring-session-samples/spring-session-sample-javaconfig-hazelcast/spring-session-sample-javaconfig-hazelcast.gradle @@ -11,7 +11,7 @@ dependencies { implementation "org.springframework.security:spring-security-web" implementation "org.webjars:bootstrap" implementation "org.webjars:webjars-taglib" - implementation "com.hazelcast:hazelcast-client" + implementation "com.hazelcast:hazelcast" implementation "org.slf4j:slf4j-api" implementation "org.slf4j:jcl-over-slf4j" implementation "org.slf4j:log4j-over-slf4j" diff --git a/spring-session-samples/spring-session-sample-javaconfig-hazelcast/src/main/java/sample/SessionConfig.java b/spring-session-samples/spring-session-sample-javaconfig-hazelcast/src/main/java/sample/SessionConfig.java index df46dc49..4e0bd232 100644 --- a/spring-session-samples/spring-session-sample-javaconfig-hazelcast/src/main/java/sample/SessionConfig.java +++ b/spring-session-samples/spring-session-sample-javaconfig-hazelcast/src/main/java/sample/SessionConfig.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2019 the original author or authors. + * Copyright 2014-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,9 +16,10 @@ package sample; +import com.hazelcast.config.AttributeConfig; import com.hazelcast.config.Config; -import com.hazelcast.config.MapAttributeConfig; -import com.hazelcast.config.MapIndexConfig; +import com.hazelcast.config.IndexConfig; +import com.hazelcast.config.IndexType; import com.hazelcast.config.NetworkConfig; import com.hazelcast.core.Hazelcast; import com.hazelcast.core.HazelcastInstance; @@ -40,12 +41,12 @@ public class SessionConfig { NetworkConfig networkConfig = config.getNetworkConfig(); networkConfig.setPort(0); networkConfig.getJoin().getMulticastConfig().setEnabled(false); - MapAttributeConfig attributeConfig = new MapAttributeConfig() + AttributeConfig attributeConfig = new AttributeConfig() .setName(HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE) - .setExtractor(PrincipalNameExtractor.class.getName()); + .setExtractorClassName(PrincipalNameExtractor.class.getName()); config.getMapConfig(HazelcastIndexedSessionRepository.DEFAULT_SESSION_MAP_NAME) - .addMapAttributeConfig(attributeConfig).addMapIndexConfig( - new MapIndexConfig(HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE, false)); + .addAttributeConfig(attributeConfig).addIndexConfig( + new IndexConfig(IndexType.HASH, HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE)); return Hazelcast.newHazelcastInstance(config); } diff --git a/spring-session-samples/spring-session-sample-misc-hazelcast/spring-session-sample-misc-hazelcast.gradle b/spring-session-samples/spring-session-sample-misc-hazelcast/spring-session-sample-misc-hazelcast.gradle index a79baccf..a3e8c6f8 100644 --- a/spring-session-samples/spring-session-sample-misc-hazelcast/spring-session-sample-misc-hazelcast.gradle +++ b/spring-session-samples/spring-session-sample-misc-hazelcast/spring-session-sample-misc-hazelcast.gradle @@ -7,7 +7,7 @@ dependencies { implementation project(':spring-session-core') implementation "org.webjars:bootstrap" implementation "org.webjars:webjars-taglib" - implementation "com.hazelcast:hazelcast-client" + implementation "com.hazelcast:hazelcast" implementation "jakarta.servlet.jsp.jstl:jakarta.servlet.jsp.jstl-api" implementation "org.apache.taglibs:taglibs-standard-jstlel" implementation "org.slf4j:slf4j-api"