diff --git a/src/main/java/dev/mednikov/social/connections/events/FollowerCreatedEvent.java b/src/main/java/dev/mednikov/social/connections/events/FollowerCreatedEvent.java new file mode 100644 index 0000000..aaeea45 --- /dev/null +++ b/src/main/java/dev/mednikov/social/connections/events/FollowerCreatedEvent.java @@ -0,0 +1,19 @@ +package dev.mednikov.social.connections.events; + +import dev.mednikov.social.connections.models.Follower; +import org.springframework.context.ApplicationEvent; + +public final class FollowerCreatedEvent extends ApplicationEvent { + + private final Follower follower; + + public FollowerCreatedEvent(Object source, Follower follower) { + super(source); + this.follower = follower; + } + + public Follower getFollower() { + return follower; + } + +} diff --git a/src/main/java/dev/mednikov/social/connections/events/FollowerDeletedEvent.java b/src/main/java/dev/mednikov/social/connections/events/FollowerDeletedEvent.java new file mode 100644 index 0000000..ab44128 --- /dev/null +++ b/src/main/java/dev/mednikov/social/connections/events/FollowerDeletedEvent.java @@ -0,0 +1,23 @@ +package dev.mednikov.social.connections.events; + +import org.springframework.context.ApplicationEvent; + +public final class FollowerDeletedEvent extends ApplicationEvent { + + private final Long followerUserId; + private final Long followedUserId; + + public FollowerDeletedEvent(Object source, Long followerUserId, Long followedUserId) { + super(source); + this.followerUserId = followerUserId; + this.followedUserId = followedUserId; + } + + public Long getFollowerUserId() { + return followerUserId; + } + + public Long getFollowedUserId() { + return followedUserId; + } +} diff --git a/src/main/java/dev/mednikov/social/connections/messaging/AnalyticsEvent.java b/src/main/java/dev/mednikov/social/connections/messaging/AnalyticsEvent.java new file mode 100644 index 0000000..0503b15 --- /dev/null +++ b/src/main/java/dev/mednikov/social/connections/messaging/AnalyticsEvent.java @@ -0,0 +1,42 @@ +package dev.mednikov.social.connections.messaging; + +import java.time.LocalDateTime; + +final class AnalyticsEvent { + + private String userId; + private String eventType; + private String timestamp; + + AnalyticsEvent (){} + + AnalyticsEvent(Long userId, String eventType){ + this.userId = userId.toString(); + this.eventType = eventType; + this.timestamp = LocalDateTime.now().toString(); + } + + String getUserId() { + return userId; + } + + void setUserId(String userId) { + this.userId = userId; + } + + String getEventType() { + return eventType; + } + + void setEventType(String eventType) { + this.eventType = eventType; + } + + String getTimestamp() { + return timestamp; + } + + void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } +} diff --git a/src/main/java/dev/mednikov/social/connections/messaging/MessageService.java b/src/main/java/dev/mednikov/social/connections/messaging/MessageService.java new file mode 100644 index 0000000..8e10bc3 --- /dev/null +++ b/src/main/java/dev/mednikov/social/connections/messaging/MessageService.java @@ -0,0 +1,54 @@ +package dev.mednikov.social.connections.messaging; + +import com.fasterxml.jackson.databind.ObjectMapper; +import dev.mednikov.social.connections.events.FollowerCreatedEvent; +import dev.mednikov.social.connections.events.FollowerDeletedEvent; +import dev.mednikov.social.connections.models.Follower; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +@Component +public class MessageService { + + private final static Logger logger = LoggerFactory.getLogger(MessageService.class); + + private final ObjectMapper objectMapper; + private final RabbitTemplate rabbitTemplate; + + public MessageService(ObjectMapper objectMapper, RabbitTemplate rabbitTemplate) { + this.objectMapper = objectMapper; + this.rabbitTemplate = rabbitTemplate; + } + + @EventListener + @Async + public void onFollowerCreatedEventListener(FollowerCreatedEvent event) { + Follower follower = event.getFollower(); + Long userId = follower.getOwner().getId(); + AnalyticsEvent analyticsEvent = new AnalyticsEvent(userId, "followers_created"); + try { + String payload = this.objectMapper.writeValueAsString(analyticsEvent); + this.rabbitTemplate.convertAndSend("", "social_events", payload); + logger.info("Event collector: follower created event sent"); + } catch (Exception ex){ + logger.error(ex.getMessage()); + } + } + + @EventListener + @Async + public void onFollowerDeletedEventListener(FollowerDeletedEvent event) { + AnalyticsEvent analyticsEvent = new AnalyticsEvent(event.getFollowerUserId(), "followers_deleted"); + try { + String payload = this.objectMapper.writeValueAsString(analyticsEvent); + this.rabbitTemplate.convertAndSend("", "social_events", payload); + logger.info("Event collector: follower deleted event sent"); + } catch (Exception ex){ + logger.error(ex.getMessage()); + } + } +} diff --git a/src/main/java/dev/mednikov/social/connections/services/FollowerServiceImpl.java b/src/main/java/dev/mednikov/social/connections/services/FollowerServiceImpl.java index 0e1be70..e0ab597 100644 --- a/src/main/java/dev/mednikov/social/connections/services/FollowerServiceImpl.java +++ b/src/main/java/dev/mednikov/social/connections/services/FollowerServiceImpl.java @@ -3,6 +3,8 @@ package dev.mednikov.social.connections.services; import dev.mednikov.social.connections.domain.CreateFollowerRequestDto; import dev.mednikov.social.connections.domain.FollowerDto; import dev.mednikov.social.connections.domain.FollowerDtoMapper; +import dev.mednikov.social.connections.events.FollowerCreatedEvent; +import dev.mednikov.social.connections.events.FollowerDeletedEvent; import dev.mednikov.social.connections.exceptions.FollowerAlreadyExistsException; import dev.mednikov.social.connections.exceptions.UserDoesNotExistException; import dev.mednikov.social.connections.models.Follower; @@ -10,6 +12,7 @@ import dev.mednikov.social.connections.models.User; import dev.mednikov.social.connections.repositories.FollowerRepository; import dev.mednikov.social.connections.repositories.IdentifierGenerator; import dev.mednikov.social.connections.repositories.UserRepository; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import java.util.Optional; @@ -22,14 +25,17 @@ public class FollowerServiceImpl implements FollowerService { private final FollowerRepository followerRepository; private final UserRepository userRepository; private final IdentifierGenerator identifierGenerator; + private final ApplicationEventPublisher eventPublisher; public FollowerServiceImpl( FollowerRepository followerRepository, UserRepository userRepository, - IdentifierGenerator identifierGenerator) { + IdentifierGenerator identifierGenerator, + ApplicationEventPublisher eventPublisher) { this.followerRepository = followerRepository; this.userRepository = userRepository; this.identifierGenerator = identifierGenerator; + this.eventPublisher = eventPublisher; } @Override @@ -61,13 +67,22 @@ public class FollowerServiceImpl implements FollowerService { follower.setId(this.identifierGenerator.getNextId()); Follower savedFollower = this.followerRepository.save(follower); - + FollowerCreatedEvent event = new FollowerCreatedEvent(this, savedFollower); + this.eventPublisher.publishEvent(event); return mapper.apply(savedFollower); } @Override public void deleteFollower(Long id) { - this.followerRepository.deleteById(id); + Optional result = this.followerRepository.findById(id); + if (result.isPresent()) { + Follower follower = result.get(); + Long followerUserId = follower.getOwner().getId(); + Long followedUserId = follower.getFollowedUser().getId(); + FollowerDeletedEvent event = new FollowerDeletedEvent(this, followerUserId, followedUserId); + this.eventPublisher.publishEvent(event); + this.followerRepository.deleteById(id); + } } }