Completed all services and last commit before saga pattern.

This commit is contained in:
Ali CANLI
2022-07-14 09:57:08 +03:00
parent 2282519f69
commit 1f68e35324
49 changed files with 790 additions and 32 deletions

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>common</artifactId>
<groupId>com.food.order</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>common-data-access</artifactId>
<dependencies>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,4 +1,4 @@
package com.food.order.system.data.access.restaurant.entity;
package com.food.order.system.common.data.access.entity;
import lombok.*;
@@ -34,6 +34,8 @@ public class RestaurantEntity {
private BigDecimal productPrice;
private Boolean productActive;
@Override
public boolean equals(Object o) {
if (this == o) return true;

View File

@@ -1,4 +1,4 @@
package com.food.order.system.data.access.restaurant.entity;
package com.food.order.system.common.data.access.entity;
import lombok.*;

View File

@@ -1,4 +1,4 @@
package com.food.order.system.data.access.restaurant.exception;
package com.food.order.system.common.data.access.exception;
public class RestaurantDataAccessException extends RuntimeException{
public RestaurantDataAccessException(String s) {

View File

@@ -1,6 +1,6 @@
package com.food.order.system.data.access.restaurant.repository;
package com.food.order.system.common.data.access.repository;
import com.food.order.system.data.access.restaurant.entity.RestaurantEntity;
import com.food.order.system.common.data.access.entity.RestaurantEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

View File

@@ -14,6 +14,7 @@
<modules>
<module>common-domain</module>
<module>common-application</module>
<module>common-data-access</module>
</modules>
<properties>

View File

@@ -5,8 +5,10 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@EnableJpaRepositories("com.food.order.system.data.access")
@EntityScan(basePackages = "com.food.order.system.data.access")
@EnableJpaRepositories(basePackages = {"com.food.order.system.data.access",
"com.food.order.system.common.data.access"})
@EntityScan(basePackages = {"com.food.order.system.data.access",
"com.food.order.system.common.data.access"})
@SpringBootApplication(scanBasePackages = "com.food.order")
public class OrderServiceApplication {
public static void main(String[] args) {

View File

@@ -29,6 +29,10 @@
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<dependency>
<groupId>com.food.order</groupId>
<artifactId>common-data-access</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,9 +1,9 @@
package com.food.order.system.data.access.restaurant.adapter;
import com.food.order.sysyem.ports.output.repository.RestaurantRepository;
import com.food.order.system.common.data.access.repository.RestaurantJpaRepository;
import com.food.order.system.data.access.restaurant.mapper.RestaurantDataAccessMapper;
import com.food.order.system.data.access.restaurant.repository.RestaurantJpaRepository;
import com.food.order.system.domain.entity.Restaurant;
import com.food.order.sysyem.ports.output.repository.RestaurantRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

View File

@@ -1,12 +1,12 @@
package com.food.order.system.data.access.restaurant.mapper;
import com.food.order.system.common.data.access.entity.RestaurantEntity;
import com.food.order.system.common.data.access.exception.RestaurantDataAccessException;
import com.food.order.system.domain.entity.Product;
import com.food.order.system.domain.entity.Restaurant;
import com.food.order.sysyem.valueobject.Money;
import com.food.order.sysyem.valueobject.ProductId;
import com.food.order.sysyem.valueobject.RestaurantId;
import com.food.order.system.data.access.restaurant.entity.RestaurantEntity;
import com.food.order.system.data.access.restaurant.exception.RestaurantDataAccessException;
import com.food.order.system.domain.entity.Product;
import com.food.order.system.domain.entity.Restaurant;
import org.springframework.stereotype.Component;
import java.util.List;

View File

@@ -13,10 +13,6 @@
<dependencies>
<dependency>
<groupId>com.food.order</groupId>
<artifactId>payment-domain</artifactId>
</dependency>
<dependency>
<groupId>com.food.order</groupId>
@@ -32,11 +28,10 @@
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>com.food.order</groupId>
<artifactId>payment-domain-core</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>

35
pom.xml
View File

@@ -100,16 +100,47 @@
<dependency>
<groupId>com.food.order</groupId>
<artifactId>restaurant-domain-core</artifactId>
<artifactId>kafka-producer</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.food.order</groupId>
<artifactId>kafka-producer</artifactId>
<artifactId>restaurant-application-service</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.food.order</groupId>
<artifactId>common-data-access</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.food.order</groupId>
<artifactId>restaurant-dataaccess</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.food.order</groupId>
<artifactId>restaurant-messaging</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.food.order</groupId>
<artifactId>restaurant-core-domain</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.food.order</groupId>
<artifactId>restaurant-domain</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.food.order</groupId>
<artifactId>kafka-consumer</artifactId>

View File

@@ -16,8 +16,6 @@
<module>restaurant-messaging</module>
<module>restaurant-container</module>
<module>restaurant-dataaccess</module>
<module>restaurant-domain/restaurant-domain-core</module>
<module>restaurant-domain/restaurant-application-service</module>
</modules>

View File

@@ -11,6 +11,51 @@
<artifactId>restaurant-container</artifactId>
<dependencies>
<dependency>
<groupId>com.food.order</groupId>
<artifactId>restaurant-core-domain</artifactId>
</dependency>
<dependency>
<groupId>com.food.order</groupId>
<artifactId>restaurant-application-service</artifactId>
</dependency>
<dependency>
<groupId>com.food.order</groupId>
<artifactId>restaurant-dataaccess</artifactId>
</dependency>
<dependency>
<groupId>com.food.order</groupId>
<artifactId>restaurant-messaging</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<image>
<name>${project.groupId}/restaurant.service:${project.version}</name>
</image>
</configuration>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>build-image</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,15 @@
package com.food.order.system.restaurant.container;
import com.food.order.system.restaurant.domain.core.RestaurantDomainService;
import com.food.order.system.restaurant.domain.core.RestaurantDomainServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RestaurantBeanConfig {
@Bean
public RestaurantDomainService restaurantService() {
return new RestaurantDomainServiceImpl();
}
}

View File

@@ -0,0 +1,18 @@
package com.food.order.system.restaurant.container;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@EnableJpaRepositories(basePackages = { "com.food.order.system.data.access.restaurant",
"com.food.order.system.common.data.access" })
@EntityScan(basePackages = { "com.food.order.system.data.access.restaurant",
"com.food.order.system.common.data.access" })
@SpringBootApplication(scanBasePackages = "com.food.order")
public class RestaurantServiceApplication {
public static void main(String[] args) {
SpringApplication.run(RestaurantServiceApplication.class, args);
}
}

View File

@@ -0,0 +1,66 @@
server:
port: 8183
logging:
level:
com.food.ordering.system: DEBUG
restaurant-service:
restaurant-approval-request-topic-name: restaurant-approval-request-value
restaurant-approval-response-topic-name: restaurant-approval-response-value
spring:
jpa:
open-in-view: false
show-sql: true
database-platform: org.hibernate.dialect.PostgreSQL9Dialect
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQL9Dialect
datasource:
url: jdbc:postgresql://localhost:5432/postgres?currentSchema=restaurant&binaryTransfer=true&reWriteBatchedInserts=true&stringtype=unspecified
username: postgres
password: postgres
driver-class-name: org.postgresql.Driver
sql:
init:
platform: postgres
mode: always
data-locations: classpath:init-data.sql
schema-locations: classpath:init-schema.sql
kafka-config:
bootstrap-servers: localhost:19092, localhost:29092, localhost:39092
schema-registry-url-key: schema.registry.url
schema-registry-url: http://localhost:8081
num-of-partitions: 3
replication-factor: 3
kafka-producer-config:
key-serializer-class: org.apache.kafka.common.serialization.StringSerializer
value-serializer-class: io.confluent.kafka.serializers.KafkaAvroSerializer
compression-type: snappy
acks: all
batch-size: 16384
batch-size-boost-factor: 100
linger-ms: 5
request-timeout-ms: 60000
retry-count: 5
kafka-consumer-config:
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: io.confluent.kafka.serializers.KafkaAvroDeserializer
restaurant-approval-consumer-group-id: restaurant-approval-topic-consumer
auto-offset-reset: earliest
specific-avro-reader-key: specific.avro.reader
specific-avro-reader: true
batch-listener: true
auto-startup: true
concurrency-level: 3
session-timeout-ms: 10000
heartbeat-interval-ms: 3000
max-poll-interval-ms: 300000
max-poll-records: 500
max-partition-fetch-bytes-default: 1048576
max-partition-fetch-bytes-boost-factor: 1
poll-timeout-ms: 150

View File

@@ -0,0 +1,22 @@
INSERT INTO restaurant.restaurants(id, name, active)
VALUES ('d215b5f8-0249-4dc5-89a3-51fd148cfb45', 'restaurant_1', TRUE);
INSERT INTO restaurant.restaurants(id, name, active)
VALUES ('d215b5f8-0249-4dc5-89a3-51fd148cfb46', 'restaurant_2', FALSE);
INSERT INTO restaurant.products(id, name, price, available)
VALUES ('d215b5f8-0249-4dc5-89a3-51fd148cfb47', 'product_1', 25.00, FALSE);
INSERT INTO restaurant.products(id, name, price, available)
VALUES ('d215b5f8-0249-4dc5-89a3-51fd148cfb48', 'product_2', 50.00, TRUE);
INSERT INTO restaurant.products(id, name, price, available)
VALUES ('d215b5f8-0249-4dc5-89a3-51fd148cfb49', 'product_3', 20.00, FALSE);
INSERT INTO restaurant.products(id, name, price, available)
VALUES ('d215b5f8-0249-4dc5-89a3-51fd148cfb50', 'product_4', 40.00, TRUE);
INSERT INTO restaurant.restaurant_products(id, restaurant_id, product_id)
VALUES ('d215b5f8-0249-4dc5-89a3-51fd148cfb51', 'd215b5f8-0249-4dc5-89a3-51fd148cfb45', 'd215b5f8-0249-4dc5-89a3-51fd148cfb47');
INSERT INTO restaurant.restaurant_products(id, restaurant_id, product_id)
VALUES ('d215b5f8-0249-4dc5-89a3-51fd148cfb52', 'd215b5f8-0249-4dc5-89a3-51fd148cfb45', 'd215b5f8-0249-4dc5-89a3-51fd148cfb48');
INSERT INTO restaurant.restaurant_products(id, restaurant_id, product_id)
VALUES ('d215b5f8-0249-4dc5-89a3-51fd148cfb53', 'd215b5f8-0249-4dc5-89a3-51fd148cfb46', 'd215b5f8-0249-4dc5-89a3-51fd148cfb49');
INSERT INTO restaurant.restaurant_products(id, restaurant_id, product_id)
VALUES ('d215b5f8-0249-4dc5-89a3-51fd148cfb54', 'd215b5f8-0249-4dc5-89a3-51fd148cfb46', 'd215b5f8-0249-4dc5-89a3-51fd148cfb50');

View File

@@ -0,0 +1,103 @@
DROP SCHEMA IF EXISTS restaurant CASCADE;
CREATE SCHEMA restaurant;
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
DROP TABLE IF EXISTS restaurant.restaurants CASCADE;
CREATE TABLE restaurant.restaurants
(
id uuid NOT NULL,
name character varying COLLATE pg_catalog."default" NOT NULL,
active boolean NOT NULL,
CONSTRAINT restaurants_pkey PRIMARY KEY (id)
);
DROP TYPE IF EXISTS approval_status;
CREATE TYPE approval_status AS ENUM ('APPROVED', 'REJECTED');
DROP TABLE IF EXISTS restaurant.order_approval CASCADE;
CREATE TABLE restaurant.order_approval
(
id uuid NOT NULL,
restaurant_id uuid NOT NULL,
order_id uuid NOT NULL,
status approval_status NOT NULL,
CONSTRAINT order_approval_pkey PRIMARY KEY (id)
);
DROP TABLE IF EXISTS restaurant.products CASCADE;
CREATE TABLE restaurant.products
(
id uuid NOT NULL,
name character varying COLLATE pg_catalog."default" NOT NULL,
price numeric(10,2) NOT NULL,
available boolean NOT NULL,
CONSTRAINT products_pkey PRIMARY KEY (id)
);
DROP TABLE IF EXISTS restaurant.restaurant_products CASCADE;
CREATE TABLE restaurant.restaurant_products
(
id uuid NOT NULL,
restaurant_id uuid NOT NULL,
product_id uuid NOT NULL,
CONSTRAINT restaurant_products_pkey PRIMARY KEY (id)
);
ALTER TABLE restaurant.restaurant_products
ADD CONSTRAINT "FK_RESTAURANT_ID" FOREIGN KEY (restaurant_id)
REFERENCES restaurant.restaurants (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE RESTRICT
NOT VALID;
ALTER TABLE restaurant.restaurant_products
ADD CONSTRAINT "FK_PRODUCT_ID" FOREIGN KEY (product_id)
REFERENCES restaurant.products (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE RESTRICT
NOT VALID;
DROP MATERIALIZED VIEW IF EXISTS restaurant.order_restaurant_m_view;
CREATE MATERIALIZED VIEW restaurant.order_restaurant_m_view
TABLESPACE pg_default
AS
SELECT r.id AS restaurant_id,
r.name AS restaurant_name,
r.active AS restaurant_active,
p.id AS product_id,
p.name AS product_name,
p.price AS product_price,
p.available AS product_available
FROM restaurant.restaurants r,
restaurant.products p,
restaurant.restaurant_products rp
WHERE r.id = rp.restaurant_id AND p.id = rp.product_id
WITH DATA;
refresh materialized VIEW restaurant.order_restaurant_m_view;
DROP function IF EXISTS restaurant.refresh_order_restaurant_m_view;
CREATE OR replace function restaurant.refresh_order_restaurant_m_view()
returns trigger
AS '
BEGIN
refresh materialized VIEW restaurant.order_restaurant_m_view;
return null;
END;
' LANGUAGE plpgsql;
DROP trigger IF EXISTS refresh_order_restaurant_m_view ON restaurant.restaurant_products;
CREATE trigger refresh_order_restaurant_m_view
after INSERT OR UPDATE OR DELETE OR truncate
ON restaurant.restaurant_products FOR each statement
EXECUTE PROCEDURE restaurant.refresh_order_restaurant_m_view();

View File

@@ -12,4 +12,27 @@
<artifactId>restaurant-dataaccess</artifactId>
<dependencies>
<dependency>
<groupId>com.food.order</groupId>
<artifactId>restaurant-application-service</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<dependency>
<groupId>com.food.order</groupId>
<artifactId>common-data-access</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,25 @@
package com.food.order.system.data.access.restaurant.adapter;
import com.food.order.system.data.access.restaurant.mapper.RestaurantDataAccessMapper;
import com.food.order.system.data.access.restaurant.repository.OrderApprovalJpaRepository;
import com.food.order.system.restaurant.domain.core.entity.OrderApproval;
import com.food.ordery.system.restaurant.domain.service.ports.output.repository.OrderApprovalRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
@Component
@RequiredArgsConstructor
public class OrderApprovalRepositoryImpl implements OrderApprovalRepository {
private final OrderApprovalJpaRepository orderApprovalJpaRepository;
private final RestaurantDataAccessMapper restaurantDataAccessMapper;
@Override
public OrderApproval save(OrderApproval orderApproval) {
return restaurantDataAccessMapper
.orderApprovalEntityToOrderApproval(orderApprovalJpaRepository
.save(restaurantDataAccessMapper.orderApprovalToOrderApprovalEntity(orderApproval)));
}
}

View File

@@ -0,0 +1,31 @@
package com.food.order.system.data.access.restaurant.adapter;
import com.food.order.system.common.data.access.entity.RestaurantEntity;
import com.food.order.system.common.data.access.repository.RestaurantJpaRepository;
import com.food.order.system.data.access.restaurant.mapper.RestaurantDataAccessMapper;
import com.food.order.system.restaurant.domain.core.entity.Restaurant;
import com.food.ordery.system.restaurant.domain.service.ports.output.repository.RestaurantRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
@Component
@RequiredArgsConstructor
public class RestaurantRepositoryImpl implements RestaurantRepository {
private final RestaurantJpaRepository restaurantJpaRepository;
private final RestaurantDataAccessMapper restaurantDataAccessMapper;
@Override
public Optional<Restaurant> findRestaurantInformation(Restaurant restaurant) {
List<UUID> restaurantProducts =
restaurantDataAccessMapper.restaurantToRestaurantProducts(restaurant);
Optional<List<RestaurantEntity>> restaurantEntities = restaurantJpaRepository
.findByRestaurantIdAndProductIdIn(restaurant.getId().getValue(),
restaurantProducts);
return restaurantEntities.map(restaurantDataAccessMapper::restaurantEntityToRestaurant);
}
}

View File

@@ -0,0 +1,24 @@
package com.food.order.system.data.access.restaurant.entity;
import com.food.order.sysyem.valueobject.OrderApprovalStatus;
import lombok.*;
import javax.persistence.*;
import java.util.UUID;
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "order_approval", schema = "restaurant")
@Entity
public class OrderApprovalEntity {
@Id
private UUID id;
private UUID restaurantId;
private UUID orderId;
@Enumerated(EnumType.STRING)
private OrderApprovalStatus status;
}

View File

@@ -0,0 +1,71 @@
package com.food.order.system.data.access.restaurant.mapper;
import com.food.order.system.common.data.access.entity.RestaurantEntity;
import com.food.order.system.common.data.access.exception.RestaurantDataAccessException;
import com.food.order.system.data.access.restaurant.entity.OrderApprovalEntity;
import com.food.order.system.restaurant.domain.core.entity.OrderApproval;
import com.food.order.system.restaurant.domain.core.entity.OrderDetail;
import com.food.order.system.restaurant.domain.core.entity.Product;
import com.food.order.system.restaurant.domain.core.entity.Restaurant;
import com.food.order.system.restaurant.domain.core.valueobject.OrderApprovalId;
import com.food.order.sysyem.valueobject.Money;
import com.food.order.sysyem.valueobject.OrderId;
import com.food.order.sysyem.valueobject.ProductId;
import com.food.order.sysyem.valueobject.RestaurantId;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
@Component
public class RestaurantDataAccessMapper {
public List<UUID> restaurantToRestaurantProducts(Restaurant restaurant) {
return restaurant.getOrderDetail().getProducts().stream()
.map(product -> product.getId().getValue())
.toList();
}
public Restaurant restaurantEntityToRestaurant(List<RestaurantEntity> restaurantEntities) {
RestaurantEntity restaurantEntity =
restaurantEntities.stream().findFirst().orElseThrow(() ->
new RestaurantDataAccessException("No restaurants found!"));
List<Product> restaurantProducts = restaurantEntities.stream().map(entity ->
Product.builder()
.productId(new ProductId(entity.getProductId()))
.name(entity.getProductName())
.price(new Money(entity.getProductPrice()))
.available(entity.getProductActive())
.build())
.collect(Collectors.toList());
return Restaurant.builder()
.restaurantId(new RestaurantId(restaurantEntity.getRestaurantId()))
.orderDetail(OrderDetail.builder()
.products(restaurantProducts)
.build())
.active(restaurantEntity.getRestaurantActive())
.build();
}
public OrderApprovalEntity orderApprovalToOrderApprovalEntity(OrderApproval orderApproval) {
return OrderApprovalEntity.builder()
.id(orderApproval.getId().getValue())
.restaurantId(orderApproval.getRestaurantId().getValue())
.orderId(orderApproval.getOrderId().getValue())
.status(orderApproval.getStatus())
.build();
}
public OrderApproval orderApprovalEntityToOrderApproval(OrderApprovalEntity orderApprovalEntity) {
return OrderApproval.builder()
.orderApprovalId(new OrderApprovalId(orderApprovalEntity.getId()))
.restaurantId(new RestaurantId(orderApprovalEntity.getRestaurantId()))
.orderId(new OrderId(orderApprovalEntity.getOrderId()))
.status(orderApprovalEntity.getStatus())
.build();
}
}

View File

@@ -0,0 +1,13 @@
package com.food.order.system.data.access.restaurant.repository;
import com.food.order.system.data.access.restaurant.entity.OrderApprovalEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.UUID;
@Repository
public interface OrderApprovalJpaRepository extends JpaRepository<OrderApprovalEntity, UUID> {
}

View File

@@ -8,14 +8,14 @@
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<modules>
<module>restaurant-domain-core</module>
<module>restaurant-application-service</module>
</modules>
<artifactId>restaurant-domain</artifactId>
<packaging>pom</packaging>
<artifactId>restaurant-domain</artifactId>
<modules>
<module>restaurant-core-domain</module>
<module>restaurant-application-service</module>
</modules>

View File

@@ -16,7 +16,7 @@
<dependencies>
<dependency>
<groupId>com.food.order</groupId>
<artifactId>restaurant-domain-core</artifactId>
<artifactId>restaurant-core-domain</artifactId>
</dependency>
<dependency>

View File

@@ -6,11 +6,10 @@
<artifactId>restaurant-domain</artifactId>
<groupId>com.food.order</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>restaurant-domain-core</artifactId>
<artifactId>restaurant-core-domain</artifactId>
<dependencies>
<dependency>

View File

@@ -11,5 +11,25 @@
<artifactId>restaurant-messaging</artifactId>
<dependencies>
<dependency>
<groupId>com.food.order</groupId>
<artifactId>restaurant-application-service</artifactId>
</dependency>
<dependency>
<groupId>com.food.order</groupId>
<artifactId>kafka-producer</artifactId>
</dependency>
<dependency>
<groupId>com.food.order</groupId>
<artifactId>kafka-consumer</artifactId>
</dependency>
<dependency>
<groupId>com.food.order</groupId>
<artifactId>kafka-model</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,48 @@
package com.food.order.system.restaurant.messaging.listener.kafka;
import com.food.order.system.kafka.consumer.KafkaConsumer;
import com.food.order.system.kafka.order.avro.model.RestaurantApprovalRequestAvroModel;
import com.food.order.system.restaurant.messaging.mapper.RestaurantMessagingDataMapper;
import com.food.ordery.system.restaurant.domain.service.ports.input.message.listener.RestaurantApprovalRequestMessageListener;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.support.KafkaHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;
import java.util.List;
@Slf4j
@Component
@RequiredArgsConstructor
public class RestaurantApprovalRequestKafkaListener implements KafkaConsumer<RestaurantApprovalRequestAvroModel> {
private final RestaurantApprovalRequestMessageListener restaurantApprovalRequestMessageListener;
private final RestaurantMessagingDataMapper restaurantMessagingDataMapper;
@Override
@KafkaListener(id = "${kafka-consumer-config.restaurant-approval-consumer-group-id}",
topics = "${restaurant-service.restaurant-approval-request-topic-name}")
public void receive(@Payload List<RestaurantApprovalRequestAvroModel> messages,
@Header(KafkaHeaders.RECEIVED_MESSAGE_KEY) List<String> keys,
@Header(KafkaHeaders.RECEIVED_PARTITION_ID) List<Integer> partitions,
@Header(KafkaHeaders.OFFSET) List<Long> offsets) {
log.info("{} number of orders approval requests received with keys {}, partitions {} and offsets {}" +
", sending for restaurant approval",
messages.size(),
keys.toString(),
partitions.toString(),
offsets.toString());
messages.forEach(restaurantApprovalRequestAvroModel -> {
log.info("Processing order approval for order id: {}", restaurantApprovalRequestAvroModel.getOrderId());
restaurantApprovalRequestMessageListener.approveOrder(restaurantMessagingDataMapper.
restaurantApprovalRequestAvroModelToRestaurantApproval(restaurantApprovalRequestAvroModel));
});
}
}

View File

@@ -0,0 +1,69 @@
package com.food.order.system.restaurant.messaging.mapper;
import com.food.order.system.kafka.order.avro.model.OrderApprovalStatus;
import com.food.order.system.kafka.order.avro.model.RestaurantApprovalRequestAvroModel;
import com.food.order.system.kafka.order.avro.model.RestaurantApprovalResponseAvroModel;
import com.food.order.system.restaurant.domain.core.entity.Product;
import com.food.order.system.restaurant.domain.core.event.OrderApprovedEvent;
import com.food.order.system.restaurant.domain.core.event.OrderRejectedEvent;
import com.food.order.sysyem.valueobject.ProductId;
import com.food.order.sysyem.valueobject.RestaurantOrderStatus;
import com.food.ordery.system.restaurant.domain.service.dto.RestaurantApprovalRequest;
import org.springframework.stereotype.Component;
import java.util.UUID;
import java.util.stream.Collectors;
@Component
public class RestaurantMessagingDataMapper {
public RestaurantApprovalResponseAvroModel
orderApprovedEventToRestaurantApprovalResponseAvroModel(OrderApprovedEvent orderApprovedEvent) {
return RestaurantApprovalResponseAvroModel.newBuilder()
.setId(UUID.randomUUID().toString())
.setSagaId("")
.setOrderId(orderApprovedEvent.getOrderApproval().getOrderId().getValue().toString())
.setRestaurantId(orderApprovedEvent.getRestaurantId().getValue().toString())
.setCreatedAt(orderApprovedEvent.getCreatedAt().toInstant())
.setOrderApprovalStatus(OrderApprovalStatus.valueOf(orderApprovedEvent.
getOrderApproval().getStatus().name()))
.setFailureMessages(orderApprovedEvent.getFailureMessages())
.build();
}
public RestaurantApprovalResponseAvroModel
orderRejectedEventToRestaurantApprovalResponseAvroModel(OrderRejectedEvent orderRejectedEvent) {
return RestaurantApprovalResponseAvroModel.newBuilder()
.setId(UUID.randomUUID().toString())
.setSagaId("")
.setOrderId(orderRejectedEvent.getOrderApproval().getOrderId().getValue().toString())
.setRestaurantId(orderRejectedEvent.getRestaurantId().getValue().toString())
.setCreatedAt(orderRejectedEvent.getCreatedAt().toInstant())
.setOrderApprovalStatus(OrderApprovalStatus.valueOf(orderRejectedEvent.
getOrderApproval().getStatus().name()))
.setFailureMessages(orderRejectedEvent.getFailureMessages())
.build();
}
public RestaurantApprovalRequest
restaurantApprovalRequestAvroModelToRestaurantApproval(RestaurantApprovalRequestAvroModel
restaurantApprovalRequestAvroModel) {
return RestaurantApprovalRequest.builder()
.id(restaurantApprovalRequestAvroModel.getId())
.sagaId(restaurantApprovalRequestAvroModel.getSagaId())
.restaurantId(restaurantApprovalRequestAvroModel.getRestaurantId())
.orderId(restaurantApprovalRequestAvroModel.getOrderId())
.status(RestaurantOrderStatus.valueOf(restaurantApprovalRequestAvroModel
.getRestaurantOrderStatus().name()))
.products(restaurantApprovalRequestAvroModel.getProducts()
.stream().map(avroModel ->
Product.builder()
.productId(new ProductId(UUID.fromString(avroModel.getId())))
.quantity(avroModel.getQuantity())
.build())
.collect(Collectors.toList()))
.price(restaurantApprovalRequestAvroModel.getPrice())
.createdAt(restaurantApprovalRequestAvroModel.getCreatedAt())
.build();
}
}

View File

@@ -0,0 +1,53 @@
package com.food.order.system.restaurant.messaging.publisher.kafka;
import com.food.order.system.kafka.order.avro.model.RestaurantApprovalResponseAvroModel;
import com.food.order.system.kafka.producer.KafkaMessageHelper;
import com.food.order.system.kafka.producer.service.KafkaProducer;
import com.food.order.system.restaurant.domain.core.event.OrderApprovedEvent;
import com.food.order.system.restaurant.messaging.mapper.RestaurantMessagingDataMapper;
import com.food.ordery.system.restaurant.domain.service.config.RestaurantServiceConfig;
import com.food.ordery.system.restaurant.domain.service.ports.output.message.publisher.OrderApprovedMessagePublisher;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Slf4j
@Component
@RequiredArgsConstructor
public class OrderApprovedKafkaMessagePublisher implements OrderApprovedMessagePublisher {
private final RestaurantMessagingDataMapper restaurantMessagingDataMapper;
private final KafkaProducer<String, RestaurantApprovalResponseAvroModel> kafkaProducer;
private final RestaurantServiceConfig restaurantServiceConfigData;
private final KafkaMessageHelper kafkaMessageHelper;
@Override
public void publish(OrderApprovedEvent orderApprovedEvent) {
String orderId = orderApprovedEvent.getOrderApproval().getOrderId().getValue().toString();
log.info("Received OrderApprovedEvent for order id: {}", orderId);
try {
RestaurantApprovalResponseAvroModel restaurantApprovalResponseAvroModel =
restaurantMessagingDataMapper
.orderApprovedEventToRestaurantApprovalResponseAvroModel(orderApprovedEvent);
kafkaProducer.send(restaurantServiceConfigData.getRestaurantApprovalResponseTopicName(),
orderId,
restaurantApprovalResponseAvroModel,
kafkaMessageHelper.getKafkaCallBack(restaurantServiceConfigData
.getRestaurantApprovalResponseTopicName(),
restaurantApprovalResponseAvroModel,
orderId,
"RestaurantApprovalResponseAvroModel"));
log.info("RestaurantApprovalResponseAvroModel sent to kafka at: {}", System.nanoTime());
} catch (Exception e) {
log.error("Error while sending RestaurantApprovalResponseAvroModel message" +
" to kafka with order id: {}, error: {}", orderId, e.getMessage());
}
}
}

View File

@@ -0,0 +1,53 @@
package com.food.order.system.restaurant.messaging.publisher.kafka;
import com.food.order.system.kafka.order.avro.model.RestaurantApprovalResponseAvroModel;
import com.food.order.system.kafka.producer.KafkaMessageHelper;
import com.food.order.system.kafka.producer.service.KafkaProducer;
import com.food.order.system.restaurant.domain.core.event.OrderRejectedEvent;
import com.food.order.system.restaurant.messaging.mapper.RestaurantMessagingDataMapper;
import com.food.ordery.system.restaurant.domain.service.config.RestaurantServiceConfig;
import com.food.ordery.system.restaurant.domain.service.ports.output.message.publisher.OrderRejectedMessagePublisher;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Slf4j
@RequiredArgsConstructor
@Component
public class OrderRejectedKafkaMessagePublisher implements OrderRejectedMessagePublisher {
private final RestaurantMessagingDataMapper restaurantMessagingDataMapper;
private final KafkaProducer<String, RestaurantApprovalResponseAvroModel> kafkaProducer;
private final RestaurantServiceConfig restaurantServiceConfigData;
private final KafkaMessageHelper kafkaMessageHelper;
@Override
public void publish(OrderRejectedEvent orderRejectedEvent) {
String orderId = orderRejectedEvent.getOrderApproval().getOrderId().getValue().toString();
log.info("Received OrderRejectedEvent for order id: {}", orderId);
try {
RestaurantApprovalResponseAvroModel restaurantApprovalResponseAvroModel =
restaurantMessagingDataMapper
.orderRejectedEventToRestaurantApprovalResponseAvroModel(orderRejectedEvent);
kafkaProducer.send(restaurantServiceConfigData.getRestaurantApprovalResponseTopicName(),
orderId,
restaurantApprovalResponseAvroModel,
kafkaMessageHelper.getKafkaCallBack(restaurantServiceConfigData
.getRestaurantApprovalResponseTopicName(),
restaurantApprovalResponseAvroModel,
orderId,
"RestaurantApprovalResponseAvroModel"));
log.info("RestaurantApprovalResponseAvroModel sent to kafka at: {}", System.nanoTime());
} catch (Exception e) {
log.error("Error while sending RestaurantApprovalResponseAvroModel message" +
" to kafka with order id: {}, error: {}", orderId, e.getMessage());
}
}
}