diff --git a/README.md b/README.md index e81cc65..8646df0 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,8 @@ # msa-ddd-eventsourcing msa,ddd,eventsourcing java example + +## Run application + +```$xslt +./run.sh +``` diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..e0264f6 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,13 @@ +version: "3.1" + +services: + mongodb: + image: mongo:latest + ports: + - 27017:27017 + + rabbitmq: + image: rabbitmq:3.5.3-management + ports: + - 5672:5672 + - 15672:15672 diff --git a/run.sh b/run.sh new file mode 100644 index 0000000..36ba926 --- /dev/null +++ b/run.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +# Setup mongodb, rabbitmq +docker-compose up -d + +# build & run application +./gradle build && java -jar build/libs/sample-msa-0.0.1.jar diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/common/AggregateRepository.java b/src/main/java/com/itchain/samplemsa/samplemsa/common/AggregateRepository.java index 34143bb..1b60520 100644 --- a/src/main/java/com/itchain/samplemsa/samplemsa/common/AggregateRepository.java +++ b/src/main/java/com/itchain/samplemsa/samplemsa/common/AggregateRepository.java @@ -1,16 +1,18 @@ package com.itchain.samplemsa.samplemsa.common; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; +import org.springframework.test.context.ActiveProfiles; import java.lang.reflect.InvocationTargetException; import java.util.List; @Component public class AggregateRepository { - private EventRepository eventRepository; + // change it to eventStorageService on production. @Autowired public AggregateRepository(EventRepository eventRepository){ this.eventRepository = eventRepository; diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/common/Event.java b/src/main/java/com/itchain/samplemsa/samplemsa/common/Event.java index 500d36a..e92abc4 100644 --- a/src/main/java/com/itchain/samplemsa/samplemsa/common/Event.java +++ b/src/main/java/com/itchain/samplemsa/samplemsa/common/Event.java @@ -6,5 +6,4 @@ public interface Event { String getID(); - } diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/customer/CustomerRepository.java b/src/main/java/com/itchain/samplemsa/samplemsa/customer/CustomerRepository.java index c6c2c25..abdb069 100644 --- a/src/main/java/com/itchain/samplemsa/samplemsa/customer/CustomerRepository.java +++ b/src/main/java/com/itchain/samplemsa/samplemsa/customer/CustomerRepository.java @@ -1,13 +1,16 @@ package com.itchain.samplemsa.samplemsa.customer; import com.itchain.samplemsa.samplemsa.common.AggregateRepository; +import com.itchain.samplemsa.samplemsa.common.Event; import com.itchain.samplemsa.samplemsa.common.EventRepository; import com.itchain.samplemsa.samplemsa.customer.domain.CustomerInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; +import org.springframework.test.context.ActiveProfiles; @Component public class CustomerRepository extends AggregateRepository { - public CustomerRepository(EventRepository eventRepository) { super(eventRepository); } diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/customer/domain/dto/CustomerInfoDTO.java b/src/main/java/com/itchain/samplemsa/samplemsa/customer/domain/dto/CustomerInfoDTO.java index a3e487c..0eabdae 100644 --- a/src/main/java/com/itchain/samplemsa/samplemsa/customer/domain/dto/CustomerInfoDTO.java +++ b/src/main/java/com/itchain/samplemsa/samplemsa/customer/domain/dto/CustomerInfoDTO.java @@ -2,9 +2,11 @@ import lombok.AllArgsConstructor; import lombok.Data; +import lombok.Getter; @AllArgsConstructor @Data +@Getter public class CustomerInfoDTO { private String id; } \ No newline at end of file diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/customer/port/adapter/service/CustomerServiceImpl.java b/src/main/java/com/itchain/samplemsa/samplemsa/customer/port/adapter/service/CustomerServiceImpl.java index 1bf127b..390306f 100644 --- a/src/main/java/com/itchain/samplemsa/samplemsa/customer/port/adapter/service/CustomerServiceImpl.java +++ b/src/main/java/com/itchain/samplemsa/samplemsa/customer/port/adapter/service/CustomerServiceImpl.java @@ -3,9 +3,11 @@ import com.itchain.samplemsa.samplemsa.customer.domain.CustomerService; import com.itchain.samplemsa.samplemsa.customer.domain.dto.CustomerInfoDTO; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; import java.util.List; +@Component public class CustomerServiceImpl implements CustomerService { @Autowired private HttpCustomerAdapter httpCustomerAdapter; diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/customer/port/adapter/service/HttpCustomerAdapter.java b/src/main/java/com/itchain/samplemsa/samplemsa/customer/port/adapter/service/HttpCustomerAdapter.java index 602c569..79756bb 100644 --- a/src/main/java/com/itchain/samplemsa/samplemsa/customer/port/adapter/service/HttpCustomerAdapter.java +++ b/src/main/java/com/itchain/samplemsa/samplemsa/customer/port/adapter/service/HttpCustomerAdapter.java @@ -1,11 +1,13 @@ package com.itchain.samplemsa.samplemsa.customer.port.adapter.service; import com.itchain.samplemsa.samplemsa.customer.domain.dto.CustomerInfoDTO; +import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; import java.util.Arrays; import java.util.List; +@Component public class HttpCustomerAdapter implements CustomerAdapter{ private static final String HOST = "localhost"; private static final String PORT = "8080"; diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/customer/web/controller/CustomerController.java b/src/main/java/com/itchain/samplemsa/samplemsa/customer/web/controller/CustomerController.java index 613eeb5..fdaa36d 100644 --- a/src/main/java/com/itchain/samplemsa/samplemsa/customer/web/controller/CustomerController.java +++ b/src/main/java/com/itchain/samplemsa/samplemsa/customer/web/controller/CustomerController.java @@ -1,39 +1,39 @@ -package com.itchain.samplemsa.samplemsa.customer.web.controller; - -import com.itchain.samplemsa.samplemsa.customer.domain.CustomerInfo; -import com.itchain.samplemsa.samplemsa.customer.domain.dto.CustomerInfoDTO; -import com.itchain.samplemsa.samplemsa.customer.application.CustomerApplicationService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; - -@RestController -public class CustomerController { - @Autowired - private CustomerApplicationService customerService; - - @RequestMapping(value = "/customers/{id}", method = RequestMethod.GET) - @ResponseBody - public CustomerInfo getCustomer(@PathVariable("id") String id) { - return customerService.getCustomer(id); - } - - @RequestMapping(value = "/customers/register-customer/{customerInfo}", method = RequestMethod.POST) - public void registerCustomer(@RequestParam(required = true) CustomerInfoDTO customerInfo) { - customerService.registerCustomer(customerInfo.getId(), customerInfo.getPw(), customerInfo.getName(), customerInfo.getAddress()); - } - - @RequestMapping(value = "/customers/remove-customer/{customerInfo}", method = RequestMethod.POST) - public void withdrawCustomer(@RequestParam(required = true) CustomerInfoDTO customerInfo) { - customerService.withdrawCustomer(customerInfo.getId(), customerInfo.getPw()); - } - - @RequestMapping(value = "/customers/edit-customer/{customerInfo}", method = RequestMethod.POST) - public void updateCustomer(@RequestParam(required = true) CustomerInfoDTO customerInfo) { - customerService.updateCustomer(customerInfo.getId(), customerInfo.getPw(), customerInfo.getName(), customerInfo.getAddress()); - } - - @RequestMapping(value = "/customers/get-point/{id}", method = RequestMethod.POST) - public int getCustomerPoint(@RequestParam(required = true) String id) { - return customerService.getCustomerPoint(id); - } -} +//package com.itchain.samplemsa.samplemsa.customer.web.controller; +// +//import com.itchain.samplemsa.samplemsa.customer.domain.CustomerInfo; +//import com.itchain.samplemsa.samplemsa.customer.domain.dto.CustomerInfoDTO; +//import com.itchain.samplemsa.samplemsa.customer.application.CustomerApplicationService; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.web.bind.annotation.*; +// +//@RestController +//public class CustomerController { +// @Autowired +// private CustomerApplicationService customerService; +// +// @RequestMapping(value = "/customers/{id}", method = RequestMethod.GET) +// @ResponseBody +// public CustomerInfo getCustomer(@PathVariable("id") String id) { +// return customerService.getCustomer(id); +// } +// +// @RequestMapping(value = "/customers/register-customer/{customerInfo}", method = RequestMethod.POST) +// public void registerCustomer(@RequestParam(required = true) CustomerInfoDTO customerInfo) { +// customerService.registerCustomer(customerInfo.getId(), customerInfo.getPw(), customerInfo.getName(), customerInfo.getAddress()); +// } +// +// @RequestMapping(value = "/customers/remove-customer/{customerInfo}", method = RequestMethod.POST) +// public void withdrawCustomer(@RequestParam(required = true) CustomerInfoDTO customerInfo) { +// customerService.withdrawCustomer(customerInfo.getId(), customerInfo.getPw()); +// } +// +// @RequestMapping(value = "/customers/edit-customer/{customerInfo}", method = RequestMethod.POST) +// public void updateCustomer(@RequestParam(required = true) CustomerInfoDTO customerInfo) { +// customerService.updateCustomer(customerInfo.getId(), customerInfo.getPw(), customerInfo.getName(), customerInfo.getAddress()); +// } +// +// @RequestMapping(value = "/customers/get-point/{id}", method = RequestMethod.POST) +// public int getCustomerPoint(@RequestParam(required = true) String id) { +// return customerService.getCustomerPoint(id); +// } +//} diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/delivery/DeliveryRepository.java b/src/main/java/com/itchain/samplemsa/samplemsa/delivery/DeliveryRepository.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/delivery/DeliveryService.java b/src/main/java/com/itchain/samplemsa/samplemsa/delivery/DeliveryService.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/delivery/controller/DeliveryController.java b/src/main/java/com/itchain/samplemsa/samplemsa/delivery/controller/DeliveryController.java old mode 100644 new mode 100755 index d37e8e3..8f75086 --- a/src/main/java/com/itchain/samplemsa/samplemsa/delivery/controller/DeliveryController.java +++ b/src/main/java/com/itchain/samplemsa/samplemsa/delivery/controller/DeliveryController.java @@ -1,4 +1,4 @@ -//package com.itchain.samplemsa.samplemsa.delivery.controller; +package com.itchain.samplemsa.samplemsa.delivery.controller;//package com.itchain.samplemsa.samplemsa.delivery.controller; // //import com.itchain.samplemsa.samplemsa.delivery.domain.Delivery; //import com.itchain.samplemsa.samplemsa.delivery.domain.TradeStatus; diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/delivery/domain/DeliverInfoService.java b/src/main/java/com/itchain/samplemsa/samplemsa/delivery/domain/DeliverInfoService.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/delivery/domain/DeliverInfoServiceImpl.java b/src/main/java/com/itchain/samplemsa/samplemsa/delivery/domain/DeliverInfoServiceImpl.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/delivery/domain/DeliverStatus.java b/src/main/java/com/itchain/samplemsa/samplemsa/delivery/domain/DeliverStatus.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/delivery/domain/Delivery.java b/src/main/java/com/itchain/samplemsa/samplemsa/delivery/domain/Delivery.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/delivery/domain/QueryService.java b/src/main/java/com/itchain/samplemsa/samplemsa/delivery/domain/QueryService.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/delivery/domain/dto/DeliveryDTO.java b/src/main/java/com/itchain/samplemsa/samplemsa/delivery/domain/dto/DeliveryDTO.java old mode 100644 new mode 100755 index 8178cad..1d644ca --- a/src/main/java/com/itchain/samplemsa/samplemsa/delivery/domain/dto/DeliveryDTO.java +++ b/src/main/java/com/itchain/samplemsa/samplemsa/delivery/domain/dto/DeliveryDTO.java @@ -3,9 +3,11 @@ import com.itchain.samplemsa.samplemsa.delivery.domain.DeliverStatus; import lombok.AllArgsConstructor; import lombok.Data; +import lombok.Getter; @AllArgsConstructor @Data +@Getter public class DeliveryDTO { private String id; private String productId; diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/delivery/domain/dto/TradeInfoDTO.java b/src/main/java/com/itchain/samplemsa/samplemsa/delivery/domain/dto/TradeInfoDTO.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/delivery/domain/event/DeliveryInfoChangedEvent.java b/src/main/java/com/itchain/samplemsa/samplemsa/delivery/domain/event/DeliveryInfoChangedEvent.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/delivery/domain/event/DeliveryInfoCreatedEvent.java b/src/main/java/com/itchain/samplemsa/samplemsa/delivery/domain/event/DeliveryInfoCreatedEvent.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/delivery/service/DeliveryApplicationService.java b/src/main/java/com/itchain/samplemsa/samplemsa/delivery/service/DeliveryApplicationService.java old mode 100644 new mode 100755 diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/delivery/service/DeliveryApplicationServiceImpl.java b/src/main/java/com/itchain/samplemsa/samplemsa/delivery/service/DeliveryApplicationServiceImpl.java old mode 100644 new mode 100755 index c141290..a422f1c --- a/src/main/java/com/itchain/samplemsa/samplemsa/delivery/service/DeliveryApplicationServiceImpl.java +++ b/src/main/java/com/itchain/samplemsa/samplemsa/delivery/service/DeliveryApplicationServiceImpl.java @@ -1,4 +1,4 @@ -//package com.itchain.samplemsa.samplemsa.delivery.application; +package com.itchain.samplemsa.samplemsa.delivery.service;//package com.itchain.samplemsa.samplemsa.delivery.application; // //import com.itchain.samplemsa.samplemsa.common.AggregateRepository; //import com.itchain.samplemsa.samplemsa.common.Event; diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/eventstore/EventStorageService.java b/src/main/java/com/itchain/samplemsa/samplemsa/eventstore/EventStorageService.java new file mode 100644 index 0000000..dcd56e3 --- /dev/null +++ b/src/main/java/com/itchain/samplemsa/samplemsa/eventstore/EventStorageService.java @@ -0,0 +1,39 @@ +package com.itchain.samplemsa.samplemsa.eventstore; + +import com.itchain.samplemsa.samplemsa.common.Event; +import com.itchain.samplemsa.samplemsa.common.EventRepository; +import com.itchain.samplemsa.samplemsa.eventstore.domain.EntityWithIdAndEventList; +import com.itchain.samplemsa.samplemsa.eventstore.domain.Store; +import com.itchain.samplemsa.samplemsa.eventstore.exception.EventIDEmptyException; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +public class EventStorageService implements EventRepository { + private Store store; + + public EventStorageService(Store store) { + this.store = store; + } + + @Override + public void save(Event event) { + if (isEventIDEmpty(event)) { + throw new EventIDEmptyException(); + } + + store.save(event.getID(), event); + } + + private boolean isEventIDEmpty(Event event) { + String eventID = event.getID(); + return eventID == null || eventID.isEmpty(); + } + + @Override + public List load(String id) { + EntityWithIdAndEventList entity = store.load(id); + return entity.getEventList(); + } +} diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/eventstore/MongodbStore.java b/src/main/java/com/itchain/samplemsa/samplemsa/eventstore/MongodbStore.java new file mode 100644 index 0000000..67a092c --- /dev/null +++ b/src/main/java/com/itchain/samplemsa/samplemsa/eventstore/MongodbStore.java @@ -0,0 +1,42 @@ +package com.itchain.samplemsa.samplemsa.eventstore; + +import com.itchain.samplemsa.samplemsa.common.Event; +import com.itchain.samplemsa.samplemsa.eventstore.domain.EntityWithIdAndEventList; +import com.itchain.samplemsa.samplemsa.eventstore.domain.Store; +import com.itchain.samplemsa.samplemsa.eventstore.domain.MongoClient; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Optional; + +@Component +@Transactional +public class MongodbStore implements Store { + @Autowired + MongoClient client; + + @Override + public EntityWithIdAndEventList save(String aggregateID, Event event) { + EntityWithIdAndEventList entity = load(aggregateID); + if (entity == null) { + entity = new EntityWithIdAndEventList(); + } + + entity.addEvent(event); + + return client.save(entity); + } + + @Override + public EntityWithIdAndEventList load(String aggregateID) { + Optional option = client.findById(aggregateID); + if (!option.isPresent()) { + return null; + } + return option.get(); + } +} diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/eventstore/domain/EntityWithIdAndEventList.java b/src/main/java/com/itchain/samplemsa/samplemsa/eventstore/domain/EntityWithIdAndEventList.java new file mode 100644 index 0000000..b97fa89 --- /dev/null +++ b/src/main/java/com/itchain/samplemsa/samplemsa/eventstore/domain/EntityWithIdAndEventList.java @@ -0,0 +1,32 @@ +package com.itchain.samplemsa.samplemsa.eventstore.domain; + +import com.itchain.samplemsa.samplemsa.common.Event; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +import java.util.ArrayList; +import java.util.List; + +@Document(collection="event_entity") +@NoArgsConstructor +@ToString +@Getter +@Setter +public class EntityWithIdAndEventList { + @Id + private String id; + + private List eventList = new ArrayList<>(); + + public void addEvent(Event event) { + this.eventList.add(event); + } + + public void appendEventList(List eventList) { + this.eventList.addAll(eventList); + } +} diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/eventstore/domain/MongoClient.java b/src/main/java/com/itchain/samplemsa/samplemsa/eventstore/domain/MongoClient.java new file mode 100644 index 0000000..958535e --- /dev/null +++ b/src/main/java/com/itchain/samplemsa/samplemsa/eventstore/domain/MongoClient.java @@ -0,0 +1,9 @@ +package com.itchain.samplemsa.samplemsa.eventstore.domain; + +import org.springframework.data.mongodb.repository.MongoRepository; +import org.springframework.stereotype.Component; +import org.springframework.stereotype.Repository; + +@Repository +public interface MongoClient extends MongoRepository { +} diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/eventstore/domain/Store.java b/src/main/java/com/itchain/samplemsa/samplemsa/eventstore/domain/Store.java new file mode 100644 index 0000000..a19c8b3 --- /dev/null +++ b/src/main/java/com/itchain/samplemsa/samplemsa/eventstore/domain/Store.java @@ -0,0 +1,8 @@ +package com.itchain.samplemsa.samplemsa.eventstore.domain; + +import com.itchain.samplemsa.samplemsa.common.Event; + +public interface Store { + EntityWithIdAndEventList save(String aggregateID, Event event); + EntityWithIdAndEventList load(String aggregateID); +} diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/eventstore/exception/EventIDEmptyException.java b/src/main/java/com/itchain/samplemsa/samplemsa/eventstore/exception/EventIDEmptyException.java new file mode 100644 index 0000000..65a21a6 --- /dev/null +++ b/src/main/java/com/itchain/samplemsa/samplemsa/eventstore/exception/EventIDEmptyException.java @@ -0,0 +1,7 @@ +package com.itchain.samplemsa.samplemsa.eventstore.exception; + +public class EventIDEmptyException extends EventStoreException{ + public EventIDEmptyException() { + super("Event ID is empty"); + } +} diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/eventstore/exception/EventStoreException.java b/src/main/java/com/itchain/samplemsa/samplemsa/eventstore/exception/EventStoreException.java new file mode 100644 index 0000000..7cfeafd --- /dev/null +++ b/src/main/java/com/itchain/samplemsa/samplemsa/eventstore/exception/EventStoreException.java @@ -0,0 +1,11 @@ +package com.itchain.samplemsa.samplemsa.eventstore.exception; + +public class EventStoreException extends RuntimeException { + public EventStoreException() { + super(); + } + + public EventStoreException(String message) { + super(message); + } +} diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/pubsub/Publisher.java b/src/main/java/com/itchain/samplemsa/samplemsa/pubsub/Publisher.java new file mode 100644 index 0000000..0fa2801 --- /dev/null +++ b/src/main/java/com/itchain/samplemsa/samplemsa/pubsub/Publisher.java @@ -0,0 +1,20 @@ +package com.itchain.samplemsa.samplemsa.pubsub; + +import com.itchain.samplemsa.samplemsa.common.Event; +import lombok.*; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +@Getter +@Setter +@NoArgsConstructor +public class Publisher { + @Autowired + private RabbitTemplate rabbitTemplate; + + public void publish(String topic, T event) { + this.rabbitTemplate.convertAndSend(topic, event); + } +} diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/pubsub/RabbitConfig.java b/src/main/java/com/itchain/samplemsa/samplemsa/pubsub/RabbitConfig.java new file mode 100644 index 0000000..f6b5b44 --- /dev/null +++ b/src/main/java/com/itchain/samplemsa/samplemsa/pubsub/RabbitConfig.java @@ -0,0 +1,69 @@ +package com.itchain.samplemsa.samplemsa.pubsub; + +import org.springframework.amqp.core.*; +import org.springframework.amqp.rabbit.annotation.RabbitListenerConfigurer; +import org.springframework.amqp.rabbit.connection.ConnectionFactory; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistrar; +import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.messaging.converter.MappingJackson2MessageConverter; +import org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory; +import org.springframework.messaging.handler.annotation.support.MessageHandlerMethodFactory; + + +@Configuration +public class RabbitConfig implements RabbitListenerConfigurer { + public static final String QUEUE_ORDERS = "orders-queue"; + public static final String EXCHANGE_ORDERS = "orders-exchange"; + + @Bean + public Queue ordersQueue() { + return QueueBuilder.durable(QUEUE_ORDERS).build(); + } + + @Bean + public Exchange ordersExchange() { + return ExchangeBuilder.topicExchange(EXCHANGE_ORDERS).build(); + } + + @Bean + public TopicExchange ordersTopicExchange() { + return new TopicExchange(EXCHANGE_ORDERS); + } + + @Bean + public Binding binding(Queue ordersQueue, TopicExchange ordersExchange) { + return BindingBuilder.bind(ordersQueue).to(ordersExchange).with(QUEUE_ORDERS); + } + + @Bean + public RabbitTemplate rabbitTemplate(final ConnectionFactory connectionFactory) { + final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory); + rabbitTemplate.setMessageConverter(producerJackson2JsonMessageConverter()); + return rabbitTemplate; + } + + @Bean + public Jackson2JsonMessageConverter producerJackson2JsonMessageConverter() { + return new Jackson2JsonMessageConverter(); + } + + @Override + public void configureRabbitListeners(RabbitListenerEndpointRegistrar registrar) { + registrar.setMessageHandlerMethodFactory(messageHandlerMethodFactory()); + } + + @Bean + MessageHandlerMethodFactory messageHandlerMethodFactory() { + DefaultMessageHandlerMethodFactory messageHandlerMethodFactory = new DefaultMessageHandlerMethodFactory(); + messageHandlerMethodFactory.setMessageConverter(consumerJackson2MessageConverter()); + return messageHandlerMethodFactory; + } + + @Bean + public MappingJackson2MessageConverter consumerJackson2MessageConverter() { + return new MappingJackson2MessageConverter(); + } +} diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/pubsub/Subscriber.java b/src/main/java/com/itchain/samplemsa/samplemsa/pubsub/Subscriber.java new file mode 100644 index 0000000..aea1087 --- /dev/null +++ b/src/main/java/com/itchain/samplemsa/samplemsa/pubsub/Subscriber.java @@ -0,0 +1,24 @@ +package com.itchain.samplemsa.samplemsa.pubsub; + +import com.itchain.samplemsa.samplemsa.common.Event; +import com.itchain.samplemsa.samplemsa.pubsub.sample.SampleEvent; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.stereotype.Service; + +@Service +@Getter +@NoArgsConstructor +public class Subscriber { + static final Logger logger = LoggerFactory.getLogger(Subscriber.class); + + @RabbitListener(queues = RabbitConfig.QUEUE_ORDERS) + public void subscribe(SampleEvent event) { + logger.info("Subscribed : " + event.toString()); + } +} diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/pubsub/sample/SampleController.java b/src/main/java/com/itchain/samplemsa/samplemsa/pubsub/sample/SampleController.java new file mode 100644 index 0000000..e0d61a3 --- /dev/null +++ b/src/main/java/com/itchain/samplemsa/samplemsa/pubsub/sample/SampleController.java @@ -0,0 +1,21 @@ +package com.itchain.samplemsa.samplemsa.pubsub.sample; + +import com.itchain.samplemsa.samplemsa.common.Event; +import com.itchain.samplemsa.samplemsa.pubsub.Publisher; +import com.itchain.samplemsa.samplemsa.pubsub.RabbitConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +@Controller +public class SampleController { + @Autowired + private Publisher publisher; + + @PostMapping("/sample/event") + public void handleMessage(@RequestBody SampleEvent event) { + System.out.println("Controller event: " + event); + publisher.publish(RabbitConfig.QUEUE_ORDERS, event); + } +} diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/pubsub/sample/SampleEvent.java b/src/main/java/com/itchain/samplemsa/samplemsa/pubsub/sample/SampleEvent.java new file mode 100644 index 0000000..60854ff --- /dev/null +++ b/src/main/java/com/itchain/samplemsa/samplemsa/pubsub/sample/SampleEvent.java @@ -0,0 +1,24 @@ +package com.itchain.samplemsa.samplemsa.pubsub.sample; + +import com.itchain.samplemsa.samplemsa.common.Event; +import lombok.*; + +import java.io.Serializable; + +@NoArgsConstructor +@Getter +@ToString +public class SampleEvent implements Event { + private String id; + private String message; + + public SampleEvent(String id, String message) { + this.id = id; + this.message = message; + } + + @Override + public String getID() { + return id; + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index e69de29..a0b6ebe 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -0,0 +1,3 @@ +spring.data.mongodb.host=localhost +spring.data.mongodb.port=27017 +spring.data.mongodb.database=samplemsa \ No newline at end of file diff --git a/src/main/resources/test.properties b/src/main/resources/test.properties new file mode 100644 index 0000000..5ee7366 --- /dev/null +++ b/src/main/resources/test.properties @@ -0,0 +1,10 @@ +# mongodb +spring.data.mongodb.host=0.0.0.0 +spring.data.mongodb.port=27017 +spring.data.mongodb.database=test + +# rabbitmq +spring.rabbitmq.host=localhost +spring.rabbitmq.port=5672 +spring.rabbitmq.username=guest +spring.rabbitmq.password=guest \ No newline at end of file diff --git a/src/test/java/com/itchain/samplemsa/samplemsa/AggregateTest.java b/src/test/java/com/itchain/samplemsa/samplemsa/AggregateTest.java old mode 100644 new mode 100755 index 6390068..76206da --- a/src/test/java/com/itchain/samplemsa/samplemsa/AggregateTest.java +++ b/src/test/java/com/itchain/samplemsa/samplemsa/AggregateTest.java @@ -1,11 +1,10 @@ package com.itchain.samplemsa.samplemsa; -import com.itchain.samplemsa.samplemsa.common.EventRepositoryImpl; +import com.itchain.samplemsa.samplemsa.mock.EventRepositoryImpl; import com.itchain.samplemsa.samplemsa.delivery.DeliveryRepository; import com.itchain.samplemsa.samplemsa.delivery.domain.DeliverStatus; import com.itchain.samplemsa.samplemsa.delivery.domain.Delivery; import org.junit.Test; -import org.springframework.beans.factory.annotation.Autowired; public class AggregateTest { DeliveryRepository deliveryRepository = new DeliveryRepository(new EventRepositoryImpl()); diff --git a/src/test/java/com/itchain/samplemsa/samplemsa/SampleAggregate.java b/src/test/java/com/itchain/samplemsa/samplemsa/SampleAggregate.java old mode 100644 new mode 100755 diff --git a/src/test/java/com/itchain/samplemsa/samplemsa/SampleEvent.java b/src/test/java/com/itchain/samplemsa/samplemsa/SampleEvent.java old mode 100644 new mode 100755 diff --git a/src/test/java/com/itchain/samplemsa/samplemsa/SampleMsaApplicationTests.java b/src/test/java/com/itchain/samplemsa/samplemsa/SampleMsaApplicationTests.java old mode 100644 new mode 100755 diff --git a/src/test/java/com/itchain/samplemsa/samplemsa/SecondEvent.java b/src/test/java/com/itchain/samplemsa/samplemsa/SecondEvent.java old mode 100644 new mode 100755 diff --git a/src/test/java/com/itchain/samplemsa/samplemsa/TradeTest.java b/src/test/java/com/itchain/samplemsa/samplemsa/TradeTest.java old mode 100644 new mode 100755 index 02ff1ca..b32e79b --- a/src/test/java/com/itchain/samplemsa/samplemsa/TradeTest.java +++ b/src/test/java/com/itchain/samplemsa/samplemsa/TradeTest.java @@ -1,9 +1,6 @@ package com.itchain.samplemsa.samplemsa; -import com.itchain.samplemsa.samplemsa.common.EventRepositoryImpl; -import com.itchain.samplemsa.samplemsa.trade.TradeRepository; import com.itchain.samplemsa.samplemsa.trade.application.TradeApplicationServiceImpl; -import com.itchain.samplemsa.samplemsa.trade.domain.Trade; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; diff --git a/src/test/java/com/itchain/samplemsa/samplemsa/eventstore/EventStorageServiceTest.java b/src/test/java/com/itchain/samplemsa/samplemsa/eventstore/EventStorageServiceTest.java new file mode 100644 index 0000000..a6132d2 --- /dev/null +++ b/src/test/java/com/itchain/samplemsa/samplemsa/eventstore/EventStorageServiceTest.java @@ -0,0 +1,53 @@ +package com.itchain.samplemsa.samplemsa.eventstore; + +import com.itchain.samplemsa.samplemsa.SampleMsaApplication; +import com.itchain.samplemsa.samplemsa.common.EventRepository; +import com.itchain.samplemsa.samplemsa.eventstore.domain.MongoClient; +import com.itchain.samplemsa.samplemsa.eventstore.exception.EventIDEmptyException; +import org.junit.After; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes=SampleMsaApplication.class) +@TestPropertySource(locations = "classpath:test.properties") +public class EventStorageServiceTest { + @Autowired + private MongoClient client; + @Autowired + @Qualifier("eventStorageService") + private EventRepository repo; + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @After + public void cleanUp() { + client.deleteAll(); + } + + @Test + @DirtiesContext + public void save_basic() { + SampleEvent event01 = new SampleEvent("event01"); + + repo.save(event01); + } + + @Test + public void save_when_event_id_is_not_provided() { + expectedException.expect(EventIDEmptyException.class); + expectedException.expectMessage("Event ID is empty"); + + SampleEvent event01 = new SampleEvent(); + repo.save(event01); + } +} diff --git a/src/test/java/com/itchain/samplemsa/samplemsa/eventstore/MongodbStoreTest.java b/src/test/java/com/itchain/samplemsa/samplemsa/eventstore/MongodbStoreTest.java new file mode 100644 index 0000000..2466c0e --- /dev/null +++ b/src/test/java/com/itchain/samplemsa/samplemsa/eventstore/MongodbStoreTest.java @@ -0,0 +1,57 @@ +package com.itchain.samplemsa.samplemsa.eventstore; + +import com.itchain.samplemsa.samplemsa.SampleMsaApplication; +import com.itchain.samplemsa.samplemsa.eventstore.domain.EntityWithIdAndEventList; +import com.itchain.samplemsa.samplemsa.eventstore.domain.MongoClient; +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.junit.Assert.assertEquals; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes=SampleMsaApplication.class) +@TestPropertySource(locations = "classpath:test.properties") +public class MongodbStoreTest { + @Autowired + MongodbStore store; + @Autowired + MongoClient client; + + @After + public void cleanUp() { + client.deleteAll(); + } + + @Test + @DirtiesContext + public void save_basic() { + SampleEvent event01 = new SampleEvent("event01"); + + EntityWithIdAndEventList set = store.save("event01", event01); + + EntityWithIdAndEventList result = client.findById(set.getId()).get(); + + assertEquals(1, set.getEventList().size()); + assertEquals(set.getId(), result.getId()); + } + + @Test + public void load_basic() { + SampleEvent event01 = new SampleEvent("event01"); + + EntityWithIdAndEventList set = store.save("1", event01); + + EntityWithIdAndEventList result = store.load(set.getId()); + + assertEquals(set.getId(), result.getId()); + assertEquals(1, result.getEventList().size()); + } + + +} diff --git a/src/test/java/com/itchain/samplemsa/samplemsa/eventstore/SampleEvent.java b/src/test/java/com/itchain/samplemsa/samplemsa/eventstore/SampleEvent.java new file mode 100644 index 0000000..988cfe0 --- /dev/null +++ b/src/test/java/com/itchain/samplemsa/samplemsa/eventstore/SampleEvent.java @@ -0,0 +1,20 @@ +package com.itchain.samplemsa.samplemsa.eventstore; + +import com.itchain.samplemsa.samplemsa.common.Event; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +@Getter +@NoArgsConstructor +@RequiredArgsConstructor +public class SampleEvent implements Event { + @NonNull + private String id; + + @Override + public String getID() { + return id; + } +} diff --git a/src/main/java/com/itchain/samplemsa/samplemsa/common/EventRepositoryImpl.java b/src/test/java/com/itchain/samplemsa/samplemsa/mock/EventRepositoryImpl.java similarity index 74% rename from src/main/java/com/itchain/samplemsa/samplemsa/common/EventRepositoryImpl.java rename to src/test/java/com/itchain/samplemsa/samplemsa/mock/EventRepositoryImpl.java index c456676..bdf1eee 100644 --- a/src/main/java/com/itchain/samplemsa/samplemsa/common/EventRepositoryImpl.java +++ b/src/test/java/com/itchain/samplemsa/samplemsa/mock/EventRepositoryImpl.java @@ -1,5 +1,7 @@ -package com.itchain.samplemsa.samplemsa.common; +package com.itchain.samplemsa.samplemsa.mock; +import com.itchain.samplemsa.samplemsa.common.Event; +import com.itchain.samplemsa.samplemsa.common.EventRepository; import org.springframework.stereotype.Component; import org.springframework.stereotype.Repository; @@ -7,7 +9,6 @@ import java.util.List; import java.util.stream.Collectors; -@Repository public class EventRepositoryImpl implements EventRepository { List eventList = new ArrayList<>(); @Override