diff --git a/src/main/java/org/springframework/session/data/mongo/MongoOperationsSessionRepository.java b/src/main/java/org/springframework/session/data/mongo/MongoOperationsSessionRepository.java index b27d817..49593fe 100644 --- a/src/main/java/org/springframework/session/data/mongo/MongoOperationsSessionRepository.java +++ b/src/main/java/org/springframework/session/data/mongo/MongoOperationsSessionRepository.java @@ -28,10 +28,18 @@ import java.util.Optional; import javax.annotation.PostConstruct; import org.bson.Document; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.index.IndexOperations; import org.springframework.data.mongodb.core.query.Query; import org.springframework.session.FindByIndexNameSessionRepository; +import org.springframework.session.events.SessionCreatedEvent; +import org.springframework.session.events.SessionDeletedEvent; +import org.springframework.session.events.SessionExpiredEvent; import com.mongodb.DBObject; @@ -48,7 +56,7 @@ import com.mongodb.DBObject; * @since 1.2 */ public class MongoOperationsSessionRepository - implements FindByIndexNameSessionRepository { + implements FindByIndexNameSessionRepository, ApplicationEventPublisherAware { /** * The default time period in seconds in which a session will expire. @@ -60,12 +68,15 @@ public class MongoOperationsSessionRepository */ public static final String DEFAULT_COLLECTION_NAME = "sessions"; + private static final Logger logger = LoggerFactory.getLogger(MongoOperationsSessionRepository.class); + private final MongoOperations mongoOperations; private Integer maxInactiveIntervalInSeconds = DEFAULT_INACTIVE_INTERVAL; private String collectionName = DEFAULT_COLLECTION_NAME; private AbstractMongoSessionConverter mongoSessionConverter = new JdkMongoSessionConverter( Duration.ofSeconds(this.maxInactiveIntervalInSeconds)); + private ApplicationEventPublisher eventPublisher; public MongoOperationsSessionRepository(MongoOperations mongoOperations) { this.mongoOperations = mongoOperations; @@ -79,6 +90,8 @@ public class MongoOperationsSessionRepository if (this.maxInactiveIntervalInSeconds != null) { session.setMaxInactiveInterval(Duration.ofSeconds(this.maxInactiveIntervalInSeconds)); } + + publishEvent(new SessionCreatedEvent(this, session)); return session; } @@ -102,6 +115,7 @@ public class MongoOperationsSessionRepository MongoSession session = convertToSession(this.mongoSessionConverter, sessionWrapper); if (session.isExpired()) { + publishEvent(new SessionExpiredEvent(this, session)); deleteById(id); return null; } @@ -142,7 +156,10 @@ public class MongoOperationsSessionRepository @Override public void deleteById(String id) { Optional.ofNullable(findSession(id)) - .ifPresent(document -> this.mongoOperations.remove(document, this.collectionName)); + .ifPresent(document -> { + publishEvent(new SessionDeletedEvent(this, convertToSession(this.mongoSessionConverter, document))); + this.mongoOperations.remove(document, this.collectionName); + }); } @PostConstruct @@ -167,4 +184,19 @@ public class MongoOperationsSessionRepository public void setCollectionName(String collectionName) { this.collectionName = collectionName; } + + @Override + public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) { + this.eventPublisher = eventPublisher; + } + + private void publishEvent(ApplicationEvent event) { + try { + this.eventPublisher.publishEvent(event); + } + catch (Throwable ex) { + logger.error("Error publishing " + event + ".", ex); + } + } + } diff --git a/src/main/java/org/springframework/session/data/mongo/ReactiveMongoOperationsSessionRepository.java b/src/main/java/org/springframework/session/data/mongo/ReactiveMongoOperationsSessionRepository.java index 0ad49b7..da4882f 100644 --- a/src/main/java/org/springframework/session/data/mongo/ReactiveMongoOperationsSessionRepository.java +++ b/src/main/java/org/springframework/session/data/mongo/ReactiveMongoOperationsSessionRepository.java @@ -22,16 +22,24 @@ import java.time.Duration; import javax.annotation.PostConstruct; import org.bson.Document; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import reactor.core.publisher.Mono; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.ReactiveMongoOperations; import org.springframework.data.mongodb.core.index.IndexOperations; import org.springframework.session.ReactiveSessionRepository; +import org.springframework.session.events.SessionCreatedEvent; +import org.springframework.session.events.SessionDeletedEvent; /** * @author Greg Turnquist */ -public class ReactiveMongoOperationsSessionRepository implements ReactiveSessionRepository { +public class ReactiveMongoOperationsSessionRepository + implements ReactiveSessionRepository, ApplicationEventPublisherAware { /** * The default time period in seconds in which a session will expire. @@ -43,6 +51,8 @@ public class ReactiveMongoOperationsSessionRepository implements ReactiveSession */ public static final String DEFAULT_COLLECTION_NAME = "sessions"; + private static final Logger logger = LoggerFactory.getLogger(ReactiveMongoOperationsSessionRepository.class); + private final ReactiveMongoOperations mongoOperations; private Integer maxInactiveIntervalInSeconds = DEFAULT_INACTIVE_INTERVAL; @@ -51,6 +61,7 @@ public class ReactiveMongoOperationsSessionRepository implements ReactiveSession Duration.ofSeconds(this.maxInactiveIntervalInSeconds)); private MongoOperations blockingMongoOperations; + private ApplicationEventPublisher eventPublisher; public ReactiveMongoOperationsSessionRepository(ReactiveMongoOperations mongoOperations) { this.mongoOperations = mongoOperations; @@ -73,6 +84,10 @@ public class ReactiveMongoOperationsSessionRepository implements ReactiveSession return Mono.justOrEmpty(this.maxInactiveIntervalInSeconds) .map(MongoSession::new) + .map(mongoSession -> { + publishEvent(new SessionCreatedEvent(this, mongoSession)); + return mongoSession; + }) .switchIfEmpty(Mono.just(new MongoSession())); } @@ -120,7 +135,12 @@ public class ReactiveMongoOperationsSessionRepository implements ReactiveSession */ @Override public Mono deleteById(String id) { - return this.mongoOperations.remove(findSession(id), this.collectionName).then(); + + return findSession(id) + .flatMap(document -> this.mongoOperations.remove(document, this.collectionName).then(Mono.just(document))) + .map(document -> convertToSession(this.mongoSessionConverter, document)) + .map(mongoSession -> Mono.fromRunnable(() -> publishEvent(new SessionDeletedEvent(this, mongoSession)))) + .then(); } /** @@ -167,4 +187,18 @@ public class ReactiveMongoOperationsSessionRepository implements ReactiveSession public void setBlockingMongoOperations(MongoOperations blockingMongoOperations) { this.blockingMongoOperations = blockingMongoOperations; } + + @Override + public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) { + this.eventPublisher = eventPublisher; + } + + private void publishEvent(ApplicationEvent event) { + try { + this.eventPublisher.publishEvent(event); + } + catch (Throwable ex) { + logger.error("Error publishing " + event + ".", ex); + } + } } diff --git a/src/test/java/org/springframework/session/data/mongo/MongoOperationsSessionRepositoryTest.java b/src/test/java/org/springframework/session/data/mongo/MongoOperationsSessionRepositoryTest.java index 6279b3c..5665327 100644 --- a/src/test/java/org/springframework/session/data/mongo/MongoOperationsSessionRepositoryTest.java +++ b/src/test/java/org/springframework/session/data/mongo/MongoOperationsSessionRepositoryTest.java @@ -141,6 +141,7 @@ public class MongoOperationsSessionRepositoryTest { given(session.isExpired()).willReturn(true); given(this.converter.convert(sessionDocument, TypeDescriptor.valueOf(Document.class), TypeDescriptor.valueOf(MongoSession.class))).willReturn(session); + given(session.getId()).willReturn("sessionId"); // when this.repository.findById(sessionId); @@ -156,7 +157,12 @@ public class MongoOperationsSessionRepositoryTest { String sessionId = UUID.randomUUID().toString(); Document sessionDocument = new Document(); + sessionDocument.put("id", sessionId); + MongoSession mongoSession = new MongoSession(sessionId, MongoOperationsSessionRepository.DEFAULT_INACTIVE_INTERVAL); + + given(this.converter.convert(sessionDocument, TypeDescriptor.valueOf(Document.class), + TypeDescriptor.valueOf(MongoSession.class))).willReturn(mongoSession); given(this.mongoOperations.findById(eq(sessionId), eq(Document.class), eq(MongoOperationsSessionRepository.DEFAULT_COLLECTION_NAME))).willReturn(sessionDocument);