From 85edf1f5d368aaa52684756a75748ec439c16a18 Mon Sep 17 00:00:00 2001 From: Garik Hakobyan Date: Tue, 2 May 2023 17:53:20 +0400 Subject: [PATCH 1/3] update --- .../com/example/demo/DemoApplication.java | 9 +++-- .../demo/controller/ProductController.java | 22 ++++++----- .../example/demo/dto/ProductCounterDto.java | 9 +++-- .../java/com/example/demo/dto/ProductDto.java | 29 ++++++++------- .../java/com/example/demo/entity/Product.java | 37 ++++++++++--------- .../demo/exceptions/ExceptionHandlers.java | 11 +++--- .../example/demo/facade/ProductFacade.java | 29 ++++++++------- .../demo/facade/ProductUniquenessFacade.java | 3 +- .../listeners/ProductCounterListener.java | 21 +++++------ .../java/com/example/demo/mapper/Map.java | 9 +++-- .../example/demo/metrics/MetricsService.java | 25 ++++++------- .../demo/repository/ProductRepository.java | 2 + .../AbstractProductErrorResponse.java | 31 ++++++++-------- .../example/demo/response/ErrorCategory.java | 26 +++++++------ .../com/example/demo/response/ErrorDto.java | 18 +++++---- .../demo/response/ResponseMessage.java | 30 ++++++++------- .../demo/service/ProductCounterService.java | 21 ++++++----- .../demo/service/ProductDomainService.java | 3 +- .../example/demo/service/ProductService.java | 21 ++++++----- src/main/resources/application.properties | 2 + 20 files changed, 193 insertions(+), 165 deletions(-) diff --git a/src/main/java/com/example/demo/DemoApplication.java b/src/main/java/com/example/demo/DemoApplication.java index 9933f96..ee4564f 100644 --- a/src/main/java/com/example/demo/DemoApplication.java +++ b/src/main/java/com/example/demo/DemoApplication.java @@ -4,12 +4,15 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; + + @SpringBootApplication @EnableJpaAuditing public class DemoApplication { - public static void main(String[] args) { - SpringApplication.run(DemoApplication.class, args); - } + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } + } diff --git a/src/main/java/com/example/demo/controller/ProductController.java b/src/main/java/com/example/demo/controller/ProductController.java index b3965d8..6ec26cd 100644 --- a/src/main/java/com/example/demo/controller/ProductController.java +++ b/src/main/java/com/example/demo/controller/ProductController.java @@ -6,7 +6,11 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + @RestController @RequestMapping("/api/v1") @@ -14,14 +18,14 @@ @Slf4j public class ProductController { - private final ProductFacade productFacade; + private final ProductFacade productFacade; - @PostMapping("/create-product") - public ResponseEntity createProduct(@RequestBody ProductDto productDto) { - log.info("Posting a new product with {} id", productDto.getName()); - var result = productFacade.countProducts(productDto); - log.info("Posting is done with status {}", result.getHttpStatus()); - return ResponseEntity.status(result.getHttpStatus()).body(result); - } + @PostMapping("/create-product") + public ResponseEntity createProduct(@RequestBody ProductDto productDto) { + log.info("Posting a new product with {} id", productDto.getName()); + var result = productFacade.countProducts(productDto); + log.info("Posting is done with status {}", result.getHttpStatus()); + return ResponseEntity.status(result.getHttpStatus()).body(result); + } } diff --git a/src/main/java/com/example/demo/dto/ProductCounterDto.java b/src/main/java/com/example/demo/dto/ProductCounterDto.java index 7e3358d..085b0a1 100644 --- a/src/main/java/com/example/demo/dto/ProductCounterDto.java +++ b/src/main/java/com/example/demo/dto/ProductCounterDto.java @@ -7,14 +7,15 @@ import java.time.Instant; + @Data @JsonInclude(JsonInclude.Include.NON_NULL) public class ProductCounterDto { - @JsonProperty("counter") - private int counter; + @JsonProperty("counter") + private int counter; - @JsonProperty("createdAt") - private Instant createdAt; + @JsonProperty("createdAt") + private Instant createdAt; } diff --git a/src/main/java/com/example/demo/dto/ProductDto.java b/src/main/java/com/example/demo/dto/ProductDto.java index f9ddf55..47c9b1f 100644 --- a/src/main/java/com/example/demo/dto/ProductDto.java +++ b/src/main/java/com/example/demo/dto/ProductDto.java @@ -6,27 +6,28 @@ import java.util.Objects; + @Data //@EqualsAndHashCode @JsonInclude(JsonInclude.Include.NON_NULL) public class ProductDto { - @JsonProperty("name") - private String name; + @JsonProperty("name") + private String name; - @JsonProperty("description") - private String description; + @JsonProperty("description") + private String description; - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof ProductDto that)) return false; - return Objects.equals(getName(), that.getName()); - } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ProductDto that)) return false; + return Objects.equals(getName(), that.getName()); + } - @Override - public int hashCode() { - return Objects.hash(getName()); - } + @Override + public int hashCode() { + return Objects.hash(getName()); + } } diff --git a/src/main/java/com/example/demo/entity/Product.java b/src/main/java/com/example/demo/entity/Product.java index 6a1ef77..454deff 100644 --- a/src/main/java/com/example/demo/entity/Product.java +++ b/src/main/java/com/example/demo/entity/Product.java @@ -11,6 +11,7 @@ import java.util.Objects; + @Getter @Setter @ToString @@ -20,26 +21,26 @@ @Slf4j public class Product { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long productId; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long productId; - @Column(name = "product_name", length = 20) - private String name; + @Column(name = "product_name", length = 20) + private String name; - @Column(name = "product_description") - private String description; + @Column(name = "product_description") + private String description; - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false; - Product product = (Product) o; - return getProductId() != null && Objects.equals(getProductId(), product.getProductId()); - } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false; + Product product = (Product) o; + return getProductId() != null && Objects.equals(getProductId(), product.getProductId()); + } - @Override - public int hashCode() { - return getClass().hashCode(); - } + @Override + public int hashCode() { + return getClass().hashCode(); + } } diff --git a/src/main/java/com/example/demo/exceptions/ExceptionHandlers.java b/src/main/java/com/example/demo/exceptions/ExceptionHandlers.java index fed4a8e..4dfabf8 100644 --- a/src/main/java/com/example/demo/exceptions/ExceptionHandlers.java +++ b/src/main/java/com/example/demo/exceptions/ExceptionHandlers.java @@ -10,13 +10,14 @@ import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; + @RestControllerAdvice @Order(Ordered.HIGHEST_PRECEDENCE) public class ExceptionHandlers { - @ExceptionHandler(JDBCException.class) - public ResponseEntity internalServerExceptionsHandler(Exception exception) { - var errorResult = new ResponseMessage(ErrorCategory.NAME_NOT_ALLOWED.errorDto(), ProductCounterService.getProductCountSize()); - return ResponseEntity.status(errorResult.getHttpStatus()).body(errorResult); - } + @ExceptionHandler(JDBCException.class) + public ResponseEntity internalServerExceptionsHandler(Exception exception) { + var errorResult = new ResponseMessage(ErrorCategory.NAME_NOT_ALLOWED.errorDto(), ProductCounterService.getProductCountSize()); + return ResponseEntity.status(errorResult.getHttpStatus()).body(errorResult); + } } diff --git a/src/main/java/com/example/demo/facade/ProductFacade.java b/src/main/java/com/example/demo/facade/ProductFacade.java index c138ee5..0309b6d 100644 --- a/src/main/java/com/example/demo/facade/ProductFacade.java +++ b/src/main/java/com/example/demo/facade/ProductFacade.java @@ -9,26 +9,27 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; + @Service @RequiredArgsConstructor @Slf4j public class ProductFacade implements ProductUniquenessFacade { - private final ProductService productService; + private final ProductService productService; - @Override - public ResponseMessage countProducts(ProductDto productDto) { - log.info("Checking if the product is unique in the in memory counter {}", productDto.getName()); - var productCounter = ProductCounterService.getProductCounter(); + @Override + public ResponseMessage countProducts(ProductDto productDto) { + log.info("Checking if the product is unique in the in memory counter {}", productDto.getName()); + var productCounter = ProductCounterService.getProductCounter(); - if (!productCounter.contains(productDto.hashCode())) { - log.info("Product is counted: product is in the db and in the inMemory counter: name={}", productDto.getName()); - var savedProduct = productService.persistProduct(productDto); - return new ResponseMessage(ErrorCategory.UNIQUE.errorDto(), savedProduct, ProductCounterService.getProductCountSize()); - } else { - log.warn("Product is not counted: product either no in the db or in the in memory counter: name={}", productDto.getName()); - return new ResponseMessage(ErrorCategory.DUPLICATED_PRODUCT.errorDto(), ProductCounterService.getProductCountSize()); - } - } + if (!productCounter.contains(productDto.hashCode())) { + log.info("Product is counted: product is in the db and in the inMemory counter: name={}", productDto.getName()); + var savedProduct = productService.persistProduct(productDto); + return new ResponseMessage(ErrorCategory.UNIQUE.errorDto(), savedProduct, ProductCounterService.getProductCountSize()); + } else { + log.warn("Product is not counted: product either no in the db or in the in memory counter: name={}", productDto.getName()); + return new ResponseMessage(ErrorCategory.DUPLICATED_PRODUCT.errorDto(), ProductCounterService.getProductCountSize()); + } + } } diff --git a/src/main/java/com/example/demo/facade/ProductUniquenessFacade.java b/src/main/java/com/example/demo/facade/ProductUniquenessFacade.java index f1b2b6b..ed7b8fd 100644 --- a/src/main/java/com/example/demo/facade/ProductUniquenessFacade.java +++ b/src/main/java/com/example/demo/facade/ProductUniquenessFacade.java @@ -3,9 +3,10 @@ import com.example.demo.dto.ProductDto; import com.example.demo.response.ResponseMessage; + public interface ProductUniquenessFacade { - ResponseMessage countProducts(ProductDto productDto); + ResponseMessage countProducts(ProductDto productDto); } diff --git a/src/main/java/com/example/demo/listeners/ProductCounterListener.java b/src/main/java/com/example/demo/listeners/ProductCounterListener.java index 276b9a3..5c0a80d 100644 --- a/src/main/java/com/example/demo/listeners/ProductCounterListener.java +++ b/src/main/java/com/example/demo/listeners/ProductCounterListener.java @@ -3,21 +3,20 @@ import com.example.demo.entity.Product; import com.example.demo.mapper.Map; import com.example.demo.service.ProductCounterService; -import com.example.demo.service.ProductService; import jakarta.persistence.PostPersist; import lombok.extern.slf4j.Slf4j; @Slf4j public class ProductCounterListener { - @PostPersist - void postPersistProductCounter(Object productDto) { - log.info("Trying to add the product into the inMemory db!"); - var counter = ProductCounterService.getProductCounter(); - if (productDto instanceof Product product) { - var entity = Map.INSTANCE.fromProduct(product); - counter.add(entity.hashCode()); - log.info("Product name={} is added into the inMemory db!", product.getName()); - } - } + @PostPersist + void postPersistProductCounter(Object productDto) { + log.info("Trying to add the product into the inMemory db!"); + var counter = ProductCounterService.getProductCounter(); + if (productDto instanceof Product product) { + var entity = Map.INSTANCE.fromProduct(product); + counter.add(entity.hashCode()); + log.info("Product name={} is added into the inMemory db!", product.getName()); + } + } } diff --git a/src/main/java/com/example/demo/mapper/Map.java b/src/main/java/com/example/demo/mapper/Map.java index 6e446ff..a2f05f6 100644 --- a/src/main/java/com/example/demo/mapper/Map.java +++ b/src/main/java/com/example/demo/mapper/Map.java @@ -8,9 +8,10 @@ @Mapper(componentModel = "spring") public interface Map { - Map INSTANCE = Mappers.getMapper(Map.class); - @Mapping(target = "productId", ignore = true) - Product toProduct(ProductDto productDto); + Map INSTANCE = Mappers.getMapper(Map.class); - ProductDto fromProduct(Product product); + @Mapping(target = "productId", ignore = true) + Product toProduct(ProductDto productDto); + + ProductDto fromProduct(Product product); } diff --git a/src/main/java/com/example/demo/metrics/MetricsService.java b/src/main/java/com/example/demo/metrics/MetricsService.java index 3cc8c79..28334b3 100644 --- a/src/main/java/com/example/demo/metrics/MetricsService.java +++ b/src/main/java/com/example/demo/metrics/MetricsService.java @@ -1,8 +1,6 @@ package com.example.demo.metrics; -import com.example.demo.facade.ProductFacade; import com.example.demo.service.ProductCounterService; -import com.example.demo.service.ProductService; import io.micrometer.core.instrument.Gauge; import io.micrometer.core.instrument.MeterRegistry; import lombok.extern.slf4j.Slf4j; @@ -14,15 +12,16 @@ @Slf4j public class MetricsService { - public Supplier fetchProductCount(){ - return ProductCounterService::getProductCountSize; - } - public MetricsService(MeterRegistry registry) { - log.info("Registering product countMetric into the Prometheus."); - Gauge.builder("product_counter", fetchProductCount()) - .strongReference(true) - .tag("product", "counter") - .register(registry); - log.info("CounterMetric is already registered in the Prometheus."); - } + public MetricsService(MeterRegistry registry) { + log.info("Registering product countMetric into the Prometheus."); + Gauge.builder("product_counter", fetchProductCount()) + .strongReference(true) + .tag("product", "counter") + .register(registry); + log.info("CounterMetric is already registered in the Prometheus."); + } + + public Supplier fetchProductCount() { + return ProductCounterService::getProductCountSize; + } } diff --git a/src/main/java/com/example/demo/repository/ProductRepository.java b/src/main/java/com/example/demo/repository/ProductRepository.java index 46352df..e15a5da 100644 --- a/src/main/java/com/example/demo/repository/ProductRepository.java +++ b/src/main/java/com/example/demo/repository/ProductRepository.java @@ -4,6 +4,8 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; + @Repository public interface ProductRepository extends JpaRepository { + } diff --git a/src/main/java/com/example/demo/response/AbstractProductErrorResponse.java b/src/main/java/com/example/demo/response/AbstractProductErrorResponse.java index 2e7ae4c..6c5f589 100644 --- a/src/main/java/com/example/demo/response/AbstractProductErrorResponse.java +++ b/src/main/java/com/example/demo/response/AbstractProductErrorResponse.java @@ -5,29 +5,30 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; + @Data @JsonInclude(JsonInclude.Include.NON_NULL) public abstract class AbstractProductErrorResponse { - @JsonIgnore - private Integer httpStatus; + @JsonIgnore + private Integer httpStatus; - @JsonProperty("notification") - private ErrorDto errors; + @JsonProperty("notification") + private ErrorDto errors; - protected AbstractProductErrorResponse(ErrorDto errorDto, Integer httpStatus) { - this.httpStatus = httpStatus; - this.errors = errorDto; - } + protected AbstractProductErrorResponse(ErrorDto errorDto, Integer httpStatus) { + this.httpStatus = httpStatus; + this.errors = errorDto; + } - protected AbstractProductErrorResponse(ErrorDto errorDto) { - this(errorDto, errorDto.getStatus().value()); - } + protected AbstractProductErrorResponse(ErrorDto errorDto) { + this(errorDto, errorDto.getStatus().value()); + } - protected AbstractProductErrorResponse() { - this.httpStatus = 200; - this.errors = new ErrorDto(); - } + protected AbstractProductErrorResponse() { + this.httpStatus = 200; + this.errors = new ErrorDto(); + } } diff --git a/src/main/java/com/example/demo/response/ErrorCategory.java b/src/main/java/com/example/demo/response/ErrorCategory.java index 7e4223c..0db35f9 100644 --- a/src/main/java/com/example/demo/response/ErrorCategory.java +++ b/src/main/java/com/example/demo/response/ErrorCategory.java @@ -3,20 +3,22 @@ import lombok.Getter; import org.springframework.http.HttpStatus; + @Getter public enum ErrorCategory { - DUPLICATED_PRODUCT("Such a product exists already", HttpStatus.NOT_ACCEPTABLE), - NAME_NOT_ALLOWED("The product name length should not be greater than 20", HttpStatus.INTERNAL_SERVER_ERROR), - UNIQUE("The product is unique", HttpStatus.OK); + DUPLICATED_PRODUCT("Such a product exists already", HttpStatus.NOT_ACCEPTABLE), + NAME_NOT_ALLOWED("The product name length should not be greater than 20", HttpStatus.INTERNAL_SERVER_ERROR), + UNIQUE("The product is unique", HttpStatus.OK); + + private final String id; + private final HttpStatus httpStatus; - private final String id; - private final HttpStatus httpStatus; + ErrorCategory(String s, HttpStatus httpStatus) { + this.id = s; + this.httpStatus = httpStatus; + } - ErrorCategory(String s, HttpStatus httpStatus) { - this.id = s; - this.httpStatus = httpStatus; - } - public ErrorDto errorDto() { - return new ErrorDto(getId(), name(), getHttpStatus()); - } + public ErrorDto errorDto() { + return new ErrorDto(getId(), name(), getHttpStatus()); + } } diff --git a/src/main/java/com/example/demo/response/ErrorDto.java b/src/main/java/com/example/demo/response/ErrorDto.java index 373ddce..2d10c64 100644 --- a/src/main/java/com/example/demo/response/ErrorDto.java +++ b/src/main/java/com/example/demo/response/ErrorDto.java @@ -2,21 +2,25 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; import org.springframework.http.HttpStatus; + @Getter @Setter @NoArgsConstructor @AllArgsConstructor public class ErrorDto { - @JsonProperty("message") - private String message; + @JsonProperty("message") + private String message; - @JsonProperty("state") - private String state; + @JsonProperty("state") + private String state; - @JsonIgnore - private HttpStatus status; + @JsonIgnore + private HttpStatus status; } diff --git a/src/main/java/com/example/demo/response/ResponseMessage.java b/src/main/java/com/example/demo/response/ResponseMessage.java index 2f87ed1..0a5b867 100644 --- a/src/main/java/com/example/demo/response/ResponseMessage.java +++ b/src/main/java/com/example/demo/response/ResponseMessage.java @@ -6,26 +6,28 @@ import lombok.Getter; import lombok.Setter; + @Getter @Setter @EqualsAndHashCode(callSuper = true) -public class ResponseMessage extends AbstractProductErrorResponse{ +public class ResponseMessage extends AbstractProductErrorResponse { + + @JsonProperty("body") + private ProductDto body; - @JsonProperty("body") - private ProductDto body; + @JsonProperty(value = "productCounter") + private Number productCounter; - @JsonProperty(value = "productCounter") - private Number productCounter; + public ResponseMessage(final ErrorDto error, Number productCounter) { + super(error); + this.productCounter = productCounter; + } - public ResponseMessage(final ErrorDto error, Number productCounter){ - super(error); - this.productCounter = productCounter; - } - public ResponseMessage(final ErrorDto error, ProductDto body, int productCounter){ - super(error); - this.body = body; - this.productCounter = productCounter; - } + public ResponseMessage(final ErrorDto error, ProductDto body, int productCounter) { + super(error); + this.body = body; + this.productCounter = productCounter; + } } diff --git a/src/main/java/com/example/demo/service/ProductCounterService.java b/src/main/java/com/example/demo/service/ProductCounterService.java index df4607f..c8115ab 100644 --- a/src/main/java/com/example/demo/service/ProductCounterService.java +++ b/src/main/java/com/example/demo/service/ProductCounterService.java @@ -7,23 +7,24 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; + @RequiredArgsConstructor @Slf4j @Service public class ProductCounterService { - private static final Set productCounter = ConcurrentHashMap.newKeySet(); + private static final Set productCounter = ConcurrentHashMap.newKeySet(); - public static Integer getProductCountSize() { - return productCounter.size(); - } + public static Integer getProductCountSize() { + return productCounter.size(); + } - public static Set getProductCounter() { - return productCounter; - } + public static Set getProductCounter() { + return productCounter; + } - public Number getProductQuantity() { - return getProductCountSize(); - } + public Number getProductQuantity() { + return getProductCountSize(); + } } diff --git a/src/main/java/com/example/demo/service/ProductDomainService.java b/src/main/java/com/example/demo/service/ProductDomainService.java index ec49de1..cd37f1c 100644 --- a/src/main/java/com/example/demo/service/ProductDomainService.java +++ b/src/main/java/com/example/demo/service/ProductDomainService.java @@ -2,6 +2,7 @@ import com.example.demo.dto.ProductDto; + public interface ProductDomainService { - ProductDto persistProduct(ProductDto productDto); + ProductDto persistProduct(ProductDto productDto); } diff --git a/src/main/java/com/example/demo/service/ProductService.java b/src/main/java/com/example/demo/service/ProductService.java index a43c908..88bf30d 100644 --- a/src/main/java/com/example/demo/service/ProductService.java +++ b/src/main/java/com/example/demo/service/ProductService.java @@ -8,22 +8,23 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; + @Service @RequiredArgsConstructor @Slf4j public class ProductService implements ProductDomainService { - private final ProductCounterService productCounterService; - private final ProductRepository productRepository; - private final Map map; + private final ProductCounterService productCounterService; + private final ProductRepository productRepository; + private final Map map; - @Override - public ProductDto persistProduct(ProductDto productDto) { - log.info("Saving product {}", productDto.getName()); - Product savedProduct = productRepository.save(map.toProduct(productDto)); - log.info("Product is already saved {}, the product quantity is {}", savedProduct.getName(), ProductCounterService.getProductCountSize()); - return map.fromProduct(savedProduct); - } + @Override + public ProductDto persistProduct(ProductDto productDto) { + log.info("Saving product {}", productDto.getName()); + Product savedProduct = productRepository.save(map.toProduct(productDto)); + log.info("Product is already saved {}, the product quantity is {}", savedProduct.getName(), ProductCounterService.getProductCountSize()); + return map.fromProduct(savedProduct); + } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 08042d5..4fcf1a1 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,5 +1,6 @@ server.port=8888 + spring.datasource.url=jdbc:h2:mem:tcp;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;MODE=MySQL spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa @@ -7,6 +8,7 @@ spring.datasource.password=password spring.jpa.database-platform=org.hibernate.dialect.H2Dialect + management.endpoints.enabled-by-default=true management.endpoints.web.exposure.include=prometheus,metrics management.endpoints.health.show-details=always \ No newline at end of file From ba73acd8fb14b6308c7efa008ff7b64692bb3456 Mon Sep 17 00:00:00 2001 From: Garik Hakobyan Date: Thu, 4 May 2023 19:28:27 +0400 Subject: [PATCH 2/3] update --- .../demo/controller/ProductController.java | 16 +++---- .../example/demo/dto/ProductCounterDto.java | 9 ++-- .../java/com/example/demo/dto/ProductDto.java | 34 +++++++------- .../java/com/example/demo/entity/Product.java | 44 +++++++++---------- .../demo/exceptions/ExceptionHandlers.java | 10 ++--- .../example/demo/facade/ProductFacade.java | 42 +++++++++++------- .../demo/facade/ProductUniquenessFacade.java | 6 ++- .../listeners/ProductCounterListener.java | 20 ++++----- .../java/com/example/demo/mapper/Map.java | 8 ++-- .../demo/metrics/MetricServiceCounter.java | 18 ++++++++ .../example/demo/metrics/MetricsService.java | 27 ------------ .../demo/metrics/MetricsServiceGauge.java | 27 ++++++++++++ .../AbstractProductErrorResponse.java | 30 ++++++------- .../example/demo/response/ErrorCategory.java | 24 +++++----- .../com/example/demo/response/ErrorDto.java | 12 ++--- .../demo/response/ResponseMessage.java | 32 +++++++------- .../demo/service/ProductCounterService.java | 20 ++++----- .../demo/service/ProductDomainService.java | 2 +- .../example/demo/service/ProductService.java | 20 ++++----- 19 files changed, 214 insertions(+), 187 deletions(-) create mode 100644 src/main/java/com/example/demo/metrics/MetricServiceCounter.java delete mode 100644 src/main/java/com/example/demo/metrics/MetricsService.java create mode 100644 src/main/java/com/example/demo/metrics/MetricsServiceGauge.java diff --git a/src/main/java/com/example/demo/controller/ProductController.java b/src/main/java/com/example/demo/controller/ProductController.java index 6ec26cd..07edbd8 100644 --- a/src/main/java/com/example/demo/controller/ProductController.java +++ b/src/main/java/com/example/demo/controller/ProductController.java @@ -18,14 +18,14 @@ @Slf4j public class ProductController { - private final ProductFacade productFacade; + private final ProductFacade productFacade; - @PostMapping("/create-product") - public ResponseEntity createProduct(@RequestBody ProductDto productDto) { - log.info("Posting a new product with {} id", productDto.getName()); - var result = productFacade.countProducts(productDto); - log.info("Posting is done with status {}", result.getHttpStatus()); - return ResponseEntity.status(result.getHttpStatus()).body(result); - } + @PostMapping("/create-product") + public ResponseEntity countProduct(@RequestBody ProductDto productDto) { + log.info("Posting a new product with {} id", productDto.getName()); + var result = productFacade.countProducts(productDto); + log.info("Posting is done with status {}", result.getHttpStatus()); + return ResponseEntity.status(result.getHttpStatus()).body(result); + } } diff --git a/src/main/java/com/example/demo/dto/ProductCounterDto.java b/src/main/java/com/example/demo/dto/ProductCounterDto.java index 085b0a1..7e3358d 100644 --- a/src/main/java/com/example/demo/dto/ProductCounterDto.java +++ b/src/main/java/com/example/demo/dto/ProductCounterDto.java @@ -7,15 +7,14 @@ import java.time.Instant; - @Data @JsonInclude(JsonInclude.Include.NON_NULL) public class ProductCounterDto { - @JsonProperty("counter") - private int counter; + @JsonProperty("counter") + private int counter; - @JsonProperty("createdAt") - private Instant createdAt; + @JsonProperty("createdAt") + private Instant createdAt; } diff --git a/src/main/java/com/example/demo/dto/ProductDto.java b/src/main/java/com/example/demo/dto/ProductDto.java index 47c9b1f..657ca9c 100644 --- a/src/main/java/com/example/demo/dto/ProductDto.java +++ b/src/main/java/com/example/demo/dto/ProductDto.java @@ -13,21 +13,21 @@ public class ProductDto { - @JsonProperty("name") - private String name; - - @JsonProperty("description") - private String description; - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof ProductDto that)) return false; - return Objects.equals(getName(), that.getName()); - } - - @Override - public int hashCode() { - return Objects.hash(getName()); - } + @JsonProperty("name") + private String name; + + @JsonProperty("description") + private String description; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ProductDto that)) return false; + return Objects.equals(getName(), that.getName()); + } + + @Override + public int hashCode() { + return Objects.hash(getName()); + } } diff --git a/src/main/java/com/example/demo/entity/Product.java b/src/main/java/com/example/demo/entity/Product.java index 454deff..3b31a3f 100644 --- a/src/main/java/com/example/demo/entity/Product.java +++ b/src/main/java/com/example/demo/entity/Product.java @@ -21,26 +21,26 @@ @Slf4j public class Product { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long productId; - - @Column(name = "product_name", length = 20) - private String name; - - @Column(name = "product_description") - private String description; - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false; - Product product = (Product) o; - return getProductId() != null && Objects.equals(getProductId(), product.getProductId()); - } - - @Override - public int hashCode() { - return getClass().hashCode(); - } + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE) + private Long productId; + + @Column(name = "product_name", length = 20) + private String name; + + @Column(name = "product_description") + private String description; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false; + Product product = (Product) o; + return getProductId() != null && Objects.equals(getProductId(), product.getProductId()); + } + + @Override + public int hashCode() { + return getClass().hashCode(); + } } diff --git a/src/main/java/com/example/demo/exceptions/ExceptionHandlers.java b/src/main/java/com/example/demo/exceptions/ExceptionHandlers.java index 4dfabf8..c5f4c97 100644 --- a/src/main/java/com/example/demo/exceptions/ExceptionHandlers.java +++ b/src/main/java/com/example/demo/exceptions/ExceptionHandlers.java @@ -15,9 +15,9 @@ @Order(Ordered.HIGHEST_PRECEDENCE) public class ExceptionHandlers { - @ExceptionHandler(JDBCException.class) - public ResponseEntity internalServerExceptionsHandler(Exception exception) { - var errorResult = new ResponseMessage(ErrorCategory.NAME_NOT_ALLOWED.errorDto(), ProductCounterService.getProductCountSize()); - return ResponseEntity.status(errorResult.getHttpStatus()).body(errorResult); - } + @ExceptionHandler(JDBCException.class) + public ResponseEntity internalServerExceptionsHandler(Exception exception) { + var errorResult = new ResponseMessage(ErrorCategory.NAME_NOT_ALLOWED.errorDto(), ProductCounterService.getProductCountSize()); + return ResponseEntity.status(errorResult.getHttpStatus()).body(errorResult); + } } diff --git a/src/main/java/com/example/demo/facade/ProductFacade.java b/src/main/java/com/example/demo/facade/ProductFacade.java index 0309b6d..a3f218a 100644 --- a/src/main/java/com/example/demo/facade/ProductFacade.java +++ b/src/main/java/com/example/demo/facade/ProductFacade.java @@ -15,21 +15,29 @@ @Slf4j public class ProductFacade implements ProductUniquenessFacade { - private final ProductService productService; - - - @Override - public ResponseMessage countProducts(ProductDto productDto) { - log.info("Checking if the product is unique in the in memory counter {}", productDto.getName()); - var productCounter = ProductCounterService.getProductCounter(); - - if (!productCounter.contains(productDto.hashCode())) { - log.info("Product is counted: product is in the db and in the inMemory counter: name={}", productDto.getName()); - var savedProduct = productService.persistProduct(productDto); - return new ResponseMessage(ErrorCategory.UNIQUE.errorDto(), savedProduct, ProductCounterService.getProductCountSize()); - } else { - log.warn("Product is not counted: product either no in the db or in the in memory counter: name={}", productDto.getName()); - return new ResponseMessage(ErrorCategory.DUPLICATED_PRODUCT.errorDto(), ProductCounterService.getProductCountSize()); - } - } + private final ProductService productService; + + + @Override + public ResponseMessage countProducts(ProductDto productDto) { + log.info("Checking if the product is unique in the in memory counter {}", productDto.getName()); + var productCounter = ProductCounterService.getProductCounter(); + + if (!productCounter.contains(productDto.getName())) { + log.info("Product is counted: product is in the db and in the inMemory counter: name={}", productDto.getName()); + var savedProduct = productService.persistProduct(productDto); + + return new ResponseMessage(ErrorCategory.UNIQUE.errorDto(), savedProduct, ProductCounterService.getProductCountSize()); + } else { + log.warn("Product is not counted: product either no in the db or in the in memory counter: name={}", productDto.getName()); + return new ResponseMessage(ErrorCategory.DUPLICATED_PRODUCT.errorDto(), ProductCounterService.getProductCountSize()); + } + } + + @Override + public ResponseMessage counter(ProductDto productDto) { + return null; + } + + } diff --git a/src/main/java/com/example/demo/facade/ProductUniquenessFacade.java b/src/main/java/com/example/demo/facade/ProductUniquenessFacade.java index ed7b8fd..e541b46 100644 --- a/src/main/java/com/example/demo/facade/ProductUniquenessFacade.java +++ b/src/main/java/com/example/demo/facade/ProductUniquenessFacade.java @@ -4,9 +4,11 @@ import com.example.demo.response.ResponseMessage; -public interface ProductUniquenessFacade { +interface ProductUniquenessFacade { - ResponseMessage countProducts(ProductDto productDto); + ResponseMessage countProducts(ProductDto productDto); + + ResponseMessage counter(ProductDto productDto); } diff --git a/src/main/java/com/example/demo/listeners/ProductCounterListener.java b/src/main/java/com/example/demo/listeners/ProductCounterListener.java index 5c0a80d..e15e63a 100644 --- a/src/main/java/com/example/demo/listeners/ProductCounterListener.java +++ b/src/main/java/com/example/demo/listeners/ProductCounterListener.java @@ -9,14 +9,14 @@ @Slf4j public class ProductCounterListener { - @PostPersist - void postPersistProductCounter(Object productDto) { - log.info("Trying to add the product into the inMemory db!"); - var counter = ProductCounterService.getProductCounter(); - if (productDto instanceof Product product) { - var entity = Map.INSTANCE.fromProduct(product); - counter.add(entity.hashCode()); - log.info("Product name={} is added into the inMemory db!", product.getName()); - } - } + @PostPersist + void postPersistProductCounter(Object productDto) { + log.info("Trying to add the product into the inMemory db!"); + var counter = ProductCounterService.getProductCounter(); + if (productDto instanceof Product product) { + var entity = Map.INSTANCE.fromProduct(product); + counter.add(entity.getName()); + log.info("Product name={} is added into the inMemory db!", product.getName()); + } + } } diff --git a/src/main/java/com/example/demo/mapper/Map.java b/src/main/java/com/example/demo/mapper/Map.java index a2f05f6..9404328 100644 --- a/src/main/java/com/example/demo/mapper/Map.java +++ b/src/main/java/com/example/demo/mapper/Map.java @@ -8,10 +8,10 @@ @Mapper(componentModel = "spring") public interface Map { - Map INSTANCE = Mappers.getMapper(Map.class); + Map INSTANCE = Mappers.getMapper(Map.class); - @Mapping(target = "productId", ignore = true) - Product toProduct(ProductDto productDto); + @Mapping(target = "productId", ignore = true) + Product toProduct(ProductDto productDto); - ProductDto fromProduct(Product product); + ProductDto fromProduct(Product product); } diff --git a/src/main/java/com/example/demo/metrics/MetricServiceCounter.java b/src/main/java/com/example/demo/metrics/MetricServiceCounter.java new file mode 100644 index 0000000..5d59544 --- /dev/null +++ b/src/main/java/com/example/demo/metrics/MetricServiceCounter.java @@ -0,0 +1,18 @@ +package com.example.demo.metrics; + + +import io.prometheus.client.Counter; + +public class MetricServiceCounter { + public static final Counter counter = Counter.build() + .name("Counter") + .help("Total Products") + .register(); + + private MetricServiceCounter() { + } + + void processRequest() { + counter.inc(); + } +} diff --git a/src/main/java/com/example/demo/metrics/MetricsService.java b/src/main/java/com/example/demo/metrics/MetricsService.java deleted file mode 100644 index 28334b3..0000000 --- a/src/main/java/com/example/demo/metrics/MetricsService.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.example.demo.metrics; - -import com.example.demo.service.ProductCounterService; -import io.micrometer.core.instrument.Gauge; -import io.micrometer.core.instrument.MeterRegistry; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -import java.util.function.Supplier; - -@Component -@Slf4j -public class MetricsService { - - public MetricsService(MeterRegistry registry) { - log.info("Registering product countMetric into the Prometheus."); - Gauge.builder("product_counter", fetchProductCount()) - .strongReference(true) - .tag("product", "counter") - .register(registry); - log.info("CounterMetric is already registered in the Prometheus."); - } - - public Supplier fetchProductCount() { - return ProductCounterService::getProductCountSize; - } -} diff --git a/src/main/java/com/example/demo/metrics/MetricsServiceGauge.java b/src/main/java/com/example/demo/metrics/MetricsServiceGauge.java new file mode 100644 index 0000000..b334eb8 --- /dev/null +++ b/src/main/java/com/example/demo/metrics/MetricsServiceGauge.java @@ -0,0 +1,27 @@ +package com.example.demo.metrics; + +import com.example.demo.service.ProductCounterService; +import io.micrometer.core.instrument.Gauge; +import io.micrometer.core.instrument.MeterRegistry; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.function.Supplier; + +@Component +@Slf4j +public class MetricsServiceGauge { + + public MetricsServiceGauge(MeterRegistry registry) { + log.info("Registering product countMetric into the Prometheus."); + Gauge.builder("product_counter", fetchProductCount()) + .strongReference(true) + .tag("product", "counter") + .register(registry); + log.info("CounterMetric is already registered in the Prometheus."); + } + + public Supplier fetchProductCount() { + return ProductCounterService::getProductCountSize; + } +} diff --git a/src/main/java/com/example/demo/response/AbstractProductErrorResponse.java b/src/main/java/com/example/demo/response/AbstractProductErrorResponse.java index 6c5f589..05d7e77 100644 --- a/src/main/java/com/example/demo/response/AbstractProductErrorResponse.java +++ b/src/main/java/com/example/demo/response/AbstractProductErrorResponse.java @@ -10,25 +10,25 @@ @JsonInclude(JsonInclude.Include.NON_NULL) public abstract class AbstractProductErrorResponse { - @JsonIgnore - private Integer httpStatus; + @JsonIgnore + private Integer httpStatus; - @JsonProperty("notification") - private ErrorDto errors; + @JsonProperty("notification") + private ErrorDto errors; - protected AbstractProductErrorResponse(ErrorDto errorDto, Integer httpStatus) { - this.httpStatus = httpStatus; - this.errors = errorDto; - } + protected AbstractProductErrorResponse(ErrorDto errorDto, Integer httpStatus) { + this.httpStatus = httpStatus; + this.errors = errorDto; + } - protected AbstractProductErrorResponse(ErrorDto errorDto) { - this(errorDto, errorDto.getStatus().value()); - } + protected AbstractProductErrorResponse(ErrorDto errorDto) { + this(errorDto, errorDto.getStatus().value()); + } - protected AbstractProductErrorResponse() { - this.httpStatus = 200; - this.errors = new ErrorDto(); - } + protected AbstractProductErrorResponse() { + this.httpStatus = 200; + this.errors = new ErrorDto(); + } } diff --git a/src/main/java/com/example/demo/response/ErrorCategory.java b/src/main/java/com/example/demo/response/ErrorCategory.java index 0db35f9..274eac8 100644 --- a/src/main/java/com/example/demo/response/ErrorCategory.java +++ b/src/main/java/com/example/demo/response/ErrorCategory.java @@ -6,19 +6,19 @@ @Getter public enum ErrorCategory { - DUPLICATED_PRODUCT("Such a product exists already", HttpStatus.NOT_ACCEPTABLE), - NAME_NOT_ALLOWED("The product name length should not be greater than 20", HttpStatus.INTERNAL_SERVER_ERROR), - UNIQUE("The product is unique", HttpStatus.OK); + DUPLICATED_PRODUCT("Such a product exists already", HttpStatus.NOT_ACCEPTABLE), + NAME_NOT_ALLOWED("The product name length should not be greater than 20", HttpStatus.INTERNAL_SERVER_ERROR), + UNIQUE("The product is unique", HttpStatus.OK); - private final String id; - private final HttpStatus httpStatus; + private final String id; + private final HttpStatus httpStatus; - ErrorCategory(String s, HttpStatus httpStatus) { - this.id = s; - this.httpStatus = httpStatus; - } + ErrorCategory(String s, HttpStatus httpStatus) { + this.id = s; + this.httpStatus = httpStatus; + } - public ErrorDto errorDto() { - return new ErrorDto(getId(), name(), getHttpStatus()); - } + public ErrorDto errorDto() { + return new ErrorDto(getId(), name(), getHttpStatus()); + } } diff --git a/src/main/java/com/example/demo/response/ErrorDto.java b/src/main/java/com/example/demo/response/ErrorDto.java index 2d10c64..d890f5e 100644 --- a/src/main/java/com/example/demo/response/ErrorDto.java +++ b/src/main/java/com/example/demo/response/ErrorDto.java @@ -15,12 +15,12 @@ @AllArgsConstructor public class ErrorDto { - @JsonProperty("message") - private String message; + @JsonProperty("message") + private String message; - @JsonProperty("state") - private String state; + @JsonProperty("state") + private String state; - @JsonIgnore - private HttpStatus status; + @JsonIgnore + private HttpStatus status; } diff --git a/src/main/java/com/example/demo/response/ResponseMessage.java b/src/main/java/com/example/demo/response/ResponseMessage.java index 0a5b867..049ea05 100644 --- a/src/main/java/com/example/demo/response/ResponseMessage.java +++ b/src/main/java/com/example/demo/response/ResponseMessage.java @@ -13,21 +13,21 @@ public class ResponseMessage extends AbstractProductErrorResponse { - @JsonProperty("body") - private ProductDto body; - - @JsonProperty(value = "productCounter") - private Number productCounter; - - public ResponseMessage(final ErrorDto error, Number productCounter) { - super(error); - this.productCounter = productCounter; - } - - public ResponseMessage(final ErrorDto error, ProductDto body, int productCounter) { - super(error); - this.body = body; - this.productCounter = productCounter; - } + @JsonProperty("body") + private ProductDto body; + + @JsonProperty(value = "productCounter") + private Number productCounter; + + public ResponseMessage(final ErrorDto error, Number productCounter) { + super(error); + this.productCounter = productCounter; + } + + public ResponseMessage(final ErrorDto error, ProductDto body, int productCounter) { + super(error); + this.body = body; + this.productCounter = productCounter; + } } diff --git a/src/main/java/com/example/demo/service/ProductCounterService.java b/src/main/java/com/example/demo/service/ProductCounterService.java index c8115ab..2fd0328 100644 --- a/src/main/java/com/example/demo/service/ProductCounterService.java +++ b/src/main/java/com/example/demo/service/ProductCounterService.java @@ -13,18 +13,18 @@ @Service public class ProductCounterService { - private static final Set productCounter = ConcurrentHashMap.newKeySet(); + private static final Set productCounter = ConcurrentHashMap.newKeySet(); - public static Integer getProductCountSize() { - return productCounter.size(); - } + public static Integer getProductCountSize() { + return productCounter.size(); + } - public static Set getProductCounter() { - return productCounter; - } + public static Set getProductCounter() { + return productCounter; + } - public Number getProductQuantity() { - return getProductCountSize(); - } + public Number getProductQuantity() { + return getProductCountSize(); + } } diff --git a/src/main/java/com/example/demo/service/ProductDomainService.java b/src/main/java/com/example/demo/service/ProductDomainService.java index cd37f1c..fba2f98 100644 --- a/src/main/java/com/example/demo/service/ProductDomainService.java +++ b/src/main/java/com/example/demo/service/ProductDomainService.java @@ -4,5 +4,5 @@ public interface ProductDomainService { - ProductDto persistProduct(ProductDto productDto); + ProductDto persistProduct(ProductDto productDto); } diff --git a/src/main/java/com/example/demo/service/ProductService.java b/src/main/java/com/example/demo/service/ProductService.java index 88bf30d..bb2765a 100644 --- a/src/main/java/com/example/demo/service/ProductService.java +++ b/src/main/java/com/example/demo/service/ProductService.java @@ -15,16 +15,16 @@ public class ProductService implements ProductDomainService { - private final ProductCounterService productCounterService; - private final ProductRepository productRepository; - private final Map map; + private final ProductCounterService productCounterService; + private final ProductRepository productRepository; + private final Map map; - @Override - public ProductDto persistProduct(ProductDto productDto) { - log.info("Saving product {}", productDto.getName()); - Product savedProduct = productRepository.save(map.toProduct(productDto)); - log.info("Product is already saved {}, the product quantity is {}", savedProduct.getName(), ProductCounterService.getProductCountSize()); - return map.fromProduct(savedProduct); - } + @Override + public ProductDto persistProduct(ProductDto productDto) { + log.info("Saving product {}", productDto.getName()); + Product savedProduct = productRepository.save(map.toProduct(productDto)); + log.info("Product is already saved {}, the product quantity is {}", savedProduct.getName(), ProductCounterService.getProductCountSize()); + return map.fromProduct(savedProduct); + } } From eb071913fe6c10fce07eb599ccccebbdfce01de7 Mon Sep 17 00:00:00 2001 From: Garik Hakobyan Date: Sat, 6 May 2023 17:31:51 +0400 Subject: [PATCH 3/3] counter is used and exception handler --- .../demo/controller/ProductController.java | 8 +++++++ .../java/com/example/demo/entity/Product.java | 2 +- .../demo/exceptions/ExceptionHandlers.java | 7 +++++++ .../example/demo/facade/ProductFacade.java | 7 +++++-- .../demo/facade/ProductUniquenessFacade.java | 2 +- .../demo/metrics/MetricServiceCounter.java | 21 ++++++++++++------- .../demo/repository/ProductRepository.java | 3 +++ .../example/demo/response/ErrorCategory.java | 1 + .../demo/service/ProductDomainService.java | 1 + .../example/demo/service/ProductService.java | 17 +++++++++++++++ 10 files changed, 57 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/example/demo/controller/ProductController.java b/src/main/java/com/example/demo/controller/ProductController.java index 07edbd8..cd393e4 100644 --- a/src/main/java/com/example/demo/controller/ProductController.java +++ b/src/main/java/com/example/demo/controller/ProductController.java @@ -28,4 +28,12 @@ public ResponseEntity countProduct(@RequestBody ProductDto prod return ResponseEntity.status(result.getHttpStatus()).body(result); } + @PostMapping("/new-product") + public ResponseEntity createProduct(@RequestBody ProductDto productDto) { + log.info("Posting a new product with {} id", productDto.getName()); + var result = productFacade.createNewProduct(productDto); + log.info("Posting is done with status {}", result.getHttpStatus()); + return ResponseEntity.status(result.getHttpStatus()).body(result); + } + } diff --git a/src/main/java/com/example/demo/entity/Product.java b/src/main/java/com/example/demo/entity/Product.java index 3b31a3f..23a698f 100644 --- a/src/main/java/com/example/demo/entity/Product.java +++ b/src/main/java/com/example/demo/entity/Product.java @@ -41,6 +41,6 @@ public boolean equals(Object o) { @Override public int hashCode() { - return getClass().hashCode(); + return Objects.hash(getName(), getDescription()); } } diff --git a/src/main/java/com/example/demo/exceptions/ExceptionHandlers.java b/src/main/java/com/example/demo/exceptions/ExceptionHandlers.java index c5f4c97..d0ce780 100644 --- a/src/main/java/com/example/demo/exceptions/ExceptionHandlers.java +++ b/src/main/java/com/example/demo/exceptions/ExceptionHandlers.java @@ -4,6 +4,7 @@ import com.example.demo.response.ResponseMessage; import com.example.demo.service.ProductCounterService; import org.hibernate.JDBCException; +import org.hibernate.query.QueryTypeMismatchException; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.http.ResponseEntity; @@ -15,6 +16,12 @@ @Order(Ordered.HIGHEST_PRECEDENCE) public class ExceptionHandlers { + @ExceptionHandler(QueryTypeMismatchException.class) + public ResponseEntity queryTypeMismatchException(Exception exception) { + var errorResult = new ResponseMessage(ErrorCategory.QUERY_TYPE_ERROR.errorDto(), ProductCounterService.getProductCountSize()); + return ResponseEntity.status(errorResult.getHttpStatus()).body(errorResult); + } + @ExceptionHandler(JDBCException.class) public ResponseEntity internalServerExceptionsHandler(Exception exception) { var errorResult = new ResponseMessage(ErrorCategory.NAME_NOT_ALLOWED.errorDto(), ProductCounterService.getProductCountSize()); diff --git a/src/main/java/com/example/demo/facade/ProductFacade.java b/src/main/java/com/example/demo/facade/ProductFacade.java index a3f218a..2167164 100644 --- a/src/main/java/com/example/demo/facade/ProductFacade.java +++ b/src/main/java/com/example/demo/facade/ProductFacade.java @@ -1,6 +1,7 @@ package com.example.demo.facade; import com.example.demo.dto.ProductDto; +import com.example.demo.metrics.MetricServiceCounter; import com.example.demo.response.ErrorCategory; import com.example.demo.response.ResponseMessage; import com.example.demo.service.ProductCounterService; @@ -16,6 +17,7 @@ public class ProductFacade implements ProductUniquenessFacade { private final ProductService productService; + private final MetricServiceCounter metricServiceCounter; @Override @@ -35,8 +37,9 @@ public ResponseMessage countProducts(ProductDto productDto) { } @Override - public ResponseMessage counter(ProductDto productDto) { - return null; + public ResponseMessage createNewProduct(ProductDto productDto) { + ProductDto entity = productService.postProduct(productDto); + return new ResponseMessage(ErrorCategory.UNIQUE.errorDto(), entity, ProductCounterService.getProductCountSize()); } diff --git a/src/main/java/com/example/demo/facade/ProductUniquenessFacade.java b/src/main/java/com/example/demo/facade/ProductUniquenessFacade.java index e541b46..36aba19 100644 --- a/src/main/java/com/example/demo/facade/ProductUniquenessFacade.java +++ b/src/main/java/com/example/demo/facade/ProductUniquenessFacade.java @@ -8,7 +8,7 @@ interface ProductUniquenessFacade { ResponseMessage countProducts(ProductDto productDto); - ResponseMessage counter(ProductDto productDto); + ResponseMessage createNewProduct(ProductDto productDto); } diff --git a/src/main/java/com/example/demo/metrics/MetricServiceCounter.java b/src/main/java/com/example/demo/metrics/MetricServiceCounter.java index 5d59544..8567a25 100644 --- a/src/main/java/com/example/demo/metrics/MetricServiceCounter.java +++ b/src/main/java/com/example/demo/metrics/MetricServiceCounter.java @@ -1,18 +1,23 @@ package com.example.demo.metrics; -import io.prometheus.client.Counter; +import io.micrometer.core.instrument.Counter; +import io.micrometer.core.instrument.MeterRegistry; +import org.springframework.stereotype.Component; +@Component public class MetricServiceCounter { - public static final Counter counter = Counter.build() - .name("Counter") - .help("Total Products") - .register(); - private MetricServiceCounter() { + private final Counter count; + + public MetricServiceCounter(MeterRegistry registry) { + this.count = Counter.builder("myCounter") + .tag("product", "counter") + .register(registry); } - void processRequest() { - counter.inc(); + public void processRequest() { + this.count.increment(); + } } diff --git a/src/main/java/com/example/demo/repository/ProductRepository.java b/src/main/java/com/example/demo/repository/ProductRepository.java index e15a5da..048e7e3 100644 --- a/src/main/java/com/example/demo/repository/ProductRepository.java +++ b/src/main/java/com/example/demo/repository/ProductRepository.java @@ -4,8 +4,11 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.Optional; + @Repository public interface ProductRepository extends JpaRepository { + Optional findProductByNameAndAndDescription(String name, String description); } diff --git a/src/main/java/com/example/demo/response/ErrorCategory.java b/src/main/java/com/example/demo/response/ErrorCategory.java index 274eac8..240c646 100644 --- a/src/main/java/com/example/demo/response/ErrorCategory.java +++ b/src/main/java/com/example/demo/response/ErrorCategory.java @@ -8,6 +8,7 @@ public enum ErrorCategory { DUPLICATED_PRODUCT("Such a product exists already", HttpStatus.NOT_ACCEPTABLE), NAME_NOT_ALLOWED("The product name length should not be greater than 20", HttpStatus.INTERNAL_SERVER_ERROR), + QUERY_TYPE_ERROR("Specified result type did not match Query selection type", HttpStatus.INTERNAL_SERVER_ERROR), UNIQUE("The product is unique", HttpStatus.OK); private final String id; diff --git a/src/main/java/com/example/demo/service/ProductDomainService.java b/src/main/java/com/example/demo/service/ProductDomainService.java index fba2f98..b54fc6c 100644 --- a/src/main/java/com/example/demo/service/ProductDomainService.java +++ b/src/main/java/com/example/demo/service/ProductDomainService.java @@ -5,4 +5,5 @@ public interface ProductDomainService { ProductDto persistProduct(ProductDto productDto); + ProductDto postProduct(ProductDto productDto); } diff --git a/src/main/java/com/example/demo/service/ProductService.java b/src/main/java/com/example/demo/service/ProductService.java index bb2765a..2af7fb3 100644 --- a/src/main/java/com/example/demo/service/ProductService.java +++ b/src/main/java/com/example/demo/service/ProductService.java @@ -3,7 +3,9 @@ import com.example.demo.dto.ProductDto; import com.example.demo.entity.Product; import com.example.demo.mapper.Map; +import com.example.demo.metrics.MetricServiceCounter; import com.example.demo.repository.ProductRepository; +import io.micrometer.core.annotation.Counted; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -16,6 +18,7 @@ public class ProductService implements ProductDomainService { private final ProductCounterService productCounterService; + private final MetricServiceCounter metricServiceCounter; private final ProductRepository productRepository; private final Map map; @@ -27,4 +30,18 @@ public ProductDto persistProduct(ProductDto productDto) { log.info("Product is already saved {}, the product quantity is {}", savedProduct.getName(), ProductCounterService.getProductCountSize()); return map.fromProduct(savedProduct); } + @Override + public ProductDto postProduct(ProductDto productDto) { + var productExist = productRepository.findProductByNameAndAndDescription(productDto.getName(), productDto.getDescription()); + if (productExist.isEmpty()) { + log.info("Saving product {}", productDto.getName()); + var productToSave = map.toProduct(productDto); + var savedProduct = productRepository.save(productToSave); + metricServiceCounter.processRequest(); + log.info("Product is already saved {}, the product quantity is {}", savedProduct.getName(), ProductCounterService.getProductCountSize()); + return map.fromProduct(savedProduct); + } + log.info("The product {} exists.", productDto.getName()); + return productDto; + } }