BAEL-2275: Init version

This commit is contained in:
Lukasz Rys
2019-11-17 15:19:28 +01:00
parent 0bf12a690c
commit 7010533b25
25 changed files with 626 additions and 0 deletions
@@ -0,0 +1,13 @@
package com.baeldung.ddd.layers;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.PropertySource;
@SpringBootApplication
@PropertySource(value={"classpath:ddd-layers.properties"})
public class DomainLayerApplication {
public static void main(String[] args) {
SpringApplication.run(DomainLayerApplication.class, args);
}
}
@@ -0,0 +1,44 @@
package com.baeldung.ddd.layers.application;
import com.baeldung.ddd.layers.application.request.AddProductRequest;
import com.baeldung.ddd.layers.application.request.CreateOrderRequest;
import com.baeldung.ddd.layers.application.response.CreateOrderResponse;
import com.baeldung.ddd.layers.domain.service.OrderService;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/orders")
public class OrderController {
private final OrderService orderService;
@Autowired
public OrderController(OrderService orderService) {
this.orderService = orderService;
}
@PostMapping(produces = MediaType.APPLICATION_JSON_UTF8_VALUE, consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
CreateOrderResponse createOrder(@RequestBody final CreateOrderRequest createOrderRequest) {
return new CreateOrderResponse(orderService
.createOrder(createOrderRequest.getProducts())
.toString());
}
@PostMapping(value = "/{id}/products", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
void addProduct(@PathVariable final ObjectId id, @RequestBody final AddProductRequest addProductRequest) {
orderService.addProduct(id, addProductRequest.getProduct());
}
@DeleteMapping(value = "/{id}/products", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
void deleteProduct(@PathVariable final ObjectId id, @RequestParam final String name) {
orderService.deleteProduct(id, name);
}
@PostMapping("/{id}/complete")
void completeOrder(@PathVariable final ObjectId id) {
orderService.completeOrder(id);
}
}
@@ -0,0 +1,18 @@
package com.baeldung.ddd.layers.application.request;
import com.baeldung.ddd.layers.domain.Product;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class AddProductRequest {
private Product product;
@JsonCreator
public AddProductRequest(@JsonProperty("product") final Product product) {
this.product = product;
}
public Product getProduct() {
return product;
}
}
@@ -0,0 +1,21 @@
package com.baeldung.ddd.layers.application.request;
import com.baeldung.ddd.layers.domain.Product;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.ArrayList;
import java.util.List;
public class CreateOrderRequest {
private List<Product> products;
@JsonCreator
public CreateOrderRequest(@JsonProperty("products") final List<Product> productList) {
this.products = new ArrayList<>(productList);
}
public List<Product> getProducts() {
return products;
}
}
@@ -0,0 +1,15 @@
package com.baeldung.ddd.layers.application.response;
import org.bson.types.ObjectId;
public class CreateOrderResponse {
private final String id;
public CreateOrderResponse(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
@@ -0,0 +1,84 @@
package com.baeldung.ddd.layers.domain;
import com.baeldung.ddd.layers.domain.exception.DomainException;
import org.bson.types.ObjectId;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Order {
private final ObjectId id;
private OrderStatus status;
private List<Product> products;
private BigDecimal price;
public Order(final ObjectId id, final List<Product> products) {
this.id = id;
this.products = new ArrayList<>(products);
this.status = OrderStatus.CREATED;
this.price = products
.stream()
.map(Product::getPrice)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
public void complete() {
validateState();
this.status = OrderStatus.COMPLETED;
}
public void addProduct(final Product product) {
validateState();
validateProduct(product);
products.add(product);
price = price.add(product.getPrice());
}
public void removeProduct(final String name) {
validateState();
final Product product = getProduct(name);
products.remove(product);
price = price.subtract(product.getPrice());
}
private Product getProduct(String name) {
return products
.stream()
.filter(product -> product
.getName()
.equals(name))
.findFirst()
.orElseThrow(() -> new DomainException("Product with " + name + " doesn't exist."));
}
private void validateState() {
if (OrderStatus.COMPLETED.equals(status)) {
throw new DomainException("The order is in completed state.");
}
}
private void validateProduct(final Product product) {
if (product == null) {
throw new DomainException("The product cannot be null.");
}
}
public ObjectId getId() {
return id;
}
public OrderStatus getStatus() {
return status;
}
public List<Product> getProducts() {
return Collections.unmodifiableList(products);
}
public BigDecimal getPrice() {
return price;
}
}
@@ -0,0 +1,5 @@
package com.baeldung.ddd.layers.domain;
public enum OrderStatus {
CREATED, COMPLETED
}
@@ -0,0 +1,43 @@
package com.baeldung.ddd.layers.domain;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.math.BigDecimal;
import java.util.Objects;
public class Product {
private final BigDecimal price;
private final String name;
@JsonCreator
public Product(@JsonProperty("price") final BigDecimal price, @JsonProperty("name") final String name) {
this.price = price;
this.name = name;
}
public BigDecimal getPrice() {
return price;
}
public String getName() {
return name;
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final Product product = (Product) o;
return Objects.equals(price, product.price) && Objects.equals(name, product.name);
}
@Override
public int hashCode() {
return Objects.hash(price, name);
}
}
@@ -0,0 +1,7 @@
package com.baeldung.ddd.layers.domain.exception;
public class DomainException extends RuntimeException {
public DomainException(final String message) {
super(message);
}
}
@@ -0,0 +1,12 @@
package com.baeldung.ddd.layers.domain.repository;
import com.baeldung.ddd.layers.domain.Order;
import org.bson.types.ObjectId;
import java.util.Optional;
public interface OrderRepository {
Optional<Order> findById(ObjectId id);
void save(Order order);
}
@@ -0,0 +1,56 @@
package com.baeldung.ddd.layers.domain.service;
import com.baeldung.ddd.layers.domain.Order;
import com.baeldung.ddd.layers.domain.Product;
import com.baeldung.ddd.layers.domain.exception.DomainException;
import com.baeldung.ddd.layers.domain.repository.OrderRepository;
import org.bson.types.ObjectId;
import java.util.List;
public class DomainOrderService implements OrderService {
private final OrderRepository orderRepository;
public DomainOrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
@Override
public ObjectId createOrder(List<Product> products) {
final Order order = new Order(ObjectId.get(), products);
orderRepository.save(order);
return order.getId();
}
@Override
public void addProduct(ObjectId id, Product product) {
final Order order = getOrder(id);
order.addProduct(product);
orderRepository.save(order);
}
@Override
public void completeOrder(ObjectId id) {
final Order order = getOrder(id);
order.complete();
orderRepository.save(order);
}
@Override
public void deleteProduct(ObjectId id, String name) {
final Order order = getOrder(id);
order.removeProduct(name);
orderRepository.save(order);
}
private Order getOrder(ObjectId id) {
return orderRepository
.findById(id)
.orElseThrow(() -> new RuntimeException("Order with given id doesn't exist"));
}
}
@@ -0,0 +1,16 @@
package com.baeldung.ddd.layers.domain.service;
import com.baeldung.ddd.layers.domain.Product;
import org.bson.types.ObjectId;
import java.util.List;
public interface OrderService {
ObjectId createOrder(List<Product> products);
void addProduct(ObjectId id, Product product);
void completeOrder(ObjectId id);
void deleteProduct(ObjectId id, String name);
}
@@ -0,0 +1,16 @@
package com.baeldung.ddd.layers.infrastracture.configuration;
import com.baeldung.ddd.layers.domain.repository.OrderRepository;
import com.baeldung.ddd.layers.domain.service.DomainOrderService;
import com.baeldung.ddd.layers.domain.service.OrderService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DomainConfiguration {
@Bean
OrderService orderService(final OrderRepository orderRepository) {
return new DomainOrderService(orderRepository);
}
}
@@ -0,0 +1,7 @@
package com.baeldung.ddd.layers.infrastracture.configuration;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
@EnableMongoRepositories
public class MongoDBConfiguration {
}
@@ -0,0 +1,30 @@
package com.baeldung.ddd.layers.infrastracture.repository;
import com.baeldung.ddd.layers.domain.Order;
import com.baeldung.ddd.layers.domain.repository.OrderRepository;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Optional;
@Component
public class MongoDbOrderRepository implements OrderRepository {
private final SpringDataOrderRepository orderRepository;
@Autowired
public MongoDbOrderRepository(final SpringDataOrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
@Override
public Optional<Order> findById(final ObjectId id) {
return orderRepository.findById(id);
}
@Override
public void save(final Order order) {
orderRepository.save(order);
}
}
@@ -0,0 +1,10 @@
package com.baeldung.ddd.layers.infrastracture.repository;
import com.baeldung.ddd.layers.domain.Order;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface SpringDataOrderRepository extends MongoRepository<Order, ObjectId> {
}