Skip to content

Commit 0aa394e

Browse files
authored
Merge pull request #17 from mkopylec/sb2
Sb2
2 parents 37a3bc8 + cac9479 commit 0aa394e

21 files changed

+161
-254
lines changed

README.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,18 @@ The project supports only Couchbase 4 and higher versions. For more information
1414
- remove `@EnableCouchbaseHttpSession` annotation
1515
- replace `session-couchbase.persistent.couchbase` properties with `spring.couchbase` in the _application.yml_ file
1616

17+
## Migrating from 2.x.x to 3.x.x
18+
19+
- `session-couchbase.timeout-in-seconds` `int` property in the _application.yml_ file is replaced by `session-couchbase.timeout` `Duration` property
20+
1721
## Installing
1822

1923
```gradle
2024
repositories {
2125
mavenCentral()
2226
}
2327
dependencies {
24-
compile 'com.github.mkopylec:session-couchbase-spring-boot-starter:2.2.0'
28+
compile group: 'com.github.mkopylec', name: 'session-couchbase-spring-boot-starter', version: '3.0.0'
2529
}
2630
```
2731

@@ -44,7 +48,7 @@ Simply use `HttpSession` interface to control HTTP session. For example:
4448
@Controller
4549
public class SessionController {
4650

47-
@GetMapping("uri")
51+
@GetMapping("/uri")
4852
public void doSomething(HttpSession session) {
4953
...
5054
}
@@ -93,17 +97,16 @@ The session is visible only within a single web application instance and will be
9397
The mode is useful for integration tests when you don't want to communicate with the real Couchbase server instance.
9498

9599
## Namespaces
96-
The starter supports HTTP session namespaces.
100+
The starter supports HTTP session namespaces to prevent session attribute's names conflicts in a distributed systems like platforms composed with micro-services.
97101
The name of the namespace can be set in _application.yml_ file:
98102

99103
```yaml
100104
session-couchbase:
101105
application-namespace: <application_namespace>
102106
```
103107

104-
Each web application in a distributed system has one application namespace under which the session attributes are stored.
108+
Each web application in a distributed system can have one application namespace under which the application's session attributes are stored.
105109
Every web application can also access global session attributes which are visible across the whole distributed system.
106-
Namespaces prevent conflicts in attributes names between different web applications in the system.
107110
Two web applications can have the same namespace and therefore access the same session attributes.
108111
If two web applications have different namespaces they cannot access each others session attributes.
109112

@@ -143,7 +146,7 @@ When changing HTTP session ID every attribute is copied to the new session, no m
143146

144147
```yaml
145148
session-couchbase:
146-
timeout-in-seconds: 1800 # HTTP session timeout.
149+
timeout: 30m # HTTP session timeout.
147150
application-namespace: default # HTTP session application namespace under which session data must be stored.
148151
principal-sessions:
149152
enabled: false # Flag for enabling and disabling finding HTTP sessions by principal. Can significantly decrease application performance when enabled.

build.gradle

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@ plugins {
22
id 'groovy'
33
id 'maven-publish'
44
id 'jacoco'
5-
id 'nebula.optional-base' version '3.2.0'
65
id 'com.github.kt3k.coveralls' version '2.8.2'
76
id 'maven'
87
id 'signing'
9-
id 'pl.allegro.tech.build.axion-release' version '1.9.0'
8+
id 'pl.allegro.tech.build.axion-release' version '1.9.2'
109
id 'io.codearte.nexus-staging' version '0.11.0'
1110
}
1211

@@ -27,35 +26,25 @@ repositories {
2726
mavenCentral()
2827
}
2928

30-
ext.springBootVersion = '1.5.11.RELEASE'
29+
ext.springBootVersion = '2.0.3.RELEASE'
3130

3231
dependencies {
3332

34-
compile group: 'org.springframework.boot', name: 'spring-boot-starter', version: springBootVersion
35-
compile("org.springframework.boot:spring-boot-starter-data-couchbase:$springBootVersion") {
36-
exclude group: 'org.springframework', module: 'spring-web'
37-
}
38-
compile group: 'org.springframework.session', name: 'spring-session', version: '1.3.2.RELEASE'
33+
compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: springBootVersion
34+
compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-couchbase', version: springBootVersion
35+
compile group: 'org.springframework.session', name: 'spring-session-core', version: '2.0.4.RELEASE'
3936
compile group: 'org.springframework.retry', name: 'spring-retry', version: '1.2.2.RELEASE'
40-
compile group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0'
41-
compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.8.9'
4237
compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.7'
4338
compile group: 'org.apache.commons', name: 'commons-collections4', version: '4.1'
4439

45-
compile group: 'org.springframework.boot', name: 'spring-boot-configuration-processor', version: springBootVersion, optional
40+
compileOnly group: 'org.springframework.boot', name: 'spring-boot-configuration-processor', version: springBootVersion
4641

4742
testCompile group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: springBootVersion
48-
testCompile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: springBootVersion
49-
testCompile group: 'org.springframework.boot', name: 'spring-boot-starter-undertow', version: springBootVersion
5043
testCompile group: 'org.spockframework', name: 'spock-spring', version: '1.1-groovy-2.4'
5144
}
5245

53-
configurations {
54-
all*.exclude group: 'org.mortbay.jetty', module: 'servlet-api'
55-
}
56-
5746
task wrapper(type: Wrapper) {
58-
gradleVersion = '4.6'
47+
gradleVersion = '4.8'
5948
}
6049

6150
task javadocJar(type: Jar) {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-bin.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists

src/main/java/com/github/mkopylec/sessioncouchbase/configuration/SessionCouchbaseAutoConfiguration.java

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,44 +2,27 @@
22

33
import com.fasterxml.jackson.databind.ObjectMapper;
44
import com.github.mkopylec.sessioncouchbase.core.CouchbaseSessionRepository;
5-
import com.github.mkopylec.sessioncouchbase.core.DelegatingSessionStrategy;
65
import com.github.mkopylec.sessioncouchbase.core.Serializer;
76
import com.github.mkopylec.sessioncouchbase.data.SessionDao;
8-
9-
import org.springframework.beans.factory.annotation.Autowired;
107
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
118
import org.springframework.boot.context.properties.EnableConfigurationProperties;
129
import org.springframework.context.ApplicationEventPublisher;
1310
import org.springframework.context.annotation.Bean;
1411
import org.springframework.context.annotation.Configuration;
1512
import org.springframework.session.SessionRepository;
1613
import org.springframework.session.config.annotation.web.http.EnableSpringHttpSession;
17-
import org.springframework.session.web.http.CookieHttpSessionStrategy;
18-
import org.springframework.session.web.http.CookieSerializer;
19-
import org.springframework.session.web.http.MultiHttpSessionStrategy;
2014

2115
@Configuration
2216
@EnableSpringHttpSession
2317
@EnableConfigurationProperties(SessionCouchbaseProperties.class)
2418
public class SessionCouchbaseAutoConfiguration {
2519

2620
protected SessionCouchbaseProperties sessionCouchbase;
27-
protected CookieSerializer cookieSerializer;
2821

2922
public SessionCouchbaseAutoConfiguration(SessionCouchbaseProperties sessionCouchbase) {
3023
this.sessionCouchbase = sessionCouchbase;
3124
}
3225

33-
@Bean
34-
@ConditionalOnMissingBean
35-
public MultiHttpSessionStrategy multiHttpSessionStrategy(SessionDao dao) {
36-
CookieHttpSessionStrategy sessionStrategy = new CookieHttpSessionStrategy();
37-
if (cookieSerializer != null) {
38-
sessionStrategy.setCookieSerializer(cookieSerializer);
39-
}
40-
return new DelegatingSessionStrategy(sessionStrategy, dao);
41-
}
42-
4326
@Bean
4427
@ConditionalOnMissingBean
4528
public Serializer serializer() {
@@ -57,9 +40,4 @@ public SessionRepository sessionRepository(SessionDao dao, ObjectMapper mapper,
5740
public ObjectMapper objectMapper() {
5841
return new ObjectMapper();
5942
}
60-
61-
@Autowired(required = false)
62-
public void setCookieSerializer(CookieSerializer cookieSerializer) {
63-
this.cookieSerializer = cookieSerializer;
64-
}
6543
}

src/main/java/com/github/mkopylec/sessioncouchbase/configuration/SessionCouchbaseProperties.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@
44
import org.springframework.boot.context.properties.ConfigurationProperties;
55
import org.springframework.boot.context.properties.NestedConfigurationProperty;
66

7+
import java.time.Duration;
8+
79
import static com.couchbase.client.java.query.consistency.ScanConsistency.REQUEST_PLUS;
10+
import static java.time.Duration.ofMinutes;
11+
import static org.apache.commons.lang3.StringUtils.trimToNull;
812

913
/**
1014
* Session couchbase configuration properties.
@@ -15,7 +19,7 @@ public class SessionCouchbaseProperties {
1519
/**
1620
* HTTP session timeout.
1721
*/
18-
private int timeoutInSeconds = 1800;
22+
private Duration timeout = ofMinutes(30);
1923
/**
2024
* HTTP session application namespace under which session data must be stored.
2125
*/
@@ -36,16 +40,16 @@ public class SessionCouchbaseProperties {
3640
@NestedConfigurationProperty
3741
private InMemory inMemory = new InMemory();
3842

39-
public int getTimeoutInSeconds() {
40-
return timeoutInSeconds;
43+
public Duration getTimeout() {
44+
return timeout;
4145
}
4246

43-
public void setTimeoutInSeconds(int timeoutInSeconds) {
44-
this.timeoutInSeconds = timeoutInSeconds;
47+
public void setTimeout(Duration timeout) {
48+
this.timeout = timeout;
4549
}
4650

4751
public String getApplicationNamespace() {
48-
return applicationNamespace;
52+
return trimToNull(applicationNamespace);
4953
}
5054

5155
public void setApplicationNamespace(String applicationNamespace) {

src/main/java/com/github/mkopylec/sessioncouchbase/core/CouchbaseSession.java

Lines changed: 59 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,28 @@
33
import org.apache.commons.collections4.CollectionUtils;
44
import org.apache.commons.collections4.MapUtils;
55
import org.slf4j.Logger;
6-
import org.springframework.session.ExpiringSession;
6+
import org.springframework.session.Session;
77

8-
import java.io.Serializable;
8+
import java.time.Duration;
9+
import java.time.Instant;
910
import java.util.HashMap;
1011
import java.util.HashSet;
1112
import java.util.Map;
1213
import java.util.Set;
1314

14-
import static java.lang.System.currentTimeMillis;
15+
import static java.time.Duration.ofSeconds;
16+
import static java.time.Instant.now;
17+
import static java.time.Instant.ofEpochSecond;
1518
import static java.util.Collections.unmodifiableSet;
1619
import static java.util.UUID.randomUUID;
17-
import static java.util.concurrent.TimeUnit.SECONDS;
1820
import static java.util.stream.Collectors.toSet;
1921
import static org.apache.commons.lang3.StringUtils.removeStart;
2022
import static org.slf4j.LoggerFactory.getLogger;
2123
import static org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME;
2224
import static org.springframework.util.Assert.hasText;
2325
import static org.springframework.util.Assert.isTrue;
2426

25-
public class CouchbaseSession implements ExpiringSession, Serializable {
26-
27-
private static final long serialVersionUID = 1L;
27+
public class CouchbaseSession implements Session {
2828

2929
public static final String CREATION_TIME_ATTRIBUTE = "$creationTime";
3030
public static final String LAST_ACCESSED_TIME_ATTRIBUTE = "$lastAccessedTime";
@@ -33,20 +33,24 @@ public class CouchbaseSession implements ExpiringSession, Serializable {
3333

3434
private static final Logger log = getLogger(CouchbaseSession.class);
3535

36-
protected String id = randomUUID().toString();
36+
protected String id = generateSessionId();
37+
3738
protected Map<String, Object> globalAttributesToUpdate = new HashMap<>();
39+
3840
protected Set<String> globalAttributesToRemove = new HashSet<>();
3941
protected Map<String, Object> globalAttributes = new HashMap<>();
4042
protected Map<String, Object> namespaceAttributesToUpdate = new HashMap<>();
4143
protected Set<String> namespaceAttributesToRemove = new HashSet<>();
4244
protected Map<String, Object> namespaceAttributes = new HashMap<>();
4345
protected boolean principalSessionsUpdateRequired = false;
46+
protected boolean idChanged = false;
47+
protected String oldId;
4448

45-
public CouchbaseSession(int timeoutInSeconds) {
46-
long now = currentTimeMillis();
49+
public CouchbaseSession(Duration timeout) {
50+
Instant now = now();
4751
setCreationTime(now);
4852
setLastAccessedTime(now);
49-
setMaxInactiveIntervalInSeconds(timeoutInSeconds);
53+
setMaxInactiveInterval(timeout);
5054
}
5155

5256
public CouchbaseSession(String id, Map<String, Object> globalAttributes, Map<String, Object> namespaceAttributes) {
@@ -63,41 +67,52 @@ public static String globalAttributeName(String attributeName) {
6367
}
6468

6569
@Override
66-
public long getCreationTime() {
67-
return getNumericGlobalAttributeValue(CREATION_TIME_ATTRIBUTE);
70+
public Instant getCreationTime() {
71+
return getDateGlobalAttributeValue(CREATION_TIME_ATTRIBUTE);
6872
}
6973

7074
@Override
71-
public long getLastAccessedTime() {
72-
return getNumericGlobalAttributeValue(LAST_ACCESSED_TIME_ATTRIBUTE);
75+
public void setLastAccessedTime(Instant lastAccessedTime) {
76+
globalAttributes.put(LAST_ACCESSED_TIME_ATTRIBUTE, lastAccessedTime.getEpochSecond());
77+
globalAttributesToUpdate.put(LAST_ACCESSED_TIME_ATTRIBUTE, lastAccessedTime.getEpochSecond());
7378
}
7479

75-
public void setLastAccessedTime(long lastAccessedTime) {
76-
globalAttributes.put(LAST_ACCESSED_TIME_ATTRIBUTE, lastAccessedTime);
77-
globalAttributesToUpdate.put(LAST_ACCESSED_TIME_ATTRIBUTE, lastAccessedTime);
80+
@Override
81+
public Instant getLastAccessedTime() {
82+
return getDateGlobalAttributeValue(LAST_ACCESSED_TIME_ATTRIBUTE);
7883
}
7984

8085
@Override
81-
public void setMaxInactiveIntervalInSeconds(int interval) {
82-
globalAttributes.put(MAX_INACTIVE_INTERVAL_ATTRIBUTE, interval);
83-
globalAttributesToUpdate.put(MAX_INACTIVE_INTERVAL_ATTRIBUTE, interval);
86+
public void setMaxInactiveInterval(Duration interval) {
87+
globalAttributes.put(MAX_INACTIVE_INTERVAL_ATTRIBUTE, interval.getSeconds());
88+
globalAttributesToUpdate.put(MAX_INACTIVE_INTERVAL_ATTRIBUTE, interval.getSeconds());
8489
}
8590

8691
@Override
87-
public int getMaxInactiveIntervalInSeconds() {
88-
return (int) globalAttributes.get(MAX_INACTIVE_INTERVAL_ATTRIBUTE);
92+
public Duration getMaxInactiveInterval() {
93+
long interval = getNumericGlobalAttributeValue(MAX_INACTIVE_INTERVAL_ATTRIBUTE);
94+
return ofSeconds(interval);
8995
}
9096

9197
@Override
9298
public boolean isExpired() {
93-
return getMaxInactiveIntervalInSeconds() >= 0 && currentTimeMillis() - SECONDS.toMillis(getMaxInactiveIntervalInSeconds()) >= getLastAccessedTime();
99+
return now().minus(getMaxInactiveInterval()).compareTo(getLastAccessedTime()) >= 0;
94100
}
95101

96102
@Override
97103
public String getId() {
98104
return id;
99105
}
100106

107+
@Override
108+
public String changeSessionId() {
109+
oldId = id;
110+
id = generateSessionId();
111+
idChanged = true;
112+
log.debug("HTTP session ID has changed from {} to {}", oldId, id);
113+
return id;
114+
}
115+
101116
@SuppressWarnings("unchecked")
102117
@Override
103118
public <T> T getAttribute(String attributeName) {
@@ -205,6 +220,14 @@ public boolean isPrincipalSessionsUpdateRequired() {
205220
return principalSessionsUpdateRequired;
206221
}
207222

223+
public boolean isIdChanged() {
224+
return idChanged;
225+
}
226+
227+
public String getOldId() {
228+
return oldId;
229+
}
230+
208231
public String getPrincipalAttribute() {
209232
Object principal = globalAttributes.get(PRINCIPAL_NAME_INDEX_NAME);
210233
if (principal == null) {
@@ -217,9 +240,9 @@ public void unsetPrincipalSessionsUpdateRequired() {
217240
principalSessionsUpdateRequired = false;
218241
}
219242

220-
protected void setCreationTime(long creationTime) {
221-
globalAttributes.put(CREATION_TIME_ATTRIBUTE, creationTime);
222-
globalAttributesToUpdate.put(CREATION_TIME_ATTRIBUTE, creationTime);
243+
protected void setCreationTime(Instant creationTime) {
244+
globalAttributes.put(CREATION_TIME_ATTRIBUTE, creationTime.getEpochSecond());
245+
globalAttributesToUpdate.put(CREATION_TIME_ATTRIBUTE, creationTime.getEpochSecond());
223246
}
224247

225248
protected void checkAttributeName(String attributeName) {
@@ -239,7 +262,16 @@ protected boolean containsPrincipalAttribute() {
239262
return globalAttributes.containsKey(PRINCIPAL_NAME_INDEX_NAME) || namespaceAttributes.containsKey(PRINCIPAL_NAME_INDEX_NAME);
240263
}
241264

265+
protected Instant getDateGlobalAttributeValue(String attributeName) {
266+
long attributeValue = getNumericGlobalAttributeValue(attributeName);
267+
return ofEpochSecond(attributeValue);
268+
}
269+
242270
protected long getNumericGlobalAttributeValue(String attributeName) {
243271
return ((Number) globalAttributes.get(attributeName)).longValue();
244272
}
273+
274+
protected String generateSessionId() {
275+
return randomUUID().toString();
276+
}
245277
}

0 commit comments

Comments
 (0)