Skip to content

Commit 2b6489c

Browse files
committed
Add support for Hazelcast 4
Closes gh-1584
1 parent c0c672b commit 2b6489c

18 files changed

+2050
-5
lines changed

settings.gradle

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ include 'spring-session-data-redis'
55
include 'spring-session-docs'
66
include 'spring-session-hazelcast'
77
include 'spring-session-jdbc'
8+
include 'hazelcast4'
9+
project(':hazelcast4').projectDir = file('spring-session-hazelcast/hazelcast4')
810

911
file('spring-session-samples').eachDirMatch(~/spring-session-sample-.*/) { dir ->
1012
include dir.name
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
plugins {
2+
id 'java-library'
3+
id 'io.spring.convention.repository'
4+
id 'io.spring.convention.springdependencymangement'
5+
id 'io.spring.convention.dependency-set'
6+
id 'io.spring.convention.checkstyle'
7+
id 'io.spring.convention.tests-configuration'
8+
id 'io.spring.convention.integration-test'
9+
}
10+
11+
configurations {
12+
classesOnlyElements {
13+
canBeConsumed = true
14+
canBeResolved = false
15+
}
16+
}
17+
18+
artifacts {
19+
classesOnlyElements(compileJava.destinationDir)
20+
}
21+
22+
dependencies {
23+
compile project(':spring-session-core')
24+
compile "com.hazelcast:hazelcast:4.0.2"
25+
compile "org.springframework:spring-context"
26+
27+
testCompile "javax.servlet:javax.servlet-api"
28+
testCompile "org.springframework:spring-web"
29+
testCompile "org.junit.jupiter:junit-jupiter-api"
30+
testCompile "org.springframework.security:spring-security-core"
31+
testRuntime "org.junit.jupiter:junit-jupiter-engine"
32+
33+
integrationTestCompile "org.testcontainers:testcontainers"
34+
integrationTestCompile "com.hazelcast:hazelcast:4.0.2"
35+
integrationTestCompile project(":spring-session-hazelcast")
36+
}
37+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
/*
2+
* Copyright 2014-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.session.hazelcast;
18+
19+
import com.hazelcast.core.HazelcastInstance;
20+
import com.hazelcast.map.IMap;
21+
import org.junit.jupiter.api.Test;
22+
23+
import org.springframework.beans.factory.annotation.Autowired;
24+
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
25+
import org.springframework.security.core.Authentication;
26+
import org.springframework.security.core.authority.AuthorityUtils;
27+
import org.springframework.security.core.context.SecurityContext;
28+
import org.springframework.security.core.context.SecurityContextHolder;
29+
import org.springframework.session.MapSession;
30+
import org.springframework.session.hazelcast.Hazelcast4IndexedSessionRepository.HazelcastSession;
31+
32+
import static org.assertj.core.api.Assertions.assertThat;
33+
34+
/**
35+
* Base class for {@link Hazelcast4IndexedSessionRepository} integration tests.
36+
*
37+
* @author Eleftheria Stein
38+
*/
39+
abstract class AbstractHazelcast4IndexedSessionRepositoryITests {
40+
41+
private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT";
42+
43+
@Autowired
44+
private HazelcastInstance hazelcastInstance;
45+
46+
@Autowired
47+
private Hazelcast4IndexedSessionRepository repository;
48+
49+
@Test
50+
void createAndDestroySession() {
51+
HazelcastSession sessionToSave = this.repository.createSession();
52+
String sessionId = sessionToSave.getId();
53+
54+
IMap<String, MapSession> hazelcastMap = this.hazelcastInstance
55+
.getMap(Hazelcast4IndexedSessionRepository.DEFAULT_SESSION_MAP_NAME);
56+
57+
assertThat(hazelcastMap.size()).isEqualTo(0);
58+
59+
this.repository.save(sessionToSave);
60+
61+
assertThat(hazelcastMap.size()).isEqualTo(1);
62+
assertThat(hazelcastMap.get(sessionId)).isEqualTo(sessionToSave);
63+
64+
this.repository.deleteById(sessionId);
65+
66+
assertThat(hazelcastMap.size()).isEqualTo(0);
67+
}
68+
69+
@Test
70+
void changeSessionIdWhenOnlyChangeId() {
71+
String attrName = "changeSessionId";
72+
String attrValue = "changeSessionId-value";
73+
HazelcastSession toSave = this.repository.createSession();
74+
toSave.setAttribute(attrName, attrValue);
75+
76+
this.repository.save(toSave);
77+
78+
HazelcastSession findById = this.repository.findById(toSave.getId());
79+
80+
assertThat(findById.<String>getAttribute(attrName)).isEqualTo(attrValue);
81+
82+
String originalFindById = findById.getId();
83+
String changeSessionId = findById.changeSessionId();
84+
85+
this.repository.save(findById);
86+
87+
assertThat(this.repository.findById(originalFindById)).isNull();
88+
89+
HazelcastSession findByChangeSessionId = this.repository.findById(changeSessionId);
90+
91+
assertThat(findByChangeSessionId.<String>getAttribute(attrName)).isEqualTo(attrValue);
92+
93+
this.repository.deleteById(changeSessionId);
94+
}
95+
96+
@Test
97+
void changeSessionIdWhenChangeTwice() {
98+
HazelcastSession toSave = this.repository.createSession();
99+
100+
this.repository.save(toSave);
101+
102+
String originalId = toSave.getId();
103+
String changeId1 = toSave.changeSessionId();
104+
String changeId2 = toSave.changeSessionId();
105+
106+
this.repository.save(toSave);
107+
108+
assertThat(this.repository.findById(originalId)).isNull();
109+
assertThat(this.repository.findById(changeId1)).isNull();
110+
assertThat(this.repository.findById(changeId2)).isNotNull();
111+
112+
this.repository.deleteById(changeId2);
113+
}
114+
115+
@Test
116+
void changeSessionIdWhenSetAttributeOnChangedSession() {
117+
String attrName = "changeSessionId";
118+
String attrValue = "changeSessionId-value";
119+
120+
HazelcastSession toSave = this.repository.createSession();
121+
122+
this.repository.save(toSave);
123+
124+
HazelcastSession findById = this.repository.findById(toSave.getId());
125+
126+
findById.setAttribute(attrName, attrValue);
127+
128+
String originalFindById = findById.getId();
129+
String changeSessionId = findById.changeSessionId();
130+
131+
this.repository.save(findById);
132+
133+
assertThat(this.repository.findById(originalFindById)).isNull();
134+
135+
HazelcastSession findByChangeSessionId = this.repository.findById(changeSessionId);
136+
137+
assertThat(findByChangeSessionId.<String>getAttribute(attrName)).isEqualTo(attrValue);
138+
139+
this.repository.deleteById(changeSessionId);
140+
}
141+
142+
@Test
143+
void changeSessionIdWhenHasNotSaved() {
144+
HazelcastSession toSave = this.repository.createSession();
145+
String originalId = toSave.getId();
146+
toSave.changeSessionId();
147+
148+
this.repository.save(toSave);
149+
150+
assertThat(this.repository.findById(toSave.getId())).isNotNull();
151+
assertThat(this.repository.findById(originalId)).isNull();
152+
153+
this.repository.deleteById(toSave.getId());
154+
}
155+
156+
@Test // gh-1076
157+
void attemptToUpdateSessionAfterDelete() {
158+
HazelcastSession session = this.repository.createSession();
159+
String sessionId = session.getId();
160+
this.repository.save(session);
161+
session = this.repository.findById(sessionId);
162+
session.setAttribute("attributeName", "attributeValue");
163+
this.repository.deleteById(sessionId);
164+
this.repository.save(session);
165+
166+
assertThat(this.repository.findById(sessionId)).isNull();
167+
}
168+
169+
@Test
170+
void createAndUpdateSession() {
171+
HazelcastSession session = this.repository.createSession();
172+
String sessionId = session.getId();
173+
174+
this.repository.save(session);
175+
176+
session = this.repository.findById(sessionId);
177+
session.setAttribute("attributeName", "attributeValue");
178+
179+
this.repository.save(session);
180+
181+
assertThat(this.repository.findById(sessionId)).isNotNull();
182+
}
183+
184+
@Test
185+
void createSessionWithSecurityContextAndFindById() {
186+
HazelcastSession session = this.repository.createSession();
187+
String sessionId = session.getId();
188+
189+
Authentication authentication = new UsernamePasswordAuthenticationToken("saves-" + System.currentTimeMillis(),
190+
"password", AuthorityUtils.createAuthorityList("ROLE_USER"));
191+
SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
192+
securityContext.setAuthentication(authentication);
193+
session.setAttribute(SPRING_SECURITY_CONTEXT, securityContext);
194+
195+
this.repository.save(session);
196+
197+
assertThat(this.repository.findById(sessionId)).isNotNull();
198+
}
199+
200+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright 2014-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.session.hazelcast;
18+
19+
import com.hazelcast.client.HazelcastClient;
20+
import com.hazelcast.client.config.ClientConfig;
21+
import com.hazelcast.core.HazelcastInstance;
22+
import org.junit.jupiter.api.AfterAll;
23+
import org.junit.jupiter.api.BeforeAll;
24+
import org.junit.jupiter.api.extension.ExtendWith;
25+
import org.testcontainers.containers.GenericContainer;
26+
import org.testcontainers.utility.MountableFile;
27+
28+
import org.springframework.context.annotation.Bean;
29+
import org.springframework.context.annotation.Configuration;
30+
import org.springframework.session.MapSession;
31+
import org.springframework.session.Session;
32+
import org.springframework.session.hazelcast.config.annotation.web.http.EnableHazelcastHttpSession;
33+
import org.springframework.test.context.ContextConfiguration;
34+
import org.springframework.test.context.junit.jupiter.SpringExtension;
35+
import org.springframework.test.context.web.WebAppConfiguration;
36+
37+
/**
38+
* Integration tests for {@link Hazelcast4IndexedSessionRepository} using client-server
39+
* topology.
40+
*
41+
* @author Eleftheria Stein
42+
*/
43+
@ExtendWith(SpringExtension.class)
44+
@ContextConfiguration
45+
@WebAppConfiguration
46+
class ClientServerHazelcast4IndexedSessionRepositoryITests extends AbstractHazelcast4IndexedSessionRepositoryITests {
47+
48+
private static GenericContainer container = new GenericContainer<>("hazelcast/hazelcast:4.0.2")
49+
.withExposedPorts(5701).withCopyFileToContainer(MountableFile.forClasspathResource("/hazelcast-server.xml"),
50+
"/opt/hazelcast/hazelcast.xml");
51+
52+
@BeforeAll
53+
static void setUpClass() {
54+
container.start();
55+
}
56+
57+
@AfterAll
58+
static void tearDownClass() {
59+
container.stop();
60+
}
61+
62+
@Configuration
63+
@EnableHazelcastHttpSession
64+
static class HazelcastSessionConfig {
65+
66+
@Bean
67+
HazelcastInstance hazelcastInstance() {
68+
ClientConfig clientConfig = new ClientConfig();
69+
clientConfig.getNetworkConfig()
70+
.addAddress(container.getContainerIpAddress() + ":" + container.getFirstMappedPort());
71+
clientConfig.getUserCodeDeploymentConfig().setEnabled(true).addClass(Session.class)
72+
.addClass(MapSession.class).addClass(Hazelcast4SessionUpdateEntryProcessor.class);
73+
return HazelcastClient.newHazelcastClient(clientConfig);
74+
}
75+
76+
}
77+
78+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright 2014-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.session.hazelcast;
18+
19+
import com.hazelcast.core.HazelcastInstance;
20+
import org.junit.jupiter.api.extension.ExtendWith;
21+
22+
import org.springframework.context.annotation.Bean;
23+
import org.springframework.context.annotation.Configuration;
24+
import org.springframework.session.hazelcast.config.annotation.web.http.EnableHazelcastHttpSession;
25+
import org.springframework.test.context.ContextConfiguration;
26+
import org.springframework.test.context.junit.jupiter.SpringExtension;
27+
import org.springframework.test.context.web.WebAppConfiguration;
28+
29+
/**
30+
* Integration tests for {@link Hazelcast4IndexedSessionRepository} using embedded
31+
* topology.
32+
*
33+
* @author Eleftheria Stein
34+
*/
35+
@ExtendWith(SpringExtension.class)
36+
@ContextConfiguration
37+
@WebAppConfiguration
38+
class EmbeddedHazelcast4IndexedSessionRepositoryITests extends AbstractHazelcast4IndexedSessionRepositoryITests {
39+
40+
@EnableHazelcastHttpSession
41+
@Configuration
42+
static class HazelcastSessionConfig {
43+
44+
@Bean
45+
HazelcastInstance hazelcastInstance() {
46+
return Hazelcast4ITestUtils.embeddedHazelcastServer();
47+
}
48+
49+
}
50+
51+
}

0 commit comments

Comments
 (0)