Skip to content
This repository was archived by the owner on Apr 4, 2025. It is now read-only.

Commit ebac581

Browse files
committed
Introduce MongoIndexedSessionRepository.
1 parent 4fbb1d3 commit ebac581

File tree

11 files changed

+229
-193
lines changed

11 files changed

+229
-193
lines changed
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
/*
2+
* Copyright 2019 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+
package org.springframework.session.data.mongo;
17+
18+
import static org.springframework.session.data.mongo.MongoSessionUtils.*;
19+
20+
import java.time.Duration;
21+
import java.util.Collections;
22+
import java.util.Map;
23+
import java.util.Optional;
24+
import java.util.stream.Collectors;
25+
26+
import org.bson.Document;
27+
import org.slf4j.Logger;
28+
import org.slf4j.LoggerFactory;
29+
import org.springframework.beans.factory.InitializingBean;
30+
import org.springframework.context.ApplicationEvent;
31+
import org.springframework.context.ApplicationEventPublisher;
32+
import org.springframework.context.ApplicationEventPublisherAware;
33+
import org.springframework.data.mongodb.core.MongoOperations;
34+
import org.springframework.data.mongodb.core.index.IndexOperations;
35+
import org.springframework.lang.Nullable;
36+
import org.springframework.session.FindByIndexNameSessionRepository;
37+
import org.springframework.session.events.SessionCreatedEvent;
38+
import org.springframework.session.events.SessionDeletedEvent;
39+
import org.springframework.session.events.SessionExpiredEvent;
40+
41+
/**
42+
* Session repository implementation which stores sessions in Mongo. Uses {@link AbstractMongoSessionConverter} to
43+
* transform session objects from/to native Mongo representation ({@code DBObject}). Repository is also responsible for
44+
* removing expired sessions from database. Cleanup is done every minute.
45+
*
46+
* @author Jakub Kubrynski
47+
* @author Greg Turnquist
48+
* @since 2.2.0
49+
*/
50+
public class MongoIndexedSessionRepository
51+
implements FindByIndexNameSessionRepository<MongoSession>, ApplicationEventPublisherAware, InitializingBean {
52+
53+
/**
54+
* The default time period in seconds in which a session will expire.
55+
*/
56+
public static final int DEFAULT_INACTIVE_INTERVAL = 1800;
57+
/**
58+
* the default collection name for storing session.
59+
*/
60+
public static final String DEFAULT_COLLECTION_NAME = "sessions";
61+
private static final Logger logger = LoggerFactory.getLogger(MongoIndexedSessionRepository.class);
62+
private final MongoOperations mongoOperations;
63+
private Integer maxInactiveIntervalInSeconds = DEFAULT_INACTIVE_INTERVAL;
64+
private String collectionName = DEFAULT_COLLECTION_NAME;
65+
private AbstractMongoSessionConverter mongoSessionConverter = new JdkMongoSessionConverter(
66+
Duration.ofSeconds(this.maxInactiveIntervalInSeconds));
67+
private ApplicationEventPublisher eventPublisher;
68+
69+
public MongoIndexedSessionRepository(MongoOperations mongoOperations) {
70+
this.mongoOperations = mongoOperations;
71+
}
72+
73+
@Override
74+
public MongoSession createSession() {
75+
76+
MongoSession session = new MongoSession();
77+
78+
if (this.maxInactiveIntervalInSeconds != null) {
79+
session.setMaxInactiveInterval(Duration.ofSeconds(this.maxInactiveIntervalInSeconds));
80+
}
81+
82+
publishEvent(new SessionCreatedEvent(this, session));
83+
84+
return session;
85+
}
86+
87+
@Override
88+
public void save(MongoSession session) {
89+
this.mongoOperations.save(Assert.requireNonNull(convertToDBObject(this.mongoSessionConverter, session),
90+
"convertToDBObject must not null!"), this.collectionName);
91+
}
92+
93+
@Override
94+
@Nullable
95+
public MongoSession findById(String id) {
96+
97+
Document sessionWrapper = findSession(id);
98+
99+
if (sessionWrapper == null) {
100+
return null;
101+
}
102+
103+
MongoSession session = convertToSession(this.mongoSessionConverter, sessionWrapper);
104+
105+
if (session != null && session.isExpired()) {
106+
publishEvent(new SessionExpiredEvent(this, session));
107+
deleteById(id);
108+
return null;
109+
}
110+
111+
return session;
112+
}
113+
114+
/**
115+
* Currently this repository allows only querying against {@code PRINCIPAL_NAME_INDEX_NAME}.
116+
*
117+
* @param indexName the name if the index (i.e. {@link FindByIndexNameSessionRepository#PRINCIPAL_NAME_INDEX_NAME})
118+
* @param indexValue the value of the index to search for.
119+
* @return sessions map
120+
*/
121+
@Override
122+
public Map<String, MongoSession> findByIndexNameAndIndexValue(String indexName, String indexValue) {
123+
124+
return Optional.ofNullable(this.mongoSessionConverter.getQueryForIndex(indexName, indexValue))
125+
.map(query -> this.mongoOperations.find(query, Document.class, this.collectionName))
126+
.orElse(Collections.emptyList()).stream()
127+
.map(dbSession -> convertToSession(this.mongoSessionConverter, dbSession))
128+
.collect(Collectors.toMap(MongoSession::getId, mapSession -> mapSession));
129+
}
130+
131+
@Override
132+
public void deleteById(String id) {
133+
134+
Optional.ofNullable(findSession(id)).ifPresent(document -> {
135+
MongoSession session = convertToSession(this.mongoSessionConverter, document);
136+
if (session != null) {
137+
publishEvent(new SessionDeletedEvent(this, session));
138+
}
139+
this.mongoOperations.remove(document, this.collectionName);
140+
});
141+
}
142+
143+
@Override
144+
public void afterPropertiesSet() {
145+
146+
IndexOperations indexOperations = this.mongoOperations.indexOps(this.collectionName);
147+
this.mongoSessionConverter.ensureIndexes(indexOperations);
148+
}
149+
150+
@Nullable
151+
private Document findSession(String id) {
152+
return this.mongoOperations.findById(id, Document.class, this.collectionName);
153+
}
154+
155+
@Override
156+
public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) {
157+
this.eventPublisher = eventPublisher;
158+
}
159+
160+
private void publishEvent(ApplicationEvent event) {
161+
162+
try {
163+
this.eventPublisher.publishEvent(event);
164+
} catch (Throwable ex) {
165+
logger.error("Error publishing " + event + ".", ex);
166+
}
167+
}
168+
169+
public void setMaxInactiveIntervalInSeconds(final Integer maxInactiveIntervalInSeconds) {
170+
this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds;
171+
}
172+
173+
public void setCollectionName(final String collectionName) {
174+
this.collectionName = collectionName;
175+
}
176+
177+
public void setMongoSessionConverter(final AbstractMongoSessionConverter mongoSessionConverter) {
178+
this.mongoSessionConverter = mongoSessionConverter;
179+
}
180+
}

src/main/java/org/springframework/session/data/mongo/MongoOperationsSessionRepository.java

Lines changed: 6 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -15,159 +15,19 @@
1515
*/
1616
package org.springframework.session.data.mongo;
1717

18-
import static org.springframework.session.data.mongo.MongoSessionUtils.*;
19-
20-
import java.time.Duration;
21-
import java.util.Collections;
22-
import java.util.Map;
23-
import java.util.Optional;
24-
import java.util.stream.Collectors;
25-
26-
import org.bson.Document;
27-
import org.slf4j.Logger;
28-
import org.slf4j.LoggerFactory;
29-
import org.springframework.beans.factory.InitializingBean;
30-
import org.springframework.context.ApplicationEvent;
31-
import org.springframework.context.ApplicationEventPublisher;
32-
import org.springframework.context.ApplicationEventPublisherAware;
3318
import org.springframework.data.mongodb.core.MongoOperations;
34-
import org.springframework.data.mongodb.core.index.IndexOperations;
35-
import org.springframework.lang.Nullable;
36-
import org.springframework.session.FindByIndexNameSessionRepository;
37-
import org.springframework.session.events.SessionCreatedEvent;
38-
import org.springframework.session.events.SessionDeletedEvent;
39-
import org.springframework.session.events.SessionExpiredEvent;
4019

4120
/**
42-
* Session repository implementation which stores sessions in Mongo. Uses {@link AbstractMongoSessionConverter} to
43-
* transform session objects from/to native Mongo representation ({@code DBObject}). Repository is also responsible for
44-
* removing expired sessions from database. Cleanup is done every minute.
21+
* This {@link org.springframework.session.FindByIndexNameSessionRepository} implementation is kept to support backwards
22+
* compatibility.
4523
*
46-
* @author Jakub Kubrynski
47-
* @author Greg Turnquist
4824
* @since 1.2
25+
* @deprecated since 2.2.0 in favor of {@link MongoIndexedSessionRepository}.
4926
*/
50-
public class MongoOperationsSessionRepository
51-
implements FindByIndexNameSessionRepository<MongoSession>, ApplicationEventPublisherAware, InitializingBean {
52-
/**
53-
* The default time period in seconds in which a session will expire.
54-
*/
55-
public static final int DEFAULT_INACTIVE_INTERVAL = 1800;
56-
/**
57-
* the default collection name for storing session.
58-
*/
59-
public static final String DEFAULT_COLLECTION_NAME = "sessions";
60-
private static final Logger logger = LoggerFactory.getLogger(MongoOperationsSessionRepository.class);
61-
private final MongoOperations mongoOperations;
62-
private Integer maxInactiveIntervalInSeconds = DEFAULT_INACTIVE_INTERVAL;
63-
private String collectionName = DEFAULT_COLLECTION_NAME;
64-
private AbstractMongoSessionConverter mongoSessionConverter = new JdkMongoSessionConverter(
65-
Duration.ofSeconds(this.maxInactiveIntervalInSeconds));
66-
private ApplicationEventPublisher eventPublisher;
27+
@Deprecated
28+
public class MongoOperationsSessionRepository extends MongoIndexedSessionRepository {
6729

6830
public MongoOperationsSessionRepository(MongoOperations mongoOperations) {
69-
this.mongoOperations = mongoOperations;
70-
}
71-
72-
@Override
73-
public MongoSession createSession() {
74-
MongoSession session = new MongoSession();
75-
if (this.maxInactiveIntervalInSeconds != null) {
76-
session.setMaxInactiveInterval(Duration.ofSeconds(this.maxInactiveIntervalInSeconds));
77-
}
78-
publishEvent(new SessionCreatedEvent(this, session));
79-
return session;
80-
}
81-
82-
@Override
83-
public void save(MongoSession session) {
84-
this.mongoOperations.save(Assert.requireNonNull(convertToDBObject(this.mongoSessionConverter, session),
85-
"convertToDBObject must not null!"), this.collectionName);
86-
}
87-
88-
@Override
89-
@Nullable
90-
public MongoSession findById(String id) {
91-
92-
Document sessionWrapper = findSession(id);
93-
94-
if (sessionWrapper == null) {
95-
return null;
96-
}
97-
98-
MongoSession session = convertToSession(this.mongoSessionConverter, sessionWrapper);
99-
100-
if (session != null && session.isExpired()) {
101-
publishEvent(new SessionExpiredEvent(this, session));
102-
deleteById(id);
103-
return null;
104-
}
105-
106-
return session;
107-
}
108-
109-
/**
110-
* Currently this repository allows only querying against {@code PRINCIPAL_NAME_INDEX_NAME}.
111-
*
112-
* @param indexName the name if the index (i.e. {@link FindByIndexNameSessionRepository#PRINCIPAL_NAME_INDEX_NAME})
113-
* @param indexValue the value of the index to search for.
114-
* @return sessions map
115-
*/
116-
@Override
117-
public Map<String, MongoSession> findByIndexNameAndIndexValue(String indexName, String indexValue) {
118-
119-
return Optional.ofNullable(this.mongoSessionConverter.getQueryForIndex(indexName, indexValue))
120-
.map(query -> this.mongoOperations.find(query, Document.class, this.collectionName))
121-
.orElse(Collections.emptyList()).stream()
122-
.map(dbSession -> convertToSession(this.mongoSessionConverter, dbSession))
123-
.collect(Collectors.toMap(MongoSession::getId, mapSession -> mapSession));
124-
}
125-
126-
@Override
127-
public void deleteById(String id) {
128-
129-
Optional.ofNullable(findSession(id)).ifPresent(document -> {
130-
MongoSession session = convertToSession(this.mongoSessionConverter, document);
131-
if (session != null) {
132-
publishEvent(new SessionDeletedEvent(this, session));
133-
}
134-
this.mongoOperations.remove(document, this.collectionName);
135-
});
136-
}
137-
138-
@Override
139-
public void afterPropertiesSet() {
140-
IndexOperations indexOperations = this.mongoOperations.indexOps(this.collectionName);
141-
this.mongoSessionConverter.ensureIndexes(indexOperations);
142-
}
143-
144-
@Nullable
145-
private Document findSession(String id) {
146-
return this.mongoOperations.findById(id, Document.class, this.collectionName);
147-
}
148-
149-
@Override
150-
public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) {
151-
this.eventPublisher = eventPublisher;
152-
}
153-
154-
private void publishEvent(ApplicationEvent event) {
155-
try {
156-
this.eventPublisher.publishEvent(event);
157-
} catch (Throwable ex) {
158-
logger.error("Error publishing " + event + ".", ex);
159-
}
160-
}
161-
162-
public void setMaxInactiveIntervalInSeconds(final Integer maxInactiveIntervalInSeconds) {
163-
this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds;
164-
}
165-
166-
public void setCollectionName(final String collectionName) {
167-
this.collectionName = collectionName;
168-
}
169-
170-
public void setMongoSessionConverter(final AbstractMongoSessionConverter mongoSessionConverter) {
171-
this.mongoSessionConverter = mongoSessionConverter;
31+
super(mongoOperations);
17232
}
17333
}

src/main/java/org/springframework/session/data/mongo/MongoSession.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public class MongoSession implements Session {
5050
private Map<String, Object> attrs = new HashMap<>();
5151

5252
public MongoSession() {
53-
this(MongoOperationsSessionRepository.DEFAULT_INACTIVE_INTERVAL);
53+
this(MongoIndexedSessionRepository.DEFAULT_INACTIVE_INTERVAL);
5454
}
5555

5656
public MongoSession(long maxInactiveIntervalInSeconds) {
@@ -147,7 +147,7 @@ public boolean equals(Object o) {
147147
public int hashCode() {
148148
return Objects.hash(id);
149149
}
150-
150+
151151
public String getId() {
152152
return this.id;
153153
}

src/main/java/org/springframework/session/data/mongo/config/annotation/web/http/EnableMongoHttpSession.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
import org.springframework.context.annotation.Configuration;
2525
import org.springframework.context.annotation.Import;
26-
import org.springframework.session.data.mongo.MongoOperationsSessionRepository;
26+
import org.springframework.session.data.mongo.MongoIndexedSessionRepository;
2727

2828
/**
2929
* Add this annotation to a {@code @Configuration} class to expose the SessionRepositoryFilter as a bean named
@@ -59,12 +59,12 @@
5959
*
6060
* @return default max inactive interval in seconds
6161
*/
62-
int maxInactiveIntervalInSeconds() default MongoOperationsSessionRepository.DEFAULT_INACTIVE_INTERVAL;
62+
int maxInactiveIntervalInSeconds() default MongoIndexedSessionRepository.DEFAULT_INACTIVE_INTERVAL;
6363

6464
/**
6565
* The collection name to use.
6666
*
6767
* @return name of the collection to store session
6868
*/
69-
String collectionName() default MongoOperationsSessionRepository.DEFAULT_COLLECTION_NAME;
69+
String collectionName() default MongoIndexedSessionRepository.DEFAULT_COLLECTION_NAME;
7070
}

0 commit comments

Comments
 (0)