Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Branch with counter #4

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions src/main/java/com/example/demo/DemoApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}


}
16 changes: 14 additions & 2 deletions src/main/java/com/example/demo/controller/ProductController.java
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -17,11 +21,19 @@ public class ProductController {
private final ProductFacade productFacade;

@PostMapping("/create-product")
public ResponseEntity<ResponseMessage> createProduct(@RequestBody ProductDto productDto) {
public ResponseEntity<ResponseMessage> 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);
}

@PostMapping("/new-product")
public ResponseEntity<ResponseMessage> 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);
}

}
1 change: 1 addition & 0 deletions src/main/java/com/example/demo/dto/ProductDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import java.util.Objects;


@Data
//@EqualsAndHashCode
@JsonInclude(JsonInclude.Include.NON_NULL)
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/com/example/demo/entity/Product.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import java.util.Objects;


@Getter
@Setter
@ToString
Expand All @@ -21,7 +22,7 @@
public class Product {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long productId;

@Column(name = "product_name", length = 20)
Expand All @@ -40,6 +41,6 @@ public boolean equals(Object o) {

@Override
public int hashCode() {
return getClass().hashCode();
return Objects.hash(getName(), getDescription());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,24 @@
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;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;


@RestControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE)
public class ExceptionHandlers {

@ExceptionHandler(QueryTypeMismatchException.class)
public ResponseEntity<ResponseMessage> 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<ResponseMessage> internalServerExceptionsHandler(Exception exception) {
var errorResult = new ResponseMessage(ErrorCategory.NAME_NOT_ALLOWED.errorDto(), ProductCounterService.getProductCountSize());
Expand Down
14 changes: 13 additions & 1 deletion src/main/java/com/example/demo/facade/ProductFacade.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -9,26 +10,37 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;


@Service
@RequiredArgsConstructor
@Slf4j
public class ProductFacade implements ProductUniquenessFacade {

private final ProductService productService;
private final MetricServiceCounter metricServiceCounter;


@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())) {
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 createNewProduct(ProductDto productDto) {
ProductDto entity = productService.postProduct(productDto);
return new ResponseMessage(ErrorCategory.UNIQUE.errorDto(), entity, ProductCounterService.getProductCountSize());
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
import com.example.demo.dto.ProductDto;
import com.example.demo.response.ResponseMessage;

public interface ProductUniquenessFacade {

interface ProductUniquenessFacade {

ResponseMessage countProducts(ProductDto productDto);

ResponseMessage createNewProduct(ProductDto productDto);


}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
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;

Expand All @@ -16,7 +15,7 @@ void postPersistProductCounter(Object productDto) {
var counter = ProductCounterService.getProductCounter();
if (productDto instanceof Product product) {
var entity = Map.INSTANCE.fromProduct(product);
counter.add(entity.hashCode());
counter.add(entity.getName());
log.info("Product name={} is added into the inMemory db!", product.getName());
}
}
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/example/demo/mapper/Map.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
@Mapper(componentModel = "spring")
public interface Map {
Map INSTANCE = Mappers.getMapper(Map.class);

@Mapping(target = "productId", ignore = true)
Product toProduct(ProductDto productDto);

Expand Down
23 changes: 23 additions & 0 deletions src/main/java/com/example/demo/metrics/MetricServiceCounter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.example.demo.metrics;


import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.stereotype.Component;

@Component
public class MetricServiceCounter {

private final Counter count;

public MetricServiceCounter(MeterRegistry registry) {
this.count = Counter.builder("myCounter")
.tag("product", "counter")
.register(registry);
}

public void processRequest() {
this.count.increment();

}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -12,17 +10,18 @@

@Component
@Slf4j
public class MetricsService {
public class MetricsServiceGauge {

public Supplier<Number> fetchProductCount(){
return ProductCounterService::getProductCountSize;
}
public MetricsService(MeterRegistry registry) {
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<Number> fetchProductCount() {
return ProductCounterService::getProductCountSize;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.Optional;


@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {
Optional<Product> findProductByNameAndAndDescription(String name, String description);

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;


@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public abstract class AbstractProductErrorResponse {
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/com/example/demo/response/ErrorCategory.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
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),
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;
Expand All @@ -16,6 +18,7 @@ public enum ErrorCategory {
this.id = s;
this.httpStatus = httpStatus;
}

public ErrorDto errorDto() {
return new ErrorDto(getId(), name(), getHttpStatus());
}
Expand Down
6 changes: 5 additions & 1 deletion src/main/java/com/example/demo/response/ErrorDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@

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
Expand Down
8 changes: 5 additions & 3 deletions src/main/java/com/example/demo/response/ResponseMessage.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
import lombok.Getter;
import lombok.Setter;


@Getter
@Setter
@EqualsAndHashCode(callSuper = true)
public class ResponseMessage extends AbstractProductErrorResponse{
public class ResponseMessage extends AbstractProductErrorResponse {


@JsonProperty("body")
Expand All @@ -18,11 +19,12 @@ public class ResponseMessage extends AbstractProductErrorResponse{
@JsonProperty(value = "productCounter")
private Number productCounter;

public ResponseMessage(final ErrorDto error, Number productCounter){
public ResponseMessage(final ErrorDto error, Number productCounter) {
super(error);
this.productCounter = productCounter;
}
public ResponseMessage(final ErrorDto error, ProductDto body, int productCounter){

public ResponseMessage(final ErrorDto error, ProductDto body, int productCounter) {
super(error);
this.body = body;
this.productCounter = productCounter;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,20 @@
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;


@RequiredArgsConstructor
@Slf4j
@Service
public class ProductCounterService {

private static final Set<Integer> productCounter = ConcurrentHashMap.newKeySet();
private static final Set<String> productCounter = ConcurrentHashMap.newKeySet();


public static Integer getProductCountSize() {
return productCounter.size();
}

public static Set<Integer> getProductCounter() {
public static Set<String> getProductCounter() {
return productCounter;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.example.demo.dto.ProductDto;


public interface ProductDomainService {
ProductDto persistProduct(ProductDto productDto);
ProductDto postProduct(ProductDto productDto);
}
Loading